Skip to content

fix(credentials): complete key-store durability follow-ups - #705

Closed
yxlyx wants to merge 1 commit into
mainfrom
fix/405-credential-durability
Closed

fix(credentials): complete key-store durability follow-ups#705
yxlyx wants to merge 1 commit into
mainfrom
fix/405-credential-durability

Conversation

@yxlyx

@yxlyx yxlyx commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Closes #405 after the symlink-policy portion landed separately in #685.

What changed

  • Sync the exact destination directory retained by createFileAtomic after an atomic credential-file replacement on POSIX.
  • Exercise the real non-macOS file-backed key store through merge/load, repeated read-modify-write, restrictive-mode, nested-target, and temp-file cleanup cases.
  • Describe the actual platform security model consistently: macOS Keychain, POSIX mode 0600, and inherited home-directory ACLs on Windows.

Why

Problem / failure mode

Atomic replacement synced the new file contents but not the directory entry, so a hard power loss could lose the rename. Reopening the containing directory from the destination path after replacement would add a race: a symlinked parent could be retargeted between rename and fsync, causing the wrong directory to be synced or reporting failure after the replacement already succeeded. The Linux/Windows key-store path also lacked live-platform test coverage, and user-facing help overstated Windows as providing POSIX 0600 semantics.

Reason for this approach

createFileAtomic already retains the exact directory handle used for its temporary file and rename. Syncing atomic.dir after atomic.replace pins the actual destination directory without a second path traversal. Tests use the real file-backed storeKey path on its live platforms and verify preservation and permissions rather than duplicating serialization logic in a mock.

Constraints and trade-offs

Windows keeps its existing weaker durability/security model: directory FlushFileBuffers is not portable and Zig file modes do not express Windows ACLs, so the implementation relies on atomic replacement, synced file contents, and the containing home-directory ACL. The docs now say this explicitly. Multi-process read-modify-write locking is a separate pre-existing concern and is outside #405's deferred items.

Rejected alternatives

  • Reopening dirname(dest) after rename was rejected because pathname resolution can race with symlink-parent retargeting.
  • Duplicating the symlink policy was rejected because fix(credentials): write atomically through symlinks #685 already implemented and merged item 1.
  • Claiming 0600 on Windows was rejected because .default_file carries no equivalent ACL guarantee.

Verification

  • scripts/eval-tier1.sh: green (1865 passed + 1 platform skip, 465/465 TUI, 17/17 PTY).
  • Final pre-push rerun: fmt, line ceiling, spec, reachability, build, 1865 + 1 skip, 465/465 TUI, invariants, and SDK all passed; one unrelated intermittent test-tui-resize-anchor.py probe missed a repaint once and then passed immediately via python3 scripts/test-tui-resize-anchor.py zig-out/bin/graff.
  • Independent focused review validated atomic.dir lifetime and the path-race fix; no in-scope blockers remain.

Atomic credential replacement synced file contents but not the containing directory, so a hard power loss could lose the rename. Sync the exact destination directory retained by createFileAtomic after replacement, avoiding a path-reopen race if a symlinked parent changes concurrently.

Exercise the real Linux/Windows file-backed key-store path through repeated merge/load cycles, and describe its platform security accurately: POSIX files use mode 0600, while Windows inherits the home directory ACL. The separately merged symlink policy remains item 1 of #405; this commit completes items 2–3 without duplicating it.

Co-Authored-By: Codegraff <blackfloofie@codegraff.com>
@justrach

Copy link
Copy Markdown
Owner

Folded onto release/v0.0.283 as fe158a8 (PR #703). #405 is closed. This PR can be closed as superseded once you are happy the fold is intact.

@justrach

justrach commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Shipped in v0.0.283 via #703 (fe158a8). Closing as superseded — not merging this branch to main.

@justrach justrach closed this Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

credential_store follow-ups: symlink semantics, keys_cli coverage, dir fsync

2 participants