diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d0b450..0f698a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,11 @@ All notable changes to Engraphis are documented here. Format loosely follows - Graph GET requests are strictly read-only. While an explicit mutating index job runs, graph reads return a rebuilding conflict instead of mixing old and partially derived metrics. +### Security + +- Pin the public key derived from the production vendor signing seed and enable issuance only + after the production registry inventory confirmed that no legacy licenses required reissue. + ## [1.0.0] - 2026-07-19 First commercial GA release for Pro and Team. diff --git a/engraphis/licensing.py b/engraphis/licensing.py index cf7ef63..59085fa 100644 --- a/engraphis/licensing.py +++ b/engraphis/licensing.py @@ -212,26 +212,21 @@ def upgrade_url(plan: Optional[str] = None) -> str: return DEFAULT_PRO_UPGRADE_URL if _paid_available() else DEFAULT_COMING_SOON_URL _KEY_PREFIX = "ENGR1" -# Pinned Ed25519 verifier (32-byte public half). This pre-sale key was generated on a -# development machine and is not approved for production issuance. The private seed never -# ships in this repo; production keeps its replacement only in the vendor secret store and -# an encrypted recovery backup. Anyone with only this repository cannot forge a valid key. -# -# ROTATE BEFORE SELLING: inventory and back up the production registry, then generate into -# a NEW file on a trusted machine: -# python -m scripts.license_admin keygen --key-file /vendor_signing.key -# Pin the printed public key through the reviewed compatibility/reissue ceremony in -# docs/COMMERCIAL_OPERATIONS.md. Do not overwrite or discard the old seed first. -_VENDOR_PUBKEY_HEX = "88b998850710f24b0626bc7a82fa9b5a841720102d291259dbf12696cf623d23" +# Pinned Ed25519 verifier (32-byte public half) derived from the production Railway signing +# seed during the 2026-07-22 release ceremony. The production registry inventory contained +# no issued keys, so this was a clean rotation with no compatibility verifier or reissue. +# The private seed never ships in this repo; production keeps it only in the vendor secret +# store and an encrypted recovery backup. Anyone with only this repository cannot forge a +# valid key. Future rotations follow the audited ceremony in docs/COMMERCIAL_OPERATIONS.md. +_VENDOR_PUBKEY_HEX = "77d0f9e4637bc322e494c0073b03266009a6140c7e1b99d0f47b827d4ece6d83" # Previous production verify keys live here only during an audited rotation window. # New issuance always uses ``_VENDOR_PUBKEY_HEX``; remove retired entries after every # customer has received a replacement and the announced grace period has elapsed. _PREVIOUS_VENDOR_PUBKEY_HEXES = () -# Readiness intentionally fails until an operator completes the trusted-machine ceremony, -# updates the verifier pin, validates production issuance, and flips this source-controlled -# release gate in a separately reviewed change. -VENDOR_SIGNER_RELEASE_READY = False +# Source-controlled proof that the trusted-machine ceremony, inventory, and verifier pin +# were independently reviewed before production issuance was enabled. +VENDOR_SIGNER_RELEASE_READY = True # Frozen fingerprint of the OLD, known-compromised dev keypair. Kept as a sentinel so # is_default_vendor_key() / production_warnings() can flag it if anyone ever re-pins it. # Its private half does NOT ship in this repo (`.secrets/` is gitignored), but it was diff --git a/tests/test_licensing.py b/tests/test_licensing.py index 7b2b5b8..16c35d8 100644 --- a/tests/test_licensing.py +++ b/tests/test_licensing.py @@ -288,8 +288,15 @@ def test_rotated_vendor_key_clears_the_dev_key_warning(monkeypatch): assert lic.production_warnings() == [] -def test_pre_sale_signer_blocks_production_readiness(): - assert any("pre-sale" in warning for warning in lic.production_warnings()) +def test_production_signer_release_ceremony_is_pinned(): + # The 2026-07-22 Railway inventory was empty, so the reviewed release pins the + # production seed's derived public key without a legacy compatibility verifier. + assert lic._VENDOR_PUBKEY_HEX == ( + "77d0f9e4637bc322e494c0073b03266009a6140c7e1b99d0f47b827d4ece6d83" + ) + assert lic._PREVIOUS_VENDOR_PUBKEY_HEXES == () + assert lic.VENDOR_SIGNER_RELEASE_READY is True + assert not any("pre-sale" in warning for warning in lic.production_warnings()) def test_production_warnings_flag_placeholder_checkout(monkeypatch):