Skip to content

feat: rewrite as a node20 TypeScript action with native PR surfaces#1

Merged
jhumel-code merged 3 commits into
mainfrom
rewrite-typescript-action
Jun 4, 2026
Merged

feat: rewrite as a node20 TypeScript action with native PR surfaces#1
jhumel-code merged 3 commits into
mainfrom
rewrite-typescript-action

Conversation

@jhumel-code

@jhumel-code jhumel-code commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Full from-scratch rewrite of the v1 bash composite action as a node20 TypeScript action, making the action as seamless as possible.

Four surfaces

  • Inline PR annotations + GitHub Security tab — SARIF uploaded via the Code Scanning API (a node action can't uses: codeql-action). Findings show on the changed lines and in the Security tab.
  • Sticky PR comment — one summary comment, updated in place each run.
  • Status-check gating — risk-score / severity thresholds (semantics preserved from v1), fail-closed.
  • Console panel + Step Summary — readiness, per-severity breakdown, headroom ladder.

Review fixes folded in

  • Single scan via engine --json-out/--sarif-out (two-scan fallback for older engines).
  • sha256-verified binary download (v1 ran it unverified).
  • Gates fail closed on a broken/empty scan (v1 failed open to a clean 100).
  • No ${{ }} injection — inputs read via the toolkit.
  • Headroom ladder sourced from the engine's projected_scores (single source of truth), not an in-action jq reimplementation (which was silently broken).

Compatibility

  • All existing inputs and the eight existing outputs preserved (+ sarif-uploaded).
  • upload-sarif and comment-on-pr default on (need security-events: write / pull-requests: write; degrade gracefully — never fail solely because a surface is unavailable). New inputs: comment-on-pr, annotations, max-annotations, github-token.

Build / test

  • Bundled to dist/ with ncc (committed). npm run all green: typecheck + 53 jest unit tests + build.
  • build-check.yml fails PRs with a stale dist/; selftest.yml exercises remote-target, self-empty, and PR surfaces.

Depends on / follow-ups

⚠️ Breaking vs v1: now node20 (was composite); upload-sarif now defaults true. See CHANGELOG migration notes.

@jhumel-code jhumel-code force-pushed the rewrite-typescript-action branch 2 times, most recently from aa27b22 to 63f3183 Compare June 4, 2026 08:24
Full from-scratch rewrite from the v1 bash composite action.

Surfaces:
- Inline PR annotations + GitHub Security tab (SARIF via the Code Scanning API)
- Sticky PR summary comment (update-in-place by marker)
- Status-check gating (risk-score / severity thresholds; fail-closed)
- Console panel + Step Summary (readiness, severity breakdown, headroom ladder)

Review fixes folded in:
- Single scan via engine --json-out/--sarif-out (two-scan fallback for old engines)
- sha256-verified binary download (v1 ran it unverified)
- Gates fail closed on a broken/empty scan (v1 failed open to a clean 100)
- Inputs read via the toolkit, never spliced into a run: block via GitHub Actions expressions

Headroom ladder is sourced from the engine's projected_scores (single source of
truth) instead of an in-action jq reimplementation. upload-sarif and comment-on-pr
default on (need security-events: write / pull-requests: write; degrade gracefully).

Backward-compatible: all existing inputs and the eight existing outputs preserved.
Bundled to dist/ with ncc (committed); 53 jest unit tests; build-check workflow
guards dist/ freshness.
@jhumel-code jhumel-code force-pushed the rewrite-typescript-action branch from 63f3183 to 734359b Compare June 4, 2026 08:42
…ne stderr

The selftest floated on `latest` engine + latest rules, so it broke when
trustabl-rules added an mcp/ pack the released engine v0.1.2 cannot load
("unknown category mcp"). Pin every selftest job to v0.1.2 + the `pre-mcp` rules
tag (a known-compatible pair) so CI tests the action, not upstream drift. The
remote-target job uses continue-on-error plus artifact/output assertions, since
that external target legitimately gates on findings (exit 1). Temporary until an
engine release with mcp-category support is `latest` (trustabl/trustabl#12).

runner.ts now includes the engine's exit code and a stderr tail in the
"produced no JSON output" error, so a failing scan is debuggable instead of opaque.
The engine marshals an empty findings slice as JSON null (Go nil-slice
behavior), so a clean scan emits findings: null. parseScanResult threw
"missing findings array" on that, failing the action on any repo with no
findings (the selftest's scan-self-empty / scan-pr-surfaces jobs). Treat
null/absent findings as an empty array; still reject non-object JSON.
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

Trustabl scan

trustabl/trustabl-action · rewrite-typescript-action · 0 findings

Readiness now   🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩   100 / 100

Findings by severity

Severity Count
critical 0 ▱▱▱▱▱▱▱▱
high 0 ▱▱▱▱▱▱▱▱
medium 0 ▱▱▱▱▱▱▱▱
low 0 ▱▱▱▱▱▱▱▱
info 0 ▱▱▱▱▱▱▱▱
Metric Value
Repository trustabl/trustabl-action
Branch rewrite-typescript-action
Readiness score 100
Risk score 0
Findings 0
Max severity none
Native exit 0
Rules version fd790fa276dd57b810d1ef883d5a2f5f14a35a4c

✅ Passed scanning

@jhumel-code jhumel-code merged commit e4053f2 into main Jun 4, 2026
5 checks passed
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