You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Skip symbolic links during traversal
`find-replace` uses `File.Info()` (a thin wrapper around `os.Stat`) to
decide whether a directory entry is a directory. `os.Stat` follows
symbolic links, so any symlink inside the working tree was transparently
resolved and walked — letting `find-replace` rewrite file contents and
rename files inside the symlink's target, anywhere on the filesystem.
This violates the documented contract ("Searches are performed
recursively from the current working directory") and is a real
privilege-escalation primitive when the tool is run with elevated
permissions (CI, root). See issue #2 for the reproducer.
Fix: in `WalkDir`, check the `fs.ModeSymlink` bit on the
`fs.DirEntry` returned by `os.ReadDir` and skip the entry before it
reaches `HandleFile`. The DirEntry already carries the symlink-bit from
the underlying `getdents64`/`readdir` call, so no extra `lstat` is
needed. The skip is logged as "Skipping symlink: <path>" so the
behavior is visible to operators.
No CLI surface change: there is intentionally no `--follow-symlinks`
opt-in flag in this commit. That would be additive and is filed as a
follow-up. Issue #13 (drop the per-entry `os.Stat` in `HandleFile`) is
related but requires a separate refactor of `HandleFile`'s dispatch and
is left for a follow-up.
Tests cover: outside-the-root file targets, outside-the-root directory
targets, inside-the-root targets (the symlink is still skipped, the
real path is still rewritten exactly once), broken symlinks (silently
skipped, no error recorded), and sanity checks for regular files and
directories.
Fixes#2
* Probe symlink capability instead of skipping by GOOS
Review feedback on #68: rather than blanket-skipping the symlink tests
when runtime.GOOS == "windows", explicitly probe for the ability to
create a symlink and skip on actual failure. That way the tests run
wherever the capability is available (e.g. a Windows runner with
SeCreateSymbolicLinkPrivilege, a sandboxed container that happens to
allow symlink creation) and are correctly skipped on a host that lacks
it (including a non-Windows host with a restrictive seccomp/AppArmor
profile or filesystem).
The probe is a t.Helper named requireSymlinks that creates a real
symlink in a fresh t.TempDir; if Symlink returns an error, the test
t.Skips with that error embedded so it's clear why.
The Windows guards in TestWalkDir_PermissionDeniedSubdirContinues and
TestWriteCleansUpTempFileOnRenameFailure are intentionally kept: those
skips are about non-symlink semantic differences (permission bits and
rename-onto-directory), not symlink capability.
---------
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments