Skip to content

fix: add lock on config.yaml to prevent TOCTOU coruption#50

Open
Zack (Zackaryia) wants to merge 3 commits into
mainfrom
zshamsi/fix-config-filelock
Open

fix: add lock on config.yaml to prevent TOCTOU coruption#50
Zack (Zackaryia) wants to merge 3 commits into
mainfrom
zshamsi/fix-config-filelock

Conversation

@Zackaryia
Copy link
Copy Markdown

Add race_test.go that demonstrates IIP-20714: multiple concurrent read-modify-write cycles on config.yaml without file locking causes invalid YAML, empty file reads, and silent data loss.

@Zackaryia Zack (Zackaryia) changed the title test: reproduce config file corruption from concurrent CLI instances fix: add lock on config.yaml to prevent TOCTOU coruption May 21, 2026
Add race_test.go that demonstrates IIP-20714: multiple concurrent
read-modify-write cycles on config.yaml without file locking causes
invalid YAML, empty file reads, and silent data loss.
@Zackaryia Zack (Zackaryia) force-pushed the zshamsi/fix-config-filelock branch 2 times, most recently from 7b5b0e5 to f13abb7 Compare May 22, 2026 16:05
Concurrent CLI invocations race on config.yaml through the non-atomic
read-modify-write in New() (viper.WriteConfig + addDocCommentsToYAML).
Wrap the entire critical section in an exclusive flock via gofrs/flock.
@Zackaryia Zack (Zackaryia) force-pushed the zshamsi/fix-config-filelock branch from f13abb7 to 378f62c Compare May 22, 2026 16:09
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This change is because the file lock fails before writing fails, so we need to edit the error message. Permission denied makes more sense in context.

Comment thread internal/config/config.go
Comment thread internal/config/config.go
Comment on lines +144 to +146
if os.Getenv("RACE_WORKER") != "1" {
t.Skip("skipping: only runs as subprocess of TestRaceConditionEndToEnd")
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there any downside to always enable the running of this test?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

It would fatal from no RACE_DATA_DIR env var.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ah, what if we just made a temp directory with t.TempDir()?

I might be misunderstanding what the test is doing, but in principle I feel like we should be able to run this in CI

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Because we need all the processes to use the same config file to test the race condition we'd have to still have RACE_DATA_DIR.

We could do TempDir as a fallback so that when this is individually ran it wont fatal but then the test name wont make sense.

Comment thread internal/config/config_test.go Outdated
@Zackaryia Zack (Zackaryia) marked this pull request as ready for review May 22, 2026 20:52
@Zackaryia Zack (Zackaryia) requested a review from a team as a code owner May 22, 2026 20:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants