Skip to content

v5: Align object encoding with upstream#2065

Merged
pjbgf merged 13 commits into
releases/v5.xfrom
commit-v5
May 6, 2026
Merged

v5: Align object encoding with upstream#2065
pjbgf merged 13 commits into
releases/v5.xfrom
commit-v5

Conversation

@pjbgf

@pjbgf pjbgf commented May 6, 2026

Copy link
Copy Markdown
Member
  • Ensures that unmodified Commit and Tag objects return their raw bytes (minus gpgsign and gpgsign-sha256 headers).
  • Aligns Commit and Tag interpretation with upstream: first instance of standard headers wins.
  • Add conformance tests to ensure verification aligns with git. Note that duplicate signatures were valid back on v2.11, which is why that test is skipped during capability mode.
  • Aligns Tree interpretation with upstream: first wins and unsorted tree is short-circuited.

pjbgf added 13 commits May 6, 2026 15:25
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Replace the per-iteration flag soup in (*Commit).Decode with a
func-based stateFn loop that mirrors upstream Git's parsing posture.
The new state machine encodes "where we are in the buffer" as the
function being called rather than as a bag of mutable booleans.

Conformance changes vs upstream commit.c:
- tree must be the first header, missing tree errors with
  ErrMalformedCommit (matches the "bogus commit object" check at
  commit.c:508-510).
- Parents are accepted only contiguously after tree; out-of-position
  parent lines are silently dropped (matches parse_commit_buffer's
  parent loop exiting at the first non-parent line and
  read_commit_extra_header_lines filtering parents from extras).
- Author and committer are accepted only at their canonical positions
  (immediately after parents, immediately after author). Out-of-place
  occurrences are dropped, mirroring parse_commit_date silently
  returning 0 plus the standard_header_field filter.
- Encoding/mergetag/gpgsig/gpgsig-sha256 follow first-wins; duplicate
  sig/mergetag continuation lines are discarded by a dedicated
  scanSkipCont state.
- Continuation strip uses line[1:] (single space) instead of
  bytes.TrimLeft, mirroring upstream's `line + 1` at commit.c:1509.
- Header/body boundary is the literal "\n" only, matching
  *line == '\n' at commit.c:1502.

Tests:
- TestDecodeRequiresTreeFirst covers the four hard-error inputs
  (missing tree, parent before tree, extra before tree, empty buffer).
- TestDecodeFirstOccurrenceWins covers the lenient drop semantics for
  duplicate tree/author/committer/gpgsig/gpgsig-sha256, parents after
  author or interleaved with extras, missing committer, encoding
  between author and committer (drops the misplaced committer), and
  author at a non-canonical position (drops author and committer).
- TestMalformedHeader is back to expecting NoError (lenient parsing of
  garbage author/committer values).

The state machine lives in plumbing/object/commit_scanner.go.

Assisted-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Tag verification re-encoded from struct fields, so any non-canonical
bytes the signature was computed over (duplicate headers, mutation-only
fields like Signature/SignatureSHA256, etc.) were lost from the payload
and signatures that were valid in upstream Git failed in go-git.

Mirror the approach already used by Commit: retain a reference to the
source plumbing.EncodedObject on Decode, add matchesSource() so
EncodeWithoutSignature can stream the raw bytes (with the inline
trailing PGP block truncated and gpgsig/gpgsig-sha256 headers stripped)
when the struct still matches the source. Mutating struct fields still
falls back to the struct-encoded payload.

Assisted-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Align Commit.Verify with upstream's parse_buffer_signed_by_header
(commit.c:1186) and parse_gpg_output rejection (gpg-interface.c:257-269).

The commit scanner now concatenates every gpgsig/gpgsig-sha256 header
into a single signature buffer instead of first-wins, and Commit.Verify
returns the new ErrMultipleSignatures when that buffer carries more
than one armored block.

Assisted-by: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <paulo@entire.io>
Copilot AI review requested due to automatic review settings May 6, 2026 14:46
@pjbgf pjbgf changed the title v5: Alignment object encoding with upstream v5: Align object encoding with upstream May 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aligns go-git’s Commit/Tag/Tree decoding, signature payload generation, and verification behavior with upstream git, and adds conformance tests to ensure Verify verdicts match git verify-commit / git verify-tag.

Changes:

  • Commit/Tag: implement stricter upstream-like header interpretation (canonical order + first-wins) and make EncodeWithoutSignature preserve exact signed payload bytes by stripping signatures from the original decoded bytes when unmodified.
  • Tree: canonicalize entry modes, detect malformed trees, track whether entries are sorted, and short-circuit lookups for unsorted trees to match upstream behavior.
  • Add Linux-only conformance tests that compare git vs go-git verification verdicts (GPG-backed), and allow tests: as a commit message prefix in CI validation.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/objectverify/main_test.go Test harness: repo init, isolated GPG env, helpers to compare git vs go-git verification.
tests/objectverify/commit_test.go Conformance cases for git verify-commit vs Commit.Verify.
tests/objectverify/tag_test.go Conformance cases for git verify-tag vs Tag.Verify.
plumbing/object/commit.go Commit decode/encode/signature-payload alignment, raw-source preservation, multi-signature rejection in Verify.
plumbing/object/commit_scanner.go New commit header state machine to enforce upstream-like parsing and first-wins semantics.
plumbing/object/commit_sha256_test.go SHA-256 object-id decoding test coverage for commits.
plumbing/object/commit_test.go Expanded unit tests for strict header parsing and EncodeWithoutSignature payload behavior.
plumbing/object/tag.go Tag decode/encode/signature-payload alignment, raw-source preservation, optional tagger encoding.
plumbing/object/tag_scanner.go New tag header state machine to enforce upstream-like parsing and header skipping.
plumbing/object/tag_test.go Expanded unit tests for tag parsing, signature handling, and EncodeWithoutSignature.
plumbing/object/signature.go Shared helpers for signature detection/counting and streaming signature stripping from raw objects.
plumbing/object/tree.go Tree decode hardened (malformed detection), mode canonicalization, sortedness tracking, and lookup changes.
plumbing/object/tree_test.go Adds tests for malformed tree rejection, canonical mode mapping, cache/state clearing, and duplicate handling.
plumbing/object/object_test.go Updates tree lookup assertions to use the new lookup path.
.github/workflows/pr-validation.yml Allows tests: prefix in commit message validation pattern.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread plumbing/object/commit.go
Comment thread plumbing/object/commit_scanner.go
Comment thread plumbing/object/tag_scanner.go
@pjbgf pjbgf merged commit bc930f4 into releases/v5.x May 6, 2026
16 checks passed
@pjbgf pjbgf deleted the commit-v5 branch May 6, 2026 14:56
Maks1mS pushed a commit to stplr-dev/stplr that referenced this pull request May 10, 2026
This PR contains the following updates:

| Package | Type | Update | Change | OpenSSF |
|---|---|---|---|---|
| [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | require | minor | `v5.18.0` → `v5.19.0` | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-git/go-git/badge)](https://securityscorecards.dev/viewer/?uri=github.com/go-git/go-git) |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/23) for more information.

---

### Release Notes

<details>
<summary>go-git/go-git (github.com/go-git/go-git/v5)</summary>

### [`v5.19.0`](https://github.com/go-git/go-git/releases/tag/v5.19.0)

[Compare Source](go-git/go-git@v5.18.0...v5.19.0)

#### What's Changed

- build: Update module github.com/go-git/go-git/v5 to v5.18.0 \[SECURITY] (releases/v5.x) by [@&#8203;go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#&#8203;2010](go-git/go-git#2010)
- v5: Bump sha1cd and go-billy by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2060](go-git/go-git#2060)
- v5: Align object encoding with upstream by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2065](go-git/go-git#2065)

**Full Changelog**: <go-git/go-git@v5.18.0...v5.19.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At 12:00 AM through 04:59 AM and 10:00 PM through 11:59 PM, Monday through Friday (`* 0-4,22-23 * * 1-5`)
  - Only on Sunday and Saturday (`* * * * 0,6`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMzIuMyIsInVwZGF0ZWRJblZlciI6IjQzLjEzMi4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJLaW5kL0RlcGVuZGVuY2llcyJdfQ==-->

Reviewed-on: https://altlinux.space/stapler/stplr/pulls/427
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.

2 participants