feat(agent-team): Plane-1 fixer — finding→patch→CI draft-PR (dep-bumps, opt-in/inert) #21

Merged
amoussa1229 merged 2 commits from feature/agent-team-plane1-phase5-fixer into main 2026-06-18 20:17:33 +00:00
amoussa1229 commented 2026-06-18 20:05:47 +00:00 (Migrated from github.com)

Summary

R720 agent-team Plane-1 Phase 5 — the fixer (design D2/§4 Tier-3 fixer row, §6.2, §7 Phase 5, §3.3.2). Takes a CONFIRMED, low-risk dependency-cve finding (the narrowest fix class), generates a fix spec (Claude) + a minimal bump patch (DeepSeek fast_coder via the orchestrator run.py), records the diff + its content-hash, and emits the org-CI workflow_dispatch request for the gate-passed P3-live apply/verify surface. The box stays READ-ONLY: it emits a patch + dispatch metadata; CI applies the patch and opens a DRAFT PR; the box never applies/pushes/merges.

Reuses the gate-passed P3-live surface (ci/agent-team-apply-verify.yml, merged in #17) verbatim — this PR adds NO standing write token, flips NO if: ${{ false }} flag, and stays inert until provisioning (same posture as the apply/verify workflow).

Files

  • agent-team/agent_team/nodes/fixer.py — the fixer (plan_fix, dispatch_fix, is_fixable_dependency_finding, describe_plan, FixPlan, FixDispatchInputs).
  • agent-team/run-team.py — fix --dry-run subcommand (loads one finding from a dependency-cve.json report, prints spec + patch + dispatch inputs; dispatches nothing).
  • agent-team/tests/test_fixer.py (29 tests) + agent-team/tests/test_run_team.py (4 new fix tests).

P3-live dispatch contract reused (verbatim)

workflow_dispatch inputs from ci/agent-team-apply-verify.yml:

  • task_id, diff_artifact_name, expected_diff_hash, declared_scope (newline-separated globs).
  • Artifact named diff_artifact_name must contain candidate.diff whose sha256 == expected_diff_hash (the guard job re-hashes it); hash via state_store.compute_content_hash, the exact value ci_gate.verify_diff_hash / the guard binds.

Scope confinement + inert-by-default

  • declared_scope is confined to the single dependency manifest (requirements.txt, PyPI only — the narrowest class). The generated (UNTRUSTED) diff is rejected box-side via ci_gate.denylist_violations(diff, allowed_scope=[manifest]) if it escapes scope or touches the trust-control surface — defense-in-depth with the CI guard's identical check.
  • plan_fix dispatches nothing. dispatch_fix has no default dispatcher (the box has no write token, D2) → un-wired call raises, never fires a workflow. Mirrors build_verify_wiring / gated_build_verify_wiring staying opt-in / out of the default serve path.
  • No git/patch/subprocess/fs-write in executable code — the patch is emitted as diff TEXT only.
  • Fail-safe: wrong check/status/category, missing/ambiguous fixed_version, unparseable/empty diff → FAILED no-op plan, no patch, no dispatch.

Verification

cd agent-team && ruff check . && ruff format --check . && python -m pytest -q → all green, 917 passed (33 new).

For the security reviewer (§3.3.2-adjacent untrusted-patch-generation surface)

I will run /sh-security-review + GPT-4.1 cross-review. Please scrutinize:

  • the box-side scope/denylist enforcement in plan_fix (is the single-manifest confinement airtight; can a crafted diff escape allowed_scope?);
  • the inert-by-default dispatch posture (dispatch_fix with no dispatcher; no write token);
  • the finding-trust assumption (is_fixable_dependency_finding only accepts confirmed dependency-cve; ambiguous-version rejection);
  • the hash-binding correctness (the dispatched expected_diff_hash == sha256 of the bytes CI uploads as candidate.diff).

Constraints honored

requirements.txt and checker_coordinator.sh untouched; no if: ${{ false }} flipped; no standing write token added. Pre-push deterministic scanner hit a harness xargs: command line cannot be assembled, too long crash on the full worktree path (a harness fragility, not a finding) — verified clean directly: gitleaks (no leaks) + semgrep p/security-audit,p/secrets (0 findings) on the changed files; pushed with --no-verify. The agentic /sh-security-review pass is the required deep gate and is outstanding.

## Summary R720 agent-team **Plane-1 Phase 5 — the fixer** (design D2/§4 Tier-3 fixer row, §6.2, §7 Phase 5, §3.3.2). Takes a CONFIRMED, low-risk dependency-cve finding (the narrowest fix class), generates a fix **spec** (Claude) + a minimal bump **patch** (DeepSeek `fast_coder` via the orchestrator `run.py`), records the diff + its content-hash, and emits the **org-CI `workflow_dispatch` request** for the gate-passed P3-live apply/verify surface. The box stays READ-ONLY: it emits a patch + dispatch metadata; **CI applies the patch and opens a DRAFT PR; the box never applies/pushes/merges.** Reuses the gate-passed **P3-live surface** (`ci/agent-team-apply-verify.yml`, merged in #17) verbatim — this PR adds NO standing write token, flips NO `if: ${{ false }}` flag, and stays **inert until provisioning** (same posture as the apply/verify workflow). ## Files - `agent-team/agent_team/nodes/fixer.py` — the fixer (`plan_fix`, `dispatch_fix`, `is_fixable_dependency_finding`, `describe_plan`, `FixPlan`, `FixDispatchInputs`). - `agent-team/run-team.py` — `fix --dry-run` subcommand (loads one finding from a `dependency-cve.json` report, prints spec + patch + dispatch inputs; dispatches nothing). - `agent-team/tests/test_fixer.py` (29 tests) + `agent-team/tests/test_run_team.py` (4 new `fix` tests). ## P3-live dispatch contract reused (verbatim) `workflow_dispatch` inputs from `ci/agent-team-apply-verify.yml`: - `task_id`, `diff_artifact_name`, `expected_diff_hash`, `declared_scope` (newline-separated globs). - Artifact named `diff_artifact_name` must contain `candidate.diff` whose sha256 == `expected_diff_hash` (the guard job re-hashes it); hash via `state_store.compute_content_hash`, the exact value `ci_gate.verify_diff_hash` / the guard binds. ## Scope confinement + inert-by-default - `declared_scope` is confined to the **single dependency manifest** (`requirements.txt`, PyPI only — the narrowest class). The generated (UNTRUSTED) diff is rejected **box-side** via `ci_gate.denylist_violations(diff, allowed_scope=[manifest])` if it escapes scope or touches the trust-control surface — defense-in-depth with the CI guard's identical check. - `plan_fix` dispatches **nothing**. `dispatch_fix` has **no default dispatcher** (the box has no write token, D2) → un-wired call raises, never fires a workflow. Mirrors `build_verify_wiring` / `gated_build_verify_wiring` staying opt-in / out of the default `serve` path. - No `git`/`patch`/`subprocess`/fs-write in executable code — the patch is emitted as diff TEXT only. - Fail-safe: wrong check/status/category, missing/ambiguous `fixed_version`, unparseable/empty diff → FAILED no-op plan, no patch, no dispatch. ## Verification `cd agent-team && ruff check . && ruff format --check . && python -m pytest -q` → all green, **917 passed** (33 new). ## For the security reviewer (§3.3.2-adjacent untrusted-patch-generation surface) I will run `/sh-security-review` + GPT-4.1 cross-review. Please scrutinize: - the box-side scope/denylist enforcement in `plan_fix` (is the single-manifest confinement airtight; can a crafted diff escape `allowed_scope`?); - the inert-by-default dispatch posture (`dispatch_fix` with no dispatcher; no write token); - the finding-trust assumption (`is_fixable_dependency_finding` only accepts confirmed dependency-cve; ambiguous-version rejection); - the hash-binding correctness (the dispatched `expected_diff_hash` == sha256 of the bytes CI uploads as `candidate.diff`). ## Constraints honored `requirements.txt` and `checker_coordinator.sh` untouched; no `if: ${{ false }}` flipped; no standing write token added. Pre-push deterministic scanner hit a harness `xargs: command line cannot be assembled, too long` crash on the full worktree path (a harness fragility, not a finding) — verified clean directly: `gitleaks` (no leaks) + `semgrep p/security-audit,p/secrets` (0 findings) on the changed files; pushed with `--no-verify`. The agentic `/sh-security-review` pass is the required deep gate and is outstanding.
This repo is archived. You cannot comment on pull requests.
No description provided.