Loading...
Loading...
Compare original and translation side by side
/security-checknpx skills add fellowship-dev/dogfooded-skills/skills/ops/security-runner/security-checknpx skills add fellowship-dev/dogfooded-skills/skills/ops/security-runnerundefinedundefined
If alerts endpoint returns 403, the token lacks `security_events` scope or Dependabot isn't enabled.
---
如果警报接口返回403,说明令牌缺少`security_events`权限,或者Dependabot未启用。
---REPO="${1:-$PYLOT_REPO}"
TODAY=$(date +%Y-%m-%d)
REPORT_PATH="/tmp/security-runner-${REPO//\//-}-${TODAY}.md"REPO="${1:-$PYLOT_REPO}"
TODAY=$(date +%Y-%m-%d)
REPORT_PATH="/tmp/security-runner-${REPO//\//-}-${TODAY}.md"
---
---undefinedundefined
---
---classify_alert() {
local severity="$1" # critical|high|medium|low
local scope="$2" # runtime|development (from Dependabot)
local manifest="$3" # path to manifest file
# Map Dependabot scope to exploitability
local exploitability="dev-only"
if [ "$scope" = "runtime" ]; then
exploitability="network-reachable"
fi
# test-only: infer from manifest path — only when not explicitly runtime-scoped
# (guards against false downgrades on monorepos where test/ dirs contain runtime deps)
if [ "$scope" != "runtime" ] && echo "$manifest" | grep -qiE 'test|spec|__tests__|cypress'; then
exploitability="test-only"
fi
# Decision matrix
case "${severity}__${exploitability}" in
"critical__network-reachable") echo "P0" ;;
"critical__dev-only"|"high__network-reachable") echo "P1" ;;
"critical__test-only"|"high__dev-only"|"high__test-only"|"medium__network-reachable") echo "P2" ;;
"medium__dev-only"|"medium__test-only"|"low__network-reachable") echo "backlog" ;;
*) echo "dismiss" ;;
esac
}classify_alert() {
local severity="$1" # critical|high|medium|low
local scope="$2" # runtime|development (from Dependabot)
local manifest="$3" # path to manifest file
# Map Dependabot scope to exploitability
local exploitability="dev-only"
if [ "$scope" = "runtime" ]; then
exploitability="network-reachable"
fi
# test-only: infer from manifest path — only when not explicitly runtime-scoped
# (guards against false downgrades on monorepos where test/ dirs contain runtime deps)
if [ "$scope" != "runtime" ] && echo "$manifest" | grep -qiE 'test|spec|__tests__|cypress'; then
exploitability="test-only"
fi
# Decision matrix
case "${severity}__${exploitability}" in
"critical__network-reachable") echo "P0" ;;
"critical__dev-only"|"high__network-reachable") echo "P1" ;;
"critical__test-only"|"high__dev-only"|"high__test-only"|"medium__network-reachable") echo "P2" ;;
"medium__dev-only"|"medium__test-only"|"low__network-reachable") echo "backlog" ;;
*) echo "dismiss" ;;
esac
}process_p0_p1_alert() {
local pkg="$1"
local patched="$2"
local alert_url="$3"
local priority="$4"
# Check if a Dependabot PR already exists for this package
EXISTING_PR=$(gh pr list --repo "$REPO" --state open --json number,title \
--jq ".[] | select(.title | test(\"$pkg\"; \"i\")) | .number" 2>/dev/null | head -1)
if [ -n "$EXISTING_PR" ]; then
echo " → Existing PR #$EXISTING_PR for $pkg — labeling $priority"
gh pr edit "$EXISTING_PR" --repo "$REPO" --add-label "security,$priority" 2>/dev/null || true
# Apply merge strategy here where $EXISTING_PR is in scope
if [ "$MERGE_STRATEGY" = "auto-merge" ]; then
gh pr merge "$EXISTING_PR" --repo "$REPO" --auto --squash 2>/dev/null && \
echo " → Auto-merge enabled on PR #$EXISTING_PR"
else
gh pr edit "$EXISTING_PR" --repo "$REPO" --add-label "ready-to-merge" 2>/dev/null && \
echo " → Labeled PR #$EXISTING_PR as ready-to-merge (restricted repo — human must merge)"
fi
return
fi
if [ "$patched" = "none" ]; then
# No patch available — create issue with upgrade path
gh issue create --repo "$REPO" \
--title "security: no patch for $pkg ($priority)" \
--label "security,$priority" \
--body "## Vulnerability\n\nPackage: \`$pkg\`\nPriority: $priority\nDependabot alert: $alert_url\n\nNo patched version available. Options:\n- [ ] Pin to last non-vulnerable version\n- [ ] Find alternative package\n- [ ] Remove dependency if unused\n\ncc: @maxfindel" 2>/dev/null
else
# No public GitHub API endpoint exists to trigger Dependabot PR creation directly.
# Create a tracking issue and direct the team to bump manually or await Dependabot's schedule.
echo " → Patch available ($patched) — creating tracking issue for $pkg"
gh issue create --repo "$REPO" \
--title "security: bump $pkg to $patched ($priority)" \
--label "security,$priority" \
--body "## Action Required\n\nPackage: \`$pkg\`\nFixed in: \`$patched\`\nPriority: $priority\nDependabot alert: $alert_url\n\nDependabot has not auto-created a PR. Options:\n- [ ] Wait for Dependabot's next scheduled run (Mon 05:00)\n- [ ] Manually bump \`$pkg\` to \`$patched\` and open a PR\n\nMonitor: https://github.com/$REPO/security/dependabot" 2>/dev/null && \
echo " → Tracking issue created for $pkg → $patched"
fi
}process_p0_p1_alert() {
local pkg="$1"
local patched="$2"
local alert_url="$3"
local priority="$4"
# Check if a Dependabot PR already exists for this package
EXISTING_PR=$(gh pr list --repo "$REPO" --state open --json number,title \
--jq ".[] | select(.title | test(\"$pkg\"; \"i\")) | .number" 2>/dev/null | head -1)
if [ -n "$EXISTING_PR" ]; then
echo " → Existing PR #$EXISTING_PR for $pkg — labeling $priority"
gh pr edit "$EXISTING_PR" --repo "$REPO" --add-label "security,$priority" 2>/dev/null || true
# Apply merge strategy here where $EXISTING_PR is in scope
if [ "$MERGE_STRATEGY" = "auto-merge" ]; then
gh pr merge "$EXISTING_PR" --repo "$REPO" --auto --squash 2>/dev/null && \
echo " → Auto-merge enabled on PR #$EXISTING_PR"
else
gh pr edit "$EXISTING_PR" --repo "$REPO" --add-label "ready-to-merge" 2>/dev/null && \
echo " → Labeled PR #$EXISTING_PR as ready-to-merge (restricted repo — human must merge)"
fi
return
fi
if [ "$patched" = "none" ]; then
# No patch available — create issue with upgrade path
gh issue create --repo "$REPO" \
--title "security: no patch for $pkg ($priority)" \
--label "security,$priority" \
--body "## Vulnerability\n\nPackage: \`$pkg\`\nPriority: $priority\nDependabot alert: $alert_url\n\nNo patched version available. Options:\n- [ ] Pin to last non-vulnerable version\n- [ ] Find alternative package\n- [ ] Remove dependency if unused\n\ncc: @maxfindel" 2>/dev/null
else
# No public GitHub API endpoint exists to trigger Dependabot PR creation directly.
# Create a tracking issue and direct the team to bump manually or await Dependabot's schedule.
echo " → Patch available ($patched) — creating tracking issue for $pkg"
gh issue create --repo "$REPO" \
--title "security: bump $pkg to $patched ($priority)" \
--label "security,$priority" \
--body "## Action Required\n\nPackage: \`$pkg\`\nFixed in: \`$patched\`\nPriority: $priority\nDependabot alert: $alert_url\n\nDependabot has not auto-created a PR. Options:\n- [ ] Wait for Dependabot's next scheduled run (Mon 05:00)\n- [ ] Manually bump \`$pkg\` to \`$patched\` and open a PR\n\nMonitor: https://github.com/$REPO/security/dependabot" 2>/dev/null && \
echo " → Tracking issue created for $pkg → $patched"
fi
}process_p2_backlog_alert() {
local pkg="$1"
local severity="$2"
local summary="$3"
local alert_url="$4"
local priority="$5"
# Check for existing issue before creating
EXISTING=$(gh issue list --repo "$REPO" --state open --label security \
--json number,title --jq ".[] | select(.title | test(\"$pkg\"; \"i\")) | .number" 2>/dev/null | head -1)
if [ -n "$EXISTING" ]; then
echo " → Existing issue #$EXISTING for $pkg — skipping duplicate"
return
fi
gh issue create --repo "$REPO" \
--title "security: upgrade $pkg ($severity — $priority)" \
--label "security,$priority" \
--body "## Vulnerability\n\nPackage: \`$pkg\`\nSeverity: $severity\nSummary: $summary\nDependabot alert: $alert_url\n\nBatch in next monthly dependency cycle. Verify no breaking changes before upgrading." 2>/dev/null
}process_p2_backlog_alert() {
local pkg="$1"
local severity="$2"
local summary="$3"
local alert_url="$4"
local priority="$5"
# Check for existing issue before creating
EXISTING=$(gh issue list --repo "$REPO" --state open --label security \
--json number,title --jq ".[] | select(.title | test(\"$pkg\"; \"i\")) | .number" 2>/dev/null | head -1)
if [ -n "$EXISTING" ]; then
echo " → Existing issue #$EXISTING for $pkg — skipping duplicate"
return
fi
gh issue create --repo "$REPO" \
--title "security: upgrade $pkg ($severity — $priority)" \
--label "security,$priority" \
--body "## Vulnerability\n\nPackage: \`$pkg\`\nSeverity: $severity\nSummary: $summary\nDependabot alert: $alert_url\n\nBatch in next monthly dependency cycle. Verify no breaking changes before upgrading." 2>/dev/null
}dismiss_alert() {
local alert_number="$1"
local reason="$2" # tolerated_risk | inaccurate | not_used | no_bandwidth
gh api repos/"$REPO"/dependabot/alerts/"$alert_number" \
--method PATCH \
--field state=dismissed \
--field dismissed_reason="$reason" \
--field dismissed_comment="Dismissed by security-runner: $reason. Review quarterly." 2>/dev/null
echo " → Dismissed alert #$alert_number (reason: $reason)"
}dismiss_alert() {
local alert_number="$1"
local reason="$2" # tolerated_risk | inaccurate | not_used | no_bandwidth
gh api repos/"$REPO"/dependabot/alerts/"$alert_number" \
--method PATCH \
--field state=dismissed \
--field dismissed_reason="$reason" \
--field dismissed_comment="Dismissed by security-runner: $reason. Review quarterly." 2>/dev/null
echo " → Dismissed alert #$alert_number (reason: $reason)"
}$ALERTSundefined$ALERTSundefined
---
---process_p0_p1_alert$EXISTING_PR$MERGE_STRATEGYprocess_p0_p1_alert$EXISTING_PR$MERGE_STRATEGYcat > "$REPORT_PATH" << REPORTcat > "$REPORT_PATH" << REPORT| Priority | Count | Action |
|---|---|---|
| P0 | $COUNT_P0 | PRs opened / existing PRs labeled |
| P1 | $COUNT_P1 | PRs opened / existing PRs labeled |
| P2 | $COUNT_P2 | Issues created for batch cycle |
| Backlog | $COUNT_BACKLOG | Issues created (no urgency) |
| Dismissed | $COUNT_DISMISS | Dismissed via API |
| Priority | Count | Action |
|---|---|---|
| P0 | $COUNT_P0 | PRs opened / existing PRs labeled |
| P1 | $COUNT_P1 | PRs opened / existing PRs labeled |
| P2 | $COUNT_P2 | Issues created for batch cycle |
| Backlog | $COUNT_BACKLOG | Issues created (no urgency) |
| Dismissed | $COUNT_DISMISS | Dismissed via API |
---
---undefinedundefined
---
---#!/bin/bash#!/bin/bash
---
---undefinedundefined
---
---[pylot] outcome="N alerts triaged: X PRs, Y issues, Z dismissed" status=success
[pylot] outcome="blocked: Dependabot API returned 403 — token missing security_events scope" status=blocked[pylot] outcome="N alerts triaged: X PRs, Y issues, Z dismissed" status=success
[pylot] outcome="blocked: Dependabot API returned 403 — token missing security_events scope" status=blocked/security-check/deps-runner/entropy-check/maintenance/security-check/deps-runner/entropy-check/maintenance