Skip to content

ci: protect the Playwright config and pin images by digest - #146

Merged
JOY (JOY) merged 1 commit into
mainfrom
ci/protect-playwright-pin-images
Oct 15, 2026
Merged

JOY (JOY) merged 1 commit into
mainfrom
ci/protect-playwright-pin-images

Conversation

@JOY

@JOY JOY (JOY) commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Two follow-ups from the security review of #91.

  1. Playwright config is a protected path. tools/ci/protected-paths.mjs now matches playwright*.config.{js,ts,mjs,cjs,mts,cts} and global-setup.* / global-teardown.* in any directory as test runner config. A PR can no longer turn off the e2e gate (testIgnore, grep, a global setup that exits early) without the protected-path review. tools/test/protected-paths.test.ts covers both rules, plus e2e specs and helpers that stay ordinary. The protected list in AGENTS.md and plan §G6 is updated.

  2. Images pinned by digest as image:tag@sha256:<multi-arch index digest>:

    • docker-compose.yml: postgres:17, supabase/gotrue:v2.197.0, axllent/mailpit:v1.31.5
    • Dockerfile and apps/extract/Dockerfile: node:26-slim; apps/web/Dockerfile: node:22-alpine
    • ci.yml and protected.yml: the postgres:17 service (MinIO was already pinned)

    No tag was bumped. node:26-slim now points to Node 26.12.0, pushed 2026-10-14T20:41Z, which is less than the one-day release age. The pin is the previous 26-slim build (Node 26.11.1, pushed 2026-10-08, still reachable as 26.11.1-slim). Every other digest is the current build of its tag, and all of them are at least 4 days old. AGENTS.md now has an "Updating pinned images" section. The repo has no Renovate or Dependabot config yet; both update tag@digest pins when one is added.

  3. Concurrency: ci, gitleaks, docs-check and protected set cancel-in-progress: ${{ github.event_name == 'pull_request' }}, so a push to main always finishes. The last two run only on pull_request, so they behave as before.

e2e.yml and e2e/ come from #91 and are not on main yet. Whichever of #91 and this PR merges second should pin the e2e workflow's images and use the same concurrency setting there. The new rules already cover e2e/playwright.config.ts and e2e/global-setup.ts.

This PR edits tools/ci/ and the workflows, so it runs its own edited protected workflow. No check is removed or loosened: the only workflow changes are digest pins and the concurrency expression.

Test plan

  • docker compose config --images resolves the pinned references
  • docker compose pull db auth mailpit pulls the pinned digests; node:26-slim@... and node:22-alpine@... pull, and the node 26 pin reports v26.11.1
  • pnpm -s lint, pnpm -s typecheck
  • pnpm exec vitest run tools/test (8 tests pass)
  • pnpm docs:check
  • CI builds the kernel and crove-extract images from the pinned base

Closes #127

🤖 Generated with Claude Code


📌 TL;DR

This PR hardens the CI/CD pipeline by pinning all container images to specific SHA256 digests to prevent supply-chain attacks and ensuring critical workflows (like main branch builds) are not cancelled by concurrent runs. It also expands the "protected paths" security gate to include Playwright configuration files, ensuring e2e test runners cannot be silently modified without review.

🎯 Type of Change

  • 🚀 New feature
  • 🐛 Bugfix
  • 🧹 Refactor
  • ⚡ Performance
  • 📚 Documentation
  • ⚙️ CI / Configuration

🔍 Changes Walkthrough

