Prevent repository .env files from injecting MCP runtime workspace bindings #704

Open
opened 2026-07-13 14:53:25 -05:00 by jcwalker3 · 1 comment
Owner

Observed reproduction:

  • gitea_auth.py loads PROJECT_ROOT/.env during import.
  • A repository .env containing GITEA_ACTIVE_WORKTREE injected a stale task-specific worktree into every fresh MCP process.
  • GITEA_ACTIVE_WORKTREE outranked role-specific and default workspace selection.
  • Closing IDEs, terminating old processes, and reconnecting could not resolve it because each new process reloaded the stale value.
  • The defect misbound reviewer and reconciler namespaces to review-pr-654 and repeatedly blocked PR #701/#703 review workflows.
  • Operational recovery and sanitized evidence are recorded in Issue #702 comment 11191 and PR #703 comment 11193.

Acceptance criteria:

  1. Repository .env loading cannot populate or override GITEA_ACTIVE_WORKTREE or any role-specific GITEA_*_WORKTREE runtime-binding variable.
  2. Runtime workspace bindings are accepted only from sanctioned managed-launch/session mechanisms.
  3. Pre-existing sanctioned process environment values retain their intended precedence.
  4. Importing gitea_auth or related modules does not mutate workspace-binding state from repository files.
  5. Reserved runtime-control keys found in .env are ignored or rejected with a sanitized actionable reason; their values are never logged.
  6. The protection applies consistently to author, reviewer, merger, and reconciler namespaces.
  7. Tests cover:
    • stale existing worktree;
    • missing/nonexistent worktree;
    • task-specific binding from .env;
    • role-specific binding from .env;
    • sanctioned launcher binding;
    • repeated imports and reconnects;
    • namespace isolation;
    • precedence behavior;
    • absence of secret leakage.
  8. Dirty-state and workspace-preflight gates cannot be bypassed by an injected missing-path binding.
  9. No environment, dotenv, offline-import, or caller-controlled path can forge native transport or mutation provenance.
  10. Cross-link #702, PR #703, #510, and any exact related workspace-binding issue.
  11. State explicitly whether this issue blocks PR #703 or is a required immediate follow-up, based on #702’s acceptance criteria.
**Observed reproduction:** - gitea_auth.py loads PROJECT_ROOT/.env during import. - A repository .env containing GITEA_ACTIVE_WORKTREE injected a stale task-specific worktree into every fresh MCP process. - GITEA_ACTIVE_WORKTREE outranked role-specific and default workspace selection. - Closing IDEs, terminating old processes, and reconnecting could not resolve it because each new process reloaded the stale value. - The defect misbound reviewer and reconciler namespaces to review-pr-654 and repeatedly blocked PR #701/#703 review workflows. - Operational recovery and sanitized evidence are recorded in Issue #702 comment 11191 and PR #703 comment 11193. **Acceptance criteria:** 1. Repository .env loading cannot populate or override GITEA_ACTIVE_WORKTREE or any role-specific GITEA_*_WORKTREE runtime-binding variable. 2. Runtime workspace bindings are accepted only from sanctioned managed-launch/session mechanisms. 3. Pre-existing sanctioned process environment values retain their intended precedence. 4. Importing gitea_auth or related modules does not mutate workspace-binding state from repository files. 5. Reserved runtime-control keys found in .env are ignored or rejected with a sanitized actionable reason; their values are never logged. 6. The protection applies consistently to author, reviewer, merger, and reconciler namespaces. 7. Tests cover: - stale existing worktree; - missing/nonexistent worktree; - task-specific binding from .env; - role-specific binding from .env; - sanctioned launcher binding; - repeated imports and reconnects; - namespace isolation; - precedence behavior; - absence of secret leakage. 8. Dirty-state and workspace-preflight gates cannot be bypassed by an injected missing-path binding. 9. No environment, dotenv, offline-import, or caller-controlled path can forge native transport or mutation provenance. 10. Cross-link #702, PR #703, #510, and any exact related workspace-binding issue. 11. State explicitly whether this issue blocks PR #703 or is a required immediate follow-up, based on #702’s acceptance criteria.
jcwalker3 added the status:readyworkflow-hardeningtype:bugcontamination labels 2026-07-13 14:53:25 -05:00
Author
Owner

CTH: Controller Decision — #704 vs #702/#703 scope & dependency (pre-review)

