|
| 1 | +# Package Signing |
| 2 | + |
| 3 | +`ModularityKit.Mutator` release packages are signed as part of the standard package publish path. |
| 4 | + |
| 5 | +The repository signs generated `.nupkg` artifacts before they are uploaded or pushed to package feeds. |
| 6 | +Unsigned release packages are treated as a validation failure. |
| 7 | + |
| 8 | +## Signing approach |
| 9 | + |
| 10 | +The repository uses `dotnet nuget sign` with: |
| 11 | + |
| 12 | +- a code-signing certificate provided to GitHub Actions as a base64-encoded PFX |
| 13 | +- a certificate password stored in GitHub Actions secrets |
| 14 | +- an RFC 3161 timestamp server |
| 15 | +- `dotnet nuget verify --all` with the expected SHA-256 signer certificate fingerprint |
| 16 | + |
| 17 | +This keeps signing explicit, auditable, and integrated with the existing `pack` and publish workflows. |
| 18 | + |
| 19 | +## Release workflow |
| 20 | + |
| 21 | +The standard package release path is: |
| 22 | + |
| 23 | +1. pack packages in `.github/workflows/publish-artifacts.yml` |
| 24 | +2. sign every `.nupkg` |
| 25 | +3. verify every signed `.nupkg` |
| 26 | +4. upload signed artifacts |
| 27 | +5. download and verify signed artifacts again before pushing to NuGet.org or GitHub Packages |
| 28 | + |
| 29 | +The signing step changes package contents only by adding signature metadata. |
| 30 | + |
| 31 | +## Required GitHub secrets |
| 32 | + |
| 33 | +Configure these repository secrets before using the package publish workflows: |
| 34 | + |
| 35 | +- `NUGET_SIGN_CERTIFICATE_BASE64` |
| 36 | +- `NUGET_SIGN_CERTIFICATE_PASSWORD` |
| 37 | +- `NUGET_SIGN_CERTIFICATE_SHA256_FINGERPRINT` |
| 38 | +- `NUGET_SIGN_TIMESTAMP_URL` |
| 39 | +- `NUGET_USERNAME` |
| 40 | + |
| 41 | +Notes: |
| 42 | + |
| 43 | +- `NUGET_SIGN_CERTIFICATE_BASE64` should be the PFX file encoded as base64 without line wrapping changes. |
| 44 | +- `NUGET_SIGN_CERTIFICATE_SHA256_FINGERPRINT` must be the SHA-256 fingerprint of the signer certificate used for verification. |
| 45 | +- `NUGET_SIGN_TIMESTAMP_URL` should point to the timestamp service provided by the certificate issuer or your preferred RFC 3161 service. |
| 46 | +- `NUGET_USERNAME` is still required for the existing NuGet Trusted Publishing login step. |
| 47 | + |
| 48 | +## Local developer expectations |
| 49 | + |
| 50 | +Local development does not require access to signing material. |
| 51 | + |
| 52 | +Contributors can still: |
| 53 | + |
| 54 | +- build the solution |
| 55 | +- pack projects locally |
| 56 | +- run tests and smoke tests |
| 57 | + |
| 58 | +Signing is enforced in the repository release workflows, not for ordinary local development. |
| 59 | + |
| 60 | +If you have access to the signing certificate locally, you can validate package signatures with: |
| 61 | + |
| 62 | +```bash |
| 63 | +dotnet nuget verify path/to/package.nupkg --all --certificate-fingerprint <SHA256_FINGERPRINT> |
| 64 | +``` |
| 65 | + |
| 66 | +To sign a package locally with the same CLI shape used in CI: |
| 67 | + |
| 68 | +```bash |
| 69 | +dotnet nuget sign path/to/package.nupkg \ |
| 70 | + --certificate-path path/to/certificate.pfx \ |
| 71 | + --certificate-password "<PASSWORD>" \ |
| 72 | + --timestamper "<RFC3161_TIMESTAMP_URL>" \ |
| 73 | + --timestamp-hash-algorithm SHA256 \ |
| 74 | + --hash-algorithm SHA256 |
| 75 | +``` |
| 76 | + |
| 77 | +## NuGet.org expectation |
| 78 | + |
| 79 | +For NuGet.org publishing, the signing certificate must also be registered with the owning NuGet.org account or organization before publishing signed packages. |
0 commit comments