Open cipherboy opened 1 month ago
Hey @cipherboy!
The util
package contains a RemoveAll(fs billy.Basic, path string) error function that can be used to that effect.
However, a native RemoveAll
within the Basic interface would come handy, but I don't see that working before v6
as you mentioned. Feel free to submit a PR to add that targeting the v6-exp
branch, which is where we are keeping the changes for v6
.
As for the os_bound
implementation, go-billy
is primarily focused on supporting go-git
. So I am not sure your specific use case would fit that bill. The os_bound
already has an arbitrary $PWD
, which is immutable. I am not sure how different that is from your version.
\o hey @pjbgf -- regarding the last point, I ran across this when working across multiple repos: https://github.com/go-git/go-git/issues/1155#issuecomment-2242778023
It seems this only works if dir == .
and $PWD
is the root of the desired Git repository. Otherwise, when I had say, dir=repos/some-repo
, every operation in the repository involving simlinks resulted in them being prefixed with dir
, rewriting links from say lib->lib64
on checkout to become lib->repos/some-repo/lib64
. I was working across multiple repositories, so continually updating the app's $PWD
for the desired repo to edit would've maybe been possible but likely would've been a bit of work.
I think the issue with this is it's unsafe for sandbox execution/bypass; you don't want to necessarily allow or follow symlinks to arbitrary places on disk if you're a git repo provider. But if you're using known repositories it probably isn't as much an issue.
Let me see if I can create a better reproducer.
@pjbgf Hmm, looks like it was simpler than I thought. Check out this code:
https://github.com/cipherboy/testbed/tree/master/go-git-repo-symlink
In particular, the current mode (dir=.
with $PWD=repo/example
) fails with:
panic: failed walking commits: failed iterating over commit object: failed to checkout commit ("97f28a73331c05fe8bfda6561f7e3786dc31c622"): remove bin/bash: no such file or directory
or similar depending on what file gets executed first.
But the other one has the error I remember:
panic: failed walking commits: failed iterating over commit object: failed to checkout commit ("36f532a4ff85e64af9683daa8dfbe157df3c8dae"): open repos/example/lib64: no such file or directory
Both of these hashes are (the freshly generated) repo's initial commit. lib
is a symlink to lib64
; both were added in the second commit.
With my hacky filesystem, both methods pass.
The implementation essentially looks like this:
i.e., a very simple one with a bunch of:
if !filepath.IsAbs(link) && !strings.HasPrefix(link, fs.baseDir) {
link = filepath.Join(fs.baseDir, link)
}
in relevant places.
@cipherboy thanks for clarifying and sharing the code. I think the current implementation is mistakenly trying to remove the target instead of the symlink. However, the safeguards in place to restrict deletion of things outside of the repository dir are blocking that from taking place. The bug here is that we are doing a Stat
instead of a Lstat
here.
Would you be keen to propose a PR to fix this?
I was wanting to call the equivalent of
os.RemoveAll(...)
on a worktree's filesystem and ended up implementing support for it here and ingo-git
(the latter was a trivial change only inRepositoryFilesystem
; would this change be welcomed here?I suspect ideally this would be implemented as an optional additional interface to not break backwards compatibility (existing user would have to implement the interface on upgrade), but maybe it would be best for a v6 to simplify the interface? Thoughts?
I also ended up implementing a non-chroot'd version (similar to
osfs/os_bound.go
, but taking into account an arbitrary$PWD
different from the actual$PWD
at the time of execution), but I'm not sure that changeset has relevance outside of my use case. :-) Let me know if it is also of interest though!