Status: dependency_decision_recorded; #704 is follow-up_hardening_not_merge_gate_for_703_or_701
Next owner: reviewer (PR #703 formal review), then author for #704 implementation
Current blocker: none for this decision
Decision: See explicit answers below (do not silently defer any #702 AC into #704).
Proof: Issue #702 body ACs; PR #703 body (AC2/AC3 recovery only); Issue #704 body ACs 1–11; comments 11191 (#702) and 11193 (#703).
Next action: Formal PR #703 review judges only #702 ACs; #704 remains separate preventative workstream; PR #701 review may resume after clean runtime + #702/#703 path, not after #704 merge.
Ready-to-paste prompt: see NEXT_PROMPT.

Explicit answers (authoritative for this thread)

1) Dotenv-injection behavior already inside #702 / PR #703 acceptance criteria

Inside #702 / PR #703 (must not be deferred to #704):

  • #702 AC2 — safely clear or re-bind a process-environment stale GITEA_ACTIVE_WORKTREE on auto-reconnect / gitea_resolve_task_capability, regardless of how the value entered os.environ (parent IDE, prior session, or post-import dotenv injection that already became env state).
  • #702 AC2 supporting mechanics in PR #703 — classify binding; clear only for authorized stale classes (provably_stale_missing_path, superseded_by_session_lease); demote missing-path env bindings in resolve_namespace_workspace(verify_paths=…); surface unverified_inherited for managed reconnect (no silent rewrite).
  • #702 AC3 — crash-orphan durable lease shadow / recoverable cleanup after unexpected exit.
  • #702 AC1 — auth crash survival (owned by PR #701 / #699), not dotenv.

Not inside #702 ACs (belongs to #704 only):

  • Blocking repository .env / load_dotenv from populating or overriding GITEA_ACTIVE_WORKTREE or role-specific GITEA_*_WORKTREE at import.
  • Reserved-key ignore/reject at dotenv load with sanitized reasons and no secret logging.
  • “Import of gitea_auth does not mutate workspace-binding state from repository files.”
  • Accepting runtime bindings only from sanctioned managed-launch/session mechanisms (source policy).
  • Dotenv-specific test matrix in #704 AC7 (task-specific / role-specific binding from .env, repeated imports/reconnects under dotenv, etc.).

Rationale: #702’s written ACs are recovery + lease durability. Comments 11191/11193 document dotenv as the operational root-cause source and explicitly call load-path guard follow-up hardening, not a rewrite of #702’s acceptance surface.

2) Must PR #703 change to satisfy #702?

No — not solely because #704 exists, and not solely for dotenv load-path prevention.

  • PR #703 satisfies #702 only by meeting #702’s three ACs (auth is #701; AC2 recovery + AC3 lease recovery are #703).
  • Dotenv injection prevention is not a #702 AC#703 is not required to implement #704’s load-path guard to close #702.
  • PR #703 must still change if formal leased review independently confirms gaps against #702 ACs (including unconfirmed leads F1–F6 on comment 11183 / 11187 when re-derived with evidence). Those remain #703/#702 if they break safe clear/re-bind or lease recovery — do not refile them as #704 merely because #704 is open.
  • Overlap note: a missing-path preflight bypass (F2-class), if reproduced, is a #702/#703 defect under “safely clear or re-bind,” not exclusive #704. #704 AC8 is preventative reinforcement at the injection source and does not absolve #703 of recovery/preflight safety.

3) Remaining hardening exclusive to #704

All of #704 AC1–AC10 preventative/source controls, especially:

  1. Repo .env cannot populate/override workspace-binding vars.
  2. Runtime bindings accepted only from sanctioned managed-launch/session mechanisms.
  3. Pre-existing sanctioned process env precedence preserved.
  4. Import path does not mutate workspace-binding state from repo files.
  5. Reserved keys ignored/rejected with sanitized actionable reason; values never logged.
  6. Applies to author, reviewer, merger, reconciler namespaces.
  7. Dotenv/injection-focused tests (including secret non-leakage).
  8. (Preventative) injection cannot create missing-path bypass at source — still does not move #702 recovery failures off #703.
  9. No dotenv/offline-import/caller path forges native transport or mutation provenance.
  10. Cross-links #702, PR #703, #510, related binding issues.
  11. Answered here: #704 does not block PR #703; it is a required immediate follow-up after operational cleanup (11191/11193), not a substitute for #702 AC completion on PR #703.

4) Must #704 merge before PR #701 review can safely resume?

No.

Gate Required for safe #701 review resume?
Neutral runtime workspace (no review-pr-654 / stale GITEA_ACTIVE_WORKTREE) Yes — operationally restored per 11191/11193
#702 recovery / PR #703 formal review + land Yes for durable crash/stale recovery (prior CTHs gate #701 behind #702/#703 landing); still independent of #704
#704 dotenv load-path guard merged No — follow-up hardening; not a #701 review merge prerequisite

Operator must still avoid reintroducing GITEA_ACTIVE_WORKTREE via .env until #704 lands; that is hygiene + #704 work, not a hard merge gate on #701.

Canonical Issue State

STATE:
dependency-decision-recorded; follow-up-hardening; does-not-block-pr-703; does-not-gate-pr-701-review-merge-order

WHO_IS_NEXT:
reviewer

NEXT_ACTION:
Formal leased review of PR #703 against #702 ACs only; implement #704 separately; do not expand #703 scope to dotenv load-path guard unless a #702 AC fails without it (it should not).

NEXT_PROMPT:

Role: REVIEWER (fresh prgs-reviewer lease) for PR #703; AUTHOR later for #704
Repo: prgs / Scaled-Tech-Consulting / Gitea-Tools

PR #703 review scope = Issue #702 ACs only:
- AC2: stale GITEA_ACTIVE_WORKTREE clear/re-bind + missing-path demotion + managed reconnect for unverified_inherited
- AC3: crash-orphan lease recovery
- Re-derive F1–F6 as #702/#703 findings only if independently reproduced; do not defer true #702 gaps to #704
- Do NOT require dotenv load_dotenv guard for APPROVE of #703

#704 remains open for preventative dotenv injection hardening (AC1–10).
#701 review resume: requires clean runtime + #702/#703 path; does NOT require #704 merged.

WHAT_HAPPENED:
Pre-review dependency analysis of #704 against #702 ACs, PR #703, and comments 11191/11193. Boundary recorded so #702 acceptance cannot be silently deferred into #704.

WHY:
#704 AC11 requires an explicit block-vs-follow-up statement; #702 ACs must remain enforceable on PR #703.

RELATED_PRS:
PR #703 (Closes #702); PR #701 (#699; resume gate is #702/#703 + clean runtime, not #704).

BLOCKERS:
none for this decision

VALIDATION:

  • #702 body: three ACs (auth / clear-or-rebind env / lease recovery) — no dotenv load-path language
  • PR #703: recovery + lease modules; explicit non-goals exclude guessed rebind; no dotenv guard claimed
  • #704 body: import/dotenv injection ACs + AC11 dependency question
  • 11191/11193: operational .env cleanup complete; follow-up hardening required; no blocker for #703 review path

LAST_UPDATED_BY:
controller dependency decision (jcwalker3 / prgs-author)

## CTH: Controller Decision — #704 vs #702/#703 scope & dependency (pre-review) Status: dependency_decision_recorded; #704 is follow-up_hardening_not_merge_gate_for_703_or_701 Next owner: reviewer (PR #703 formal review), then author for #704 implementation Current blocker: none for this decision Decision: See explicit answers below (do not silently defer any #702 AC into #704). Proof: Issue #702 body ACs; PR #703 body (AC2/AC3 recovery only); Issue #704 body ACs 1–11; comments 11191 (#702) and 11193 (#703). Next action: Formal PR #703 review judges only #702 ACs; #704 remains separate preventative workstream; PR #701 review may resume after clean runtime + #702/#703 path, not after #704 merge. Ready-to-paste prompt: see NEXT_PROMPT. ### Explicit answers (authoritative for this thread) #### 1) Dotenv-injection behavior already inside #702 / PR #703 acceptance criteria **Inside #702 / PR #703 (must not be deferred to #704):** - **#702 AC2** — safely clear or re-bind a *process-environment* stale `GITEA_ACTIVE_WORKTREE` on auto-reconnect / `gitea_resolve_task_capability`, **regardless of how the value entered `os.environ`** (parent IDE, prior session, **or** post-import dotenv injection that already became env state). - **#702 AC2 supporting mechanics in PR #703** — classify binding; clear only for authorized stale classes (`provably_stale_missing_path`, `superseded_by_session_lease`); demote missing-path env bindings in `resolve_namespace_workspace(verify_paths=…)`; surface `unverified_inherited` for managed reconnect (no silent rewrite). - **#702 AC3** — crash-orphan durable lease shadow / recoverable cleanup after unexpected exit. - **#702 AC1** — auth crash survival (owned by PR #701 / #699), not dotenv. **Not inside #702 ACs (belongs to #704 only):** - Blocking repository `.env` / `load_dotenv` from *populating or overriding* `GITEA_ACTIVE_WORKTREE` or role-specific `GITEA_*_WORKTREE` at import. - Reserved-key ignore/reject at dotenv load with sanitized reasons and no secret logging. - “Import of `gitea_auth` does not mutate workspace-binding state from repository files.” - Accepting runtime bindings *only* from sanctioned managed-launch/session mechanisms (source policy). - Dotenv-specific test matrix in #704 AC7 (task-specific / role-specific binding *from .env*, repeated imports/reconnects under dotenv, etc.). Rationale: #702’s written ACs are **recovery + lease durability**. Comments 11191/11193 document dotenv as the **operational root-cause source** and explicitly call load-path guard **follow-up hardening**, not a rewrite of #702’s acceptance surface. #### 2) Must PR #703 change to satisfy #702? **No — not solely because #704 exists, and not solely for dotenv load-path prevention.** - PR #703 satisfies #702 only by meeting #702’s three ACs (auth is #701; AC2 recovery + AC3 lease recovery are #703). - **Dotenv injection prevention is not a #702 AC** → #703 is **not** required to implement #704’s load-path guard to close #702. - PR #703 **must still change** if formal leased review independently confirms gaps against **#702** ACs (including unconfirmed leads F1–F6 on comment 11183 / 11187 when re-derived with evidence). Those remain **#703/#702** if they break safe clear/re-bind or lease recovery — **do not refile them as #704** merely because #704 is open. - Overlap note: a **missing-path preflight bypass** (F2-class), if reproduced, is a **#702/#703** defect under “safely clear or re-bind,” not exclusive #704. #704 AC8 is preventative reinforcement at the injection source and does **not** absolve #703 of recovery/preflight safety. #### 3) Remaining hardening exclusive to #704 All of #704 AC1–AC10 preventative/source controls, especially: 1. Repo `.env` cannot populate/override workspace-binding vars. 2. Runtime bindings accepted only from sanctioned managed-launch/session mechanisms. 3. Pre-existing sanctioned process env precedence preserved. 4. Import path does not mutate workspace-binding state from repo files. 5. Reserved keys ignored/rejected with sanitized actionable reason; values never logged. 6. Applies to author, reviewer, merger, reconciler namespaces. 7. Dotenv/injection-focused tests (including secret non-leakage). 8. (Preventative) injection cannot create missing-path bypass *at source* — still does not move #702 recovery failures off #703. 9. No dotenv/offline-import/caller path forges native transport or mutation provenance. 10. Cross-links #702, PR #703, #510, related binding issues. 11. **Answered here:** #704 does **not** block PR #703; it is a **required immediate follow-up** after operational cleanup (11191/11193), not a substitute for #702 AC completion on PR #703. #### 4) Must #704 merge before PR #701 review can safely resume? **No.** | Gate | Required for safe #701 review resume? | |------|----------------------------------------| | Neutral runtime workspace (no `review-pr-654` / stale `GITEA_ACTIVE_WORKTREE`) | **Yes** — operationally restored per 11191/11193 | | #702 recovery / PR #703 formal review + land | **Yes for durable crash/stale recovery** (prior CTHs gate #701 behind #702/#703 landing); still independent of #704 | | #704 dotenv load-path guard merged | **No** — follow-up hardening; not a #701 review merge prerequisite | Operator must still avoid reintroducing `GITEA_ACTIVE_WORKTREE` via `.env` until #704 lands; that is hygiene + #704 work, not a hard merge gate on #701. ## Canonical Issue State STATE: dependency-decision-recorded; follow-up-hardening; does-not-block-pr-703; does-not-gate-pr-701-review-merge-order WHO_IS_NEXT: reviewer NEXT_ACTION: Formal leased review of PR #703 against #702 ACs only; implement #704 separately; do not expand #703 scope to dotenv load-path guard unless a #702 AC fails without it (it should not). NEXT_PROMPT: ```text Role: REVIEWER (fresh prgs-reviewer lease) for PR #703; AUTHOR later for #704 Repo: prgs / Scaled-Tech-Consulting / Gitea-Tools PR #703 review scope = Issue #702 ACs only: - AC2: stale GITEA_ACTIVE_WORKTREE clear/re-bind + missing-path demotion + managed reconnect for unverified_inherited - AC3: crash-orphan lease recovery - Re-derive F1–F6 as #702/#703 findings only if independently reproduced; do not defer true #702 gaps to #704 - Do NOT require dotenv load_dotenv guard for APPROVE of #703 #704 remains open for preventative dotenv injection hardening (AC1–10). #701 review resume: requires clean runtime + #702/#703 path; does NOT require #704 merged. ``` WHAT_HAPPENED: Pre-review dependency analysis of #704 against #702 ACs, PR #703, and comments 11191/11193. Boundary recorded so #702 acceptance cannot be silently deferred into #704. WHY: #704 AC11 requires an explicit block-vs-follow-up statement; #702 ACs must remain enforceable on PR #703. RELATED_PRS: PR #703 (Closes #702); PR #701 (#699; resume gate is #702/#703 + clean runtime, not #704). BLOCKERS: none for this decision VALIDATION: - #702 body: three ACs (auth / clear-or-rebind env / lease recovery) — no dotenv load-path language - PR #703: recovery + lease modules; explicit non-goals exclude guessed rebind; no dotenv guard claimed - #704 body: import/dotenv injection ACs + AC11 dependency question - 11191/11193: operational .env cleanup complete; follow-up hardening required; no blocker for #703 review path LAST_UPDATED_BY: controller dependency decision (jcwalker3 / prgs-author)
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#704