feat(release): require signed entitlements and fail-closed packaging - #28
Conversation
43ba6b1 to
e7bea50
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 43ba6b1159
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await utimes(destination, fixedDate, fixedDate); | ||
| } | ||
|
|
||
| const zip = spawnSync('zip', ['-X', '-q', zipPath, ...files], { cwd: stageRoot, encoding: 'utf8' }); |
There was a problem hiding this comment.
Force a timezone when creating the deterministic ZIP
When the same package is built on hosts with different timezones, utimes sets a fixed instant but zip records that instant as local DOS time, producing different archive bytes and SHA-256 values. For example, creating this archive under TZ=UTC versus TZ=America/Los_Angeles records 2026-01-01 00:00 versus 2025-12-31 16:00 and yields different hashes, undermining reproducible release evidence; invoke zip with a fixed timezone such as UTC.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 50d4ef8: the packaging subprocess now runs with TZ=UTC, so ZIP DOS timestamps and the resulting SHA-256 remain stable across host time zones.
There was a problem hiding this comment.
🟡 Changes recommended
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds a Chrome Web Store “submission pack” to the repo: documented listing/policy/checklist, CI validation of required raster assets, and deterministic store ZIP packaging that intentionally fails closed until production entitlement signature verification is configured (SOD-837).
Changes:
- Add scripts + tests to validate Chrome Web Store image dimensions and to inventory/package a deterministic upload ZIP.
- Add CI step and pnpm scripts for store-asset validation and store packaging.
- Add store listing, privacy policy, and release checklist documentation plus new marketing SVG sources.
File summaries
| File | Description |
|---|---|
| tests/panel/store-package.test.mjs | Adds tests covering store asset validation, runtime inventory filtering, and fail-closed packaging gate. |
| scripts/validate-store-assets.mjs | Implements required store image dimension validation (used by CI and tests). |
| scripts/package-chrome-store.mjs | Implements deterministic runtime inventory + ZIP packaging with fail-closed entitlement safety gate. |
| README.md | Documents new CI gate and points to store submission/release docs. |
| package.json | Adds validate:store and package:store scripts. |
| docs/PRIVACY_POLICY.md | Adds a privacy policy draft intended for store publication workflow. |
| docs/CHROME_WEB_STORE_SUBMISSION.md | Adds source-of-truth listing copy + submission requirements and gates. |
| docs/CHROME_WEB_STORE_RELEASE_CHECKLIST.md | Adds an operational checklist for store release gating and manual verification. |
| assets/marketing/selectpilot-small-promo.svg | Adds source SVG for small promo tile. |
| assets/marketing/selectpilot-marquee.svg | Adds source SVG for marquee tile. |
| assets/marketing/README.md | Updates marketing asset inventory and adds validation guidance. |
| .gitignore | Ignores dist/ (store packaging output location). |
| .github/workflows/ci.yml | Adds CI step to run pnpm validate:store. |
Review details
- Files reviewed: 10/15 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
ca00980 to
50d4ef8
Compare
Final exact-SHA evidenceSigned head: Clean Hetzner verification passed:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50d4ef8a37
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| export async function assertReleaseSafe(files, root = projectRoot) { | ||
| const entitlement = await readFile(path.join(root, 'background/entitlement-service.js'), 'utf8'); | ||
| if (/const PUBLIC_KEY_HEX = ['"]{2}/.test(entitlement) || entitlement.includes('accepting as unsigned MVP')) { |
There was a problem hiding this comment.
Require signed responses before unblocking the package
Once SOD-837 populates PUBLIC_KEY_HEX and removes the warning text, this check permits packaging even though normalizeRemoteResponse still accepts both an entitlement with no response.signature and the legacy tier-only response (background/entitlement-service.js lines 110-143). In that state an unsigned response can still unlock paid features while pnpm package:store reports success, so the release gate must also ensure that every accepted production entitlement requires a valid signature.
Useful? React with 👍 / 👎.
|
|
||
| const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); | ||
| const fixedDate = new Date('2026-01-01T00:00:00Z'); | ||
| const runtimeRoots = ['agent', 'api', 'background', 'billing', 'content', 'licensing', 'panel', 'popup', 'pricing', 'shared', 'utils']; |
There was a problem hiding this comment.
Exclude remotely hosted billing code from the upload
When the entitlement blocker is cleared, recursively packaging the entire billing root includes billing/paddle-checkout.js, whose loadPaddle function injects executable JavaScript from https://cdn.paddle.com/paddle/paddle.js. Manifest V3 Store packages cannot depend on remotely hosted executable code and static review can reject the ZIP even though this module is currently unreachable, so omit unused billing modules from the inventory or bundle an allowed local implementation.
Useful? React with 👍 / 👎.
Add SOD-836 listing, privacy, asset validation, and deterministic package tooling. Store packaging remains blocked until SOD-837 configures production entitlement signatures.\n\nVerification: pnpm validate:store; node --test tests/panel/store-package.test.mjs Refs: SOD-836, SOD-837
Annotate SOD-836 package and validation surfaces for fail-closed specification coverage.\n\nVerification: spec compiler will run on Hetzner exact SHA. Refs: SOD-836
Force UTC ZIP metadata and resolve relative CLI entry paths. Add regression coverage proving both commands execute instead of silently no-op.\n\nVerification: node --test tests/panel/store-package.test.mjs Refs: SOD-836
50d4ef8 to
c2cb42a
Compare
Reject unsigned, expired, token-mismatched, unknown-key, and tampered entitlements. Keep private signer material outside Git and store packaging blocked until a production public key ring is injected. Verified: pnpm lint, pnpm typecheck, pnpm test, pnpm build, pnpm lint:manifest, pnpm validate:store, negative pnpm package:store, pnpm test:privacy, pnpm test:e2e, pnpm bench:frontier, pnpm runtime:compile-policy, pnpm runtime:validate-policy, node scripts/stress-runner.mjs
e36e36e
into
codex/ci-foundation-repair
Summary
Verification
pnpm lintpnpm typecheckpnpm test(17 panel tests, 46 server tests)pnpm buildpnpm lint:manifestpnpm validate:storepnpm package:store(expected fail-closed without production public key)pnpm test:privacypnpm test:e2e(7/7)pnpm bench:frontierpnpm runtime:compile-policypnpm runtime:validate-policynode scripts/stress-runner.mjs(10/10)Risk / Rollout