# Qv Devops Pr Review

> PR review for DevOps changes — runs the generic /qv-pr-review flow then layers a structured GitHub Actions security audit (action pinning, permissions, OIDC, secrets handling). Use when reviewing a PR that touches DevOps paths or invoking /qv-devops-pr-review.

- Skill: `tetherto/qv-devops-pr-review` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tetherto/qv-devops-pr-review`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tetherto/qv-devops-pr-review/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: tetherto (https://skillmd.com/u/tetherto)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tetherto/qv-devops-pr-review

---


# DevOps PR Review

A DevOps-flavored PR review on top of the generic [`/qv-pr-review`](../qv-pr-review/SKILL.md) flow. Adds a deterministic GitHub Actions security audit pass grounded in the repository's [GitHub and CI guidance](../../../.github/AGENTS.md) and the checklist below, so DevOps reviewers always see the same high-risk patterns regardless of the prose style of the diff.

The skill is **a wrapper, not a fork** — the bulk of the review (gitflow, CI, title/body, generic correctness, security) is done by `/qv-pr-review`. This skill layers DevOps-specific findings into the same pending review payload.

## When to use this skill

**Use when:**

- User asks to review a PR whose changes are dominated by DevOps-owned paths (`.github/workflows/`, `.github/actions/`, `.github/scripts/`, `scripts/`, IaC under `terraform/`, `ansible/`, `k8s/`, `Dockerfile*`, `.github/CODEOWNERS`, `.github/dependabot.yml`)
- User invokes `/qv-devops-pr-review` with a PR URL
- Triggered as a follow-up from `/qv-devops-pr-status` after the user picks a PR

If the PR's touched paths are dominated by a different pod, fall back to `/qv-pr-review`. The generic flow already auto-loads the relevant pod's rules.

## Inputs

- **Required**: PR URL (`https://github.com/tetherto/qvac/pull/<num>`)
- **Optional**: user-provided focus notes

If the URL is missing, ask for it. Nothing else to ask up-front.

## Safety rules

