Add SecurityPractice.md, Security Genome record, and deny-escalation lockout
Design doc for hardening qonto-assistant before deployment to
railiance01: this is the first fleet service that must be
internet-reachable (external harness clients, not just in-cluster
jobs) while holding a real bank credential. Covers identity (key-cape
in place of the interim bearer token), authorization (finance.qonto.read
in flex-auth + tenant-engine capability roles instead of the
hardcoded default_tenant_id), network exposure (facade-only internet
address), isolation profile, and a Kings Guard mapping (the existing
audit stream is already Immune-Observation-shaped; nothing to rebuild
later).
Ships one concrete, dependency-free piece of that design now:
DenyEscalationTracker locks out an actor who repeatedly triggers
arg_constraint/credential_exfil denies within a short window, closing
the gap where a probing client could retry indefinitely at whatever
rate the existing rate limiter otherwise allows. Wired through
CapabilityService, on by default, configurable via
QONTO_DENY_ESCALATION_* env vars. Ordinary denies (authz_denied,
tenant_scope) never count toward it.
Also adds specs/security-genome.yaml (kings-guard's genome-record
shape, populated now so no rework is needed once a consumer exists).
Verified: pytest -> 39 passed (8 new); REST and MCP smoke scripts both
pass against fixtures; compileall clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 22:59:06 +02:00
|
|
|
# Security Genome record for qonto-assistant.
|
|
|
|
|
#
|
|
|
|
|
# Schema per kings-guard/specs/NetKingdomImmuneArchitecture.md §9.1
|
2026-09-05 01:39:48 +02:00
|
|
|
# ("Minimum Genome Record"). King's Guard now consumes this source's structured
|
|
|
|
|
# audit events; the adjacent cadence declaration supplies stream-completeness
|
|
|
|
|
# semantics without making the consumer an authority for source intent.
|
Add SecurityPractice.md, Security Genome record, and deny-escalation lockout
Design doc for hardening qonto-assistant before deployment to
railiance01: this is the first fleet service that must be
internet-reachable (external harness clients, not just in-cluster
jobs) while holding a real bank credential. Covers identity (key-cape
in place of the interim bearer token), authorization (finance.qonto.read
in flex-auth + tenant-engine capability roles instead of the
hardcoded default_tenant_id), network exposure (facade-only internet
address), isolation profile, and a Kings Guard mapping (the existing
audit stream is already Immune-Observation-shaped; nothing to rebuild
later).
Ships one concrete, dependency-free piece of that design now:
DenyEscalationTracker locks out an actor who repeatedly triggers
arg_constraint/credential_exfil denies within a short window, closing
the gap where a probing client could retry indefinitely at whatever
rate the existing rate limiter otherwise allows. Wired through
CapabilityService, on by default, configurable via
QONTO_DENY_ESCALATION_* env vars. Ordinary denies (authz_denied,
tenant_scope) never count toward it.
Also adds specs/security-genome.yaml (kings-guard's genome-record
shape, populated now so no rework is needed once a consumer exists).
Verified: pytest -> 39 passed (8 new); REST and MCP smoke scripts both
pass against fixtures; compileall clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 22:59:06 +02:00
|
|
|
|
|
|
|
|
security_genome_record:
|
|
|
|
|
id: kg:genome:qonto-assistant
|
|
|
|
|
version: 0.1.0
|
|
|
|
|
|
|
|
|
|
ownership:
|
|
|
|
|
tenant_id: binky
|
|
|
|
|
accountable_owner: bernd.worsch
|
|
|
|
|
operational_owner: qonto-assistant
|
|
|
|
|
|
|
|
|
|
purpose:
|
|
|
|
|
intent: >
|
|
|
|
|
Sole holder of the company Qonto bank API credential; exposes
|
|
|
|
|
read-only finance capabilities (org summary, transactions,
|
|
|
|
|
CostRunRate hints) to authorized agent harnesses and operators via a
|
|
|
|
|
governed REST + MCP surface, so no client ever holds the bank key
|
|
|
|
|
directly.
|
|
|
|
|
criticality: high
|
|
|
|
|
|
|
|
|
|
identities:
|
2026-09-05 01:39:48 +02:00
|
|
|
workload_identity: "key-cape JWT verification supported; runtime enforcement is configuration-bound"
|
Add SecurityPractice.md, Security Genome record, and deny-escalation lockout
Design doc for hardening qonto-assistant before deployment to
railiance01: this is the first fleet service that must be
internet-reachable (external harness clients, not just in-cluster
jobs) while holding a real bank credential. Covers identity (key-cape
in place of the interim bearer token), authorization (finance.qonto.read
in flex-auth + tenant-engine capability roles instead of the
hardcoded default_tenant_id), network exposure (facade-only internet
address), isolation profile, and a Kings Guard mapping (the existing
audit stream is already Immune-Observation-shaped; nothing to rebuild
later).
Ships one concrete, dependency-free piece of that design now:
DenyEscalationTracker locks out an actor who repeatedly triggers
arg_constraint/credential_exfil denies within a short window, closing
the gap where a probing client could retry indefinitely at whatever
rate the existing rate limiter otherwise allows. Wired through
CapabilityService, on by default, configurable via
QONTO_DENY_ESCALATION_* env vars. Ordinary denies (authz_denied,
tenant_scope) never count toward it.
Also adds specs/security-genome.yaml (kings-guard's genome-record
shape, populated now so no rework is needed once a consumer exists).
Verified: pytest -> 39 passed (8 new); REST and MCP smoke scripts both
pass against fixtures; compileall clean.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 22:59:06 +02:00
|
|
|
deployment_identity: "TBD — pending Railiance placement decision"
|
|
|
|
|
|
|
|
|
|
capabilities:
|
|
|
|
|
provides:
|
|
|
|
|
- finance.qonto.read
|
|
|
|
|
consumes:
|
|
|
|
|
- openbao-secret.read # tenants/binky/qonto-api
|
|
|
|
|
- qonto-thirdparty-api.read
|
|
|
|
|
|
|
|
|
|
communication:
|
|
|
|
|
ingress:
|
|
|
|
|
- caller: facade-activator # not yet built — see docs/SecurityPractice.md §6
|
|
|
|
|
protocol: https
|
|
|
|
|
egress:
|
|
|
|
|
- destination: openbao
|
|
|
|
|
protocol: https
|
|
|
|
|
- destination: qonto-thirdparty-api
|
|
|
|
|
protocol: https
|
|
|
|
|
# No other egress is expected or permitted. Any additional outbound
|
|
|
|
|
# destination observed at runtime is, by definition, a deviation from
|
|
|
|
|
# this genome.
|
|
|
|
|
|
|
|
|
|
data:
|
|
|
|
|
classifications:
|
|
|
|
|
- tenant-confidential
|
|
|
|
|
- financial
|
|
|
|
|
persistence: ephemeral
|
|
|
|
|
export_allowed: false
|
|
|
|
|
|
|
|
|
|
provenance:
|
|
|
|
|
signed_artifact_required: false # not yet implemented fleet-wide
|
|
|
|
|
approved_registry: "TBD"
|
|
|
|
|
sbom_required: false # not yet implemented; tracked as a gap
|
|
|
|
|
reproducible_build_preferred: true
|
|
|
|
|
|
|
|
|
|
expected_behavior:
|
|
|
|
|
max_request_rate: "per QONTO_RATE_LIMIT_REQUESTS / QONTO_RATE_LIMIT_WINDOW_SECONDS (config.py)"
|
|
|
|
|
external_network_access: false # beyond the two declared egress destinations
|
|
|
|
|
interactive_shell: prohibited
|
|
|
|
|
privilege_escalation: prohibited
|
|
|
|
|
|
|
|
|
|
recovery:
|
|
|
|
|
redeployable: true
|
|
|
|
|
maximum_recovery_time: PT5M # stateless; cold-start dominated by scale-to-zero wake latency
|
|
|
|
|
maximum_data_loss: PT0S # no persisted state
|
|
|
|
|
|
|
|
|
|
tolerances:
|
|
|
|
|
- id: local-dev-shared-secret-auth
|
|
|
|
|
description: >
|
|
|
|
|
QONTO_ASSISTANT_MCP_TOKEN shared-secret bearer auth is tolerated
|
|
|
|
|
only for fixture-backed local development, never for a deployment
|
|
|
|
|
holding real Qonto credentials.
|
|
|
|
|
expires_at: null # revisit once key-cape integration (QONTO-WP-0004) lands
|
|
|
|
|
- id: self-asserted-actor-claims
|
|
|
|
|
description: >
|
|
|
|
|
X-Actor-* headers are self-asserted, not yet cryptographically
|
|
|
|
|
bound to verified identity. Tolerated until key-cape/flex-auth
|
|
|
|
|
integration (QONTO-WP-0004) closes this.
|
|
|
|
|
expires_at: null
|
2026-09-05 01:39:48 +02:00
|
|
|
|
|
|
|
|
# Source emission claim for the load-bearing deny observation class. The full
|
|
|
|
|
# machine-readable declaration is kept separate so consumers can ingest it
|
|
|
|
|
# without interpreting the genome schema.
|
|
|
|
|
audit_emission_cadence: audit-emission-cadence.yaml
|