operations.py: OpenBao KV v2 CAS, LLDAP self-rotation (forward and revert), ExternalSecret force-sync and status, rollout restart (RolloutFailed is a definite failure), pilot checks. synthetic_pilot.py on the T08 stack plus OpenBao 2.5.4 with CCR-2026-0058's policy: rotation completed; a one-off wrong delivery reverted in declared order with the earlier value restored. Runner: revert steps run in declared order (BEA-10), definite failures revert, unknown outcomes stop, receipts carry error types. Found and corrected (in railiance-platform) CCR-2026-0058's required_parameters refusing reads. Packaging moved to new T13. 29 executor tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 994874@bnt-lap001 Assistant-Session: 6017c416-d619-47eb-bd1a-f670a02d7d87
254 lines
15 KiB
Markdown
254 lines
15 KiB
Markdown
---
|
||
id: netkingdom-bounded-execution-admission-v0.1
|
||
type: standard
|
||
title: "NetKingdom Bounded Execution Admission v0.1"
|
||
domain: netkingdom
|
||
status: proposed
|
||
version: "0.1"
|
||
owner: net-kingdom
|
||
created: "2026-10-31"
|
||
updated: "2026-10-31"
|
||
last_reviewed: "2026-10-31"
|
||
review_interval: 3m
|
||
scope: accountable-automation
|
||
schema:
|
||
- canon/schemas/bounded-execution-admission_v0.1.schema.json
|
||
validator:
|
||
- tools/bounded-execution-admission/validate.py
|
||
examples:
|
||
- examples/bounded-execution-admission/
|
||
related:
|
||
- canon/standards/service-identity-privilege_v0.1.md
|
||
- canon/standards/playbook-capability-contract_v0.2.md
|
||
- workplans/NK-WP-0056-bounded-executor-path.md
|
||
- workplans/NK-WP-0040-execution-attribution-receipt.md
|
||
---
|
||
|
||
# NetKingdom Bounded Execution Admission v0.1
|
||
|
||
## 0. Status
|
||
|
||
Proposed (NK-WP-0056-T01). Nothing here is enforced by a running service yet. The executor runtime
|
||
is T02/T03, budget and kill-switch enforcement is T07, and the first live use is the T06 pilot. A
|
||
document that passes the validator is a well-formed **request**. It is an **admission** only together
|
||
with a carrier record that a person approved (section 5).
|
||
|
||
## 1. Purpose
|
||
|
||
SI-15 names the golden path *prepare → admit → execute → verify → retain*, and allows "a bounded
|
||
executor under the admission" at step 3. This standard defines what that admission is. The founder
|
||
approves, at `aal2`:
|
||
|
||
- an exact plan, by digest;
|
||
- a validity window;
|
||
- a scope ceiling in SI `MODE @ SCOPE` terms;
|
||
- a blast-radius rule;
|
||
- a stop-and-revert policy tied to named machine checks;
|
||
- a risk class;
|
||
- an expense budget.
|
||
|
||
The executor consumes the admission once. Top-level decisions and guardrails stay with the person,
|
||
and execution below them is delegated, bounded and reconstructable.
|
||
|
||
Out of scope: who runs the executor (T02), how a carrier stores approvals (Approval Engine owns that),
|
||
and the receipt's emission and custody (NK-WP-0040-T02).
|
||
|
||
## 2. Vocabulary
|
||
|
||
| Term | Meaning |
|
||
| --- | --- |
|
||
| Admission request | The immutable document defined here (`BoundedExecutionAdmission`), identified by `spec.id` and by its digest |
|
||
| Carrier | The system that records a person's approval of one request and its single consumption: Approval Engine, or a founder SSH signature (NK-WP-0049 practice) |
|
||
| Admission | A request plus a carrier record that passes BEA-C1..C7 |
|
||
| Executor | The non-human identity that runs the plan: a `WORKLOAD`, `SERVICE` or harness-launched `AGENT` (SI-14) |
|
||
| Step class | `delegable` (the executor may run it under an admission), `root-class` (the founder admits each run; high risk only), `human-intrinsic` (never in an admission: for example a person's own password) |
|
||
| Check | A named, source-pinned machine check that must pass after a mutating step |
|
||
| Consumer | The unit the blast radius counts: a service whose behaviour a step can change |
|
||
|
||
## 3. The admission request
|
||
|
||
A YAML or JSON document validated by `canon/schemas/bounded-execution-admission_v0.1.schema.json`:
|
||
|
||
| Field | Meaning |
|
||
| --- | --- |
|
||
| `spec.id`, `title`, `purpose`, `work_ref` | Identity and intent. `id` is `BEA-YYYY-NNNN` |
|
||
| `risk_class` | `low`, `medium` or `high`. Bounds the window, the attempts, the ceiling and the step classes |
|
||
| `window.not_before` / `not_after` | When the admission can be consumed. At most 72 h (low), 24 h (medium) or 4 h (high) |
|
||
| `approval` | Who may approve (`approvers`, `HUMAN`, `aal2`) and through which carriers |
|
||
| `executor` | The executing identity, its principal type and runtime |
|
||
| `scope_ceiling` | Grants `{mode, scope, environments}` that bound every step. Scopes are `/`-separated paths, and a grant covers its own scope and anything below it |
|
||
| `blast_radius` | `unit`, the `consumers` the plan may touch, and `max_concurrent` |
|
||
| `trust_requires` | Playbook Capability Contract trust states the executor must find satisfied before the first step |
|
||
| `plan.source` | Repository, commit, and the sha256 of every file the run executes or checks with |
|
||
| `plan.steps`, `plan.revert_steps` | Ordered steps: `operation`, `target`, `consumer`, `class`, `mutates`, `requires` (the grant it needs), `checks_after`, `revert` or `irreversible` |
|
||
| `plan_digest` | `sha256:` over the canonical JSON of `plan` (sorted keys, no whitespace, UTF-8) |
|
||
| `checks` | Named checks: `ref` (a pinned file), `sha256`, `timeout_seconds`, optional `settle_seconds`, `expect: pass` |
|
||
| `stop_and_revert` | `on_check_failure` and `on_budget_exhausted` (`revert` or `stop`); `on_unknown: stop`; `on_revert_failure: stop-and-alert` |
|
||
| `budget` | `wall_time_seconds`, `attempts`, and `cost` (CPU seconds, egress bytes, currency, amount) |
|
||
| `consumption` | `single_use: true`, `consume_before_first_step: true` |
|
||
| `receipt` | The NK-WP-0040 execution-attribution receipt, where it goes, and that it is retained by hash with no secret values |
|
||
| `not_authorized` | What this admission explicitly does not cover |
|
||
|
||
`settle_seconds` exists because of the T08 finding: privacyIDEA's resolver cache hides a broken bind
|
||
for up to 120 s, so a check run sooner proves nothing.
|
||
|
||
## 4. Rules (validator: `validate`)
|
||
|
||
| Rule | Requirement |
|
||
| --- | --- |
|
||
| BEA-1 | The document matches the schema (`HUMAN` approvers at `aal2`, single use, `on_unknown: stop`) |
|
||
| BEA-2 | `plan_digest` equals the digest of `plan`: the person admits exactly this plan |
|
||
| BEA-3 | The window is positive and no longer than the risk class allows |
|
||
| BEA-4 | The executor is not `HUMAN` and not an approver. An `AGENT` must be harness-launched (SI-14) |
|
||
| BEA-5 | No `SOVEREIGN` or `GOVERN` in the ceiling. No `CONSTRUCT` in `PRODUCTION`. `ADMINISTER` needs `max_concurrent: 1`; at a whole-service scope (no `/`) it needs `high` risk and only `root-class` steps |
|
||
| BEA-6 | Least privilege: every step and revert step is covered by a ceiling grant of the same mode, and every ceiling grant covers at least one step |
|
||
| BEA-7 | No `human-intrinsic` step. A `root-class` step needs `high` risk |
|
||
| BEA-8 | Every step's consumer is in the blast radius. `medium` and `high` risk change one consumer at a time |
|
||
| BEA-9 | Every mutating step names checks, revert steps included: a revert must prove the restored state with its own checks. Every check is used and pinned: its `ref` and `sha256` appear in `plan.source.files` |
|
||
| BEA-10 | Every mutating step has a revert step, or is `irreversible` at `high` risk. Revert steps mutate and do not nest. Step ids are unique. The executor runs revert steps in their declared order (the recovery order: data, then delivery, then restart), limited to those whose forward step ran |
|
||
| BEA-11 | A revertable plan reverts on check failure. A plan with nothing to revert stops |
|
||
| BEA-12 | The wall time fits the window, the checks (timeouts plus settle times) fit the wall time, and attempts are at most 3 (1 at `high` risk) |
|
||
| BEA-13 | The executed source is pinned by file and commit |
|
||
| BEA-14 | No secret-shaped value anywhere in the document |
|
||
|
||
Findings name the rule and a location, never a value.
|
||
|
||
## 5. Carrier and consumption (validator: `check-approval`)
|
||
|
||
A carrier record (`netkingdom.io/bounded-execution-approval/v0.1`) states the carrier, its approval
|
||
reference, the admission id and digest, the approver (name, principal type, assurance), the approval
|
||
time, and the consumptions.
|
||
|
||
The **admission digest** is `sha256:` over the canonical JSON of the whole request, including
|
||
`plan_digest`. That digest is what a carrier binds.
|
||
|
||
| Rule | Requirement |
|
||
| --- | --- |
|
||
| BEA-C1 | The carrier is one the request allows, and the record has the expected shape |
|
||
| BEA-C2 | The record names this admission's id and digest |
|
||
| BEA-C3 | The approver is a listed `HUMAN` approver and not the executor |
|
||
| BEA-C4 | The approval was made at `aal2` |
|
||
| BEA-C5 | The approval was made before the window closed |
|
||
| BEA-C6 | Consumed at most once |
|
||
| BEA-C7 | The consumption happened in the window, after approval, by the executor identity |
|
||
|
||
**Approval Engine (preferred carrier).** Approval Engine already stores an approval that binds action,
|
||
actor, principal, purpose and target by digest, carries a validity window, and is consumed exactly
|
||
once (`POST /v1/approvals/{id}/consume`), read back through `GET /v1/approvals/{id}`. The proposed
|
||
mapping, which is for agreement with Approval Engine and Access under T02, not decided here:
|
||
|
||
- `action: bounded-execution`;
|
||
- `actor`: the executor identity;
|
||
- `principal`: the approver;
|
||
- `purpose`: `spec.purpose`;
|
||
- `target: {admission_id, admission_digest}`;
|
||
- validity equal to `window`;
|
||
- the executor consumes before its first step (`consume_before_first_step`).
|
||
|
||
Approval Engine's own contract notes that `consume` does not check that the request digest is
|
||
equivalent to the decision. An independent mediator must therefore fetch the approval and compare
|
||
`target.admission_digest` itself. A `consumed: true` returned by the caller is not proof.
|
||
|
||
**Founder SSH signature (transitional carrier).** This is the NK-WP-0049 practice:
|
||
|
||
- the founder signs the canonical request with `ssh-keygen -Y sign`, namespace
|
||
`netkingdom-bounded-execution`;
|
||
- the signature is verified against the repository's `allowed_signers`;
|
||
- `aal2` is established by the signing key's custody, not by a token.
|
||
|
||
Single use is then only as strong as the executor's own consumption ledger. That is acceptable for
|
||
the transition and is recorded as such in the receipt.
|
||
|
||
## 6. Mapping
|
||
|
||
**SI-15 golden path.**
|
||
|
||
| Golden-path step | What it means here |
|
||
| --- | --- |
|
||
| Prepare | `plan.source` (source-reviewed, pinned files), tested on synthetic fixtures. For bind changes, NK-WP-0056-T08's synthetic stack |
|
||
| Admit | Carrier approval of the admission digest at `aal2` |
|
||
| Execute | The executor, inside `scope_ceiling`, `blast_radius`, `window` and `budget`, consuming once |
|
||
| Verify | The named checks during the run. Afterwards, an independent verifier checks the carrier record (BEA-C1..C7) and the receipt's source hashes |
|
||
| Retain | The receipt, kept by hash with no secret values |
|
||
|
||
**Playbook Capability Contract.** `trust_requires` uses the contract's trust-state vocabulary. The
|
||
executor refuses to start unless each state is satisfied, using the readiness checks of the
|
||
capability declarations it runs. A step's `operation` should name a declared capability operation
|
||
once Railiance declarations exist for it.
|
||
|
||
**Execution-attribution receipt (Playbook Capability Contract v0.2, NK-WP-0040).** One receipt per run:
|
||
|
||
| Receipt field | Filled from |
|
||
| --- | --- |
|
||
| `initiator` | The carrier's approver (the founder). The person authorized the run; the executor ran it |
|
||
| `delegation` | Absent unless the approver acted through an agent |
|
||
| `executing_workload`, `runtime_principal` | `executor.identity`, `executor.runtime` |
|
||
| `run_id` | New per run |
|
||
| `source_commit` | `plan.source.commit` |
|
||
| `artifact_digest` | `plan_digest` |
|
||
| `target`, `action` | Per step |
|
||
| `decision_refs` | `spec.id`, the admission digest and the carrier's approval reference |
|
||
| `time_interval` | Measured |
|
||
|
||
The receipt adds the outcome per step, check results, whether a revert ran, and the budget used. It
|
||
never holds a secret value.
|
||
|
||
Founder decision 2026-10-31, agreed with audit-core (AUDIT-WP-0018):
|
||
|
||
- When the executor consumes the admission, before its first step, it emits a separate
|
||
`execution.run.started` event, so a run that crashes before its receipt is still detectable.
|
||
- It then emits one `execution.attribution.receipt` per run:
|
||
- `target` and `action` at the admission level (`admission:<spec.id>`, `bounded-execution`);
|
||
- per-step detail in `steps[]`;
|
||
- `decision_refs` labelled `admission`, `admission_digest` and `approval`.
|
||
- Envelope ids are `run:<run_id>:started` and `run:<run_id>:receipt`.
|
||
|
||
**Policy decision point.** access-engine's gate (FLEX-WP-0040) has two decisions: `start` before
|
||
consume, and `execute-step` after it. The T06 pilot runs without the gate: its receipt records the
|
||
gate as `not-evaluated` and claims no allow. Any further admission needs the gate, or an exception
|
||
the founder records (founder decision 2026-10-31).
|
||
|
||
**Failure classes.** A failed check, or an operation that reports a definite failure (for example a rollout that never becomes ready), reverts per `on_check_failure`. An error whose outcome is not established stops (`on_unknown: stop`) without reverting. Receipts name the error type, never its message.
|
||
|
||
**Credentials during a run.** Write roles exist only during the admitted window: the platform creates
|
||
them when an admission is approved and deletes them after the receipt (CCR-2026-0058). A directory
|
||
bind rotates its own password, so no password-manager account is needed (founder decisions
|
||
2026-10-31).
|
||
|
||
## 7. The bind split as admissions
|
||
|
||
NK-WP-0056 tagged each step of the 2026-10-30 LLDAP bind split. The examples express them:
|
||
|
||
| Runbook step | Class | Example |
|
||
| --- | --- | --- |
|
||
| 2, 4, 10 (verify) | delegable, read-only | `bind-split-read-only-verify.yaml`: low risk, `OBSERVE` only, nothing to revert |
|
||
| 3 create `svc-*` accounts | root-class | `bind-split-create-service-accounts.yaml`: high, whole-directory `ADMINISTER` (no narrower LLDAP grant, SI-X6), revert deletes what was created |
|
||
| 5–8 switch one consumer | delegable | `bind-rotation-svc-authelia.yaml`: medium, one consumer, a synthetic-journey check after the restart, a revert per step. This is the T06 pilot shape |
|
||
| 9 change LLDAP's super-admin | root-class | `bind-split-switch-super-admin.yaml`: high, one attempt, `settle_seconds: 125` on the journey check (privacyIDEA cache) |
|
||
| 10 `admin`'s own password; seal `ld-admin` | human-intrinsic | Refused: `tools/bounded-execution-admission/fixtures/invalid/human-intrinsic-step.yaml` (BEA-7) |
|
||
|
||
The examples are illustrative. They pin real files at a real commit, but the executor and its
|
||
operations do not exist yet.
|
||
|
||
## 8. Conformance
|
||
|
||
```bash
|
||
make bounded-execution-admission-test # validator tests
|
||
make bounded-execution-admission-check # validate the examples
|
||
python3 tools/bounded-execution-admission/validate.py check-approval <admission> <carrier-record>
|
||
python3 tools/bounded-execution-admission/validate.py digest <admission>
|
||
```
|
||
|
||
Agents may run these: they are offline and read-only. Writing an admission is preparation, and
|
||
approving one is the founder's act.
|
||
|
||
## 9. Open items
|
||
|
||
- T02: the carrier mapping with Approval Engine and Access (action name, actor and representation,
|
||
digest equivalence, consume scope for the executor), and the executor runtime owner.
|
||
- T03: the executor identity and its grants, matching the ceilings in the examples.
|
||
- T07: enforcement of budget and attempts at run time, the founder's kill switch, and aggregate
|
||
review through posture feedback (NK-WP-0031).
|
||
- NK-WP-0040-T02: receipt emission, custody and schema in audit-core.
|
||
- Recurring admissions (one approval for repeated runs of the same plan) are deliberately excluded
|
||
from v0.1: every admission is single use.
|