2026-08-29 10:19:05 +02:00
|
|
|
# audit-core — NetKingdom security layer declaration
|
|
|
|
|
#
|
Align to Security Layer Model v0.7; revise SCOPE; raise AUDIT-WP-0009
The standard is accepted at v0.7 and all three of audit-core's v0.6
findings landed in it (§9.6 threat decomposition, cadence MUST for
load-bearing sources with reconciliation/heartbeat for low-volume
classes, §3.3's Evidence row restated as an estate trade).
INTENT.md: layer/role declared in frontmatter as §11 and companion §2
require — layer.yaml alone did not discharge it. Layer section rewritten
for the Evidence role and its obligations. New Evidence Bound section
carrying the §9.6 sound/unsound forms and the three-row threat table,
including the residual nothing in the model prevents.
SCOPE.md: replaced the statehub register stub, which carried no boundary
at all. Statute-fixed prohibitions now live here, separated from the
merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and
data.archive are not ours rather than not yet.
Assessment found nine gaps. Headline: postgres_backend returns
tamper_evidence=True unconditionally while docs/integrity.md permits it
only against a live external attestation, and the one on record is
2026-08-16 with no job renewing it — audit-core overclaiming its own
bound, the §9.6 defect turned inward. Also: no cadence, heartbeat,
reconciliation, or load-bearing classification exists, so the obligation
audit-core argued up from SHOULD to MUST is not yet dischargeable
against audit-core.
AUDIT-WP-0009 raised, ten tasks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
2026-08-29 14:42:51 +02:00
|
|
|
# Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md
|
2026-08-29 10:19:05 +02:00
|
|
|
# Assent: AUDIT-IN-0001 (audit-core's own voice, per §11 "who must declare")
|
|
|
|
|
# history/2026-08-28-approval-evidence-assent.md
|
|
|
|
|
# history/2026-08-29-security-layer-model-v0.6-review.md
|
Align to Security Layer Model v0.7; revise SCOPE; raise AUDIT-WP-0009
The standard is accepted at v0.7 and all three of audit-core's v0.6
findings landed in it (§9.6 threat decomposition, cadence MUST for
load-bearing sources with reconciliation/heartbeat for low-volume
classes, §3.3's Evidence row restated as an estate trade).
INTENT.md: layer/role declared in frontmatter as §11 and companion §2
require — layer.yaml alone did not discharge it. Layer section rewritten
for the Evidence role and its obligations. New Evidence Bound section
carrying the §9.6 sound/unsound forms and the three-row threat table,
including the residual nothing in the model prevents.
SCOPE.md: replaced the statehub register stub, which carried no boundary
at all. Statute-fixed prohibitions now live here, separated from the
merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and
data.archive are not ours rather than not yet.
Assessment found nine gaps. Headline: postgres_backend returns
tamper_evidence=True unconditionally while docs/integrity.md permits it
only against a live external attestation, and the one on record is
2026-08-16 with no job renewing it — audit-core overclaiming its own
bound, the §9.6 defect turned inward. Also: no cadence, heartbeat,
reconciliation, or load-bearing classification exists, so the obligation
audit-core argued up from SHOULD to MUST is not yet dischargeable
against audit-core.
AUDIT-WP-0009 raised, ten tasks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
2026-08-29 14:42:51 +02:00
|
|
|
# history/2026-08-29-v0.7-alignment-and-scope-assessment.md
|
2026-08-29 10:19:05 +02:00
|
|
|
#
|
|
|
|
|
# Reference form offered by ops-warden and adopted here, so §11's declaration
|
|
|
|
|
# check is mechanical rather than a reader's judgment about prose. audit-core
|
|
|
|
|
# raised that defect; adopting the form is the other half of raising it.
|
|
|
|
|
|
|
|
|
|
schema_version: "0.1"
|
|
|
|
|
framework: netkingdom-security-layer-model
|
Align to Security Layer Model v0.7; revise SCOPE; raise AUDIT-WP-0009
The standard is accepted at v0.7 and all three of audit-core's v0.6
findings landed in it (§9.6 threat decomposition, cadence MUST for
load-bearing sources with reconciliation/heartbeat for low-volume
classes, §3.3's Evidence row restated as an estate trade).
INTENT.md: layer/role declared in frontmatter as §11 and companion §2
require — layer.yaml alone did not discharge it. Layer section rewritten
for the Evidence role and its obligations. New Evidence Bound section
carrying the §9.6 sound/unsound forms and the three-row threat table,
including the residual nothing in the model prevents.
SCOPE.md: replaced the statehub register stub, which carried no boundary
at all. Statute-fixed prohibitions now live here, separated from the
merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and
data.archive are not ours rather than not yet.
Assessment found nine gaps. Headline: postgres_backend returns
tamper_evidence=True unconditionally while docs/integrity.md permits it
only against a live external attestation, and the one on record is
2026-08-16 with no job renewing it — audit-core overclaiming its own
bound, the §9.6 defect turned inward. Also: no cadence, heartbeat,
reconciliation, or load-bearing classification exists, so the obligation
audit-core argued up from SHOULD to MUST is not yet dischargeable
against audit-core.
AUDIT-WP-0009 raised, ten tasks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
2026-08-29 14:42:51 +02:00
|
|
|
standard_version: "0.7"
|
2026-08-29 10:19:05 +02:00
|
|
|
repository: audit-core
|
|
|
|
|
layer: engine
|
|
|
|
|
role: evidence # §3.3 engine typing
|
|
|
|
|
declared_by: intakes/intakes.md AUDIT-IN-0001
|
|
|
|
|
declared_at: "2026-08-29"
|
|
|
|
|
|
|
|
|
|
# §3.3: an Evidence engine records what happened and proves integrity of what
|
|
|
|
|
# it holds. It is explicitly not a decision point (§6, §9.4).
|
|
|
|
|
decision_surfaces_exposed: none
|
|
|
|
|
|
|
|
|
|
# §9.4 — normative and permanent. audit-core exposes no verdict on whether an
|
|
|
|
|
# approval is still valid; a consumer branching on such an answer would route an
|
|
|
|
|
# authorization decision through the audit fabric.
|
|
|
|
|
approval_validity_query: forbidden
|
|
|
|
|
|
Align to Security Layer Model v0.7; revise SCOPE; raise AUDIT-WP-0009
The standard is accepted at v0.7 and all three of audit-core's v0.6
findings landed in it (§9.6 threat decomposition, cadence MUST for
load-bearing sources with reconciliation/heartbeat for low-volume
classes, §3.3's Evidence row restated as an estate trade).
INTENT.md: layer/role declared in frontmatter as §11 and companion §2
require — layer.yaml alone did not discharge it. Layer section rewritten
for the Evidence role and its obligations. New Evidence Bound section
carrying the §9.6 sound/unsound forms and the three-row threat table,
including the residual nothing in the model prevents.
SCOPE.md: replaced the statehub register stub, which carried no boundary
at all. Statute-fixed prohibitions now live here, separated from the
merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and
data.archive are not ours rather than not yet.
Assessment found nine gaps. Headline: postgres_backend returns
tamper_evidence=True unconditionally while docs/integrity.md permits it
only against a live external attestation, and the one on record is
2026-08-16 with no job renewing it — audit-core overclaiming its own
bound, the §9.6 defect turned inward. Also: no cadence, heartbeat,
reconciliation, or load-bearing classification exists, so the obligation
audit-core argued up from SHOULD to MUST is not yet dischargeable
against audit-core.
AUDIT-WP-0009 raised, ten tasks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
2026-08-29 14:42:51 +02:00
|
|
|
# §5 applies to Staff. audit-core is an Engine and holds no §4 Tooling contact
|
|
|
|
|
# (key-cape, OpenBao). Companion §4 asks that UNCATALOGUED infrastructure be
|
AUDIT-WP-0009 T02/T10 — schedule attestation, and make the §5 check total
T02. deploy/attest-cronjob.yaml: daily at 03:17 UTC against the 168h window,
its own ServiceAccount, and a Role reaching exactly one named ConfigMap —
get/update/patch, no create, no list. audit_core/attest_publish.py does the
publish in stdlib; the image carries no kubectl, and adding one to an audit
receiver's image to write a single file is the worse trade.
Three refusals, all deliberate:
The producer is not the receiver. A receiver that could rewrite its own
attestation could forge it. audit-core-egress is now scoped to
component: receiver and a separate audit-core-attest-egress carries the 6443
rule, so the receiver never gains API-server reach. Asserted by test.
It refuses to publish over a broken chain. A fresh head written over a break
replaces an honest chain_break with a fresh-looking attestation. Stale
degrades the claim visibly; false does not.
Mounted as a directory, not subPath. Found while writing the manifest: a
subPath ConfigMap mount is resolved once at pod start and never updates, so
the daily attestation would land in the ConfigMap and never reach the running
receiver — tamper_evidence would age out to false while the job reported
success every night, silent in both directions.
The offsite copy stays an operator step. audit-core holds no Nextcloud
credential and should not acquire one to publish a hash, so docs/integrity.md
states the bound plainly: until that copy exists the delivered control defends
against a database owner, not a cluster owner, and no stronger claim may be
made from it.
T10. layer.yaml lists four infrastructure contacts — platform-pg, state-hub,
kube-apiserver, the container registry — each with its role and whether another
layer reads it. tooling_contacts stays [], which is true under §5 as written;
the companion's totality request is met by the uncatalogued list rather than by
inventing a Tooling row. tests/test_layer_conformance.py derives the egress
destinations from the manifests and the registry from the pinned digests, so a
new contact appearing in deploy/ without a row fails the test rather than
waiting for a reviewer to notice.
Applying the manifests remains an operator action; nothing here was applied.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nb7Q6ZmXppNDkTWytfYqfv
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2069992@bnt-lap001
Assistant-Session: 167dd7f8-2a25-4be1-aa46-3b6f1a5f94c6
2026-09-10 16:39:20 +02:00
|
|
|
# listed anyway so the check is total rather than vacuous, and that carve-out
|
|
|
|
|
# sunsets within two review intervals for a store another layer reads.
|
|
|
|
|
#
|
|
|
|
|
# Completed 2026-09-10 (AUDIT-WP-0009-T10). The list below is asserted total by
|
|
|
|
|
# `tests/test_layer_conformance.py`, which fails when a new infrastructure
|
|
|
|
|
# contact appears in `deploy/` without a row here — the check is mechanical
|
|
|
|
|
# rather than a promise to remember.
|
2026-08-29 10:19:05 +02:00
|
|
|
tooling_contacts: []
|
Align to Security Layer Model v0.7; revise SCOPE; raise AUDIT-WP-0009
The standard is accepted at v0.7 and all three of audit-core's v0.6
findings landed in it (§9.6 threat decomposition, cadence MUST for
load-bearing sources with reconciliation/heartbeat for low-volume
classes, §3.3's Evidence row restated as an estate trade).
INTENT.md: layer/role declared in frontmatter as §11 and companion §2
require — layer.yaml alone did not discharge it. Layer section rewritten
for the Evidence role and its obligations. New Evidence Bound section
carrying the §9.6 sound/unsound forms and the three-row threat table,
including the residual nothing in the model prevents.
SCOPE.md: replaced the statehub register stub, which carried no boundary
at all. Statute-fixed prohibitions now live here, separated from the
merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and
data.archive are not ours rather than not yet.
Assessment found nine gaps. Headline: postgres_backend returns
tamper_evidence=True unconditionally while docs/integrity.md permits it
only against a live external attestation, and the one on record is
2026-08-16 with no job renewing it — audit-core overclaiming its own
bound, the §9.6 defect turned inward. Also: no cadence, heartbeat,
reconciliation, or load-bearing classification exists, so the obligation
audit-core argued up from SHOULD to MUST is not yet dischargeable
against audit-core.
AUDIT-WP-0009 raised, ten tasks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1
2026-08-29 14:42:51 +02:00
|
|
|
uncatalogued_infrastructure:
|
|
|
|
|
- id: platform-pg
|
|
|
|
|
system: CNPG PostgreSQL on railiance01
|
|
|
|
|
role: audit-core's own operational custody store
|
|
|
|
|
read_by_other_layers: true # subject to the companion §4 sunset
|
|
|
|
|
note: >-
|
|
|
|
|
Not a §4 Tooling row. Listed for totality, not as a declared gap.
|
AUDIT-WP-0009 T02/T10 — schedule attestation, and make the §5 check total
T02. deploy/attest-cronjob.yaml: daily at 03:17 UTC against the 168h window,
its own ServiceAccount, and a Role reaching exactly one named ConfigMap —
get/update/patch, no create, no list. audit_core/attest_publish.py does the
publish in stdlib; the image carries no kubectl, and adding one to an audit
receiver's image to write a single file is the worse trade.
Three refusals, all deliberate:
The producer is not the receiver. A receiver that could rewrite its own
attestation could forge it. audit-core-egress is now scoped to
component: receiver and a separate audit-core-attest-egress carries the 6443
rule, so the receiver never gains API-server reach. Asserted by test.
It refuses to publish over a broken chain. A fresh head written over a break
replaces an honest chain_break with a fresh-looking attestation. Stale
degrades the claim visibly; false does not.
Mounted as a directory, not subPath. Found while writing the manifest: a
subPath ConfigMap mount is resolved once at pod start and never updates, so
the daily attestation would land in the ConfigMap and never reach the running
receiver — tamper_evidence would age out to false while the job reported
success every night, silent in both directions.
The offsite copy stays an operator step. audit-core holds no Nextcloud
credential and should not acquire one to publish a hash, so docs/integrity.md
states the bound plainly: until that copy exists the delivered control defends
against a database owner, not a cluster owner, and no stronger claim may be
made from it.
T10. layer.yaml lists four infrastructure contacts — platform-pg, state-hub,
kube-apiserver, the container registry — each with its role and whether another
layer reads it. tooling_contacts stays [], which is true under §5 as written;
the companion's totality request is met by the uncatalogued list rather than by
inventing a Tooling row. tests/test_layer_conformance.py derives the egress
destinations from the manifests and the registry from the pinned digests, so a
new contact appearing in deploy/ without a row fails the test rather than
waiting for a reviewer to notice.
Applying the manifests remains an operator action; nothing here was applied.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nb7Q6ZmXppNDkTWytfYqfv
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 2069992@bnt-lap001
Assistant-Session: 167dd7f8-2a25-4be1-aa46-3b6f1a5f94c6
2026-09-10 16:39:20 +02:00
|
|
|
- id: state-hub
|
|
|
|
|
system: Custodian State Hub
|
|
|
|
|
role: >-
|
|
|
|
|
Work coordination only. Reads and writes workplans, tasks, intakes and
|
|
|
|
|
progress events. Carries no audit event, no sender credential and no
|
|
|
|
|
custody role, and audit-core's runtime does not contact it — this is a
|
|
|
|
|
development-time contact, listed because §5 totality does not distinguish.
|
|
|
|
|
read_by_other_layers: false
|
|
|
|
|
- id: kube-apiserver
|
|
|
|
|
system: k3s API server on railiance01
|
|
|
|
|
role: >-
|
|
|
|
|
Written by the audit-core-attest CronJob to publish the chain-head
|
|
|
|
|
attestation into one named ConfigMap (AUDIT-WP-0009-T02). The receiver
|
|
|
|
|
has no API-server egress: a receiver able to rewrite its own attestation
|
|
|
|
|
could forge it, so the reach belongs to the attest workload alone.
|
|
|
|
|
read_by_other_layers: false
|
|
|
|
|
- id: forgejo.coulomb.social
|
|
|
|
|
system: Container registry
|
|
|
|
|
role: >-
|
|
|
|
|
Image source, pinned by digest in deploy/. Build-time contact; no runtime
|
|
|
|
|
call. Listed because a registry that can change what runs is an
|
|
|
|
|
infrastructure contact whether or not §5 catalogues it.
|
|
|
|
|
read_by_other_layers: false
|
2026-08-29 10:19:05 +02:00
|
|
|
|
|
|
|
|
# §9.6 — the bound audit-core delivers, stated so no doctrine rests on more.
|
|
|
|
|
evidence_bound:
|
|
|
|
|
proves:
|
|
|
|
|
- records held were not altered after arrival
|
|
|
|
|
- records held were not truncated after arrival
|
|
|
|
|
does_not_prove:
|
|
|
|
|
- that a record was ever sent
|
|
|
|
|
- absence of a record as evidence of non-occurrence
|
|
|
|
|
conditional_on:
|
|
|
|
|
- external chain-head attestation stored outside platform-pg
|
|
|
|
|
contract: docs/integrity.md
|
|
|
|
|
not_claimed: [WORM, object-lock, archival-custody]
|
2026-09-21 02:09:47 +02:00
|
|
|
|
|
|
|
|
# §11 emission guarantee — AUDIT-IN-0005, docs/section-4-source-of-evidence.md
|
|
|
|
|
#
|
|
|
|
|
# §11 requires the declaration from a repository catalogued in §4 as a SOURCE of
|
|
|
|
|
# evidence. audit-core is catalogued as the Evidence engine — the custody and
|
|
|
|
|
# detection half — and emits no event into another repository's custody. The
|
|
|
|
|
# emission guarantee for an event belongs to the repository that emits it; that
|
|
|
|
|
# is audit-core's standing boundary (AUDIT-IN-0001, AUDIT-WP-0009 non-goals) and
|
|
|
|
|
# the reason audit-core declines the source role for access-engine's decision
|
|
|
|
|
# record.
|
|
|
|
|
#
|
|
|
|
|
# The one artifact audit-core does produce on its own behalf is declared anyway,
|
|
|
|
|
# in the same spirit as uncatalogued_infrastructure above: stated so the check is
|
|
|
|
|
# total rather than vacuous, not because §11 is read to compel it. Prose in
|
|
|
|
|
# docs/integrity.md is not a machine-readable declaration — the defect audit-core
|
|
|
|
|
# raised against another repository, so not one it leaves standing in its own.
|
|
|
|
|
source_of_evidence: false
|
|
|
|
|
source_of_evidence_note: >-
|
|
|
|
|
audit-core holds custody and the detection surface. Emission class, cadence and
|
|
|
|
|
detection obligations sit on each sender's registration
|
|
|
|
|
(deploy/senders-scope.{json,yaml}, heartbeat_classes per class), never on the
|
|
|
|
|
archive. audit-core cannot detect non-production by a source and claims no
|
|
|
|
|
ability to — AUDIT-IN-0003, GH-DEC-2026-014 limit 3.
|
|
|
|
|
|
|
|
|
|
emission_guarantee:
|
|
|
|
|
- id: chain-head-attestation
|
|
|
|
|
emits: external chain-head attestation for the audit event chain
|
|
|
|
|
class: load-bearing
|
|
|
|
|
rarity: rare # one scheduled artifact per day, never volume
|
|
|
|
|
rate_monitoring: forbidden # §11 / emission-cadence profile, rare class
|
|
|
|
|
cadence:
|
|
|
|
|
form: scheduled
|
|
|
|
|
interval: daily
|
|
|
|
|
schedule: "17 3 * * *" # UTC, deploy/attest-cronjob.yaml
|
|
|
|
|
producer: CronJob audit-core-attest-chain, its own ServiceAccount
|
|
|
|
|
published_to: ConfigMap audit-core-chain-head
|
|
|
|
|
detection_surface:
|
|
|
|
|
form: freshness-window
|
|
|
|
|
window_hours: 168 # 7x the cadence; widens, never removes
|
|
|
|
|
on_absence: >-
|
|
|
|
|
tamper_evidence degrades to False with the reason recorded, and a missing,
|
|
|
|
|
unreadable, undated or stale attestation is treated the same as absent.
|
|
|
|
|
Non-production is detected deterministically at read time by the consumer
|
|
|
|
|
of the claim, not inferred from a rate.
|
|
|
|
|
surfaces: ["GET /v1/integrity", "GET /readyz (last-known, no chain walk)"]
|
|
|
|
|
contract: docs/integrity.md
|
|
|
|
|
bound: >-
|
|
|
|
|
The attestation proves the head it cites; it is not WORM and does not prove
|
|
|
|
|
any record was ever sent. An operator-run offsite copy is a separate lane
|
|
|
|
|
and is not claimed as part of this guarantee.
|