fix(config): stop lowercasing filesystem paths - #613
Open
YpNo wants to merge 1 commit into
Open
Conversation
Closes tale#612. `string.lower` rewrites the value it validates rather than rejecting a non-lowercase one, so four options that are filesystem paths were silently changed before use. On a case-sensitive filesystem that is a different path, and it fails quietly: validation succeeds, then Headplane reads or writes somewhere the operator never named. `server.data_path` is the worst of the four because it is where the Headplane database lives. An operator using `/srv/Headplane` gets a database at `/srv/headplane` instead, and roles and sessions simply appear to be missing. `server.cookie_domain` keeps `string.lower`. It is not a path and DNS is case-insensitive, so normalising it there is correct. This also makes the four consistent with `server.tls_cert_path` and `server.tls_key_path`, which were already plain `string`. The tests fail on the previous declarations — I checked by restoring them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Stop lowercasing filesystem paths — drops the arktype
string.lowermorphing operator fromserver.data_path,headscale.config_path,headscale.dns_records_path, andheadscale.tls_cert_path(full and partial variants), so mixed-case paths are used exactly as written. - Test coverage — three new unit tests in
tests/unit/config/path-casing.test.tsassert mixed-case paths round-trip unmodified, plus a guard thatcookie_domainis still lowercased. - Changelog — entry added under
# Next.
The fix is correct: string.lower rewrites the value it validates rather than rejecting non-lowercase input, so on case-sensitive filesystems these paths silently resolved elsewhere — most damagingly server.data_path, where the Headplane database lives. Keeping string.lower on cookie_domain is right, and this aligns the four paths with server.tls_cert_path / server.tls_key_path, which were already plain string. The tests use exact-string assertions and would fail if lowercasing were reintroduced.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
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.

Closes #612.
string.lowerrewrites the value it validates rather than rejecting anon-lowercase one, so four options that are filesystem paths were silently
changed before use:
server.data_pathheadscale.config_pathheadscale.dns_records_pathheadscale.tls_cert_pathOn a case-sensitive filesystem that is a different path, and it fails quietly. Validation succeeds, then Headplane reads or writes somewhere the operator never named.
server.data_pathis the worst of the four, since it is where theHeadplane database lives:
/srv/Headplanegets a database at/srv/headplaneinstead, and roles and sessions simply appear to be missing.server.cookie_domaindeliberately keepsstring.lower. It is not a path and DNS is case-insensitive, so normalising it there is correct.This also makes the four consistent with
server.tls_cert_pathandserver.tls_key_path, which were already plainstring.Behaviour change
Paths are now used exactly as written. Anyone who currently relies on being silently redirected to a lowercase path would be affected, though that seems unlikely to be deliberate.
Testing
Three tests in
tests/unit/config/path-casing.test.ts: mixed-casedata_path, mixed-case Headscale paths, and one assertingcookie_domainis still lowercased so a later change does not undo that on purpose.I restored the old declarations to confirm the tests fail on them — the two path tests fail, the
cookie_domainone still passes.pnpm run typecheckandpnpm run lintclean, 203 unit tests passing.