Skip to content

Releases: apatureai/gate

v0.1.5

Choose a tag to compare

@adiprathapa adiprathapa released this 25 Aug 01:39
f6e5f2a

Fixed

  • gate-mode no longer silently overrides .gate.yml. The Action input carried default: "none", so omitting gate-mode overrode the file with none on every run — a repo that opted into rules.gate: blockers got an advisory check that could never fail. An omitted input now lets the file decide; an explicit value still wins.
  • An invalid gate-mode is refused instead of silently never gating — rejected with a neutral "Action setup failed" Check Run naming the input.

Changed

  • Fork gate hardened. A PR whose payload does not state its fork status is treated as a fork rather than assumed same-repo.
  • Baselines compare against the deployment that rendered them.
  • Default-branch measurement coverage widened — measured on install and on merge commits whose tree matches a reviewed head, so a repo's first PR still has a baseline.

Adoption

  • Added CHANGELOG.md, examples/gate.yml (a liftable workflow consuming apatureai/gate@v1), and README corrections.
  • All package manifests bumped to 0.1.5 to track the release tag.

v0.1.4

Choose a tag to compare

@adiprathapa adiprathapa released this 18 Aug 22:46

Scoping a measured violation to what the pull request actually did.

rules.measurements: off | advisory | block is now in the config schema, and
advisory stays the default: gating is opt-in and never a vendor default. Under
block, a measurement fails a check only when it is both block-eligible, which
is the engine's own precision claim, and answerable to this pull request.

Baselines. Gate records the measurement set it observed at a commit and
compares a pull request against the set stored for its base, so the first run on
a mature repository does not hand back the whole back catalogue. No baseline
never gates, and says so in as many words: "Gate has not looked at the base" is a
different sentence from "the base was clean", and the two never render alike.

Severity bands. A pre-existing violation that this pull request moved into a
worse band can now fail a check, and is reported as already present rather than
as new. Bands are the engine's, ordinal, and coarse enough that re-measurement
noise cannot move one. overflow band regressions are reported and never gate,
because those cuts are shares of a viewport rather than a published standard.

Identity. A markup refactor around an untouched violation carries it over
rather than reading as one fixed plus one introduced, and a violation is placed
against the viewport it was measured at.

Requires a Gate version that knows these keys: an older build rejects them as
unrecognized and skips the review, so pin @v1 or later before writing them.

v0.1.3

Choose a tag to compare

@adiprathapa adiprathapa released this 17 Aug 03:23

Gate runs untrusted pull request code in a hardened sandbox, captures the preview deploy, and publishes a design review as a sticky comment and a Check Run. It does not produce the critique itself; you point it at a critique service such as apatureai/verdict.

Upgrade if you use verify_stability

v0.1.2 rejects verify_stability in .gate.yml with Unrecognized key, and publishes a neutral "The .gate.yml file is invalid, so Gate skipped this review." It does not fail your PR, but you get no reviews and no hint that the tag is the cause. @v1 now points here.

A green check can no longer mean nothing was verified

An engine can now retract its own grade. grade is a required field, so an engine whose every finding was deleted before it could be reported still has to put something there and it floors to ship. Coverage cannot catch that case: the route was reviewed, so coverage is full and truthful while the grade means nothing. Gate stripped the engine's retraction at parse and published the green tick anyway, in blocking mode as well as advisory. It now withholds the grade, and treats a retraction reason it has not been taught as a retraction rather than defaulting to a pass.

Two things that were CLI-only now cross the wire

Gate tells the engine which component libraries the repository declares, so the deep prompt carries the right rubric addenda. It sends ids rather than detected text on purpose: package.json is part of the untrusted pull request, and letting its contents into the prompt would make a PR's own manifest an injection channel.

verify_stability: true in .gate.yml asks the engine to capture each page twice and compare the bytes.

Honest limitations

Gate produces no critique on its own. Without a critique service configured it publishes a neutral Check Run saying so, never a pass. Component-library detection reads the root package.json only, so a monorepo declaring its UI dependencies in a workspace package is not detected. The sandbox supervisor's resource caps are Linux-only; on other runners the time ceiling still applies.

v0.1.2

Choose a tag to compare

@adiprathapa adiprathapa released this 16 Aug 04:58

Gate runs untrusted pull request code in a hardened sandbox, captures the preview deploy, and publishes a design review as a sticky comment and a Check Run. It does not produce the critique itself; you point it at a critique service.

Fixed: a pull request could forge Gate's own verdict

The sticky comment is Markdown, and its structure is what tells a reader which words are Gate's: the ## Apature Gate: design review heading and the bold grade line under it. Engine-supplied fields reached that comment unsanitized, so a crafted suggestion could close the <details> block it sat in and open a second heading with **✅ Ship** under it. A reviewer scrolling the comment saw Gate apparently approving the pull request.

This never executed anything: GitHub strips raw HTML. It was forgery, and it did not need a compromised engine, because a model's prose derives partly from the untrusted page text of the pull request under review.

Every field originating from the engine or the model is now escaped so it cannot open a block construct, close one, forge a grade line, or break out of a table cell. Also closed in this release:

  • Bare www. hosts are defanged. GitHub autolinks them with no scheme present, so a rule anchored on https?:// could never match one. SECURITY.md claimed this was covered before it was true.
  • Evidence URLs carrying credentials in the authority are refused. https://github.com@attacker.example/x.png reads as one host and resolves to another, under Gate's own "Evidence" anchor text.
  • A pipe in an evidence URL no longer ends the table cell and silently drops the link.
  • Bidirectional controls such as U+202E are stripped rather than escaped. Escaping does nothing against a character whose whole effect is on rendering.

Also in this release

The Check Run now states the engine's grounding drop count. Zero findings and three findings that could not be grounded both arrive as an empty list under a ship grade, and only the engine knew which happened.

Upgrading

@v1 now points here. If you pin a version, move to v0.1.2; v0.1.1 renders unsanitized engine output.

Honest limitations

Gate does not critique anything itself. Without a critique service configured it publishes a neutral Check Run saying so, never a pass. A triage pass in the reference engine can report full coverage over routes it did not deeply review; that is tracked upstream and is not fixed here.

v0.1.1: a green check can no longer mean nothing was reviewed

Choose a tag to compare

@adiprathapa adiprathapa released this 16 Aug 02:11

What Gate is

Gate is a GitHub Action that runs a pull request's preview build inside a hardened sandbox, hands the verified preview URL to a critique service you supply, and publishes that service's design review back to the pull request as one sticky comment plus a Check Run. It judges and reports: it never edits code, never commits, never opens fix PRs, and never asks for contents: write.

Gate is the GitHub-facing half of a two-part system. It does not screenshot the page and does not run the vision model. Both sit behind an HTTP contract, and no implementation of that contract ships in this repository. verdict is a working one, and its matching v0.1.1 is released alongside this.

Upgrading from v0.1.0 is strongly recommended. At v0.1.0 Gate could publish a green check for a review that never happened. This release makes that impossible.

A green check can no longer mean nothing was reviewed

This is the change worth reading if you read only one.

A critique service returns a structured result with a grade in it, and a result with no findings grades ship. That is the right answer when the service looked at your pages and found nothing wrong. It is badly wrong when the service looked at nothing at all, because both cases produce the same empty result, and v0.1.0 published both as a passing check.

Two independent conditions now have to hold before Gate shows you a grade:

  1. Something judged the page. The service stamps whether a model was actually involved. If it says no, or says nothing at all, Gate withholds the grade and publishes a neutral check titled Not judged or Judgment not stated, naming the field that would restore it.
  2. Something was reviewed. The service now reports which routes and viewports it actually looked at, by name. A run that reviewed none of them gets a neutral check titled Nothing reviewed, which says in words that this is not a pass and not a failure, and lists every route it skipped with the reason.

Here is what the second case now publishes, instead of a green Ship:

No grade. The engine reviewed nothing: 0 of 2 requested routes were judged on this run, so the result below describes no page. This run is not a pass and not a failure.

A result with no findings grades ship by construction, which is why this is neutral rather than green: there was nothing to find because nothing was looked at. The routes and the reason each was skipped are listed below.

📋 Coverage: 0 of 2 route(s) reviewed; skipped /pricing, /checkout; viewports skipped: mobile, tablet, desktop.

A review that honestly covered part of your UI is still a real review, still passes, and now names what it missed:

Grade: Ship

No issues found.

📋 Coverage: 1 of 2 route(s) reviewed; reviewed /pricing; skipped /checkout; viewports skipped: tablet.

Not reviewed

  • route /checkout (no preview deployment matched the head SHA)
  • viewport tablet (not configured)

That distinction is deliberate. A partial review should not be punished for being honest about being partial; a review that covered nothing is not a review. The Check Run and the sticky comment apply the identical rule, so the two surfaces cannot disagree, and the Action's own run status reports the same thing as the check.

Setup mistakes now read as setup mistakes

