Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/audit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ jobs:
name: cargo-deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: audit-deny
- name: Generate Cargo.lock
# Cargo.lock is gitignored (.gitignore:7-13). Generate one in
# the job so the deny run has deterministic resolved versions.
run: cargo generate-lockfile
- uses: EmbarkStudios/cargo-deny-action@v2
- uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2
with:
command: check
log-level: info
Expand All @@ -66,9 +66,9 @@ jobs:
name: cargo-audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: audit-audit
- name: Generate Cargo.lock
Expand Down
54 changes: 27 additions & 27 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ jobs:
name: fmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
components: rustfmt
- run: cargo fmt --all --check
Expand All @@ -37,11 +37,11 @@ jobs:
name: clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
components: clippy
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: clippy
- run: cargo clippy --all-targets --all-features -- -D warnings
Expand All @@ -57,11 +57,11 @@ jobs:
# When bumping MSRV, update both places.
toolchain: [stable, "1.93.0"]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@master
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # master
Comment thread
jimbofreedman marked this conversation as resolved.
with:
toolchain: ${{ matrix.toolchain }}
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: test-${{ matrix.os }}-${{ matrix.toolchain }}
- run: cargo test --all-features
Expand All @@ -85,9 +85,9 @@ jobs:
- label: "default"
flags: ""
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: features-${{ matrix.label }}
- run: cargo build ${{ matrix.flags }}
Expand Down Expand Up @@ -123,11 +123,11 @@ jobs:
name: wasm
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: wasm
- run: cargo build --target wasm32-unknown-unknown --no-default-features
Expand All @@ -136,18 +136,18 @@ jobs:
name: coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
components: llvm-tools-preview
- uses: taiki-e/install-action@v2
- uses: taiki-e/install-action@41049aa56687c35e0afa74eed4f09cec4f9afabf # v2
with:
tool: cargo-llvm-cov
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: coverage
- run: cargo llvm-cov --workspace --all-features --lcov --output-path lcov.info
- uses: codecov/codecov-action@v4
- uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
files: lcov.info
fail_ci_if_error: false
Expand All @@ -159,9 +159,9 @@ jobs:
env:
RUSTDOCFLAGS: "-D warnings"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: docs
- run: cargo doc --no-deps --all-features
Expand All @@ -170,11 +170,11 @@ jobs:
name: pre-commit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
components: rustfmt, clippy
- uses: actions/setup-python@v5
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.x'
# Pin `pre-commit` so CI stays reproducible. The e2e tests assert
Expand All @@ -187,11 +187,11 @@ jobs:
# venv). Keyed on the config hash so a hook/rev change busts the
# cache; avoids re-cloning on every run and reduces flakiness from
# transient network errors.
- uses: actions/cache@v4
- uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: ~/.cache/pre-commit
key: pre-commit-${{ runner.os }}-${{ hashFiles('.pre-commit-config.yaml') }}
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: pre-commit
# `cargo test --test pre_commit_e2e` exercises pre-commit
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-plz.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ jobs:
name: release-plz
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
# release-plz walks conventional-commit history back to the
# last release tag — needs full history, not a shallow clone.
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
- name: Run release-plz
uses: MarcoIeni/release-plz-action@v0.5
uses: MarcoIeni/release-plz-action@2eb1d8bcb770b4c48ccfaad919734b38b51958c9 # v0.5
Comment thread
jimbofreedman marked this conversation as resolved.
env:
# A ref (tag/PR) created with the default GITHUB_TOKEN does NOT
# trigger other workflows (GitHub's recursion guard) — so the
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ jobs:
- target: x86_64-pc-windows-msvc
os: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable
with:
targets: ${{ matrix.target }}
- uses: Swatinem/rust-cache@v2
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
with:
shared-key: release-${{ matrix.target }}
- name: Install dist
Expand Down
56 changes: 48 additions & 8 deletions tests/audit_workflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,44 @@ fn read_deny_toml() -> String {
fs::read_to_string(&p).unwrap_or_else(|e| panic!("failed to read {}: {e}", p.display()))
}

