11.3 Review campaigns and remediation work items
packs:security-governance
After this you can: open a review campaign, decide each item, let a revoke open remediation work, close the campaign into the ledger, and set a cadence.
Before you start — tick each one:
- Lesson 11.2 — Controls and the evidence ledger (
opschain learn 11.2)
In the GUI: Governance → Reviews → the Campaigns tab — review campaigns (open, decide, close into an attestation); the posture report is opschain governance posture.
A campaign turns a point-in-time dataset into a governed sign-off:
items, each with a reviewer and a decision, closing into a ledger
attestation. The first shipped campaign content is the access
review — "who can do what, reviewed quarterly" — with every revoke
decision opening a named remediation work item instead of silently
auto-revoking. The model reference is opschain docs governance.
Licence entitlement. The campaign machinery is base platform, but a campaign with no items cannot close, and item sourcing is pack content: the access-review kind requires
packs:security-governance(seeopschain docs entitlements). Work items stay base — an entitlement lapse never hides open remediation work.Who can do this. Opening campaigns and configuring cadences are admin-plane acts. Reviewing is user-plane: a reviewer is an ordinary user with a path-RBAC grant on
/governance/campaigns(readable: reads; updatable: decisions and closure), and work items ride/governance/work_itemsthe same way. Decisions, closure and work-item completion sit on the step-up floor (opschain learn 7.4).
1. Open an access review
The access-review campaign sources its items server-side from the
live access dataset: every grant at the per-identity (rule × principal)
grain, every superuser/block assignment, and both token inventories —
each item carrying a provider-badged, point-in-time subject_summary
the reviewer decides on, so the campaign reviews a snapshot that cannot
drift with the live rows. As an admin:
opschain admin governance campaigns open-access-review \
--control access-governance --reviewer thomas --due 2026-11-30T00:00:00Z
opened access-review campaign 01a2f8a0-1c2d-7e3f-8a4b-5c6d7e8f9a0b with 14 sourced item(s) — due 2026-11-30T00:00:00Z
opschain governance campaigns list --status open
ID CONTROL KIND STATUS OPENED AT DUE AT ITEMS
01a2f8a0-1c2d-7e3f-8a4b-5c6d7e8f9a0b 01a2f0e2-… access_review open 2026-10-27T10:20:00Z 2026-11-30T00:00:00Z 14
(The cited control must exist — create it first as in lesson 11.2. A
generic campaign of your own items uses opschain admin governance campaigns open --control <key> --kind <kind> --item '<subject-kind>:<subject-id>[:<reviewer>]'. In the GUI both opens sit
on Governance → Reviews & approvals → Campaigns: Open access review,
and Open campaign for any other kind — the control, the kind, an
optional due time, and the items typed row by row or pasted one per line
in the same subject-kind:subject-id[:reviewer] form.)
2. Decide the items
As thomas (the reviewer, elevated), walk the items and record
decisions in the shared approval grammar — retain, revoke or
flag:
opschain governance campaigns show <campaign-id>
id: 01a2f8a0-1c2d-7e3f-8a4b-5c6d7e8f9a0b
control: 01a2f0e2-…
kind: access_review
status: open
opened at: 2026-10-27T10:20:00Z
due at: 2026-11-30T00:00:00Z
ITEM SUBJECT REVIEWER DECISION DECIDED BY SUMMARY
01a2f8a1-… grant:01a2e1b0-… thomas - - policy "LimeBank operators" grants jessica (ldap:corp) read, update on /projects/limebank/environments/prod
01a2f8a2-… api_token:01a2e2c0-… thomas - - api token for contractor-ci (CI pipeline), expires 2027-01-01T00:00:00Z
opschain governance campaigns decide <campaign-id> <item-id> --decision retain
decision recorded — item 01a2f8a1-…: retain
opschain governance campaigns decide <campaign-id> <item-id-2> --decision revoke \
--comment "contractor offboarded 2026-09"
decision recorded — item 01a2f8a2-…: revoke
remediation work item 01a2f8b0-…: Revoke api_token 01a2e2c0-… (open)
A revoke does not auto-revoke: in the decision's own transaction
it opens a named work item carrying the subject's snapshot summary —
one per campaign item, however often the decision is re-recorded.
3. Remediate — the work items
The operator remediates by hand (delete the grant, revoke the token), then records it:
opschain governance work-items list --status open
ID NAME STATUS CAMPAIGN SUBJECT CLOSED BY
01a2f8b0-… Revoke api_token 01a2e2c0-… open 01a2f8a0-… api_token:01a2e2c0-… -
opschain governance work-items complete <work-item-id> \
--notes "revoked api token tok_7f2; removed limegrid operator grant"
work item 01a2f8b0-… completed by thomas
A completed item refuses a second completion rather than overwriting the recorded notes. Work items are deliberately base — no pack gate ever hides open remediation.
4. Close into the ledger
A fully-decided campaign closes into the evidence ledger: all-retain
closes verified; any revoke or flag closes verified_with_exceptions
— the closing attestation cites the campaign:
opschain governance campaigns close <campaign-id> --notes "Q4 access review"
campaign 01a2f8a0-1c2d-7e3f-8a4b-5c6d7e8f9a0b closed — attestation seq 42 (sha256:6d2f…b0e9)
opschain governance evidence list --limit 5
A campaign with undecided items refuses to close: nothing was reviewed, so nothing can honestly be attested.
5. Put it on a cadence
A cadence is "this control is reviewed every N": a 5-field cron schedule on the scheduler leader tick. A due cadence opens a campaign of its kind and advances; while the previous campaign is still open the schedule advances without opening a duplicate:
opschain admin governance cadences create --control access-governance \
--schedule "0 2 1 */3 *" --campaign-kind access_review --grace 604800
created cadence 01a2f8c0-… on control 01a2f0e2-… — next due 2027-01-01T02:00:00Z
opschain admin governance cadences list
ID CONTROL SCHEDULE CAMPAIGN KIND GRACE NEXT DUE ENABLED
01a2f8c0-… 01a2f0e2-… 0 2 1 */3 * access_review 604800s 2027-01-01T02:00:00Z yes
In the GUI the cadences live on Governance → Reviews & approvals → Cadences (administrators): New cadence, each row's Edit and its Enabled switch, beside the next due time and the latest campaign the cadence opened. The dialog's Schedule field does not assume you know cron: pick a preset, or build the schedule in words — "Every quarter on day 1 at 02:00", "Every year on day 1 of January at 09:00", "Every week on Mon at 09:00" — and the cron expression it produces is shown beside the sentence; the Expression view takes a typed expression for anything the builder cannot say.
An open campaign past its due time plus the grace draws the loud
warn:review_cadences:lapsed event once — overdue reviews are
themselves compliance evidence:
opschain audit --type warn:review_cadences:lapsed
Two campaign kinds source their items server-side when a cadence fires:
access_review (the live access-review dataset, above) and
secret_rotation — "secrets are rotated every N, attested": the items
are the vault's secret paths at firing time (paths only, values are
never read), one per node, for the reviewers to attest rotation on:
opschain admin governance cadences create --control secret-rotation \
--schedule "0 3 1 * *" --campaign-kind secret_rotation --grace 604800
Check yourself
- What does a
revokedecision create in the same transaction, and what verdict does the closing attestation carry when any item was revoked? Then: what does the campaign refuse while an item is undecided?
What you learned
- Campaigns review a server-sourced snapshot; decisions are the shared
approval grammar (
audit:review_campaigns:approve|reject|flag), and closure appends a verdict-bearing attestation to the ledger. - Revoke opens a named work item — remediation is an explicit, recorded operator act, and the work-item surfaces never hide behind a pack.
- Cadences ride the scheduler leader tick, fire exactly once, never stack duplicates, and lapse loudly.
Next: lesson 11.4 — Notification mandates and delivery evidence (opschain learn 11.4), or back to your track (opschain learn).