Skip to content

Commit 15c2d14

Browse files
authored
Use environments to protect CI (#796)
1 parent 3a36643 commit 15c2d14

File tree

2 files changed

+57
-30
lines changed

2 files changed

+57
-30
lines changed

.github/workflows/ci.yml

Lines changed: 57 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,81 @@
11
name: CI
2-
# SECURITY NOTE: This workflow uses pull_request_target which has access to secrets.
3-
# This is needed because tests require access to external services with credentials.
4-
# `pull_request_target` will always run without manual approval, even if "Require approval for all external contributors" is enabled in the repo settings.
5-
# Therefore we implement a "safe to test" label that must be manually added once we have checked that the diff is safe.
6-
# For PRs from forks, secrets are only provided when the "safe to test" label is present.
7-
# This allows maintainers to safely test external contributions while preventing
8-
# malicious actors from accessing secrets.
2+
# SECURITY: Uses environment protection for external PRs instead of unsafe "safe to test" labels.
3+
# Environment protection provides secure manual approval tied to specific commits,
4+
# eliminating race conditions and ensuring maintainer review before secrets access.
95
on:
106
push:
117
branches: [main]
128
paths-ignore:
139
- "**.md"
1410
- ".changeset/**"
1511
pull_request_target:
16-
types: [opened, synchronize, reopened, labeled]
12+
types: [opened, synchronize, reopened]
1713
paths-ignore:
1814
- "**.md"
1915
- ".changeset/**"
2016
pull_request:
2117
types: [opened, synchronize, reopened]
22-
paths:
23-
- .github/workflows/ci.yml
18+
paths-ignore:
19+
- "**.md"
20+
- ".changeset/**"
2421

25-
concurrency: ${{ github.workflow }}--${{ github.ref }}
22+
concurrency:
23+
group: ${{ github.workflow }}--${{ github.event_name == 'pull_request_target' && format('pr#{0}', github.event.pull_request.number) || github.ref }}
24+
cancel-in-progress: true
2625

2726
permissions:
28-
pull-requests: write
27+
contents: read
28+
pull-requests: read
2929

3030
jobs:
31-
main:
32-
name: Node.js 20
31+
# Basic validation job - runs for all PRs without secrets
32+
basic-validation:
33+
name: Build and lint
3334
runs-on: ubuntu-latest
34-
# Only run tests with secrets if:
35-
# 1. This is a push to main, OR
36-
# 2. PR is from the same repository (trusted), OR
37-
# 3. PR has the "safe to test" label (maintainer approved)
35+
if: github.event_name == 'pull_request'
36+
37+
steps:
38+
- name: Checkout sources
39+
uses: actions/checkout@v4
40+
41+
- name: Install Node.js
42+
uses: actions/setup-node@v4
43+
with:
44+
node-version: 20.x
45+
cache: npm
46+
cache-dependency-path: package-lock.json
47+
48+
- name: Install dependencies
49+
run: npm ci --no-fund --no-audit
50+
51+
- name: Build
52+
run: npm run build
53+
54+
- name: Check formatting
55+
run: npm run format:check
56+
57+
- name: Run linters
58+
run: npm run lint
59+
60+
# Integration tests with secrets - requires approval for external PRs
61+
tests:
62+
name: Tests
63+
runs-on: ubuntu-latest
64+
# SECURITY: Use environment protection for external contributors
65+
environment: ${{ github.event.pull_request.head.repo.full_name != github.repository && 'external-testing' || '' }}
66+
# Run tests with secrets for:
67+
# 1. Push to main (trusted), OR
68+
# 2. PR from same repository (trusted)
69+
# For external PRs: environment protection requires manual approval
3870
if: |
39-
github.event_name == 'push' ||
40-
github.event.pull_request.head.repo.full_name == github.repository ||
41-
contains(github.event.pull_request.labels.*.name, 'safe to test')
71+
github.event_name == 'push' ||
72+
(github.event.pull_request.head.repo.full_name == github.repository)
4273
4374
steps:
4475
- name: Checkout sources
4576
uses: actions/checkout@v4
4677
with:
78+
# Environment protection provides security - we can safely checkout PR code
4779
ref: ${{ github.event.pull_request.head.sha || github.sha }}
4880

4981
- name: Decrypt keyfile
@@ -52,22 +84,18 @@ jobs:
5284
KEYFILE_PASSPHRASE: ${{secrets.KEYFILE_PASSPHRASE}}
5385

5486
- name: Install Node.js
55-
uses: actions/setup-node@v3
87+
uses: actions/setup-node@v4
5688
with:
57-
node-version: 20.19
89+
node-version: 20.x
90+
cache: npm
91+
cache-dependency-path: package-lock.json
5892

5993
- name: Install dependencies
6094
run: npm ci --no-fund --no-audit
6195

6296
- name: Build
6397
run: npm run build
6498

65-
- name: Check formatting
66-
run: npm run format:check
67-
68-
- name: Run linters
69-
run: npm run lint
70-
7199
- name: Run tests
72100
run: npm run test
73101
env:

bb.test

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)