Use environments to protect CI (#796) #1511
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: CI | |
# SECURITY: Uses environment protection for external PRs instead of unsafe "safe to test" labels. | |
# Environment protection provides secure manual approval tied to specific commits, | |
# eliminating race conditions and ensuring maintainer review before secrets access. | |
on: | |
push: | |
branches: [main] | |
paths-ignore: | |
- "**.md" | |
- ".changeset/**" | |
pull_request_target: | |
types: [opened, synchronize, reopened] | |
paths-ignore: | |
- "**.md" | |
- ".changeset/**" | |
pull_request: | |
types: [opened, synchronize, reopened] | |
paths-ignore: | |
- "**.md" | |
- ".changeset/**" | |
concurrency: | |
group: ${{ github.workflow }}--${{ github.event_name == 'pull_request_target' && format('pr#{0}', github.event.pull_request.number) || github.ref }} | |
cancel-in-progress: true | |
permissions: | |
contents: read | |
pull-requests: read | |
jobs: | |
# Basic validation job - runs for all PRs without secrets | |
basic-validation: | |
name: Build and lint | |
runs-on: ubuntu-latest | |
if: github.event_name == 'pull_request' | |
steps: | |
- name: Checkout sources | |
uses: actions/checkout@v4 | |
- name: Install Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: 20.x | |
cache: npm | |
cache-dependency-path: package-lock.json | |
- name: Install dependencies | |
run: npm ci --no-fund --no-audit | |
- name: Build | |
run: npm run build | |
- name: Check formatting | |
run: npm run format:check | |
- name: Run linters | |
run: npm run lint | |
# Integration tests with secrets - requires approval for external PRs | |
tests: | |
name: Tests | |
runs-on: ubuntu-latest | |
# SECURITY: Use environment protection for external contributors | |
environment: ${{ github.event.pull_request.head.repo.full_name != github.repository && 'external-testing' || '' }} | |
# Run tests with secrets for: | |
# 1. Push to main (trusted), OR | |
# 2. PR from same repository (trusted) | |
# For external PRs: environment protection requires manual approval | |
if: | | |
github.event_name == 'push' || | |
(github.event.pull_request.head.repo.full_name == github.repository) | |
steps: | |
- name: Checkout sources | |
uses: actions/checkout@v4 | |
with: | |
# Environment protection provides security - we can safely checkout PR code | |
ref: ${{ github.event.pull_request.head.sha || github.sha }} | |
- name: Decrypt keyfile | |
run: ./.github/scripts/decrypt_secret.sh | |
env: | |
KEYFILE_PASSPHRASE: ${{secrets.KEYFILE_PASSPHRASE}} | |
- name: Install Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: 20.x | |
cache: npm | |
cache-dependency-path: package-lock.json | |
- name: Install dependencies | |
run: npm ci --no-fund --no-audit | |
- name: Build | |
run: npm run build | |
- name: Run tests | |
run: npm run test | |
env: | |
AWS_BUCKET: ${{secrets.AWS_BUCKET}} | |
AWS_ACCESS_KEY_ID: ${{secrets.AWS_ACCESS_KEY_ID}} | |
AWS_SECRET_ACCESS_KEY: ${{secrets.AWS_SECRET_ACCESS_KEY}} | |
AZURE_ACCOUNT_ID: ${{secrets.AZURE_ACCOUNT_ID}} | |
AZURE_ACCOUNT_KEY: ${{secrets.AZURE_ACCOUNT_KEY}} | |
AZURE_CONTAINER_NAME: ${{secrets.AZURE_CONTAINER_NAME}} | |
AWS_REGION: ${{secrets.AWS_REGION}} |