feat(install): collapse Caddy to TLS-only, drop PUBLIC_PATHS, add --no-tls (ADR-0001 Child B — refs #54)#59
Merged
Conversation
…o-tls (ADR-0001 Child B — refs #54) Wave 2 of ADR-0001: demote Caddy to a dumb TLS terminator + reverse proxy. All auth now lives in FastAPI (password + session cookies + Bearer — Child A surface). Two-source drift around PUBLIC_PATHS goes away because there is no second source anymore. Caddyfile --------- packaging/caddy/Caddyfile.template collapses from 107 → 42 lines (the directive block itself is the 10-line ADR §1 form; remainder is doc header + commented-import seam). Drops the global basicauth block, the /chat handle_path, the /v1 handle, the @public path matcher, and the default basicauth handler. Renders into a single TLS-terminating reverse_proxy 127.0.0.1:8080. API --- src/hal0/api/middleware/auth.py: delete PUBLIC_PATHS frozenset + require_token_unless_public dependency. git grep PUBLIC_PATHS returns zero hits in src/ (remaining mentions are doc / changelog comments). src/hal0/api/__init__.py: rewire routers — wizard endpoints + auth endpoints + /v1/models mount auth-free; admin routers still carry Depends(require_token); /v1 splits into v1.public_router (models probe) + v1.router (inference, auth-required). Installer --------- installer/install.sh: remove --auth=basic and the admin-credential prompts. Add --no-tls (skip Caddy entirely; bind 0.0.0.0:8080). The default path installs Caddy with the new minimal template; --no-tls binds the API directly. Env vars rename HAL0_HOSTNAME → HAL0_PUBLIC_HOST to match the template. Auth self-test removed (no edge auth to round- trip against). HAL0_TLS_DIRECTIVE auto-resolves to "internal" for *.local / localhost and to the ACME contact email otherwise. Wizard UI (real integration) ---------------------------- ui/src/views/FirstRun.vue: insert a new "Set up password (optional)" step before the model picker. Probes /api/auth/status on mount and auto-skips when a password is already set. Submit POSTs to /api/auth/password (the public first-run path from Child A); Skip advances without setting one (open-mode posture, surfaced in the install summary). UI builds cleanly with vite. Harness ------- tests/harness/installer-test.sh: drop the auth-basic row. Add tls-default (asserts the rendered Caddyfile is the minimal form — no basicauth / @public, reverse_proxy line present) and no-tls (asserts Caddy unit absent, hal0-api binds 0.0.0.0, /api/auth/status reports auth_mode=open). HAL0_HARNESS_AUTH env knob renamed to HAL0_HARNESS_TLS. Tests ----- tests/api/test_no_public_paths.py: new — asserts the PUBLIC_PATHS symbol is gone, asserts every formerly-public path stays reachable without credentials, asserts a writer route still 401s without auth. 15 new tests, all green. tests/api/test_auth_middleware.py: drop the /api/install/curated-models case from the protected-routes parametrize (wizard endpoint is now public by design). Out of scope (Child C will land): - installer/README.md, PLAN.md, FINDINGS.md edits - closing #43 / #51 CI: Hal0ai org Actions are billing-blocked; verified locally with PYTHONPATH=<worktree>/src uv run --no-sync pytest — 869 passed, 3 skipped, 4 deselected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 17, 2026
thinmintdev
added a commit
that referenced
this pull request
May 17, 2026
…d C — refs #54) (#60) Wave 2, Child C of ADR-0001. Documentation pass for the auth collapse shipped in PRs #58 (Child A — FastAPI password + session cookies + dual cookie/Bearer middleware) and #59 (Child B — Caddyfile reduction + PUBLIC_PATHS deletion + --no-tls flag + HAL0_PUBLIC_HOST / HAL0_HARNESS_TLS rename). installer/README.md ------------------- Rewrites the auth section to describe the single FastAPI auth layer. Drops every reference to --auth=basic / HAL0_ADMIN_USER / HAL0_ADMIN_PASSWORD / HAL0_HOSTNAME / Caddy basic_auth / htpasswd. Documents the --no-tls flag (FastAPI binds 0.0.0.0:8080, reachable at http://<host>:8080/). Renames HAL0_HOSTNAME to HAL0_PUBLIC_HOST in the env-var table. Adds an "Upgrade notes (pre-v1)" subsection explaining that existing --auth=basic installs lose edge auth on upgrade and the two mitigations — set a password in the wizard, or --no-tls behind your own reverse proxy. Calls out the wizard's password-setup step (POST /api/auth/password, public on first run per Child A). PLAN.md ------- §1 "Auth + reverse proxy" rewritten to reflect the single FastAPI layer and a "Trust posture" subsection: hal0 defaults to open on the LAN; password auth is opt-in via the dashboard wizard; programmatic clients use Bearer tokens unchanged from #29. Drops the Caddy basic_auth / PUBLIC_PATHS prose; narrows Caddy's scope to TLS termination + reverse proxy. §10 (harness flags) renames HAL0_HARNESS_AUTH → HAL0_HARNESS_TLS to match what the harness scripts actually look for. docs/api-errors.md ------------------ Adds a brief note in the 401 section linking to ADR-0001 / PR #58 and naming the new endpoints (POST /api/auth/login, /api/auth/logout, /api/auth/password). The envelope shapes themselves are unchanged. tests/harness/FINDINGS.md ------------------------- Prepends "FIXED BY ARCHITECTURE REMOVAL (ADR-0001)" notes to the three historical entries that the auth collapse renders structurally unrepeatable: §10 (Caddy basic_auth swallows PUBLIC_PATHS — the original #28 critical bug, fixed in PR #49 and now historical because Caddy no longer has matchers or basicauth per PR #59), §16 (basic_auth password unrecoverable post-install — source of the #43 HITL decision, fixed by deletion because credential capture moved into the wizard per PRs #58 + #59), and §21 (/api/metrics/prometheus orphan in PUBLIC_PATHS — fixed by deletion because PUBLIC_PATHS is gone). The original report bodies are preserved verbatim below each note for historical reference. Re-run instructions updated to the new HAL0_HARNESS_TLS knob. README.md, tests/harness/README.md ---------------------------------- Sync the auth-posture summary in the repo root README and the harness opt-in flags table to match the new single-FastAPI model and the HAL0_HARNESS_TLS rename. These weren't called out in the spec but were left stale after Child B; updating them keeps the docs internally consistent. Closes #43 and #51 (per the parent ADR plan). Issue close comments follow the merge via the gh CLI; this PR body is the GH-semantics hook in case the manual close doesn't land. closes #43 closes #51 refs #54 refs #57 Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
thinmintdev
added a commit
that referenced
this pull request
May 21, 2026
ADR-0001 (Collapse edge auth into FastAPI) is implemented. Child A (#58 — FastAPI password auth), Child B (#59 — Caddyfile reduction + --no-tls), and Child C (#60 — docs pass) all landed. Flips the header from Proposed → Accepted, records proposal/acceptance dates separately, names the implementing PRs, and appends an Outcome section summarizing what shipped against the original Decision. Adds #28 (the critical basic_auth ordering bug) to the closed-on-land list per tests/harness/FINDINGS.md §10. README.md and installer/README.md were already brought into line with the v1 single-FastAPI-layer reality in PR #60 — no further changes needed there.
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.
Wave 2 of ADR-0001 (refs #54, lands the breaking change Child A unblocked).
ADR:
docs/adr/0001-collapse-edge-auth-into-fastapi.md. Parent issue: #54. Spec: #56.Summary
PUBLIC_PATHSfrozenset +require_token_unless_publicdependency. Route publicness is now declared by NOT attaching an auth dep atinclude_router(...)time — no allowlist, no two-source drift class of bugs (Caddy basic_auth swallows PUBLIC_PATHS allowlist — first-run wizard unbootstrappable #28, PUBLIC_PATHS duplicated in Python + Caddyfile — needs single source of truth #51).--auth=basic+ admin-credential prompts frominstaller/install.sh. Add--no-tlswhich skips Caddy entirely and binds FastAPI on0.0.0.0:8080(right path for hosts behind an existing reverse proxy).ui/src/views/FirstRun.vue— probes/api/auth/statuson mount, auto-skips when a password is already set, otherwise renders a "Set up password (optional)" step that POSTs to/api/auth/password(Child A's first-run public path).Files touched, by concern
packaging/caddy/Caddyfile.template(-89 / +24, 107 → 42 lines — the directive block itself is the 10-line ADR §1 form; remainder is doc header + commented-import seam)PUBLIC_PATHSdeletion + router rewiringsrc/hal0/api/middleware/auth.py,src/hal0/api/__init__.py,src/hal0/api/routes/v1.py(split intopublic_router+router),src/hal0/api/routes/health.py(doc comment)installer/install.sh(drop--auth=basic, add--no-tls, renameHAL0_HOSTNAME→HAL0_PUBLIC_HOST, auto-picktls internalvs ACME based on hostname)ui/src/views/FirstRun.vue(new step 1 = password; picker/license/install/done renumber to 2/3/4/5; auto-skip whenpassword_set)tests/harness/installer-test.sh(dropauth-basic; addtls-default+no-tls),scripts/harness.sh(renameHAL0_HARNESS_AUTH→HAL0_HARNESS_TLS)tests/api/test_no_public_paths.py(new, 15 tests),tests/api/test_auth_middleware.py(drop/api/install/curated-modelsfrom the protected-routes parametrize — wizard endpoint now public by design)git grep PUBLIC_PATHSreturns zero hits insrc/andpackaging/. Remaining mentions live indocs/adr/0001-...,tests/harness/FINDINGS.md, and a couple of historical comments — Child C will sweep those.Caddyfile LoC delta
packaging/caddy/Caddyfile.template: 107 → 42 lines (-65 net). The actual Caddy directives went frombasicauth+@public pathmatcher + 3handleblocks +handle_path /chat*(~70 effective lines) down to:{$HAL0_PUBLIC_HOST:hal0.local} { tls {$HAL0_TLS_DIRECTIVE:internal} encode zstd gzip reverse_proxy 127.0.0.1:8080 }Wizard UI: real or scaffolded?
Real integration.
ui/src/views/FirstRun.vuegot a new step 1 (password) inserted before the picker. It probes/api/auth/statuson mount; ifpassword_setis already true the step auto-skips to the picker. Submit calls the public-on-first-runPOST /api/auth/password. Skip advances without setting one. Step renumber: picker 1→2, license 2→3, install 3→4, done 4→5. Build verified withvite build.Test results
15 new tests in
tests/api/test_no_public_paths.pyall green. The auth + installer regression suite (211 tests acrosstest_auth_*+test_password_auth+test_installer_routes) all green.Out of scope — Child C lands these
Per the ADR's three-PR plan:
installer/README.md,PLAN.md,tests/harness/FINDINGS.mddoc sweepsDo NOT close #54 on merge — Child C still needs to land.
CI heads-up
Hal0ai org Actions are billing-blocked; PR CI will fail in ~2s with no logs. Verified locally with the
PYTHONPATH=<worktree>/src uv run --no-sync pytestinvocation above. User will admin-merge.🤖 Generated with Claude Code