From b983798635ac53c8d1c53b92ad9ca46d4cec2404 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Tue, 24 Mar 2026 16:17:17 -0500 Subject: [PATCH] Only attest the changed subset of files on release re-run --- .github/workflows/release.yml | 18 ++++++++++++++---- src/github.rs | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f023691bc..6a4d18561 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -90,13 +90,23 @@ jobs: env: GITHUB_EVENT_INPUTS_SHA: ${{ github.event.inputs.sha }} GITHUB_EVENT_INPUTS_TAG: ${{ github.event.inputs.tag }} + - name: Determine files to attest + if: ${{ github.event.inputs.dry-run == 'false' }} + id: attest-check + run: | + if [ -s dist/UPLOADED_FILES ]; then + { + echo 'subject_path<> "$GITHUB_OUTPUT" + fi + - name: Generate attestations uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 - if: ${{ github.event.inputs.dry-run == 'false' }} + if: ${{ github.event.inputs.dry-run == 'false' && steps.attest-check.outputs.subject_path != '' }} with: - subject-path: | - dist/*.tar.gz - dist/*.tar.zst + subject-path: ${{ steps.attest-check.outputs.subject_path }} - name: Publish to Astral mirror if: ${{ github.event.inputs.dry-run == 'false' }} diff --git a/src/github.rs b/src/github.rs index 0d3079fe6..2d16945f5 100644 --- a/src/github.rs +++ b/src/github.rs @@ -465,6 +465,16 @@ pub async fn command_upload_release_distributions(args: &ArgMatches) -> Result<( }; }; + // Determine which files are already present on the release so we can write + // a manifest of only the newly-uploaded files (used for attestation on retry). + let existing_assets: BTreeSet = release.assets.iter().map(|a| a.name.clone()).collect(); + + let newly_uploaded_sources: Vec = wanted_filenames + .iter() + .filter(|(source, dest)| filenames.contains(*source) && !existing_assets.contains(*dest)) + .map(|(source, _)| source.clone()) + .collect(); + let mut digests = BTreeMap::new(); let retry_policy = ExponentialBackoff::builder().build_with_max_retries(5); @@ -565,5 +575,19 @@ pub async fn command_upload_release_distributions(args: &ArgMatches) -> Result<( return Err(anyhow!("SHA256SUM content mismatch; release might be bad!")); } + // Write manifest of newly-uploaded files for downstream steps (e.g., attestation). + // On a first run this includes all files; on a retry it includes only the files + // that were not already present on the release. + let manifest_lines: Vec = newly_uploaded_sources + .iter() + .map(|source| dist_dir.join(source).display().to_string()) + .collect(); + std::fs::write(dist_dir.join("UPLOADED_FILES"), manifest_lines.join("\n"))?; + println!( + "{} of {} release artifacts are new", + newly_uploaded_sources.len(), + filenames.len() + ); + Ok(()) }