Consumes pre-classified visual-diff JSON and a reviewer-signed acceptance log to produce a single go/no-go CI verdict for visual regression. Blocks when intentional baseline changes lack a non-author reviewer sign-off or when regressions are present, and emits the binding gate artifacts - visual-gate.json + visual-gate.md - with fail-closed handling of a missing classifier run and author-cannot-self-approve enforcement, so the pipeline can exit non-zero on BLOCK. Use when the gate's input is pre-classified diff data and the enforcement concern is reviewer approval and a binding CI verdict.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Low
Low-risk findings.
1 low severity finding. Worth noting, but not necessarily harmful.
The skill exposes the agent to untrusted, user-generated content from public third-party sources, creating a risk of indirect prompt injection. This includes browsing arbitrary URLs, reading social media posts or forum comments, and analyzing content from unknown websites.
In `references/artifact-and-ci-wiring.md`, the CI entrypoint `scripts/run_visual_gate.py` ingests free-text-y YAML from the PR branch at `.visual-acceptance.yml` and JSON from `visual-classifications.json` via `yaml.safe_load(...read_text())` and `json.loads(...read_text())`, meaning an outsider who can author/publish PR content can supply that text for the workflow to read.
.visual-acceptance.yml
content-type · 2 sites
The CI entrypoint ingests free-text YAML from `.visual-acceptance.yml` on the PR branch via yaml.safe_load(); an outsider who can author PR content controls this file's contents, creating an indirect prompt-injection surface.
references/artifact-and-ci-wiring.md
65
acceptance = yaml.safe_load(ACCEPT_PATH.read_text()) if ACCEPT_PATH.exists() else {"snapshots": []}
references/artifact-and-ci-wiring.md
58
ACCEPT_PATH = Path(".visual-acceptance.yml")
visual-classifications.json
content-type · 2 sites
The CI entrypoint ingests JSON from `visual-classifications.json` on the PR branch via json.loads(); an outsider who can author PR content controls this file, and its field values (engine, snapshot) are interpolated into printed output, creating an indirect prompt-injection surface.
references/artifact-and-ci-wiring.md
64
classifications = json.loads(CLASS_PATH.read_text())
references/artifact-and-ci-wiring.md
57
CLASS_PATH = Path("visual-classifications.json") # output of the visual-diff classification step