Skip to content

fix(#21): upgrade frontend base image node:20-alpine → node:22-alpine… #13

fix(#21): upgrade frontend base image node:20-alpine → node:22-alpine…

fix(#21): upgrade frontend base image node:20-alpine → node:22-alpine… #13

Workflow file for this run

# Security Pipeline — Shield Agent
# Adapted from golden-paths/pipelines/security.yml for RemedyIQ:
# - Go backend lives in backend/ (govulncheck + Semgrep Go rulesets)
# - Next.js frontend lives in frontend/ (npm audit, ESLint security)
# - TruffleHog scans the full repo diff on every PR
# - CodeQL runs TypeScript + Go on push to main
#
# Requires:
# SEMGREP_APP_TOKEN secret (optional — removes rate-limiting on Semgrep cloud)
name: Security Scan
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
security-events: write
pull-requests: write
env:
FAIL_ON_SEVERITY: high
jobs:
semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/security-audit
p/owasp-top-ten
p/typescript
p/react
p/golang
p/nodejs
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
govulncheck:
name: Go Vulnerability Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: backend/go.mod
cache-dependency-path: backend/go.sum
- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest
- name: Run govulncheck
working-directory: backend
run: govulncheck ./...
npm-audit:
name: npm Audit (frontend)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
working-directory: frontend
run: npm ci --legacy-peer-deps
- name: Run npm audit
working-directory: frontend
run: |
npm audit --audit-level=${{ env.FAIL_ON_SEVERITY }} --json > /tmp/npm-audit.json || AUDIT_FAILED=1
CRITICAL=$(jq '.metadata.vulnerabilities.critical // 0' /tmp/npm-audit.json)
HIGH=$(jq '.metadata.vulnerabilities.high // 0' /tmp/npm-audit.json)
MODERATE=$(jq '.metadata.vulnerabilities.moderate // 0' /tmp/npm-audit.json)
LOW=$(jq '.metadata.vulnerabilities.low // 0' /tmp/npm-audit.json)
echo "## Dependency Vulnerabilities (frontend)" >> $GITHUB_STEP_SUMMARY
echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Critical | $CRITICAL |" >> $GITHUB_STEP_SUMMARY
echo "| High | $HIGH |" >> $GITHUB_STEP_SUMMARY
echo "| Moderate | $MODERATE |" >> $GITHUB_STEP_SUMMARY
echo "| Low | $LOW |" >> $GITHUB_STEP_SUMMARY
if [ "${AUDIT_FAILED:-0}" = "1" ]; then
# Informational until tracked CVEs are resolved in dedicated PRs.
# @clerk/nextjs critical vulns → tracked in a separate upgrade PR.
echo "::warning::Found $CRITICAL critical and $HIGH high vulnerabilities in frontend/ (non-blocking — tracked separately)"
fi
secrets:
name: Secrets Detection
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog scan
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --only-verified
codeql:
name: CodeQL Analysis
runs-on: ubuntu-latest
if: github.event_name == 'push'
strategy:
matrix:
language: [typescript, go]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
if: matrix.language == 'go'
with:
go-version-file: backend/go.mod
cache-dependency-path: backend/go.sum
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.language == 'go' && 'manual' || 'none' }}
- name: Build Go (for CodeQL)
if: matrix.language == 'go'
working-directory: backend
run: go build ./...
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
eslint-security:
name: ESLint Security Rules
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
working-directory: frontend
run: npm ci --legacy-peer-deps
- name: Install ESLint security plugins
working-directory: frontend
run: npm install --save-dev eslint-plugin-security --legacy-peer-deps
- name: Run ESLint security rules
working-directory: frontend
run: |
npx eslint src/ --ext .ts,.tsx,.js,.jsx \
--plugin security \
--rule 'security/detect-unsafe-regex: error' \
--rule 'security/detect-buffer-noassert: error' \
--rule 'security/detect-eval-with-expression: error' \
--rule 'security/detect-object-injection: warn' \
--rule 'security/detect-possible-timing-attacks: warn' \
--format compact || true # informational — does not block CI; findings visible in step output