The deploy pipeline watched a VERSION file that does not exist, so a
version bump built the image but never deployed it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The web interface could create a vault and never remove one, so the only
way to undo a mistake was the CLI. There is now a Delete link on every
vault you administer, leading to a page that says what is about to go —
owner, versions stored, grants pointing at it — and asks for your
account password before it goes.
The gate is re-authentication, not a confirmation checkbox. A session
token is enough to read and write a vault; it should not be enough to
erase every version of one, because a session is what an unlocked
laptop leaves lying around. The one-time code is required too when the
account has one enrolled.
It lives in confirmDeletion, so the rule holds wherever deletion is
reachable: DELETE /api/v1/databases/{id} now takes {password, totp?}
and answers 401 without it, and keeporg db -delete prompts. That is a
breaking change to the endpoint, which is why the server goes to 0.7.0
and the desktop clients to 0.4.0.
An account that signs in only through an identity provider has no
password to type. Rather than lock those deployments out of deleting
anything, they confirm by typing the vault's exact name — the weaker
gate, and deliberately the fallback.
Deleting takes the record, its grants, every stored version and the key
a merge vault left with the server, and tells the watchers over SSE.
Copies already in people's mirror directories stay where they are: the
server stops tracking a vault, it does not reach into anybody's home
directory.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
location / covered /invite/{token}, /oidc/callback, /device and
/healthz along with the web interface, so Vouch stood in front of all
of them. An invite link was the worst of it: it goes to somebody who has
no account anywhere yet, and Vouch bounced them to a login they cannot
pass. The OIDC callback was fragile for a different reason — the
authorization code it carries is single-use and short-lived, and a
second login round trip is a poor place to spend it.
Those four paths now proxy straight through. KeepOrg authenticates each
of them itself: an invite is a capability token, the callback is checked
against its state, a device code expires in ten minutes, and /healthz is
unauthenticated by design. /web keeps Vouch in front of it, and /api was
already exempt.
The proxy settings move to the server block, where every location
inherits them, and the upstream becomes a named block. location / has to
repeat the headers in full: a location that sets one proxy_set_header
replaces the inherited set rather than adding to it.
Checked with nginx -t and against a running keeporgd with a 401 standing
in for Vouch: /, /web and /web/* redirect to auth.tiredsysadmin.cc,
while /healthz, /invite/, /device and /oidc/* serve KeepOrg's own pages
and /api returns KeepOrg's 401.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Running the server meant running the API by hand: invites, accounts,
groups and grants existed only as endpoints and CLI commands, so the
browser could create a vault and nothing else.
/web/groups walks the group tree and opens onto one group's members,
roles and vault access, including the grants it inherits from above and
where they come from. /web/users lists the accounts you may see, and
lets a server administrator disable, enable, clear a lost second
factor, promote, demote or delete one. /web/invites shows the
outstanding links with their use counts, issues new ones and revokes
them.
Every administrative change is now a function of the state and the
caller in admin.go, which both the JSON handlers and the forms call. The
alternative was a second copy of the permission rules behind the pages,
which would have drifted on the first change. The same move gave the API
the two verbs it was missing: DELETE /api/v1/invites/{token} and
PATCH /api/v1/users/{id}.
Account changes are server-administrator only. A group administrator
decides who reaches which vault; disabling an account or clearing
somebody's second factor reaches past the group they share. Disable and
delete revoke that account's sessions, and the three changes that would
lock the caller out are refused on their own account.
Pages go through webPage and forms through webForm, so the session and
CSRF checks cannot be forgotten on a new form. No page carries any
JavaScript.
Server 0.6.0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>