name: Security # 独立安全扫描工作流:深度安全扫描 # - 定时:每周一凌晨 3 点执行 # - 手动触发:workflow_dispatch(可指定扫描目标) on: schedule: - cron: "0 3 * * 1" # 每周一凌晨 3 点 workflow_dispatch: inputs: target_url: description: "DAST 扫描目标 URL(留空则使用 NEXTAUTH_URL secret 或 localhost:8015)" required: false default: "" skip_dast: description: "跳过 DAST 扫描" type: boolean required: false default: false jobs: deep-security-scan: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - name: Install dependencies run: npm ci # 1. 依赖扫描:npm audit - name: Dependency scan (npm audit) run: | echo "::group::npm audit" npm audit --audit-level=moderate || true npm audit --json > audit-report.json || true echo "::endgroup::" continue-on-error: true # 2. 深度依赖分析 + 静态分析:Snyk - name: Snyk dependency & code scan uses: snyk/actions/node@master env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: args: --severity-threshold=medium --sarif-file-output=snyk.sarif continue-on-error: true # 3. 文件系统扫描:Trivy FS(代码 + 依赖) - name: Trivy filesystem scan run: | echo "::group::Trivy FS scan" trivy fs --format json --output trivy-fs-report.json --exit-code 0 . trivy fs --format table --exit-code 0 . echo "::endgroup::" continue-on-error: true # 4. 容器镜像扫描:构建 nextjs-app 镜像并扫描 - name: Build & scan container image run: | echo "::group::Build Next.js standalone" SKIP_ENV_VALIDATION=1 NEXT_TELEMETRY_DISABLED=1 npm run build mkdir -p .next/standalone/public mkdir -p .next/standalone/.next/static cp -r public/* .next/standalone/public/ || true cp -r .next/static/* .next/standalone/.next/static/ || true cp Dockerfile .next/standalone/Dockerfile echo "::endgroup::" echo "::group::Build Docker image" docker build -t nextjs-app:scan .next/standalone echo "::endgroup::" echo "::group::Trivy image scan" trivy image --format json --output trivy-image-report.json --exit-code 0 nextjs-app:scan trivy image --format table --exit-code 0 nextjs-app:scan echo "::endgroup::" continue-on-error: true # 5. DAST:OWASP ZAP 基线扫描 - name: OWASP ZAP Baseline Scan (DAST) if: ${{ github.event.inputs.skip_dast != 'true' }} uses: zaproxy/action-baseline@v0.10.0 with: target: ${{ github.event.inputs.target_url || secrets.NEXTAUTH_URL || 'http://localhost:8015' }} cmd_options: '-a -j' continue-on-error: true # 6. 生成汇总报告 - name: Generate summary report if: always() run: | echo "# 安全扫描汇总报告" > security-summary.md echo "" >> security-summary.md echo "- 扫描时间: $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> security-summary.md echo "- 触发方式: ${{ github.event_name }}" >> security-summary.md echo "- 运行编号: ${{ github.run_id }}" >> security-summary.md echo "" >> security-summary.md echo "## 扫描结果" >> security-summary.md echo "" >> security-summary.md echo "| 扫描类型 | 状态 | 详情 |" >> security-summary.md echo "|---------|------|------|" >> security-summary.md # npm audit 汇总 if [ -f audit-report.json ]; then AUDIT_SUMMARY=$(jq -r '.metadata.vulnerabilities | "critical:\(.critical) high:\(.high) moderate:\(.moderate) low:\(.low) info:\(.info)"' audit-report.json 2>/dev/null || echo "解析失败") echo "| npm audit | 完成 | ${AUDIT_SUMMARY} |" >> security-summary.md else echo "| npm audit | 未生成报告 | - |" >> security-summary.md fi # Trivy FS 汇总 if [ -f trivy-fs-report.json ]; then FS_COUNT=$(jq -r '[.Results[]?.Vulnerabilities[]?] | length' trivy-fs-report.json 2>/dev/null || echo "0") echo "| Trivy FS | 完成 | 漏洞数: ${FS_COUNT} |" >> security-summary.md else echo "| Trivy FS | 未生成报告 | - |" >> security-summary.md fi # Trivy Image 汇总 if [ -f trivy-image-report.json ]; then IMG_COUNT=$(jq -r '[.Results[]?.Vulnerabilities[]?] | length' trivy-image-report.json 2>/dev/null || echo "0") echo "| Trivy Image | 完成 | 漏洞数: ${IMG_COUNT} |" >> security-summary.md else echo "| Trivy Image | 未生成报告 | - |" >> security-summary.md fi # Snyk 汇总 if [ -f snyk.sarif ]; then SNYK_COUNT=$(jq -r '[.runs[]?.results[]?] | length' snyk.sarif 2>/dev/null || echo "0") echo "| Snyk | 完成 | 问题数: ${SNYK_COUNT} |" >> security-summary.md else echo "| Snyk | 未生成报告(可能缺少 SNYK_TOKEN) | - |" >> security-summary.md fi echo "" >> security-summary.md echo "## 处理建议" >> security-summary.md echo "" >> security-summary.md echo "- **Critical**: 24 小时内修复或缓解" >> security-summary.md echo "- **High**: 7 天内修复" >> security-summary.md echo "- **Medium**: 30 天内修复" >> security-summary.md echo "- **Low**: 90 天内评估处理" >> security-summary.md echo "" >> security-summary.md echo "详细报告见 artifact: security-reports-full" >> security-summary.md echo "::notice::安全扫描汇总报告已生成" cat security-summary.md # 7. 上传所有报告 - uses: actions/upload-artifact@v3 if: always() with: name: security-reports-full path: | audit-report.json trivy-fs-report.json trivy-image-report.json snyk.sarif security-summary.md