skills/ci-security-scanning-with-strix/SKILL.md
You can gate PRs two ways — pick based on the environment, or combine them:
Both fail the build on validated findings and both emit SARIF 2.1.0, so you can start with one and add the other later.
Run a diff-scoped Strix scan on every PR: only changed files are tested, quick mode keeps it fast, and exit code 2 fails the build when validated vulnerabilities are found.
Create .github/workflows/security.yml:
name: Security Scan
on:
pull_request:
jobs:
strix-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required for diff-scope resolution
- name: Install Strix
run: curl -sSL https://strix.ai/install | bash
- name: Run Security Scan
env:
STRIX_LLM: ${{ secrets.STRIX_LLM }}
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
run: strix -n -t ./ --scan-mode quick --max-budget 10
# Don't fail open: a run that hits the hard budget stop exits 0 but leaves
# run.json status "stopped", not "completed". Enforce completion explicitly.
# This does not catch an agent that wrapped up early on a budget *warning*
# (it still calls finish_scan and records "completed"), so size the budget.
- name: Fail unless the scan completed
run: |
run_json=$(ls -t strix_runs/*/run.json | head -1)
status=$(jq -r .status "$run_json")
if [ "$status" != "completed" ]; then
echo "Strix run status is '$status' — the scan did not complete (likely budget exhausted). Raise --max-budget." >&2
exit 1
fi
Then tell the user to add two repository secrets: STRIX_LLM (model id, e.g. openai/gpt-5.4) and LLM_API_KEY (the provider key). Do not create these values yourself.
Notes:
--scope-mode auto). If diff resolution fails, keep fetch-depth: 0 or set --diff-base to the PR's actual base branch — use origin/${{ github.base_ref }} in GitHub Actions rather than a hard-coded origin/main, since repos use different default branches.0 pass, 2 vulnerabilities found (fails the job), 1 setup error.0 exit means "no validated vulnerabilities in what was analyzed"; if --max-budget is hit before the diff is fully covered, the scan wraps up early and can still exit 0. The "Fail unless the scan completed" step above narrows the gap: strix_runs/<run>/run.json is "stopped" when the scan was cut off at the hard budget limit without a final report. It is not a complete guard — the agents get graduated wrap-up warnings before that limit, and a run that wraps up on a warning still calls finish_scan and records "completed" with partial coverage. So keep that step in any pipeline that gates merges and give the scan real headroom (compare run.json's llm_usage.cost against --max-budget; if it ran right up to the cap, raise it). For a quick diff-scoped PR scan --max-budget 10 is usually ample, raise it for large diffs.Strix writes SARIF 2.1.0 to strix_runs/<run>/findings.sarif:
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: strix_runs
Any pipeline works the same way — install, set the two env vars, run headless:
curl -sSL https://strix.ai/install | bash
# Resolve the PR's base branch robustly (use your CI's base-branch variable if it
# has one, e.g. GitHub Actions: origin/${{ github.base_ref }}). Avoid piping the
# git lookup into another command — a failed lookup would otherwise be masked.
BASE_BRANCH="${CI_MERGE_REQUEST_TARGET_BRANCH_NAME:-}" # GitLab MR target
if [ -z "$BASE_BRANCH" ]; then
BASE_BRANCH=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null)
BASE_BRANCH="${BASE_BRANCH#origin/}"
fi
DIFF_BASE="origin/${BASE_BRANCH:-main}"
# Fail loudly rather than silently narrowing scope (e.g. to HEAD~1, which on a
# multi-commit branch would scan only the last commit and let earlier ones pass).
if ! git rev-parse --verify --quiet "$DIFF_BASE" >/dev/null; then
echo "Cannot resolve diff base '$DIFF_BASE'. Fetch the base branch (git fetch origin <base>) or set --diff-base explicitly." >&2
exit 1
fi
strix -n -t ./ --scan-mode quick --scope-mode diff --diff-base "$DIFF_BASE" --max-budget 10
Gate the pipeline on the exit code (see the budget/fail-open caveat above — give the scan enough budget to finish). Schedule standard scans nightly and deep scans for release candidates.
No workflow file, no Docker, no LLM key. Two ways to use it:
PR-review app (zero code): the user installs the Strix GitHub/GitLab/Bitbucket app and enables PR reviews for the repo in the app.strix.ai dashboard. Every PR is then reviewed automatically, with findings posted as PR comments. Nothing to add to the repo. This is the lowest-effort path — recommend it first when the user just wants PR gating.
API-triggered from any pipeline: if you want to trigger from an existing pipeline (or a system without the SCM app), call the API with a token that has pr_reviews:write (or scans:write). Store the token as a CI secret; ask the user to create it at Settings → API Access. Example GitHub Actions step:
- name: Strix PR review (managed)
if: github.event_name == 'pull_request'
env:
STRIX_API_TOKEN: ${{ secrets.STRIX_API_TOKEN }}
run: |
curl -sS --fail https://app.strix.ai/api/v1/pr-reviews/start \
-H "Authorization: Bearer $STRIX_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"repository_full_name\":\"${{ github.repository }}\",\"pr_number\":${{ github.event.pull_request.number }}}"
To gate the build on results, poll the PR review / scan status and fail on unresolved criticals/highs. Full endpoints (PR reviews, scans, SARIF export, schedules for scheduled deep scans) are in the managed-pentesting-with-strix skill.
Recommend Option B for most teams (no maintenance, central dashboard); use Option A when scans must stay entirely within your own infrastructure.