Have quire-ci fetch secrets from the API instead of the bootstrap file
Bootstrap file still carries secrets on disk, but quire-ci now ignores
them and always resolves through the API -- regardless of transport
mode. Removes the filesystem-secret code path (the
TransportMode::Filesystem branch in SecretRegistry construction) and
the unused SecretString import.

Assisted-by: Owl Alpha via pi
change klwwnkuwlxvyzuzssnqwyknxknmlsumo
commit f92e5b5ffd63db155e5422e866c25b458c3ce352
author Alpha Chen <alpha@kejadlen.dev>
date
parent nyyltzyt
diff --git a/quire-ci/src/main.rs b/quire-ci/src/main.rs
index 000187f..b94f3e2 100644
--- a/quire-ci/src/main.rs
+++ b/quire-ci/src/main.rs
@@ -1,7 +1,6 @@
 mod sink;
 
 use std::cell::RefCell;
-use std::collections::HashMap;
 use std::io;
 use std::path::PathBuf;
 use std::rc::Rc;
@@ -16,9 +15,7 @@ use quire_core::ci::run::RunMeta;
 use quire_core::ci::runtime::{Runtime, RuntimeError, RuntimeEvent, RuntimeHandle};
 use quire_core::ci::transport::{ApiSession, Transport, TransportMode};
 use quire_core::fennel::FennelError;
-use quire_core::secret::{
-    Error as SecretError, Result as SecretResult, SecretRegistry, SecretString,
-};
+use quire_core::secret::{Error as SecretError, Result as SecretResult, SecretRegistry};
 use quire_core::telemetry::{self, FmtMode, MietteLayer};
 
 /// Errors from running a job's `run_fn`. Lua errors are re-wrapped
@@ -263,7 +260,7 @@ fn main() -> Result<()> {
                 },
                 mode: transport.transport,
             };
-            let (git_dir, meta, secrets, sentry_handoff) = load_bootstrap(&bootstrap)?;
+            let (git_dir, meta, sentry_handoff) = load_bootstrap(&bootstrap)?;
 
             // Sentry's reqwest transport spawns Tokio tasks for HTTP
             // sends, so the client must be constructed and dropped from
@@ -288,12 +285,8 @@ fn main() -> Result<()> {
             let miette_layer = MietteLayer::new();
             telemetry::init_tracing(miette_layer, FmtMode::Plain)?;
 
-            let registry = if transport.mode == TransportMode::Filesystem {
-                SecretRegistry::from(secrets)
-            } else {
-                let client = ApiClient::new(transport.session.clone());
-                SecretRegistry::new(move |name| client.fetch_secret(name))
-            };
+            let client = ApiClient::new(transport.session.clone());
+            let registry = SecretRegistry::new(move |name| client.fetch_secret(name));
 
             run_pipeline(
                 cli.workspace,
@@ -372,25 +365,12 @@ fn validate(workspace: PathBuf) -> Result<()> {
 }
 
 /// Read and parse the bootstrap file the orchestrator wrote before
-/// spawning. Wraps revealed secret values back into `SecretString`.
-///
-/// Unlinks the file as soon as the bytes are in memory — secrets only
-/// need to live on disk for the moment between `write_bootstrap` and
-/// this read, and getting them off disk early limits the blast radius
-/// of a later panic or crash leaving a 0600 file behind.
+/// spawning.
 ///
-/// The Sentry handoff, when present, carries the DSN and the
-/// orchestrator's trace id — the 0600 bootstrap file is the line of
-/// defense for both.
-#[allow(clippy::type_complexity)]
-fn load_bootstrap(
-    path: &std::path::Path,
-) -> Result<(
-    PathBuf,
-    RunMeta,
-    HashMap<String, SecretString>,
-    Option<SentryHandoff>,
-)> {
+/// Unlinks the file as soon as the bytes are in memory — getting it off
+/// disk early limits the blast radius of a later panic or crash leaving
+/// a 0600 file behind.
+fn load_bootstrap(path: &std::path::Path) -> Result<(PathBuf, RunMeta, Option<SentryHandoff>)> {
     let bytes = fs_err::read(path).into_diagnostic()?;
     if let Err(e) = fs_err::remove_file(path) {
         // Don't abort — the bytes are already loaded and the server
@@ -402,12 +382,7 @@ fn load_bootstrap(
         );
     }
     let bootstrap: Bootstrap = serde_json::from_slice(&bytes).into_diagnostic()?;
-    let secrets = bootstrap
-        .secrets
-        .into_iter()
-        .map(|(name, value)| (name, SecretString::from(value)))
-        .collect();
-    Ok((bootstrap.git_dir, bootstrap.meta, secrets, bootstrap.sentry))
+    Ok((bootstrap.git_dir, bootstrap.meta, bootstrap.sentry))
 }
 
 fn run_pipeline(
@@ -589,6 +564,7 @@ fn compile_at(workspace: &std::path::Path) -> Result<Pipeline> {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use std::collections::HashMap;
 
     #[test]
     fn parse_events_target_classifies_input() {
@@ -617,19 +593,18 @@ mod tests {
                 pushed_at: jiff::Timestamp::now(),
             },
             git_dir: PathBuf::from("/tmp/repo.git"),
-            secrets: HashMap::from([("token".to_string(), "shh".to_string())]),
+            secrets: HashMap::new(),
             sentry: None,
         };
         fs_err::write(&path, serde_json::to_vec(&bootstrap).unwrap()).expect("write");
 
-        let (git_dir, meta, secrets, sentry) = load_bootstrap(&path).expect("load");
+        let (git_dir, meta, sentry) = load_bootstrap(&path).expect("load");
         assert!(
             !path.exists(),
             "bootstrap file should be removed after read"
         );
         assert_eq!(git_dir, PathBuf::from("/tmp/repo.git"));
         assert_eq!(meta.r#ref, "HEAD");
-        assert_eq!(secrets.len(), 1);
         assert!(sentry.is_none());
     }
 }