feat(advisories): add provisional GHSA feed (#242)

* feat(advisories): add provisional ghsa feed

* fix(workflows): include advisory signatures in checksums

* fix(workflows): mirror ghsa feed at release root

* feat(advisories): consolidate ghsa into agent feed

* ci(advisories): consolidate ghsa during nvd poll

* fix(advisories): retain unreplaced ghsa feed entries

* chore(skills): bump advisory feed consumers

* fix(release): resolve ts import closure dry run

* fix(release): preserve urls while stripping comments

* fix(release): ignore skill test-only changes

* fix(advisories): follow ghsa pagination links

* test(advisories): add nvd ghsa pipeline dry run
This commit is contained in:
davida-ps
2026-05-24 21:41:59 +03:00
committed by GitHub
parent 8a9bdfcd23
commit 4dbac421ab
34 changed files with 1944 additions and 81 deletions
+23
View File
@@ -93,6 +93,29 @@ jobs:
- name: Check for outdated deps
run: npm outdated || true
advisory-feed-tests:
name: Advisory Feed Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: GHSA Without CVE Feed Tests
run: node scripts/test-ghsa-without-cve-feed.mjs
- name: GHSA Poll Workflow Tests
run: node scripts/test-ghsa-poll-workflow.mjs
- name: NVD GHSA Consolidation Workflow Tests
run: node scripts/test-nvd-ghsa-consolidation-workflow.mjs
- name: NVD + GHSA Pipeline Dry Run
run: node scripts/test-nvd-ghsa-pipeline-dry-run.mjs
- name: Skill Release Workflow Tests
run: node scripts/test-skill-release-workflow.mjs
- name: Deploy Pages Advisory Checksums Tests
run: node scripts/test-deploy-pages-checksums.mjs
clawsec-suite-tests:
name: ClawSec Suite Verification Tests
runs-on: ubuntu-latest
+51 -23
View File
@@ -249,16 +249,51 @@ jobs:
set -euo pipefail
mkdir -p public/advisories
cp advisories/feed.json public/advisories/feed.json
if [ -f advisories/ghsa-without-cve.json ]; then
cp advisories/ghsa-without-cve.json public/advisories/ghsa-without-cve.json
fi
echo "Copied advisory feed to public/advisories/"
cat public/advisories/feed.json | jq '.advisories | length' | xargs -I {} echo "Feed contains {} advisories"
if [ -f public/advisories/ghsa-without-cve.json ]; then
cat public/advisories/ghsa-without-cve.json | jq '.advisories | length' | xargs -I {} echo "GHSA provisional feed contains {} advisories"
fi
- name: Sign advisory feed and verify
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: public/advisories/feed.json
signature_file: public/advisories/feed.json.sig
public_key_output: public/signing-public.pem
- name: Sign provisional GHSA feed and verify
if: hashFiles('public/advisories/ghsa-without-cve.json') != ''
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: public/advisories/ghsa-without-cve.json
signature_file: public/advisories/ghsa-without-cve.json.sig
- name: Generate advisory checksums manifest
run: |
set -euo pipefail
FEED_FILE="public/advisories/feed.json"
FEED_SHA=$(sha256sum "$FEED_FILE" | awk '{print $1}')
FEED_SIZE=$(stat -c%s "$FEED_FILE" 2>/dev/null || stat -f%z "$FEED_FILE")
FILES_JSON="{}"
ADVISORY_ARTIFACTS=(public/advisories/*.json public/advisories/*.json.sig)
for file in "${ADVISORY_ARTIFACTS[@]}"; do
[ -e "$file" ] || continue
REL_PATH="${file#public/}"
FILE_SHA=$(sha256sum "$file" | awk '{print $1}')
FILE_SIZE=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file")
FILES_JSON=$(jq \
--arg path "$REL_PATH" \
--arg sha "$FILE_SHA" \
--argjson size "$FILE_SIZE" \
'. + {($path): {sha256: $sha, size: $size, path: $path, url: ("https://clawsec.prompt.security/" + $path)}}' \
<<< "$FILES_JSON")
done
# Generate checksums manifest conforming to parseChecksumsManifest expectations:
# - schema_version: "1" (manifest format version)
@@ -272,36 +307,19 @@ jobs:
--arg version "1.1.0" \
--arg generated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg repo "${{ github.repository }}" \
--arg sha "$FEED_SHA" \
--argjson size "$FEED_SIZE" \
--argjson files "$FILES_JSON" \
'{
schema_version: $schema_version,
algorithm: $algorithm,
version: $version,
generated_at: $generated,
repository: $repo,
files: {
"advisories/feed.json": {
sha256: $sha,
size: $size,
path: "advisories/feed.json",
url: "https://clawsec.prompt.security/advisories/feed.json"
}
}
files: $files
}' > public/checksums.json
echo "Generated public/checksums.json"
jq . public/checksums.json
- name: Sign advisory feed and verify
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: public/advisories/feed.json
signature_file: public/advisories/feed.json.sig
public_key_output: public/signing-public.pem
- name: Sign checksums and verify
uses: ./.github/actions/sign-and-verify
with:
@@ -334,7 +352,7 @@ jobs:
- name: Show signed advisory artifacts
run: |
echo "Signed advisory artifacts:"
ls -la public/advisories/feed.json*
ls -la public/advisories/*.json*
ls -la public/checksums.json public/checksums.sig public/signing-public.pem
- name: Setup Node.js
@@ -387,6 +405,16 @@ jobs:
cp "public/advisories/feed.json.sig" "$MIRROR_LATEST_DIR/advisories/feed.json.sig"
cp "public/advisories/feed.json.sig" "$MIRROR_LATEST_DIR/feed.json.sig"
fi
if [ -f "public/advisories/ghsa-without-cve.json" ]; then
mkdir -p "$MIRROR_LATEST_DIR/advisories"
cp "public/advisories/ghsa-without-cve.json" "$MIRROR_LATEST_DIR/advisories/ghsa-without-cve.json"
cp "public/advisories/ghsa-without-cve.json" "$MIRROR_LATEST_DIR/ghsa-without-cve.json"
fi
if [ -f "public/advisories/ghsa-without-cve.json.sig" ]; then
mkdir -p "$MIRROR_LATEST_DIR/advisories"
cp "public/advisories/ghsa-without-cve.json.sig" "$MIRROR_LATEST_DIR/advisories/ghsa-without-cve.json.sig"
cp "public/advisories/ghsa-without-cve.json.sig" "$MIRROR_LATEST_DIR/ghsa-without-cve.json.sig"
fi
if [ -f "public/checksums.json" ]; then
cp "public/checksums.json" "$MIRROR_LATEST_DIR/checksums.json"
fi
+28 -13
View File
@@ -27,14 +27,26 @@ jobs:
set -euo pipefail
mkdir -p public/advisories
cp advisories/feed.json public/advisories/feed.json
if [ -f advisories/ghsa-without-cve.json ]; then
cp advisories/ghsa-without-cve.json public/advisories/ghsa-without-cve.json
fi
- name: Generate advisory checksums manifest
run: |
set -euo pipefail
FEED_FILE="public/advisories/feed.json"
FEED_SHA=$(sha256sum "$FEED_FILE" | awk '{print $1}')
FEED_SIZE=$(stat -c%s "$FEED_FILE" 2>/dev/null || stat -f%z "$FEED_FILE")
FILES_JSON="{}"
for file in public/advisories/*.json; do
REL_PATH="${file#public/}"
FILE_SHA=$(sha256sum "$file" | awk '{print $1}')
FILE_SIZE=$(stat -c%s "$file" 2>/dev/null || stat -f%z "$file")
FILES_JSON=$(jq \
--arg path "$REL_PATH" \
--arg sha "$FILE_SHA" \
--argjson size "$FILE_SIZE" \
'. + {($path): {sha256: $sha, size: $size, path: $path, url: ("https://clawsec.prompt.security/" + $path)}}' \
<<< "$FILES_JSON")
done
jq -n \
--arg schema_version "1" \
@@ -42,22 +54,14 @@ jobs:
--arg version "1.1.0" \
--arg generated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg repo "${{ github.repository }}" \
--arg sha "$FEED_SHA" \
--argjson size "$FEED_SIZE" \
--argjson files "$FILES_JSON" \
'{
schema_version: $schema_version,
algorithm: $algorithm,
version: $version,
generated_at: $generated,
repository: $repo,
files: {
"advisories/feed.json": {
sha256: $sha,
size: $size,
path: "advisories/feed.json",
url: "https://clawsec.prompt.security/advisories/feed.json"
}
}
files: $files
}' > public/checksums.json
- name: Generate ephemeral signing key for PR verification
@@ -81,6 +85,14 @@ jobs:
signature_file: public/advisories/feed.json.sig
public_key_output: public/signing-public.pem
- name: Sign provisional GHSA feed and verify
if: hashFiles('public/advisories/ghsa-without-cve.json') != ''
uses: ./.github/actions/sign-and-verify
with:
private_key: ${{ steps.test_key.outputs.private_key }}
input_file: public/advisories/ghsa-without-cve.json
signature_file: public/advisories/ghsa-without-cve.json.sig
- name: Sign checksums and verify
uses: ./.github/actions/sign-and-verify
with:
@@ -107,5 +119,8 @@ jobs:
set -euo pipefail
test -f dist/index.html
test -f public/advisories/feed.json.sig
if [ -f public/advisories/ghsa-without-cve.json ]; then
test -f public/advisories/ghsa-without-cve.json.sig
fi
test -f public/checksums.sig
test -f public/signing-public.pem
+158
View File
@@ -0,0 +1,158 @@
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
+80 -12
View File
@@ -21,6 +21,8 @@ concurrency:
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
@@ -833,8 +835,54 @@ jobs:
exit 1
fi
- name: Poll GHSA without CVE and consolidate feed
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
mkdir -p "$(dirname "$SKILL_FEED_PATH")"
cp "$FEED_PATH" "$SKILL_FEED_PATH"
- name: Detect advisory feed changes
id: feed_changes
run: |
set -euo pipefail
NVD_CHANGED=false
GHSA_CHANGED=false
AGENT_CHANGED=false
if [ "${{ steps.transform.outputs.new_count }}" != "0" ] || [ "${{ steps.updates.outputs.update_count }}" != "0" ]; then
NVD_CHANGED=true
fi
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 "nvd_changed=$NVD_CHANGED" >> "$GITHUB_OUTPUT"
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: Guard dependency manifests from NVD updates
if: steps.transform.outputs.new_count != '0' || steps.updates.outputs.update_count != '0'
if: steps.feed_changes.outputs.changed == 'true'
run: |
set -euo pipefail
@@ -851,8 +899,17 @@ jobs:
exit 1
fi
- name: Sign GHSA feed and verify
if: steps.feed_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 advisory feed and verify
if: steps.transform.outputs.new_count != '0' || steps.updates.outputs.update_count != '0'
if: steps.feed_changes.outputs.agent_changed == 'true'
uses: ./.github/actions/sign-and-verify
with:
private_key: ${{ secrets.CLAWSEC_SIGNING_PRIVATE_KEY }}
@@ -864,18 +921,18 @@ jobs:
${{ env.SKILL_FEED_PATH }}
- name: Sync advisory signature to skill feed
if: steps.transform.outputs.new_count != '0' || steps.updates.outputs.update_count != '0'
if: steps.feed_changes.outputs.agent_changed == 'true'
run: cp "$FEED_SIG_PATH" "$SKILL_FEED_SIG_PATH"
- name: Clean workspace for PR
if: steps.transform.outputs.new_count != '0' || steps.updates.outputs.update_count != '0'
if: steps.feed_changes.outputs.changed == 'true'
run: |
# Reset any unintended changes, keep only feed files
git checkout -- .github/ 2>/dev/null || true
git clean -fd .github/ 2>/dev/null || true
- name: Upsert NVD advisory PR
if: steps.transform.outputs.new_count != '0' || steps.updates.outputs.update_count != '0'
if: steps.feed_changes.outputs.changed == 'true'
id: upsert-pr
env:
GH_TOKEN: ${{ github.token }}
@@ -884,9 +941,14 @@ jobs:
BRANCH_PREFIX="automated/nvd-cve-update"
PR_COMMENT="Superseded by newer automated NVD advisory update."
TITLE="chore: CVE advisories - ${{ steps.transform.outputs.new_count }} new, ${{ steps.updates.outputs.update_count }} updated"
TITLE="chore: update NVD/GHSA advisories - ${{ steps.transform.outputs.new_count }} NVD new, ${{ steps.updates.outputs.update_count }} NVD updated"
COMMIT_SUBJECT="$TITLE"
COMMIT_BODY=$'Automated update from NVD CVE feed.\nKeywords: ${{ env.KEYWORDS }}\nPoll window: ${{ steps.dates.outputs.start_date }} to ${{ steps.dates.outputs.end_date }}'
COMMIT_BODY=$'Automated update from NVD CVE and GHSA advisory feeds.\nKeywords: ${{ env.KEYWORDS }}\nPoll window: ${{ steps.dates.outputs.start_date }} to ${{ steps.dates.outputs.end_date }}'
GHSA_TOTAL="$(jq '.advisories | length' "$GHSA_FEED_PATH")"
GHSA_ACTIVE="$(jq '[.advisories[] | select(.status == "active")] | length' "$GHSA_FEED_PATH")"
GHSA_MATURED="$(jq '[.advisories[] | select(.status == "matured")] | length' "$GHSA_FEED_PATH")"
GHSA_STALE="$(jq '[.advisories[] | select(.status == "stale")] | length' "$GHSA_FEED_PATH")"
if [ "${{ inputs.force_full_scan }}" = "true" ]; then
MODE="full-rebuild (ignore feed state)"
@@ -897,16 +959,19 @@ jobs:
BODY_FILE="$(mktemp)"
cat > "$BODY_FILE" <<EOF
## Summary
Automated update from NVD CVE feed.
Automated update from NVD CVE and GHSA advisory feeds.
- **Mode:** ${MODE}
- **New advisories:** ${{ steps.transform.outputs.new_count }}
- **Updated advisories:** ${{ steps.updates.outputs.update_count }}
- **New NVD advisories:** ${{ steps.transform.outputs.new_count }}
- **Updated NVD advisories:** ${{ steps.updates.outputs.update_count }}
- **GHSA source feed changed:** ${{ steps.feed_changes.outputs.ghsa_changed }}
- **Consolidated agent feed changed:** ${{ steps.feed_changes.outputs.agent_changed }}
- **GHSA provisional advisories:** ${GHSA_TOTAL} total (${GHSA_ACTIVE} active, ${GHSA_MATURED} matured, ${GHSA_STALE} stale)
- **Poll window:** ${{ steps.dates.outputs.start_date }} → ${{ steps.dates.outputs.end_date }}
- **Keywords:** ${{ env.KEYWORDS }}
---
*This PR was automatically generated by the NVD CVE polling workflow.*
*This PR was automatically generated by the NVD CVE polling workflow with GHSA consolidation.*
EOF
PR_LIST_JSON="$(
@@ -953,7 +1018,7 @@ jobs:
git fetch origin main
git checkout -B "$TARGET_BRANCH" origin/main
git add "$FEED_PATH" "$FEED_SIG_PATH" "$SKILL_FEED_PATH" "$SKILL_FEED_SIG_PATH"
git add "$FEED_PATH" "$FEED_SIG_PATH" "$GHSA_FEED_PATH" "$GHSA_FEED_SIG_PATH" "$SKILL_FEED_PATH" "$SKILL_FEED_SIG_PATH"
if git diff --cached --quiet; then
echo "::error::Expected advisory feed changes but none were staged."
exit 1
@@ -1033,6 +1098,9 @@ jobs:
echo "| CVEs Found (filtered) | ${{ steps.process.outputs.filtered_count }} |" >> $GITHUB_STEP_SUMMARY
echo "| New Advisories | ${{ steps.transform.outputs.new_count }} |" >> $GITHUB_STEP_SUMMARY
echo "| Updated Advisories | ${{ steps.updates.outputs.update_count }} |" >> $GITHUB_STEP_SUMMARY
echo "| GHSA source feed changed | ${{ steps.feed_changes.outputs.ghsa_changed }} |" >> $GITHUB_STEP_SUMMARY
echo "| Consolidated agent feed changed | ${{ steps.feed_changes.outputs.agent_changed }} |" >> $GITHUB_STEP_SUMMARY
echo "| GHSA provisional advisories | $(jq '.advisories | length' "$GHSA_FEED_PATH") |" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.transform.outputs.new_count }}" != "0" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
+11 -7
View File
@@ -6,8 +6,7 @@ on:
- '*-v[0-9]*.[0-9]*.[0-9]*'
pull_request:
paths:
- 'skills/*/skill.json'
- 'skills/*/SKILL.md'
- 'skills/**'
workflow_dispatch:
inputs:
tag:
@@ -39,7 +38,7 @@ jobs:
- name: Verify signing key consistency (repo + docs)
run: ./scripts/ci/verify_signing_key_consistency.sh
- name: Validate version parity for bumped skills
- name: Validate version parity for changed skills
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
@@ -79,12 +78,15 @@ jobs:
}
touched_skills_file="$(mktemp)"
git diff --name-only "${BASE_SHA}...${HEAD_SHA}" -- 'skills/*/skill.json' 'skills/*/SKILL.md' \
git diff --name-only "${BASE_SHA}...${HEAD_SHA}" -- \
'skills/*/**' \
':(exclude)skills/*/test/**' \
':(exclude)skills/*/tests/**' \
| awk -F/ 'NF >= 3 {print $1 "/" $2}' \
| sort -u > "${touched_skills_file}"
if [ ! -s "${touched_skills_file}" ]; then
echo "No skill metadata files changed in this PR."
echo "No release-relevant skill package files changed in this PR."
rm -f "${touched_skills_file}"
exit 0
fi
@@ -129,6 +131,8 @@ jobs:
continue
fi
checked_skills=$((checked_skills + 1))
json_version_changed=false
md_version_changed=false
@@ -141,11 +145,11 @@ jobs:
fi
if [ "${json_version_changed}" != "true" ] && [ "${md_version_changed}" != "true" ]; then
echo "No version bump detected for ${skill_dir}; skipping."
echo "::error file=${skill_dir}::Changed skill package has no version bump. Update skill.json and SKILL.md versions and add CHANGELOG.md release notes."
failures=$((failures + 1))
continue
fi
checked_skills=$((checked_skills + 1))
echo "Version bump detected for ${skill_dir} (skill.json changed: ${json_version_changed}, SKILL.md changed: ${md_version_changed})"
if [ ! -f "${json_path}" ]; then