At v0.1.0, several configuration errors surfaced as "The design engine is temporarily unavailable. The PR is not blocked; Gate will retry." That sentence is false for a wrong secret or a mistyped URL. Retrying sends the same wrong value.

  • A wrong shared secret now reads Review not submitted ... HTTP 401 signature_mismatch on the pull request, carrying the service's own status and error code, what to check for that code, and no promise of a retry.
  • An endpoint that is not a URL is caught before a review is attempted. That covers a bare verdict-acme.fly.dev (which is what the Fly, Render and Railway dashboards print at you), a typo'd htp://, and a host:port with no scheme. The neutral check is titled Engine endpoint invalid, shows the value it could not parse, suggests a corrected form, and says "This one does not clear by itself" rather than promising a retry that would change nothing.
  • No critique service configured at all names the two variables you have to set, and says in words that this is not a pass.
  • pnpm demo:live refuses a bad endpoint before starting a browser or a server, so you catch this on a laptop instead of in CI.

Every one of these still ends in a neutral Check Run. No failure of Gate's own is allowed to turn a pull request red.

The listing itself now says a critique service is required

action.yml's description read "Judgment-only design review for your PR preview deployments." It now reads "Judgment-only design review for your PR preview deployments. Requires a critique service you host; none ships here, and without one this action reviews nothing and says so." You see the requirement before you install, not after.

The README workflow now runs as written

The copy-paste workflow on the landing page referenced a deploy step that was never defined, and read .gate.yml out of a workspace it never checked out. Both are fixed. A test now finds every fenced workflow snippet in every markdown file in the repository and fails if any of them reads an output from an undefined step, reads the workspace without actions/checkout, or triggers on pull_request_target, so a snippet added to a new document later is covered without anyone remembering to add it.

Also in this release

  • Dependency advisories cleared across the tree.
  • Routes your critique service skipped are listed on the review, including routes dropped by a per-PR route cap.
  • The pre-rename .designreview.yml config filename and the JUDGMENT_ENGINE_* variables still work, each with a one-line warning naming both the old name and the new one. This is a deprecation, not a supported alias.
  • A result whose schema version does not match is reported as a setup error rather than as an outage.

Verified for this release

From a clean clone of the tagged commit: pnpm install --frozen-lockfile, pnpm build, pnpm typecheck and pnpm lint (eslint --max-warnings=0) all clean, and pnpm test passing at 102 test files, 717 tests, 0 failures. CI is green on the release commit.

Requirements

Node 24 or newer, pnpm 10.34.3, macOS or Linux. In the calling workflow, checks: write and pull-requests: write, and nothing more.

- uses: apatureai/gate@v1

The v1 major tag points at this release.

Honest limitations

None of these are fixed by this release, and they are worth reading before you wire Gate in.

  • Half the system is behind an HTTP contract you have to implement. Every claim about screenshot quality, prompt design or finding accuracy belongs to the critique service. Gate's tests prove Gate's orchestration and delivery. They prove nothing about review quality.
  • Review quality is entirely the service's. The judgment stamp answers "did anything judge this?", not "was the judgment any good?". A service running a real but bad model gets a real, bad review published verbatim.
  • The coverage guarantee depends on the service reporting coverage. A service that omits the field keeps its grade, and the Check Run states in band that Gate cannot confirm the result covers your whole UI. A third-party service that both claims a model ran and omits coverage cannot be caught from the payload, and Gate says so rather than implying a completeness it cannot verify. verdict always reports coverage and refuses to serve a result without it.
  • The Action path constrains hostile pull request code; it does not sandbox it. The ulimit caps, default-deny environment, loopback-redirect refusal and fork gating are real mitigations. The aggregate cgroup-v2 caps that would make them airtight are not implemented. Read the threat model before running this on a repository that accepts fork pull requests.
  • The resource cap is Linux-only, and the process-count half of it needs bash: ulimit -v does not apply on macOS, and ulimit -u does not exist in dash.
  • Windows is not supported. The supervisor relies on POSIX process groups.
  • Nothing fails CI on a new dependency advisory. Both trees audit clean today, but no job enforces that, so the guarantee is only as fresh as the last manual pnpm audit.
  • Billing has never processed a real charge. The Stripe plumbing and tier limits are unit-tested against fakes.
  • Some source comments cite documents that are not in this repository. The load-bearing parts are absorbed into the README; the citations are left in place as the record of why each piece exists.
  • The internal package manifests still read 0.1.0. Nothing here is published to npm, and for a GitHub Action the tag is the version.

MIT licensed.

v0.1.0

Choose a tag to compare

@adiprathapa adiprathapa released this 10 Aug 12:53

