Skip to content

Normalize receipt signing envs and enforce Ed25519-signed receipts with ENS verification#10

Merged
GsCommand merged 1 commit intomainfrom
codex/implement-receipt-signing-and-ens-support
Feb 22, 2026
Merged

Normalize receipt signing envs and enforce Ed25519-signed receipts with ENS verification#10
GsCommand merged 1 commit intomainfrom
codex/implement-receipt-signing-and-ens-support

Conversation

@GsCommand
Copy link
Contributor

Motivation

  • Standardize and prioritize Railway-style environment variables for receipt signing so the runtime uses a single source-of-truth for private/public keys and signer id.
  • Fix recurring failure modes where keys were parsed incorrectly, receipts were unsigned, or verification failed due to format mismatches.
  • Ensure the runtime always emits cryptographically signed receipts (or fails fast) and supports ENS-based verification with optional strict KID enforcement.

Description

  • Add unified env resolution and normalization that prefers RECEIPT_SIGNING_PRIVATE_KEY_PEM_B64, RECEIPT_SIGNING_PUBLIC_KEY_B64, and RECEIPT_SIGNER_ID while continuing to accept legacy CL_ aliases, implemented in server.mjs via envAnySource/runtimeConfig normalization.
  • Decode and strictly validate keys: decode PEM_B64 -> PEM, validate private key is PKCS8 Ed25519, accept raw 32-byte public key (RECEIPT_SIGNING_PUBLIC_KEY_B64) or legacy PEM and extract raw32, and derive a deterministic kid from sha256(pubkey_raw32) (base64url slice).
  • Enforce signing invariant: all successful verb responses are deterministically signed using signReceiptEd25519Sha256 from @commandlayer/runtime-core, and the server fails fast at boot with a clear error when signer config is invalid unless DEV_AUTO_KEYS=1 (which generates ephemeral in-memory keys).
  • Improve /verify to use env pubkey by default and ?ens=1 to fetch ENS TXT (cl.sig.pub, cl.sig.canonical, optional cl.sig.kid) with optional ?strict_kid=1 enforcement, and normalize response to expose ok, reason?, signer_id, kid, hash_sha256, and verified_with.
  • Add health diagnostics exposing signer_ok, signer_id, kid, signer_source, and public_key_fingerprint, add test-only ENS mocking via ENS_MOCK_TXT_JSON, and update docs and .env.example to match the Railway canonical vars and ENS TXT format.
  • Files changed: server.mjs, runtime/tests/runtime-signing.test.mjs (new), .env.example, README.md, and docs/CONFIGURATION.md.

Testing

  • Ran unit test suite with npm run test:unit and all tests passed (16 tests across existing suites and new signing tests).
  • Ran full test + smoke flow via npm test which executed unit tests and the smoke test and succeeded end-to-end (including run-time signing and verify roundtrip).
  • Performed static check node --check server.mjs and executed an ad-hoc sample script to start the server and mint a sample receipt which showed expected /health and metadata.proof fields, confirming the kid and signature_b64 were present and valid.

Codex Task

@GsCommand GsCommand merged commit 9259871 into main Feb 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant