cli: specialize error for missing workflows dir in remote input (#1324)
Some checks are pending
CI / Lint (push) Waiting to run
CI / Test (push) Waiting to run
CI / Test site build (push) Waiting to run
CI / All tests pass (push) Blocked by required conditions
zizmor wheel builds for PyPI 🐍 / Build Linux wheels (musllinux) (push) Waiting to run
zizmor wheel builds for PyPI 🐍 / Build Windows wheels (push) Waiting to run
zizmor wheel builds for PyPI 🐍 / Build macOS wheels (push) Waiting to run
zizmor wheel builds for PyPI 🐍 / Build source distribution (push) Waiting to run
zizmor wheel builds for PyPI 🐍 / Release (push) Blocked by required conditions
zizmor wheel builds for PyPI 🐍 / Build Linux wheels (manylinux) (push) Waiting to run
Deploy zizmor documentation site 🌐 / Deploy zizmor documentation to GitHub Pages 🌐 (push) Waiting to run
GitHub Actions Security Analysis with zizmor 🌈 / Run zizmor 🌈 (push) Waiting to run

This commit is contained in:
William Woodruff 2025-11-08 14:33:14 -05:00 committed by GitHub
parent 2e85156ddf
commit 327844d3da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 70 additions and 1 deletions

View file

@ -711,7 +711,13 @@ impl Client {
.await
.map_err(ClientError::from)?
.error_for_status()
.map_err(ClientError::from)?
.map_err(|err| match err {
// TODO: Disambiguate a 404 from missing repo vs missing workflows dir.
e if e.status() == Some(StatusCode::NOT_FOUND) => {
CollectionError::RemoteWithoutWorkflows(ClientError::from(e), slug.to_string())
}
e => ClientError::from(e).into(),
})?
.json()
.await
.map_err(ClientError::from)?;

View file

@ -931,6 +931,24 @@ async fn main() -> ExitCode {
Some(report)
}
CollectionError::RemoteWithoutWorkflows(_, slug) => {
let group = Group::with_title(Level::ERROR.primary_title(err.to_string()))
.elements([
Level::HELP.message(
format!(
"ensure that {slug} contains one or more workflows under `.github/workflows/`"
)
),
Level::HELP.message(
format!("ensure that {slug} exists and you have access to it")
)
]);
let renderer = Renderer::styled();
let report = renderer.render(&[group]);
Some(report)
}
_ => None,
},
_ => None,

View file

@ -72,6 +72,12 @@ pub(crate) enum CollectionError {
#[error("invalid input: must have .yml or .yaml extension")]
InvalidExtension,
/// Workflow-specific collection was requested, but the remote
/// input doesn't contain any workflows. This typically means the remote
/// repository doesn't have a `.github` or `.github/workflows` directory.
#[error("input {1} doesn't contain any workflows")]
RemoteWithoutWorkflows(#[source] ClientError, String),
/// A GitHub API error occurred while fetching a remote input.
#[error("GitHub API error while fetching remote input")]
Client(#[from] ClientError),

View file

@ -396,3 +396,37 @@ fn issue_1286() -> Result<()> {
Ok(())
}
/// Regression test for #1300.
///
/// Ensures that we produce a useful error when a user specifies
/// `--collect=workflows` on a remote input that doesn't have a
/// `.github/workflows/` directory.
#[cfg_attr(not(feature = "gh-token-tests"), ignore)]
#[test]
fn issue_1300() -> Result<()> {
insta::assert_snapshot!(
zizmor()
.expects_failure(true)
.output(OutputMode::Both)
.offline(false)
.args(["--collect=workflows"])
.input("woodruffw-experiments/empty")
.run()?,
@r"
🌈 zizmor v@@VERSION@@
fatal: no audit was performed
error: input @@INPUT@@ doesn't contain any workflows
|
= help: ensure that @@INPUT@@ contains one or more workflows under `.github/workflows/`
= help: ensure that @@INPUT@@ exists and you have access to it
Caused by:
0: input @@INPUT@@ doesn't contain any workflows
1: request error while accessing GitHub API
2: HTTP status client error (404 Not Found) for url (https://api.github.com/repos/@@INPUT@@/contents/.github/workflows)
"
);
Ok(())
}

View file

@ -9,6 +9,11 @@ of `zizmor`.
## Next (UNRELEASED)
### Enhancements 🌱
* `zizmor` now produces a more useful error message when asked to
collect only workflows from a remote input that contains no workflows (#1324)
### Performance Improvements 🚄
* `zizmor`'s core has been refactored to be asynchronous, making online