Skip to content

ci: attest provenance + SBOM for released .vsix, add grouped Dependabot config#228

Merged
mtskf merged 3 commits into
mainfrom
fix/post-publish-security-automation
Jul 16, 2026
Merged

ci: attest provenance + SBOM for released .vsix, add grouped Dependabot config#228
mtskf merged 3 commits into
mainfrom
fix/post-publish-security-automation

Conversation

@mtskf

@mtskf mtskf commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Summary

Post-publish security automation for the release pipeline: the publish job now attaches a signed build-provenance attestation and an SBOM attestation to the released .vsix, and a new grouped Dependabot config keeps dependencies visible without daily churn. LOW-priority supply-chain hardening; no change to the shipped extension's behaviour.

Changes

  • publish.yml — provenance + SBOM attestation. Generates an SPDX SBOM (Syft via SHA-pinned anchore/sbom-action) and attests both signed build provenance and the SBOM against the packaged extension.vsix, via the first-party actions/attest. Step order: Build → Generate SBOM → Package .vsixAudit .vsixAttest provenanceAttest SBOM → Publish. The two attest steps sit before the Marketplace / Open VSX publish, so a transient attestation failure blocks the release rather than shipping an unattested artifact, and the attested digest equals the bytes handed to the marketplaces. The third-party SBOM step is deliberately placed before the .vsix audit so that audit remains the last gate before any publish-bound step — a compromised action cannot mutate an already-audited .vsix (review finding). Consumers verify with gh attestation verify extension.vsix --repo mtskf/quoll.
  • Permissions. Adds only id-token: write + attestations: write to the publish job; everything else stays read. No artifact-metadata: write — that is only needed for registry storage records, which this file-subject attestation does not create.
  • .github/dependabot.yml (new). Weekly grouped version updates: minor+patch grouped into one PR per ecosystem (majors open individually), for both npm and GitHub Actions. Complements the already-enabled repo-level Dependabot security-updates toggle.

Design notes

  • Action choice — deviation from the TODO's literal wording. The TODO named actions/attest-build-provenance, but GitHub has unified on actions/attest: actions/attest-sbom now carries an explicit deprecation notice, and attest-build-provenance states "new implementations should use actions/attest". Using the single canonical actions/attest for both legs (Provenance mode = no sbom-path; SBOM mode = sbom-path) is the future-proof, core-API-direct choice (Quoll's top design axis) and needs the exact same two permissions.
  • SBOM scope (Codex review, acknowledged). The SBOM is generated from the build's dependency graph (path: .) — a superset that covers every component esbuild bundles into the shipped dist/ — rather than a byte-for-byte manifest of the --no-dependencies .vsix. Prod-only extraction under pnpm + bundling was judged disproportionate for this LOW-priority hardening; the superset never under-reports shipped components.
  • sbom-action least-privilege. upload-release-assets: false (the job holds only contents: read); the SBOM is retained as a downloadable workflow artifact. Syft is frozen transitively by the action SHA pin (v1.42.3, baked in SyftVersion.ts), so syft-version is intentionally left unset to avoid drift — Dependabot bumps the action and its Syft in lockstep.
  • Dependabot @types ignore (Codex review, addressed). engines.vscode@types/vscode@types/node are hand-pinned together; the ignore entries are scoped with update-types: [version-update:*] so only routine version bumps are silenced — the security-update path stays intact.

Design reviewed by Codex (5 findings: all addressed or reasoned).

Related

  • TODO: Post-publish security automation — SBOM, build provenance, grouped dependency PRs.

Test Plan

  • Both YAML files parse (validated with js-yaml).
  • Publish-job permission scope asserted to be exactly {contents: read, id-token: write, attestations: write}.
  • All actions remain SHA-pinned with trailing version comments.
  • ⚠️ The actual attestation + SBOM output can only be verified on the next v* release tag — the publish workflow runs only on tag push, so CI on this PR does not exercise these steps. Verify on the next release that provenance + SBOM attestations appear for the .vsix and gh attestation verify succeeds.

mtskf added 3 commits July 17, 2026 07:48
…ot config

Generate an SPDX SBOM (Syft via anchore/sbom-action) and attest signed
build provenance + the SBOM against the packaged extension.vsix, inserted
after the .vsix audit and before the Marketplace/Open VSX publish so an
unattested artifact is never published. Uses the unified actions/attest for
both legs (GitHub deprecated attest-sbom and folded attest-build-provenance
into actions/attest). Adds only id-token:write + attestations:write to the
publish job.

Add .github/dependabot.yml: weekly grouped version updates (npm minor+patch
grouped, majors individual; github-actions grouped), silencing only routine
version bumps of the hand-pinned @types/vscode / @types/node while leaving
the security-update path intact.
Address review findings:
- Move the third-party anchore/sbom-action before packaging/audit so a
  compromised action cannot mutate an already-audited .vsix before the
  attest/publish steps (the SBOM scans the dependency graph and does not
  need the packaged .vsix). Only first-party actions/attest steps now run
  between the audit gate and publish.
- Scope the github-actions Dependabot group to minor+patch so action majors
  open individually, matching the npm group and the config's header comment.
@mtskf
mtskf merged commit 89b2c08 into main Jul 16, 2026
1 check passed
@mtskf
mtskf deleted the fix/post-publish-security-automation branch July 16, 2026 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant