Public: anyone can read this; the crew can change it.
The forge's scheduled /pull to an adapter carries the signed admin identity, so the template accepts it #10090
Check · Review · Land · Live done — Landed and live in production.
Scheduled `POST /pull` calls are now signed as an `admin`, so an adapter built from `examples/adapter-template` accepts them. Before this, every scheduled pull of the template was recorded as failed.
shipped production is serving it deploy f21b126
Scheduled POST /pull calls are now signed as an admin, so an adapter built from examples/adapter-template accepts them. Before this, every scheduled pull of the template was recorded as failed.
src/apps/pull_schedule.ts:pullIdentity(dataDir, appId)builds the headers withidentityHeadersfromsrc/apps/proxy.ts, the same function and app identity key the proxy uses to sign a person. The caller is a fixedPULL_CALLER(forge|forge|admin), and the signature expires afterPULL_WAIT_MS(10 s).postPull(port, identity, waitMs)adds those two headers and changes nothing else about the request. Only the signed string and its HMAC go out; the key is never in the request or a log.test/pull-schedule.test.ts: a new block runspullAppover loopback against the template's realmakeHandler, keyed withidentityKey(dir, app)and given a fake source.
- Signed, the run is recorded ok with the new cursor, and the test checks that no header contains the key.
- With the signature left off, the run is recorded failed with reason status 401 is not 2xx.
- One existing call changed to the new argument order: postPull(port, {}, 50).
docs/ADAPTERS.md, "The template": now says the scheduled call does carry the signed identity, and how.
The caller's id and name are both the literal forge rather than a real user id. The template only checks that they are not empty, but an adapter that looks those fields up as a forge user would not find one.
Checks: bun scripts/gate.ts and bun x tsc --noEmit pass. scripts/fast.ts said the diff was too broad to name tests (1352 files), so I picked them myself: test/pull-schedule.test.ts, test/adapter-template.test.ts and test/apps-adapter.test.ts all pass, and the full suite is left to the forge's check. I did not keep a plan on the issue with keep_plan, because that tool was not available in this session.
To try it: bun test test/pull-schedule.test.ts. To see the failure this fixes, make pullIdentity return {}: the "signed" test then records a failed run.
🤖 Generated with Claude Code
Scheduled pulls now carry the signed admin identity via identityHeaders under the app identity key, same as the proxy; the key is never sent. Tests run pullApp against the real template handler: ok when signed, failed (401) when not; the docs sentence now states it. Pipeline-neutral, small, no new dependency, no web/TUI surface. Next: (1) tolerate a clock-skew margin on expiresMs if adapters reject near-expired grants; (2) consider a real forge user id for PULL_CALLER if adapters ever look callers up.
Scheduled
POST /pullcalls are now signed as anadmin, so an adapter built fromexamples/adapter-templateaccepts them. Before this, every scheduled pull of the template was recorded as failed.src/apps/pull_schedule.ts:pullIdentity(dataDir, appId)builds the headers withidentityHeadersfromsrc/apps/proxy.ts, the same function and app identity key the proxy uses to sign a person. The caller is a fixedPULL_CALLER(forge|forge|admin), and the signature expires afterPULL_WAIT_MS(10 s).postPull(port, identity, waitMs)adds those two headers and changes nothing else about the request. Only the signed string and its HMAC go out; the key is never in the request or a log.test/pull-schedule.test.ts: a new block runspullAppover loopback against the template's realmakeHandler, keyed withidentityKey(dir, app)and given a fake source.- Signed, the run is recorded
okwith the new cursor, and the test checks that no header contains the key. - With the signature left off, the run is recordedfailedwith reasonstatus 401 is not 2xx. - One existing call changed to the new argument order:postPull(port, {}, 50).docs/ADAPTERS.md, "The template": now says the scheduled call does carry the signed identity, and how.The caller's id and name are both the literal
forgerather than a real user id. The template only checks that they are not empty, but an adapter that looks those fields up as a forge user would not find one.Checks:
bun scripts/gate.tsandbun x tsc --noEmitpass.scripts/fast.tssaid the diff was too broad to name tests (1352 files), so I picked them myself:test/pull-schedule.test.ts,test/adapter-template.test.tsandtest/apps-adapter.test.tsall pass, and the full suite is left to the forge's check. I did not keep a plan on the issue withkeep_plan, because that tool was not available in this session.To try it:
bun test test/pull-schedule.test.ts. To see the failure this fixes, makepullIdentityreturn{}: the "signed" test then records a failed run.🤖 Generated with Claude Code
Closes #10082