Gate runs a pull request's preview build inside a hardened sandbox, hands the verified preview URL to a critique service you supply, and publishes that service's design review back to GitHub as one sticky comment plus a Check Run. It is the GitHub-facing half of a two-part system: it judges and reports, it never edits code, and it never requests contents: write.

This is the first tagged release. Everything below was run against this tag on macOS 15.6, Node 24.14.0, pnpm 10.34.3.

What works today

From a clean clone, with no credentials, no API keys and no network:

  • The sandbox supervisor (packages/action/src/local-serve.ts). Process-group teardown rather than process teardown, a default-deny environment allowlist, hard ulimit caps, and loopback-only readiness probing that refuses an off-loopback redirect instead of following it. pnpm demo runs it against a fixture that forks a worker which traps SIGTERM and refuses to die, so you watch the containment happen. This part stands alone and is worth reading even if you never use the rest of Gate.
  • Review delivery. Sticky-comment upsert, Check Run mapping, and screenshot annotation. pnpm demo:review replays a recorded critique through the real delivery path and writes the exact comment, Check Run payload and annotated PNGs a pull request would have received.
  • Action path orchestration (runAction), covered end to end against a mock engine.
  • The engine client: async job protocol, HMAC signing, schema-version and Zod checks, and fail-closed degradation. A drifted or malformed result publishes nothing rather than a comment full of nulls.
  • Preview login sealing (gate auth), offline against a bundled fixture.
  • The App path (webhooks, BullMQ queue with supersession, Postgres with row-level tenant isolation tested against a non-superuser role), tested against PGlite and in-memory fakes.

573 tests across 92 files, with no live network anywhere in the suite.

What does not work yet

Read this part before wiring Gate into anything.

  • Half the system is not in this repository. Screenshot capture and the vision model sit behind the HTTP contract in packages/types, and no implementation of that contract ships here. With no reachable critique service configured, every review ends in a neutral Check Run saying exactly that, and nothing else is published. Writing that service is roadmap item 1, and it is the biggest single unlock.
  • The Action path constrains hostile pull request code; it does not sandbox it. The ulimit caps, environment allowlist, redirect refusal and fork gating are real mitigations. The aggregate cgroup-v2 caps that would close the gap are roadmap item 6. Read the threat model in the README before running this on a repository that accepts fork pull requests, and never on pull_request_target with repository secrets in scope.
  • The resource cap is Linux-only. ulimit -v does not apply on macOS, so the demo honestly reports applied no there. ulimit -u does not exist in dash, so the capped command runs under /bin/bash when it is present.
  • Windows is not supported. The supervisor relies on POSIX process groups.
  • uses: apatureai/gate@v0.1.0 does not resolve as a Marketplace action yet. The Action is a Docker action defined by action.yml and Dockerfile.action; publishing it is roadmap item 8.
  • Nothing is published to npm. All packages are private: true. Clone and build.
  • Billing has never processed a real charge. The Stripe plumbing and tier limits are unit-tested against fakes.
  • Dependency advisories are open. pnpm audit at the root reports 7 (1 moderate, 6 high) and apps/dashboard reports 4 high. The exact packages and which reach runtime are listed in roadmap item 5. Re-audit before deploying.
  • Baseline before/after comparison is built but unwired. packages/delivery/src/baseline.ts is tested; nothing on the review path calls it.

Quickstart

Needs Node 24 or newer and pnpm 10.34.3. No credentials.

git clone https://github.com/apatureai/gate.git
cd gate
git checkout v0.1.0
pnpm install --frozen-lockfile

pnpm demo          # the sandbox supervisor, live, against a hostile fixture app
pnpm demo:review   # a full design review comment, from a recorded critique, written to ./out

pnpm demo succeeds when the last line reads PASS, the teardown census ends in 0 left with orphans: 0, and the environment section reports leaked none. On a fresh clone you will see exactly eight gate bin warnings during install; they are explained in the README and disappear after pnpm build.

pnpm demo:review succeeds when four files land in out/, including out/review-comment.md and out/annotated-f_001.png with a red box drawn around the off-palette call to action.

Verified at this tag:

pnpm build       tsc -b, clean, exit 0
pnpm typecheck   tsc -b, exit 0
pnpm lint        eslint . --max-warnings=0, exit 0
pnpm test        Test Files  92 passed (92)
                      Tests  573 passed (573)

The README has the full quickstart, the threat model, the critique service contract, the configuration reference, and the roadmap. Contributions are welcome; the roadmap is the list of things most worth doing.

MIT licensed.