Security - 2x Daily Dependency Scan #100
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================================ | |
| # Security Dependency Scan - 2x Daily Forced Scans | |
| # ============================================================================ | |
| # | |
| # This workflow complements Dependabot by forcing additional dependency scans | |
| # 2x per day (midnight and noon UTC) to catch vulnerabilities faster. | |
| # | |
| # Runs: 2x daily (00:00 UTC and 12:00 UTC) | |
| # Action: Triggers Dependabot via API + runs npm audit | |
| # ============================================================================ | |
| name: Security - 2x Daily Dependency Scan | |
| on: | |
| schedule: | |
| - cron: '0 0 * * *' # Midnight UTC | |
| - cron: '0 12 * * *' # Noon UTC | |
| workflow_dispatch: # Manual trigger | |
| permissions: | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| jobs: | |
| # =================================== | |
| # NPM Audit Scan | |
| # =================================== | |
| npm-audit: | |
| name: NPM Audit Security Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9.1.0 | |
| - name: Run npm audit | |
| id: audit | |
| continue-on-error: true | |
| run: | | |
| echo "Running npm audit..." | |
| pnpm audit --json > audit-report.json || true | |
| # Check for CRITICAL or HIGH vulnerabilities | |
| CRITICAL=$(cat audit-report.json | jq -r '.metadata.vulnerabilities.critical // 0') | |
| HIGH=$(cat audit-report.json | jq -r '.metadata.vulnerabilities.high // 0') | |
| echo "critical=$CRITICAL" >> $GITHUB_OUTPUT | |
| echo "high=$HIGH" >> $GITHUB_OUTPUT | |
| if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then | |
| echo "Found $CRITICAL CRITICAL and $HIGH HIGH vulnerabilities" | |
| exit 1 | |
| fi | |
| - name: Create security issue if vulnerabilities found | |
| if: failure() && steps.audit.outcome == 'failure' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const critical = '${{ steps.audit.outputs.critical }}'; | |
| const high = '${{ steps.audit.outputs.high }}'; | |
| const title = `🚨 Security Alert: ${critical} CRITICAL + ${high} HIGH vulnerabilities detected`; | |
| const body = ` | |
| ## Security Vulnerability Alert | |
| **Scan Time:** ${new Date().toUTCString()} | |
| **Scan Type:** Automated 2x Daily Dependency Scan | |
| ### Summary | |
| - **CRITICAL:** ${critical} | |
| - **HIGH:** ${high} | |
| ### Action Required | |
| 1. Review the npm audit report in the workflow logs | |
| 2. Check Dependabot PRs for available fixes | |
| 3. If no PR exists, manually update vulnerable packages | |
| ### View Details | |
| - [Workflow Run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | |
| - [Security Tab](${{ github.server_url }}/${{ github.repository }}/security) | |
| --- | |
| *This issue was created automatically by the 2x Daily Security Scan* | |
| `; | |
| // Check if issue already exists | |
| const issues = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| labels: 'security,automated,dependencies' | |
| }); | |
| const existingIssue = issues.data.find(issue => | |
| issue.title.includes('Security Alert') && | |
| issue.title.includes('vulnerabilities detected') | |
| ); | |
| if (existingIssue) { | |
| // Update existing issue | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: existingIssue.number, | |
| body: body | |
| }); | |
| } else { | |
| // Create new issue | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: title, | |
| body: body, | |
| labels: ['security', 'automated', 'dependencies', 'critical'] | |
| }); | |
| } | |
| # =================================== | |
| # Trigger Dependabot Scan (via API) | |
| # =================================== | |
| trigger-dependabot: | |
| name: Trigger Dependabot Scan | |
| runs-on: ubuntu-latest | |
| needs: npm-audit | |
| steps: | |
| - name: Trigger Dependabot via workflow dispatch | |
| run: | | |
| echo "Dependabot scans are triggered automatically by GitHub" | |
| echo "This job serves as a reminder to check Dependabot PRs" | |
| - name: Check for open Dependabot PRs | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const prs = await github.rest.pulls.list({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open' | |
| }); | |
| const dependabotPRs = prs.data.filter(pr => | |
| pr.user.login === 'dependabot[bot]' | |
| ); | |
| if (dependabotPRs.length > 0) { | |
| console.log(`Found ${dependabotPRs.length} open Dependabot PRs:`); | |
| dependabotPRs.forEach(pr => { | |
| console.log(`- ${pr.title} (#${pr.number})`); | |
| }); | |
| } else { | |
| console.log('No open Dependabot PRs found'); | |
| } | |
| # ============================================================================ | |
| # HOW IT WORKS | |
| # ============================================================================ | |
| # | |
| # 1. Runs 2x per day (midnight and noon UTC) | |
| # 2. Executes npm audit to scan for vulnerabilities | |
| # 3. If CRITICAL or HIGH vulnerabilities found: | |
| # a. Creates/updates GitHub Issue with details | |
| # b. Alerts team via issue | |
| # 4. Checks for open Dependabot PRs and logs them | |
| # | |
| # This complements Dependabot's daily scan (6:00 UTC) with additional | |
| # scans at 00:00 and 12:00 UTC for faster vulnerability detection. | |
| # | |
| # Email Notifications: | |
| # - Disable in: Settings > Notifications > Email preferences | |
| # - Or: Settings > Notifications > Watching > Ignore workflow notifications | |
| # | |
| # ============================================================================ |