Skip to content

fix(git): widen is_safe_refname, is_emittable_ref, and RefPattern alphabets for +/@ (#4194) - #4348

Open
iroiro147 wants to merge 2 commits into
block:mainfrom
iroiro147:fix/4194-refname-widen-v2
Open

fix(git): widen is_safe_refname, is_emittable_ref, and RefPattern alphabets for +/@ (#4194)#4348
iroiro147 wants to merge 2 commits into
block:mainfrom
iroiro147:fix/4194-refname-widen-v2

Conversation

@iroiro147

Copy link
Copy Markdown

Problem (#4194)

git check-ref-format accepts + and @ in ref components (no newline, no NUL, no control chars, no . at the start of a component, no trailing /), but is_safe_refname rejected anything outside [a-zA-Z0-9_./-]. Real-world upstream branches like OriginTrail/dkg's refs/heads/test/842+841-devnet were un-mirrorable into Buzz git.

Both characters have no meaning to the object-store key scheme or to path traversal (.-based traversal protection is unchanged, and refnames are still pinned to the refs/ prefix).

Fix

This PR supersedes #4257 with the review feedback from @alanshurafa folded in as ordinary commits.

Commit 1 (90d7800f3) — widen is_safe_refname in buzz-relay/src/api/git/manifest.rs (and the hydrate-side test) to accept + and @. Conservative scope: =, ,, !, ] remain excluded.

Commit 2 (4a88e6017) — fold in review feedback:

  • Widen is_emittable_ref in buzz-relay/src/api/git/manifest_event.rs — re-spelled the old alphabet and silently continued +/@ refs out of the kind:30618 ref-state event. Without this, a widened is_safe_refname alone makes things worse: the ref pushes, CASes, hydrates, and clones — and then never appears in any branch lister (desktop projects/hooks.ts, web repos/use-repo-refs.ts — silent lister drop).
  • Widen RefPattern::parse in buzz-core/src/git_perms.rs:152 — literal protection rules could not name +/@ refs; those refs became pushable-but-unnameable from the enforcement side.
  • Doc nit[a-zA-Z0-9_./+-@][a-zA-Z0-9_./+@-] (+ immediately before @) so it doesn't read as a char-class range +-@ (which would include : ; < = > ?).
  • Restored assertionassert!(!is_safe_refname("")) is load-bearing (ManifestError::EmptyHead doc relies on the read side rejecting """); restored with a comment citing the consumer.

Verification

Coverage added:

  • manifest.rs::safe_refnames and hydrate.rs::safe_refnames — positive +/@ cases + negative =, ,, !, ] cases.
  • manifest_event.rs::emits_refs_with_plus_and_at_in_component — event builds include the new refs in tag lists, not silently continue them out.
  • manifest_event.rs::is_emittable_ref_widened_alphabet — direct predicate test.
  • git_perms.rs::pattern_literal_accepts_plus_and_at — literal protection rule can name +/@ refs; wildcard semantics unchanged (refs/heads/* still matches exactly one segment; refs/heads/** crosses components).

Test counts green:

  • cargo test -p buzz-relay --lib safe_refnames → 2/2
  • cargo test -p buzz-relay --lib manifest_event → 11/11
  • cargo test -p buzz-core --lib git_perms → 35/35
  • cargo fmt --check -p buzz-core -p buzz-relay → clean

The 10 unrelated pre-existing failures in api::media + telemetry suites are untouched and out of scope.

Refs #4194
Supersedes #4257

Signed-off-by: Sarthak Singh sarthak.singh@juspay.in

…k#4194)

`git check-ref-format` accepts `+` and `@` in ref components (no newline,
no NUL, no control chars, no `.` at the start of a component, no trailing
`/`), but `is_safe_refname` rejected anything outside `[a-zA-Z0-9_./-]`.
Real-world upstream branches like `OriginTrail/dkg`'s
`refs/heads/test/842+841-devnet` were un-mirrorable into Buzz git.

Both characters have no meaning to the object-store key scheme or to path
traversal (`.`-based traversal protection is unchanged, and refnames are
still pinned to the `refs/` prefix so they cannot escape into other key
spaces). The predicate is shared symmetrically by write-side `validate`
and read-side hydration, so widening once fixes both sides of the seam.

Keep the widening conservative — the other git-legal chars called out in
the issue (`=`, `,`, `!`, `]`) are not observed failing at any upstream
mirror and remain excluded to preserve a small attack surface. They can
be added in a follow-up if a real failure surfaces.

Regression coverage extends the existing `safe_refnames` tests in both
`manifest.rs` and `hydrate.rs`:
- positive: `refs/heads/test/842+841-devnet` and `refs/tags/release@v1`
- negative: `=`, `,`, `!`, `]` remain rejected

`cargo check -p buzz-relay` and `cargo test -p buzz-relay --lib safe_refnames`
are green (2/2 tests pass; the 10 unrelated pre-existing failures in
api::media + telemetry suites are untouched and out of scope).

Refs block#4194

Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
…_safe_refname (block#4194)

Two sibling predicates re-spelled the pre-widening alphabet from is_safe_refname and silently dropped refs containing + or @:

- is_emittable_ref in buzz-relay/src/api/git/manifest_event.rs — refs were continued out of the kind:30618 ref-state event, so refs/heads/test/842+841-devnet pushed clean, CASed, hydrated, cloned, and then never appeared in any branch lister (desktop projects/hooks.ts, web repos/use-repo-refs.ts).
- RefPattern::parse in buzz-core/src/git_perms.rs:152 — literal protection rules could not name +/@ refs; those refs were pushable-but-unnameable from the enforcement side.

Caught during review of block#4257 (thanks @alanshurafa). Widening is_safe_refname alone was insufficient: a ref that pushes, CASes, hydrates, and clones — but never appears in any lister — is strictly worse than today's 400-class rejection because nothing reports it.

Two small items folded in:

- Restore assert!(!is_safe_refname("")) in manifest.rs — load-bearing (ManifestError::EmptyHead doc relies on it).
- Doc notation [a-zA-Z0-9_./+@-], not [a-zA-Z0-9_./+-@] — unambiguous (avoids char-class range interpretation +-@ which would include : ; < = > ?).

Coverage:

- manifest_event.rs::emits_refs_with_plus_and_at_in_component — event build includes refs with +/@ in its tag lists.
- manifest_event.rs::is_emittable_ref_widened_alphabet — direct predicate test.
- git_perms.rs::pattern_literal_accepts_plus_and_at — literal pattern can now name such refs; wildcard semantics unchanged.

Test counts: 2/2 safe_refnames + 11/11 manifest_event + 35/35 git_perms, all green.

Refs block#4194

Signed-off-by: Sarthak Singh <sarthak.singh@juspay.in>
@iroiro147

Copy link
Copy Markdown
Author

Standing-health check (re-verified against current main 28ae6cd21, 0 commits since this branch's merge-base — clean merge, no drift):

  • All checks green (DCO / Semgrep / zizmor).
  • Merge dry-run vs current `main`: zero conflicts.
  • Targeted suites re-run green: `api::git::manifest` 34/34, `api::git::manifest_event` 11/11, `buzz-core::git_perms` 35/35.
  • Confirmed current `main` does not already contain the `+@` widening (no land / no superseding change).

Ready for review; no action needed from contributors.

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