# Signed application releases Application release attestations are distinct from the npm package provenance already generated by the release workflow. They let a platform require a signature from a trusted build identity before extracting or running an uploaded application. An Ed25519 statement binds the exact compressed artifact SHA-256, project ID, builder and build IDs, optional source revision, migration/configuration digest, declared deployment capabilities, issuance time, and expiry. The schema digest covers the database configuration and sorted SQL migration file digests. Capabilities describe configured SQLite, job, scheduler, unsafe migration, and preview-data features; they are not a proof about arbitrary application behavior. Create a key with `generateReleaseSigningKey("build-key-1")` from `@clank.run/framework/release-attestation`. Save its JSON privately outside included application paths (for example `.clank/keys/build.json` with mode `0600`). Give only the public key to the platform: ```ts const platform = await openPlatform({ dataDirectory: "./platform-data", publicUrl: "https://platform.example", releaseAttestations: { required: true, maxAgeMs: 24 * 60 * 60 * 1000, keys: [{ keyId: "build-key-1", publicKey: "BASE64URL_PUBLIC_KEY", projects: ["EXACT_PROJECT_ID"], builders: ["local-ci"], }], }, }); ``` After local checks, upload with `clank deploy --signing-key .clank/keys/build.json --builder local-ci --build-id VERIFIED_BUILD_ID`. The CLI signs the actual upload bytes and sends the bounded `x-clank-release-attestation` header. The dry-run command only produces an artifact; use `signReleaseAttestation` to sign that artifact separately if needed. The platform rejects missing required signatures, altered bytes or statements, unknown/expired keys, wrong project or builder scope, expired statements, and attestations older than the configured maximum age. Signatures allow at most 30 seconds of future clock skew. The default signing lifetime is one hour, capped at seven days. Optional policies may allow unsigned uploads, but verify every supplied signature. Without a policy, existing unsigned deployments continue to work. Accepted statements are recorded with the release. Authorized project readers can retrieve `GET /api/projects/PROJECT_ID/releases/RELEASE_ID/attestation`. Use `verifyReleaseAttestation` with the original bytes and an independent public-key policy for external verification. Removing a trusted key prevents subsequent admission; already running releases are not stopped. Rollback to an admitted release uses existing rollback controls, rather than requiring its old statement to remain unexpired. The control database adds an additive receipt table. Rollback of framework code leaves that table harmlessly retained. Removing or relaxing the policy is an explicit operator decision; no fallback occurs on a verification error.