Skip to content

feat(release): require signed entitlements and fail-closed packaging - #28

Merged
kristoffersodersten merged 4 commits into
codex/ci-foundation-repairfrom
codex/sod-836-store-submission-package
Aug 22, 2026
Merged

feat(release): require signed entitlements and fail-closed packaging#28
kristoffersodersten merged 4 commits into
codex/ci-foundation-repairfrom
codex/sod-836-store-submission-package

Conversation

@kristoffersodersten

@kristoffersodersten kristoffersodersten commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add deterministic Chrome Web Store assets, listing sources, validation, and package inventory.
  • Require Ed25519-signed entitlements with explicit key IDs; reject unsigned, expired, token-mismatched, unknown-key, and tampered payloads.
  • Keep private signer material outside Git and block Store packaging until a production public key ring is supplied.

Verification

  • pnpm lint
  • pnpm typecheck
  • pnpm test (17 panel tests, 46 server tests)
  • pnpm build
  • pnpm lint:manifest
  • pnpm validate:store
  • negative pnpm package:store (expected fail-closed without production public key)
  • pnpm test:privacy
  • pnpm test:e2e (7/7)
  • pnpm bench:frontier
  • pnpm runtime:compile-policy
  • pnpm runtime:validate-policy
  • node scripts/stress-runner.mjs (10/10)

Risk / Rollout

  • Paid features remain locked until the authorized production signer identity is provisioned and its public key ring is injected during release build.
  • No private key material is included.
  • Store dashboard submission, hosted policy/support URLs, reviewer approval, publication, and physical runtime acceptance remain external gates.

@kristoffersodersten
kristoffersodersten marked this pull request as ready for review August 21, 2026 16:32
Copilot AI lite review requested due to automatic review settings August 21, 2026 16:32
@kristoffersodersten
kristoffersodersten force-pushed the codex/sod-836-store-submission-package branch from 43ba6b1 to e7bea50 Compare August 21, 2026 16:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread scripts/package-chrome-store.mjs Outdated
await utimes(destination, fixedDate, fixedDate);
}

const zip = spawnSync('zip', ['-X', '-q', zipPath, ...files], { cwd: stageRoot, encoding: 'utf8' });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@kristoffersodersten kristoffersodersten Aug 21, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Comment thread scripts/package-chrome-store.mjs Outdated
Comment thread scripts/validate-store-assets.mjs Outdated
@kristoffersodersten
kristoffersodersten force-pushed the codex/sod-836-store-submission-package branch from ca00980 to 50d4ef8 Compare August 21, 2026 16:38
@kristoffersodersten

kristoffersodersten commented Aug 21, 2026

Copy link
Copy Markdown
Owner Author

Final exact-SHA evidence

Signed head: 50d4ef8a3724d38709fc93e8437abdfd2d2ca94a
Base: acd636721b467b9f14a8eab9d17e752a4c7f314b

Clean Hetzner verification passed:

  • frozen dependency install
  • lint, manifest lint, strict typecheck, build
  • 12 panel tests + 38 server tests
  • privacy suite
  • 6 exact Store image dimensions
  • 30/30 specification nodes, 0 unmapped files/functions
  • runtime policy compile/validation
  • 10/10 deterministic stress contracts
  • exact-SHA admission evidence
  • 7/7 Playwright extension E2E

pnpm package:store builds and validates the extension, then exits non-zero only at the intentional SOD-837 production entitlement-signature gate. No ZIP or unsigned bypass is emitted.

@copilot review
@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread scripts/package-chrome-store.mjs Outdated

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')) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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'];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge 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
@kristoffersodersten
kristoffersodersten force-pushed the codex/sod-836-store-submission-package branch from 50d4ef8 to c2cb42a Compare August 22, 2026 22:50
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
@kristoffersodersten kristoffersodersten changed the title feat(release): add fail-closed store package feat(release): require signed entitlements and fail-closed packaging Aug 22, 2026
@kristoffersodersten
kristoffersodersten merged commit e36e36e into codex/ci-foundation-repair Aug 22, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants