diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e6ff76c0..5a5b056e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2 - - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + - uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 - name: Test dependencies run: | @@ -71,7 +71,7 @@ jobs: with: persist-credentials: false - - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + - uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 - name: Test site run: make site diff --git a/.github/workflows/codegen.yml b/.github/workflows/codegen.yml index 6a37e81d..00dcb468 100644 --- a/.github/workflows/codegen.yml +++ b/.github/workflows/codegen.yml @@ -31,7 +31,7 @@ jobs: make refresh-schemas - name: create PR - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: draft: true commit-message: "[BOT] update JSON schemas from SchemaStore" @@ -63,14 +63,14 @@ jobs: with: persist-credentials: false - - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + - uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 - name: try to refresh context capabilities run: | make webhooks-to-contexts - name: create PR - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: draft: true commit-message: "[BOT] update context capabilities" @@ -101,14 +101,14 @@ jobs: with: persist-credentials: false - - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + - uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 - name: try to refresh CodeQL injection sinks run: | make codeql-injection-sinks - name: create PR - uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0 with: draft: true commit-message: "[BOT] update CodeQL injection sinks" diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index fdb073d0..c76760dd 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -60,7 +60,7 @@ jobs: shell: bash - name: Upload artifact - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: artifacts-${{ matrix.target }} path: ${{ steps.archive-release.outputs.filename }} @@ -78,7 +78,7 @@ jobs: steps: - name: Download artifacts - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: pattern: artifacts-* path: distrib/ diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index bb07ad78..132ad257 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -86,7 +86,7 @@ jobs: shell: bash - name: Upload digest - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: digests-${{ matrix.image.platform-pair }} path: ${{ runner.temp }}/digests/* @@ -107,7 +107,7 @@ jobs: steps: - name: Download digests - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: path: ${{ runner.temp }}/digests pattern: digests-* diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index 0a0b027e..41b4dcaf 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -47,7 +47,7 @@ jobs: args: --release --out dist --manifest-path crates/zizmor/Cargo.toml manylinux: ${{ matrix.platform.manylinux }} - name: Upload wheels - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: wheels-linux-${{ matrix.platform.target }} path: dist @@ -77,7 +77,7 @@ jobs: args: --release --out dist --manifest-path crates/zizmor/Cargo.toml manylinux: musllinux_1_2 - name: Upload wheels - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: wheels-musllinux-${{ matrix.platform.target }} path: dist @@ -102,7 +102,7 @@ jobs: target: ${{ matrix.platform.target }} args: --release --out dist --manifest-path crates/zizmor/Cargo.toml - name: Upload wheels - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: wheels-windows-${{ matrix.platform.target }} path: dist @@ -127,7 +127,7 @@ jobs: target: ${{ matrix.platform.target }} args: --release --out dist --manifest-path crates/zizmor/Cargo.toml - name: Upload wheels - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: wheels-macos-${{ matrix.platform.target }} path: dist @@ -145,7 +145,7 @@ jobs: command: sdist args: --out dist --manifest-path crates/zizmor/Cargo.toml - name: Upload sdist - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: wheels-sdist path: dist @@ -161,7 +161,7 @@ jobs: permissions: id-token: write # Trusted Publishing + PEP 740 attestations steps: - - uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 + - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 - name: Attest uses: astral-sh/attest-action@2c727738cea36d6c97dd85eb133ea0e0e8fe754b # v0.0.4 with: diff --git a/.github/workflows/site.yml b/.github/workflows/site.yml index b2b91177..bd0734a6 100644 --- a/.github/workflows/site.yml +++ b/.github/workflows/site.yml @@ -31,7 +31,7 @@ jobs: persist-credentials: false - name: Install the latest version of uv - uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 + uses: astral-sh/setup-uv@681c641aba71e4a1c380be3ab5e12ad51f415867 # v7.1.6 - name: build site run: make site diff --git a/.github/workflows/test-output.yml b/.github/workflows/test-output.yml index d065830a..ec9fdec6 100644 --- a/.github/workflows/test-output.yml +++ b/.github/workflows/test-output.yml @@ -67,3 +67,27 @@ jobs: --no-exit-codes \ --format github \ crates/zizmor/tests/integration/test-data/several-vulnerabilities.yml + + test-plain-presentation: + name: Test plain text presentation + runs-on: ubuntu-latest + if: contains(github.event.pull_request.labels.*.name, 'test-plain-presentation') + permissions: {} + + steps: + - name: Checkout repository + uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 + with: + persist-credentials: false + + - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2 + + - name: Run zizmor + run: | + # Normally we'd want a workflow to fail if the audit fails, + # but we're only testing presentation here. + cargo run \ + -- \ + --no-exit-codes \ + --format plain \ + crates/zizmor/tests/integration/test-data/several-vulnerabilities.yml diff --git a/Cargo.lock b/Cargo.lock index 7fd44670..a7638a54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -307,9 +307,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" dependencies = [ "serde_core", ] @@ -2129,9 +2129,9 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" dependencies = [ "base64 0.22.1", "bytes", @@ -2993,9 +2993,9 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", @@ -3116,9 +3116,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.26.2" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2135256a14d38ef69702cf6afdb6a36805d8914523de06eb4e2756cee08736f2" +checksum = "974d205cc395652cfa8b37daa053fe56eebd429acf8dc055503fee648dae981e" dependencies = [ "cc", "regex", @@ -3140,7 +3140,7 @@ dependencies = [ [[package]] name = "tree-sitter-iter" -version = "0.0.2" +version = "0.0.3" dependencies = [ "tree-sitter", "tree-sitter-yaml", @@ -3804,7 +3804,7 @@ checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" [[package]] name = "yamlpatch" -version = "0.7.0" +version = "0.8.0" dependencies = [ "indexmap", "insta", @@ -3820,7 +3820,7 @@ dependencies = [ [[package]] name = "yamlpath" -version = "0.29.0" +version = "0.31.0" dependencies = [ "line-index", "self_cell", @@ -3944,7 +3944,7 @@ dependencies = [ [[package]] name = "zizmor" -version = "1.18.0" +version = "1.19.0" dependencies = [ "annotate-snippets", "anstream", diff --git a/Cargo.toml b/Cargo.toml index 2472254a..863aca2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ annotate-snippets = "0.12.10" anstream = "0.6.21" assert_cmd = "2.1.1" async-trait = "0.1.89" -camino = "1.2.1" +camino = "1.2.2" clap = "4.5.53" clap-verbosity-flag = { version = "3.0.4", default-features = false } clap_complete = "4.5.61" @@ -52,7 +52,7 @@ line-index = "0.1.2" memchr = "2.7.6" owo-colors = "4.2.3" regex = "1.12.1" -reqwest = { version = "0.12.23", default-features = false } +reqwest = { version = "0.12.25", default-features = false } reqwest-middleware = "0.4.2" self_cell = "1" serde = { version = "1.0.228", features = ["derive"] } @@ -69,14 +69,14 @@ tower-lsp-server = "0.23" tracing = "0.1.43" tracing-indicatif = "0.3.14" tracing-subscriber = "0.3.20" -tree-sitter = "0.26.2" +tree-sitter = "0.26.3" tree-sitter-bash = "0.25.1" -tree-sitter-iter = { path = "crates/tree-sitter-iter", version = "0.0.2" } +tree-sitter-iter = { path = "crates/tree-sitter-iter", version = "0.0.3" } # Exact version since the upstream performed a breaking change outside of semver. # See: https://github.com/zizmorcore/zizmor/pull/1427 tree-sitter-powershell = "=0.25.10" -yamlpath = { path = "crates/yamlpath", version = "0.29.0" } -yamlpatch = { path = "crates/yamlpatch", version = "0.7.0" } +yamlpath = { path = "crates/yamlpath", version = "0.31.0" } +yamlpatch = { path = "crates/yamlpatch", version = "0.8.0" } tree-sitter-yaml = "0.7.2" tikv-jemallocator = "0.6" diff --git a/crates/github-actions-models/src/dependabot/v2.rs b/crates/github-actions-models/src/dependabot/v2.rs index 9865f11f..2549ca66 100644 --- a/crates/github-actions-models/src/dependabot/v2.rs +++ b/crates/github-actions-models/src/dependabot/v2.rs @@ -349,6 +349,8 @@ pub enum AllowDeny { #[derive(Deserialize, Debug, PartialEq)] #[serde(rename_all = "kebab-case")] pub enum PackageEcosystem { + /// `bazel` + Bazel, /// `bun` Bun, /// `bundler` @@ -369,6 +371,8 @@ pub enum PackageEcosystem { DotnetSdk, /// `helm` Helm, + /// `julia` + Julia, /// `elm` Elm, /// `gitsubmodule` diff --git a/crates/tree-sitter-iter/Cargo.toml b/crates/tree-sitter-iter/Cargo.toml index 46289139..0d44bf97 100644 --- a/crates/tree-sitter-iter/Cargo.toml +++ b/crates/tree-sitter-iter/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tree-sitter-iter" description = "A very simple pre-order iterator for tree-sitter CSTs" -version = "0.0.2" +version = "0.0.3" authors.workspace = true homepage.workspace = true edition.workspace = true diff --git a/crates/yamlpatch/Cargo.toml b/crates/yamlpatch/Cargo.toml index 19e36bd5..497d4d6a 100644 --- a/crates/yamlpatch/Cargo.toml +++ b/crates/yamlpatch/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yamlpatch" -version = "0.7.0" +version = "0.8.0" description = "Comment and format-preserving YAML patch operations" repository = "https://github.com/zizmorcore/zizmor/tree/main/crates/yamlpatch" keywords = ["yaml", "patch"] diff --git a/crates/yamlpath/Cargo.toml b/crates/yamlpath/Cargo.toml index fae7ecac..8a3cbc19 100644 --- a/crates/yamlpath/Cargo.toml +++ b/crates/yamlpath/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yamlpath" -version = "0.29.0" +version = "0.31.0" description = "Format-preserving YAML feature extraction" repository = "https://github.com/zizmorcore/zizmor/tree/main/crates/yamlpath" readme = "README.md" diff --git a/crates/zizmor/Cargo.toml b/crates/zizmor/Cargo.toml index dc4a9145..c241e617 100644 --- a/crates/zizmor/Cargo.toml +++ b/crates/zizmor/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "zizmor" description = "Static analysis for GitHub Actions" -version = "1.18.0" +version = "1.19.0" repository = "https://github.com/zizmorcore/zizmor" documentation = "https://docs.zizmor.sh" keywords = ["cli", "github-actions", "static-analysis", "security"] diff --git a/crates/zizmor/src/audit/excessive_permissions.rs b/crates/zizmor/src/audit/excessive_permissions.rs index 76204252..790ede83 100644 --- a/crates/zizmor/src/audit/excessive_permissions.rs +++ b/crates/zizmor/src/audit/excessive_permissions.rs @@ -14,6 +14,7 @@ use crate::{ static KNOWN_PERMISSIONS: LazyLock> = LazyLock::new(|| { [ ("actions", Severity::High), + ("artifact-metadata", Severity::Medium), ("attestations", Severity::High), ("checks", Severity::Medium), ("contents", Severity::High), @@ -21,6 +22,8 @@ static KNOWN_PERMISSIONS: LazyLock> = LazyLock::new(|| { ("discussions", Severity::Medium), ("id-token", Severity::High), ("issues", Severity::High), + // What does the write permission even do here? + ("models", Severity::Low), ("packages", Severity::High), ("pages", Severity::High), ("pull-requests", Severity::High), diff --git a/crates/zizmor/src/data/dependabot-2.0.json b/crates/zizmor/src/data/dependabot-2.0.json index f3c407f5..235fd156 100644 --- a/crates/zizmor/src/data/dependabot-2.0.json +++ b/crates/zizmor/src/data/dependabot-2.0.json @@ -647,24 +647,28 @@ }, "package-ecosystem-values": { "enum": [ + "bazel", "bun", "bundler", "cargo", "composer", + "conda", "devcontainers", "docker", "docker-compose", "dotnet-sdk", "elm", - "gitsubmodule", "github-actions", + "gitsubmodule", "gomod", "gradle", "helm", + "julia", "maven", "mix", "npm", "nuget", + "opentofu", "pip", "pub", "rust-toolchain", diff --git a/crates/zizmor/src/main.rs b/crates/zizmor/src/main.rs index bcf411f6..620ad0f5 100644 --- a/crates/zizmor/src/main.rs +++ b/crates/zizmor/src/main.rs @@ -118,6 +118,15 @@ struct App { #[arg(long, value_enum, default_value_t)] format: OutputFormat, + /// Whether to render OSC 8 links in the output. + /// + /// This affects links under audit IDs, as well as any links + /// produced by audit rules. + /// + /// Only affects `--format=plain` (the default). + #[arg(long, value_enum, default_value_t, env = "ZIZMOR_RENDER_LINKS")] + render_links: CliRenderLinks, + /// Whether to render audit URLs in the output, separately from any URLs /// embedded in OSC 8 links. /// @@ -325,6 +334,44 @@ pub(crate) enum OutputFormat { Github, } +#[derive(Debug, Default, Copy, Clone, ValueEnum)] +pub(crate) enum CliRenderLinks { + /// Render OSC 8 links in output if support is detected. + #[default] + Auto, + /// Always render OSC 8 links in output. + Always, + /// Never render OSC 8 links in output. + Never, +} + +#[derive(Debug, Copy, Clone)] +pub(crate) enum RenderLinks { + Always, + Never, +} + +impl From for RenderLinks { + fn from(value: CliRenderLinks) -> Self { + match value { + CliRenderLinks::Auto => { + // We render links if stdout is a terminal. This is assumed + // to preclude CI environments and log files. + // + // TODO: Switch this to the support-hyperlinks crate? + // See: https://github.com/zkat/supports-hyperlinks/pull/8 + if stdout().is_terminal() { + RenderLinks::Always + } else { + RenderLinks::Never + } + } + CliRenderLinks::Always => RenderLinks::Always, + CliRenderLinks::Never => RenderLinks::Never, + } + } +} + #[derive(Debug, Default, Copy, Clone, ValueEnum)] pub(crate) enum CliShowAuditUrls { /// Render audit URLs in output automatically based on output format and runtime context. @@ -641,6 +688,7 @@ async fn run(app: &mut App) -> Result { ColorMode::Never } else if std::env::var("FORCE_COLOR").is_ok() || std::env::var("CLICOLOR_FORCE").is_ok() + || utils::is_ci() { ColorMode::Always } else { @@ -816,6 +864,7 @@ async fn run(app: &mut App) -> Result { ®istry, &results, &app.show_audit_urls.into(), + &app.render_links.into(), app.naches, ), OutputFormat::Json | OutputFormat::JsonV1 => { diff --git a/crates/zizmor/src/output/plain.rs b/crates/zizmor/src/output/plain.rs index d9227e0c..e10749c6 100644 --- a/crates/zizmor/src/output/plain.rs +++ b/crates/zizmor/src/output/plain.rs @@ -7,7 +7,7 @@ use anstream::{eprintln, print, println}; use owo_colors::OwoColorize; use crate::{ - ShowAuditUrls, + RenderLinks, ShowAuditUrls, finding::{ Finding, Severity, location::{Location, LocationKind}, @@ -44,6 +44,7 @@ impl From<&Severity> for Level<'_> { pub(crate) fn finding_snippets<'doc>( registry: &'doc InputRegistry, finding: &'doc Finding<'doc>, + render_links_mode: &RenderLinks, ) -> Vec>> { // Our finding might span multiple workflows, so we need to group locations // by their enclosing workflow to generate each snippet correctly. @@ -68,15 +69,20 @@ pub(crate) fn finding_snippets<'doc>( for (input_key, locations) in locations_by_workflow { let input = registry.get_input(input_key); + let path = match render_links_mode { + RenderLinks::Always => input.link().unwrap_or(input_key.presentation_path()), + RenderLinks::Never => input_key.presentation_path(), + }; + snippets.push( Snippet::source(input.as_document().source()) .fold(true) .line_start(1) - .path(input.link().unwrap_or(input_key.presentation_path())) + .path(path) .annotations(locations.iter().map(|loc| { - let annotation = match loc.symbolic.link { - Some(ref link) => link, - None => &loc.symbolic.annotation, + let annotation = match (loc.symbolic.link.as_deref(), render_links_mode) { + (Some(link), RenderLinks::Always) => link, + _ => &loc.symbolic.annotation, }; AnnotationKind::from(loc.symbolic.kind) @@ -96,10 +102,11 @@ pub(crate) fn render_findings( registry: &InputRegistry, findings: &FindingRegistry, show_urls_mode: &ShowAuditUrls, + render_links_mode: &RenderLinks, naches_mode: bool, ) { for finding in findings.findings() { - render_finding(registry, finding, show_urls_mode); + render_finding(registry, finding, show_urls_mode, render_links_mode); println!(); } @@ -192,11 +199,19 @@ pub(crate) fn render_findings( } } -fn render_finding(registry: &InputRegistry, finding: &Finding, show_urls_mode: &ShowAuditUrls) { - let title = Level::from(&finding.determinations.severity) +fn render_finding( + registry: &InputRegistry, + finding: &Finding, + show_urls_mode: &ShowAuditUrls, + render_links_mode: &RenderLinks, +) { + let mut title = Level::from(&finding.determinations.severity) .primary_title(finding.desc) - .id(finding.ident) - .id_url(finding.url); + .id(finding.ident); + + if matches!(render_links_mode, RenderLinks::Always) { + title = title.id_url(finding.url); + } let confidence = format!( "audit confidence → {:?}", @@ -204,7 +219,7 @@ fn render_finding(registry: &InputRegistry, finding: &Finding, show_urls_mode: & ); let mut group = Group::with_title(title) - .elements(finding_snippets(registry, finding)) + .elements(finding_snippets(registry, finding, render_links_mode)) .element(Level::NOTE.message(confidence)); if let Some(tip) = &finding.tip { diff --git a/crates/zizmor/tests/integration/common.rs b/crates/zizmor/tests/integration/common.rs index 6ae9f233..52cfcb1b 100644 --- a/crates/zizmor/tests/integration/common.rs +++ b/crates/zizmor/tests/integration/common.rs @@ -42,6 +42,7 @@ pub struct Zizmor { stdin: Option, unbuffer: bool, offline: bool, + gh_token: bool, inputs: Vec, config: Option, no_config: bool, @@ -53,13 +54,19 @@ pub struct Zizmor { impl Zizmor { /// Create a new zizmor runner. pub fn new() -> Self { - let cmd = Command::new(cargo::cargo_bin!()); + let mut cmd = Command::new(cargo::cargo_bin!()); + + // Our child `zizmor` process starts with a clean environment, to + // ensure we explicitly test interactions with things like `CI` + // and `GH_TOKEN`. + cmd.env_clear(); Self { cmd, stdin: None, unbuffer: false, offline: true, + gh_token: true, inputs: vec![], config: None, no_config: false, @@ -84,11 +91,6 @@ impl Zizmor { self } - pub fn unsetenv(mut self, key: &str) -> Self { - self.cmd.env_remove(key); - self - } - pub fn input(mut self, input: impl Into) -> Self { self.inputs.push(input.into()); self @@ -114,6 +116,11 @@ impl Zizmor { self } + pub fn gh_token(mut self, flag: bool) -> Self { + self.gh_token = flag; + self + } + pub fn output(mut self, output: OutputMode) -> Self { self.output = output; self @@ -147,7 +154,12 @@ impl Zizmor { } else { // If we're running in online mode, we pre-assert the // presence of GH_TOKEN to make configuration failures more obvious. - std::env::var("GH_TOKEN").context("online tests require GH_TOKEN to be set")?; + let token = + std::env::var("GH_TOKEN").context("online tests require GH_TOKEN to be set")?; + + if self.gh_token { + self.cmd.env("GH_TOKEN", token); + } } if self.no_config && self.config.is_some() { diff --git a/crates/zizmor/tests/integration/e2e.rs b/crates/zizmor/tests/integration/e2e.rs index d64ed9bb..fc56c027 100644 --- a/crates/zizmor/tests/integration/e2e.rs +++ b/crates/zizmor/tests/integration/e2e.rs @@ -83,13 +83,21 @@ fn menagerie() -> Result<()> { #[test] fn color_control_basic() -> Result<()> { - // No terminal, so no color by default. + // No terminal and not CI, so no color by default. let no_color_default_output = zizmor() .output(OutputMode::Both) .input(input_under_test("e2e-menagerie")) .run()?; assert!(!no_color_default_output.contains("\x1b[")); + // No terminal but CI, so color by default. + let color_default_ci_output = zizmor() + .setenv("CI", "true") + .output(OutputMode::Both) + .input(input_under_test("e2e-menagerie")) + .run()?; + assert!(color_default_ci_output.contains("\x1b[")); + // Force color via --color=always. let forced_color_via_arg_output = zizmor() .output(OutputMode::Both) @@ -600,7 +608,6 @@ fn test_cant_retrieve_offline() -> Result<()> { zizmor() .expects_failure(true) .offline(true) - .unsetenv("GH_TOKEN") .args(["pypa/sampleproject"]) .run()?, @r" @@ -626,7 +633,7 @@ fn test_cant_retrieve_no_gh_token() -> Result<()> { zizmor() .expects_failure(true) .offline(false) - .unsetenv("GH_TOKEN") + .gh_token(false) .args(["pypa/sampleproject"]) .run()?, @r" diff --git a/docs/integrations.md b/docs/integrations.md index 6c863da0..bd552580 100644 --- a/docs/integrations.md +++ b/docs/integrations.md @@ -255,7 +255,7 @@ To do so, add the following to your `.pre-commit-config.yaml` `#!yaml repos:` se ```yaml - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.18.0 # (1)! + rev: v1.19.0 # (1)! hooks: - id: zizmor ``` diff --git a/docs/release-notes.md b/docs/release-notes.md index 6b0beee7..c79be398 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -9,6 +9,13 @@ of `zizmor`. ## Next (UNRELEASED) +### Enhancements 🌱 + +* The [excessive-permissions] audit is now aware of the `artifact-metadata` + and `models` permissions (#1461) + +## 1.19.0 + ### New Features 🌈 * **New audit**: [archived-uses] detects usages of archived repositories in @@ -37,6 +44,10 @@ of `zizmor`. * zizmor now produces a more useful error message when input collection yields no inputs (#1439) +* The `--render-links` flag now allows users to control `zizmor`'s OSC 8 terminal + link rendering behavior. This is particularly useful in environments that + advertise themselves as terminals but fail to correctly render or ignore + OSC 8 links (#1454) ### Performance Improvements 🚄 @@ -54,6 +65,10 @@ of `zizmor`. * Fixed a bug where the `opentofu` ecosystem was not recognized in Dependabot configuration files (#1452) +* `--color=always` no longer implies `--render-links=always`, as some + environments (like GitHub Actions) support ANSI color codes but fail + to handle OSC escapes gracefully (#1454) + ## 1.18.0 ### Enhancements 🌱 @@ -1190,7 +1205,7 @@ This is one of `zizmor`'s bigger recent releases! Key enhancements include: ### What's Changed * fix(cli): remove '0 ignored' from another place by @woodruffw in #157 -* perf: speed up impostor-commit's fast path by @woodruffw in #158 +* perf: speed up [impostor-commit]'s fast path by @woodruffw in #158 * fix(cli): fixup error printing by @woodruffw in #159 ## v0.3.1 @@ -1343,5 +1358,6 @@ This is one of `zizmor`'s bigger recent releases! Key enhancements include: [dependabot-cooldown]: ./audits.md#dependabot-cooldown [concurrency-limits]: ./audits.md#concurrency-limits [archived-uses]: ./audits.md#archived-uses +[impostor-commit]: ./audits.md#impostor-commit [exit code]: ./usage.md#exit-codes diff --git a/docs/snippets/help.txt b/docs/snippets/help.txt index 0c3cd8fc..49ac502d 100644 --- a/docs/snippets/help.txt +++ b/docs/snippets/help.txt @@ -28,6 +28,8 @@ Options: Don't show progress bars, even if the terminal supports them --format The output format to emit. By default, cargo-style diagnostics will be emitted [default: plain] [possible values: plain, json, json-v1, sarif, github] + --render-links + Whether to render OSC 8 links in the output [env: ZIZMOR_RENDER_LINKS=] [default: auto] [possible values: auto, always, never] --show-audit-urls Whether to render audit URLs in the output, separately from any URLs embedded in OSC 8 links [env: ZIZMOR_SHOW_AUDIT_URLS=] [default: auto] [possible values: auto, always, never] --color