Skip to content
Closed
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
rust:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ concurrency:

jobs:
fuzz:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scorecard-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ permissions:
jobs:
analysis:
name: Scorecard Analysis
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
contents: read
security-events: write
Expand Down
49 changes: 49 additions & 0 deletions tests/workflow_runner_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//! Repository contract for deterministic GitHub-hosted runner selection.
//!
//! Wardnet's required pull-request workflows must not depend on GitHub's floating
//! `ubuntu-latest` alias. A floating image can change independently of the
//! repository and, during hosted-runner transitions, can leave exact-head jobs
//! queued before checkout. Pinning the Ubuntu image makes runner acquisition a
//! reviewed repository change while preserving GitHub-hosted execution.

use std::fs;
use std::path::Path;

const PINNED_UBUNTU_RUNNER: &str = "ubuntu-24.04";
const FLOATING_UBUNTU_RUNNER: &str = "ubuntu-latest";

const RUNNER_BACKED_WORKFLOWS: &[&str] = &[
".github/workflows/ci.yml",
".github/workflows/fuzz.yml",
".github/workflows/scorecard-analysis.yml",
];

#[test]
fn runner_backed_workflows_pin_the_hosted_ubuntu_image() {
let repository = Path::new(env!("CARGO_MANIFEST_DIR"));

for relative in RUNNER_BACKED_WORKFLOWS {
let path = repository.join(relative);
let workflow = fs::read_to_string(&path)
.unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display()));

assert!(
!workflow.contains(FLOATING_UBUNTU_RUNNER),
"{relative} must not use the floating {FLOATING_UBUNTU_RUNNER} runner alias"
);

let runners = workflow
.lines()
.filter_map(|line| line.trim().strip_prefix("runs-on:"))
.map(str::trim)
.collect::<Vec<_>>();
assert!(
!runners.is_empty(),
"{relative} must define at least one runs-on value"
);
assert!(
runners.iter().all(|runner| *runner == PINNED_UBUNTU_RUNNER),
"{relative} must use {PINNED_UBUNTU_RUNNER} for every runs-on value; found {runners:?}"
);
}
}
Loading