veza/.github/workflows/container-scan.yml
senke 9cd0da0046 fix(v0.12.6): apply all pentest remediations — 36 findings across 36 files
CRITICAL fixes:
- Race condition (TOCTOU) in payout/refund with SELECT FOR UPDATE (CRITICAL-001/002)
- IDOR on analytics endpoint — ownership check enforced (CRITICAL-003)
- CSWSH on all WebSocket endpoints — origin whitelist (CRITICAL-004)
- Mass assignment on user self-update — strip privileged fields (CRITICAL-005)

HIGH fixes:
- Path traversal in marketplace upload — UUID filenames (HIGH-001)
- IP spoofing — use Gin trusted proxy c.ClientIP() (HIGH-002)
- Popularity metrics (followers, likes) set to json:"-" (HIGH-003)
- bcrypt cost hardened to 12 everywhere (HIGH-004)
- Refresh token lock made mandatory (HIGH-005)
- Stream token replay prevention with access_count (HIGH-006)
- Subscription trial race condition fixed (HIGH-007)
- License download expiration check (HIGH-008)
- Webhook amount validation (HIGH-009)
- pprof endpoint removed from production (HIGH-010)

MEDIUM fixes:
- WebSocket message size limit 64KB (MEDIUM-010)
- HSTS header in nginx production (MEDIUM-001)
- CORS origin restricted in nginx-rtmp (MEDIUM-002)
- Docker alpine pinned to 3.21 (MEDIUM-003/004)
- Redis authentication enforced (MEDIUM-005)
- GDPR account deletion expanded (MEDIUM-006)
- .gitignore hardened (MEDIUM-007)

LOW/INFO fixes:
- GitHub Actions SHA pinning on all workflows (LOW-001)
- .env.example security documentation (INFO-001)
- Production CORS set to HTTPS (LOW-002)

All tests pass. Go and Rust compile clean.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 00:44:46 +01:00

84 lines
2.7 KiB
YAML

name: Container Image Scan
on:
push:
branches: [main]
paths:
- 'veza-backend-api/Dockerfile*'
- 'apps/web/Dockerfile*'
- 'veza-stream-server/Dockerfile*'
pull_request:
branches: [main]
paths:
- 'veza-backend-api/Dockerfile*'
- 'apps/web/Dockerfile*'
- 'veza-stream-server/Dockerfile*'
workflow_dispatch:
jobs:
scan-backend:
name: Scan Backend Image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Build backend image
run: docker build -t veza-backend:scan -f veza-backend-api/Dockerfile.production veza-backend-api/
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0.28.0
with:
image-ref: 'veza-backend:scan'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true
scan-stream-server:
name: Scan Stream Server Image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Build stream server image
run: docker build -t veza-stream:scan -f veza-stream-server/Dockerfile .
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0.28.0
with:
image-ref: 'veza-stream:scan'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true
scan-frontend:
name: Scan Frontend Image
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Check if frontend Dockerfile exists
id: check
run: |
if [ -f "apps/web/Dockerfile" ] || [ -f "apps/web/Dockerfile.production" ]; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Build frontend image
if: steps.check.outputs.exists == 'true'
run: |
DOCKERFILE=$([ -f "apps/web/Dockerfile.production" ] && echo "apps/web/Dockerfile.production" || echo "apps/web/Dockerfile")
docker build -t veza-frontend:scan -f "$DOCKERFILE" apps/web/
- name: Run Trivy vulnerability scanner
if: steps.check.outputs.exists == 'true'
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0.28.0
with:
image-ref: 'veza-frontend:scan'
format: 'table'
exit-code: '1'
severity: 'CRITICAL,HIGH'
ignore-unfixed: true