diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8117c15..740d905 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,15 +28,10 @@ concurrency: group: release-${{ github.ref }} cancel-in-progress: false +# Least privilege at the top level: read-only by default. The single job below widens only the write scopes it +# needs, which is what OpenSSF Scorecard's Token-Permissions check rewards (a read-only top level, writes per job). permissions: - # Create the GitHub Release and upload the attested .nupkg/.snupkg as its assets (see the publish step). - contents: write - # Allow the job to request a GitHub OIDC token, exchanged for a short-lived NuGet API key - # via trusted publishing (no long-lived NUGET_API_KEY secret is stored). - id-token: write - # Store the signed build-provenance attestations in the repository's attestation store, - # so anyone can verify a released package with `gh attestation verify`. - attestations: write + contents: read env: DOTNET_NOLOGO: 'true' @@ -50,6 +45,15 @@ jobs: runs-on: ubuntu-latest # build + test + pack + attest + push is ~4 min; cap a hung release rather than the 6-hour default. timeout-minutes: 20 + permissions: + # Create the GitHub Release and upload the attested .nupkg/.snupkg as its assets (see the publish step). + contents: write + # Request a GitHub OIDC token, exchanged for a short-lived NuGet API key via trusted publishing + # (no long-lived NUGET_API_KEY secret is stored). + id-token: write + # Store the signed build-provenance attestations in the repository's attestation store, + # so anyone can verify a released package with `gh attestation verify`. + attestations: write steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 diff --git a/maintainers/workflows/release.en.md b/maintainers/workflows/release.en.md index b68522d..4568aae 100644 --- a/maintainers/workflows/release.en.md +++ b/maintainers/workflows/release.en.md @@ -40,8 +40,10 @@ SPDX SBOM) → upload artifacts → **attest build provenance** → **NuGet logi The workflow needs three write scopes: `contents: write` (create the Release and upload assets), `id-token: write` (mint the short-lived NuGet key via trusted -publishing), and `attestations: write` (store the signed provenance). No -long-lived `NUGET_API_KEY` is stored. +publishing), and `attestations: write` (store the signed provenance). They are +granted on the `pack-push` job only; the top-level token stays read-only +(`contents: read`) — the least-privilege shape OpenSSF Scorecard's +Token-Permissions check rewards. No long-lived `NUGET_API_KEY` is stored. ## Handle with care diff --git a/maintainers/workflows/release.fr.md b/maintainers/workflows/release.fr.md index 8f8d392..6e7e16c 100644 --- a/maintainers/workflows/release.fr.md +++ b/maintainers/workflows/release.fr.md @@ -42,7 +42,10 @@ run. Le workflow a besoin de trois périmètres en écriture : `contents: write` (créer la Release et uploader les assets), `id-token: write` (générer la clé NuGet éphémère via trusted publishing) et `attestations: write` (stocker la provenance -signée). Aucun `NUGET_API_KEY` durable n'est stocké. +signée). Ils sont accordés uniquement sur le job `pack-push` ; le token top-level +reste en lecture seule (`contents: read`) — la forme de moindre privilège que +récompense le check Token-Permissions d'OpenSSF Scorecard. Aucun `NUGET_API_KEY` +durable n'est stocké. ## À manipuler avec précaution