Repository navigation
feat(bundles): every app with a web page says how its first admin is created, and Crow tells you to finish setup when it can't do it for you - #791
Merged
Conversation
…created, and Crow tells you to finish setup when it can't do it for you A freshly installed app's own first-run admin page could be claimed by anyone or anything on the machine before the owner got there. Every bundle with a web UI now declares firstAdmin: crow (Crow creates it, with a keychain-stored generated secret or a post-install step), finish-setup (the first visitor claims it), default-login (it ships a known login) or none. The registry check fails a web-UI bundle without one. After installing a finish-setup or default-login app, its Extensions page shows 'Finish <app>'s setup now' with a link (or 'restart Crow first' when the proxy route is not live yet) and a Done button, and the bell rings once. The markers are per install and never sync. Claude-Session: https://claude.ai/code/session_015Vve3soBJ9qTcyeCCLyYyh
… open in a new tab again, and Plex is flagged Review follow-ups: - A crow declaration now names how: via env with secretEnv (a keychain- generated variable the compose file actually uses) or via postInstall (a script that reads one). A token that is not the admin password no longer passes. - Nest tiles for proxied apps open in a new tab again, exactly as before. - Plex can be claimed by the first Plex account until it has a claim token: finish-setup. ntfy has nothing to claim: none. immich and kodi connect to an app you already run: a new external mode. changedetection gets a note to set its password. - The bell rings even when the install half-fails, an installed web app with no declaration is treated as finish-setup, a failed proxy mount no longer reads as 'restart pending', and the Done endpoint returns a fixed error message. Claude-Session: https://claude.ai/code/session_015Vve3soBJ9qTcyeCCLyYyh
kh0pper
force-pushed
the
feat/bundle-first-admin
branch
from
November 6, 2026 16:21
68be76c to
8a8c54d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Security audit N3-4, phase 1.
A freshly installed app's own first-run admin page could be claimed by anyone or anything on the machine before the owner got there. An audit VM run showed another account reaching uptime-kuma's setup page on loopback first.
The operator ruled that Crow creates the app's first admin where the app supports it, with a random password in the keychain, and that every other app gets a "finish this app's setup now" notice. This phase adds the declaration, the check and the notice. Converting more apps to Crow-created admins comes in later PRs. No compose or env file changes here.
firstAdminin the manifest (schema plusbundle-contract.mjsrules). There are five modes:crow: Crow creates the admin, and the declaration says how:via: "env"withsecretEnv, which must be a keychain-generated variable that the compose file actually uses;via: "postInstall", whose script must read one.A token that isn't the admin password (vaultwarden's
/admintoken, for example) does not pass.finish-setup: the first visitor claims it.default-login: the app ships a known login. Requiresuser.external: it connects to an app you already run, and that app's login applies.none: no login of its own.Every bundle with a
webUImust declare one, andbuild-registry --checkfails otherwise.Declared on every web-UI bundle (42 manifests, patch bumps so installed copies refresh):
crow: actual-budget, maker-lab-advanced, miniflux, minio, unsloth.default-login: shiori, motioneye.finish-setup: uptime-kuma, gitea, forgejo, vaultwarden (signups stay open until you turn them off), plex (claimable by the first Plex account until it has a claim token), changedetection (set its password), frigate, paperless and the other first-visit apps.external: immich, kodi.none: ntfy (nothing to claim: deny-all, no signup), the token-gated browser, and the apps with no login of their own.After installing a
finish-setupordefault-loginapp (also an installed web-UI bundle with no declaration, such as a community bundle, and also when the install half-fails):The developer docs describe
firstAdminand prefercrowwhenever an app can take an admin from env or a CLI.Tests:
firstAdminfailing the check;crowpasses its rule;Nest tiles are unchanged: proxied apps still open in a new tab, pinned by a test against the previous output.
After deploy, existing
finish-setupinstalls show the card once, without a bell.Host:
build-registry --checkandcheck-port-allocationpass. 1600 tests pass across the bundle, manifest, registry, extensions, keychain, install, i18n, design-system, settings-scope, nest and public-hygiene files.Next phases, tracked in the private engineering notes:
crow, each checked against its pinned image;webUIfor seven federated apps that have admin pages but nowebUItoday;post-install.shscripts that nothing runs.https://claude.ai/code/session_015Vve3soBJ9qTcyeCCLyYyh