feat(ci): add audit-force-merge workflow + script for mcp-server (mcp-audit) #49
Reference in New Issue
Block a user
Delete Branch "fix/mcp-audit-force-merge"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
mcp-server had no audit-force-merge detector, unlike molecule-core and internal repos.
Fix
.gitea/workflows/audit-force-merge.yml— triggers onpull_request_target:closed.gitea/scripts/audit-force-merge.sh— fail-closed detector with:PR_SCHEMA_OKvalidates presence+type for all consumed fields//fallbacks(.statuses | type) == "array"REQUIRED_CHECKS_JSONbranch-aware with fail-closed branch-key validation.gitea/scripts/tests/test_audit_force_merge.shRefs: mcp-audit, molecule-core#2366, internal#844.
REQUEST_CHANGES on head
2033d9c19d.Full-diff-scope against fresh origin/main is not clean. The PR adds the expected audit workflow/script/test, but it also deletes
.gitea/workflows/gitea-merge-queue.yml. That removes the per-repo merge-queue capability added by #45/#2355 and is unrelated collateral; please restore it.Second blocker: the audit workflow does not concretely wire mcp-server's protected required context.
.gitea/workflows/audit-force-merge.ymlpassesREQUIRED_CHECKS: ${{ vars.REQUIRED_CHECKS }}andREQUIRED_CHECKS_JSON: ${{ vars.REQUIRED_CHECKS_JSON }}instead of declaring the real mcp-server protected set in the production path (CI / test (pull_request), as shown by the live green required status). This repeats the #844 class of issue: the parser can be correct while the workflow coverage is not guaranteed. Please wire the real required set into the workflow or otherwise make the required set explicit and auditable in the PR.The script's parser is broadly fail-closed (HTTP 200 checks, PR schema/type checks, statuses array type check, branch-key exists+array for JSON, and unsafe-default grep only finds non-gating
.title // ""), and live CI is green/mergeable. But the collateral deletion and required-check wiring must be fixed before approval.REQUEST_CHANGES on head
2033d9c19d. The audit script itself has the expected fail-closed pieces (HTTP 200 checks, PR schema/type checks, statuses array check, REQUIRED_CHECKS_JSON branch-key exists+array check; grep found only non-gating.title // ""; T1-T9 tests are present). But the PR is not safe to approve as a full-diff-scope change.Collateral regression: the PR deletes
.gitea/workflows/gitea-merge-queue.yml. That removes the mcp-server self-merge workflow while this PR is supposed to add force-merge audit coverage. Keep/restore the merge-queue workflow; audit-force-merge should be additive.Production required-check wiring is not pinned in repo.
.gitea/workflows/audit-force-merge.yml:25-26readsREQUIRED_CHECKSandREQUIRED_CHECKS_JSONfrom repo variables. The PR does not declare the mcp-server protected context (CI / test (pull_request), matching.gitea/workflows/ci.ymljobtestand live PR status), so I cannot verify the production workflow covers the real protected set. This repeats the wiring trap: parser exists, but the repo diff does not prove production is using a complete branch-keyed required-check set.Fix shape: make #49 additive (no gitea-merge-queue deletion) and wire a branch-keyed REQUIRED_CHECKS_JSON value for main that includes the real mcp-server required context, or otherwise put the required-check config under versioned review so coverage is auditable. Then the parser/tests can be approved.
APPROVED on head
a6d5b62fee.Full-diff-scope is clean against fresh origin/main: the PR only adds .gitea/workflows/audit-force-merge.yml, .gitea/scripts/audit-force-merge.sh, and .gitea/scripts/tests/test_audit_force_merge.sh. The previous collateral deletion is fixed: .gitea/workflows/gitea-merge-queue.yml is present and unchanged.
The production workflow now wires mcp-server's required context explicitly via REQUIRED_CHECKS_JSON for main: CI / test (pull_request). Parser behavior is fail-closed: PR/status fetches require HTTP 200, PR_SCHEMA_OK validates presence and types for merge fields/base/head, statuses must be an array, and JSON branch entries must exist and be arrays. Unsafe-default grep only finds non-gating .title // "". The 9 regression tests cover schema, statuses-array, and branch-key failure cases. Live CI is green and mergeable=true.
APPROVED on head
a6d5b62fee. Full-diff-scope is now additive audit files only: adds .gitea/workflows/audit-force-merge.yml, .gitea/scripts/audit-force-merge.sh, and .gitea/scripts/tests/test_audit_force_merge.sh; no deletion of gitea-merge-queue.yml. Production workflow wires REQUIRED_CHECKS_JSON directly with main ->CI / test (pull_request), matching mcp-server's live CI/test context. Script is fail-closed on PR/status HTTP, consumed PR field types, statuses array type, and missing/non-array branch-key; grep found only non-gating.title // "". T1-T9 tests present; live CI / test is green.qa 2nd-lane (full-SHA
d51e6f5feb). 5-axis on the audit-force-merge detector:(1) Correctness — SOUND. Fail-closed end-to-end: every API fetch verifies HTTP 200 AND validates response schema (merged/merge_commit_sha/merged_by.login/base.ref/head.sha types) before use; not-merged ⇒ no emission (exit 0); branch-aware REQUIRED_CHECKS_JSON validated as array-for-branch before iteration; empty required ⇒ not-applicable (exit 0). Trims whitespace on each required-check name. Emits structured incident.force_merge JSON only when a required check was non-success at merged HEAD.
(2) Robustness/tests — test_audit_force_merge.sh (+72) accompanies; mktemp+rm for response bodies; set -euo pipefail.
(3) Security/content-sec — GITEA_TOKEN read from env, passed only in Authorization header (not logged/echoed); no cred VALUES or live coords in the diff (soft/clean). Triggers on pull_request_target:closed (post-merge audit, no privileged mutation).
(4) Performance — 2 API calls per closed PR; negligible.
(5) Gate-readiness — CI green; pull_request_target:closed audit-only.
NON-BLOCKING NOTE: it reads /commits/HEAD/status (combined, latest-per-context) and treats a required check absent from .statuses as 'missing'⇒non-success⇒flagged. If any required check is reported as a check-run NOT surfaced in /status, that would over-report — but for a post-merge AUDIT detector over-reporting is the FAIL-SAFE direction (flags for human review, never silently passes a real force-merge). Acceptable as-is; optional follow-up to also consult check-runs. Gate-integrity value (branch-protection down-payment). APPROVED.
Security+correctness 5-axis — APPROVE (re-confirm on full-SHA d51e6f5feb18e9d820da668218e7976574794de0; supersedes my stale 9178 on the prior head). audit-force-merge workflow + script (+241/-0, 3 files) — §SOP-6 force-merge detector for mcp-server (gate-integrity-positive, same family as molecule-core audit-force-merge).
pull_request_target:closed+merged==true, fetches PR → checks merged → resolves required checks (branch-aware REQUIRED_CHECKS_JSON dict, else REQUIRED_CHECKS) → reads status at HEAD → flags any required check notsuccess→ emitsincident.force_mergestructured JSON +::warning::. Logic sound.set -euo pipefail; a missing required check → "missing" → flagged (never silently passes); empty-required → notice+exit 0.${VAR:?required}env (not logged); jq-parsed inputs (no injection); emits to stdout for Loki. No host/cred literals — content-clean.CI/test green on head. Author core-be (≠ me). Sound — APPROVE. Needs CR-B qa 2nd lane → merge.