Skip to content

chore(deps): bump the actions group with 3 updates #50

chore(deps): bump the actions group with 3 updates

chore(deps): bump the actions group with 3 updates #50

Workflow file for this run

# This workflow is managed by gh actions-lock.
# SPDX-License-Identifier: MPL-2.0
# 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:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
lint-workflows:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v7.0.1
- 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
# actions-lock may prepend its own comment. Require the licence
# in the leading comment block, before the workflow body.
if ! awk '/^# SPDX-License-Identifier:/ { found=1 } /^[^#[:space:]]/ { exit } END { exit !found }' "$file"; then
echo "ERROR: $file missing SPDX header"
failed=1
fi
done
if [ $failed -eq 1 ]; then
echo "Add '# SPDX-License-Identifier: MPL-2.0' to the leading comment block"
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 a top-level 'permissions:' block (e.g. contents: read)"
exit 1
fi
echo "All workflows have permissions declared"
# Bun is the estate's first-choice runtime (LANGUAGE-POLICY.adoc §1:
# Bun > Deno > pnpm > npm) and executes .ts directly (§1.2). Tag form
# matches every other ref in this repo and is resolved by actions.lock.
- name: Set up Bun
uses: oven-sh/setup-bun@v2.2.0
with:
bun-version: latest
- 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>
# Delegated to scripts/check-action-pinning.js. The rule it enforces is
# unchanged in spirit — every action ref must resolve to an immutable
# commit — but "pinned" now includes refs the workflow lockfile
# resolves, which is how this repo pins them. Kept as a script rather
# than inline because the inline form needs a heredoc inside a YAML
# block scalar, and that is a well-known way to ship a gate that
# silently does nothing.
if ! bun scripts/check-action-pinning.js; then
unpinned="see above"
else
unpinned=""
fi
if [ -n "$unpinned" ]; then
echo "ERROR: Found unpinned actions:"
echo ""
echo "Replace version tags with SHA pins, e.g.:"
echo " uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # 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_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"