"""Regenerate examples/bounded-execution-admission/ and the human-intrinsic invalid fixture (NK-WP-0056-T01). Pins the named files at the current commit and computes plan_digest. Run after changing those files or the schema. """ import hashlib, json, pathlib, subprocess, sys, yaml ROOT = pathlib.Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT / "tools/bounded-execution-admission")) import validate as V commit = subprocess.run(["git", "-C", str(ROOT), "rev-parse", "--short=12", "HEAD"], capture_output=True, text=True).stdout.strip() def pin(*paths): return [{"path": p, "sha256": hashlib.sha256((ROOT / p).read_bytes()).hexdigest()} for p in paths] def sha(p): return hashlib.sha256((ROOT / p).read_bytes()).hexdigest() JOURNEY = "sso-mfa/k8s/synthetic-journey/journey.py" LANE = "tools/service-binds/bind-lane.py" RUNNER = "bounded-executor/executor.py" PILOT_OPS = "bounded-executor/operations.py" SPLIT = "sso-mfa/k8s/lldap/bind-split.py" COMMON = { "approval": {"approvers": ["admin"], "principal_type": "HUMAN", "assurance": "aal2", "carriers": ["approval-engine", "founder-ssh-signature"]}, "consumption": {"single_use": True, "consume_before_first_step": True}, "receipt": {"schema": "netkingdom.playbook-capability-contract/v0.2#execution-attribution-receipt", "emit_to": "audit-core", "retain": "by-hash-no-secret-values", "independent_verifier": "tools/bounded-execution-admission/validate.py check-approval + receipt source hashes"}, } EXECUTOR = {"identity": "service:nk-bind-executor", "principal_type": "WORKLOAD", "runtime": "k8s sso/serviceaccount nk-bind-executor (planned, NK-WP-0056-T03)"} P = ["PRODUCTION"] def check(cid, desc, ref, timeout, settle=0): c = {"id": cid, "description": desc, "ref": ref, "sha256": sha(ref), "timeout_seconds": timeout, "expect": "pass"} if settle: c["settle_seconds"] = settle return c def doc(id_, title, purpose, risk, window, ceiling, radius, files, steps, reverts, checks, policy, budget, not_auth, trust=("runtime_secret_trust", "runtime_identity_trust")): spec = {"id": id_, "title": title, "purpose": purpose, "work_ref": "NK-WP-0056-T01 example", "risk_class": risk, "window": window, **{"approval": COMMON["approval"]}, "executor": EXECUTOR, "scope_ceiling": ceiling, "blast_radius": radius, "trust_requires": list(trust), "plan": {"source": {"repo": "net-kingdom", "commit": commit, "files": pin(*files)}, "steps": steps, **({"revert_steps": reverts} if reverts else {})}, "plan_digest": "", "checks": checks, "stop_and_revert": policy, "budget": budget, "consumption": COMMON["consumption"], "receipt": COMMON["receipt"], "not_authorized": not_auth} d = {"apiVersion": "netkingdom.io/bounded-execution-admission/v0.1", "kind": "BoundedExecutionAdmission", "spec": spec} spec["plan_digest"] = V.plan_digest(d) return d def step(id_, op, target, consumer, cls, mutates, mode, scope, checks=None, revert=None, irreversible=None): s = {"id": id_, "operation": op, "target": target, "consumer": consumer, "class": cls, "mutates": mutates, "requires": {"mode": mode, "scope": scope}} if checks: s["checks_after"] = checks if revert: s["revert"] = revert if irreversible: s["irreversible"] = True return s KV = "openbao/platform/workloads/net-kingdom/directory-binds/svc-authelia" rotation = doc( "BEA-2026-0001", "Rotate the svc-authelia directory bind (bind-split steps 5-8, one consumer)", "Pilot shape for NK-WP-0056-T06: generate a new bind password into OpenBao, set it in LLDAP, let ESO deliver it, restart Authelia, prove sign-in with the synthetic journey; revert on any failed check.", "medium", {"not_before": "2026-11-03T09:00:00Z", "not_after": "2026-11-03T11:00:00Z"}, [{"mode": "OPERATE", "scope": KV, "environments": P}, {"mode": "OPERATE", "scope": "lldap/people/svc-authelia", "environments": P}, {"mode": "OPERATE", "scope": "k8s/sso/externalsecret/authelia-secrets", "environments": P}, {"mode": "OPERATE", "scope": "k8s/sso/deployment/authelia", "environments": P}], {"unit": "consumer", "consumers": ["authelia"], "max_concurrent": 1}, [RUNNER, PILOT_OPS, JOURNEY], [step("generate", "openbao.kv.write-next-version", "openbao:" + KV[len("openbao/"):], "authelia", "delegable", True, "OPERATE", KV, ["kv-advanced"], "restore-kv"), step("set-directory", "lldap.user.change-own-password-from-kv", "lldap:svc-authelia", "authelia", "delegable", True, "OPERATE", "lldap/people/svc-authelia", ["bind-signs-in"], "restore-directory"), step("deliver", "eso.force-sync", "k8s:sso/externalsecret/authelia-secrets", "authelia", "delegable", True, "OPERATE", "k8s/sso/externalsecret/authelia-secrets", ["eso-synced"], "redeliver"), step("restart", "k8s.rollout-restart", "k8s:sso/deployment/authelia", "authelia", "delegable", True, "OPERATE", "k8s/sso/deployment/authelia", ["synthetic-journey"], "restart-again")], [step("restore-kv", "openbao.kv.write-previous-value-as-next-version", "openbao:" + KV[len("openbao/"):], "authelia", "delegable", True, "OPERATE", KV, ["kv-advanced"]), step("restore-directory", "lldap.user.change-own-password-from-kv", "lldap:svc-authelia", "authelia", "delegable", True, "OPERATE", "lldap/people/svc-authelia", ["bind-signs-in"]), step("redeliver", "eso.force-sync", "k8s:sso/externalsecret/authelia-secrets", "authelia", "delegable", True, "OPERATE", "k8s/sso/externalsecret/authelia-secrets", ["eso-synced"]), step("restart-again", "k8s.rollout-restart", "k8s:sso/deployment/authelia", "authelia", "delegable", True, "OPERATE", "k8s/sso/deployment/authelia", ["synthetic-journey"])], [check("kv-advanced", "KV svc-authelia has exactly one new version, CAS on the previous one", PILOT_OPS, 30), check("bind-signs-in", "the new KV value signs in to LLDAP as svc-authelia", PILOT_OPS, 30), check("eso-synced", "the ExternalSecret is Ready with a refresh after the step started; the executor never reads the Secret", PILOT_OPS, 120), check("synthetic-journey", "syn-journey signs in through KeyCape, Authelia and privacyIDEA at aal2", PILOT_OPS, 90)], {"on_check_failure": "revert", "on_budget_exhausted": "revert", "on_unknown": "stop", "on_revert_failure": "stop-and-alert", "alert": "founder via State Hub message and audit-core"}, {"wall_time_seconds": 1200, "attempts": 2, "cost": {"compute_cpu_seconds": 120, "egress_bytes": 5000000, "currency": "EUR", "amount": 0.05}}, ["any bind other than svc-authelia", "any LLDAP group change", "changing LLDAP's configured super-admin", "reading or changing any human account", "any change outside the sso namespace"]) create = doc( "BEA-2026-0002", "Create the service bind accounts (bind-split step 3, root-class)", "Create svc-authelia, svc-keycape and svc-privacyidea in LLDAP as read-only binds. Needs lldap_admin: LLDAP has no narrower grant that can create users (SI-X6), so the founder admits this run and the executor runs it.", "high", {"not_before": "2026-11-03T09:00:00Z", "not_after": "2026-11-03T12:00:00Z"}, [{"mode": "ADMINISTER", "scope": "lldap", "environments": P}, {"mode": "OPERATE", "scope": "openbao/platform/workloads/net-kingdom/directory-binds", "environments": P}], {"unit": "account", "consumers": ["lldap"], "max_concurrent": 1}, [SPLIT, LANE], [step("create-accounts", "lldap.user.create-read-only-binds", "lldap:svc-authelia,svc-keycape,svc-privacyidea", "lldap", "root-class", True, "ADMINISTER", "lldap", ["accounts-read-only"], "delete-accounts"), step("hold-passwords", "openbao.kv.write-cas0", "openbao:platform/workloads/net-kingdom/directory-binds", "lldap", "root-class", True, "OPERATE", "openbao/platform/workloads/net-kingdom/directory-binds", ["accounts-sign-in"], "destroy-kv")], [step("delete-accounts", "lldap.user.delete-created", "lldap:svc-authelia,svc-keycape,svc-privacyidea", "lldap", "root-class", True, "ADMINISTER", "lldap", ["accounts-read-only"]), step("destroy-kv", "openbao.kv.destroy-created", "openbao:platform/workloads/net-kingdom/directory-binds", "lldap", "root-class", True, "OPERATE", "openbao/platform/workloads/net-kingdom/directory-binds", ["accounts-sign-in"])], [check("accounts-read-only", "each account exists in lldap_strict_readonly only and cannot write", SPLIT, 60), check("accounts-sign-in", "each KV value signs in to LLDAP as its account", LANE, 60)], {"on_check_failure": "revert", "on_budget_exhausted": "revert", "on_unknown": "stop", "on_revert_failure": "stop-and-alert", "alert": "founder via State Hub message"}, {"wall_time_seconds": 900, "attempts": 1, "cost": {"compute_cpu_seconds": 60, "egress_bytes": 1000000, "currency": "EUR", "amount": 0.02}}, ["switching any consumer to the new accounts", "any human account", "changing LLDAP's configured super-admin"]) superadmin = doc( "BEA-2026-0003", "Switch LLDAP's configured super-admin to ld-admin (bind-split step 9, root-class)", "Change LLDAP_LDAP_USER_DN from admin to ld-admin and restart LLDAP; admin keeps its rights through lldap_admin membership. Changes who administers the directory, so the founder admits the run.", "high", {"not_before": "2026-11-03T09:00:00Z", "not_after": "2026-11-03T11:00:00Z"}, [{"mode": "ADMINISTER", "scope": "lldap", "environments": P}, {"mode": "OPERATE", "scope": "k8s/sso/deployment/lldap", "environments": P}], {"unit": "consumer", "consumers": ["lldap"], "max_concurrent": 1}, [SPLIT, JOURNEY], [step("switch-user-dn", "lldap.config.set-ldap-user-dn", "k8s:sso/secret/lldap-secrets#LLDAP_LDAP_USER_DN", "lldap", "root-class", True, "ADMINISTER", "lldap", ["ld-admin-administers"], "switch-back"), step("restart-lldap", "k8s.rollout-restart", "k8s:sso/deployment/lldap", "lldap", "root-class", True, "OPERATE", "k8s/sso/deployment/lldap", ["synthetic-journey"], "restart-lldap-again")], [step("switch-back", "lldap.config.set-ldap-user-dn", "k8s:sso/secret/lldap-secrets#LLDAP_LDAP_USER_DN", "lldap", "root-class", True, "ADMINISTER", "lldap", ["ld-admin-administers"]), step("restart-lldap-again", "k8s.rollout-restart", "k8s:sso/deployment/lldap", "lldap", "root-class", True, "OPERATE", "k8s/sso/deployment/lldap", ["synthetic-journey"])], [check("ld-admin-administers", "ld-admin signs in and administers; admin keeps lldap_admin membership", SPLIT, 60), check("synthetic-journey", "all three binds still serve sign-in: syn-journey reaches aal2", JOURNEY, 90, settle=125)], {"on_check_failure": "revert", "on_budget_exhausted": "revert", "on_unknown": "stop", "on_revert_failure": "stop-and-alert", "alert": "founder via State Hub message; crisis list item for ld-admin"}, {"wall_time_seconds": 900, "attempts": 1, "cost": {"compute_cpu_seconds": 60, "egress_bytes": 1000000, "currency": "EUR", "amount": 0.02}}, ["changing admin's own password", "sealing ld-admin's password (human-intrinsic, step 10)", "any service bind change"]) verify = doc( "BEA-2026-0004", "Read-only verification of the directory split (bind-split steps 2, 4 and 10 verify)", "Plan and verify reads that the founder used to do signed in as admin: account inventory, group membership, bind identities of the consumers. No mutation, so nothing to revert.", "low", {"not_before": "2026-11-03T09:00:00Z", "not_after": "2026-11-04T09:00:00Z"}, [{"mode": "OBSERVE", "scope": "lldap/people", "environments": P}, {"mode": "OBSERVE", "scope": "k8s/sso", "environments": P}], {"unit": "consumer", "consumers": ["lldap", "authelia", "keycape", "privacyidea"], "max_concurrent": 4}, [SPLIT], [step("inventory", "lldap.read.users-and-groups", "lldap:people", "lldap", "delegable", False, "OBSERVE", "lldap/people", ["split-shape"]), step("consumer-binds", "k8s.read.bind-identities", "k8s:sso", "authelia", "delegable", False, "OBSERVE", "k8s/sso", ["split-shape"])], [], [check("split-shape", "every consumer binds as its own svc- account; no service binds as admin", SPLIT, 60)], {"on_check_failure": "stop", "on_budget_exhausted": "stop", "on_unknown": "stop", "on_revert_failure": "stop-and-alert"}, {"wall_time_seconds": 300, "attempts": 3, "cost": {"compute_cpu_seconds": 30, "egress_bytes": 500000, "currency": "EUR", "amount": 0.01}}, ["any write to LLDAP, Kubernetes or OpenBao"]) out = ROOT / "examples/bounded-execution-admission" for name, d in [("bind-rotation-svc-authelia", rotation), ("bind-split-create-service-accounts", create), ("bind-split-switch-super-admin", superadmin), ("bind-split-read-only-verify", verify)]: (out / f"{name}.yaml").write_text("# NK-WP-0056-T01 example: the bind split (NK-WP-0054) as admissions. Illustrative: the executor\n" "# (T03) and its operations do not exist yet; files are pinned at the commit named in plan.source.\n" + yaml.safe_dump(d, sort_keys=False, width=120)) # Invalid: step 10, the founder's own password, is human-intrinsic. bad = json.loads(json.dumps(superadmin)); s = bad["spec"]; s["id"] = "BEA-2026-0099" s["plan"]["steps"].append(step("change-admin-password", "lldap.user.set-password", "lldap:admin", "lldap", "human-intrinsic", True, "ADMINISTER", "lldap", ["ld-admin-administers"], "switch-back")) s["plan_digest"] = V.plan_digest(bad) fx = ROOT / "tools/bounded-execution-admission/fixtures"; (fx / "invalid").mkdir(parents=True, exist_ok=True) (fx / "invalid/human-intrinsic-step.yaml").write_text(yaml.safe_dump(bad, sort_keys=False, width=120)) print("commit", commit)