Skip to content

fix(settings): refuse boot on a nested directory that serves no tenant - #711

Merged
taitelee merged 2 commits into
mainfrom
fix/settings-empty-root-refuses-boot
Oct 1, 2026
Merged

taitelee merged 2 commits into
mainfrom
fix/settings-empty-root-refuses-boot

Conversation

@taitelee

@taitelee taitelee commented Oct 1, 2026

Copy link
Copy Markdown
Member

Summary

A settings.dir holding folders but none of the four files is read as nested. When every folder was rejected, or none was named by a tenant id (a fresh volume whose only entry is lost+found, a parent directory mounted by mistake), settings.Open still returned a registry and the server came up serving no tenant, answering every tenant route unknown tenant. Before #598 that root refused boot.

Boot now refuses a nested root that would serve no tenant, with the findings plus one naming the rule, through the same path a flat invalid root takes, so the error still points at wavehouse validate and wavehouse bootstrap. The rule is boot's alone: a whole-directory reload that finds every folder gone or broken still drops every tenant and keeps running (#611), and wavehouse validate is unchanged. A root with one valid folder beside a rejected or stray one still boots and serves that tenant, and an empty or missing root still refuses as the four files, missing.

Test plan

  • settings.Open refuses a root whose every folder is rejected, and a root whose only folder is lost+found, each with the findings
  • settings.Open on one valid folder beside a broken one and a stray one opens and serves the valid tenant
  • Existing pins unchanged: an emptied directory on reload removes every tenant and keeps running; empty and missing roots refuse as "config.json: missing"; wavehouse validate exit codes
  • make ci passes locally, integration and e2e included

Related Issues

Closes #599
Part of #583

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: a0938615-3057-4fd2-a121-26ef0a8529ef

📥 Commits

Reviewing files that changed from the base of the PR and between 9100b45 and 7da05f8.

📒 Files selected for processing (10)
  • AGENTS.md
  • CHANGELOG.md
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/deployment.md
  • docs/src/content/docs/settings-directory.mdx
  • internal/app/app_test.go
  • internal/app/wire.go
  • internal/settings/registry.go
  • internal/settings/registry_test.go
  • internal/settings/tree.go

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (5)
Source excerpt: In a Docker / Podman / Kubernetes deployment, **`data_dir` must resolve to a host-backed volume**.

📄 CodeRabbit inference engine (docs/src/content/docs/deployment.md)

Files:

  • docs/src/content/docs/deployment.md
Source excerpt: | Change | Files to update | | ------ | --------------- | | Change architecture / add a package | `docs/src/content/docs/architecture.md`, `AGENTS.md` |

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • docs/src/content/docs/architecture.md
  • AGENTS.md
Source excerpt: **wire.go** — one `wire*` function per component, each handed the settings registry whole and deriving the per-call getters the internal packages take (`DLQFor`, `DedupeFor`, `GapWindow`, …) and registering its `AfterAdopt`...

📄 CodeRabbit inference engine (docs/src/content/docs/architecture.md)

Files:

  • internal/app/wire.go
See [AGENTS.md](../AGENTS.md) for project conventions, architecture notes, and AI agent instructions.

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Files:

  • AGENTS.md
Source excerpt: **Docs prose**: never hard-wrap Markdown — one paragraph is one line.

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Files:

  • docs/src/content/docs/settings-directory.mdx
  • docs/src/content/docs/architecture.md
  • docs/src/content/docs/deployment.md
  • AGENTS.md
  • CHANGELOG.md
🪛 LanguageTool
docs/src/content/docs/architecture.md

[style] ~223-~223: This word has been used in one of the immediately preceding sentences. Using a synonym could make your text more interesting to read, unless the repetition is intentional.
Context: ...eps running. The tenant map is replaced whole by a reload, so a lookup is one lock-fr...

(EN_REPEATEDWORDS_WHOLE)

CHANGELOG.md

[typographical] ~98-~98: Consider using an em dash in dialogues and enumerations.
Context: - **A settings directory holding only fol...

(DASH_RULE)

🔇 Additional comments (10)
internal/settings/tree.go (1)

24-33: LGTM!

internal/settings/registry.go (1)

37-41: LGTM!

Also applies to: 90-94, 201-205

internal/settings/registry_test.go (1)

224-228: LGTM!

Also applies to: 230-264

internal/app/app_test.go (1)

902-903: LGTM!

Also applies to: 905-909, 955-956, 958-958, 962-962

internal/app/wire.go (1)

60-61: LGTM!

AGENTS.md (1)

48-48: LGTM!

CHANGELOG.md (1)

98-98: LGTM!

docs/src/content/docs/architecture.md (1)

223-223: LGTM!

docs/src/content/docs/deployment.md (1)

568-568: LGTM!

docs/src/content/docs/settings-directory.mdx (1)

