From 9d6af2bd713de6519104145ccd5ddde86620a04d Mon Sep 17 00:00:00 2001 From: Iain Lane Date: Thu, 3 Jul 2025 15:01:20 +0100 Subject: [PATCH] fix: treat empty config path as unset We had a workflow start failing when we updated Zizmor to a version which contained `ZIZMOR_CONFIG` support. The reason is that we have some logic (in a CI job) which supplies a config file dynamically using `--config`, and this logic uses the same environment variable name. The problem was that the logic was setting `ZIZMOR_CONFIG` to an empty string when we didn't have a config file to supply. This was previously fine, but since 1e123cfbe5ad7534cf7c099fd21e74293880876b Zizmor itself now looks at this variable. An empty string is treated as valid, so we try to load a config file from the empty path, which fails. ```console $ ZIZMOR_CONFIG= zizmor . fatal: no audit was performed error: failed to load config: No such file or directory (os error 2) = note: check your configuration file for errors = note: see: https://docs.zizmor.sh/configuration/ ``` This can be a bit obscure to track down and fix, so what we do here is treat the empty string the same as if the variable (or flag) was unset, so we don't try to load a config file in this scenario. --- crates/zizmor/src/config.rs | 7 ++++++- crates/zizmor/tests/integration/common.rs | 6 +++++- crates/zizmor/tests/integration/e2e.rs | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/crates/zizmor/src/config.rs b/crates/zizmor/src/config.rs index df2632df3..32f5b4deb 100644 --- a/crates/zizmor/src/config.rs +++ b/crates/zizmor/src/config.rs @@ -87,7 +87,12 @@ impl Config { return Ok(Self::default()); } - let config = match &app.config { + let app_config = app + .config + .as_ref() + .filter(|config| !config.as_str().is_empty()); + + let config = match app_config { Some(path) => serde_yaml::from_str(&fs::read_to_string(path)?)?, None => { // If the user didn't pass a config path explicitly with diff --git a/crates/zizmor/tests/integration/common.rs b/crates/zizmor/tests/integration/common.rs index bc8c6e85f..a69999347 100644 --- a/crates/zizmor/tests/integration/common.rs +++ b/crates/zizmor/tests/integration/common.rs @@ -104,6 +104,10 @@ impl Zizmor { self } + pub fn has_config_set_from_env(&self) -> bool { + self.cmd.get_envs().any(|(key, _)| key == "ZIZMOR_CONFIG") + } + pub fn run(mut self) -> Result { if self.offline { self.cmd.arg("--offline"); @@ -115,7 +119,7 @@ impl Zizmor { if let Some(config) = self.config { self.cmd.arg("--config").arg(config); - } else { + } else if !self.has_config_set_from_env() { self.cmd.arg("--no-config"); } diff --git a/crates/zizmor/tests/integration/e2e.rs b/crates/zizmor/tests/integration/e2e.rs index 795f1c117..3ec48d758 100644 --- a/crates/zizmor/tests/integration/e2e.rs +++ b/crates/zizmor/tests/integration/e2e.rs @@ -211,6 +211,26 @@ fn invalid_config_file() -> Result<()> { Ok(()) } +#[test] +fn empty_config_env_var() -> Result<()> { + zizmor() + .setenv("ZIZMOR_CONFIG", "") + .input(input_under_test("e2e-menagerie")) + .run()?; + + Ok(()) +} + +#[test] +fn empty_config_arg() -> Result<()> { + zizmor() + .config("") + .input(input_under_test("e2e-menagerie")) + .run()?; + + Ok(()) +} + #[test] fn invalid_inputs() -> Result<()> { for workflow_tc in [