Subject: [PATCH 0/8] tightening ref handling outside of refs/

From: Jeff King <[email-masked]>
Date: Mon, 29 Apr 2024 04:15:12 -0400

This is picking up the discussion from:

  https://lore.kernel.org/git/[email-masked]/

The basic issue is that we don't really enforce pseudoref syntax for
names outside of "refs/", so you update random files in .git like:

  git update-ref objects/info/commit-graphs/commit-graph-chain HEAD

This is mitigated a bit by:

  1. You can't usually _overwrite_ files unless they look vaguely
     sha1-ish (in this case the chain file contains hashes of graph
     files, which is enough). So high-ticket items like "config" should
     be immune.

  2. Receive-pack is a bit more careful here, and refuses anything
     outside of "refs/". So you can't get up to any mischief via "git
     push".

But I still find it a bit scary/weird in general. And as noted in that
thread, there's some attempt to enforce this that is done
inconsistently. So you can update and read such refs, but are forbidden
to delete them.

Of course all of this becomes a non-issue with reftables, where those
names are not used in the filesystem at all. But even there I think we'd
probably want to consistently enforce the syntax rules (both between
delete/update/read, but also consistency with the files backend).

This series teaches check_refname_format() to enforce these rules (when
instructed; see patch 6 for a discussion of all sorts of complications).

These changes are not backwards-compatible! But that is kind of the
point. This is stuff that was never supposed to work. My concern would
just be that somehow somebody is relying on it. Pay attention
specifically to patches 4, 7, and 8, which are where the behavior
changes are.

  [1/8]: t0600: don't create ref outside of refs/
  [2/8]: t5619: use fully qualified refname for branch
  [3/8]: refs: move is_pseudoref_syntax() definition earlier
  [4/8]: refs: disallow dash in pseudoref syntax
  [5/8]: refs: use is_pseudoref_syntax() in refname_is_safe()
  [6/8]: check_refname_format(): add FULLY_QUALIFIED flag
  [7/8]: refs: check refnames as fully qualified when writing
  [8/8]: refs: check refnames as fully qualified when resolving

 refs.c                                     | 59 ++++++++++++----------
 refs.h                                     |  1 +
 t/t0600-reffiles-backend.sh                |  2 +-
 t/t1430-bad-ref-name.sh                    | 20 ++++++++
 t/t5619-clone-local-ambiguous-transport.sh |  4 +-
 5 files changed, 57 insertions(+), 29 deletions(-)

-Peff