feat(licensing): verification runtime — minting deploy + prod public-key wiring (PR C)#510
Merged
Merged
Conversation
6 tasks: runLicenseCheck idempotency bug fix + regression test;
inject CACHEPLANE_LICENSE_PUBLIC_KEY into publish.yml; add
minting-deploy job to ci.yml mirroring existing Vercel deploy
patterns; document provideChat({license}) in libs/chat/README;
wire examples/chat/angular to read optional license token; final
verification + operational checklist for PR description.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previously, repeat calls with the same (package, token) tuple short- circuited to the literal 'licensed' regardless of what was actually computed on the first call. That hid 'missing' / 'expired' / 'tampered' statuses from any caller that invoked the check twice. Switches the dedup Set<string> to a Map<string, LicenseStatus> and returns the cached actual status. Adds a regression test for the no-token path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The GH secret existed since 2026-04-30 but was never referenced by any workflow. As a result, the published @ngaf/chat bundle baked in the dev-fixture public key from libs/licensing/fixtures/dev-public-key.hex — meaning real license tokens signed by the minting service would not verify in consumer apps. This single-line addition wires the secret into the env block of the build step that runs `nx ... build ... licensing`. The existing prebuild script (libs/licensing/scripts/generate-public-key.mjs) already reads the env var and emits the prod hex into license-public-key.generated.ts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Vercel project (prj_3x6SBua2bmAk374uFrp0MdqZSe9u) exists with all runtime env vars (LICENSE_SIGNING_PRIVATE_KEY_HEX, RESEND_API_KEY, Neon Postgres set) but was never deployed via CI. Adds a parallel deploy job mirroring the existing patterns, gated on push to main. Requires GH secret VERCEL_MINTING_PROJECT_ID (operational; not in this PR). Hits /api/health after deploy to confirm the service returned 200 within 30s of going live. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Shows the provideChat({ license: '…' }) snippet customers paste after
purchase, plus the build-time-define variant for public repos. Notes
that verification is offline and advisory (console.warn, no render
block) — matches PR C's enforcement policy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds provideChat({ license: environment.license }) so a smoke-test
session can drop a real token into environment.ts and exercise the
verify path end-to-end. When license is undefined (the default in
main), the demo behaves identically to today: runLicenseCheck fires
once advisorily, status is 'noncommercial' under dev NODE_ENV, no
blocking. The token is intentionally absent from environment.ts so
the demo stays unlicensed in main.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
3 tasks
blove
added a commit
that referenced
this pull request
May 21, 2026
…lane.ai (#512) The Vercel project threadplane-minting-service has the domain mint.threadplane.ai assigned (not minting.threadplane.ai which was assumed when PR #510 landed). Updates the post-deploy health check URL to match. Also the domain customers see for Stripe webhooks. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the loop on the
@ngaf/chatrelicense. Mostly operational/CI work plus one library bug fix and one example wiring. Enforcement stays advisory only (console.warn, no UI nag) per the locked brainstorm decision. Origin allowlist deferred.What this PR delivers:
runLicenseCheckidempotency bug fixed. Repeat calls with the same(package, token)tuple now return the cached actualLicenseStatus, not the literal'licensed'. Adds a regression test for the no-token path.CACHEPLANE_LICENSE_PUBLIC_KEYwired intopublish.yml. The GH secret existed since 2026-04-30 but was never referenced; published@ngaf/chattherefore baked in the dev fixture key. One-line env injection makes the prebuild script (libs/licensing/scripts/generate-public-key.mjs) pick up the prod hex.apps/minting-servicedeployed via CI. Newminting-deployjob inci.yml, parallel to existing website/cockpit/demo deploys, gated on push to main. Hitshttps://minting.threadplane.ai/api/healthafter deploy for a sanity check.libs/chat/README.mdgains a "Using a commercial license" section showing theprovideChat({ license: '…' })snippet customers paste after purchase, plus the build-time-define variant.examples/chat/angular/wired to readenvironment.license. Default isundefinedso the demo stays unlicensed in main; a smoke-test session can drop a real token intoenvironment.tsto exercise the verify path.Operational tasks (post-merge, not in code)
VERCEL_MINTING_PROJECT_ID = prj_3x6SBua2bmAk374uFrp0MdqZSe9uminting.threadplane.aito thethreadplane-minting-serviceprojecthttps://minting.threadplane.ai/api/stripe-webhook@ngaf/chatpublish after this lands: confirmdist/libs/licensing/fesm2022/*.mjscontains the prod public-key hex (not the dev fixture793132582f3d…)docs/superpowers/specs/2026-05-20-licensing-verification-runtime-design.mdTest plan
npx nx run licensing:test→ success (regression test passes; no regressions in existing tests)npx nx run chat:test→ success (no library code changed; baseline preserved)npx nx run examples-chat-angular:build→ successyaml.safe_load) → oklibs/licensing/,libs/chat/README.md,.github/workflows/{publish,ci}.yml,examples/chat/angular/, anddocs/superpowers/touched.Out of scope (deliberately)
LicenseClaimsstays{ sub, tier, iat, exp, seats }. Origin allowlist is a future PR.ChatConfig.licenseonly. Customer pastes the token into their app config.console.warnfromrunLicenseCheck.Risks
vercel env pull+@noble/ed25519.VERCEL_MINTING_PROJECT_IDsecret hasn't been added yet. The CI job'sif:gate means it only runs on push to main; a pre-merge dry-run isn't possible. Mitigation: the operational checklist above is the first thing to do post-merge.environment.licensestaysundefinedby default. The verify path is only exercised during manual smoke testing. Acceptable for an advisory-only enforcement model.🤖 Generated with Claude Code