Summary
In internal/sshconfig/writer.go, the AddHost function performs a read-check-write sequence (read existing hosts → check for duplicate aliases → append new host) that is not atomic. Under concurrent --add invocations, two goroutines/processes can both pass the duplicate-alias check and each append a Host block, resulting in duplicate entries in the SSH config file.
Affected code
internal/sshconfig/writer.go — AddHost function, specifically the readExistingHosts → alias comparison loop → append/write sequence.
Suggested fix
Wrap the entire read/check/write sequence with an exclusive file lock (e.g. flock / syscall.Flock on Linux/macOS) or use an atomic temp-file-and-rename approach:
- Open (or create) the SSH config file.
- Acquire an exclusive lock before calling
readExistingHosts.
- Perform the alias comparison and decision (return existing host or error).
- Append/write the new host block while still holding the lock.
- Release the lock only after the file has been fully updated.
Context
Raised during code review in PR #1 by @coderabbitai. Deferred to a follow-up issue so PR #1 stays focused on the --add/--find feature work.
PR reference: #1
Comment reference: #1 (comment)
/cc @machugram
Summary
In
internal/sshconfig/writer.go, theAddHostfunction performs a read-check-write sequence (read existing hosts → check for duplicate aliases → append new host) that is not atomic. Under concurrent--addinvocations, two goroutines/processes can both pass the duplicate-alias check and each append aHostblock, resulting in duplicate entries in the SSH config file.Affected code
internal/sshconfig/writer.go—AddHostfunction, specifically thereadExistingHosts→ alias comparison loop → append/write sequence.Suggested fix
Wrap the entire read/check/write sequence with an exclusive file lock (e.g.
flock/syscall.Flockon Linux/macOS) or use an atomic temp-file-and-rename approach:readExistingHosts.Context
Raised during code review in PR #1 by @coderabbitai. Deferred to a follow-up issue so PR #1 stays focused on the
--add/--findfeature work.PR reference: #1
Comment reference: #1 (comment)
/cc @machugram