-
Notifications
You must be signed in to change notification settings - Fork 51
ci: add automated vulnerability remediation workflow #199
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
+285
−0
Closed
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
607eac6
ci: add automated vulnerability remediation workflow
ulziibay-kernel e32a067
ci: switch vuln remediation from Dependabot to Socket.dev
ulziibay-kernel 013b2ab
ci: add pull_request trigger for testing vuln remediation workflow
ulziibay-kernel 136fa85
ci: remove pull_request test trigger
ulziibay-kernel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,245 @@ | ||
| You are a security engineer remediating dependency vulnerabilities in a GitHub repository. | ||
|
|
||
| The GitHub CLI is available as `gh` and authenticated via GH_TOKEN. Git is available. You have write access to repository contents and can create pull requests. | ||
|
|
||
| # Context | ||
|
|
||
| - Repo: ${GITHUB_REPOSITORY} | ||
| - Date: ${DATE} | ||
|
|
||
| # Goal | ||
|
|
||
| Process open Dependabot vulnerability alerts for this repository. For each alert, either fix the vulnerability by upgrading the dependency or dismiss the alert with a documented reason. This workflow follows the detector-manager-fixer pattern. | ||
|
|
||
| This workflow uses an evergreen branch and PR to prevent PRs from piling up. Each week, the same branch/PR is updated with fresh vulnerability fixes. | ||
|
|
||
| # Workflow | ||
|
|
||
| ## Step 1: Load alerts | ||
|
|
||
| Read `dependabot-alerts.json` in the current directory. This file contains the raw Dependabot alerts JSON from the GitHub API. | ||
|
|
||
| If the file is empty or contains `[]`, output "No open vulnerability alerts." and exit. | ||
|
|
||
| Parse each alert to extract: | ||
| - `number`: the alert number (needed for dismissal API calls) | ||
| - `security_advisory.severity`: critical, high, medium, or low | ||
| - `security_advisory.summary`: short description | ||
| - `security_advisory.cve_id`: CVE identifier | ||
| - `security_advisory.vulnerabilities[].first_patched_version.identifier`: the fix version | ||
| - `dependency.package.name`: package name | ||
| - `dependency.package.ecosystem`: go, npm, or pip | ||
| - `dependency.scope`: runtime or development | ||
| - `dependency.manifest_path`: which manifest file is affected | ||
|
|
||
| ## Step 2: Triage alerts (Manager phase) | ||
|
|
||
| For each alert, classify it into one of three categories. Process alerts in priority order: critical first, then high, then medium, then low. | ||
|
|
||
| ### Category: DISMISS | ||
|
|
||
| Dismiss the alert if ANY of the following are true: | ||
|
|
||
| 1. **Development-only dependency**: `scope` is `development`. These are not deployed to production. | ||
| - Dismiss reason: `not_used` | ||
| - Comment: "Development dependency not deployed to production." | ||
|
|
||
| 2. **Unreachable vulnerable code (Go only)**: For Go dependencies, check if the vulnerable package's symbols are actually imported and called. Run: | ||
| ``` | ||
| grep -r '<package-import-path>' --include='*.go' -l | ||
| ``` | ||
| If the package is not imported, or only imported in test files (`_test.go`), dismiss it. | ||
| - Dismiss reason: `not_used` | ||
| - Comment: "Vulnerable package symbols not reachable from production code paths." | ||
|
|
||
| 3. **Alert in non-production manifest**: If the manifest path points to a test, script, or example directory (e.g., `scripts/`, `e2e/`, `testing/`, `replays/`), the dependency is not part of the production deployment. | ||
| - Dismiss reason: `not_used` | ||
| - Comment: "Dependency only used in [test/script/example] code, not in production." | ||
|
|
||
| ### Category: FIX | ||
|
|
||
| Fix the alert if ALL of the following are true: | ||
|
|
||
| 1. The dependency is a runtime dependency (`scope` is `runtime`) | ||
| 2. A `first_patched_version` exists | ||
| 3. The dependency is in a production manifest (not scripts/tests/examples) | ||
|
|
||
| ### Category: DEFER | ||
|
|
||
| Defer the alert if: | ||
|
|
||
| 1. It is a runtime dependency but no patched version is available yet | ||
| 2. The fix requires a major version bump that is likely to have breaking changes | ||
|
|
||
| Do not create any dismissal or PR for deferred alerts — they will be reported in the PR body for human review. | ||
|
|
||
| ## Step 3: Dismiss alerts | ||
|
|
||
| For each alert classified as DISMISS, call: | ||
|
|
||
| ``` | ||
| gh api --method PATCH "/repos/${GITHUB_REPOSITORY}/dependabot/alerts/<NUMBER>" \ | ||
| -f state=dismissed \ | ||
| -f dismissed_reason="<REASON>" \ | ||
| -f dismissed_comment="<COMMENT>" | ||
| ``` | ||
|
|
||
| Valid values for `dismissed_reason`: `fix_started`, `inaccurate`, `no_bandwidth`, `not_used`, `tolerable_risk`. | ||
|
|
||
| Track all dismissals for the final report. | ||
|
|
||
| ## Step 4: Setup the evergreen branch | ||
|
|
||
| Check if the evergreen branch already exists: | ||
|
|
||
| ``` | ||
| git fetch origin security/vuln-remediation 2>/dev/null || true | ||
| ``` | ||
|
|
||
| If the branch exists, check it out and reset it to main: | ||
|
|
||
| ``` | ||
| git checkout -B security/vuln-remediation origin/main | ||
| ``` | ||
|
|
||
| If it doesn't exist, create it from main: | ||
|
|
||
| ``` | ||
| git checkout -b security/vuln-remediation | ||
| ``` | ||
|
|
||
| ## Step 5: Fix vulnerabilities | ||
|
|
||
| For each alert classified as FIX, grouped by manifest file: | ||
|
|
||
| ### Go dependencies (`go.mod`) | ||
|
|
||
| From the directory containing the `go.mod` file: | ||
|
|
||
| ``` | ||
| go get <package>@v<patched_version> | ||
| go mod tidy | ||
| ``` | ||
|
|
||
| If `go get` with the exact patched version fails, try `@latest`: | ||
|
|
||
| ``` | ||
| go get <package>@latest | ||
| go mod tidy | ||
| ``` | ||
|
|
||
| ### npm dependencies (`package.json` or `package-lock.json` or `pnpm-lock.yaml`) | ||
|
|
||
| From the directory containing the manifest: | ||
|
|
||
| If `package.json` lists the dependency directly, update the version constraint and run `bun install`. | ||
|
|
||
| If the vulnerability is in a lockfile-only transitive dependency, run: | ||
|
|
||
| ``` | ||
| bun update <package> | ||
| ``` | ||
|
|
||
| ### Python dependencies (`pyproject.toml` or `requirements.txt`) | ||
|
|
||
| From the directory containing the manifest: | ||
|
|
||
| Edit the version constraint in `pyproject.toml` or `requirements.txt`, then: | ||
|
|
||
| ``` | ||
| uv sync | ||
| ``` | ||
|
|
||
| Or if uv is not available: | ||
|
|
||
| ``` | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| ## Step 6: Verify the build | ||
|
|
||
| For each directory containing a modified manifest file, verify the build still works: | ||
|
|
||
| 1. Check if a Makefile exists with a `build` target — if so, run `make build` | ||
| 2. Otherwise, for Go: `go build ./...` | ||
| 3. For Node/Bun: `bun run build` (if a build script exists) | ||
|
|
||
| All builds must succeed. If a build fails due to a specific dependency upgrade: | ||
|
|
||
| 1. Revert that dependency change: `git checkout -- <manifest-file> <lockfile>` | ||
| 2. Re-run `go mod tidy` or `bun install` to restore the previous state | ||
| 3. Move the alert from FIX to DEFER | ||
| 4. Continue with the next dependency | ||
|
|
||
| ## Step 7: Run tests | ||
|
|
||
| For each directory containing a modified manifest file: | ||
|
|
||
| 1. Check if a Makefile exists with a `test` target — if so, run `make test` | ||
| 2. Otherwise, for Go: `go test ./...` | ||
| 3. For Node/Bun: `bun test` (if a test script exists) | ||
|
|
||
| If tests fail due to a specific dependency upgrade: | ||
|
|
||
| 1. Analyze if the failure is related to the upgrade or a flaky test | ||
| 2. If related to the upgrade, revert that dependency and move the alert to DEFER | ||
| 3. If the test is flaky/unrelated, note it and proceed | ||
|
|
||
| ## Step 8: Format code | ||
|
|
||
| Run `bun run format` to ensure all code is properly formatted before committing. | ||
|
|
||
| ## Step 9: Create or update the evergreen PR | ||
|
|
||
| If any fixes were applied and builds/tests pass: | ||
|
|
||
| 1. Commit all changes with message: `security: vulnerability remediation (${DATE})` | ||
| Include in the commit body a list of what was fixed. | ||
|
|
||
| 2. Force push the branch: `git push -f origin security/vuln-remediation` | ||
|
|
||
| 3. Check if a PR already exists: | ||
| ``` | ||
| gh pr list --head security/vuln-remediation --state open --json number | ||
| ``` | ||
|
|
||
| 4. Build the PR body with this structure: | ||
|
|
||
| ``` | ||
| ## Vulnerability Remediation — ${DATE} | ||
|
|
||
| ### Fixed | ||
| | CVE | Package | Severity | Old Version | New Version | Manifest | | ||
| |-----|---------|----------|-------------|-------------|----------| | ||
| | ... | ... | ... | ... | ... | ... | | ||
|
|
||
| ### Dismissed | ||
| | CVE | Package | Severity | Reason | Comment | | ||
| |-----|---------|----------|--------|---------| | ||
| | ... | ... | ... | ... | ... | | ||
|
|
||
| ### Deferred (needs human review) | ||
| | CVE | Package | Severity | Why | | ||
| |-----|---------|----------|-----| | ||
| | ... | ... | ... | ... | | ||
| ``` | ||
|
|
||
| 5. If a PR exists, update its body with the new report. | ||
|
|
||
| 6. If no PR exists, create one with: | ||
| - Title: `security: vulnerability remediation` | ||
| - Body: the report above | ||
|
|
||
| 7. Find a reviewer: Use `gh pr list --state merged --limit 20 --json author` to identify users who have recently authored merged PRs, then assign one randomly using `gh pr edit <pr-number> --add-assignee <username>` | ||
|
|
||
| If no fixes were applied but dismissals or deferrals were made, still post a summary as a PR comment or issue comment so there is a record. | ||
|
|
||
| # Constraints | ||
|
|
||
| - Process at most 10 alerts per run (prioritize by severity: critical > high > medium > low) | ||
| - Only dismiss alerts with documented reasons — never silently skip | ||
| - All builds AND tests must pass before the PR is created | ||
| - Use the evergreen branch `security/vuln-remediation` — always reset it to main before making changes | ||
| - Never force-push or modify `main` directly | ||
| - If no actionable alerts remain after triage, exit without creating/updating the PR | ||
| - Be conservative: when in doubt, classify as DEFER rather than DISMISS | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| name: Vulnerability Remediation | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: '0 3 * * 3' | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: write | ||
| pull-requests: write | ||
|
|
||
| jobs: | ||
| remediate: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Generate app token | ||
| id: app-token | ||
| uses: actions/create-github-app-token@v1 | ||
| with: | ||
| app-id: ${{ secrets.ADMIN_APP_ID }} | ||
| private-key: ${{ secrets.ADMIN_APP_PRIVATE_KEY }} | ||
|
|
||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ steps.app-token.outputs.token }} | ||
|
|
||
| - name: Install Cursor CLI | ||
| run: | | ||
| curl https://cursor.com/install -fsS | bash | ||
| echo "$HOME/.cursor/bin" >> $GITHUB_PATH | ||
|
|
||
| - name: Configure git identity | ||
| run: | | ||
| git config user.name "kernel-internal[bot]" | ||
| git config user.email "260533166+kernel-internal[bot]@users.noreply.github.com" | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version-file: 'server/go.mod' | ||
|
|
||
| - name: Fetch Dependabot alerts | ||
| env: | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| run: | | ||
| gh api "/repos/${{ github.repository }}/dependabot/alerts?state=open&per_page=100" > dependabot-alerts.json 2>/dev/null || echo "[]" > dependabot-alerts.json | ||
|
|
||
| - name: Remediate vulnerabilities | ||
| env: | ||
| CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| run: | | ||
| export DATE="$(date -u +%Y-%m-%d)" | ||
| envsubst '${GITHUB_REPOSITORY} ${DATE}' < .github/workflows/vuln-remediation-prompt.md | agent -p --model ${{ secrets.CURSOR_PREFERRED_MODEL }} --trust --force --output-format=text |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prompt references
buncommands but Bun is not installedMedium Severity
The prompt instructs the AI agent to run
bun install,bun update,bun run build,bun test, andbun run format, but the workflow YAML does not install Bun. The PR description says Bun setup was intentionally omitted, and the repo's other CI workflows usepnpminstead. Step 8 unconditionally tells the agent to runbun run format(not gated on npm deps), which will always fail. The npm dependency instructions in Step 5, Step 6, and Step 7 also referencebunand will fail if triggered.Additional Locations (2)
.github/workflows/vuln-remediation-prompt.md#L130-L141.github/workflows/vuln-remediation-prompt.md#L162-L171