22-22: LGTM!


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Startup now refuses to proceed when a nested settings directory contains no valid tenant to serve.
    • Reloading a nested settings directory with no valid tenants removes the tenants’ active settings while keeping the server running. Invalid tenant folders continue to be handled independently when other valid tenants are present.

Walkthrough

Nested settings roots with no serving tenant now fail at boot. Reloads can apply the same empty tree, remove all tenants, and keep the process running. Flat-directory behavior and validation behavior remain unchanged.

Changes

Nested settings tenant availability

Layer / File(s) Summary
Boot and reload behavior
internal/settings/tree.go, internal/settings/registry.go, internal/settings/registry_test.go, internal/app/app_test.go, internal/app/wire.go, AGENTS.md, CHANGELOG.md, docs/src/content/docs/*
Tree.serves checks whether any tenant has a document. Open rejects nested trees with no serving tenant, while reload can apply an empty tree and remove all tenants. Tests cover boot refusal, valid tenants alongside rejected or unrecognized folders, and reload behavior. Documentation describes the boot and reload behavior.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: ericandrechek

Merge Risk: ⚪ Minimal · up to 7da05

Nested settings roots that serve no tenant now refuse to boot, while reloads and validation behave as before. No merge-blocking risk was identified.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 7da05

The change tightens startup validation without broadening tenant access. Instances with no valid tenant configuration now refuse startup, while existing reload and recovery behavior remains intact. No introduced security weakness was identified in the inspected paths, but verification was limited to the affected lifecycle and tenant-routing controls.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The new failure condition affects application instances opening a nested settings root with no usable tenant document. Its controlling input is the settings-directory contents; the inspected tenant-request resolution path does not provide authority to change that root or invoke the boot-only branch.

Security Findings and Attack Paths

  • observed — The three concrete public-entrypoint routing ranges resolve to Go test functions exercising startup, keepalive fallback, and gap-window recovery. Their changes do not introduce production request handlers or new remotely callable operations.

Trust Boundaries and Controls

  • observed — The startup change strengthens configuration admission without replacing tenant-keyed lookup. Existing controls refuse rejected tenants, skip unrecognized folder names, and retain service for valid tenants beside them.

Resilience and Maintainability Implications

  • observed — Failure containment is explicit: rejected boot returns no registry before downstream wiring, whereas empty nested reload remains an allowed transition with a tested restoration path. The new check does not add a resource reservation or cleanup obligation.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Issue [#599] requires boot refusal when a nested settings.dir serves no tenant. internal/settings/registry.go checks tree.Nested && !tree.serves() during boot and returns no registry with a `no …
Out of Scope Changes check ✅ Passed The changes remain within Issue [#599]. Registry code changes add the boot-only no-tenant refusal and preserve the reported reload behavior. Tests verify the new boot cases and related existing behavi…
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 5 files. (5 skipped: 5 …
Title check ✅ Passed The title clearly and concisely describes the main change: refusing boot when a nested settings directory serves no tenant.
Description check ✅ Passed The description directly explains the boot behavior change, preserved reload behavior, test coverage, and related issue.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
✨ Simplify code
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added documentation Improvements or additions to documentation go Pull requests that update go code area/docs Documentation, site/, README area/app Process wiring (internal/app): component build, run, release labels Oct 1, 2026
@github-actions

github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

📚 Docs preview is live → https://9ee4f67b-wavehouse-docs.wave-rf.workers.dev

  • Commit — 7da05f8: docs(settings): note the no-tenant boot refusal in architecture.md and AGENTS.md
  • Author — @taitelee
  • Committed — 2026-10-01 11:57 (UTC-04:00)
  • Deployed — 2026-10-01 13:05 EDT

@github-code-quality

github-code-quality Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: Go

Go

The overall line coverage in commit 7da05f8 in the fix/settings-empty-r... branch remains at 93%, unchanged from commit 6fa9723 in the main branch.

Show a line coverage summary of the most impacted files.
File main 6fa9723 fix/settings-empty-r... 7da05f8 +/-
internal/mq/embedded.go 90% 90% 0%
internal/ingest/worker.go 97% 97% 0%
internal/app/wire.go 93% 93% 0%
internal/settings/registry.go 100% 100% 0%
internal/settings/tree.go 100% 100% 0%
internal/app/discoveries.go 97% 100% +3%

Updated October 01, 2026 17:10 UTC

@taitelee

taitelee commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@taitelee
taitelee marked this pull request as ready for review October 1, 2026 17:02
@taitelee
taitelee requested review from a team and EricAndrechek October 1, 2026 17:02
@taitelee
taitelee merged commit 32e03a0 into main Oct 1, 2026
32 checks passed
@taitelee
taitelee deleted the fix/settings-empty-root-refuses-boot branch October 1, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/app Process wiring (internal/app): component build, run, release area/docs Documentation, site/, README documentation Improvements or additions to documentation go Pull requests that update go code

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

bug(settings): a settings.dir holding only folders now boots and serves no tenant

1 participant