Skip to content

visual-artifacts v1: PR 2 core phase renderers (think/review/security/qa/ship)#218

Merged
garagon merged 2 commits into
mainfrom
visual-artifacts-v1-pr2-core-phase-renderers
May 11, 2026
Merged

visual-artifacts v1: PR 2 core phase renderers (think/review/security/qa/ship)#218
garagon merged 2 commits into
mainfrom
visual-artifacts-v1-pr2-core-phase-renderers

Conversation

@garagon
Copy link
Copy Markdown
Owner

@garagon garagon commented May 11, 2026

Summary

PR 2 of the Visual Artifacts v1 round. Wires renderers for the remaining core phases so /think, /review, /security, /qa, and /ship artifacts can each be inspected as a static HTML view. Same trust + path-safety contract as PR 1.

What changed

Shared helpers (bin/lib/visual-render.sh)

  • nano_visual_normalize_artifact — jq-based coercion that turns a legacy or malformed artifact into a predictable shape (summary, context_checkpoint, scope_drift, findings, conflicts as objects/arrays). Every renderer reads the normalized form.
  • nano_visual_severity_class — maps blocking / critical / high / etc to a CSS class so review/security/qa agree on color.
  • nano_visual_safe_pr_url — allowlist for ship pr_url. Only https://github.com/* renders as a clickable link; every other URL renders as escaped text with an explicit "host not in allowlist" note.
  • nano_visual_safe_screenshot_path — stricter allowlist for future QA screenshot rendering.
  • New CSS for .counter, .finding.sev-bad/warn/info/ok, .chip, .pr-link, .unsafe-url.

Body renderers (bin/render-artifact.sh)

  • render_think_body — value proposition, scope mode chip, narrowest wedge, key risk, premise validation, archetype card with optional example reference, out-of-scope list.
  • render_review_body — 4-counter summary (blocking / should fix / nitpicks / positive), scope drift status chip with out-of-scope and missing file lists, severity-styled findings.
  • render_security_body — 5-counter summary (critical / high / medium / low / total), findings with category chips (OWASP A0n / STRIDE), proof_of_concept and reproduce blocks wrapped in <details><pre>.
  • render_qa_body — mode / status chips, WTF likelihood, 5-counter test/bug breakdown, findings with reproduce + root cause + fixed flag.
  • render_ship_bodyreport_only mode renders a short report card (no release-packet styling); normal mode renders PR title / number / URL / status / CI passed. Unsafe PR URLs render as text with data-testid="unsafe-pr-url".
  • render_findings_section — shared helper for review/security/qa.
  • render_context_checkpoint — shared helper for the trailing card.

CI extensions

  • 8 new e2e cells: think, review, security, qa, ship normal, ship report_only, ship malicious URL, XSS across all 5 phases.
  • 5 new template safety checks: nano_visual_safe_pr_url usage, rel="noopener noreferrer", nano_visual_severity_class, CSS classes.
  • Template safety lint now allows the # url-allowlist marker so the legitimate case pattern does not trip the "no http(s) URLs" check.

Test counts

Suite PR 1 PR 2
ci/e2e-visual-artifacts.sh 86 154
ci/check-visual-artifact-templates.sh 20 25
Total contract surface 106 179

Codex review trail (2 passes, clean)

Pass Finding Fix
1 P2: ship ci_passed not escaped (boolean-typed in schema, but artifact may store string) pipe through nano_html_escape like every other scalar
2 (none — clean)

Test plan

  • ci/e2e-visual-artifacts.sh 154/154
  • ci/check-visual-artifact-templates.sh 25/25
  • Sabotage: inject URL in renderer source — lint detects (24/25)
  • All 5 phase renderers XSS-checked with <script> / <img onerror> / <iframe> fixtures
  • Ship malicious PR URL (javascript:alert(1)) renders as escaped text only, never as <a href>
  • Ship report_only mode shows the report card and omits the release-packet header
  • Codex review pass 2 returned clean

garagon added 2 commits May 11, 2026 16:29
…/ship)

Wires renderers for the remaining core phases so /think, /review,
/security, /qa, and /ship artifacts can each be inspected as a
static HTML view. Same trust + path-safety contract as PR 1.

Shared helpers in bin/lib/visual-render.sh:
- nano_visual_normalize_artifact: jq-based coercion that turns a
  legacy or malformed artifact into a predictable shape (summary,
  context_checkpoint, scope_drift, findings, conflicts as objects /
  arrays). Every renderer reads the normalized form.
- nano_visual_severity_class: maps blocking/critical/high/etc to a
  CSS class so review/security/qa agree on color and styling.
- nano_visual_safe_pr_url: allowlist for ship pr_url. Only
  https://github.com/* renders as a clickable link; every other URL
  renders as escaped text with an explicit "host not in allowlist"
  note.
- nano_visual_safe_screenshot_path: stricter allowlist for future
  QA screenshot rendering (PR 3 may wire this).

Body renderers in bin/render-artifact.sh:
- render_think_body: value proposition, scope mode chip, narrowest
  wedge, key risk, premise validation, archetype card with optional
  example reference, out-of-scope list.
- render_review_body: 4-counter summary (blocking / should fix /
  nitpicks / positive), scope drift status chip with out-of-scope
  and missing file lists, severity-styled findings.
- render_security_body: 5-counter summary (critical / high / medium
  / low / total), findings with category chips (OWASP A0n /
  STRIDE), proof_of_concept and reproduce blocks wrapped in
  <details><pre> so multi-line escaped content stays readable.
- render_qa_body: mode / status chips, WTF likelihood, 5-counter
  test/bug breakdown, findings with reproduce + root_cause +
  fixed flag.
- render_ship_body: report_only mode renders a short report card
  (no release-packet styling); normal mode renders PR title / number
  / URL / status / CI passed. Unsafe PR URLs are rendered as text
  with data-testid="unsafe-pr-url" so callers can audit.
- render_findings_section: shared helper for review/security/qa.
- render_context_checkpoint: shared helper for the trailing card.

CI extensions:
- 8 new e2e cells (think, review, security, qa, ship normal, ship
  report_only, ship malicious URL, XSS across all 5 phases).
- 5 new template safety checks (nano_visual_safe_pr_url usage,
  rel="noopener noreferrer", nano_visual_severity_class, CSS for
  .finding.sev-bad and .counter).
- Template safety lint now allows the `# url-allowlist` marker so
  the legitimate code-level case pattern does not trip the
  "no http(s) URLs" check.

Test counts:
- e2e: 86 -> 152 (66 new checks across 8 phase + XSS cells)
- template safety: 20 -> 25
- Total contract surface: 177 checks
Codex PR 2 pass 1 finding. /ship's schema only requires summary
to be an object, so a malformed artifact with
"ci_passed":"<script>alert(1)</script>" rendered raw markup. Every
other JSON-derived ship field passes through nano_html_escape; the
boolean-typed ci_passed was the one gap.

Pipe ci_passed through nano_html_escape like every other scalar.
Adds a regression cell with a string-typed ci_passed containing a
script tag; the rendered HTML must contain the escaped form and
must not contain the raw tag.

Test count: 152 -> 154.
@garagon garagon merged commit 32dfa39 into main May 11, 2026
62 checks passed
@garagon garagon deleted the visual-artifacts-v1-pr2-core-phase-renderers branch May 11, 2026 19:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant