diff --git a/README.md b/README.md index 3235040..8d4b21e 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,12 @@ The dynamic, self-optimizing security platform is the long-term direction in ## Orientation - [SCOPE.md](SCOPE.md) — what this repo owns, current state, and when it is relevant -- [Security layer model](canon/standards/security-layer-model_v0.7.md) — how the - security estate is layered (Taxonomy / Tooling / Engines / Staff) and what each - layer may own -- [Agent companion](canon/standards/security-layer-model-companion_v0.1.md) — the - operative two-page form of that standard: what to declare, what binds you, what - you may never claim +- **[SECURITY-COMPANION.md](SECURITY-COMPANION.md) — start here.** The working + form of the security layer model: what to declare, what binds you, what you may + never claim about evidence, and the two things the estate cannot do yet +- [Security layer model](canon/standards/security-layer-model_v0.7.md) — the + statute the companion serves (accepted 2026-08-29): how the security estate is + layered (Taxonomy / Tooling / Engines / Staff) and what each layer may own - [Security scenario composition](canon/standards/security-scenario-composition_v0.1.md) — deterministic, plan-only capability and trust composition - [Posture feedback](canon/standards/posture-feedback_v0.1.md) — deterministic, diff --git a/SECURITY-COMPANION.md b/SECURITY-COMPANION.md new file mode 100644 index 0000000..da470f4 --- /dev/null +++ b/SECURITY-COMPANION.md @@ -0,0 +1,219 @@ +--- +id: netkingdom-security-companion-v0.2 +type: standard-companion +title: "NetKingdom Security — Working Companion v0.2" +domain: netkingdom +status: accepted +version: "0.2" +companion_to: canon/standards/security-layer-model_v0.7.md +owner: gate-house +publication_owner: net-kingdom +created: "2026-08-29" +updated: "2026-08-29" +review_interval: 3m +standard_token: security-companion_v0.2 +--- + +# NetKingdom Security — Working Companion + +**Start here.** This is the operative form of +[`canon/standards/security-layer-model_v0.7.md`](canon/standards/security-layer-model_v0.7.md) +(accepted): the same rules, without the change log or the review history. + +The statute governs where the two disagree. **A disagreement is a finding** — +report it to `gate-house` rather than working around it. + +For *how to get something done* in NetKingdom — which lane, which credential, +which route — ask `ops-warden`. This document says what the rules are; +`ops-warden` stewards the paths through them. + +--- + +## 1. The four layers + +| Layer | You are this if you produce | Deterministic | +| --- | --- | --- | +| **Taxonomy** | terms, semantic contracts, standards | n/a | +| **Tooling** | state and persistence | yes | +| **Engine** | a deterministic API for one modeled concept | yes | +| **Staff** | specifications, decisions, workplans, tasks | **no** | + +One test decides it: **given the same authoritative inputs, do you always return +the same result?** If your core function is inference or judgment you are Staff, +however much of your work happens at runtime. + +Engines carry a role — **PDP** (decides; `access-engine` only), **PIP** +(supplies facts as claims), **Evidence** (`audit-core`), **Lifecycle** (an API +over Tooling it owns). A new engine is a PIP unless the statute is amended. + +## 2. Declare your layer + +In your `INTENT.md` frontmatter, plus prose in your own voice in the body. A +layer someone else stated about you is not a declaration. + +```yaml +layer: Staff # Taxonomy | Tooling | Engine | Staff +role: null # Engines only: PDP | PIP | Evidence | Lifecycle +``` + +Working references, both offered estate-wide: `ops-warden`'s `layer.yaml`, +`scripts/check_layer_conformance.py`, `tests/test_layer_conformance.py`; +`kings-guard`'s adaptation of the same for a repository with no Tooling +contacts at all. + +**Contest the proposed layer if it is wrong.** Three repositories have returned +corrections that changed the standard; one talked us out of an exception we had +offered. A correction is worth more than a label. + +## 3. The rules that bind everyone + +1. **One decision point.** `access-engine` renders authorization decisions. No + other repository, in any layer, renders or caches one. +2. **Compiled data that determines an outcome is still deciding.** A registry, + cache, or schema that resolves a result before the engine runs decided early. +3. **Doctrine arrives as a claim.** Anything changing an outcome — authority + ceiling, zone stance, posture, maturity level — reaches the decision as a + request claim or a versioned policy rule. Never a side channel. +4. **Adaptive systems may only tighten.** Reduce, step up, request containment; + never manufacture authority. +5. **Staff never touches Tooling directly.** Act through Engine APIs. See §4. +6. **Every allow has a lifetime** — a TTL, or a binding to a session or + obligation that ends. + +## 4. If you touch Tooling + +"Tooling" means a system catalogued as Tooling in statute §4 — today `key-cape` +and `OpenBao`. Uncatalogued infrastructure (State Hub, `llm-connect`) is outside +the rule, but **list it anyway** so your conformance check is total. That +carve-out sunsets: an uncatalogued store another layer *reads* must, within two +review intervals, be catalogued or declared a gap. + +| Shape | When | You must | +| --- | --- | --- | +| **Read-only diagnostic** | no engine exposes the read | declare it; no writes; it is a gap to close | +| **Conduit** | you run the *owner's* tool under the *caller's* identity | present no credential of your own, widen nothing, stay reconstructable as the caller | +| **Declared gap** | you must contact Tooling and no engine exposes it | declare `capability`, `intended_owner`, `blocked_on`, `review` — machine-readably | + +A conduit presenting its own token is not a conduit. A declared gap is **tracked +non-conformance** — but declaring beats hiding, and it is never scored below +silence. + +There is deliberately **no "operator of third-party Tooling" shape**. Someone +must run OpenBao, and that stays a declared gap whose review keeps returning, +because a clean operator shape would turn a tracked gap into a permanent +allowance. + +## 5. If you cause side effects (you are PEP-shaped) + +Being PEP-shaped does not change your layer. `ops-warden` issuing a certificate +and `ops-mason` opening a route are both Staff and both PEP-shaped. + +1. **No side effect without a decision record** naming the request it was + rendered for — **or** your declared stance permits proceeding and **you record + the application of that stance in its place.** A fail-open result is metadata, + never silence. +2. **Do not replay a verdict outside its own binding and lifetime.** Within them + it is the decision being used as issued. The test is mechanical: replay is + permitted iff the canonical request digest matches and the lifetime holds. + Caching a DENY is permitted where the refusal is recorded against the request + refused and the cache lifetime is declared. +3. **Publish your unreachable-engine stance map** — total, per zone or + equivalent, no implicit default, no per-call discretion. **Publish it at a + path named in your layer declaration, and register it in statute §13.1** — a + map only you can read is not published. The published map MUST equal shipped + behaviour; assert that with a test. Reference: `ops-warden` + `ADR-0009` + `pep-stance.yaml`. +4. **Stay reconstructable**, within the bound in §6. + +If `access-engine` is reachable but degraded, the fallback is the engine's. If it +is unreachable, the behaviour is necessarily yours — which is why it is declared +in advance rather than decided in the moment. + +## 6. What you may never claim about evidence + +An append-only archive with a verified chain proves records were **not altered or +truncated after arrival**. It proves nothing about an event never sent. + +- ✗ "the audit record proves it happened" +- ✗ "there is no record, so it did not happen" +- ✓ "the archive proves the records it holds were not altered or truncated after arrival" + +Which control covers which threat: + +| Threat | Covered by | +| --- | --- | +| Accidental omission (crash between mutation and emit) | atomic emission via a **local** outbox — **prevented** | +| Adversarial omission (a compromised source suppresses) | cadence and reconciliation — **detected after the fact** | +| Adversarial omission at a compromised source | **nothing prevents it.** Known residual | + +If a control's soundness depends on an event being present, that evidence is +**load-bearing**: emission must be atomic with the state change, queued locally, +and you **MUST** declare an expected cadence. For rare load-bearing events — +revocations, denials, containment — rate monitoring cannot work, so the required +form is **reconciliation or a heartbeat**: a positive claim that can itself go +missing. + +Otherwise evidence is **attributive**: seek atomicity, and if you trade it away +deliberately, declare the trade and never describe the trail as complete. + +## 7. If you are an agent + +Same layer as your human colleagues, different blast radius: + +1. **No standing credential.** Authority is per task, time-bounded, attributable + to the principal you act for. +2. **Tool use is a conduit or an Engine API.** There is no third route. **Tool + availability is not permission** — a callable tool means the operation exists, + not that you may invoke it. +3. **Your memory is not a state plane.** Memory, tool-call traces, and prompt + caches must not become state another layer depends on unless catalogued. +4. **Every action is reconstructable as the caller's action.** + +Session semantics — session loops, tool policy, harness routing, model selection +— are `glas-harness`'s, not this standard's. Rule 2 is the seam between them, and +neither side is sufficient alone. + +## 8. Conformance: four states + +| State | Meaning | +| --- | --- | +| **Conforming** | no Tooling contact, or only declared diagnostic/conduit shapes | +| **Blocked-clean** | the capability does not exist because no engine exposes it, and you make no Tooling contact | +| **Declared gap** | a declared Tooling contact — tracked non-conformance | +| **Undeclared violation** | anything else | + +**Blocked-clean is not worse than conforming.** Declining a shortcut and leaving +a capability at zero is compliance at cost, and will never be ranked below a +repository that quietly opened a client and said nothing. + +## 9. If you operate workloads (Railiance) + +Operations belong to **Railiance** (`railiance-master`), not to NetKingdom. A +workload is a managed running deployable, operated through four axes: +`railiance-*` ownership, `rail-*` execution contract, `rapp-*` managed package, +`reef-*` substrate. `rein-*` is **not** a fifth axis — reins are `glas-harness` +agent-harness backends. + +What holds for any Railiance consumer of NetKingdom security: decisions come from +`access-engine` and nowhere else; approvals are objects in `approval-engine` +consumed as claims; credentials come from `secrets-engine` **after** a decision; +evidence goes to `audit-core` under §6's bound; anything causing a protected side +effect is PEP-shaped and owes §5. + +**How the axes map onto the layer model is not settled** — see statute §20.3. Do +not assume a mapping; raising the question is welcome. + +## 10. Two things the estate cannot do yet + +Stated so nobody plans around a capability that does not exist: + +- **Nothing is observed in production.** `kings-guard` has reported it has never + seen a real event. Do not cite "observed in operation" as evidence. +- **Nothing can be contained automatically.** There is no actuation surface — no + API to reduce authority, require step-up, or isolate a workload. The capability + is at zero, not degraded, and it is nobody's gap to close alone. + +--- + +**Statute:** [`canon/standards/security-layer-model_v0.7.md`](canon/standards/security-layer-model_v0.7.md) — accepted 2026-08-29. +**Owner:** `gate-house`. **Guidance on getting things done:** `ops-warden`. diff --git a/canon/standards/security-layer-model-companion_v0.1.md b/canon/standards/security-layer-model-companion_v0.1.md deleted file mode 100644 index 5b5d8fe..0000000 --- a/canon/standards/security-layer-model-companion_v0.1.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -id: netkingdom-security-layer-model-companion-v0.1 -type: standard-companion -title: "NetKingdom Security Layer Model — Agent Companion v0.1" -domain: netkingdom -status: proposed -version: "0.1" -companion_to: canon/standards/security-layer-model_v0.7.md -owner: gate-house -publication_owner: net-kingdom -created: "2026-08-29" -updated: "2026-08-29" -review_interval: 3m -standard_token: security-layer-model-companion_v0.1 ---- - -# Security Layer Model — Agent Companion - -**This is the operative form of `security-layer-model_v0.7.md`.** Same rules, no -change log, no review history. The statute governs where the two disagree; if you -find a disagreement, report it — that is a finding, not a formatting problem. - -Read this if you are an agent or an operator working in a NetKingdom repository, -or if your repository has been asked to declare its layer. - ---- - -## 1. The four layers - -| Layer | You are this if you produce | Deterministic | -| --- | --- | --- | -| **Taxonomy** | terms, semantic contracts, standards | n/a | -| **Tooling** | state and persistence | yes | -| **Engine** | a deterministic API for one modeled concept | yes | -| **Staff** | specifications, decisions, workplans, tasks | **no** | - -One test decides it: **given the same authoritative inputs, do you always return -the same result?** If your core function is inference or judgment, you are Staff -— however much of your work happens at runtime. - -Engines carry a role: **PDP** (decides — `access-engine` only), **PIP** -(supplies facts as claims), **Evidence** (`audit-core`), **Lifecycle** (an API -over Tooling it owns). A new engine is a PIP unless the statute says otherwise. - -## 2. Declare your layer - -Put this in your `INTENT.md` frontmatter. A layer someone else stated about you -is not a declaration. - -```yaml -layer: Staff # Taxonomy | Tooling | Engine | Staff -role: null # Engines only: PDP | PIP | Evidence | Lifecycle -``` - -Then state it in prose, in your own voice, in the body. Contest the proposed -layer if it is wrong — a correction is worth more than a label. - -Reference implementation of the machine-readable form: `ops-warden`'s -`layer.yaml`, `scripts/check_layer_conformance.py`, and -`tests/test_layer_conformance.py`. - -## 3. The rules that bind everyone - -1. **One decision point.** `access-engine` renders authorization decisions. No - other repository, in any layer, renders or caches one. -2. **Compiled data that determines an outcome is still deciding.** A registry, - cache, or schema that resolves a result before the engine runs has decided - early. -3. **Doctrine arrives as a claim.** Anything that changes an outcome — an - authority ceiling, a zone stance, a posture, a maturity level — reaches the - decision as a request claim or a versioned policy rule, never by a side - channel. -4. **Adaptive systems may only tighten.** Reduce authority, require step-up, - request containment — never manufacture authority. -5. **Staff never touches Tooling directly.** It acts through Engine APIs. See §4. -6. **Every allow has a lifetime.** A TTL, or a binding to a session or - obligation that ends. - -## 4. If you touch Tooling - -"Tooling" means a system catalogued as Tooling in the statute's §4 — today -`key-cape` and `OpenBao`. Uncatalogued infrastructure (the State Hub, -`llm-connect`) is outside this rule, but list it anyway so your check is total. - -Three sanctioned shapes. Anything else is a violation: - -| Shape | When | You must | -| --- | --- | --- | -| **Read-only diagnostic** | no engine exposes the read | declare it; no writes; treat it as a gap to close | -| **Conduit** | you run the *owner's* tool under the *caller's* identity | present no credential of your own, widen nothing, stay reconstructable as the caller | -| **Declared gap** | you must contact Tooling and no engine exposes it | declare `capability`, `intended_owner`, `blocked_on`, `review` — machine-readably | - -A conduit that presents its own token is not a conduit. A declared gap is -**tracked non-conformance**, not conformance — but declaring it is always better -than hiding it, and it will never be scored below silence. - -## 5. If you cause side effects (you are PEP-shaped) - -Being PEP-shaped does not change your layer. `ops-warden` issuing a certificate -and `ops-mason` opening a route are both Staff and both PEP-shaped. - -1. **No side effect without a decision record** naming the request it was - rendered for. -2. **Never cache the verdict.** Caching an input claim under its own freshness - rule is fine; caching the answer is a second decision point. -3. **Publish your unreachable-engine stance** — total, per zone or equivalent, - no implicit default, no per-call discretion. Reference shape: `ops-warden` - `ADR-0009`. -4. **Stay reconstructable**, within the bound in §6. - -If `access-engine` is reachable but degraded, the fallback is the engine's. If it -is unreachable, the behaviour is necessarily yours — which is why it must be -declared in advance rather than decided in the moment. - -## 6. What you may never claim about evidence - -An append-only archive with a verified chain proves records were **not altered -or truncated after arrival**. It proves nothing about an event never sent. - -- ✗ "the audit record proves it happened" -- ✗ "there is no record, so it did not happen" -- ✓ "the archive proves the records it holds were not altered or truncated after arrival" - -The event an adversary most wants missing is the negative one — a revocation, a -denial, a containment action. If a control's soundness depends on an event being -present, that evidence is **load-bearing** and its emission must be atomic with -the state change, queued locally. Otherwise it is **attributive**: seek -atomicity, and if you trade it away deliberately, declare the trade and never -describe the trail as complete. - -If you emit adaptive-relevant events, publish an expected cadence. A drop below -it is a finding. Silence is a signal. - -## 7. If you are an agent - -Same layer as your human colleagues, different blast radius: - -1. **No standing credential.** Authority is per task, time-bounded, attributable. -2. **Tool use is a conduit or an Engine API.** There is no third route. -3. **Your memory is not a state plane.** Memory, tool-call traces, and prompt - caches must not become state another layer depends on unless catalogued. -4. **Every action is reconstructable as the caller's action.** - -Tool availability is not permission. A tool being callable says the operation -exists, not that you may invoke it. - -## 8. Conformance: four states - -| State | Meaning | -| --- | --- | -| **Conforming** | no Tooling contact, or only declared diagnostic/conduit shapes | -| **Blocked-clean** | the capability does not exist because no engine exposes it, and you make no Tooling contact | -| **Declared gap** | a declared §5.3 contact — tracked non-conformance | -| **Undeclared violation** | anything else | - -**Blocked-clean is not worse than conforming.** Declining a shortcut and leaving -a capability at zero is compliance at cost. It will never be ranked below a -repository that quietly opened a client and said nothing. - -## 9. Consuming NetKingdom security from outside - -Operations is **HelixForge's** responsibility — its reef, rail, rapp, and rein -concepts — and NetKingdom provides the security and approval framework those -operations consume. - -**That interface is not specified yet.** What holds today is only what holds for -any consumer: authorization decisions come from `access-engine`, approvals are -objects in `approval-engine` consumed as claims, credentials are materialized by -`secrets-engine` after a decision, and evidence goes to `audit-core` under the -bound in §6. A HelixForge component that causes a protected side effect is -PEP-shaped and §5 applies to it. - -What is **not** settled: how a reef, rail, rapp, or rein maps onto the layer -model — whether they are subjects a decision is rendered about, principals that -request, PEP-shaped consumers, or none of these. Until that is written, do not -assume a mapping. Raising it is welcome. - -## 10. Two things the estate cannot do yet - -Stated so nobody plans around a capability that does not exist: - -- **Nothing is observed in production.** `kings-guard` has reported that it has - never seen a real event. Do not cite "observed in operation" as evidence. -- **Nothing can be contained automatically.** There is no actuation surface — - no API to reduce authority, require step-up, or isolate a workload. The - capability is at zero, not degraded. - ---- - -**Statute:** `canon/standards/security-layer-model_v0.7.md`. -**Known gap in this version:** §5.3 says publish your stance map but not *where*, -and omits the statute's §6.4 inventory obligation — a repository could satisfy -this document and no register would learn of its stance. Fixed in v0.2; until -then read statute §6.4 and §13.1. -**Owner:** gate-house. **Report a disagreement between this and the statute as a -finding.** diff --git a/canon/standards/security-layer-model_v0.7.md b/canon/standards/security-layer-model_v0.7.md index e4e162c..fdc231e 100644 --- a/canon/standards/security-layer-model_v0.7.md +++ b/canon/standards/security-layer-model_v0.7.md @@ -3,7 +3,7 @@ id: netkingdom-security-layer-model-v0.7 type: standard title: "NetKingdom Security Layer Model v0.7" domain: netkingdom -status: proposed +status: accepted version: "0.7" supersedes: canon/standards/security-layer-model_v0.6.md owner: gate-house @@ -986,9 +986,21 @@ do while the register is nearly empty. ## 14. Adoption -Status is **proposed** — the frontmatter is authoritative, and v0.2 was the last -version to reach `accepted`. Four repositories have assented, each with a record, -and all four returned findings on the versions since: +Status is **accepted**, on the owner's decision of 2026-08-29. + +Two things that acceptance does and does not mean, kept apart because +`ops-warden` asked for the distinction: + +| | | +| --- | --- | +| **Boundary assent** | given by the four repositories below, at the version named in each record, and undisturbed since | +| **Revision review** | each of the four reviewed v0.6 and returned findings; **every change in v0.7 is the adopted remedy of a finding they raised** | +| **Not claimed** | no repository has reviewed v0.7 *as text*. The first revision review will confirm or correct it | + +Accepting a standard nobody has re-read is a deliberate call: the estate learns +more from using it than from another round of prose refinement, and the changes +in v0.7 were requested rather than invented. Findings against the accepted text +remain welcome and are §12's normal business, not an exception. | Repository | Record | Outcome | | --- | --- | --- | @@ -1218,14 +1230,11 @@ v0.3 → v0.4: text it grades. Raised by `access-engine`. Its two substantive points remain live: observation in production is unstaffed (§12) and actuation has no surface (§9.2). -- The **agent companion** (`security-layer-model-companion_v0.1.md`) is the - operative form of this statute. The statute governs on disagreement, and a - disagreement is a finding. Its §5.3 omits where a stance map is published and - omits the §6.4 inventory obligation entirely — a repository could satisfy the - companion faithfully, publish into its own repo, believe itself conforming, and - no register would learn of it. Raised by `access-engine` in answer to the - question of what would show the companion insufficient. To be fixed in - companion v0.2. +- The **working companion** (`net-kingdom/SECURITY-COMPANION.md`, v0.2, root of + the repository for onboarding) is the operative form of this statute. The statute governs on disagreement, and a + disagreement is a finding. The v0.1 gap `access-engine` found — publish + your stance map, but nowhere saying where, and no inventory obligation — is + fixed in v0.2 §5.3. - How the Railiance operational axes meet this model beyond §20's first statement, which is deliberately minimal.