Merge branch 'dev' into dependabot/npm_and_yarn/dev/tailwind-postcss-… #164
Workflow file for this run
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
| # security.yml — Colabs | |
| # | |
| # Three independent security scanning jobs, each targeting a different surface: | |
| # | |
| # secret-scan — credentials accidentally committed (Gitleaks) | |
| # audit — known CVEs in npm dependencies (npm audit) | |
| # codeql — static analysis: XSS, open redirect, prototype pollution | |
| # | |
| # Triggers: | |
| # PR into dev or main → all three jobs run, block merge on failure | |
| # Weekly (Monday 08:00) → full scan of main, catches newly disclosed CVEs | |
| # Manual dispatch → run on demand from the Actions tab | |
| # | |
| # Required status checks to add in branch protection (Settings → Branches): | |
| # ✓ Security / secret-scan | |
| # ✓ Security / codeql | |
| # (audit is required too but consider leaving it advisory initially — see note below) | |
| # | |
| # Note on audit as a required check: | |
| # npm audit fails on high/critical CVEs. Transitive dependency vulnerabilities | |
| # you cannot immediately update will permanently block all PRs until resolved. | |
| # Strategy: add it as required, then use .nsprc or audit-exceptions for any | |
| # known unfixable transitive CVEs — document the reason as a comment. | |
| name: Security | |
| on: | |
| push: | |
| branches: | |
| - '**' | |
| pull_request: | |
| branches: | |
| - dev | |
| - main | |
| schedule: | |
| - cron: '0 8 * * 1' | |
| workflow_dispatch: | |
| # Separate concurrency groups for PRs vs scheduled/manual runs. | |
| # PR runs cancel each other (only latest push matters). | |
| # Scheduled and manual runs must NEVER be cancelled mid-flight — | |
| # a cancelled security scan gives a false "green" signal. | |
| concurrency: | |
| group: security-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # JOB 1 — Secret scanning (Gitleaks) | |
| # | |
| # Why this matters for Colabs specifically: | |
| # - Open source contributors copy-paste from local .env files | |
| # - Supabase anon keys, GitHub OAuth client secrets, and JWT secrets all | |
| # have recognisable patterns that Gitleaks catches out of the box | |
| # - A leaked Supabase anon key with permissive RLS is a direct data breach | |
| # | |
| # Scans the FULL git history of the PR diff — a secret added in commit 1 and | |
| # "removed" in commit 3 is still caught. fetch-depth: 0 is required for this. | |
| # Required for repositories owned by organizations (SpaceyaTech). | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| secret-scan: | |
| name: Security / secret-scan | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| security-events: write # required to upload SARIF to the Security tab | |
| steps: | |
| - name: Checkout (full history for complete diff scan) | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Verify Gitleaks License Presence | |
| # Diagnoses if the GITLEAKS_LICENSE secret is accessible to the workflow. | |
| # Secrets are not available in PRs from forks, and Gitleaks is free for public repos. | |
| # Therefore, we issue a warning rather than failing the build. | |
| run: | | |
| if [ -z "$GITLEAKS_LICENSE" ]; then | |
| echo "::warning::GITLEAKS_LICENSE is empty! Check Org settings if this is a private repository. This is expected for PRs from forks." | |
| else | |
| echo "GITLEAKS_LICENSE is present and populated." | |
| fi | |
| env: | |
| GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} | |
| - name: Run Gitleaks | |
| uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2.3.9 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} | |
| GITLEAKS_ENABLE_SARIF: true | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # JOB 2 — Dependency vulnerability audit (npm audit) | |
| # | |
| # Why this matters for Colabs specifically: | |
| # - Supabase client, React Hook Form, Zod, Framer Motion — any of these | |
| # can receive a CVE disclosure after you've already installed them | |
| # - Colabs will add Stripe — a CVE in the payment library path is critical | |
| # - --audit-level=high: ignore low/moderate (too noisy in open source), | |
| # fail on high/critical (direct risk to user data or payment flow) | |
| # | |
| # The weekly schedule is what makes this valuable — it catches CVEs that | |
| # are disclosed against packages you haven't touched in months. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| audit: | |
| name: Security / audit | |
| if: github.event_name != 'push' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 20 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Audit for high and critical CVEs | |
| # Focus on production dependencies to ensure application security | |
| # while avoiding blocks from unfixable build-tool vulnerabilities. | |
| run: npm audit --audit-level=high --omit=dev | |
| # 3. Add a comment above it explaining the CVE, why it is acceptable | |
| # temporarily, and a target date to resolve it. | |
| # Never add exceptions silently. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # JOB 3 — Static Application Security Testing (CodeQL) | |
| # | |
| # Why this matters for Colabs specifically: | |
| # - GitHub OAuth flow has redirect URIs — CodeQL catches open redirects | |
| # where user-supplied next params reach window.location without validation | |
| # - Supabase query builders with user input — CodeQL catches unvalidated | |
| # input reaching query construction in Edge Functions | |
| # - File upload (Storage) — CodeQL catches path traversal patterns | |
| # - dangerouslySetInnerHTML with user content — DOM-based XSS | |
| # | |
| # Uses security-extended query suite (broader than default): | |
| # + DOM XSS, prototype pollution, open redirect, uncontrolled format strings | |
| # | |
| # Results appear in: Security → Code scanning alerts on the repo. | |
| # Free for public repos, runs entirely within GitHub infrastructure. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| codeql: | |
| name: Security / codeql | |
| if: github.event_name != 'push' || github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| security-events: write | |
| actions: read | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Initialise CodeQL | |
| uses: github/codeql-action/init@v4 | |
| with: | |
| languages: javascript | |
| queries: security-extended | |
| - name: Install dependencies for import tracing | |
| run: npm ci | |
| - name: Perform CodeQL analysis | |
| uses: github/codeql-action/analyze@v4 | |
| with: | |
| category: '/language:javascript' | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # JOB 4 — Unintended .env commit check | |
| # | |
| # Ensures .env files aren't accidentally pushed into the repository. | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| check-env: | |
| name: Security / check-env | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Check for tracked .env files | |
| run: | | |
| ENV_FILES=$(git ls-files | awk '/(^|\/)\.env($|\.)/ && !/\.(example|template|sample)$/') | |
| if [ -n "$ENV_FILES" ]; then | |
| echo "::error::Found committed .env files. These files usually contain secrets and should not be tracked by git." | |
| echo "The following .env files are currently tracked:" | |
| echo "$ENV_FILES" | |
| echo "Please remove them using: git rm --cached <file>" | |
| echo "And ensure they are listed in .gitignore before committing." | |
| exit 1 | |
| fi | |
| TEMPLATE_FILES=$(git ls-files | awk '/(^|\/)\.env\.(example|template|sample)$/') | |
| if [ -n "$TEMPLATE_FILES" ]; then | |
| for file in $TEMPLATE_FILES; do | |
| # 1. Known high-entropy prefixes: eyJ (JWTs), sk_test_/sk_live_/whsec_ (Stripe), gh[pousr]_ (GitHub) | |
| SUSPICIOUS=$(grep -E '=(eyJ|sk_(test|live)_|whsec_|gh[pousr]_)' "$file" || true) | |
| # 2. Generic 32+ char alphanumerics, ignoring usual placeholder words | |
| GENERIC=$(grep -E '=[a-zA-Z0-9]{32,}' "$file" | grep -v -i -E '(your|example|dummy|mock|insert|here)' || true) | |
| if [ -n "$SUSPICIOUS" ] || [ -n "$GENERIC" ]; then | |
| echo "::error::File $file contains what looks like actual key patterns." | |
| [ -n "$SUSPICIOUS" ] && echo "$SUSPICIOUS" | |
| [ -n "$GENERIC" ] && echo "$GENERIC" | |
| echo "Please ensure templates only contain empty values or placeholders (e.g., 'your_key_here')." | |
| exit 1 | |
| fi | |
| done | |
| fi | |
| echo "No tracked .env files found, and templates are clean." |