provisioning-catalog/playbooks/offboard_operator/playbook.ncl

77 lines
2.9 KiB
Text

let pb = import "schemas/lib/playbook.ncl" in
pb.make_playbook {
id = "offboard_operator",
name = "Offboard Operator",
description = "Revokes NATS JWT credential, proposes delegation removal patch on policy-<workspace> repo signed by remaining quorum. After completion the operator cannot sign ops commands.",
version = 1,
preconditions = [
"Identify operator by name and Radicle DID",
"Remaining quorum (after removal) still meets the threshold for the workspace",
"Any pending ops signed by this operator should be reviewed before offboarding",
],
params = [
{ name = "workspace", description = "Target workspace", required = true, default_val = "" },
{ name = "operator_name", description = "Name matching onboard record", required = true, default_val = "" },
{ name = "operator_did", description = "Radicle DID of the operator to remove", required = true, default_val = "" },
{ name = "reason", description = "Offboarding reason (recorded in audit)", required = false, default_val = "voluntary" },
],
steps = [
{
id = "revoke_nats_credential",
name = "Revoke operator NATS JWT credential",
script = "steps/revoke_nats_credential.nu",
dry_run_arg = "--dry-run",
on_error = 'Stop,
depends_on = [],
},
{
id = "propose_delegation_removal",
name = "Propose delegation removal from policy-<workspace> repo",
script = "steps/propose_delegation_removal.nu",
dry_run_arg = "--dry-run",
on_error = 'Stop,
depends_on = ["revoke_nats_credential"],
},
{
id = "sign_removal_patch",
name = "Await remaining quorum signatures on removal patch",
script = "steps/sign_removal_patch.nu",
dry_run_arg = "--dry-run",
on_error = 'Stop,
depends_on = ["propose_delegation_removal"],
},
{
id = "verify_operator_cannot_sign",
name = "Verify revoked operator credential is rejected",
script = "steps/verify_operator_blocked.nu",
dry_run_arg = "--dry-run",
on_error = 'Continue,
depends_on = ["sign_removal_patch"],
},
{
id = "emit_audit",
name = "Emit operator-offboard audit event",
script = "steps/emit_audit.nu",
params = { event_type = "operator_offboard" },
dry_run_arg = "--dry-run",
on_error = 'Continue,
depends_on = ["sign_removal_patch"],
},
],
rollback_strategy = 'manual,
success_criteria = [
"Operator NATS JWT credential is revoked (NATS rejects connection attempts)",
"Operator DID removed from policy-<workspace> delegation set",
"Test sign attempt with revoked credential returns 403",
"ops history shows operator-offboard audit event",
],
emit_audit = true,
adr_refs = ["adr-037", "adr-038"],
}