Skip to content

Signing your game

Sign your packaged game so a player’s OS launches it without a warning — macOS Gatekeeper’s “unidentified developer” block, Windows SmartScreen’s “unknown publisher” prompt. Signing proves the build came from you and that no byte changed since you signed it. You use your own developer credentials; plume3d-pack runs the signing tools for you.

What signing is — and isn’t. Code signing gives provenance + tamper-evidence: a modified build is refused or flagged. It is not encryption — it doesn’t stop someone extracting assets from a shipped build (no client-side scheme can). It is separate from the .p3d package integrity (--dev-key), which the runtime verifies every launch.

  1. Join the Apple Developer Program and create a Developer ID Application certificate (install it in your login keychain). Create an App Store Connect API key (.p8) for notarization.
  2. Store the notary credential once: xcrun notarytool store-credentials "<profile>" --key AuthKey.p8 --key-id <KEY_ID> --issuer <ISSUER_ID> (it goes into the keychain; the tool never sees the .p8).
  3. Sign + notarize + staple in one command:
Terminal window
plume3d-pack <appDir> --target macos --runtime <shipping plume3d> --out dist/ \
--codesign-identity "Developer ID Application: <Your Name> (TEAMID)" \
--notarize --notary-profile "<profile>"

plume3d-pack codesigns inside-out with the hardened runtime + a secure timestamp, submits to Apple’s notary service, and staples the ticket. The result passes spctl -a -vvv as Notarized Developer ID — a clean Mac runs it with no prompt. (First run pops a keychain “allow” dialog — click Always Allow.)

The recommended path is Azure Artifact Signing (a managed cloud CA — no hardware token, signs headless, and runs from your macOS/Linux build box via the cross-platform dotnet sign tool). Set up an Artifact Signing account, complete identity validation, create a Public Trust certificate profile, and grant your signing identity the Certificate Profile Signer role. Then:

Terminal window
plume3d-pack <appDir> --target windows --runtime <plume3d.exe> --out dist/ \
--azure-endpoint https://<region>.codesigning.azure.net/ \
--azure-account <account> --azure-cert-profile <profile>

Authentication comes from your Azure login (DefaultAzureCredential). SmartScreen reputation accrues by download volume; a valid signature shows a verified publisher.

There’s no OS gate on Linux, so provenance is a detached OpenPGP signature over a checksum manifest. Generate a signing key (gpg --quick-generate-key "<You> <email>" ed25519 sign 2y), publish the public key, then:

Terminal window
plume3d-pack <appDir> --target linux --runtime <plume3d> --out dist/ --gpg-key <KEYID>

This writes SHA256SUMS + SHA256SUMS.asc beside the .tar.gz. Users verify with your published key: gpg --verify SHA256SUMS.asc SHA256SUMS && sha256sum -c SHA256SUMS. (A passphrase-protected key prompts via gpg-agent on the first sign; preload the agent for CI.)

Official Plume3D releases ship a build-provenance attestation next to the binaries — a signed statement of which commit produced them and each file’s SHA-256. It answers “was this the real build?”, independent of the OS signature. The engine’s unsigned binary is also byte-reproducible (you can rebuild from source and get the same bytes; scripts/verify_reproducible.sh), so the attestation is checkable, not just trusted.

Each release attaches provenance.intoto.json (an in-toto SLSA v1 statement) and a detached signature provenance.intoto.json.asc. To verify a download:

Terminal window
# 1. The statement is genuinely WyldMagic's (import the published release key first):
gpg --verify provenance.intoto.json.asc provenance.intoto.json
# 2. Your download matches what was attested:
shasum -a 256 plume3d-<version>-<platform>.tar.gz
# -> must equal that file's subject.digest.sha256 in provenance.intoto.json

(The signature is a WyldMagic GPG key rather than keyless Sigstore because releases build on self-hosted CI, not a Sigstore-trusted identity provider.)


Omit the signing flags for a platform and its artifact is left unsigned. See also: Packaging & distribution, Configuration, Get Plume3D.