Skip to content

Git ref accepts #tag= and #commit= together; winner is nondeterministic #10

Description

@fchimpan

Summary

A git ref specifying both #tag= and #commit= is accepted, and which one wins is nondeterministic: both option keys write the same internal field while ref options are iterated in Go map order. branch+commit and ref+commit are explicitly rejected, so this combination slipping through is an inconsistency. (Borderline case: it requires self-contradictory user input, but a confused user writing "tag v1.0.0, which is commit deadbeef" gets a silently nondeterministic fetch instead of an error — and a ref like this committed to CI produces non-reproducible builds.)

Reproduction

buf build 'https://github.com/org/repo.git#tag=v1.0.0,commit=deadbeef'
# accepted; fetches either the tag or the commit depending on map iteration order of that run

Root cause

private/buf/buffetch/internal/ref_parser.go:141-142:

case "tag", "commit":
	rawRef.GitCommitOrTag = value

Both keys collapse into GitCommitOrTag, and options come from a map (random iteration order), so the last write wins nondeterministically. By the time validateRawRef runs (ref_parser.go:344-347), only one value remains, so the existing branch/ref-vs-commitOrTag conflict checks cannot detect it.

Expected

Reject tag+commit together, matching the existing branch+commit and ref+commit errors.


Found via a full mutest (mutation-testing) run over this repo; verified by source inspection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions