Skip to content

docs(plans): scope Caddy form-based auth (caddy-security plugin)#129

Merged
smartwatermelon merged 4 commits intomainfrom
claude/docs-caddy-forms-auth-plan-641492
Apr 20, 2026
Merged

docs(plans): scope Caddy form-based auth (caddy-security plugin)#129
smartwatermelon merged 4 commits intomainfrom
claude/docs-caddy-forms-auth-plan-641492

Conversation

@smartwatermelon
Copy link
Copy Markdown
Owner

@smartwatermelon smartwatermelon commented Apr 19, 2026

Summary

  • Adds docs/plans/2026-04-19-caddy-forms-auth.md — a task-by-task implementation plan for replacing Caddy's basic_auth with a form-based login that 1Password can auto-fill.
  • Not implementing today. This is a scoping doc so the work is ready to pick up cleanly later.

Approach (from the plan)

Rebuild the custom Caddy binary with the caddy-security plugin alongside the existing caddy-dns/cloudflare module. Same pattern already used for DNS-01. JWT session cookie, bcrypt password hash in a users.json, single user, no MFA. LAN bypass matcher is preserved.

Effort estimate: ~5–6 hours wall-clock across 8 tasks. Rollback procedure and deliberately-parked follow-ups (MFA, OIDC, per-path auth) are documented in the plan.

Test plan

  • markdownlint --config ~/.config/markdownlint-cli/.markdownlint.json passes
  • Plan file is self-contained — each task has file paths, exact commands, expected output
  • (Deferred to execution) implement tasks 1–8 when prioritized

🤖 Generated with Claude Code

Tracks #130.

Plan for replacing basic_auth with a form-based login so 1Password can
auto-fill. Single user, no MFA, JWT session cookie, local bcrypt store.
Custom Caddy rebuild with caddy-security alongside existing
caddy-dns/cloudflare — same pattern as the current binary.

Not implementing today. ~5-6 hours wall-clock when picked up. Includes
rollback steps and a list of deliberately out-of-scope follow-ups (MFA,
OIDC, per-path auth) that slot in later without rearchitecting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread docs/plans/2026-04-19-caddy-forms-auth.md
…template

Sentry bug-prediction flagged that Task 5 Step 3 proposed a users.json
template with __MONITORING_EMAIL__ but never instructed extending
caddy-setup.sh's substitute_template() to handle that placeholder. A
future implementer following the plan verbatim would deploy a users.json
containing the literal string __MONITORING_EMAIL__ as the user's email,
which caddy-security's local identity store would reject.

Fix (matches Sentry's primary suggested fix):
- Task 5 Step 3: call out that substitute_template's sed list must add
  -e "s|__MONITORING_EMAIL__|${MONITORING_EMAIL}|g" and that
  caddy-setup.sh must load MONITORING_EMAIL from config.conf.
- Task 6: insert a new Step 1 preflight check that MONITORING_EMAIL is
  non-empty before any substitution runs; renumber the remaining steps.

Post-push loop iteration 1: addresses sentry[bot] finding on
docs/plans/2026-04-19-caddy-forms-auth.md:346

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread docs/plans/2026-04-19-caddy-forms-auth.md Outdated
Sentry bug-prediction flagged that Task 7 Step 6's rollback cp
reference a Caddyfile.pre-forms-auth backup that no prior step creates
— only the binary backup (Task 1 Step 2) and a parenthetical reminder
*after* the rollback command existed. A linear reader would overwrite
the Caddyfile in Step 2 without backing it up first, and discover the
rollback recipe is broken only when they need it.

Fix (matches Sentry's primary suggested fix):
- Insert explicit Task 7 Step 2 "Back up the current deployed Caddyfile"
  before the caddy-setup.sh invocation.
- Renumber subsequent Step 3..8.
- Drop the confusing parenthetical at the old Step 6.
- Update the CLAUDE.md operations-doc bullet that referenced old step 6.

Post-push loop iteration 2: addresses sentry[bot] finding on
docs/plans/2026-04-19-caddy-forms-auth.md:544

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread docs/plans/2026-04-19-caddy-forms-auth.md Outdated
Ran the adversarial reviewer locally on the full plan (not just the one
line Sentry flagged) to catch everything in one pass and stop the CI
ping-pong. Applies every substantive finding plus the previously
uncommitted cross-midnight rollback fix:

- Task 1 Step 3: clarify Homebrew pin is on TILSIT, not dev machine
  (the dev machine builds via the Caddy download API, not brew).
- Task 2 Step 3: JWT keychain install must go through
  `ssh andrewrich@tilsit.local` (not operator) — non-interactive SSH as
  operator cannot run sudo without a TTY, and System keychain writes
  require root.
- Task 5 Step 3: explicit placement instructions for the three
  caddy-setup.sh edits. users.json deploy must happen BEFORE `caddy
  validate` runs, otherwise caddy-security's `local identity store`
  directive sees a missing file and rejects the config.
- Task 5 removes the broken "validate locally" sub-step that referenced
  /tmp/Caddyfile.substituted — a file no prior step produces. Rely on
  caddy-setup.sh's built-in validate after deploy.
- Task 7 Step 2 expected-output strings now match what caddy-setup.sh
  actually emits ("✓ Copied Caddyfile to ..." not "✓ Installed ...").
- Task 7 Step 5 functional tests: split into on-TILSIT (LAN bypass only)
  and from-dev-machine (external path). Previous version ran all curls
  from TILSIT itself, which hits the @local_network matcher and makes
  every external assertion pass for the wrong reason.
- Task 7 Step 7 rollback: uses `ls -t | head -1` glob lookup instead of
  `$(date +%Y%m%d)` reconstruction, which would break if the cutover
  rolls past midnight — exactly when rollback is most needed.

Post-push-loop iteration 3: addresses sentry[bot] cross-midnight finding
(docs/plans/2026-04-19-caddy-forms-auth.md:555) + seven additional
local-review findings caught pre-push, not post-push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread docs/plans/2026-04-19-caddy-forms-auth.md
@smartwatermelon
Copy link
Copy Markdown
Owner Author

Pre-merge note — NEUTRAL checks are benign

  • CodeQL: NEUTRAL — no code files in this diff, so CodeQL had nothing to scan. Details page shows conclusion: skipping, not a finding.
  • Seer Code Review: NEUTRAL — prior iteration reviews were for earlier commits; current HEAD has only plan-doc edits, no re-review triggered.

All findings from the post-push loop on this PR are resolved:

  1. Sentry: users.json / MONITORING_EMAIL substitute_template gap → fixed in 74b0851
  2. Sentry: Caddyfile backup never created before overwrite → fixed in 941df43
  3. Sentry: cross-midnight $(date +%Y%m%d) in rollback → fixed in 6d552d0
  4. Sentry: "id": "__OPERATOR_USERNAME__" needs UUID — deferred to issue feat(caddy): replace basic_auth with form-based login (1Password-friendly) #130 (not fixing in this scoping PR, executor will address at implementation time)

Consolidated exhaustive local-review pass in 6d552d0 also addressed seven additional findings pre-push.

Safe to merge.

@smartwatermelon smartwatermelon merged commit 0816550 into main Apr 20, 2026
8 checks passed
@smartwatermelon smartwatermelon deleted the claude/docs-caddy-forms-auth-plan-641492 branch April 20, 2026 00:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant