Skip to content

ci(publish): split release workflow into build, sign, pack, sbom generation and publish jobs - #38

Merged
damyanpetev merged 8 commits into
btraykov/strong-name-signingfrom
btraykov/release-workflow-refactoring
Aug 31, 2026
Merged

ci(publish): split release workflow into build, sign, pack, sbom generation and publish jobs#38
damyanpetev merged 8 commits into
btraykov/strong-name-signingfrom
btraykov/release-workflow-refactoring

Conversation

@turbobobbytraykov

@turbobobbytraykov turbobobbytraykov commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Restructures the NuGet release workflow (publish.yml) into isolated, least-privilege jobs, pins the expected strong-name and Authenticode signer identities, and adds signed-package digest continuity, SBOM generation, attestations, and release evidence to the same pipeline that publishes the package.

What changed

  • Split the single publish job into six chained jobs: buildsign-assembliespacksbompublishattach-to-release.
  • Set top-level permissions to none and grant each job only what it needs: sign-assemblies and pack receive Azure OIDC/Key Vault access, sbom can create attestations, publish receives only OIDC for NuGet trusted publishing, and only attach-to-release can write release assets.
  • Disabled persisted checkout credentials and pinned all 26 GitHub Actions references to immutable commit SHAs.
  • Configured build-output and signed-assembly downloads to fail on an artifact digest mismatch.
  • Added eng/IG.publickey.hex: the approved Infragistics strong-name public key, pinned in the repo and checked independently of the signing key used at build time.
  • Added eng/IG.authenticode-certificates.sha256: an allowlist containing the SHA-256 fingerprint of each approved Authenticode signing certificate.
  • Added .github/scripts/verify-strong-name.ps1: verifies each packaged assembly with sn.exe and compares its full public key/token with the repository pin, so a different internally valid key is rejected; sn.exe resolution now supports an explicit path, checks PATH, and falls back to the newest installed Windows SDK.
  • Authenticode validation now requires a valid signature and an approved certificate fingerprint; the signer subject is retained as informational release output without making certificate renewal depend on its display formatting.
  • Packs only the handed-off signed build output with --no-build --no-restore, signs and verifies the .nupkg, records its SHA-256 digest, and exposes that digest to downstream jobs.
  • Added a nested, pinned sbom-tool 4.1.5 manifest so release signing restores do not discover the SBOM tool.
  • The sbom job restores npm dependency metadata without lifecycle scripts, generates SPDX 2.2 and 3.0 documents over the signed package plus the NuGet and npm dependency graphs, verifies both outputs and the package reference, and bounds external license lookup to 180 seconds.
  • Revalidates the package immediately before attestation and binds both the build provenance and SPDX 2.2 SBOM attestations to that explicit SHA-256 digest and package name; SPDX 3.0 is retained as release evidence because actions/attest does not currently accept it as an SBOM predicate.
  • publish performs no checkout or build, verifies the package digest against both the pack and sbom jobs, revalidates its NuGet signature, and publishes through NuGet trusted publishing.
  • attach-to-release uploads the signed package, its checksum, both SPDX documents, and both attestation bundles as release assets.
  • Release trigger changed from release: created to release: published.

Why

The previous single-job workflow combined build, Key Vault signing, packaging, and NuGet publishing responsibilities, and neither the strong-name key nor the Authenticode signer identity was pinned against substitution. The new job boundaries narrow each credential's exposure, make key or signer substitution a hard failure, and prove that the exact signed and attested package is the one sent to NuGet.org and attached to the GitHub release.

Testing

  • Built all three target frameworks (net8.0/net9.0/net10.0) with a disposable strong-name key — build succeeds, only pre-existing nullable warnings.
  • Packed from the handed-off build output only (--no-build --no-restore) and confirmed the .nupkg contains all three assemblies, the generated JS bundle, and all 8 theme CSS files.
  • Confirmed verify-strong-name.ps1 rejects assemblies signed with a substituted (disposable) key, and independently re-derived the pinned public key's token.
  • Confirmed all three release DLLs match the pinned Authenticode SHA-256 fingerprint and that a substituted fingerprint is rejected.
  • Ran verify-strong-name.ps1 against the release DLLs using both automatic Windows 10 SDK resolution and an explicit -SnPath; an invalid explicit path is rejected.
  • Release run 32997751378 exercised the build, assembly signing, package signing, and digest handoffs; its actual nupkg-signed artifact was then used to validate the corrected SBOM commands locally.
  • Generated both SPDX 2.2 and SPDX 3.0 from that signed artifact and confirmed each non-empty manifest references IgniteUI.Blazor.GridLite.0.9.2-alpha.1.nupkg; SPDX 2.2 reported 98 packages and 2 files.
  • Confirmed an external license-service HTTP 524 remains a non-fatal enrichment warning and does not suppress mandatory SBOM output validation.
  • Independently confirmed the actions/attest commit SHA against the upstream v4.2.2 tag.
  • Confirmed the pinned actions/attest input contract supports explicit subject-name/subject-digest binding, and both attestations use the digest reverified immediately before attestation.
  • Ran npm ci --ignore-scripts without lifecycle execution or a change to the signed package digest, then regenerated SPDX 2.2 from the real signed artifact: 98 packages and 2 files were detected, including the .nupkg, esbuild, and vite.
  • git diff --check clean; all 26 action references in the workflow confirmed pinned to commit SHAs.
  • A fresh release event is still required to exercise the complete six-job chain at the current branch head; rerunning the older failed release would continue to use its original workflow commit.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

This PR restructures the NuGet release pipeline into chained, least-privilege jobs, adds artifact integrity checks between jobs, and integrates SBOM generation + attestation into the same workflow while pinning strong-name identity verification.

Changes:

  • Split publish.yml into build/sign/pack/sbom/publish/release-attach jobs with minimal permissions and checksum-verified artifact handoffs.
  • Added pinned strong-name public key and verification script to detect key substitution.
  • Moved SBOM generation from the standalone sbom.yml into publish.yml, including provenance + SBOM attestations.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
eng/IG.publickey.hex Adds the pinned strong-name public key blob used for validation.
.github/workflows/sbom.yml Removes standalone SBOM workflow (superseded by publish.yml).
.github/workflows/publish.yml Replaces single-job release with chained least-privilege jobs + checksum validation + SBOM/attestation and release asset upload.
.github/scripts/verify-strong-name.ps1 Verifies assembly strong-name identity against the pinned public key/token.
.github/scripts/artifact-checksums.ps1 Writes/verifies per-handoff SHA-256 manifests to detect tampering/drift.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/workflows/publish.yml
Comment thread .github/workflows/publish.yml
Comment thread .github/scripts/verify-strong-name.ps1 Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

.github/workflows/publish.yml:465

  • The least-privilege summary says only sign-assemblies, pack, and sbom receive id-token: write, but publish also receives it here. This permission is expected for NuGet trusted publishing, so update the description to include the publish job rather than documenting a stricter permission boundary than the workflow implements.
    permissions:
      contents: read
      id-token: write

Comment thread .github/workflows/publish.yml

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

.github/workflows/publish.yml:479

  • The publish job never checks out or reads repository contents, and the pinned NuGet login action only needs OIDC. Granting contents: read unnecessarily gives every step in the credential-bearing publish job a readable repository token, contrary to the least-privilege boundary introduced here; retain only id-token: write.
      contents: read

Comment thread .github/workflows/publish.yml Outdated
Comment thread .github/workflows/publish.yml Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@turbobobbytraykov

Copy link
Copy Markdown
Contributor Author

Hi, @PureWeen! I think I was able to follow your recommendations from the other PRs I stacked below this one:
#32 and #38

Can you please reveiw this one?

A successful release with all of the changes from this branch: https://github.com/IgniteUI/IgniteUI.Blazor.GridLite/releases/tag/0.9.2-alpha.2
and the workflow run that produced it: https://github.com/IgniteUI/IgniteUI.Blazor.GridLite/actions/runs/33002796906

@damyanpetev
damyanpetev merged commit 976db8b into btraykov/strong-name-signing Aug 31, 2026
5 checks passed
@damyanpetev
damyanpetev deleted the btraykov/release-workflow-refactoring branch August 31, 2026 15:39
damyanpetev added a commit that referenced this pull request Aug 31, 2026
* Strong-name signing for the assemblies

* ci(publish): split release workflow into build, sign, pack, sbom generation and publish jobs (#38)
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.

3 participants