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