Agent skill

Create Fix PR

by openshift-eng in openshift-eng/ai-helpers

A skill your agent uses when opening or updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally.

Apache-2.0Auto-check passedSecurity

Install Create Fix PR

skills CLI
$ npx skills add openshift-eng/ai-helpers --skill create-fix-pr -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install openshift-eng/ai-helpers create-fix-pr --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/openshift-eng/ai-helpers.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/compliance/skills/create-fix-pr .claude/skills/create-fix-pr && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
create-fix-pr
GitHub stars
120
Token cost
~6.2k tokens
SKILL.md length
2,601 words
Files
1
Skills in repo
118
Repo updated
First seen
Licence
Apache-2.0

At a glance

A skill your agent uses when opening or updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally.

  • Updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally
  • SKILL.md covers When to Use This Skill, Required Inputs, Prerequisites and Fork Mode (FORK_ORG set), plus 9 more sections
  • Calls git, gh and jq; reaches github.com and cli.github.com
  • Tasks that involve Vulnerability scanning

What it does

Create Fix PR is an agent skill from openshift-eng/ai-helpers. Use when opening or updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally.

Its SKILL.md is about 6.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Security, covering Vulnerability scanning. It works with GitHub and Jira. The repository describes itself as: Developer productivity tools for Claude Code & other AI assistants. The licence is Apache-2.0.

When your agent uses it

  • Updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally
  • Tasks that involve Vulnerability scanning

Example prompts

  • “/create-fix-pr”

What it can do on your machine

Read from SKILL.md and the folder at commit a627176. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • git
    • gh
    • jq
    • go
    • make

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • github.com
    • cli.github.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Create Fix PR loads about 6.2k tokens when it runs. Until then it costs about 38 tokens; SKILL.md has 2,601 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~38
When it runs · the whole SKILL.md, loaded when a task matches
~6.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from openshift-eng/ai-helpers at commit a627176, republished under its Apache-2.0 licence (© openshift-eng). 2,601 words, ~6,244 tokens.

