[codex] add portable binary release validation#56
Conversation
| needs: build | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 | ||
|
|
||
| - name: Setup QEMU | ||
| uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e8 | ||
|
|
||
| - name: Download build artifacts | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 | ||
| with: | ||
| path: dist | ||
| merge-multiple: true | ||
|
|
||
| - name: Make Linux artifacts executable | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| chmod +x dist/skillet-linux-* | ||
|
|
||
| - name: Smoke test arm64 musl artifact under emulation | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| OUTPUT=$(docker run --rm --platform linux/arm64/v8 -v "$PWD/dist:/artifacts:ro" alpine:3.22 /artifacts/skillet-linux-arm64-musl --version) | ||
| printf '%s\n' "$OUTPUT" | ||
| grep -F "sklt/" <<< "$OUTPUT" | ||
|
|
||
| - name: Smoke test arm64 gnu artifact under emulation | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| OUTPUT=$(docker run --rm --platform linux/arm64/v8 -v "$PWD/dist:/artifacts:ro" ubuntu:24.04 /artifacts/skillet-linux-arm64-gnu --version) | ||
| printf '%s\n' "$OUTPUT" | ||
| grep -F "sklt/" <<< "$OUTPUT" | ||
|
|
||
| wine-smoke: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, to fix this issue you add a permissions: block to the workflow (either at the root level so it applies to all jobs, or per job) and set it to the minimum scopes required. For CI workflows that only read the code and upload artifacts (using actions that do not require repo writes), contents: read is a good minimal starting point.
For this specific workflow, the steps use:
actions/checkoutto read the repositoryjdx/mise-action,docker/setup-qemu-action,actions/upload-artifact, andactions/download-artifact
All of these operate with theGITHUB_TOKENat most needing read access to repository contents (and the artifact actions typically work without additional repo write permissions). There is no indication of any step that pushes commits, creates releases, or modifies issues/PRs.
The single best fix is therefore:
- Add a root-level
permissions:block after theon:section (e.g., after line 8) settingcontents: read. This will apply to all jobs (build,checksums,qemu-smoke,wine-smoke,docker-integration,packaging-validate, etc.) unless they override it. - No other imports, methods, or definitions are needed since this is purely a workflow configuration change.
Concretely:
-
Edit
.github/workflows/build-matrix.yaml. -
Insert:
permissions: contents: read
between the
on:block and thejobs:key.
| @@ -7,6 +7,9 @@ | ||
| pull_request: | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| build: | ||
| strategy: |
| needs: build | ||
| runs-on: ubuntu-latest | ||
|
|
||
| env: | ||
| WINEDEBUG: -all | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 | ||
|
|
||
| - name: Setup mise | ||
| uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac | ||
|
|
||
| - name: Install Wine | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| sudo apt-get update | ||
| sudo apt-get install -y wine64 | ||
|
|
||
| - name: Download build artifacts | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 | ||
| with: | ||
| path: dist | ||
| merge-multiple: true | ||
|
|
||
| - name: Smoke test Windows artifact with Wine | ||
| run: bun scripts/smoke-artifact.ts --target=windows-x64 --artifact-dir=dist --runner=wine64 | ||
|
|
||
| docker-integration: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
To fix the problem, explicitly define restricted GITHUB_TOKEN permissions in the workflow. Since none of the shown jobs perform any GitHub write operations (they check out code, download artifacts, build and smoke‑test binaries/images), they only require read access to repository contents and, optionally, to packages if images are pushed (not shown here). The best minimal fix is to add a top‑level permissions block with contents: read, which applies to all jobs that do not override it.
Concretely, in .github/workflows/build-matrix.yaml, add a root‑level permissions: section right after the name: Build Matrix line (before on:). This will ensure that build, checksums, qemu-smoke, wine-smoke, docker-integration, packaging-validate, windows-packaging-validate, and any other jobs inherit contents: read and do not get broader defaults. No additional methods, imports, or definitions are needed—this is a pure YAML configuration change.
| @@ -1,5 +1,8 @@ | ||
| name: Build Matrix | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: |
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 | ||
|
|
||
| - name: Setup mise | ||
| uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac | ||
|
|
||
| - name: Setup QEMU | ||
| uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e8 | ||
|
|
||
| - name: Build musl binaries | ||
| run: mise run build -- --targets=linux-x64-musl,linux-arm64-musl | ||
|
|
||
| - name: Smoke test amd64 Docker image | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| docker buildx create --name skillet-smoke-builder --use || docker buildx use skillet-smoke-builder | ||
| docker buildx build --platform linux/amd64 --load -t skillet:amd64 . | ||
| docker run --rm --platform linux/amd64 skillet:amd64 --help | ||
|
|
||
| - name: Smoke test arm64 Docker image | ||
| shell: bash | ||
| run: | | ||
| set -euo pipefail | ||
| docker buildx use skillet-smoke-builder | ||
| docker buildx build --platform linux/arm64 --load -t skillet:arm64 . | ||
| docker run --rm --platform linux/arm64 skillet:arm64 --help | ||
|
|
||
| packaging-validate: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, fix this by adding an explicit permissions: block that grants only the minimal required scopes (usually contents: read) either at the workflow root (affecting all jobs) or on specific jobs. This prevents the workflow from inheriting potentially broader default permissions from the repository or organization.
For this workflow, the safest and simplest change without altering functionality is to define a workflow-level permissions block immediately after the name: (or after on:), setting contents: read. None of the shown jobs perform write operations to the repository or other resources via GITHUB_TOKEN; they mostly check out code, download artifacts, build, and run tests. actions/checkout operates fine with contents: read. Therefore, we can add:
permissions:
contents: readnear the top of .github/workflows/build-matrix.yaml. This will apply to all jobs, including docker-integration (line 150) where CodeQL reported the issue, and will remove the warning while preserving existing behavior.
Concretely:
- Edit
.github/workflows/build-matrix.yaml. - Insert a workflow-level
permissions:block between line 1 (name: Build Matrix) and line 3 (on:), or betweenon:andjobs:. I’ll place it right after thename:for clarity. - No imports or additional methods are needed since this is a YAML configuration change only.
| @@ -1,5 +1,8 @@ | ||
| name: Build Matrix | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: |
| needs: checksums | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 | ||
|
|
||
| - name: Setup mise | ||
| uses: jdx/mise-action@c37c93293d6b742fc901e1406b8f764f6fb19dac | ||
|
|
||
| - name: Download checksum artifact | ||
| uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 | ||
| with: | ||
| name: skillet-checksums | ||
| path: dist | ||
|
|
||
| - name: Validate rendered packaging assets | ||
| run: mise run package-validate | ||
|
|
||
| - name: Validate Homebrew formula syntax | ||
| run: ruby -c packaging/homebrew/skillet.rb | ||
|
|
||
| windows-packaging-validate: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
To fix this, explicitly define permissions for the GITHUB_TOKEN in the workflow and scope them as narrowly as possible. The jobs shown (docker-integration, packaging-validate, windows-packaging-validate, and the referenced checksums job) only need to read the repository contents and artifacts; they do not push commits, create releases, or modify issues/PRs. Therefore, setting contents: read at the workflow (root) level is an appropriate minimal starting point and aligns with the CodeQL suggestion.
The best minimal fix without changing existing functionality is:
- Add a
permissions:block at the root of.github/workflows/build-matrix.yaml, alongsidenameandon, so it applies to all jobs that don’t override it. - Set
contents: readwithin that block. This allowsactions/checkoutand other read-only operations to work, while preventing write operations viaGITHUB_TOKEN. - Do not alter any job steps or add any additional scopes such as
pull-requestsorissues, since nothing in the provided snippet requires them.
Concretely, in .github/workflows/build-matrix.yaml, insert:
permissions:
contents: readbetween the name: Build Matrix line and the on: block (or immediately after on: if you prefer), ensuring indentation and YAML structure remain valid. No imports or external methods are needed.
| @@ -1,5 +1,8 @@ | ||
| name: Build Matrix | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: | ||
| branches: |
| runs-on: windows-latest | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 | ||
|
|
||
| - name: Pack Chocolatey package | ||
| shell: pwsh | ||
| run: | | ||
| New-Item -ItemType Directory -Force -Path dist/choco | Out-Null | ||
| choco pack packaging/chocolatey/skillet.nuspec --outputdirectory dist/choco | ||
|
|
||
| - name: Validate Chocolatey PowerShell scripts | ||
| shell: pwsh | ||
| run: | | ||
| [scriptblock]::Create((Get-Content -Raw packaging/chocolatey/tools/chocolateyinstall.ps1)) | Out-Null | ||
| [scriptblock]::Create((Get-Content -Raw packaging/chocolatey/tools/chocolateyuninstall.ps1)) | Out-Null | ||
|
|
||
| - name: Validate winget manifests parse as YAML | ||
| shell: pwsh | ||
| run: | | ||
| $package = Get-Content package.json -Raw | ConvertFrom-Json | ||
| $wingetDir = Join-Path packaging/winget $package.version | ||
| Get-Content (Join-Path $wingetDir 'echohello-dev.skillet.yaml') -Raw | ConvertFrom-Yaml | Out-Null | ||
| Get-Content (Join-Path $wingetDir 'echohello-dev.skillet.installer.yaml') -Raw | ConvertFrom-Yaml | Out-Null | ||
| Get-Content (Join-Path $wingetDir 'echohello-dev.skillet.locale.en-US.yaml') -Raw | ConvertFrom-Yaml | Out-Null |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 6 days ago
In general, fix this issue by explicitly specifying a permissions: block that grants only the minimal required scopes for the GITHUB_TOKEN. This can be done at the workflow root (affecting all jobs that don’t override it) or per job. Here, all the shown jobs only read the repository (checkout, download artifacts, packaging/validation) and do not write to issues, PRs, or contents, so a minimal permissions: contents: read at the workflow root is appropriate.
The single best fix with no functional change is to add a top-level permissions: block right after the name: line (line 1) in .github/workflows/build-matrix.yaml. This will apply contents: read to all jobs, including windows-packaging-validate, and satisfies CodeQL’s recommendation. No additional imports or definitions are needed, and no existing steps/jobs need to be modified.
Specifically:
- In
.github/workflows/build-matrix.yaml, insert:
permissions:
contents: readafter line 1 (name: Build Matrix) and before the on: block at line 3. No other lines need to change.
| @@ -1,4 +1,6 @@ | ||
| name: Build Matrix | ||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| push: |
Summary
portableso release verification exercises the portable.exeflow end to end, and add renderer/package validation helpers for generated packaging assetsWhy
The distribution assets added in #45, #46, #47, #48, and #49 depended on compiled Bun binaries being portable, but the repository only smoke-tested host builds and did not verify that release assets were uploaded and consumable through package-manager flows. That left a gap where packaging metadata could look correct while real installs from release URLs still failed.
What changed
scripts/smoke-artifact.tsso one smoke path can validate arbitrary artifacts and wrapper runners likewine64scripts/validate-packaging.tsand amise run package-validatetask to verify rendered packaging output and manifest structure from current build checksumsbuild-matrix.yamlwith QEMU arm64 binary checks, Wine Windows binary checks, Docker amd64/arm64 image checks, and packaging validation jobsrelease-binaries.yamlto build release artifacts, upload them to the GitHub release, and verify Homebrew, Chocolatey, and winget installation from those release-backed assetsportableinstaller type for the compiled Windows binaryValidation
bun scripts/build-release.ts --targets=darwin-arm64,darwin-x64,windows-x64,linux-x64-gnu,linux-x64-musl,linux-arm64-gnu,linux-arm64-muslbun scripts/write-checksums.tsbun scripts/smoke-artifact.tsbun scripts/validate-packaging.tsbunx vitest run tests/distribution/homebrew.test.ts tests/distribution/chocolatey.test.ts tests/distribution/winget.test.ts tests/distribution/npm-package.test.ts tests/build/targets.test.tsFollow-up context