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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

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

opened this

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 with identityHeaders from src/apps/proxy.ts, the same function and app identity key the proxy uses to sign a person. The caller is a fixed PULL_CALLER (forge|forge|admin), and the signature expires after PULL_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 runs pullApp over loopback against the template's real makeHandler, keyed with identityKey(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

Closes #10082

commented

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 with identityHeaders from src/apps/proxy.ts, the same function and app identity key the proxy uses to sign a person. The caller is a fixed PULL_CALLER (forge|forge|admin), and the signature expires after PULL_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 runs pullApp over loopback against the template's real makeHandler, keyed with identityKey(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

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs