Skip to content

2026-07-16-github-trigger-on-pluggable-app-free-auth-plan.md #24

2026-07-16-github-trigger-on-pluggable-app-free-auth-plan.md

2026-07-16-github-trigger-on-pluggable-app-free-auth-plan.md #24

# REQ-UPSTREAM-CONTRACT-TESTS — the pi upgrade gate.
#
# Asserts the assumptions pi-dispatch pins about pi, and fails the build when one stops holding.
# CONST-PI-VERSION-PINNED makes an upgrade an explicit commit that edits a version string, so this
# workflow is what turns that commit into a gate rather than a hope.
#
# Every assertion below covers a failure that is SILENT. A crash reports itself and needs no test;
# these do not. Each maps to a point where a claim about pi was verified, believed, and later refuted:
# - "appendSystemPrompt composes with file discovery" -> it REPLACES it, via a `??`
# - "createAgentSession reloads the loader you pass" -> only one it built itself
# - "-nc is a flag you remember" -> it is an object you forget to build
# - "pi never throws" -> its own JSDoc says otherwise
# Each was found by reading source, not by running code. These tests are what catch the next one.
name: pi upgrade check
on:
push:
paths:
- "image/**"
- "worker/**"
- "receiver/**"
- "guardrails/**"
- "package.json"
- ".github/workflows/pi-upgrade-check.yml"
pull_request:
paths:
- "image/**"
- "worker/**"
- "receiver/**"
- "guardrails/**"
- "package.json"
- ".github/workflows/pi-upgrade-check.yml"
schedule:
# Weekly: pi ships breaking changes between minors and its HEAD moved within 24h of this
# project's design being written. A pin that is never exercised rots silently.
- cron: "0 6 * * 1"
workflow_dispatch:
jobs:
version-pin:
name: pins are exact (CONST-PI-VERSION-PINNED)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: No floating ranges on pi packages
run: |
# A floating range turns a silent upstream minor into every queued job becoming a
# no-op with no signal, because the queue still reports success.
if grep -rnE '@earendil-works/pi-[a-z-]+@[\^~]|"@earendil-works/pi-[a-z-]+":[[:space:]]*"[\^~]' image/ package.json; then
echo "::error::Floating range on a pi package. CONST-PI-VERSION-PINNED requires an exact pin."
exit 1
fi
echo "OK: pi pinned exactly"
- name: Base image is pinned by digest
run: |
# Same reasoning, different vendor. A floating base tag is the identical silent break.
if ! grep -qE '^FROM .*@sha256:[0-9a-f]{64}' image/Dockerfile; then
echo "::error::Base image is not digest-pinned in image/Dockerfile."
exit 1
fi
echo "OK: base pinned by digest"
no-automatic-merge:
name: no automatic merge (CONST-MERGE-NEVER-AUTOMATIC)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: No merge API call anywhere
run: |
# CONST-MERGE-NEVER-AUTOMATIC: "grep is the test". A match is a merge symbol reaching
# the code — the human review step is the last line and is not negotiable.
if grep -rnE 'pulls\.merge|gh pr merge|mergePullRequest|merge_pull_request|[Aa]utoMerge|/pulls/.*/merge' worker/src image/runner receiver/src; then
echo "::error::Merge symbol found. CONST-MERGE-NEVER-AUTOMATIC forbids any merge call."
exit 1
fi
echo "OK: no merge symbols"
contract-tests:
name: pinned assumptions still hold (offline, no API key)
runs-on: ubuntu-latest
services:
# A real Valkey backs the queue integration test (enqueue + dedup). AOF is not needed for a
# test run; the point is a genuine Redis-protocol server, not the fake.
valkey:
image: valkey/valkey:8
ports:
- 6379:6379
options: >-
--health-cmd "valkey-cli ping" --health-interval 10s --health-timeout 3s --health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc" # pi requires >=22.19.0; engine-strict enforces it
- run: npm ci --no-audit --no-fund
# The scariest assertions in this project are FREE: every trap lives at the resource-loader
# boundary (pure) or at before_agent_start (which fires strictly before any provider HTTP
# call). No API key, no tokens, no flake, no excuse not to run them on every build.
#
# PI_DISPATCH_REQUIRE_*_TESTS=1 turns a skip into a hard failure. A skipped assertion is an
# UNVERIFIED assertion, and "skipped = pass" is precisely the reasoning that lets a
# guardrail-less agent ship green. VALKEY_TEST_URL activates the queue integration test.
- name: Contract tests -- guardrails, -nc, exit codes, env allowlist, queue, receiver enqueue (all required)
env:
PI_DISPATCH_REQUIRE_LOADER_TESTS: "1"
PI_DISPATCH_REQUIRE_WORKER_TESTS: "1"
PI_DISPATCH_REQUIRE_RECEIVER_TESTS: "1"
VALKEY_TEST_URL: "redis://127.0.0.1:6379"
run: npm test
image:
name: the job image holds its contract
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: docker build -f image/Dockerfile -t pi-job:ci .
# --- INT-SDK-SESSION-OPTIONS ---
# `pi --mode print` does not exist: --mode accepts text|json|rpc, and --print/-p is a separate
# boolean. --help rather than a real prompt, because a real prompt needs a paid API key and a
# contract test that costs money is a contract test that gets disabled.
# --entrypoint is required: ENTRYPOINT is the runner and ignores CMD, so `docker run img pi ...`
# would silently run the runner instead of pi and the assertion would test nothing.
- name: pi -p is still a flag
run: docker run --rm --entrypoint pi pi-job:ci -p --help >/dev/null
# --- CONST-ISOLATION-CONTAINER-PER-JOB ---
# --cap-drop=ALL is the enforcement surface. Read the effective capability set directly rather
# than install libcap just to ask.
- name: No capabilities under --cap-drop=ALL
run: |
caps=$(docker run --rm --cap-drop=ALL --security-opt no-new-privileges \
--entrypoint sh pi-job:ci -c 'grep ^CapEff /proc/self/status' | awk '{print $2}')
[ "$caps" = "0000000000000000" ] || { echo "::error::Container retains capabilities: $caps"; exit 1; }
echo "OK: CapEff=$caps"
- name: Runs as a non-root user
run: |
uid=$(docker run --rm --entrypoint id pi-job:ci -u)
[ "$uid" != "0" ] || { echo "::error::Job container runs as root."; exit 1; }
# --- INT-CONTAINER-JOB-INPUTS ---
# /job:ro is what makes CONST-ISSUE-TEXT-IS-DATA enforceable by filesystem permission rather
# than by asking nicely. It is a security boundary, so assert the kernel enforces it.
- name: /job is genuinely read-only from inside
run: |
mkdir -p fixture/pi
echo "x" > fixture/pi/APPEND_SYSTEM.md
if docker run --rm --cap-drop=ALL -v "$PWD/fixture:/job:ro" --entrypoint sh pi-job:ci \
-c 'echo pwned > /job/pi/APPEND_SYSTEM.md' 2>/dev/null; then
echo "::error::/job is writable. The agent can rewrite its own instructions."
exit 1
fi
echo "OK: /job:ro enforced"
# --- INT-CONTAINER-RUNTIME-CONTRACT ---
# pi lazily creates ~/.pi/agent and writes auth.json on the FIRST credential operation. If the
# dir is root-owned the job dies EACCES at runtime, on a path nothing in the Dockerfile hints
# at. COPY --chown does not fix it (it skips auto-created parents), so assert the real thing.
- name: The agent dir is writable by the runtime user
run: docker run --rm --entrypoint sh pi-job:ci -c 'touch "$HOME/.pi/agent/auth.json" && rm "$HOME/.pi/agent/auth.json"'
- name: The guardrails are baked where the runner reads them
run: |
docker run --rm --entrypoint grep pi-job:ci -q "pi-dispatch-guardrails-v1" /opt/pi-dispatch/HARD_RULES.md \
|| { echo "::error::Guardrails sentinel missing from /opt/pi-dispatch/HARD_RULES.md"; exit 1; }
# --- DES-PLAYWRIGHT-CLI-NOT-CHROME-DEVTOOLS / REQ-FRONTEND-VISUAL-VERIFY ---
# Root-installed Chromium lands in /root/.cache/ms-playwright, invisible to the non-root user
# CONST-ISOLATION-CONTAINER-PER-JOB requires. --shm-size, NOT --ipc=host: Playwright recommends
# the latter, but it shares the HOST IPC namespace with a container running adversarial-input
# agent code. The crash it prevents is caused by a 64MB /dev/shm, so fix that instead.
#
# This asserts REAL rendering, not merely "a PNG exists". An earlier version opened a file://
# URL -- which playwright-cli BLOCKS by default -- so it screenshotted about:blank and passed
# on a blank page: green and vacuous. Two corrections: (1) navigate over http, which is what a
# frontend job actually does (a dev server), and which is not blocked; (2) diff the screenshot
# against a blank baseline, so a blank or all-tofu page FAILS. A non-empty PNG proves nothing;
# a PNG that differs from about:blank proves the browser painted the page.
# Two assertions that a NON-VACUOUS test needs, both learned the hard way:
# - The page is served over HTTP (a dev server, what a frontend job hits), not file:// --
# playwright-cli BLOCKS file:// by default, so the old test screenshotted about:blank and
# passed green on a blank page.
# - Correctness is proven by finding a MARKER in the page snapshot, not by diffing the
# screenshot against blank. When the server is down, `open` renders Chrome's own
# connection-refused error page, which ALSO differs from blank -- so a pixel diff passes on
# an error page. The DOM snapshot containing our marker proves the real page loaded.
# - The page is passed via env, not a bind mount: mounts are the one thing that behaves
# differently across host OSes, and this must not depend on that.
# Both directions verified locally: a dead server makes the marker absent and the step fails.
- name: Chromium renders a real page as non-root
run: |
docker run --rm --init --cap-drop=ALL --security-opt no-new-privileges --shm-size=1g \
-e PAGE='<html><body style="background:#f00"><h1 style="color:#fff">RENDER-CHECK-MARKER</h1></body></html>' \
--entrypoint sh pi-job:ci -c \
'node -e "require(\"http\").createServer((_,r)=>{r.writeHead(200,{\"content-type\":\"text/html\"});r.end(process.env.PAGE)}).listen(8099)" & sleep 1;
playwright-cli open http://localhost:8099 >/dev/null 2>&1;
playwright-cli snapshot 2>&1 | grep -q RENDER-CHECK-MARKER || { echo "page did not load — chromium could not navigate/render"; exit 1; };
playwright-cli screenshot --filename /tmp/s.png >/dev/null 2>&1;
test -s /tmp/s.png || { echo "no screenshot produced"; exit 1; }' \
|| { echo "::error::Chromium did not render a real page. Check PLAYWRIGHT_BROWSERS_PATH (build+run), PLAYWRIGHT_MCP_BROWSER, PLAYWRIGHT_MCP_SANDBOX, fonts."; exit 1; }
# Fonts: a weaker, independent check. The render diff above already catches a totally blank
# page; this catches "fonts package silently dropped" specifically. Neither proves LEGIBILITY
# (that needs OCR, which is not worth it here) -- honest about what it does and does not show.
- name: Fonts are installed
run: |
n=$(docker run --rm --entrypoint sh pi-job:ci -c 'fc-list | wc -l')
[ "$n" -gt 0 ] || { echo "::error::No fonts. Chromium renders tofu; REQ-FRONTEND-VISUAL-VERIFY degraded."; exit 1; }
echo "OK: $n fonts"