flex-auth/cadence.yaml

147 lines
6.4 KiB
YAML
Raw Normal View History

# flex-auth (access-engine) — §11 emission guarantee, per event class.
#
# Authority: security-layer-model §9.6 and §11; GH-DEC-2026-018 §2 and §3;
# net-kingdom/canon/standards/emission-cadence-security-profile_v0.1.md.
# Reference instance: approval-engine/cadence.yaml. Detection form:
# gate-house/docs/contracts/approval-emission-detection.md.
#
# WHY THIS FILE EXISTS AND WHY IT IS PER CLASS.
#
# flex-auth asked whether it is a §4 source of evidence for the decision record
# or only the producer of an artifact audit-core sources, declined to take the
# reading that favoured it, and held the question open as declared gap G2.
# GH-DEC-2026-018 §1 ruled that a custodian is never the source of what it
# holds: §9.6 rests on an archive being unable to prove a record was never
# sent, and that sentence has content only because archive and emitter are
# different parties. audit-core reached the same conclusion on its own
# authority (AUDIT-IN-0005) and declined the role. So flex-auth is the source.
#
# GH-DEC-2026-018 §4 ruled the declaration is PER EVENT CLASS and deliberately
# did NOT classify these classes, because §11 forbids a conformance run to
# infer class from event name, payload or observed rate and that prohibition
# binds a ruling as hard as it binds a runner. The classification below is
# therefore flex-auth's, published as §11 requires the source to publish it,
# and it is supplied to a checker rather than derived by one.
#
# The reason it is per class and not per repository: one guarantee averaged
# over a stream carrying both a high-volume allow and a rare deny is an
# average, not a declaration, and rate monitoring over that average cannot see
# the deny go missing. A denial is one of the three paradigm load-bearing
# events §9.6 names, and it is the event an adversary most wants absent.
schema_version: "0.1"
source: flex-auth # §4 row `access-engine`; FLEX-DEC-2026-013
kind: load-bearing
form: heartbeat-or-reconciliation
rate_monitoring: forbidden # class-level exception stated on `allow` only
# STATE. The classification below is published and in force as a declaration.
# The emission pipeline is not built: no sender named flex-auth or
# access-engine is registered with audit-core, no token lane, no scope row, and
# the decision record reaches consumers in the /v1/check response rather than
# into any custody. This file is therefore the declaration §11 requires and not
# a claim that the guarantee is delivered today. The delivery gap is G2 in
# docs/conformance/security-layer-conformance.md, with owner, blocker and
# review date, and it fails CLOSED on its distinguishing case: a stream with no
# declared cadence produces no silence finding, so the failure mode is a missed
# detection and never a manufactured permission.
state: declared-not-yet-emitting
gap: G2 # docs/conformance/security-layer-conformance.md
heartbeat:
class: flex-auth.decision.heartbeat
interval: 24h
assertion: nothing-to-report
missing: finding
reconciliation:
# Declared for EVERY class, including the volume one. Rate monitoring can see
# a stream stop; it cannot see a targeted subset removed, and a suppression
# aimed at one subject or one tenant is exactly the shape that leaves the
# aggregate rate inside its window.
compare:
local: committed outbox counts per class
remote: "audit-core event counts where source=flex-auth"
divergence: finding
undrained_local: lag-not-divergence
lag_bound:
outbox_depth: 100
outbox_age: 1h
exceed: finding
# EVENT CLASS INVENTORY.
#
# The classes are the decision-record effect vocabulary of
# `flex-auth.decision-record.v1` (docs/decision-record-contract.md,
# pkg/api.DecisionEffect). Every one of them is load-bearing: a decision record
# is the artifact a consumer's authority rests on, and §17 moved its schema
# here on the ground that it is the one thing in the estate only this
# repository produces.
classes:
deny:
action: flex-auth.decision.deny
evidence_class: load-bearing
rarity: rare
rate_monitoring: forbidden
detection: [heartbeat, reconciliation]
note: >-
§9.6's paradigm case, named there by the standard. Rare by nature, which
is where rate monitoring is the wrong instrument and the stakes are
highest.
redact:
action: flex-auth.decision.redact
evidence_class: load-bearing
rarity: rare
rate_monitoring: forbidden
detection: [heartbeat, reconciliation]
note: >-
A partial denial. It restricts authority, so it carries the same
suppression incentive as a deny and is classified with it.
not_applicable:
action: flex-auth.decision.not_applicable
evidence_class: load-bearing
rarity: rare
rate_monitoring: forbidden
detection: [heartbeat, reconciliation]
note: >-
No policy matched. A consumer fails closed on it, so its absence has the
same effect as a suppressed deny.
audit_only:
action: flex-auth.decision.audit_only
evidence_class: load-bearing
rarity: rare
rate_monitoring: forbidden
detection: [heartbeat, reconciliation]
note: >-
The effect whose entire purpose is the record. A record of it that does
not arrive is the decision not having happened.
allow:
action: flex-auth.decision.allow
evidence_class: load-bearing
rarity: volume
rate_monitoring: permitted # §3 of the profile: explicitly classified rate-suitable
expected_rate:
window: 1h
minimum: 1
below_minimum: finding
detection: [expected-rate, reconciliation]
note: >-
Classified volume, and stated as a classification rather than left to be
inferred from observed traffic. Reconciliation is declared anyway,
because rate monitoring over an allow stream cannot see a targeted subset
removed. An allow carries a TTL lifetime, so a suppressed allow expires
into a denial of service rather than into a standing grant.
heartbeat:
action: flex-auth.decision.heartbeat
evidence_class: operational
rarity: scheduled
note: The positive assertion above; not a decision.
bound: >-
Heartbeat and reconciliation detect loss, outage, drain failure and accident.
Neither detects a compromised source suppressing an event and its own count
together — §9.6's stated residual, and §16 puts the independent observer
outside audit-core's scope. Conformance to this declaration is not a claim of
stream completeness.