File Summary of Changes
.github/workflows/*.yml Updated cancel-in-progress to only cancel on pull_request events (preventing cancellation of main/push runs). Pinned postgres:17 service image to a specific digest.
AGENTS.md Added a new "Updating pinned images" section documenting the digest-pinning policy and bumping procedure. Updated the protected paths list to include Playwright configs.
Dockerfile Pinned node:26-slim base images to a specific SHA256 digest.
apps/extract/Dockerfile Pinned node:26-slim base images to a specific SHA256 digest.
apps/web/Dockerfile Pinned node:22-alpine base images to a specific SHA256 digest.
docker-compose.yml Pinned postgres:17, supabase/gotrue, and axllent/mailpit images to specific SHA256 digests.
docs/plan/crove-os-kernel.md Updated the G6 protected paths documentation to reflect the addition of Playwright config files.
tools/ci/protected-paths.mjs Added regex patterns to protect playwright*.config.* and global-setup/teardown.* files from unauthorized changes.
tools/test/protected-paths.test.ts Added test cases to verify that Playwright configs are correctly classified as protected, and that unrelated e2e files are not.

📊 Architectural Flow

flowchart TD
    subgraph "Supply Chain Security"
        A[Container Images] -->|Pinned to SHA256 Digest| B[Docker / CI Runtime]
        B -->|Immutable Build| C[Production / CI Environment]
    end

    subgraph "CI Concurrency Control"
        D[GitHub Event] --> E{Event Type?}
        E -->|pull_request| F[Cancel In-Progress: True]
        E -->|push / workflow_dispatch| G[Cancel In-Progress: False]
    end

    subgraph "Protected Paths Gate (G6)"
        H[PR Diff] --> I[tools/ci/protected-paths.mjs]
        I -->|Matches Regex| J[Playwright Configs / Global Setup]
        I -->|Matches Regex| K[Vitest / Package.json / etc.]
        J --> L[Flag as Protected]
        K --> L
        L --> M[Require Security Review / Invariant Suite]
    end
Loading

@claude claude 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.

⚠️ Code review skipped — your organization has no extra usage available to pay for this review.

If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.

Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.

@vercel

vercel Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
crove Ready Ready Preview Oct 15, 2026 4:27pm UTC

Request Review

@coderabbitai

coderabbitai Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 48 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: cca3ea39-6cd8-40da-bf24-b77f0dc862c2
📥 Commits

Reviewing files that changed from the base of the PR and between b21d931 and 199ad6f.

📒 Files selected for processing: 12
  • .github/workflows/ci.yml
  • .github/workflows/docs-check.yml
  • .github/workflows/gitleaks.yml
  • .github/workflows/protected.yml
  • AGENTS.md
  • Dockerfile
  • apps/extract/Dockerfile
  • apps/web/Dockerfile
  • docker-compose.yml
  • docs/plan/crove-os-kernel.md
  • tools/ci/protected-paths.mjs
  • tools/test/protected-paths.test.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

dos[bot]
dos Bot approved these changes Oct 15, 2026

@dos dos 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.

⏱️ Code Review completed (12 eligible files · 17,521 chars · 1 model call(s) · 1 PR unit(s))

Whole diff with bounded context at base df5f249 / head c89b42e.

✅ CLEAN_PASS: Complete diff reviewed

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request pins Docker base and service images by digest across multiple Dockerfiles and docker-compose.yml, documents the image pinning policy in AGENTS.md, and extends the protected paths list to include Playwright configuration and global setup/teardown files. The review feedback suggests broadening the regex matching global setup/teardown files to cover common naming variations (such as camelCase, snake_case, and directory structures) to prevent potential security bypasses, along with adding corresponding test cases.

// The Playwright config and global setup decide which e2e tests run (`testIgnore`, `grep`, a setup that exits
// early), so they count as test runner config in any directory.
[/(^|\/)playwright(\.[a-z]+)?\.config\.[cm]?[jt]s$/, 'test runner config'],
[/(^|\/)global-(setup|teardown)\.[cm]?[jt]s$/, 'test runner global setup'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-high high

The current regex /(^|\/)global-(setup|teardown)\.[cm]?[jt]s$/ only matches global setup/teardown files that use a hyphen (e.g., global-setup.ts). It will miss files using camelCase (e.g., globalSetup.ts), snake_case (e.g., global_setup.ts), or structured directories (e.g., global-setup/index.ts). Update the regex to match these common naming conventions and directory structures to prevent potential bypasses of the protected path gate.

Suggested change
[/(^|\/)global-(setup|teardown)\.[cm]?[jt]s$/, 'test runner global setup'],
[/(^|\/)global[-_]?(setup|teardown|Setup|Teardown)(\.[cm]?[jt]s$|\/)/, 'test runner global setup'],

Comment on lines +36 to +37
'e2e/global-setup.ts',
'e2e/global-teardown.mjs',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Add test cases for the camelCase, snake_case, and directory-based global setup/teardown variations to ensure they are correctly flagged as protected paths.

Suggested change
'e2e/global-setup.ts',
'e2e/global-teardown.mjs',
'e2e/global-setup.ts',
'e2e/global-teardown.mjs',
'e2e/globalSetup.ts',
'e2e/global_teardown.mjs',
'e2e/global-setup/index.ts',
'e2e/global-teardown/helper.js',

- protected-paths: playwright*.config.* and global-setup/teardown files in
  any directory count as test runner config, so a PR cannot quietly turn
  off the e2e gate. Tests and the protected list in AGENTS.md and the plan
  are updated.
- Pin every container image by digest (image:tag@sha256:<index digest>):
  docker-compose.yml (postgres, gotrue, mailpit), the Dockerfile base
  images, and the postgres service in ci.yml and protected.yml.
  node:26-slim is pinned to the Node 26.11.1 build because the current
  26.12.0 build is younger than the one-day release age.
- AGENTS.md: "Updating pinned images" explains how to bump a pin.
- Workflows cancel in-progress runs only for pull requests, so pushes to
  main always get a result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JOY
JOY (JOY) force-pushed the ci/protect-playwright-pin-images branch from c89b42e to 199ad6f Compare October 15, 2026 16:27
@JOY
JOY (JOY) merged commit 2f91b28 into main Oct 15, 2026
12 of 13 checks passed

This branch was successfully deployed

1 active deployment
Preview — 199ad6f5 Deployed Oct 15, 2026 by vercel[bot]
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.

CI: protect the Playwright config and pin compose images by digest

1 participant