Skip to content

fix(config): stop lowercasing filesystem paths - #613

Open
YpNo wants to merge 1 commit into
tale:mainfrom
YpNo:fix/config-path-lowercasing
Open

fix(config): stop lowercasing filesystem paths#613
YpNo wants to merge 1 commit into
tale:mainfrom
YpNo:fix/config-path-lowercasing

Conversation

@YpNo

@YpNo YpNo commented Aug 19, 2026

Copy link
Copy Markdown

Closes #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:

  • server.data_path
  • headscale.config_path
  • headscale.dns_records_path
  • headscale.tls_cert_path

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, since it is where the
Headplane database lives: /srv/Headplane gets a database at /srv/headplane instead, and roles and sessions simply appear to be missing.

server.cookie_domain deliberately 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.

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-case data_path, mixed-case Headscale paths, and one asserting cookie_domain is 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_domain one still passes.

pnpm run typecheck and pnpm run lint clean, 203 unit tests passing.

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>
@YpNo
YpNo requested a review from tale as a code owner August 19, 2026 20:16
@github-actions github-actions Bot added the Config Related to Headplane specific configuration label Aug 19, 2026

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Stop lowercasing filesystem paths — drops the arktype string.lower morphing operator from server.data_path, headscale.config_path, headscale.dns_records_path, and headscale.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.ts assert mixed-case paths round-trip unmodified, plus a guard that cookie_domain is 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.

Pullfrog  | View workflow run | Using DeepSeek Pro (free via Pullfrog for OSS) | 𝕏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Config Related to Headplane specific configuration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

server.data_path and other path options are silently lowercased

1 participant