Commit Graph
2 Commits
Author SHA1 Message Date
officer b1b9e2afc3 a way to actually connect it
Deleting the old UI took its connection panel with it, so the plugin installed,
opened, and had nowhere to type a URL. The frame would have loaded and answered
503 on every request inside it — which reads as Gitea being down rather than as
nobody having said where Gitea is.

The panel now asks for the connection FIRST and shows the form when there is
none.

Two halves, and which one you get depends on who you are: the URL is the
owner's, one instance per server, and everyone else supplies only a token and
inherits it. Not a UI choice — service_connections stores a member's row with a
null URL for exactly this reason, so "members never see the instance URL" is a
property of the schema rather than a filter somebody has to remember.

Defaults to http://localhost:3000 and says why in the field: the sidecar
fetches SERVER-side, so localhost means the machine Officer runs on. It needs
no TLS and never leaves the box, where the public URL takes the same traffic
out and back.
2026-08-19 08:36:05 +00:00
officer f680e25f82 gitea: the plugin, rendering Gitea's own interface
Eleventh plugin out, and the first that is not a move. The seventeen files that
reimplemented a fraction of Gitea's interface were deleted rather than carried
across — each one a promise to keep pace with a project that moves faster than
this plugin will.

That removed a platform change nobody now has to build. useGiteaLocation read
:owner/:name/:tab/:item from five route patterns and a plugin gets two, so
extracting as-is would have needed the plugin system to declare extra routes.
Nothing inside an iframe needs a route, so the requirement went with the screen.

No regression window: gitea's router had been commented out of hono.ts since
2026-08-13 with api: [], and officer-gitea was running nowhere. The screen
rendered and every request 404'd.

The proxy is what makes the iframe possible, not decoration. Officer and Gitea
are different registrable domains, so a frame pointed straight at the instance
gets a login page whose cookie the browser drops as third-party. Through
Officer's origin it is first-party and survives; X-Frame-Options and CSP are
stripped, safe only because the frame is the origin the browser already
authenticated.

/_web/* forwards the browser's own cookies and injects NOTHING. The sidecar
holds an API token and injecting it there would show every user the owner's
view of every repository. It is used only by /_api/*.

Two doors, because an iframe's sub-resources carry no Authorization header:
the ordinary routes go through the platform's gate, and /_web/* is declared
unauthenticated and authenticates itself with a minted, path-scoped cookie —
32 random bytes against the user who asked, not dev-proxy's constant =1 which
anyone knowing the cookie name can set. Verifying it also sets `user`, because
createSidecarProxy fills X-Officer-User from it and the sidecar refuses a
request without one.

Ships an affordance: git for what git does, tea for pull requests and issues.
Nothing copies it into capabilities/ yet — gitea is that mechanism's first
customer.
2026-08-19 07:58:55 +00:00