Download SKILL.mdSave it as .claude/skills/create-fix-pr/SKILL.md (or your agent's skills folder).
name
create-fix-pr
description
Use when opening or updating a GitHub pull request after Phase 5 of `/compliance:analyze-cve` has applied and verified a CVE fix locally.

Create Fix PR

Opens a GitHub pull request for the CVE fix already applied in REPO_DIR (Phase 5). Never commits, pushes, or opens a PR without explicit approval — interactive, or AUTO_APPROVE=yes recorded once upfront (see Autonomous Mode). Direct CVE mode (no --jira=/--jql=) still creates the PR; it just omits Jira Fixes: links and the Jira follow-up comment.

Called from Phase 6 of the analyze-cve skill after Phase 5 verification succeeds.


When to Use This Skill

Use this skill when:

  • Phase 5 applied a fix in REPO_DIR and verification passed
  • The user approved creating a GitHub PR
  • embargo_status is not True

Do not use this skill to apply the fix itself (that is Phase 5) or to post the analysis report (that is report-to-jira in Phase 4).


Required Inputs

From the parent command:

InputSourceRequired
REPO_DIRPhase 0.7Yes
GIT_BRANCHPhase 0.7 (mapped release branch, e.g. release-4.17)Yes
REPO_URLPhase 0.7Yes
CVE_IDPhase 0.5 / direct CVE modeYes
SOURCE_TICKET--jira= / --jql=No
AUTO_APPROVEPhase 0 (--auto-approve, default no)Yes
FORK_ORGCaller environment (e.g. CI/RWS runner)No — enables Fork Mode when set
PHASE5_FILESPhase 5 allowlist (incl. untracked)Yes
Module path, old version, new versionPhase 4 / 5Yes if a dependency bump
Short CVE descriptionPhase 1Recommended
Phase 5 change summaryPhase 5 "Document Changes"Yes

Prerequisites

Hard requirements for this skill. Phase 0 does not treat gh as required (warn-only). This skill must not assume either tool is present — re-check both, then fail if either is missing. Do not create a PR another way.

bash
which git 2>/dev/null || echo "MISSING: git"
which gh 2>/dev/null || echo "MISSING: gh"
gh auth status 2>/dev/null || echo "MISSING: gh auth"
  • IF git is missing → print install instructions and return status: failed (git_missing). Stop. Do not commit or push.
  • IF gh is missing → print install instructions (https://cli.github.com/) and return status: failed (gh_missing). Stop. Do not commit or push.
  • IF gh auth status fails → print gh auth login instructions and return status: failed (gh_unauthenticated). Stop. Do not commit or push.
  • Do not print token or login output that contains credentials.

Credential rule: Never print, echo, or log tokens, PATs, or gh auth output that contains credentials. Reference credentials only via environment variable names.


Fork Mode (FORK_ORG set)

By default (no FORK_ORG) this skill pushes the fix branch directly to the cloned repo's own origin and opens a same-repo branch→base PR. That requires the authenticated gh/git identity to have direct write access to every upstream repo image-repo-mapping might resolve to (e.g. openshift/cert-manager-operator, openshift/cert-manager, openshift/secrets-store-csi-driver-operator, ...). In an unattended CI/RWS runner that isn't a collaborator on all of those repos, that's the wrong default.

IF the environment variable FORK_ORG is set (e.g. a bot-owned org), push to a fork under that org instead and open a cross-repo PR — mirrors the fork/upstream model used elsewhere for automated OpenShift PRs. This section only changes where the branch is pushed and how the PR's --head is specified; Step 0 (safety gates), Step 1 (org/repo/base-branch resolution from origin), Step 2 (conflicting-PR detection), and Step 3b (commit, allowlist validation) are unchanged and still operate against REPO_DIR/ORG/REPO/BASE_BRANCH resolved from origin.

Resolve the fork repo
bash
FORK_REPO="${FORK_ORG}/${REPO}"   # REPO = repo name parsed from origin in Step 1, e.g. "cert-manager-operator"
Ensure the fork exists and is actually a fork of this repo

Never assume a repo at ${FORK_REPO} is the right push target just because the name matches — verify its fork lineage first. Reusing an unrelated (or unexpectedly renamed/transferred) repo that happens to occupy that name would push the fix branch and open a PR from somewhere unintended.

bash
if FORK_JSON=$(gh repo view "${FORK_REPO}" --json isFork,parent 2>/dev/null); then
  IS_FORK=$(echo "$FORK_JSON" | jq -r '.isFork')
  PARENT_FULL_NAME=$(echo "$FORK_JSON" | jq -r '.parent.fullName // empty')
else
  IS_FORK=""
  PARENT_FULL_NAME=""
fi
  • IF ${FORK_REPO} exists (the gh repo view above succeeded) and (IS_FORK is not exactly true or PARENT_FULL_NAME is not exactly ${ORG}/${REPO}) → stop immediately, do not add the fork remote or push anything, and return status: failed (fork_wrong_lineage).
  • IF ${FORK_REPO} exists and lineage matches → skip fork creation below, continue to Step 3a.
  • IF ${FORK_REPO} does not exist → create it:
bash
gh repo fork "${ORG}/${REPO}" --org "${FORK_ORG}" --remote=false --clone=false --default-branch-only=false
FORK_CREATE_EXIT=$?
  • IF FORK_CREATE_EXIT is non-zero → stop immediately and return status: failed (fork_create_failed). Do not poll, do not add the fork remote, do not push — the create call already reported failure, so there is nothing to wait for.
  • IF FORK_CREATE_EXIT is 0 → the fork was accepted; poll briefly, since GitHub creates forks asynchronously:
bash
for i in $(seq 1 10); do
  gh repo view "${FORK_REPO}" >/dev/null 2>&1 && break
  sleep 3
done
  • IF the fork still doesn't exist after polling → return status: failed (fork_create_failed). Do not fall back to pushing to origin — that would silently switch to requiring direct upstream write access, which is exactly what FORK_ORG was set to avoid.
3a (fork mode). Branch — same as default mode

Branch creation/naming is identical to the non-fork case below (BRANCH_NAME derived from CVE_ID/SOURCE_TICKET, checked out from BASE_BRANCH).

3c (fork mode). Push to the fork, not origin
bash
git -C "${REPO_DIR}" remote add fork "https://github.com/${FORK_REPO}.git" 2>/dev/null \
  || git -C "${REPO_DIR}" remote set-url fork "https://github.com/${FORK_REPO}.git"

# Keep the fork in sync with the upstream base branch before pushing a branch built on top of it,
# so the PR diff is just this fix — not a stale-fork drift diff.
git -C "${REPO_DIR}" fetch origin "${BASE_BRANCH}"
git -C "${REPO_DIR}" push fork "refs/remotes/origin/${BASE_BRANCH}:refs/heads/${BASE_BRANCH}" --force-with-lease 2>/dev/null || true

git -C "${REPO_DIR}" push -u fork "${BRANCH_NAME}"

Never force-push ${BASE_BRANCH} on origin (the upstream repo) — the force-with-lease sync above only ever targets the fork remote's copy of that branch name, never origin.

Step 4 (fork mode). Create the PR across fork → upstream

Do not use gh pr create --head "${FORK_ORG}:${BRANCH_NAME}". gh pr create --head only supports a user-owned head repo via the owner:branch syntax — per gh pr create --help: "Using an organization as the owner is currently not supported" (tracked at cli/cli#10093). Since FORK_ORG may be a GitHub organization, use the REST API's head_repo parameter instead (via gh api), which unambiguously names the head repository regardless of whether FORK_ORG is a user or an org:

bash
printf '%s' "${PR_BODY}" > "${WORK_CVE}/pr-body.md"

PR_URL=$(gh api \
  "repos/${ORG}/${REPO}/pulls" \
  -f head_repo="${FORK_REPO}" \
  -f head="${BRANCH_NAME}" \
  -f base="${BASE_BRANCH}" \
  -f title="${PR_TITLE}" \
  -F body=@"${WORK_CVE}/pr-body.md" \
  --jq '.html_url')

head is the bare branch name here (no owner: prefix) — disambiguation comes entirely from the separate head_repo field, so this works whether FORK_ORG/FORK_REPO is user- or org-owned. Everything else (title/body construction, stacked-PR update path) is unchanged; PR_URL is captured directly from the API response instead of gh pr create's output.

Auth note

gh auth status in Prerequisites must reflect a token with public_repo (classic PAT) or equivalent fork/push/PR scope on ${FORK_ORG} and PR-creation scope against the upstream repo — this is set up by the caller before this skill runs (not part of this skill). Never echo the token itself.


Step 0: Safety Gates

  1. IF embargo_status = True → abort immediately. Do not commit, push, create a PR, or mention ticket contents.

  2. IF Phase 5 did not complete successfully → return status: skipped (phase5_incomplete).

  3. Confirm there are local changes to commit:

    bash
    git -C "${REPO_DIR}" status --porcelain
    git -C "${REPO_DIR}" diff --stat
    • IF working tree is clean and HEAD is already on a fix branch with the Phase 5 remediation committed (dependency bump, source, or config) → validate that branch's changes against PHASE5_FILES (see the check in Step 3b) before skipping to Step 4. A clean worktree only means nothing is uncommitted; it does not prove the existing commit(s) contain only Phase 5 paths. IF the branch diff vs ${BASE_BRANCH} contains paths outside PHASE5_FILES → always return status: failed (phase5_files_mismatch) immediately. Never gated by AUTO_APPROVE and never prompt.
    • IF working tree is clean and HEAD is still ${GIT_BRANCH} with no Phase 5 commit → return status: skipped (no_local_changes).
  4. IF AUTO_APPROVE=no (and the parent hasn't already recorded a yes) → Ask:

    Phase 5 applied the fix locally. Create a GitHub PR against <GIT_BRANCH>?
    • IF no → return status: skipped (user_declined). Leave the working tree as-is.
    • IF yes → continue. Still do not commit until Step 3.

    IF AUTO_APPROVE=yes → treat as yes, skip the prompt, continue. Still do not commit until Step 3.


Step 1: Resolve GitHub Repo and Base Branch

bash
git -C "${REPO_DIR}" remote get-url origin

Parse ORG/REPO from the origin URL (github.com/openshift/hypershift.git → openshift/hypershift). If origin is SSH (git@github.com:org/repo.git), parse the same way.

BASE_BRANCH = GIT_BRANCH from Phase 0.7 (the mapped release branch the clone is on). Do not open the PR against main unless that is actually GIT_BRANCH.


Step 2: Detect Conflicting Open PRs

Title match only. Do not inspect PR files, body, module versions, or go.mod diffs.

bash
gh pr list --repo "${ORG}/${REPO}" --state open --base "${BASE_BRANCH}" \
  --json number,title,url,headRefName,author

A PR is a match if its title contains (case-insensitive) either this CVE_ID, or SOURCE_TICKET (when set).

IF none → continue to Step 3 with strategy new.

IF any match:

  • AUTO_APPROVE=no → present the list and wait for the user:

    text
    Open PR(s) on <ORG/REPO> base <BASE_BRANCH> already have this CVE/Jira in the title:
    
      #<N>  <title>  <url>  head=<branch>
    
    How should I proceed?
      1. stack     — check out that PR branch, commit this fix on top, push (PR updates)
      2. wait      — stop; do not open a competing PR
      3. independent — new branch from <BASE_BRANCH> (may need rebase later)
    ChoiceAction
    stackgit fetch origin <headRefName> && git checkout <headRefName> && git pull. Re-apply leftover Phase 5 changes if they are not already on that branch (same method as Phase 5 — bump, patch, or config edit). Strategy = stack.
    waitReturn status: skipped (user_wait_for_pr) including the existing PR URL.
    independentWarn that a second PR on the same base may need rebase later. If go.mod is in this diff, mention possible module-file conflicts. Strategy = new.
    No answerDo not guess. Ask again.
  • AUTO_APPROVE=yes → always wait, automatically, with no exceptions: return status: skipped (user_wait_for_pr_auto) including the existing PR URL. Never auto-choose stack (that pushes commits onto a branch nobody reviewed for this run) or independent (that opens a second, possibly duplicate/conflicting PR) unattended. Log clearly that this run stopped because of the existing PR, so a human can revisit with --auto-approve=no if a different resolution is actually wanted.


Step 3: Branch, Commit, Push

Work only inside REPO_DIR.

Vendor: Phase 5 already ran go mod vendor/make vendor (if applicable) and included any resulting paths in PHASE5_FILES before verification. Do not run vendor sync here — doing so after PHASE5_FILES was written would generate paths that never make it into the allowlist and get silently dropped from the commit. IF a dependency bump is present in PHASE5_FILES but vendor/ looks out of sync (e.g. go mod vendor reports diffs) → stop and tell the user to re-run Phase 5, rather than fixing it here.

3a. Branch

New PR (strategy = new):

bash
git -C "${REPO_DIR}" fetch origin "${BASE_BRANCH}"
git -C "${REPO_DIR}" checkout "${BASE_BRANCH}"
git -C "${REPO_DIR}" pull --ff-only origin "${BASE_BRANCH}"

SLUG="$(echo "${CVE_ID}" | tr '[:upper:]' '[:lower:]')"
if [ -n "${SOURCE_TICKET}" ]; then
  BRANCH_NAME="fix/${SLUG}-$(echo "${SOURCE_TICKET}" | tr '[:upper:]' '[:lower:]')"
else
  BRANCH_NAME="fix/${SLUG}"
fi

git -C "${REPO_DIR}" checkout -b "${BRANCH_NAME}"

Re-apply the Phase 5 changes on this branch if checking out BASE_BRANCH discarded uncommitted work. Prefer not discarding: stash before checkout if the working tree is dirty, then stash pop onto BRANCH_NAME.

Stack (strategy = stack): already on the existing PR branch. Set BRANCH_NAME to that head ref. Do not create a new branch.

Show full SKILL.md (1,057 more words)Show less
3b. Commit

Stage only PHASE5_FILES, not the whole worktree. That allowlist is written in Phase 5 (phase5-files.txt) and includes new untracked files. go.mod, go.sum, go.work, and vendor/ are common for dependency version bumps, but other CVE remediations may only touch source, config, Dockerfiles, or scripts.

WORK_CVE is in the command's own workspace (.work/), not inside REPO_DIR. Paths in the allowlist are relative to REPO_DIR.

bash
WORK_CVE="${AI_HELPERS_WORKSPACE:-.}/.work/compliance/analyze-cve/${CVE_ID}"
PHASE5_FILES="${WORK_CVE}/phase5-files.txt"

IF phase5-files.txt is missing or empty → rebuild it from Phase 5 "Document Changes" (and phase5-before.status if present). IF the allowlist still cannot be determined → always return status: failed (phase5_files_missing) immediately. Never gated by AUTO_APPROVE and never prompt. Do not fall back to whole-worktree git diff / git add -A / git add . in any case.

bash
# inspect current tree for sanity, but do not use it as the stage set
git -C "${REPO_DIR}" status --porcelain

while IFS= read -r f; do
  [ -n "${f}" ] || continue
  git -C "${REPO_DIR}" add -- "${f}"
done < "${PHASE5_FILES}"

git add -- <path> stages modifications, deletions, and untracked files. Examples of what belongs on the allowlist:

  • Dependency bump: go.mod, go.sum, and go.work / vendor/ only if Phase 5 changed them
  • Code/config fix: the source or config files Phase 5 added or edited
  • Mixed: the union of those paths

Do not add .work/, analysis reports, or credentials. Do not add pre-existing dirty files that are absent from PHASE5_FILES. Do not git add go.mod / vendor/ unless they are on the allowlist.

Validate the staged set exactly matches the allowlist. The loop above only adds allowlisted paths — it does not prove the index is free of anything else (e.g. leftover pre-existing staged files). Diff the two sets and reject extras instead of committing them silently:

bash
git -C "${REPO_DIR}" diff --cached --name-only > "${WORK_CVE}/staged-files.txt"

EXTRA="$(comm -23 <(sort "${WORK_CVE}/staged-files.txt") <(sort "${PHASE5_FILES}"))"
if [ -n "${EXTRA}" ]; then
  echo "Unstaging paths not in PHASE5_FILES:"
  echo "${EXTRA}"
  while IFS= read -r x; do
    [ -n "${x}" ] || continue
    git -C "${REPO_DIR}" restore --staged -- "${x}"
  done <<< "${EXTRA}"
fi

MISSING="$(comm -23 <(sort "${PHASE5_FILES}") <(sort "${WORK_CVE}/staged-files.txt"))"
if [ -n "${MISSING}" ]; then
  echo "ERROR: PHASE5_FILES paths missing from the staged set:"
  echo "${MISSING}"
  exit 1   # return status: failed (phase5_files_incomplete)
fi

IF any path was rejected → tell the user which paths were unstaged and why before continuing. Re-run the diff after unstaging to confirm the index now matches PHASE5_FILES exactly (accounting for deletions).

On a stack branch, or when Step 0 skipped ahead because a Phase 5 commit already existed, run the equivalent check against the branch, not just the index:

bash
git -C "${REPO_DIR}" diff --name-only "${BASE_BRANCH}...HEAD" > "${WORK_CVE}/branch-files.txt"
comm -23 <(sort "${WORK_CVE}/branch-files.txt") <(sort "${PHASE5_FILES}")

IF that reports any path outside PHASE5_FILES → stop; do not push or open/update the PR. Always return status: failed (phase5_files_mismatch) immediately, for manual follow-up. Never gated by AUTO_APPROVE and never prompt.

Commit message. Match the actual Phase 5 change, not a canned module bump. Use the repo's own convention when detectable — e.g. many OpenShift repos expect UPSTREAM: <upstream-pr-or-carry>: <subject>:

bash
git -C "${REPO_DIR}" log --oneline -20

If the recent history shows the UPSTREAM: convention and a dependency bump with a known upstream fix PR number (from the Phase 4 remediation plan):

UPSTREAM: <upstream-pr>: Bump <module> to <new> for <CVE_ID>

If a dependency bump that is downstream-only / fork / carry (no tracked upstream PR, but repo uses UPSTREAM: convention):

UPSTREAM: <carry>: Bump <module> to <new> for <CVE_ID>

If the repo does not use the UPSTREAM: convention, use a plain subject. Dependency bump:

Bump <module> to <new> for <CVE_ID>

If the fix is not a version bump (code, config, workaround), regardless of convention:

Fix <CVE_ID>: <short description of the change>

Body: one or two sentences describing what changed and why. Include Fixes: <SOURCE_TICKET> in Jira mode; omit that line in direct CVE mode. For a bump, include old → new versions. Do not claim a module bump if Phase 5 did not bump a module.

bash
git -C "${REPO_DIR}" commit --signoff -m "${COMMIT_SUBJECT}" -m "${COMMIT_BODY}"

Sign off (DCO) by default — most upstream/downstream OpenShift-style repos require it and a missing sign-off is a common, avoidable PR-check failure. Never use --no-verify or skip hooks unless the user explicitly asks.

3c. Push
bash
git -C "${REPO_DIR}" push -u origin "${BRANCH_NAME}"

Default is a normal push. Amending an existing commit and force-pushing is never authorized by AUTO_APPROVE; it always requires an interactive user (moot in practice, since AUTO_APPROVE=yes never selects stack — see Step 2).


Step 4: Create or Update the GitHub PR

Title

Dependency bump:

<CVE_ID>: bump <module-short> to <new> [<SOURCE_TICKET>]

Omit [<SOURCE_TICKET>] in direct CVE mode. Example: CVE-2026-33186: bump google.golang.org/grpc to v1.79.3 [OCPBUGS-80452]

Non-bump fix:

<CVE_ID>: <short description> [<SOURCE_TICKET>]
Body

Read the repo's PR template if one exists (cat "${REPO_DIR}/.github/PULL_REQUEST_TEMPLATE.md" 2>/dev/null) and structure the body around it. Otherwise use:

Jira mode — every Jira key must be a markdown link. Use a Fixes: line (do not use a bare key):

markdown
## Summary

Fixes: [<SOURCE_TICKET>](<JIRA_BASE_URL>/browse/<SOURCE_TICKET>)

<What Phase 5 changed and why — e.g. bump `<module>` from `<old>` to `<new>`, or a code/config workaround.>

<2–3 sentence CVE description from Phase 1>

## Changes

- <file- or behavior-level bullets from the Phase 5 diff>

## Verification

- `make verify` / `go mod verify` (if modules changed)
- `make build` / `go build ./...`
- `govulncheck ./...`

---
Always review AI generated responses prior to use.
AI-assisted change via compliance plugin (`/compliance:analyze-cve`)

Direct CVE mode — same body without the Fixes: line and without Jira URLs.

Do not include hostnames, cluster names, routes, usernames, passwords, or tokens in the title, body, or comments.

Create vs update

New PR (default mode — no FORK_ORG):

bash
gh pr create \
  --repo "${ORG}/${REPO}" \
  --base "${BASE_BRANCH}" \
  --head "${BRANCH_NAME}" \
  --title "${PR_TITLE}" \
  --body "${PR_BODY}"

New PR (fork mode — FORK_ORG set): use the Fork Mode Step 4 variant (gh api repos/.../pulls -f head_repo=...) instead of the gh pr create call above.

Stacked on existing PR: push is enough (to origin by default, or fork in Fork Mode). Optionally:

bash
gh pr comment "${EXISTING_PR}" --repo "${ORG}/${REPO}" \
  --body "Added <CVE_ID> fix: <what Phase 5 changed>."

And gh pr edit to append the CVE / Jira key to title and the Fixes: line if missing.

Capture PR_URL from gh pr create output or gh pr view --json url (default mode), or from the gh api response (Fork Mode).

IF create fails (permissions, fork needed) → show the exact gh error (no secrets). If the error indicates missing write access and FORK_ORG is not set, suggest re-running with FORK_ORG configured (see Fork Mode) rather than guessing at a fork target. Otherwise give the user the title/body to paste, return status: failed (pr_create_failed). Do not retry more than once.


Step 5: Post PR URL to Jira (Jira mode only)

Skip this step if SOURCE_TICKET is unset (direct CVE mode) → still status: success for the GitHub PR.

Use the report-to-jira skill's Follow-up: PR URL comment section. Do not edit or replace the Phase 4 analysis comment. Do not add/remove labels here.

IF posting fails → display the comment in session for manual paste. The GitHub PR is still a success (jira_followup: failed).


Return Value

Success:

json
{
  "skill": "create-fix-pr",
  "status": "success",
  "action": "created | updated",
  "pr_url": "https://github.com/<org>/<repo>/pull/<n>",
  "pr_number": 123,
  "branch": "fix/cve-yyyy-nnnnn-ocpbugs-12345",
  "base_branch": "release-4.17",
  "cve_id": "CVE-YYYY-NNNNN",
  "source_ticket": "OCPBUGS-12345 or null",
  "jira_followup": "posted | skipped | failed"
}

Skipped:

json
{
  "skill": "create-fix-pr",
  "status": "skipped",
  "reason": "user_declined | no_local_changes | phase5_incomplete | user_wait_for_pr | user_wait_for_pr_auto | embargo"
}

Failed:

json
{
  "skill": "create-fix-pr",
  "status": "failed",
  "reason": "git_missing | gh_missing | gh_unauthenticated | pr_create_failed | commit_failed | phase5_files_missing | phase5_files_mismatch | fork_wrong_lineage | fork_create_failed",
  "error": "<message without secrets>"
}

Integration with analyze-cve

Called from Phase 6 of the analyze-cve skill after Phase 5 verification succeeds. Runs after the Repo Guard has confirmed REPO_DIR still exists.


Guardrails

  • Never commit, push, or open a PR without explicit approval — interactive, or AUTO_APPROVE=yes recorded once upfront
  • Never force-push to BASE_BRANCH / main / master / release-*
  • Never skip git hooks unless the user asks
  • Never stage paths outside PHASE5_FILES; never git add -A or git add .
  • Never commit/push/PR without validating the staged (and, for stack, the branch) path set against PHASE5_FILES and rejecting extras
  • Never run vendor sync in Phase 6 — it happens in Phase 5, before PHASE5_FILES is written
  • Never push to, or open a PR from, a FORK_ORG repo without first verifying its fork lineage (isFork + parent.fullName match) — never reuse a same-named repo that isn't actually a fork of the target
  • Never let AUTO_APPROVE=yes auto-select stack or independent on a PR-title conflict — always wait unattended
  • Never let AUTO_APPROVE=yes skip a hard-fail case (missing/mismatched PHASE5_FILES, ambiguous conflict resolution) — those always require a human, flag or not
  • Never include secrets in commit messages, PR text, or Jira comments
  • Stop immediately on embargo
  • Direct CVE mode must still produce a PR

© openshift-eng, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in plugins/compliance/skills/create-fix-pr of openshift-eng/ai-helpers.

Open the folder on GitHubat commit a627176

Compare with similar skills

Create Fix PR next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Create Fix PR compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Create Fix PR this skillopenshift-eng/ai-helpers120—~6.2kAutomated safety check: PassApache-2.0
Security AdvisoryMidnightBSD/src114—~2.2kAutomated safety check: PassCustom licence
Security Vulnerability Analysiseclipse-ankaios/ankaios125—~1.5kAutomated safety check: PassApache-2.0
Warp Vulnerability Triagewarpdotdev/warp65k1 repos~2.1kAutomated safety check: PassAGPL-3.0
Cve Doctorgetlago/lago-front163—~2.9kAutomated safety check: PassMIT
Deal With Security Advisorypaperclipai/paperclip99k—~2kAutomated safety check: PassMIT

Similar skills

  • Security Advisory

    MidnightBSD/src

    Handle a security fix end to end for MidnightBSD src - triage a FreeBSD security advisory (FreeBSD-SA-) or CVE against this tree, port the fix to master and both stable branches, add the UPDATING…

    114 GitHub stars~2.2k tokensUpdated 4 days ago
    SecurityAuto-check passed
  • Security Vulnerability Analysis

    eclipse-ankaios/ankaios

    Analyze potential Ankaios security vulnerabilities from pasted reports, local evidence, or advisory URLs.

    125 GitHub stars~1.5k tokensUpdated today
    SecurityAuto-check passed
  • Gathers security findings from Dependabot, GCP container scanning, Docker Scout and Linear security issues, then triages and remediates them across Warp's repos and images.

    65k GitHub starsUsed in 1 repo~2.1k tokens
    SecurityAuto-check passed
  • Cve Doctor

    getlago/lago-front

    Triage a CVE / Dependabot alert in a JS/TS project and recommend the least-invasive fix.

    163 GitHub stars~2.9k tokensUpdated today
    SecurityAuto-check passed
  • Deal With Security Advisory

    paperclipai/paperclip

    Handle confidential GitHub Security Advisory response for Paperclip.

    99k GitHub stars~2k tokensUpdated today
    SecurityAuto-check passed
  • Snapshot

    boostsecurityio/poutine

    Run snapshot regression tests after changes to OPA rules, scanners, analyzers, or formatters to detect output regressions.

    523 GitHub stars~214 tokensUpdated yesterday
    SecurityAuto-check passed

More from openshift-eng/ai-helpers

All 118 skills in this repo
  • Investigate CI Reliability

    openshift-eng/ai-helpers

    Find and independently validate actionable reliability defects across OpenShift release jobs and presubmits, then export portable issue handoffs.

    120 GitHub stars~1.9k tokensUpdated yesterday
    Auto-check passed
  • Address Review PR

    openshift-eng/ai-helpers

    Fetch and address all PR review comments — categorize by priority, make code changes, post replies, and push.

    120 GitHub stars~2.9k tokensUpdated yesterday
    Auto-check passed
  • Categorize Activity Types

    openshift-eng/ai-helpers

    Categorize Jira issues into Red Hat Sankey Activity Type categories using MCP Jira tools.

    120 GitHub stars~2.4k tokensUpdated yesterday
    Auto-check passed
  • Has Review Work

    openshift-eng/ai-helpers

    Decide whether a GitHub PR has unanswered authorized review comments or new required CI failures worth a follow-up agent.

    120 GitHub stars~1.9k tokensUpdated yesterday
    Auto-check passed
  • Must Gather Analyzer

    openshift-eng/ai-helpers

    Analyze OpenShift must-gather diagnostic data including cluster operators, pods, nodes, and network components.

    120 GitHub stars~2.3k tokensUpdated yesterday
    Auto-check passed
  • Payload Autodl JSON

    openshift-eng/ai-helpers

    Schema for the autodl JSON data file produced by payload-analysis for database ingestion — you must use this skill whenever generating the autodl JSON file

    120 GitHub stars~2.6k tokensUpdated yesterday
    Auto-check passed

Works with

Categories

Questions about Create Fix PR

What does Create Fix PR do?

A skill your agent uses when opening or updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally. Create Fix PR is an agent skill from openshift-eng/ai-helpers. Use when opening or updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally.

When should I use Create Fix PR?

Create Fix PR fits situations like: updating a GitHub pull request after Phase 5 of /compliance:analyze-cve has applied and verified a CVE fix locally; tasks that involve Vulnerability scanning.

How do I install Create Fix PR in Claude Code?

Run `npx skills add openshift-eng/ai-helpers --skill create-fix-pr -a claude-code`. Or copy the skill folder (plugins/compliance/skills/create-fix-pr in openshift-eng/ai-helpers) into .claude/skills/create-fix-pr in your project. Claude Code loads it when a task matches its description.

How do I install Create Fix PR in Codex?

Run `npx skills add openshift-eng/ai-helpers --skill create-fix-pr -a codex`. Or copy the skill folder (plugins/compliance/skills/create-fix-pr in openshift-eng/ai-helpers) into .agents/skills/create-fix-pr in your project. Codex loads it when a task matches its description.

Can I use Create Fix PR in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add openshift-eng/ai-helpers --skill create-fix-pr -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/create-fix-pr, .gemini/skills/create-fix-pr, .github/skills/create-fix-pr and .opencode/skills/create-fix-pr in your project.

What does Create Fix PR need to run?

Going by SKILL.md and its folder, Create Fix PR needs the command-line tools its instructions call (git, gh, jq, go and make).

Does Create Fix PR access the network?

SKILL.md names 2 domains. In commands or code: github.com and cli.github.com; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.

Is Create Fix PR safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Create Fix PR use?

Create Fix PR is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Create Fix PR use?

About 6.2k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Create Fix PR?

Skills that share tags, products or a category with Create Fix PR: Security Advisory (MidnightBSD/src, 114 stars), Security Vulnerability Analysis (eclipse-ankaios/ankaios, 125 stars), Warp Vulnerability Triage (warpdotdev/warp, 65k stars) and Cve Doctor (getlago/lago-front, 163 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Create Fix PR?

openshift-eng (a GitHub organization) maintains it in openshift-eng/ai-helpers, which has 120 GitHub stars. The repository holds 118 skills in this directory. The repository was last updated on October 6, 2026.

Source: openshift-eng/ai-helpers on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.