bascule-gateway: BASCULE_DEMO_AUDIT=1 startup synthesizer

Adds an env-gated startup hook that submits one synthetic AuditEvent
(notarize=true) to the AuditPipeline. The flush_loop then submits the
leaf to QM via CreateAnchor on its next cycle, demonstrating the
bascule→QM integration end-to-end without requiring real OIDC sessions
(genesis hasn't lifted the realm yet).

Default off — only triggers if BASCULE_DEMO_AUDIT=1 in pod env. Leaves
no permanent test surface in normal deployments. Slated for removal
once OIDC sessions can drive the path through the auth filter chain;
keeping it default-off makes that removal a no-op for production.

Signed-off-by: Tyler J King <tking@guildhouse.dev>
This commit is contained in:
Tyler J King 2026-04-25 06:05:22 -04:00
parent eab96ef3d4
commit 6c30ae3181

View file

@ -138,6 +138,54 @@ spec:
let _flush_handle = pipeline.clone().start_flush_loop( let _flush_handle = pipeline.clone().start_flush_loop(
std::time::Duration::from_secs(config.audit_flush_interval_secs), std::time::Duration::from_secs(config.audit_flush_interval_secs),
); );
// F.4 demo entry: synthesize one notarize=true audit event at
// startup so the flush_loop has something to submit to QM. This
// is gated on BASCULE_DEMO_AUDIT=1 (off by default). It's the
// only way to exercise the bascule→QM CreateAnchor path until
// genesis lands the OIDC realm and real operator sessions can
// flow through the auth filter. Remove (or leave as a no-op
// default-off ship hatch) once OIDC works end-to-end.
if std::env::var("BASCULE_DEMO_AUDIT").as_deref() == Ok("1") {
use bascule_core::audit::{AuditEvent, ExecutionResult, ExecutionStatus, PolicyDecision};
use bascule_core::command::{ChangeClassification, CommandRecord};
use bascule_core::session::OperatorIdentity;
let demo_event = AuditEvent {
event_id: uuid::Uuid::new_v4(),
session_id: uuid::Uuid::new_v4(),
operator_identity: OperatorIdentity::Oidc {
issuer: "https://auth.guildhouse.dev/realms/ffc-hetzner-nur01".into(),
subject: "f4-demo".into(),
email: "f4-demo@guildhouse.dev".into(),
},
timestamp: chrono::Utc::now(),
command: CommandRecord {
verb: "demo".into(),
namespace: Some("bascule".into()),
resource_type: Some("audit_event".into()),
resource_name: Some("f4-demo".into()),
parameters: serde_json::json!({"phase": "F.4"}),
},
classification: ChangeClassification::Mutative,
policy_decision: PolicyDecision::allow_all_stub(),
execution_result: ExecutionResult {
status: ExecutionStatus::Success,
summary: "F.4 demo event — bascule-to-QM CreateAnchor integration proof".into(),
resources_affected: 0,
mutations_applied: 0,
},
target_resources: vec![],
target_profile_hash: None,
};
let pipeline_clone = pipeline.clone();
tokio::spawn(async move {
tracing::info!("BASCULE_DEMO_AUDIT=1 — submitting one synthetic audit event for F.4 demo");
pipeline_clone.submit(&demo_event, true).await;
});
}
pipeline pipeline
} else { } else {
// No PG — create a pipeline with a lazy pool (will error on submit) // No PG — create a pipeline with a lazy pool (will error on submit)