Just to point out some related behaviors that make the lack of this feature
particularly surprising (even forehead-slapworthy) in some use cases:
Imagine a user U who can ls, checkout, etc a directory (say, /trunk). That
directory has a subdirectory that is invisible to U (say, /trunk/private). U
will discover to her surprise that she cannot branch /trunk. So U can check out
trunk, but then U can't make a branch, even though U supposedly has write access
to /branches and, as far as U knows, read access to /trunk. Unexpected, eh? :-)
Here's an IRC conversation (massively edited for clarity/flow) about it. Thanks
to danielsh and philipm for thinking through the implementation oddity that
would be involved in fixing this -- clearly the "needsdesign" tag on this bug
report remains accurate.
<kfogel> suppose I have "* = rw" for / of repos R, and a sub-authz
rule for "R:/trunk/private" that says "* = " with the
next line saying "@privategroup = rw".
<kfogel> Now, suppose I have a user U, who is *not* a member
of @privategroup. U tries to make a branch of trunk (and
trunk has a 'private' subdirectory at the time U tries to
make the branch):
<kfogel> svn --username U cp -m "Seeing what happens." \
<kfogel> Now U will get this error:
<kfogel> svn: access to '/repos/R/!svn/bc/2494/trunk' forbidden
<kfogel> Should U be able to make the branch, and just not have a
private/ subdir in the branch? Or is an error the right
reaction? (In which case, the error is quite confusing,
but then again, it kind of has to be, because it can't
reveal the existence of the private subdirectory.)
<danielsh> kfogel: if you allow the branch to be created, what would
'svn log -qvl1' on the resulting revision print for that
<danielsh> kfogel: point is that branches/newbranch/private is NOT
covered by authz rules
<kfogel> The resulting revision (the one that created the branch)
would not *contain* the private/ directory, so there's no
log adjustment to be made anyway. It should just print
<kfogel> (We already have an accepted 'svn log' behavior for
revisions that contain changes to paths one isn't allowed
to see. When I have U do 'svn log' on a revision that
modified something in /trunk/private/, svn has a reasonable
behavior right now -- namely, to show me nothing).
<kfogel> danielsh: if some other user (one who was a member of
@privategroup) had done the cp, things might be different
<kfogel> danielsh: in that case, when that privileged user does "svn
log", they'll see everything, and the private/ dir will be
in the branch; and when user U (unprivileged) does 'svn
log' on that revision, they will see whatever they would
see on any other revision that involves a mixture of
visible and invisible things.
<danielsh> kfogel: but if the revision doesn't contain the private/
dir, you have to do a "delete private/" in the FS, and then
you have in the revision a readable path with unreadable
copyfrom... and I'm just not sure how we handle that.
<philipm> How could the user make a copy that doesn't include the
authz prohibited child?
<danielsh> kfogel: I'm tryig to see if allowing the copy to go through
(sans private/) would make sense
<kfogel> danielsh: asking more about desired behavior than implementation
<kfogel> philipm: right now, they can do a checkout of trunk/.
<kfogel> philipm: so, my point is, they reasonably expect that they
can do a cp of something they can already do a checkout or
an ls of.
<kfogel> philipm: then they try it, and get a weird error.
<philipm> Can they copy the working copy?
<kfogel> philipm: sure... heh, ummm... I wonder if that works right.
<philipm> If you try to commit the copy and delete the excluded child
the FS will reject the commit.
<philipm> It rejects it at the copy stage.
<philipm> It wouldn't be a cheap copy. It would be a cheap copy with
<danielsh> it should let the copy go through, but delete the private/
child, and hide the existence of the deletion from
<kfogel> $ svn cp --username U -m \
"Creating a branch from wc this time." \
svn: Directory 'private' is missing
svn: Directory 'private' is missing
<kfogel> philipm, danielsh: (yes, it printed that twice)
<kfogel> philipm, danielsh: so, in 1.6.7, the server reveals to the
client the name of the forbidden directory. If that's
still true in 1.7.x, we have a problem.
<philipm> They have always been revealed
<kfogel> philipm: I didn't realize that.
<danielsh> 19:11:42 @danielsh | it should let the copy go
through, but delete the private/ child, and hide
the existence of the deletion from unauthn'd users.
<danielsh> kfogel, * : ^^^ is that implementable? Would it work?
<kfogel> danielsh: in my opinion, that's the right user-visible
behavior. How hard it is to implement, I have no idea.
<kfogel> danielsh: (I am going to note all this in #2662, though, so
at least we don't have to think it all through again)
<danielsh> kfogel: you would create the revision as a copy + delete of
a child, and then hide paths that have unreadable
<danielsh> not sure if that works, easy to implement, makes sense, etc
<danielsh> keywords.add("needsdesign") # :-)
<kfogel> danielsh: Mmmmm. I think that's right. In other words, if
user U does 'svn log' on the new revision, U doesn't see
the deletion of the privileged path. However, if a
privileged user does 'svn log', they can see that deletion
too. Agree about the "needsdesign" -- #2662 is already
marked with that :-).
<danielsh> kfogel: I'm sure there is a boatload of corner cases in
this back-of-the-envelope design ...
<kfogel> danielsh: yup