/// True when `wf` pins `action` to `version` in either of the two forms
/// this repo accepts:
///
/// - a floating tag — `owner/action@v2`
/// - a digest pin annotated with that tag — `owner/action@<40-hex> # v2`
///
/// Both are version contracts; the digest form is the stricter of the two.
/// `renovate.json` extends `helpers:pinGitHubActionDigests`, so Renovate
/// rewrites every tag into the digest form and carries the tag over into a
/// trailing comment. Asserting only the bare tag would make the repo's own
/// supply-chain policy fail its own tests (ENG-4706 / PR #17).
///
/// Still rejected, because they drop the version contract entirely: a
/// branch ref (`@main`, `@master`), a digest with no version comment, and
/// a digest whose comment names a *different* version.
fn pins_action_at(wf: &str, action: &str, version: &str) -> bool {
let needle = format!("{action}@");
wf.lines().any(|line| {
let Some((_, rest)) = line.split_once(&needle) else {
return false;
};
// Split the git ref from any trailing `# comment`.
let (git_ref, comment) = match rest.split_once('#') {
Some((r, c)) => (r.trim(), Some(c.trim())),
None => (rest.trim(), None),
};
// Floating tag: the ref itself IS the version. Exact match, so
// `v0.5` is not satisfied by a `v0.51` tag.
if git_ref == version {
return true;
}
// Digest pin: the version moves into the comment Renovate writes.
git_ref.len() == 40
&& git_ref.chars().all(|c| c.is_ascii_hexdigit())
&& comment == Some(version)
})
}

// ---------------------------------------------------------------------------
// audit.yaml — triggers, schedule, permissions, concurrency
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -169,22 +207,24 @@ fn audit_workflow_has_separate_concurrency_group() {
#[test]
fn audit_workflow_uses_cargo_deny_action_v2() {
let wf = read_workflow();
// Tag pinning matters: @v2 floats over v2.x.x; @main would let
// upstream silently change behaviour. Lock the floating major.
// Version pinning matters: @main would let upstream silently change
// behaviour. Lock v2 — either as the floating major tag or as a
// digest pinned to it (see `pins_action_at`).
assert!(
wf.contains("EmbarkStudios/cargo-deny-action@v2"),
"audit.yaml must pin EmbarkStudios/cargo-deny-action@v2 \
(floating major). A different tag breaks the ticket's \
action-version contract."
pins_action_at(&wf, "EmbarkStudios/cargo-deny-action", "v2"),
"audit.yaml must pin EmbarkStudios/cargo-deny-action to v2 — as \
`@v2` or as `@<sha> # v2`. A different tag, a branch ref, or an \
unannotated digest breaks the ticket's action-version contract."
);
}

#[test]
fn audit_workflow_uses_audit_check_v2() {
let wf = read_workflow();
assert!(
wf.contains("rustsec/audit-check@v2"),
"audit.yaml must pin rustsec/audit-check@v2 (floating major)."
pins_action_at(&wf, "rustsec/audit-check", "v2"),
"audit.yaml must pin rustsec/audit-check to v2 — as `@v2` or as \
`@<sha> # v2`."
);
}

Expand Down
33 changes: 31 additions & 2 deletions tests/release_plz_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@ fn read_workflow() -> String {
read(".github/workflows/release-plz.yaml")
}

/// True when `wf` pins `action` to `version`, accepting both the floating
/// tag (`owner/action@v0.5`) and the digest form Renovate rewrites it into
/// (`owner/action@<40-hex> # v0.5`) — `renovate.json` extends
/// `helpers:pinGitHubActionDigests`. Branch refs, bare digests, and
/// digests annotated with a different version are still rejected.
///
/// Deliberately duplicated from `tests/audit_workflow.rs` (which carries
/// the long rationale): each workflow test file in this repo is
/// self-contained and keeps its own copy of its small string helpers.
fn pins_action_at(wf: &str, action: &str, version: &str) -> bool {
let needle = format!("{action}@");
wf.lines().any(|line| {
let Some((_, rest)) = line.split_once(&needle) else {
return false;
};
let (git_ref, comment) = match rest.split_once('#') {
Some((r, c)) => (r.trim(), Some(c.trim())),
None => (rest.trim(), None),
};
if git_ref == version {
return true;
}
git_ref.len() == 40
&& git_ref.chars().all(|c| c.is_ascii_hexdigit())
&& comment == Some(version)
})
}

// --- release-plz.toml ---

#[test]
Expand Down Expand Up @@ -137,8 +165,9 @@ fn release_plz_workflow_triggers_only_on_push_to_main() {
fn release_plz_workflow_uses_action_v0_5() {
let wf = read_workflow();
assert!(
wf.contains("MarcoIeni/release-plz-action@v0.5"),
"release-plz.yaml must pin MarcoIeni/release-plz-action@v0.5."
pins_action_at(&wf, "MarcoIeni/release-plz-action", "v0.5"),
"release-plz.yaml must pin MarcoIeni/release-plz-action to v0.5 — \
as `@v0.5` or as `@<sha> # v0.5`."
);
}

Expand Down
Loading