From 6028c0d978e4ac2a01b808720c93b7bf88cc4845 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 11 Mar 2026 02:21:34 +0000 Subject: [PATCH] Remove 11 unnecessary CI workflows Removed template boilerplate workflows not relevant to boj-server: ts-blocker, npm-bun-blocker, guix-nix-policy, jekyll-gh-pages, jekyll, rsr-antipattern, scorecard-enforcer, wellknown-enforcement, workflow-linter, security-policy, instant-sync. Kept: zig-test, release, mirror, hypatia-scan, codeql, scorecard, quality, secret-scanner. Co-Authored-By: Claude Opus 4.6 --- .github/workflows/guix-nix-policy.yml | 35 ----- .github/workflows/instant-sync.yml | 33 ----- .github/workflows/jekyll-gh-pages.yml | 52 ------- .github/workflows/jekyll.yml | 66 --------- .github/workflows/npm-bun-blocker.yml | 20 --- .github/workflows/rsr-antipattern.yml | 92 ------------ .github/workflows/scorecard-enforcer.yml | 72 --------- .github/workflows/security-policy.yml | 43 ------ .github/workflows/ts-blocker.yml | 25 ---- .github/workflows/wellknown-enforcement.yml | 96 ------------ .github/workflows/workflow-linter.yml | 155 -------------------- 11 files changed, 689 deletions(-) delete mode 100644 .github/workflows/guix-nix-policy.yml delete mode 100644 .github/workflows/instant-sync.yml delete mode 100644 .github/workflows/jekyll-gh-pages.yml delete mode 100644 .github/workflows/jekyll.yml delete mode 100644 .github/workflows/npm-bun-blocker.yml delete mode 100644 .github/workflows/rsr-antipattern.yml delete mode 100644 .github/workflows/scorecard-enforcer.yml delete mode 100644 .github/workflows/security-policy.yml delete mode 100644 .github/workflows/ts-blocker.yml delete mode 100644 .github/workflows/wellknown-enforcement.yml delete mode 100644 .github/workflows/workflow-linter.yml diff --git a/.github/workflows/guix-nix-policy.yml b/.github/workflows/guix-nix-policy.yml deleted file mode 100644 index d93060b..0000000 --- a/.github/workflows/guix-nix-policy.yml +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -name: Guix/Nix Package Policy -on: [push, pull_request] - -permissions: read-all - -jobs: - check: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - name: Enforce Guix primary / Nix fallback - run: | - # Check for package manager files - HAS_GUIX=$(find . -name "*.scm" -o -name ".guix-channel" -o -name "guix.scm" 2>/dev/null | head -1) - HAS_NIX=$(find . -name "*.nix" 2>/dev/null | head -1) - - # Block new package-lock.json, yarn.lock, Gemfile.lock, etc. - NEW_LOCKS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E 'package-lock\.json|yarn\.lock|Gemfile\.lock|Pipfile\.lock|poetry\.lock|cargo\.lock' || true) - if [ -n "$NEW_LOCKS" ]; then - echo "⚠️ Lock files detected. Prefer Guix manifests for reproducibility." - fi - - # Prefer Guix, fallback to Nix - if [ -n "$HAS_GUIX" ]; then - echo "✅ Guix package management detected (primary)" - elif [ -n "$HAS_NIX" ]; then - echo "✅ Nix package management detected (fallback)" - else - echo "ℹ️ Consider adding guix.scm or flake.nix for reproducible builds" - fi - - echo "✅ Package policy check passed" diff --git a/.github/workflows/instant-sync.yml b/.github/workflows/instant-sync.yml deleted file mode 100644 index e900c7e..0000000 --- a/.github/workflows/instant-sync.yml +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -# Instant Forge Sync - Triggers propagation to all forges on push/release -name: Instant Sync - -on: - push: - branches: [main, master] - release: - types: [published] - -permissions: - contents: read - -jobs: - dispatch: - runs-on: ubuntu-latest - steps: - - name: Trigger Propagation - uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v3 - with: - token: ${{ secrets.FARM_DISPATCH_TOKEN }} - repository: hyperpolymath/.git-private-farm - event-type: propagate - client-payload: |- - { - "repo": "${{ github.event.repository.name }}", - "ref": "${{ github.ref }}", - "sha": "${{ github.sha }}", - "forges": "" - } - - - name: Confirm - run: echo "::notice::Propagation triggered for ${{ github.event.repository.name }}" diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml deleted file mode 100644 index 8c74ca4..0000000 --- a/.github/workflows/jekyll-gh-pages.yml +++ /dev/null @@ -1,52 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -# Sample workflow for building and deploying a Jekyll site to GitHub Pages -name: Deploy Jekyll with GitHub Pages dependencies preinstalled - -on: - # Runs on pushes targeting the default branch - push: - branches: ["main"] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - name: Setup Pages - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 - - name: Build with Jekyll - uses: actions/jekyll-build-pages@44a6e6beabd48582f863aeeb6cb2151cc1716697 # v1 - with: - source: ./ - destination: ./_site - - name: Upload artifact - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml deleted file mode 100644 index e50077d..0000000 --- a/.github/workflows/jekyll.yml +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. - -# Sample workflow for building and deploying a Jekyll site to GitHub Pages -name: Deploy Jekyll site to Pages - -on: - # Runs on pushes targeting the default branch - push: - branches: ["main"] - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - name: Setup Ruby - # https://github.com/ruby/setup-ruby/releases/tag/v1.207.0 - uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd - with: - ruby-version: '3.1' # Not needed with a .ruby-version file - bundler-cache: true # runs 'bundle install' and caches installed gems automatically - cache-version: 0 # Increment this number if you need to re-download cached gems - - name: Setup Pages - id: pages - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 - - name: Build with Jekyll - # Outputs to the './_site' directory by default - run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}" - env: - JEKYLL_ENV: production - - name: Upload artifact - # Automatically uploads an artifact from the './_site' directory by default - uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4 - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 diff --git a/.github/workflows/npm-bun-blocker.yml b/.github/workflows/npm-bun-blocker.yml deleted file mode 100644 index 104c140..0000000 --- a/.github/workflows/npm-bun-blocker.yml +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -name: NPM/Bun Blocker -on: [push, pull_request] - -permissions: read-all - -jobs: - check: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - name: Block npm/bun - run: | - if [ -f "package-lock.json" ] || [ -f "bun.lockb" ] || [ -f ".npmrc" ]; then - echo "❌ npm/bun artifacts detected. Use Deno instead." - exit 1 - fi - echo "✅ No npm/bun violations" diff --git a/.github/workflows/rsr-antipattern.yml b/.github/workflows/rsr-antipattern.yml deleted file mode 100644 index 2a2e70d..0000000 --- a/.github/workflows/rsr-antipattern.yml +++ /dev/null @@ -1,92 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -# RSR Anti-Pattern CI Check -# SPDX-License-Identifier: PMPL-1.0-or-later -# -# Enforces: No TypeScript, No Go, No Python (except SaltStack), No npm -# Allows: ReScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme - -name: RSR Anti-Pattern Check - -on: - push: - branches: [main, master, develop] - pull_request: - branches: [main, master, develop] - - -permissions: read-all - -jobs: - antipattern-check: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - - name: Check for TypeScript - run: | - # Exclude bindings/deno/ - those are Deno FFI files using Deno.dlopen, not plain TypeScript - # Exclude .d.ts files - those are TypeScript type declarations for ReScript FFI - TS_FILES=$(find . \( -name "*.ts" -o -name "*.tsx" \) | grep -v node_modules | grep -v 'bindings/deno' | grep -v '\.d\.ts$' || true) - if [ -n "$TS_FILES" ]; then - echo "❌ TypeScript files detected - use ReScript instead" - echo "$TS_FILES" - exit 1 - fi - echo "✅ No TypeScript files (Deno FFI bindings excluded)" - - - name: Check for Go - run: | - if find . -name "*.go" | grep -q .; then - echo "❌ Go files detected - use Rust/WASM instead" - find . -name "*.go" - exit 1 - fi - echo "✅ No Go files" - - - name: Check for Python (non-SaltStack) - run: | - PY_FILES=$(find . -name "*.py" | grep -v salt | grep -v _states | grep -v _modules | grep -v pillar | grep -v venv | grep -v __pycache__ || true) - if [ -n "$PY_FILES" ]; then - echo "❌ Python files detected - only allowed for SaltStack" - echo "$PY_FILES" - exit 1 - fi - echo "✅ No non-SaltStack Python files" - - - name: Check for npm lockfiles - run: | - if [ -f "package-lock.json" ] || [ -f "yarn.lock" ]; then - echo "❌ npm/yarn lockfile detected - use Deno instead" - exit 1 - fi - echo "✅ No npm lockfiles" - - - name: Check for tsconfig - run: | - if [ -f "tsconfig.json" ]; then - echo "❌ tsconfig.json detected - use ReScript instead" - exit 1 - fi - echo "✅ No tsconfig.json" - - - name: Verify Deno presence (if package.json exists) - run: | - if [ -f "package.json" ]; then - if [ ! -f "deno.json" ] && [ ! -f "deno.jsonc" ]; then - echo "⚠️ Warning: package.json without deno.json - migration recommended" - fi - fi - echo "✅ Deno configuration check complete" - - - name: Summary - run: | - echo "╔════════════════════════════════════════════════════════════╗" - echo "║ RSR Anti-Pattern Check Passed ✅ ║" - echo "║ ║" - echo "║ Allowed: ReScript, Deno, WASM, Rust, OCaml, Haskell, ║" - echo "║ Guile/Scheme, SaltStack (Python) ║" - echo "║ ║" - echo "║ Blocked: TypeScript, Go, npm, Python (non-Salt) ║" - echo "╚════════════════════════════════════════════════════════════╝" diff --git a/.github/workflows/scorecard-enforcer.yml b/.github/workflows/scorecard-enforcer.yml deleted file mode 100644 index f4e549d..0000000 --- a/.github/workflows/scorecard-enforcer.yml +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -# Prevention workflow - runs OpenSSF Scorecard and fails on low scores -name: OpenSSF Scorecard Enforcer - -on: - push: - branches: [main] - schedule: - - cron: '0 6 * * 1' # Weekly on Monday - workflow_dispatch: - -permissions: read-all - -jobs: - scorecard: - runs-on: ubuntu-latest - permissions: - security-events: write - id-token: write # For OIDC - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - with: - persist-credentials: false - - - name: Run Scorecard - uses: ossf/scorecard-action@dc50aa0d6266d87a76935ff2d34e030454be3285 # v2.4.3 - with: - results_file: results.sarif - results_format: sarif - publish_results: true - - - name: Upload SARIF - uses: github/codeql-action/upload-sarif@4dd1439054423ad07501db44cf2fd84746f8ca8e # v3 - with: - sarif_file: results.sarif - - - name: Check minimum score - run: | - # Parse score from results - SCORE=$(jq -r '.runs[0].tool.driver.properties.score // 0' results.sarif 2>/dev/null || echo "0") - - echo "OpenSSF Scorecard Score: $SCORE" - - # Minimum acceptable score (0-10 scale) - MIN_SCORE=5 - - if [ "$(echo "$SCORE < $MIN_SCORE" | bc -l)" = "1" ]; then - echo "::error::Scorecard score $SCORE is below minimum $MIN_SCORE" - exit 1 - fi - - # Check specific high-priority items - check-critical: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - - name: Check SECURITY.md exists - run: | - if [ ! -f "SECURITY.md" ]; then - echo "::error::SECURITY.md is required" - exit 1 - fi - - - name: Check for pinned dependencies - run: | - # Check workflows for unpinned actions - unpinned=$(grep -r "uses:.*@v[0-9]" .github/workflows/*.yml 2>/dev/null | grep -v "#" | head -5 || true) - if [ -n "$unpinned" ]; then - echo "::warning::Found unpinned actions:" - echo "$unpinned" - fi diff --git a/.github/workflows/security-policy.yml b/.github/workflows/security-policy.yml deleted file mode 100644 index da78541..0000000 --- a/.github/workflows/security-policy.yml +++ /dev/null @@ -1,43 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -name: Security Policy -on: [push, pull_request] - -permissions: read-all - -jobs: - check: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - name: Security checks - run: | - FAILED=false - - # Block MD5/SHA1 for security (allow for checksums/caching) - WEAK_CRYPTO=$(grep -rE 'md5\(|sha1\(' --include="*.py" --include="*.rb" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" . 2>/dev/null | grep -v 'checksum\|cache\|test\|spec' | head -5 || true) - if [ -n "$WEAK_CRYPTO" ]; then - echo "⚠️ Weak crypto (MD5/SHA1) detected. Use SHA256+ for security:" - echo "$WEAK_CRYPTO" - fi - - # Block HTTP URLs (except localhost) - HTTP_URLS=$(grep -rE 'http://[^l][^o][^c]' --include="*.py" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" --include="*.yaml" --include="*.yml" . 2>/dev/null | grep -v 'localhost\|127.0.0.1\|example\|test\|spec' | head -5 || true) - if [ -n "$HTTP_URLS" ]; then - echo "⚠️ HTTP URLs found. Use HTTPS:" - echo "$HTTP_URLS" - fi - - # Block hardcoded secrets patterns - SECRETS=$(grep -rEi '(api_key|apikey|secret_key|password)\s*[=:]\s*["\x27][A-Za-z0-9+/=]{20,}' --include="*.py" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" --include="*.env" . 2>/dev/null | grep -v 'example\|sample\|test\|mock\|placeholder' | head -3 || true) - if [ -n "$SECRETS" ]; then - echo "❌ Potential hardcoded secrets detected!" - FAILED=true - fi - - if [ "$FAILED" = true ]; then - exit 1 - fi - - echo "✅ Security policy check passed" diff --git a/.github/workflows/ts-blocker.yml b/.github/workflows/ts-blocker.yml deleted file mode 100644 index e172118..0000000 --- a/.github/workflows/ts-blocker.yml +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -name: TypeScript/JavaScript Blocker -on: [push, pull_request] - -permissions: read-all - -jobs: - check: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - name: Block new TypeScript/JavaScript - run: | - NEW_TS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(ts|tsx)$' | grep -v '\.gen\.' || true) - NEW_JS=$(git diff --name-only --diff-filter=A HEAD~1 2>/dev/null | grep -E '\.(js|jsx)$' | grep -v '\.res\.js$' | grep -v '\.gen\.' | grep -v 'node_modules' || true) - - if [ -n "$NEW_TS" ] || [ -n "$NEW_JS" ]; then - echo "❌ New TS/JS files detected. Use ReScript instead." - [ -n "$NEW_TS" ] && echo "$NEW_TS" - [ -n "$NEW_JS" ] && echo "$NEW_JS" - exit 1 - fi - echo "✅ ReScript policy enforced" diff --git a/.github/workflows/wellknown-enforcement.yml b/.github/workflows/wellknown-enforcement.yml deleted file mode 100644 index df361dd..0000000 --- a/.github/workflows/wellknown-enforcement.yml +++ /dev/null @@ -1,96 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -name: Well-Known Standards (RFC 9116 + RSR) -on: - push: - branches: [main, master] - paths: - - '.well-known/**' - - 'security.txt' - pull_request: - paths: - - '.well-known/**' - schedule: - # Weekly expiry check - - cron: '0 9 * * *' - workflow_dispatch: - - -permissions: read-all - -jobs: - validate: - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - - name: RFC 9116 security.txt validation - run: | - SECTXT="" - [ -f ".well-known/security.txt" ] && SECTXT=".well-known/security.txt" - [ -f "security.txt" ] && SECTXT="security.txt" - - if [ -z "$SECTXT" ]; then - echo "::warning::No security.txt found. See https://github.com/hyperpolymath/well-known-ecosystem" - exit 0 - fi - - # Required: Contact - grep -q "^Contact:" "$SECTXT" || { echo "::error::Missing Contact field"; exit 1; } - - # Required: Expires - if ! grep -q "^Expires:" "$SECTXT"; then - echo "::error::Missing Expires field" - exit 1 - fi - - # Check expiry - EXPIRES=$(grep "^Expires:" "$SECTXT" | cut -d: -f2- | tr -d ' ' | head -1) - if date -d "$EXPIRES" > /dev/null 2>&1; then - DAYS=$(( ($(date -d "$EXPIRES" +%s) - $(date +%s)) / 86400 )) - if [ $DAYS -lt 0 ]; then - echo "::error::security.txt EXPIRED" - exit 1 - elif [ $DAYS -lt 30 ]; then - echo "::warning::security.txt expires in $DAYS days" - else - echo "✅ security.txt valid ($DAYS days)" - fi - fi - - - name: RSR well-known compliance - run: | - MISSING="" - [ ! -f ".well-known/security.txt" ] && [ ! -f "security.txt" ] && MISSING="$MISSING security.txt" - [ ! -f ".well-known/ai.txt" ] && MISSING="$MISSING ai.txt" - [ ! -f ".well-known/humans.txt" ] && MISSING="$MISSING humans.txt" - - if [ -n "$MISSING" ]; then - echo "::warning::Missing RSR recommended files:$MISSING" - echo "Reference: https://github.com/hyperpolymath/well-known-ecosystem/.well-known/" - else - echo "✅ RSR well-known compliant" - fi - - - name: Mixed content check - run: | - MIXED=$(grep -rE 'src="http://|href="http://' --include="*.html" --include="*.htm" . 2>/dev/null | grep -vE 'localhost|127\.0\.0\.1|example\.com' | head -5 || true) - if [ -n "$MIXED" ]; then - echo "::error::Mixed content (HTTP in HTML)" - echo "$MIXED" - exit 1 - fi - echo "✅ No mixed content" - - - name: DNS security records check - if: hashFiles('CNAME') != '' - run: | - DOMAIN=$(cat CNAME 2>/dev/null | tr -d '\n') - if [ -n "$DOMAIN" ]; then - echo "Checking DNS for $DOMAIN..." - # CAA record - dig +short CAA "$DOMAIN" | grep -q "issue" && echo "✅ CAA record" || echo "::warning::No CAA record" - # DNSSEC - dig +dnssec +short "$DOMAIN" | grep -q "RRSIG" && echo "✅ DNSSEC" || echo "::warning::No DNSSEC" - fi diff --git a/.github/workflows/workflow-linter.yml b/.github/workflows/workflow-linter.yml deleted file mode 100644 index 19bde38..0000000 --- a/.github/workflows/workflow-linter.yml +++ /dev/null @@ -1,155 +0,0 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -# workflow-linter.yml - Validates GitHub workflows against RSR security standards -# This workflow can be copied to other repos for consistent enforcement -name: Workflow Security Linter - -on: - push: - paths: - - '.github/workflows/**' - pull_request: - paths: - - '.github/workflows/**' - workflow_dispatch: - -permissions: read-all - -jobs: - lint-workflows: - runs-on: ubuntu-latest - permissions: - contents: read - - steps: - - name: Checkout - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.2 - - - name: Check SPDX Headers - run: | - echo "=== Checking SPDX License Headers ===" - failed=0 - for file in .github/workflows/*.yml .github/workflows/*.yaml; do - [ -f "$file" ] || continue - if ! head -1 "$file" | grep -q "^# SPDX-License-Identifier:"; then - echo "ERROR: $file missing SPDX header" - failed=1 - fi - done - if [ $failed -eq 1 ]; then - echo "Add '# SPDX-License-Identifier: PMPL-1.0' as first line" - exit 1 - fi - echo "All workflows have SPDX headers" - - - name: Check Permissions Declaration - run: | - echo "=== Checking Permissions ===" - failed=0 - for file in .github/workflows/*.yml .github/workflows/*.yaml; do - [ -f "$file" ] || continue - if ! grep -q "^permissions:" "$file"; then - echo "ERROR: $file missing top-level 'permissions:' declaration" - failed=1 - fi - done - if [ $failed -eq 1 ]; then - echo "Add 'permissions: read-all' at workflow level" - exit 1 - fi - echo "All workflows have permissions declared" - - - name: Check SHA-Pinned Actions - run: | - echo "=== Checking Action Pinning ===" - # Find any uses: lines that don't have @SHA format - # Pattern: uses: owner/repo@<40-char-hex> - unpinned=$(grep -rn "uses:" .github/workflows/ | \ - grep -v "@[a-f0-9]\{40\}" | \ - grep -v "uses: \./\|uses: docker://\|uses: actions/github-script" || true) - - if [ -n "$unpinned" ]; then - echo "ERROR: Found unpinned actions:" - echo "$unpinned" - echo "" - echo "Replace version tags with SHA pins, e.g.:" - echo " uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1" - exit 1 - fi - echo "All actions are SHA-pinned" - - - name: Check for Duplicate Workflows - run: | - echo "=== Checking for Duplicates ===" - # Known duplicate patterns - if [ -f .github/workflows/codeql.yml ] && [ -f .github/workflows/codeql-analysis.yml ]; then - echo "ERROR: Duplicate CodeQL workflows found" - echo "Delete codeql-analysis.yml (keep codeql.yml)" - exit 1 - fi - if [ -f .github/workflows/rust.yml ] && [ -f .github/workflows/rust-ci.yml ]; then - echo "WARNING: Potential duplicate Rust workflows" - echo "Consider consolidating rust.yml and rust-ci.yml" - fi - echo "No critical duplicates found" - - - name: Check CodeQL Language Matrix - run: | - echo "=== Checking CodeQL Configuration ===" - if [ ! -f .github/workflows/codeql.yml ]; then - echo "No CodeQL workflow found (optional)" - exit 0 - fi - - # Detect repo languages - has_js=$(find . -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" -path "*/src/*" -o -path "*/lib/*" 2>/dev/null | head -1) - has_py=$(find . -name "*.py" -path "*/src/*" -o -path "*/lib/*" 2>/dev/null | head -1) - has_go=$(find . -name "*.go" -path "*/src/*" -o -path "*/cmd/*" -o -path "*/pkg/*" 2>/dev/null | head -1) - has_rs=$(find . -name "*.rs" -path "*/src/*" 2>/dev/null | head -1) - has_java=$(find . -name "*.java" -path "*/src/*" 2>/dev/null | head -1) - has_rb=$(find . -name "*.rb" -path "*/lib/*" -o -path "*/app/*" 2>/dev/null | head -1) - - echo "Detected languages:" - [ -n "$has_js" ] && echo " - javascript-typescript" - [ -n "$has_py" ] && echo " - python" - [ -n "$has_go" ] && echo " - go" - [ -n "$has_rs" ] && echo " - rust (note: CodeQL rust is limited)" - [ -n "$has_java" ] && echo " - java-kotlin" - [ -n "$has_rb" ] && echo " - ruby" - - # Check for over-reach - if grep -q "language:.*'go'" .github/workflows/codeql.yml && [ -z "$has_go" ]; then - echo "WARNING: CodeQL configured for Go but no Go files found" - fi - if grep -q "language:.*'python'" .github/workflows/codeql.yml && [ -z "$has_py" ]; then - echo "WARNING: CodeQL configured for Python but no Python files found" - fi - if grep -q "language:.*'java'" .github/workflows/codeql.yml && [ -z "$has_java" ]; then - echo "WARNING: CodeQL configured for Java but no Java files found" - fi - if grep -q "language:.*'ruby'" .github/workflows/codeql.yml && [ -z "$has_rb" ]; then - echo "WARNING: CodeQL configured for Ruby but no Ruby files found" - fi - - echo "CodeQL check complete" - - - name: Check Secrets Guards - run: | - echo "=== Checking Secrets Usage ===" - # Look for secrets without conditional guards in mirror workflows - if [ -f .github/workflows/mirror.yml ]; then - if grep -q "secrets\." .github/workflows/mirror.yml; then - if ! grep -q "if:.*vars\." .github/workflows/mirror.yml; then - echo "WARNING: mirror.yml uses secrets without vars guard" - echo "Add 'if: vars.FEATURE_ENABLED == true' to jobs" - fi - fi - fi - echo "Secrets check complete" - - - name: Summary - run: | - echo "" - echo "=== Workflow Linter Summary ===" - echo "All critical checks passed." - echo "" - echo "For more info, see: robot-repo-bot/ERROR-CATALOG.scm"