78 lines
2.9 KiB
Text
78 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"],
|
||
|
|
}
|