audit-core/tenancy.yaml
tegwick 4d5d989344
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Refine AUDIT-WP-0008 open tasks against draft-8.
The framework moved from draft-5 to draft-8 while this workplan ran. No finding
was reversed, but three things changed underneath it: R moved to 2 once
rapp-postgres declared the window, a sixth axis V (availability) appeared, and
the implemented-versus-evidenced distinction became a schema field.

T03 reduces: the confirmation-oracle finding landed as Decision 4.5.3 and
question 11 is marked framework-resolved, so no amendment remains -- only our
own position document. The legal question routes to risk-nexus rather than
the-custodian, per §19.11 and policy-nexus INTENT.

T06 reduces to confirmation: all five findings were adopted and the two stale
status lines it was going to flag are already fixed.

T07 is new. V1 needs critical dependencies enumerated, restart recovery
exercised and recovery time measured. The 2026-08-16 reboot walk observed ~40s
of unreadiness but is not an exercise and does not enumerate the dependency set.

T08 is new and covers two defects in our own declaration. provider.R.available
quotes a 30-day horizon we do not solely control -- at P1 the horizon is the
instance maximum across co-residents. And under Decision 6.1, user-engine was
never told what we declared, which makes the declaration drift rather than a
completed change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:20:58 +02:00

148 lines
6.8 KiB
YAML

# audit-core tenancy posture
#
# Declared per NetKingdom Tenancy Posture v0.1 (draft-8),
# net-kingdom/canon/standards/tenancy-posture_v0.1.md.
# Location and schema per Decision 5.4; per-path detail per Decision 5.2;
# provider block per Decision 5.5.
#
# Conformance is accuracy, not altitude (§6). Nothing here is claimed above
# what this repo can evidence today. E is deliberately declared lower than the
# mechanism in place because the adversarial artifact is still absent.
schema_version: "0.1"
framework: netkingdom-tenancy-posture
service: audit-core
role: tenant-audit-service
tenancy:
reviewed: "2026-08-17"
review_due: "2027-02-17"
service_class: batch # §8.3.2. Co-resident with latency-critical
# tenant-engine on platform-pg; the mixture is
# reported by the platform, not hidden.
current: { I: 1, A: 2, E: 1, P: 1, R: 2, V: 0 }
implemented: { E: 2 }
target: { I: 1, A: 2, E: 3, P: 1, R: 2, V: 1 }
# §5.2 — declare per path, quote the minimum. The quoted E above is the
# minimum across paths. As of AUDIT-WP-0008-T04 both paths carry the same
# mechanism; the quoted level stays at 1 for the evidence reason in gap.E,
# not because a path is weaker.
paths:
E:
write: 2 # Sender credential bound to the sources and tenants it may
# claim; checked at one choke point (audit_core/ingestion.py).
read: 2 # Event reads filtered to permitted tenants; surfaces with no
# tenant key require full scope. Cross-tenant fetch returns
# 404, not 403, so the surface is not an existence oracle.
placement_exceptions: [] # No tenant is on dedicated substrate. All
# tenants share database audit_core on
# platform-pg.
gap:
I: >-
I1 is accurate and is not currently a target. Senders authenticate with
bearer tokens and the tenant arrives in the request body, checked against
an allowlist bound to the credential (§4.1 places request-supplied tenant
identifiers at I1 however canonical the string). The allowlist is a real
control, but it is an A-axis control; it does not make the identity
verified. Moving to I2 means senders carrying a verified token with a
tenant claim, which is a change to every sender and not audit-core's to
make alone. Recorded as accurate, not as ambition.
A: >-
A2 is accurate. Authorization is a single local boundary — permitted
sources, permitted tenants, may_write, may_read — bound once and centrally.
No flex-auth delegation. A3 is not a near-term target: flex-auth is itself
at A0 on its own self-report (/v1/check authenticates no caller), so
delegating to it today would lower this service's assurance, not raise it.
E: >-
The E2 mechanism is in place on both paths as of AUDIT-WP-0008-T04, and
the quoted level is still 1. This is deliberate. §13.2 states that a
passing CI run is not E2 evidence: the E2 artifact is adversarial, needs
separate tenant contexts compared against each other, and carries a review
date rather than a green build. The repo's cross-tenant tests are
mechanical. Under §13.1 the level is not claimable until that artifact
exists, so E stays at 1 until AUDIT-WP-0008-T05 produces it with
whitehat-security. Declaring E2 on the strength of unit tests would be the
overclaim §6 prohibits, and the read-path defect this repo just fixed was
found precisely by refusing that kind of reasoning.
E_target: >-
E3 (row-level security per rapp-postgres ADR-0003) targeted 2027-03-31.
Blocked behind the E2 artifact — §4.3 requires E2 evidence alongside any
E3 claim — and needs the EXPLAIN comparison first, since RLS disables
functional indexes built on non-leakproof functions. E4 is unreachable at
P1 by the §3.2 coupling and is not a target.
R_ceiling: >-
R4 is unreachable under the current design and is not a target. Per
Decision 4.5.3 — which this repo found — the hash chain commits to a
SHA-256 of the cleartext record, which survives key destruction as a
confirmation oracle over low-entropy fields. A fleet R4 target must exempt
this service explicitly. See docs/erasure-and-audit.md (AUDIT-WP-0008-T03).
credentials: >-
Stated gap against Decision 9.2 rather than a silent exclusion. Database
credentials comply with 9.1: dynamic leases re-read from a mounted Secret
at connection time, no restart on rotation. Ingest credentials do not:
they are static long-lived bearer tokens, rotated overlap-first by
publishing a replacement alongside the incumbent and then dropping the
predecessor. audit-core raised this omission during review and is not
exempting itself from the rule it asked for. No dated remedy yet; leasing
consumer-facing credentials needs a broker path that does not exist.
retention_placement: >-
audit-core's INTENT wants unbounded WORM archive. That is data.archive in
ITC-CAP terms, recorded as an unmet requirement in
data/capability/audit-core-operational.json, and it is deliberately not a
backup-window question: a 30-day WAL window is not an archive, is not
searchable, and restores instance-wide. Reviewed 2026-12-31. If no
data.archive provision is procured by then, audit-core reopens placement
under the §4.5 retention trigger, with P2 as the fallback — a worse answer
than archive, named now so it is not improvised later.
V: >-
No exercise establishes restart recovery for the complete audit path.
V1 is the target; replica count or Kubernetes restart policy is not
treated as evidence.
provider:
capability: operations.audit
profile: administrative
axes:
E:
available: 2
maximum: 3
conditions:
- "E3 requires rapp-postgres ADR-0003 applied to audit_core and its EXPLAIN probe."
- "E4 is unreachable at P1 with one runtime credential."
evidence:
- "audit_core/ingestion.py"
- "tests/test_ingestion.py"
R:
available: 2
maximum: 2
conditions:
- "R4 is unreachable while the integrity chain commits to cleartext hashes."
evidence:
- "rapp-postgres/consumers/audit-core.yaml"
- "audit_core/interface.py"
V:
available: 0
maximum: 1
conditions:
- "Exercise restart recovery across audit-core, platform-pg and OpenBao."
evidence:
A2:
- "audit_core/ingestion.py"
- "tests/test_ingestion.py"
E1:
- "audit_core/postgres_backend.py"
- "tests/test_backend_conformance.py"
P1: "rapp-postgres/docs/evidence/isolation-2026-08-10.md"
R2:
- "rapp-postgres/consumers/audit-core.yaml"
- "tests/test_interface.py"