From 1875ed150bd713ab76b61f39a2be69a32be0c532 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 4 Mar 2026 12:28:06 +0000 Subject: [PATCH] Sync lint config and CI with bootc-dev conventions Basically just trying to reduce CI drift. Assisted-by: OpenCode (Claude claude-opus-4-6) Signed-off-by: Colin Walters --- .github/workflows/ci.yaml | 40 ++++++++++++++++++++++++--------------- Cargo.toml | 19 +++++++++++++++++++ Justfile | 33 ++++++++++++++++++++++++++++++++ examples/client.rs | 10 +++++----- src/imageproxy.rs | 2 ++ 5 files changed, 84 insertions(+), 20 deletions(-) create mode 100644 Justfile diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 84d5459..8ea7db3 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,20 +1,21 @@ name: CI permissions: - actions: read + contents: read on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] + +# don't waste job slots on superseded code +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true env: - CARGO_NET_RETRY: 10 CARGO_TERM_COLOR: always - CI: 1 - RUSTUP_MAX_RETRIES: 10 - RUST_BACKTRACE: short jobs: semver-checks: @@ -27,14 +28,27 @@ jobs: # Pinned until cargo-semver-checks supports rustdoc format v57 (Rust 1.93+) rust-toolchain: "1.92.0" + linting: + name: Lints + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v6 + - name: Set up Rust + uses: bootc-dev/actions/setup-rust@main + - name: Install tools + uses: taiki-e/install-action@v2 + with: + tool: just + - name: Install rustfmt and clippy + run: rustup component add rustfmt clippy + - name: just lint + run: just lint + build-test: name: Build+Test runs-on: ubuntu-latest container: quay.io/coreos-assembler/fcos-buildroot:testing-devel - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] steps: - name: Checkout repository uses: actions/checkout@v6 @@ -43,16 +57,12 @@ jobs: fetch-depth: 20 - name: Cache Dependencies uses: Swatinem/rust-cache@v2 - - name: cargo fmt (check) - run: cargo fmt -- --check -l - name: Compile (no features) run: cargo test --no-run - name: Compile (all features) run: cargo test --no-run --all-features - name: Test run: cargo test --all-features -- --nocapture --quiet - - name: cargo clippy (non-gating) - run: cargo clippy - name: Checkout ostree-rs-ext uses: actions/checkout@v6 with: diff --git a/Cargo.toml b/Cargo.toml index 81187b3..fd5ae70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,3 +33,22 @@ tempfile = "3.20.0" [lib] path = "src/imageproxy.rs" + +# Synchronized with https://github.com/bootc-dev/bootc/blob/main/Cargo.toml +[lints.rust] +# Require an extra opt-in for unsafe +unsafe_code = "deny" +# Absolutely must handle errors +unused_must_use = "forbid" +missing_debug_implementations = "deny" +# Feel free to comment this one out locally during development of a patch. +dead_code = "deny" + +[lints.clippy] +# These should only be in local code +dbg_macro = "deny" +todo = "deny" +# These two are in my experience the lints which are most likely +# to trigger, and among the least valuable to fix. +needless_borrow = "allow" +needless_borrows_for_generic_args = "allow" diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..58d63f6 --- /dev/null +++ b/Justfile @@ -0,0 +1,33 @@ +# Build everything +build: + cargo build --all-targets --all-features + +# Run all tests using nextest +test: + #!/bin/bash + set -euo pipefail + if command -v cargo-nextest &>/dev/null; then + cargo nextest run --all-features + else + cargo test --all-targets --all-features + fi + # https://github.com/rust-lang/cargo/issues/6669 + cargo test --doc --all-features + +# Check formatting +fmt-check: + cargo fmt -- --check -l + +# Run clippy +clippy: + cargo clippy --all-targets --all-features -- -D warnings + +# Full lint check (formatting + clippy), mirrors CI +lint: fmt-check clippy + +# Run semver checks against the last published version +semver-check: + cargo semver-checks + +# Lint and test (used by CI, and for local development) +ci: lint test diff --git a/examples/client.rs b/examples/client.rs index 1e2b409..99f81d4 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -68,7 +68,7 @@ struct Metadata { } impl CommonOpts { - fn to_config(self) -> ImageProxyConfig { + fn into_config(self) -> ImageProxyConfig { let mut r = ImageProxyConfig::default(); if self.debug { r.debug = true; @@ -81,7 +81,7 @@ impl CommonOpts { } async fn get_metadata(o: GetMetadataOpts) -> Result<()> { - let config = o.common.to_config(); + let config = o.common.into_config(); let proxy = containers_image_proxy::ImageProxy::new_with_config(config).await?; let img = proxy.open_image(&o.reference).await?; let (digest, manifest) = proxy.fetch_manifest(&img).await?; @@ -91,7 +91,7 @@ async fn get_metadata(o: GetMetadataOpts) -> Result<()> { } async fn get_blob(o: GetBlobOpts) -> Result<()> { - let config = o.common.to_config(); + let config = o.common.into_config(); let proxy = containers_image_proxy::ImageProxy::new_with_config(config).await?; let img = proxy.open_image(&o.reference).await?; let (mut blob, driver) = proxy.get_blob(&img, &o.digest, o.size).await?; @@ -115,7 +115,7 @@ async fn get_blob(o: GetBlobOpts) -> Result<()> { } async fn get_blob_raw(o: GetBlobOpts) -> Result<()> { - let config = o.common.to_config(); + let config = o.common.into_config(); let proxy = containers_image_proxy::ImageProxy::new_with_config(config).await?; let img = proxy.open_image(&o.reference).await?; let (_, mut datafd, err) = proxy.get_raw_blob(&img, &o.digest).await?; @@ -139,7 +139,7 @@ async fn get_blob_raw(o: GetBlobOpts) -> Result<()> { } async fn fetch_container_to_devnull(o: FetchContainerToDevNullOpts) -> Result<()> { - let config = o.metaopts.common.to_config(); + let config = o.metaopts.common.into_config(); let proxy = containers_image_proxy::ImageProxy::new_with_config(config).await?; let img = &proxy.open_image(&o.metaopts.reference).await?; let manifest = proxy.fetch_manifest(img).await?.1; diff --git a/src/imageproxy.rs b/src/imageproxy.rs index 3e510e9..7bca363 100644 --- a/src/imageproxy.rs +++ b/src/imageproxy.rs @@ -287,6 +287,8 @@ impl TryFrom for Command { // By default, we set up pdeathsig to "lifecycle bind" the child process to us. let mut c = config.skopeo_cmd.unwrap_or_else(|| { let mut c = std::process::Command::new("skopeo"); + // SAFETY: set_parent_process_death_signal is async-signal-safe + #[allow(unsafe_code)] unsafe { c.pre_exec(|| { Ok(rustix::process::set_parent_process_death_signal(Some(