Every verb ended in `return data as T | any`, and `T | any` collapses to `any` —
so client.get<Foo>() handed back `any` and no annotation downstream meant
anything. That was the source of most of the implicit-any errors: the callbacks
had nothing to infer from.
Returning `as T` drops the whole class (19 errors to 9) rather than annotating
each parameter. Two calls in useAuth were relying on the looseness and now
declare their response shapes.
signin also no longer stores `undefined` as the bearer token when the server
withholds one; that path returns early.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three unrelated type errors that each pointed at something actually broken:
- Dashboard.CodeEditor was deleted in ab03b17 ("Projects") while the
/code-editor route and the dock's Editor item kept pointing at it, so the
route rendered undefined. Screen restored.
- Appearance.tsx imported 'themes', a workspace deleted in 0746844. Nothing
reads settings.appearance.colorTheme and no theme CSS survives, so the picker
was writing a value with no consumer. Removed it and the setting; colorMode
stays, it is live.
- officerdev exported both a component and a type named AppRegistry, so
`import { AppRegistry }` resolved to the type and <AppRegistry /> failed to
typecheck. Renamed the Record type to AppRegistryMap.
Also declares "*.css" so side-effect stylesheet imports resolve.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
resolveUserPath and five sibling checks used startsWith(rootDir), which also
accepts a sibling directory whose name begins with the root's: from a root of
/home/br, "../br-backup/secret" resolves to /home/br-backup/secret and passed.
Compare against root + sep (or the root itself) via a shared isInside helper.
Verified the escape cases now deny while "", ".", and ordinary relative paths
still resolve.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
bodyParser caught parse failures and did nothing — the throw was commented out
and `body` was never set, so handlers destructured undefined and the client got
a 500 for a malformed request. Throw BAD_REQUEST instead.
Also adds the regression tests for the Host suffix match fixed in 2ca850c.
Verified against a running server: malformed JSON now 400, valid credentials
path still 401, spoofed Host still 403.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The no-Origin branch asked whether the configured origin ends with the
client-supplied Host, so `Host: dev` matched https://rezio.pastilhas.dev — as
did `pastilhas.dev` and `o.pastilhas.dev`. Match the URL authority exactly
instead. Officer always runs behind an HTTPS reverse proxy, so the forwarded
Host is expected to equal PUBLIC_URL's authority.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Origin validation, every rate limiter and the password-strength check each
treated an unset PUBLIC_BUILD_ENV as "relaxed", so a deployment that forgot the
variable silently ran with CORS reflecting any origin, no brute-force limit on
the sole account, and no password rules. setup.sh writes it, but .env.example
never mentioned it.
The three now share IS_DEV_BUILD, which is true only when PUBLIC_BUILD_ENV is
explicitly "dev" or "development". Anything else, including unset, is hardened.
Documented in .env.example.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The handler called onOpenChange and navigate, neither of which is in scope in
PipelineRunner — they belong to TaskRunnerModal, declared further down. Clicking
the button after a pipeline finished threw instead of navigating.
PipelineRunner now takes an onClose prop and calls useNavigate itself.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer is single-user: the server owner is the only account, created once by
/auth/bootstrap. Everything that existed to serve additional users was
unreachable, so it is gone rather than left looking like it does something.
Accounts: drop the invite / resend-invite / delete / list-users routes and the
Users settings screen, the inert /auth/signup handler, and the account
verification chain it fed (verify, resend-verification, VerifyScreen, the
UserInvite + VerifyAdmin + VerifyRegistration templates). /auth/verify-token
survives for password resets only, and now requires a reset-password token
rather than accepting any signed JWT.
Roles: drop the users.role column and the four-value USER_ROLES enum. The
permissions table granted every role identical methods, and every
role === 'Super Admin' check was permanently true. The JWT no longer carries a
role claim.
Sandbox: remove sidecar/sandbox.ts and its five call sites. bwrap was selected
only for non-Super-Admin users, so it never ran. It was also not a usable agent
jail as written — --share-net, the project root (with .env) bound read-only,
and runuser dropping to the server's own uid. Rebuilding it for agent
containment would be a different construction, and git history keeps this one.
getHomeDir keeps its DATA_PATH meaning; the new getOwnerHomeDir resolves the
owner's real login home, which is what terminals, chats and task runs use.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>