Skip to content

Windows: eagerly bind state directory filesystem identity - #216

Merged
bren-wp merged 4 commits into
mainfrom
hardening/windows-state-directory-eager-identity
Sep 10, 2026
Merged

Windows: eagerly bind state directory filesystem identity#216
bren-wp merged 4 commits into
mainfrom
hardening/windows-state-directory-eager-identity

Conversation

@bren-wp

@bren-wp bren-wp commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Authorization

Problem

A Windows production CI run for #215 exposed an existing failure in TestStoreRejectsReplacementDirectoryAfterBinding: a renamed/recreated state directory was accepted once by the Store.

This is not caused by #215. The root cause is Windows os.SameFile laziness: Go's Windows FileInfo retains the path and resolves VolumeSerialNumber / FileIndexHigh / FileIndexLow on the first SameFile call. If the directory path is replaced before that first call, the historical FileInfo can resolve the replacement object. The existing CreationTime secondary comparison can also collide for rapidly created directories.

Fix

  • Add a platform identity-priming contract.
  • On Windows, call os.SameFile(info, info) immediately while validating/binding the state directory so Go caches its Win32 volume/file-index identity before later path replacement.
  • Fail closed if the identity cannot be resolved reliably.
  • Preserve non-Windows semantics; the non-Windows priming hook is a nil guard only.
  • Keep the existing os.SameFile + CreationTime comparison as defense in depth after both snapshots have been primed.

Deterministic regression

A Windows-only regression test creates and binds the original state directory, renames it, creates a replacement at the original path, deliberately gives the replacement the same CreationTime, and requires the bound identity comparison to reject it.

Change isolation

  • Exactly four files under internal/config.
  • No installer, release, transfer, protocol, UI, telemetry, dependency or VERSION changes.
  • No weakening of recovery behavior: an initially absent/invalid state path may still bind after the caller repairs it, as existing tests require.

Validation gate

Exact final head: 1f4d61f73ac360a1a8068a1d163efc1bd3d25de7.

  • Exact-head Ghost FTP CI completed/success.
  • Core formatting, race/vet, audits and regression suite completed/success.
  • Windows x64/x86 production build completed/success, including the previously failing state-directory tests, release artifact verification and Authenticode smoke.
  • Linux amd64/arm64/i386 production build completed/success.
  • Linux distro package parity completed/success.
  • Debian 13, Ubuntu 26.04 LTS and Fedora 44 install/remove/GUI lifecycle completed/success.

main remained exact 83b5344bebc6b690add09cfe1099aa0acee322d4 before merge and the PR remained mergeable. Merge is guarded by the exact final head SHA. After merge, exact post-merge main push workflows must be verified before #215 is revalidated.

@bren-wp
bren-wp marked this pull request as ready for review September 10, 2026 00:06
@bren-wp
bren-wp merged commit 527e68e into main Sep 10, 2026
5 checks passed
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.

1 participant