Skip to content

feat(remediation): conditional approval (A-keep) — free-core auto-approves#606

Closed
remyluslosius wants to merge 1 commit into
mainfrom
feat/remediation-conditional-approval
Closed

feat(remediation): conditional approval (A-keep) — free-core auto-approves#606
remyluslosius wants to merge 1 commit into
mainfrom
feat/remediation-conditional-approval

Conversation

@remyluslosius

Copy link
Copy Markdown
Contributor

Conditional approval (A-keep): free-core remediation auto-approves

Implements the A-keep ADR (PR #604). Free-core single-rule remediation no longer requires a separate human approval, so a single operator can request and Fix a finding directly — removing the self-review deadlock (you could request a fix but never approve your own request, getting a 409 self_review).

Change

  • remediation.Request(…, requiresApproval bool):
    • false (free core) — inserts the request directly in approved (reviewed_at set, reviewed_by NULL, an auto-approved review_note) and emits remediation.requested + remediation.approved. The operator clicks Fix; no approval step.
    • true (licensed bulk/auto track) — inserts pending_approval and goes through Approve/Reject with separation of duties, exactly as before.
  • The single-rule request handler passes false.

Retained for the licensed track

The whole governance machinery (request → approve/reject, self-review guard, the endpoints, the frontend approve/reject UI) is unchanged — it's what the OpenWatch+ bulk/auto track will use.

No migration, no frontend change

The request status drives the UI, which already renders approved → Fix and keeps the pending_approval/approve UI for the licensed track. The hook's source-inspection tests are unaffected.

Tests

  • Service AC-01 now covers both auto-approve (free core) and the approval-required path.
  • HTTP AC-05/AC-06 seed a pending_approval request directly (the free-core POST auto-approves) to keep exercising the approve endpoint + the pending-execute 409 path.

Verified locally

Full remediation + worker + server suite green (exit 0); Specter 110 specs valid, 100% structural coverage; gofmt clean.

Cross-PR: the ADR + governance docs are in #604. This PR implements that ADR; #604's "Implementation pending" status flips to done once both land. Independent of #605 (401 auth fix).

…roves

Implements the A-keep ADR: free-core single-rule remediation no longer requires
a separate human approval, so a single operator can request and Fix a finding
directly (removing the self-review deadlock). The approve/reject flow with
separation of duties is retained for the licensed bulk/auto track.

- Request(...requiresApproval bool): false (free core) inserts an 'approved'
  row directly (reviewed_at set, reviewed_by NULL, auto-approved review_note)
  and emits remediation.requested + remediation.approved; true (licensed
  bulk/auto) inserts 'pending_approval' and goes through Approve/Reject.
- The single-rule request handler passes false.
- Tests: AC-01 covers auto-approve + the approval-required path; the HTTP
  AC-05/AC-06 approve and pending-execute paths seed a pending_approval request
  (the free-core POST auto-approves). Frontend unchanged (the hook already
  renders approved -> Fix and keeps the pending_approval/approve UI for the
  licensed track).

Note: the ADR + governance docs land in #604; their status flips to
'implemented' once both merge.
@remyluslosius

Copy link
Copy Markdown
Contributor Author

Folded into #609 (release: bundle 0.2.0-rc.11) and merged there to avoid the CHANGELOG rebase cascade. Content is on main.

@remyluslosius remyluslosius deleted the feat/remediation-conditional-approval branch June 20, 2026 04:04
remyluslosius added a commit that referenced this pull request Jun 20, 2026
… 110) (#610)

- CLAUDE.md: Last Updated 2026-06-20; Remediation row -> Complete (#601/#606/#607);
  scanning-status note -> v0.2.0-rc.11 incl. free-core remediation; spec count 108 -> 110
- BACKLOG.md: drop done rows (Remediation tab, specter 100%-all-tiers, -p 1 -> -p 4)
- scan_remaining_work.md: Phase 7 first-slice shipped banner; remaining = licensed track
- SESSION_LOG.md: 2026-06-20 entry (rc.11 cut, bundle mechanics, gotchas)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant