name: Poll GHSA Without CVE

on:
  workflow_dispatch:

permissions: read-all

concurrency:
  group: poll-ghsa-without-cve
  cancel-in-progress: false

env:
  FEED_PATH: advisories/feed.json
  FEED_SIG_PATH: advisories/feed.json.sig
  GHSA_FEED_PATH: advisories/ghsa-without-cve.json
  GHSA_FEED_SIG_PATH: advisories/ghsa-without-cve.json.sig
  SKILL_FEED_PATH: skills/clawsec-feed/advisories/feed.json
  SKILL_FEED_SIG_PATH: skills/clawsec-feed/advisories/feed.json.sig

jobs:
  poll-and-update:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Setup Node.js
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: '20'
          cache: 'npm'

      - name: Run GHSA feed tests
        run: node scripts/test-ghsa-without-cve-feed.mjs

      - name: Poll GitHub Security Advisories
        env:
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          set -euo pipefail
          node scripts/ghsa-without-cve-feed.mjs \
            --output "$GHSA_FEED_PATH" \
            --consolidated-feed "$FEED_PATH" \
            --existing-feed "$GHSA_FEED_PATH" \
            --nvd-feed "$FEED_PATH" \
            --stale-after-days 60

      - name: Sync consolidated feed to clawsec-feed skill
        run: |
          set -euo pipefail
          mkdir -p "$(dirname "$SKILL_FEED_PATH")"
          cp "$FEED_PATH" "$SKILL_FEED_PATH"

      - name: Detect feed changes
        id: changes
        run: |
          set -euo pipefail

          GHSA_CHANGED=false
          AGENT_CHANGED=false

          if ! git diff --quiet -- "$GHSA_FEED_PATH" || [ ! -f "$GHSA_FEED_SIG_PATH" ]; then
            GHSA_CHANGED=true
          fi

          if ! git diff --quiet -- "$FEED_PATH" "$SKILL_FEED_PATH" || [ ! -f "$FEED_SIG_PATH" ] || [ ! -f "$SKILL_FEED_SIG_PATH" ]; then
            AGENT_CHANGED=true
          fi

          echo "ghsa_changed=$GHSA_CHANGED" >> "$GITHUB_OUTPUT"
          echo "agent_changed=$AGENT_CHANGED" >> "$GITHUB_OUTPUT"

          if [ "$GHSA_CHANGED" = "true" ] || [ "$AGENT_CHANGED" = "true" ]; then
            echo "changed=true" >> "$GITHUB_OUTPUT"
          else
            echo "changed=false" >> "$GITHUB_OUTPUT"
          fi

      - name: Sign GHSA feed and verify
        if: steps.changes.outputs.ghsa_changed == 'true'
        uses: ./.github/actions/sign-and-verify
        with:
          private_key: ${{ secrets.CLAWSEC_SIGNING_PRIVATE_KEY }}
          private_key_passphrase: ${{ secrets.CLAWSEC_SIGNING_PRIVATE_KEY_PASSPHRASE }}
          input_file: ${{ env.GHSA_FEED_PATH }}
          signature_file: ${{ env.GHSA_FEED_SIG_PATH }}

      - name: Sign consolidated agent feed and verify
        if: steps.changes.outputs.agent_changed == 'true'
        uses: ./.github/actions/sign-and-verify
        with:
          private_key: ${{ secrets.CLAWSEC_SIGNING_PRIVATE_KEY }}
          private_key_passphrase: ${{ secrets.CLAWSEC_SIGNING_PRIVATE_KEY_PASSPHRASE }}
          input_file: ${{ env.FEED_PATH }}
          signature_file: ${{ env.FEED_SIG_PATH }}
          verify_files: |
            ${{ env.FEED_PATH }}
            ${{ env.SKILL_FEED_PATH }}

      - name: Sync consolidated signature to clawsec-feed skill
        if: steps.changes.outputs.agent_changed == 'true'
        run: cp "$FEED_SIG_PATH" "$SKILL_FEED_SIG_PATH"

      - name: Create Pull Request
        if: steps.changes.outputs.changed == 'true'
        id: create-pr
        uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
        with:
          token: ${{ github.token }}
          branch: automated/ghsa-without-cve-feed
          delete-branch: true
          title: 'chore: update provisional GHSA advisory feed'
          body: |
            ## Summary
            Updates the provisional GHSA advisory feed and the consolidated agent advisory feed.

            - Feed: `${{ env.GHSA_FEED_PATH }}`
            - Agent feed: `${{ env.FEED_PATH }}`
            - Stale threshold: 60 days without a CVE
            - Statuses: `active`, `matured`, `stale`

            ---
            *This PR was automatically generated by the GHSA-without-CVE polling workflow.*
          commit-message: |
            chore: update provisional GHSA advisory feed

            Poll public GitHub Security Advisories without CVE identifiers.
          add-paths: |
            ${{ env.FEED_PATH }}
            ${{ env.FEED_SIG_PATH }}
            ${{ env.GHSA_FEED_PATH }}
            ${{ env.GHSA_FEED_SIG_PATH }}
            ${{ env.SKILL_FEED_PATH }}
            ${{ env.SKILL_FEED_SIG_PATH }}

      - name: Summary
        run: |
          set -euo pipefail
          echo "## GHSA Without CVE Poll Summary" >> "$GITHUB_STEP_SUMMARY"
          echo "" >> "$GITHUB_STEP_SUMMARY"
          echo "| Metric | Value |" >> "$GITHUB_STEP_SUMMARY"
          echo "|--------|-------|" >> "$GITHUB_STEP_SUMMARY"
          echo "| Feed changed | ${{ steps.changes.outputs.changed }} |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Agent feed changed | ${{ steps.changes.outputs.agent_changed }} |" >> "$GITHUB_STEP_SUMMARY"
          echo "| GHSA source feed changed | ${{ steps.changes.outputs.ghsa_changed }} |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Feed path | $GHSA_FEED_PATH |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Agent feed path | $FEED_PATH |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Total advisories | $(jq '.advisories | length' "$GHSA_FEED_PATH") |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Active | $(jq '[.advisories[] | select(.status == "active")] | length' "$GHSA_FEED_PATH") |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Matured | $(jq '[.advisories[] | select(.status == "matured")] | length' "$GHSA_FEED_PATH") |" >> "$GITHUB_STEP_SUMMARY"
          echo "| Stale | $(jq '[.advisories[] | select(.status == "stale")] | length' "$GHSA_FEED_PATH") |" >> "$GITHUB_STEP_SUMMARY"
          if [ -n "${{ steps.create-pr.outputs.pull-request-url }}" ]; then
            echo "" >> "$GITHUB_STEP_SUMMARY"
            echo "Upserted PR: ${{ steps.create-pr.outputs.pull-request-url }}" >> "$GITHUB_STEP_SUMMARY"
          fi