Inherits all safety rules from [`/qv-pr-review`](../qv-pr-review/SKILL.md#safety-rules--do-not-touch-the-users-local-repo) verbatim:

- **Read-only with respect to the user's local working tree.** No `git switch`, `git checkout`, `git reset`, `git restore`, `git stash`, `git pull`, `git merge`, `git rebase`, `git cherry-pick`, `git clean`, `gh pr checkout`, or any write inside the user's working tree.
- All file inspection happens in the worktree cache at `~/.cache/qvac-pr-review/pr-<num>/` (managed by `worktree-prepare.mjs`) or via `gh api .../contents/<path>?ref=<sha>` to `/tmp/`.

## Efficiency rules

Inherits the `~5–8 shell-call` budget from `/qv-pr-review`. The DevOps audit pass adds at most **3 additional reads** (Read/Grep/Glob, not shell) per touched workflow/action file. Cache: reuse `/tmp/pr-<num>.json`, `/tmp/pr-<num>.patch`, and the worktree path from the underlying `/qv-pr-review` run.

## Workflow

### 1. Run the generic /qv-pr-review flow up to step 7a (overview)

Read [`.agents/skills/qv-pr-review/SKILL.md`](../qv-pr-review/SKILL.md) and follow steps 0a → 7a inclusive:

- 0a. Prepare worktree (`worktree-prepare.mjs`)
- 1. Parse PR URL
- 2. Fetch PR metadata
- 3. Gitflow validation
- 4. Read the applicable scoped instructions. DevOps paths use [`.github/AGENTS.md`](../../../.github/AGENTS.md) and its linked source documents. The PR-format spec lives in the [`devops-pr-create`](../qv-devops-pr-create/SKILL.md) skill and is invoked explicitly.
- 5. Validate PR title + body against the format spec inlined below (DevOps allowed prefixes: `infra`/`feat`/`fix`/`chore`/`doc`/`test`; tags: `[bc]`/`[notask]`/`[skiplog]`; title regex: `^([A-Z]+-\d+ )?(infra|feat|fix|chore|doc|test)(\[(bc|notask|skiplog)\])?: \S.+$`)
- 6. Review dimensions
- 7a. Print risk overview in chat — but **do not yet run step 7b** (the inline-comment selection prompt). The DevOps audit pass in step 2 below contributes additional findings.

### 2. Run the DevOps GitHub Actions security audit

For every `.github/workflows/*.yml` and `.github/actions/**/action.yml` in the patch, perform the checks below using Read/Grep/Glob against the worktree path. Each check that fires becomes a finding with a tier per the table.

| # | Check | Basis | Finding tier |
|---|---|---|---|
| A1 | Every `uses: <vendor>/<action>@<ref>` is pinned to a 40-char SHA (regex `@[0-9a-f]{40}\b`) with a trailing `# v<ver>` comment. Tag pins (`@v3`, `@main`, branch refs) fail. First-party `./.github/actions/<name>` references are exempt. | `.github/AGENTS.md` | High |
| A2 | Permissions are declared explicitly — either a top-level `permissions:` block, OR every job has its own `permissions:` block. Relying on repo-default permissions fails. | `.github/AGENTS.md` | High |
| A3 | No occurrence of `permissions: write-all` anywhere in the workflow. | `.github/AGENTS.md` | High |
| A4 | If the workflow uses `pull_request_target`, none of its jobs check out PR HEAD via `actions/checkout@... ref: ${{ github.event.pull_request.head.sha }}` or `${{ github.head_ref }}`. | `.github/AGENTS.md` | High |
| A5 | No direct interpolation of `${{ github.event.pull_request.title }}`, `body`, `head_ref`, `commits[*].message`, or any `github.event.*` user-controlled field inside `run:` blocks. They MUST be piped via `env:`. | `.github/AGENTS.md` | High |
| A6 | If the workflow has `id-token: write`, OIDC is consumed by an auth action (`google-github-actions/auth`, `aws-actions/configure-aws-credentials`, `azure/login`) — not used for token forging that reaches a long-lived credential. | `.github/AGENTS.md` | Medium |
| A7 | No `${{ secrets.X }}` interpolated directly inside a `run:` block. Pass via `env:` or action `with:` instead. | `.github/AGENTS.md` | High |
| A8 | No `set -x` / `bash -x` in steps that touch secrets; no `printenv`, `env`, `cat`, or `echo` of a secret value, even for "debugging". | `.github/AGENTS.md` | High |
| A9 | Concurrency block is declared. Release/state-mutating workflows have `cancel-in-progress: false`. | Current workflow conventions | Medium |
| A10 | Every job has `timeout-minutes`. Default budget 30; >30 needs a justifying comment. | Current workflow conventions | Low |
| A11 | `continue-on-error: true` is NOT set on Tier-1 checks (lint, format, type-check, security scans, tests). | `docs/devops/TIER-1-SCOPE.md` | Medium |
| A12 | Outputs use `$GITHUB_OUTPUT`, never the deprecated `::set-output::`. | Current workflow conventions | Low |
| A13 | When `actions/cache` is used, cache writes are gated on non-fork triggers (`push` / `workflow_dispatch` / `merge_group`) — not blanket on `pull_request`. | `.github/AGENTS.md` | Medium |
| A14 | Workflow filename matches the existing repo conventions (`on-pr-*.yml`, `on-merge-*.yml`, `on-pr-close-*.yml`, `release-*.yml`, `create-github-release-*.yml`, `prebuilds-*.yml`, `pr-test-*.yml`, `pr-validation-*.yml`, `pr-checks-*.yml`, `integration-*-*.yml`, `reusable-*.yml`, `trigger-reusable-*.yml`). New file with a divergent name → finding. Pre-existing files keep their name unless the PR renames them. | Active workflow names | Low |

For each finding, capture: file, line, the offending excerpt (3-8 lines), the tier, and a one-line "why" pulled from the rule. Write findings into the same chat overview structure that `/qv-pr-review` step 7a uses, under a new sub-heading `### GHA security audit`.

### 3. Re-print the consolidated chat overview

After both passes, re-print the full overview (gitflow / CI / generic-high / generic-medium / GHA-audit / lows / verified) so the user sees one ranked list. Findings retain the deep-link + excerpt rules from `/qv-pr-review` step 7a.

### 4. Run /qv-pr-review steps 7b → 12

Continue with the generic flow:

- 7b. Selection prompt — the multi-select includes BOTH generic findings and GHA-audit findings. Defaults: every High pre-selected (including all GHA-audit Highs); Medium pre-selected; Low opt-in.
- 8. Assemble inline comments from the user-confirmed set
- 9. Pre-flight check
- 10. Show the `gh api ... pulls/<num>/reviews` command, wait for confirmation
- 11. Post on confirmation
- 12. Output the link to the pending review

### 5. Audit summary in chat (after posting)

After the pending review URL is printed, append a single-line audit summary:

```
GHA audit: <H high> / <M medium> / <L low> findings on N workflow files. <K> filed inline; <skipped> skipped per user.
```

This makes audit coverage observable without reading the inline payload.

## Inline comment style for GHA-audit findings

Inherit the comment style from `/qv-pr-review`. Add one DevOps-specific convention: every GHA-audit finding's body MUST cite the rule it traces back to, e.g.:

```markdown
Untrusted input piped directly into shell. Per `.github/AGENTS.md`,
this MUST go through an `env:` block — `${{ github.event.pull_request.title }}` lands in the rendered shell verbatim and is exploitable.

```yaml
env:
  PR_TITLE: ${{ github.event.pull_request.title }}
run: |
  echo "$PR_TITLE"
```
```

The cite makes the audit finding auditable: the reviewer can verify the rule still says what the comment claims.

## Quality Checklist

Before posting the pending review, verify:

- [ ] Underlying `/qv-pr-review` workflow ran through step 7a successfully (worktree prepared, gitflow checked, CI checked, scoped instructions loaded, title/body validated)
- [ ] GHA-audit pass ran on every changed `.github/workflows/*.yml` and `.github/actions/**/action.yml`
- [ ] Each GHA-audit finding has: file path, post-change line, 3-8 line excerpt at PR head SHA, deep link, tier, and source citation
- [ ] User-confirmed selection from step 7b matches the assembled payload exactly (count + IDs)
- [ ] Audit summary line is printed after step 12

## References

- Generic PR review skill (parent flow): [.agents/skills/qv-pr-review/SKILL.md](../qv-pr-review/SKILL.md)
- GitHub Actions and secrets guidance: [.github/AGENTS.md](../../../.github/AGENTS.md)
- DevOps PR-create skill (canonical home for commit / PR-title format): [`devops-pr-create`](../qv-devops-pr-create/SKILL.md)
- Pod metadata: [.github/teams/devops.json](../../../.github/teams/devops.json)
- Worktree manager: [.agents/skills/_lib/pr-skills/worktree-prepare.mjs](../_lib/pr-skills/worktree-prepare.mjs)

