Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions .claude/skills/prisma-taurus/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,8 @@ Site / cloudId: `perforce.atlassian.net` = `2accdbdb-9d65-4c22-b174-5d4a9d437c59

**Before creating the PR — reconcile `vulnerability_history.md` on the SAME fix branch (so it ships in this PR, no separate PR):**

> ⚠️ **This file lives at the repo root, not under `.claude/`, on purpose.** Headless/`dontAsk` runs are denied Edit, Write, *and* Bash-based writes (redirects, `sed -i`, etc.) against anything under `.claude/` — a hard, tool-agnostic guardrail, confirmed empirically, that no `--allowed-tools`/`--add-dir` combination changes. It used to live at `.claude/skills/prisma-taurus/vulnerability_history.md`.

`vulnerability_history.md` is a **problem-solving reference, not a log of what happened.** Its job is to help a future run (a) fix similar vulnerabilities faster and (b) know when a temporary fix can be removed because a newer upstream version resolved the original CVE. Update it **in place** — improve the matching recipe or pattern; do **not** append a blow-by-blow "what happened today" entry.

At the end of every run, reconcile it for two things:
Expand All @@ -744,7 +746,7 @@ At the end of every run, reconcile it for two things:
If the run applied known recipes cleanly and there is no new lesson and nothing to prune, change nothing and go straight to the PR — don't pad the file. When there *is* something to record, commit it **on the fix branch** alongside the code fixes and push, so the doc update is part of this same PR rather than a separate one:
```bash
cd .worktrees/<branch-name> # or re-add the worktree on the fix branch if already removed
git add .claude/skills/prisma-taurus/vulnerability_history.md
git add vulnerability_history.md
git commit -m "Document <lesson> in prisma-taurus history"
git push origin <branch-name>
```
Expand All @@ -769,20 +771,22 @@ gh pr create --repo Blazemeter/taurus --base master \
If `gh` is not on PATH, create via the GitHub API using `$GITHUB_TOKEN` (`POST /repos/Blazemeter/taurus/pulls`).

**15b — request GitHub Copilot's review (best-effort; must NEVER fail the run):**
> ⚠️ **Call the REST endpoint directly — do not call `gh pr edit --add-reviewer @copilot` at all.** It routes through GraphQL, which is a confirmed, known no-op for bot logins (Copilot is a bot, not a user): it returns **exit 0 while silently attaching nothing** (verified directly on a real PR — twice). Since it never reports failure, there's no way to gate the REST call on its result — and keeping it as an earlier statement in the same script is actively worse than useless: if the shell has `set -e` (or any other exit-on-error behavior) active and that call happens to genuinely fail for an unrelated reason (auth blip, rate limit), it aborts the script before the REST call below ever runs. It buys nothing (REST is the confirmed-working path for bot reviewers) and risks everything. Skip it:
```bash
# so the maintainer doesn't have to click "Request review" on the site.
# Any failure here is fine — the PR from 15a already exists.
if ! command -v gh >/dev/null 2>&1; then
echo "gh not installed — skipping Copilot reviewer request (PR already created; request it manually if wanted)"
else
gh pr edit <pr-number-or-url> --repo Blazemeter/taurus --add-reviewer @copilot 2>/dev/null \
|| gh api repos/Blazemeter/taurus/pulls/<number>/requested_reviewers \
-f 'reviewers[]=copilot-pull-request-reviewer[bot]' 2>/dev/null \
|| echo "Copilot reviewer not added (needs gh >= 2.88.0 and Copilot code review enabled) — PR created regardless; request it manually if wanted"
gh api repos/Blazemeter/taurus/pulls/<number>/requested_reviewers \
-f 'reviewers[]=copilot-pull-request-reviewer[bot]' 2>/dev/null \
|| echo "Copilot reviewer request failed outright (needs gh >= 2.88.0) — PR created regardless; request it manually if wanted"
Comment thread
henrychv marked this conversation as resolved.
fi
```
Keeping 15b separate is deliberate: a bad `--reviewer` on `gh pr create` can fail the *whole* create call and leave no PR. By creating first and requesting Copilot after, the PR is guaranteed and the Copilot request is a harmless add-on. (This is GitHub Copilot's own PR review — separate from and in addition to the step-12 local pre-push review.) Never block or error the run because Copilot couldn't be added.

> ⚠️ **Do not verify attachment immediately either — that's a second, separate trap.** Even the REST call above can return `201 Created` while `requested_reviewers` still reads empty moments later (verified directly), because Copilot's actual review can take a long time to start (observed: ~2h from request to a submitted review, on a sibling repo's PR) — not the ~5 minutes step 16a budgets for. An empty `requested_reviewers`/no-review-yet check right after 15b proves nothing either way; step 16a's own bounded poll (and its cap-elapsed handling) is the only place that's allowed to conclude anything about whether Copilot reviewed.

PR body should include (apply the step-5 reporting rule — **lead with fixable-detected/fixed, not the raw total**):
- **Jira:** `<MOB-XXXXX>` (the ticket created above).
- **Headline first — Fixable in taurus, this run: `<X>` detected → `<Y>` fixed.** Distinct CVEs; count only this repo's own `Dockerfile` / `requirements.txt` fixes confirmed gone in the branch scan. This is the opening line — do **not** open with the raw total or any JMeter/Gatling count. If `Y < X`, list which didn't land and why. Add `**Rebuild-clearable: <R>**` when `R > 0`, noting these need no code change and clear on the next master build (labeled subset of `X − Y`, never an extra count).
Expand Down Expand Up @@ -1087,7 +1091,7 @@ For each vulnerability, look up sources in this order:
| Prisma Cloud console (master job's scan lands here) | `https://us-west1.cloud.twistlock.com/us-4-161024623` → Monitor → Vulnerabilities → Images → CI |
| Docker Hub unstable tag | `https://hub.docker.com/v2/repositories/blazemeter/taurus/tags/unstable` |
| .NET 8.0 release metadata | `https://dotnetcli.azureedge.net/dotnet/release-metadata/8.0/releases.json` |
| Vulnerability fix history | `vulnerability_history.md` (in this skill's folder) — consult this before fixing any CVE |
| Vulnerability fix history | `vulnerability_history.md` (repo root, not `.claude/` — see the reconciliation step before the PR) — consult this before fixing any CVE |
Comment thread
henrychv marked this conversation as resolved.

## taurus-branch-builder parameters

Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python${PYTH
# layer-cached taurus-branch-builder build the earlier install layer can be reused while this layer
# re-resolves, so the entry is what actually applies the update. Keep them; just don't add a new
# entry for a package on that basis alone (prove provenance first -- see the OS-provenance rule in
# .claude/skills/prisma-taurus/vulnerability_history.md).
# vulnerability_history.md, repo root).
# (--only-upgrade never installs new packages; absent ones are skipped -- so a wrong/renamed name
# fails silently. Verify with `apt-cache policy <pkg>` in the image before adding one.)
# These entries are unpinned and self-maintaining: each resolves to the pocket's current version at
# build time, which also picks up security updates published AFTER the base image tag was built.
# Do NOT prune an entry merely because the base image caught up -- that trades away the forward
# protection for no benefit. See .claude/skills/prisma-taurus/vulnerability_history.md (pruning note).
# protection for no benefit. See vulnerability_history.md (repo root; pruning note).
RUN apt-get update && \
apt-get install -y --no-install-recommends --only-upgrade \
libgnutls30t64 \
Expand Down Expand Up @@ -251,7 +251,7 @@ RUN update-alternatives --install /usr/local/bin/ruby ruby ${RBENV_ROOT}/shims/r
# recipe deleted it, which silenced Prisma but ALSO de-registered the feature, so `require` fell back
# to Ruby's own stdlib copy and the VULNERABLE code kept loading (measured in the published image:
# ERB.version 4.0.4 / JSON::VERSION 2.9.1 despite patched gems being installed). That is scanner
# appeasement, not a fix -- see .claude/skills/prisma-taurus/vulnerability_history.md,
# appeasement, not a fix -- see vulnerability_history.md (repo root),
# "When a Ruby gem has a CVE" step 3.
#
# Consequence, accepted deliberately: Prisma still reads the stale default gemspec and reports
Expand Down
6 changes: 3 additions & 3 deletions Jenkinsfile-vulnerability-ai
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ report the branch name, whether it is a normal fix branch or an R-only docs
branch, and a short summary, then stop."

if [ "$VERBOSE_OUTPUT" = "true" ]; then
{ claude --print --verbose --output-format stream-json --session-id "$CLAUDE_SESSION_ID" --model "$CLAUDE_MODEL" "$PROMPT" --permission-mode dontAsk --allowed-tools "Bash" "Read" "Write" "Edit" "Skill" "ToolSearch" "mcp__github__*" "mcp__claude_ai_Atlassian_Rovo__*"; echo $? > "$WORKSPACE/.claude_exit_code"; } | jq -r -f "$WORKSPACE/.claude/skills/prisma-taurus/scripts/verbose-progress.jq"
{ claude --print --verbose --output-format stream-json --session-id "$CLAUDE_SESSION_ID" --model "$CLAUDE_MODEL" "$PROMPT" --permission-mode dontAsk --allowed-tools "Bash" "Read" "Write" "Edit" "Skill" "ToolSearch" "mcp__github__*" "mcp__claude_ai_Atlassian_Rovo__*"; echo $? > "$WORKSPACE/.claude_exit_code"; } | jq --unbuffered -r -f "$WORKSPACE/.claude/skills/prisma-taurus/scripts/verbose-progress.jq"
claude_status=$(cat "$WORKSPACE/.claude_exit_code")
rm -f "$WORKSPACE/.claude_exit_code"
exit "$claude_status"
Expand Down Expand Up @@ -270,7 +270,7 @@ the PR, and the Copilot review. Stop after step 16 - do NOT post to Slack
this invocation; a later invocation handles those with its own credentials."

if [ "$VERBOSE_OUTPUT" = "true" ]; then
{ claude --print --verbose --output-format stream-json --resume "$CLAUDE_SESSION_ID" --model "$CLAUDE_MODEL" "$PROMPT" --permission-mode dontAsk --allowed-tools "Bash" "Read" "Write" "Edit" "Skill" "ToolSearch" "mcp__github__*" "mcp__claude_ai_Atlassian_Rovo__*"; echo $? > "$WORKSPACE/.claude_exit_code"; } | jq -r -f "$WORKSPACE/.claude/skills/prisma-taurus/scripts/verbose-progress.jq"
{ claude --print --verbose --output-format stream-json --resume "$CLAUDE_SESSION_ID" --model "$CLAUDE_MODEL" "$PROMPT" --permission-mode dontAsk --allowed-tools "Bash" "Read" "Write" "Edit" "Skill" "ToolSearch" "mcp__github__*" "mcp__claude_ai_Atlassian_Rovo__*"; echo $? > "$WORKSPACE/.claude_exit_code"; } | jq --unbuffered -r -f "$WORKSPACE/.claude/skills/prisma-taurus/scripts/verbose-progress.jq"
claude_status=$(cat "$WORKSPACE/.claude_exit_code")
rm -f "$WORKSPACE/.claude_exit_code"
exit "$claude_status"
Expand Down Expand Up @@ -323,7 +323,7 @@ nothing further to do, step 17 still applies (it covers the no-PR case) -
do not skip straight to a bare final summary without it."

if [ "$VERBOSE_OUTPUT" = "true" ]; then
{ claude --print --verbose --output-format stream-json --resume "$CLAUDE_SESSION_ID" --model "$CLAUDE_MODEL" "$PROMPT" --permission-mode dontAsk --allowed-tools "Bash" "Read" "Skill" "ToolSearch"; echo $? > "$WORKSPACE/.claude_exit_code"; } | jq -r -f "$WORKSPACE/.claude/skills/prisma-taurus/scripts/verbose-progress.jq"
{ claude --print --verbose --output-format stream-json --resume "$CLAUDE_SESSION_ID" --model "$CLAUDE_MODEL" "$PROMPT" --permission-mode dontAsk --allowed-tools "Bash" "Read" "Skill" "ToolSearch"; echo $? > "$WORKSPACE/.claude_exit_code"; } | jq --unbuffered -r -f "$WORKSPACE/.claude/skills/prisma-taurus/scripts/verbose-progress.jq"
claude_status=$(cat "$WORKSPACE/.claude_exit_code")
rm -f "$WORKSPACE/.claude_exit_code"
exit "$claude_status"
Expand Down
File renamed without changes.
Loading