chore(ci): harden supply-chain controls before reopening PRs

Isolate npm publish from PR CI, enforce frozen lockfiles and a 24h
minimumReleaseAge, and document safe pull_request_target usage so fork
PRs cannot reach publish credentials.

Co-authored-by: Rotimi Best <rotimi-best@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-10 21:00:29 +01:00
committed by Rotimi Best
co-authored by Rotimi Best
parent bbf5eb24de
commit 9adc38bd8a
13 changed files with 100 additions and 24 deletions
+5
View File
@@ -0,0 +1,5 @@
# High-risk supply-chain paths — prefer maintainer review before merge.
/.github/workflows/ @rotimi-best
/pnpm-lock.yaml @rotimi-best
/pnpm-workspace.yaml @rotimi-best
/package.json @rotimi-best
+1
View File
@@ -39,6 +39,7 @@ Fixes # (place issue number here without bracket)
- [ ] Removed all `console.logs` - [ ] Removed all `console.logs`
- [ ] Merged the latest changes from main onto my branch with `git pull origin main` - [ ] Merged the latest changes from main onto my branch with `git pull origin main`
- [ ] My changes don't cause any responsiveness issues - [ ] My changes don't cause any responsiveness issues
- [ ] If this PR changes `pnpm-lock.yaml`, `.github/workflows/**`, or publish config: call that out in the PR description
### Appreciated ### Appreciated
@@ -1,19 +1,23 @@
name: 'Apply issue labels to PR' name: 'Apply issue labels to PR'
# pull_request_target is used so labeling works for fork PRs.
# SAFE ONLY because this workflow never checks out or executes PR code.
# Do not add actions/checkout, pnpm install, build, or cache steps here.
on: on:
pull_request_target: pull_request_target:
types: types:
- opened - opened
permissions:
contents: none
issues: read
pull-requests: write
jobs: jobs:
label_on_pr: label_on_pr:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: none
issues: read
pull-requests: write
steps: steps:
- name: Apply labels from linked issue to PR - name: Apply labels from linked issue to PR
uses: actions/github-script@v5 uses: actions/github-script@v5
+5
View File
@@ -5,6 +5,11 @@ on:
types: types:
- created - created
- edited - edited
permissions:
contents: read
issues: write
jobs: jobs:
take-issue: take-issue:
name: Disable take issue name: Disable take issue
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
${{ runner.os }}-pnpm-store- ${{ runner.os }}-pnpm-store-
- name: Install dependencies - name: Install dependencies
run: pnpm i run: pnpm install --frozen-lockfile
- name: Build Storybook - name: Build Storybook
run: | run: |
@@ -0,0 +1,44 @@
name: MCP package build check
# Verifies @classroomio/mcp still builds on PRs/pushes that touch it.
# Intentionally separate from publish-mcp.yml so PR CI never sees NPM_TOKEN.
on:
pull_request:
paths:
- 'packages/mcp/**'
- 'packages/question-types/**'
- 'packages/utils/**'
- 'pnpm-lock.yaml'
- '.github/workflows/mcp-package-build-check.yml'
push:
paths:
- 'packages/mcp/**'
- 'packages/question-types/**'
- 'packages/utils/**'
- 'pnpm-lock.yaml'
- '.github/workflows/mcp-package-build-check.yml'
branches:
- main
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20.19.3
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build publishable MCP package
run: pnpm mcp:build
@@ -24,6 +24,9 @@ on:
- '.nvmrc' - '.nvmrc'
- '.github/workflows/package-build-check.yml' - '.github/workflows/package-build-check.yml'
permissions:
contents: read
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
+11 -5
View File
@@ -1,15 +1,19 @@
name: Publish @classroomio/course-app to NPM name: Publish @classroomio/course-app to NPM
on: workflow_dispatch # Publish-only via manual dispatch. Do not add pull_request triggers here.
on:
workflow_dispatch:
jobs: jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: production
permissions: permissions:
packages: write
contents: read contents: read
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20.19.3 node-version: 20.19.3
@@ -17,11 +21,13 @@ jobs:
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Install, Build & Publish - name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build & Publish
working-directory: packages/course-app working-directory: packages/course-app
run: | run: |
pnpm i
pnpm build pnpm build
pnpm publish --no-git-checks pnpm publish --no-git-checks
env: env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+6 -13
View File
@@ -1,22 +1,16 @@
name: Publish @classroomio/mcp to NPM name: Publish @classroomio/mcp to NPM
# Publish-only. Never triggered by pull_request — keeps NPM_TOKEN off the PR trust boundary.
# PR/push build verification lives in mcp-package-build-check.yml.
on: on:
workflow_dispatch: workflow_dispatch:
pull_request:
paths:
- "packages/mcp/**"
push:
paths:
- "packages/mcp/**"
branches:
- main
jobs: jobs:
publish: publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
environment: production
permissions: permissions:
packages: write
contents: read contents: read
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -24,18 +18,17 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: 20.19.3 node-version: 20.19.3
registry-url: "https://registry.npmjs.org" registry-url: 'https://registry.npmjs.org'
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
- name: Install dependencies - name: Install dependencies
run: pnpm install --no-frozen-lockfile run: pnpm install --frozen-lockfile
- name: Build publishable MCP package - name: Build publishable MCP package
run: pnpm mcp:build run: pnpm mcp:build
- name: Publish package - name: Publish package
if: github.event_name == 'workflow_dispatch'
run: pnpm --filter @classroomio/mcp publish --no-git-checks --access public run: pnpm --filter @classroomio/mcp publish --no-git-checks --access public
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,5 +1,9 @@
name: 'Check PR' name: 'Check PR'
# pull_request_target is used so title lint can comment on fork PRs.
# SAFE ONLY because this workflow never checks out or executes PR code.
# Do not add actions/checkout, pnpm install, build, or cache steps here.
on: on:
pull_request_target: pull_request_target:
types: types:
@@ -9,6 +13,7 @@ on:
- synchronize - synchronize
permissions: permissions:
contents: read
pull-requests: write pull-requests: write
jobs: jobs:
+3
View File
@@ -12,6 +12,9 @@ on:
- 'packages/ui/**' - 'packages/ui/**'
- '.github/workflows/ui-prefix-check.yml' - '.github/workflows/ui-prefix-check.yml'
permissions:
contents: read
jobs: jobs:
ui-prefix: ui-prefix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
+4
View File
@@ -22,6 +22,10 @@ Ready to dive into the code and make a real impact? Here's your path:
Would you prefer a chat before you dive into a lot of work? Our [Discord server](https://dub.sh/ciodiscord) is your harbor. Share your thoughts, and we'll meet you there with open arms. We're responsive and friendly, promise! Would you prefer a chat before you dive into a lot of work? Our [Discord server](https://dub.sh/ciodiscord) is your harbor. Share your thoughts, and we'll meet you there with open arms. We're responsive and friendly, promise!
## Dependency and workflow changes
PRs that touch `pnpm-lock.yaml`, `.github/workflows/**`, or npm publish config get extra review. Prefer the smallest lockfile diff that matches your change, and do not add `pull_request_target` workflows that check out or build untrusted PR code.
## Features ## Features
If you spot a feature that isn't part of our official plan but could propel ClassroomIO forward, don't hesitate. Raise it as an enhancement issue, and let us know you're ready to take the lead. We'll be quick to respond. If you spot a feature that isn't part of our official plan but could propel ClassroomIO forward, don't hesitate. Raise it as an enhancement issue, and let us know you're ready to take the lead. We'll be quick to respond.
+3
View File
@@ -6,6 +6,9 @@ packages:
onlyBuiltDependencies: onlyBuiltDependencies:
- esbuild - esbuild
- '@tailwindcss/oxide' - '@tailwindcss/oxide'
# Block brand-new registry publishes for 24h (supply-chain cooldown).
# Locked versions in pnpm-lock.yaml stay installable; this gates adds/updates.
minimumReleaseAge: 1440
minimumReleaseAgeExclude: minimumReleaseAgeExclude:
- '@getworkbench/hono' - '@getworkbench/hono'
- '@getworkbench/core' - '@getworkbench/core'