Skip to content

feat(remediation): free-core governance (request/approve + projected lift)#599

Closed
remyluslosius wants to merge 4 commits into
mainfrom
feat/remediation-governance
Closed

feat(remediation): free-core governance (request/approve + projected lift)#599
remyluslosius wants to merge 4 commits into
mainfrom
feat/remediation-governance

Conversation

@remyluslosius

Copy link
Copy Markdown
Contributor

Remediation governance (free core, AGPLv3) — the see-and-govern loop

First slice of Phase 7 remediation. Operators view what's remediable and the projected per-framework compliance lift, request a fix, and route it through approval — without ever touching a host. The act of mutating a host is a later PR.

  • Migration 0037: remediation_requests + remediation_transactions.
  • internal/remediation: Request/Approve/Reject (forward-only state machine, FOR UPDATE transitions, separation of duties, one-open-per-host+rule) + read-only ProjectLift (per-framework delta from host_rule_state.framework_refs).
  • Free endpoints: list / get / request / approve / reject / steps.
  • Frontend: per-rule "Request remediation" affordance on the Compliance tab; read-only Remediation tab; dev auth-fixture grants + accurate self-review 409 copy.
  • Spec api-remediation, frontend-remediation-tab.

Plan: docs/engineering/remediation_core_plan.md + remediation_licensed_plan.md.

Stacked PRs (merge in order): this is 1 of 3. Followed by admin user-management, then remediation execution.

Scope the Phase 7 remediation feature as an open-core split: the free
AGPL core is the see-and-govern loop (view findings + projected lift,
request, approve, view signed transaction history); the OpenWatch+
licensed side is the act of mutating a host (remediation_execution) and
the fleet auto-remediation engine (remediation_auto).

Ratified: auto-remediation is a licensed feature.
OpenWatch Core (free, AGPLv3) half of Phase 7 remediation: a see-and-govern
loop over failing rules. View what is remediable + the projected per-framework
compliance lift, request a fix, route it through approval. The free path never
contacts a host or mutates host_rule_state/transactions; the act of mutating a
host stays behind the OpenWatch+ remediation_execution license.

Backend:
- Migration 0037: remediation_requests + remediation_transactions (per-step
  Kensa journal, written only by the licensed execute path).
- internal/remediation: Request/Approve/Reject (forward-only state machine,
  FOR UPDATE transitions, separation of duties, one-open-per-host+rule) and a
  read-only ProjectLift (per-framework delta from host_rule_state.framework_refs).
- Free endpoints (list/get/request/approve/reject/steps). Act verbs
  (:dry-run/:execute/:rollback) enforce the dangerous license-gated permission:
  403 (RBAC first), 402 free tier, 501 when licensed (body is OpenWatch+).
- Spec api-remediation (C-01..C-07, AC-01..AC-06).

Frontend:
- useHostRemediations hook; per-failing-rule Request-remediation affordance on
  the Compliance tab (gated on remediation:request, open-state suppressed);
  Remediation tab read panel (request list, projected lift, approve/reject
  gated on remediation:approve, transaction-model explainer) with the host-
  mutating Execute control rendered as a disabled OpenWatch+ upsell.
- Spec frontend-remediation-tab (C-01..C-03, AC-01..AC-03).

Plan: docs/engineering/remediation_core_plan.md + remediation_licensed_plan.md
…copy

- auth-bootstrap dev shim: grant the admin role its remediation:* and
  exception:* permissions so the per-rule Request/Approve affordances render
  in dev (the shim faked a stale admin permission set; production derives the
  full set from the backend). Also adds compliance:read.
- Remediation tab: a 409 on approve/reject now surfaces the backend's specific
  reason. A self-review block (you requested it) reads 'You cannot approve or
  reject your own request' instead of the misleading 'already changed state'.
@github-actions github-actions Bot added documentation Improvements or additions to documentation frontend security tests size/XL labels Jun 18, 2026
Pick up the GA-readiness changes (#602): Specter gate raised to 100% across
all tiers + the structural-coverage gate. specter.yaml auto-merged (remediation
spec registrations + the new tier config are in different regions).
remyluslosius added a commit that referenced this pull request Jun 19, 2026
…k + admin user-mgmt (#601)

Lands the full remediation stack (formerly #599 + #600 + #601) in one squash merge.

- Governance (was #599): request/approve/reject workflow + projected-lift estimate; remediation_requests + remediation_transactions (migration 0037).
- Admin user management (was #600): admin password reset + account disable/enable; users.disabled_at (migration 0038), login rejects disabled accounts, sessions revoked on disable.
- Execution engine (was #601): per-rule Fix + rollback over Kensa v0.5.1 (pkg/kensa.Default Remediate/Rollback), queued RemediationWorker, host-detail Fix button. Single-rule manual execute/rollback is FREE CORE; bulk/auto remediation is the licensed track (license.EnforceFeature(remediation_execution)).

Validated against main's 100% Specter gate (structural + outcome). Two stale-test gaps that #600/#601 never gate-tested (they targeted intermediate stack branches; go-ci only runs on PRs to main) were fixed: system-rbac/AC-07 (remediation:execute is ungated) and api-users/AC-16-18 (per-AC subtest tokens).
@remyluslosius

Copy link
Copy Markdown
Contributor Author

Superseded by #601, which landed the full remediation stack (governance + admin + execution) in a single squash merge to main (commit on main as of 2026-06-19). Closing; this PR's changes are now on main.

@remyluslosius remyluslosius deleted the feat/remediation-governance branch June 19, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation frontend security size/XL tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant