From 6c30ae3181b869d8774010a7c42eed25ee955098bfd42448cfa792bbc0b52c2e Mon Sep 17 00:00:00 2001 From: Tyler J King Date: Sat, 25 Apr 2026 06:05:22 -0400 Subject: [PATCH] bascule-gateway: BASCULE_DEMO_AUDIT=1 startup synthesizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- bascule-gateway/src/main.rs | 48 +++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/bascule-gateway/src/main.rs b/bascule-gateway/src/main.rs index 468ac7e..645ae95 100644 --- a/bascule-gateway/src/main.rs +++ b/bascule-gateway/src/main.rs @@ -138,6 +138,54 @@ spec: let _flush_handle = pipeline.clone().start_flush_loop( 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 } else { // No PG — create a pipeline with a lazy pool (will error on submit)