Sigstore signatures
Keyless signing with the workflow identity, and what exactly is verified.
How signing works
There is no private key stored anywhere. During publish.yml, cosign sign-blob asks GitHub for an OIDC token naming the workflow, Fulcio issues a short-lived certificate bound to that identity, the signature is recorded in Rekor and everything is stored in a .sigstore.json bundle.
Drawing the diagram…
sequenceDiagram autonumber participant GA as GitHub Actions publish.yml participant OI as GitHub OIDC participant CO as cosign participant FU as Fulcio participant RE as Rekor participant GR as GitHub Releases participant CL as Client GA->>OI: request ID token (id-token write) OI-->>GA: JWT naming workflow, repository and ref GA->>CO: sign-blob manifest.json CO->>CO: ephemeral key pair CO->>FU: JWT and public key FU-->>CO: short lived certificate CO->>RE: signature and certificate RE-->>CO: signed entry timestamp CO-->>GA: manifest.sigstore.json bundle GA->>GR: attach manifest.json and the bundle CL->>GR: download both CL->>CL: verify chain to the trust root, signature, Rekor evidence, identity, issuer
Diagram description
Inside publish.yml, cosign asks GitHub for an OIDC token that names the workflow. Fulcio issues a short-lived certificate bound to that identity and an ephemeral key, cosign signs the blob, the signature is recorded in Rekor and everything is stored in a bundle. A client later verifies the bundle against the Sigstore trust root and checks the identity and the issuer.
Mermaid code
sequenceDiagram
autonumber
participant GA as GitHub Actions publish.yml
participant OI as GitHub OIDC
participant CO as cosign
participant FU as Fulcio
participant RE as Rekor
participant GR as GitHub Releases
participant CL as Client
GA->>OI: request ID token (id-token write)
OI-->>GA: JWT naming workflow, repository and ref
GA->>CO: sign-blob manifest.json
CO->>CO: ephemeral key pair
CO->>FU: JWT and public key
FU-->>CO: short lived certificate
CO->>RE: signature and certificate
RE-->>CO: signed entry timestamp
CO-->>GA: manifest.sigstore.json bundle
GA->>GR: attach manifest.json and the bundle
CL->>GR: download both
CL->>CL: verify chain to the trust root, signature, Rekor evidence, identity, issuerWhat is signed and with which identity
| Artifact | Bundle |
|---|---|
manifest.json | manifest.sigstore.json |
checkpoint.txt | checkpoint.sigstore.json |
- Certificate identity:
https://github.com/MacGuard/macguard-yara-channel/.github/workflows/publish.yml@refs/heads/main. - OIDC issuer:
https://token.actions.githubusercontent.com. - Workflow repository:
MacGuard/macguard-yara-channel(--certificate-github-workflow-repository).
The package rules-release.tar.gz is not signed separately: it is covered because the signed manifest contains the SHA-256 of each file and rules_root, and the package is checked to contain exactly those files.
In MacGuard
The app ships a pinned cosign (v3.1.1, SHA-256 checked) and a pinned trusted_root.json trust root; it verifies offline with --trusted-root. There is no maintained Swift Sigstore library, which is why cosign is used (see DMGTrustAuditor/DMGTrustAuditor/docs/ADR-0001-sigstore-verification.md).
LIMIT There are no SLSA or in-toto attestations. Only two blobs are signed with Sigstore. That proves which workflow signed those bytes; by itself it does not prove the build process was the expected one beyond the workflow identity.
PROPOSED Adding provenance attestations (SLSA) would be a design change; it is not implemented or scheduled in this repository.