Abort startup on a config file pixa cannot read (closes #176) #181

Open
clawbot wants to merge 4 commits from issue-176-unreadable-config into next
Collaborator

Closes #176, per its plan.

Of the places pixa looks for its config file on its own, any place where os.Stat failed was passed over, so a file in a directory pixa may not enter was skipped without a word and pixa started on a later file or on the environment and defaults. Now only a file that does not exist is passed over, including one whose path runs through a file, such as under a HOME of /dev/null; any other error aborts startup naming the file, as a file that does not parse already did. README.md says so where it gives the search order.

To know: a directory pixa may not enter on one of those paths now aborts startup even when no config file is in it, since pixa cannot tell; for example /etc/pixa open only to root, or a HOME that belongs to another user. In the Docker image pixad's HOME is /home/pixad, which does not exist, so the image is not affected.

Disclosures:

  • Judgement call (from the review): a path that runs through a file counts as a file that does not exist.
  • The test for a directory pixa may not enter is skipped as root, where the gate runs the tests; the test with a config.yml that links to itself covers the same change as root.
  • Rule suppressed: //nolint:gosec (G302) on the permission test's cleanup, which gives the directory back 0o700 so t.TempDir can remove it.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/pixa/issues/176, per its plan. Of the places pixa looks for its config file on its own, any place where `os.Stat` failed was passed over, so a file in a directory pixa may not enter was skipped without a word and pixa started on a later file or on the environment and defaults. Now only a file that does not exist is passed over, including one whose path runs through a file, such as under a `HOME` of `/dev/null`; any other error aborts startup naming the file, as a file that does not parse already did. `README.md` says so where it gives the search order. To know: a directory pixa may not enter on one of those paths now aborts startup even when no config file is in it, since pixa cannot tell; for example `/etc/pixa` open only to root, or a `HOME` that belongs to another user. In the Docker image pixad's `HOME` is `/home/pixad`, which does not exist, so the image is not affected. Disclosures: - Judgement call (from the review): a path that runs through a file counts as a file that does not exist. - The test for a directory pixa may not enter is skipped as root, where the gate runs the tests; the test with a `config.yml` that links to itself covers the same change as root. - Rule suppressed: `//nolint:gosec` (G302) on the permission test's cleanup, which gives the directory back `0o700` so `t.TempDir` can remove it. Model: opus-5-5
clawbot added the needs-review label 2026-10-04 13:33:41 +02:00
clawbot self-assigned this 2026-10-04 13:33:41 +02:00
Author
Collaborator

FAIL (needs-rework)

  1. internal/config/config_validation_internal_test.go: the new test never runs in the gate, which runs the tests as root, where it is skipped, so nothing there guards the change. The same failure can be made as root: a config.yml in the working directory that is a symbolic link to itself makes os.Stat fail with "too many levels of symbolic links"; a test built on it fails before the fix and passes after it, as root too. Acceptable: a test the gate runs, such as that one; the permission test may stay beside it.

  2. internal/config/config.go, loadConfigFile: a search path that runs through a regular file now aborts startup, though no file can be there. For example, a service account whose HOME is /dev/null, with no file in /etc/pixa, now fails with "not a directory" on /dev/null/.config/pixa/config.yml, where before pixa went on to the working directory and then the environment. README.md says only a file that does not exist is passed over, which this one is. Acceptable: pass over "not a directory" (syscall.ENOTDIR) as well as "does not exist", with a test (for example HOME set to a regular file); README.md and the code comment then hold as written.

Judgement call: finding 2 reads the plan's "does not exist" as covering a path through a regular file, since no file can be there.
Disclosure: TODO.md conflicted with next; I resolved it locally (both entries, this one on top) to review.

Model: opus-5-5

**FAIL** (needs-rework) 1. `internal/config/config_validation_internal_test.go`: the new test never runs in the gate, which runs the tests as root, where it is skipped, so nothing there guards the change. The same failure can be made as root: a `config.yml` in the working directory that is a symbolic link to itself makes `os.Stat` fail with "too many levels of symbolic links"; a test built on it fails before the fix and passes after it, as root too. Acceptable: a test the gate runs, such as that one; the permission test may stay beside it. 2. `internal/config/config.go`, `loadConfigFile`: a search path that runs through a regular file now aborts startup, though no file can be there. For example, a service account whose `HOME` is `/dev/null`, with no file in `/etc/pixa`, now fails with "not a directory" on `/dev/null/.config/pixa/config.yml`, where before pixa went on to the working directory and then the environment. `README.md` says only a file that does not exist is passed over, which this one is. Acceptable: pass over "not a directory" (`syscall.ENOTDIR`) as well as "does not exist", with a test (for example `HOME` set to a regular file); `README.md` and the code comment then hold as written. Judgement call: finding 2 reads the plan's "does not exist" as covering a path through a regular file, since no file can be there. Disclosure: `TODO.md` conflicted with `next`; I resolved it locally (both entries, this one on top) to review. Model: opus-5-5
clawbot added needs-rework and removed needs-review labels 2026-10-04 14:59:13 +02:00
clawbot force-pushed issue-176-unreadable-config from 4de726f109 to 4637026bc4 2026-10-04 15:21:15 +02:00 Compare
clawbot added 4 commits 2026-10-04 15:36:10 +02:00
Of the places pixa looks for its config file on its own, a file in a
directory pixa may not enter is passed over today and pixa starts
without it. This test puts the config file in such a directory and
expects startup to abort with an error naming the file. It is skipped
when run as root, which may enter any directory.

Model: opus-5-5
Of the places pixa looks for its config file on its own, it passed over
any place where os.Stat failed, so a file in a directory pixa may not
enter was skipped without a word and pixa started on a later file or on
the environment and defaults. Now only a file that does not exist is
passed over; any other error aborts startup naming the file, as a file
that does not parse already did. README.md says so where it gives the
search order.

Model: opus-5-5
The test for a directory pixa may not enter is skipped as root, where
the gate runs the tests. A config.yml in the working directory that is
a symbolic link to itself fails os.Stat as root too, and must abort
startup. A config path that runs through a file, such as one under a
HOME of /dev/null, cannot hold a file and must be passed over like one
that does not exist; today it aborts startup.

Model: opus-5-5
Of the places pixa looks for its config file on its own, one whose path
runs through a file, such as under a HOME of /dev/null, aborted startup
with "not a directory", though no file can be there. It is now passed
over like a file that does not exist, as README.md says.

Model: opus-5-5
clawbot force-pushed issue-176-unreadable-config from 4637026bc4 to 7f52b5bb3f 2026-10-04 15:36:10 +02:00 Compare
clawbot added needs-review and removed needs-rework labels 2026-10-04 15:44:12 +02:00
Author
Collaborator

Rework of #181 (comment), rebased onto next:

  1. New test TestConfigFileLinkingToItselfAbortsStartup, which runs as root: a config.yml in the working directory that links to itself must abort startup. The permission test stays.
  2. loadConfigFile now passes over syscall.ENOTDIR as well as "does not exist", with the code comment saying so; new test TestConfigPathThroughFileIsPassedOver sets HOME to /dev/null. README.md holds as written.

Model: opus-5-5

Rework of https://git.eeqj.de/sneak/pixa/pulls/181#issuecomment-123724, rebased onto `next`: 1. New test `TestConfigFileLinkingToItselfAbortsStartup`, which runs as root: a `config.yml` in the working directory that links to itself must abort startup. The permission test stays. 2. `loadConfigFile` now passes over `syscall.ENOTDIR` as well as "does not exist", with the code comment saying so; new test `TestConfigPathThroughFileIsPassedOver` sets `HOME` to `/dev/null`. `README.md` holds as written. Model: opus-5-5
Some checks are pending
check / check (push) Waiting to run
You are not authorized to merge this pull request.
This pull request can be merged automatically.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin issue-176-unreadable-config:issue-176-unreadable-config
git checkout issue-176-unreadable-config
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/pixa#181