Block direct pushes to stable branches from MCP workflow sessions #671

Closed
opened 2026-07-10 16:19:28 -05:00 by jcwalker3 · 2 comments
Owner

Problem

Issue #670 documented a bare direct-to-master commit, 2fa97c26, that landed on prgs/master without PR/review provenance. Separately, a PR #654 merger run attempted git push prgs master, which was audited as no-op but still represents a dangerous workflow pattern.

MCP workflow sessions must not treat direct stable-branch publication as recovery or convenience. Stable branch updates must land only through sanctioned Gitea merge tooling or an explicitly authorized reconciler path.

Partial protections already exist (author_proofs.PROTECTED_BRANCHES, root checkout guards, branch-push proofs) but do not fully:

  • detect shell equivalents of git push <remote> master / main / stable refs;
  • mark the session contaminated after such attempts (including no-op/dry-run attempts that prove intent);
  • block subsequent review/merge/close/completion mutations until reconciler audit;
  • detect root/control-checkout local commits not associated with issue branches.

Required behavior

  • MCP workflow sessions must not directly push to stable branches such as master (and configured stable set: main, etc.).
  • Stable branch updates must happen through sanctioned Gitea merge tooling or an explicitly authorized reconciler path.
  • Detect shell commands equivalent to git push <remote> master (including refspecs, HEAD:master, --force, dry-run/--dry-run where intent is clear).
  • Detect local commits on the root/control checkout not associated with issue branches.
  • Mark the session workflow-contaminated after direct stable-branch push attempts.
  • Prevent review, merge, close, or issue-completion mutations after such contamination until reconciler audit.
  • Document that worker sessions must never push stable branches directly.

Scope

  1. Command/intent detection for direct stable-branch pushes (shell and any script helpers).
  2. Root/control checkout local-commit detection not tied to issue feature branches.
  3. Session contamination marker (align with #630 contamination class patterns).
  4. Fail-closed gates on review/merge/close/completion tools when contaminated.
  5. Tests and docs per acceptance criteria.
  6. Link and satisfy #670 AC5 (workflow-hardening issue for prevention).

Explicit non-goals

  • Do not rewrite or force-push history for 2fa97c26 (controller disposition on #670).
  • Do not block sanctioned gitea_merge_pr / Gitea API merge paths.
  • Do not block git fetch / pull --ff-only of master into control checkout when authorized for sync.
  • Do not block feature-branch pushes to non-stable refs.
  • Do not solve restart/pkill contamination (#630) except shared contamination machinery if useful.

Required implementation investigation

  • author_proofs.py (PROTECTED_BRANCHES, push proofs)
  • root_checkout_guard.py / _enforce_root_checkout_guard
  • shell/command classification paths; native_mcp_preference.py; reviewer workflow boundaries
  • merge path (merge_pr.py, gitea_merge_pr) as the sanctioned alternative
  • #670 incident evidence; PR #654 merger audit notes
  • contamination session state patterns from #630

Proposed implementation direction

  1. Central detector for push command lines targeting stable refs.
  2. Session flag stable_branch_push_contamination (or general contamination enum including this class).
  3. Wire fail-closed checks into review/merge/close/issue-complete mutation entrypoints.
  4. Optional: pre-exec deny for shell git push … master when command wrapper exists; otherwise post-attempt classification.
  5. Docs in workflow skill / control-plane guide / developer guidelines.

Security and workflow-safety requirements

  • Fail closed on ambiguous push targets that may resolve to stable.
  • No false block of issue feature-branch pushes.
  • Contamination must not be clearable by the same worker session without reconciler/controller path.
  • Preserve author/reviewer/merger role separation.

Acceptance criteria

  1. Detect shell commands equivalent to git push <remote> master.
  2. Detect local commits on the root/control checkout not associated with issue branches.
  3. Mark the session workflow-contaminated after direct stable-branch push attempts.
  4. Prevent review, merge, close, or issue-completion mutations after such contamination until reconciler audit.
  5. Add tests for:
    • no-op dry-run push
    • real direct push
    • sanctioned Gitea merge
    • fetch-only operations
    • root checkout local commit
  6. Document that worker sessions must never push stable branches directly.

Required tests

As in AC5; plus regression that feature-branch push still allowed; sanctioned merge still allowed.

Observability and audit requirements

  • Log contamination events with command summary (redacted), session id, remote, ref.
  • Durable comment or incident link when contamination blocks a mutation.

Dependencies and linkage

  • Evidence/incident: #670 (this issue fulfills recommended hardening / AC5)
  • Related contamination: #630 (process-kill class; share patterns, different vector)
  • Related guards: root checkout #475 (closed), author_proofs protected branches
  • Sanctioned path: Gitea merge tools; reconciler-authorized cleanup only when policy allows

Non-goals for #670 disposition

This issue does not decide accept/revert of 2fa97c26; controller owns that on #670.

Canonical issue state

STATE: ready-for-author
WHO_IS_NEXT: author
NEXT_ACTION: Implement detection, contamination, fail-closed gates, tests, docs
NEXT_PROMPT: Author implements this issue under branches/ worktree; link #670; PR; stop; no self-merge

Required final evidence

PR with detector, gates, tests AC5, docs; proof sanctioned merge and fetch-only still pass.

Required final response and handoff

Brief PR → reviewer; note #670 linkage.

## Problem Issue #670 documented a bare direct-to-master commit, `2fa97c26`, that landed on `prgs/master` without PR/review provenance. Separately, a PR #654 merger run attempted `git push prgs master`, which was audited as no-op but still represents a dangerous workflow pattern. MCP workflow sessions must not treat direct stable-branch publication as recovery or convenience. Stable branch updates must land only through sanctioned Gitea merge tooling or an explicitly authorized reconciler path. Partial protections already exist (`author_proofs.PROTECTED_BRANCHES`, root checkout guards, branch-push proofs) but do **not** fully: * detect shell equivalents of `git push <remote> master` / `main` / stable refs; * mark the session contaminated after such attempts (including no-op/dry-run attempts that prove intent); * block subsequent review/merge/close/completion mutations until reconciler audit; * detect root/control-checkout local commits not associated with issue branches. ## Required behavior * MCP workflow sessions must **not** directly push to stable branches such as `master` (and configured stable set: `main`, etc.). * Stable branch updates must happen through **sanctioned Gitea merge tooling** or an **explicitly authorized reconciler** path. * Detect shell commands equivalent to `git push <remote> master` (including refspecs, `HEAD:master`, `--force`, dry-run/`--dry-run` where intent is clear). * Detect local commits on the root/control checkout not associated with issue branches. * Mark the session **workflow-contaminated** after direct stable-branch push attempts. * Prevent review, merge, close, or issue-completion mutations after such contamination until reconciler audit. * Document that worker sessions must never push stable branches directly. ## Scope 1. Command/intent detection for direct stable-branch pushes (shell and any script helpers). 2. Root/control checkout local-commit detection not tied to issue feature branches. 3. Session contamination marker (align with #630 contamination class patterns). 4. Fail-closed gates on review/merge/close/completion tools when contaminated. 5. Tests and docs per acceptance criteria. 6. Link and satisfy #670 AC5 (workflow-hardening issue for prevention). ## Explicit non-goals * Do not rewrite or force-push history for `2fa97c26` (controller disposition on #670). * Do not block sanctioned `gitea_merge_pr` / Gitea API merge paths. * Do not block `git fetch` / `pull --ff-only` of master into control checkout when authorized for sync. * Do not block feature-branch pushes to non-stable refs. * Do not solve restart/pkill contamination (#630) except shared contamination machinery if useful. ## Required implementation investigation * `author_proofs.py` (`PROTECTED_BRANCHES`, push proofs) * `root_checkout_guard.py` / `_enforce_root_checkout_guard` * shell/command classification paths; `native_mcp_preference.py`; reviewer workflow boundaries * merge path (`merge_pr.py`, `gitea_merge_pr`) as the sanctioned alternative * #670 incident evidence; PR #654 merger audit notes * contamination session state patterns from #630 ## Proposed implementation direction 1. Central detector for push command lines targeting stable refs. 2. Session flag `stable_branch_push_contamination` (or general contamination enum including this class). 3. Wire fail-closed checks into review/merge/close/issue-complete mutation entrypoints. 4. Optional: pre-exec deny for shell `git push … master` when command wrapper exists; otherwise post-attempt classification. 5. Docs in workflow skill / control-plane guide / developer guidelines. ## Security and workflow-safety requirements * Fail closed on ambiguous push targets that may resolve to stable. * No false block of issue feature-branch pushes. * Contamination must not be clearable by the same worker session without reconciler/controller path. * Preserve author/reviewer/merger role separation. ## Acceptance criteria 1. Detect shell commands equivalent to `git push <remote> master`. 2. Detect local commits on the root/control checkout not associated with issue branches. 3. Mark the session workflow-contaminated after direct stable-branch push attempts. 4. Prevent review, merge, close, or issue-completion mutations after such contamination until reconciler audit. 5. Add tests for: * no-op dry-run push * real direct push * sanctioned Gitea merge * fetch-only operations * root checkout local commit 6. Document that worker sessions must never push stable branches directly. ## Required tests As in AC5; plus regression that feature-branch push still allowed; sanctioned merge still allowed. ## Observability and audit requirements * Log contamination events with command summary (redacted), session id, remote, ref. * Durable comment or incident link when contamination blocks a mutation. ## Dependencies and linkage * Evidence/incident: **#670** (this issue fulfills recommended hardening / AC5) * Related contamination: **#630** (process-kill class; share patterns, different vector) * Related guards: root checkout #475 (closed), `author_proofs` protected branches * Sanctioned path: Gitea merge tools; reconciler-authorized cleanup only when policy allows ## Non-goals for #670 disposition This issue does not decide accept/revert of `2fa97c26`; controller owns that on #670. ## Canonical issue state ```text STATE: ready-for-author WHO_IS_NEXT: author NEXT_ACTION: Implement detection, contamination, fail-closed gates, tests, docs NEXT_PROMPT: Author implements this issue under branches/ worktree; link #670; PR; stop; no self-merge ``` ## Required final evidence PR with detector, gates, tests AC5, docs; proof sanctioned merge and fetch-only still pass. ## Required final response and handoff Brief PR → reviewer; note #670 linkage.
Author
Owner

Canonical Issue State

STATE: ready-for-author (claimed)
WHO_IS_NEXT: author
NEXT_ACTION: Implement stable-branch push detection, session contamination marker, and fail-closed mutation gates with tests and docs
NEXT_PROMPT: Author (jcwalker3 / prgs-author) implements #671 in branches/fix-issue-671-block-stable-branch-push: pure detector for direct stable-branch pushes, durable contamination marker, fail-closed gate on review/merge/close/completion until reconciler audit, AC5 tests, docs; open PR with Closes #671; stop before review/merge.
WHAT_HAPPENED: Controller override of the allocator. The next-work allocator (dry-run) selected #607 (Sentry-to-Gitea incident bridge, priority 20) as highest-priority author work, not #671. The controller explicitly overrode that selection to claim #671 first.
WHY: #671 addresses the active repository-integrity incident (direct-to-master commit 2fa97c26 documented on #670, plus the PR #654 merger git push prgs master attempt) and therefore takes precedence over feature work such as #607. Override and reason recorded here in canonical issue state per controller direction.
RELATED_PRS: #654 (merger direct-push attempt evidence); PR for this work to follow with Closes #671
BLOCKERS: none
VALIDATION: Full pytest suite to be run in the issue worktree before PR handoff; guard is pure-logic + durable-state with unit tests for AC5 cases
LAST_UPDATED_BY: author (jcwalker3 / prgs-author)

## Canonical Issue State STATE: ready-for-author (claimed) WHO_IS_NEXT: author NEXT_ACTION: Implement stable-branch push detection, session contamination marker, and fail-closed mutation gates with tests and docs NEXT_PROMPT: Author (jcwalker3 / prgs-author) implements #671 in branches/fix-issue-671-block-stable-branch-push: pure detector for direct stable-branch pushes, durable contamination marker, fail-closed gate on review/merge/close/completion until reconciler audit, AC5 tests, docs; open PR with Closes #671; stop before review/merge. WHAT_HAPPENED: Controller override of the allocator. The next-work allocator (dry-run) selected #607 (Sentry-to-Gitea incident bridge, priority 20) as highest-priority author work, not #671. The controller explicitly overrode that selection to claim #671 first. WHY: #671 addresses the active repository-integrity incident (direct-to-master commit 2fa97c26 documented on #670, plus the PR #654 merger `git push prgs master` attempt) and therefore takes precedence over feature work such as #607. Override and reason recorded here in canonical issue state per controller direction. RELATED_PRS: #654 (merger direct-push attempt evidence); PR for this work to follow with Closes #671 BLOCKERS: none VALIDATION: Full pytest suite to be run in the issue worktree before PR handoff; guard is pure-logic + durable-state with unit tests for AC5 cases LAST_UPDATED_BY: author (jcwalker3 / prgs-author)
jcwalker3 added status:in-progress and removed status:ready labels 2026-07-11 18:54:19 -05:00
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: claim - issue: #671 - branch: fix/issue-671-block-stable-branch-push - phase: claimed - profile: prgs-author - pr: none - blocker: none - next_action: create worktree and begin implementation
jcwalker3 added status:pr-open and removed status:in-progress labels 2026-07-11 19:09:25 -05:00
sysadmin removed the status:pr-open label 2026-07-12 00:51:10 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#671