Use the shared coordination frame for audit heartbeat defaults
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
This commit is contained in:
parent
bf8a9ede67
commit
5eb7e86f7a
5 changed files with 50 additions and 9 deletions
|
|
@ -268,3 +268,19 @@ next. Ordinary denies (`authz_denied`, `tenant_scope`, `unknown_capability`)
|
|||
never count toward this — only the two reason classes that indicate
|
||||
probing/exfiltration rather than a client mistake. See
|
||||
`docs/SecurityPractice.md` §9.3 and `src/qonto_assistant/security_watch.py`.
|
||||
|
||||
|
||||
## Ecosystem coordination-frame adoption — 2026-10-15
|
||||
|
||||
The source heartbeat default now imports FRAME_SECONDS from the generated
|
||||
qonto_assistant/coordination.py. Initial frame is f=3600s, configured once in
|
||||
coordination-engine/config/coordination-frame.json. The source-owned cadence
|
||||
and rapp-qonto manifest derive the same interval and preserve config SHA-256
|
||||
provenance. Regenerate them with net-kingdom/tools/coordination-frame/render.py;
|
||||
--check detects drift. An explicitly configured instance interval still needs
|
||||
matching declaration and receiver mapping.
|
||||
|
||||
This source update does not deploy rapp-qonto or create its missing collector.
|
||||
QONTO-WP-0006-T02/T03 and AUDIT-WP-0013-T05 still hold sender/delivery and
|
||||
independent observation acceptance. Existing bank credential TTL, policy,
|
||||
identity, rate limits and process-local counter limitations are unchanged.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
# Source-owned InfoTechCanon declaration; intended cadence, not delivery proof.
|
||||
# Generic document 0.2.0 / schema 0.1; owner bundle b08b4d95fc4b0bd3.
|
||||
# Source-owned cadence; coordination timings generated from coordination-engine/config/coordination-frame.json
|
||||
schema_version: '0.1'
|
||||
declaration_id: qonto-assistant.audit.v1
|
||||
source: qonto-assistant
|
||||
|
|
@ -11,7 +10,7 @@ sources:
|
|||
form: heartbeat-or-reconciliation
|
||||
heartbeat:
|
||||
event_class: audit.heartbeat
|
||||
interval: PT24H
|
||||
interval: PT3600S
|
||||
assertion: nothing-to-report
|
||||
missing: finding
|
||||
extensions: &id001
|
||||
|
|
@ -33,7 +32,7 @@ sources:
|
|||
form: heartbeat-or-reconciliation
|
||||
heartbeat:
|
||||
event_class: audit.heartbeat
|
||||
interval: PT24H
|
||||
interval: PT3600S
|
||||
assertion: nothing-to-report
|
||||
missing: finding
|
||||
extensions: *id001
|
||||
|
|
@ -53,7 +52,7 @@ sources:
|
|||
form: heartbeat-or-reconciliation
|
||||
heartbeat:
|
||||
event_class: audit.heartbeat
|
||||
interval: PT24H
|
||||
interval: PT3600S
|
||||
assertion: nothing-to-report
|
||||
missing: finding
|
||||
extensions: *id001
|
||||
|
|
@ -65,6 +64,13 @@ extensions:
|
|||
netkingdom:
|
||||
contract_digest: b08b4d95fc4b0bd3
|
||||
contract_document_version: 0.2.0
|
||||
coordination_frame:
|
||||
ref: coordination-engine/config/coordination-frame.json
|
||||
sha256: d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67
|
||||
frame_seconds: 3600
|
||||
heartbeat_frames: 1
|
||||
registered_wait_frames: 2
|
||||
effective_deadline_frames: 3
|
||||
qonto-assistant:
|
||||
transport: structured-stdout
|
||||
instance_boundary: process
|
||||
|
|
@ -76,9 +82,9 @@ extensions:
|
|||
reset: permitted-only-when-stream_instance_id-changes
|
||||
heartbeat:
|
||||
event_class: audit.heartbeat
|
||||
interval: PT24H
|
||||
interval: PT3600S
|
||||
interval_config: QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS
|
||||
default_interval_seconds: 86400
|
||||
default_interval_seconds: 3600
|
||||
lifecycle:
|
||||
startup: required
|
||||
periodic_while_process_active: required
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import os
|
|||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from .coordination import FRAME_SECONDS
|
||||
|
||||
|
||||
def _repo_root() -> Path:
|
||||
return Path(__file__).resolve().parents[2]
|
||||
|
|
@ -92,7 +94,7 @@ class Settings:
|
|||
os.getenv("QONTO_DENY_ESCALATION_LOCKOUT_SECONDS", "300")
|
||||
),
|
||||
audit_heartbeat_interval_seconds=max(
|
||||
1, int(os.getenv("QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS", "86400"))
|
||||
1, int(os.getenv("QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS", str(FRAME_SECONDS)))
|
||||
),
|
||||
key_cape_jwks_url=os.getenv("QONTO_KEY_CAPE_JWKS_URL") or None,
|
||||
key_cape_issuer=os.getenv("QONTO_KEY_CAPE_ISSUER", "https://key-cape.netkingdom"),
|
||||
|
|
|
|||
6
src/qonto_assistant/coordination.py
Normal file
6
src/qonto_assistant/coordination.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
"""Generated cadence timings; regenerate with NetKingdom coordination-frame tool."""
|
||||
# Source: coordination-engine/config/coordination-frame.json
|
||||
FRAME_CONFIG_SHA256 = "d15e092387f128ffdfd00b9815707a05ff77c5bb0ba4d9a428fbc37b8c440b67"
|
||||
FRAME_SECONDS = 3600
|
||||
RECEIVER_WAIT_SECONDS = 7200
|
||||
EFFECTIVE_DEADLINE_SECONDS = 10800
|
||||
|
|
@ -8,6 +8,7 @@ import pytest
|
|||
import yaml
|
||||
|
||||
from qonto_assistant.audit import AUDIT_STREAM_ID, AuditLogger
|
||||
from qonto_assistant.coordination import FRAME_SECONDS
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
|
@ -17,7 +18,7 @@ def test_declaration_preserves_emitter_boundary_and_counters():
|
|||
source = declaration["extensions"]["qonto-assistant"]
|
||||
assert declaration["stream_id"] == AUDIT_STREAM_ID
|
||||
assert source["instance_boundary"] == "process"
|
||||
assert source["heartbeat"]["default_interval_seconds"] == 86400
|
||||
assert source["heartbeat"]["default_interval_seconds"] == FRAME_SECONDS
|
||||
assert source["reconciliation"]["persistence"] == "process-local"
|
||||
events = []
|
||||
audit = AuditLogger(sink=events.append)
|
||||
|
|
@ -58,3 +59,13 @@ def test_declaration_passes_supplied_owner_inventory_against_canonical_schema():
|
|||
assert report["profile_assessed"] is True
|
||||
assert report["conformant"] is True
|
||||
assert report["assessment_scope"] == "supplied-inventory"
|
||||
|
||||
|
||||
|
||||
def test_default_interval_uses_generated_frame_and_explicit_override_survives(monkeypatch):
|
||||
from qonto_assistant.config import Settings
|
||||
|
||||
monkeypatch.delenv("QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS", raising=False)
|
||||
assert Settings.from_env().audit_heartbeat_interval_seconds == FRAME_SECONDS
|
||||
monkeypatch.setenv("QONTO_AUDIT_HEARTBEAT_INTERVAL_SECONDS", "600")
|
||||
assert Settings.from_env().audit_heartbeat_interval_seconds == 600
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue