-
Notifications
You must be signed in to change notification settings - Fork 46
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
base: main
Are you sure you want to change the base?
Changes from all commits
607eac6
e32a067
013b2ab
136fa85
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| 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. The Socket CLI is available as `socket` and authenticated via SOCKET_SECURITY_API_KEY. | ||
|
|
||
| # Context | ||
|
|
||
| - Repo: ${GITHUB_REPOSITORY} | ||
| - Date: ${DATE} | ||
|
|
||
| # Goal | ||
|
|
||
| Process vulnerability alerts from a Socket.dev scan report for this repository. For each alert, either fix the vulnerability by upgrading the dependency or log the decision with a 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 `socket-report.json` in the current directory. This file contains the Socket scan report JSON. | ||
|
|
||
| If the report shows `"healthy": true` and the `alerts` map is empty, output "No vulnerability alerts. Scan is healthy." and exit. | ||
|
|
||
| The Socket report nests alerts by ecosystem, package, version, file, and location. Flatten these into a list of unique alerts. For each alert, extract: | ||
| - Alert type (e.g., `cve`, `installScripts`, `networkAccess`, `envVars`, etc.) | ||
| - Severity: `error`, `warn`, `monitor`, `ignore` | ||
| - Package name and version | ||
| - Ecosystem (npm, go, pypi, etc.) | ||
| - Description / summary if available | ||
| - CVE ID if the alert type is `cve` | ||
|
|
||
| If `socket-report.json` is missing or unparseable, fall back to running a fresh scan: | ||
|
|
||
| ``` | ||
| socket scan create --repo=<repo-name> --branch=main --report --json --fold=version > socket-report.json | ||
| ``` | ||
|
|
||
| ## Step 2: Triage alerts (Manager phase) | ||
|
|
||
| Focus only on alerts with severity `error` or `warn`. Ignore `monitor` and `ignore` level alerts. | ||
|
|
||
| For each alert, classify it into one of three categories. Process alerts in priority order: `error` first, then `warn`. | ||
|
|
||
| ### Category: DISMISS | ||
|
|
||
| Skip the alert if ANY of the following are true: | ||
|
|
||
| 1. **Non-CVE behavioral alert**: Alert types like `installScripts`, `networkAccess`, `envVars`, `shellAccess`, `filesystemAccess` are informational supply chain signals. Log them but do not attempt to fix. These are useful for awareness but not actionable via dependency bumps. | ||
|
|
||
| 2. **Development-only dependency**: If the package appears only in dev dependency sections (devDependencies in package.json, test files in go.mod). These are not deployed to production. | ||
|
|
||
| 3. **Unreachable vulnerable code (Go only)**: For Go dependencies, check if the vulnerable package's symbols are actually imported and called: | ||
| ``` | ||
| grep -r '<package-import-path>' --include='*.go' -l | ||
| ``` | ||
| If the package is not imported, or only imported in test files (`_test.go`), skip it. | ||
|
|
||
| 4. **Alert in non-production manifest**: If the manifest path points to a test, script, or example directory (e.g., `scripts/`, `e2e/`, `testing/`, `replays/`, `shared/cdp-test/`), the dependency is not part of the production deployment. | ||
|
|
||
| ### Category: FIX | ||
|
|
||
| Fix the alert if ALL of the following are true: | ||
|
|
||
| 1. The alert type is `cve` (a known vulnerability with a CVE ID) | ||
| 2. The dependency is a runtime/production dependency | ||
| 3. A newer version of the package exists that resolves the CVE | ||
| 4. The dependency is in a production manifest | ||
|
|
||
| ### Category: DEFER | ||
|
|
||
| Defer the alert if: | ||
|
|
||
| 1. It is a CVE in 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 attempt fixes for deferred alerts — they will be reported in the PR body for human review. | ||
|
|
||
| ## Step 3: 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 4: 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>@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 5: 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 6: 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 7: Format code | ||
|
|
||
| Run `bun run format` to ensure all code is properly formatted before committing. | ||
|
|
||
| ## Step 8: 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 | | ||
| |-----|---------|----------|-------------|-------------|----------| | ||
| | ... | ... | ... | ... | ... | ... | | ||
|
|
||
| ### Skipped (non-actionable) | ||
| | Alert Type | Package | Severity | Reason | | ||
| |------------|---------|----------|--------| | ||
| | ... | ... | ... | ... | | ||
|
|
||
| ### 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 there are deferred items, still post a summary as a PR comment or issue so there is a record. | ||
|
|
||
| # Constraints | ||
|
|
||
| - Process at most 10 CVE alerts per run (prioritize by severity: error > warn) | ||
| - Only act on `cve` type alerts for fixes — behavioral alerts are informational only | ||
| - 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| 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: Install Socket CLI | ||
| run: npm install -g @socketsecurity/cli | ||
|
|
||
| - name: Run Socket scan | ||
| env: | ||
| SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_API_TOKEN }} | ||
| run: | | ||
| socket scan create --repo="${{ github.event.repository.name }}" --branch=main --default-branch --report --json > socket-report.json 2>/dev/null || echo '{"healthy":true,"alerts":{}}' > socket-report.json | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Socket scan failures silently produce fake healthy reportHigh Severity The socket scan command suppresses all stderr with |
||
|
|
||
| - name: Remediate vulnerabilities | ||
| env: | ||
| CURSOR_API_KEY: ${{ secrets.CURSOR_API_KEY }} | ||
| GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
| SOCKET_SECURITY_API_KEY: ${{ secrets.SOCKET_API_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 | ||


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