Skip to content

fix: handle annotated tags in GetTags() to prevent NullReferenceException#7

Open
NormandErwan wants to merge 7 commits into
mainfrom
claude/security-audit-plan-SKyrF
Open

fix: handle annotated tags in GetTags() to prevent NullReferenceException#7
NormandErwan wants to merge 7 commits into
mainfrom
claude/security-audit-plan-SKyrF

Conversation

@NormandErwan
Copy link
Copy Markdown
Owner

@NormandErwan NormandErwan commented May 2, 2026

Summary

  • GetTags() crashed with NullReferenceException when the repository contained annotated tags (created with git tag -a). It cast tag.Target directly to Commit using the null-forgiving operator !, but for annotated tags tag.Target is a TagAnnotation, not a Commit, so the cast silently returned null and the subsequent .Author.When access threw.
  • Unity's UnityCsReference repository uses annotated tags exclusively, so GetLatestVersions() — and therefore the entire tool — always crashed at startup.
  • Fixed by extracting GetTaggedCommit(Tag), which peels through the TagAnnotation chain with a while loop until it reaches the underlying Commit (or returns null for non-commit targets, falling back to DateTimeOffset.MinValue for sorting).

Test plan

  • GetTags_WithAnnotatedTag_ReturnsTagName — regression test: annotated tag must appear in results without throwing
  • GetTags_WithLightweightTag_ReturnsTagName — lightweight tag (tag.Target is Commit directly, while-loop never iterates)
  • GetTags_WithNestedAnnotatedTag_ReturnsTagName — outer TagAnnotation → inner TagAnnotationCommit (loop iterates twice, multi-level peeling)
  • GetTags_WithTagNotPointingToCommit_IsStillReturned — tag pointing to a blob; GetTaggedCommit returns null, tag still appears in output sorted last

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4

claude added 6 commits May 2, 2026 14:05
GetTags() casts tag.Target directly to Commit. For annotated tags,
tag.Target is a TagAnnotation, so the cast yields null and the
null-forgiving ! operator causes a NullReferenceException at runtime.
UnityCsReference uses annotated tags, making this crash systematic.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
For annotated tags, tag.Target is a TagAnnotation (not a Commit), so
casting it directly to Commit returned null and the null-forgiving !
caused a NullReferenceException. Extracted GetTaggedCommit() which
traverses the annotation chain until it reaches the underlying Commit,
handling both lightweight and annotated tags (including nested ones).

Fixes the crash that prevented --repositoryTags auto-discovery from
working with UnityCsReference, which exclusively uses annotated tags.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
RepositoryExtensionsTests creates Repository instances directly,
requiring LibGit2Sharp types and its native binaries to be explicitly
present in the test output. Relying on the transitive reference through
UnityXrefMaps.csproj is not sufficient for native library resolution.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
Commands.Stage with the "*" glob pathspec may not reliably match
untracked files in LibGit2Sharp; using the explicit filename avoids
a potential empty index that would cause Commit() to throw.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
Replace Commands.Stage with Index.Add/Write (lower-level, unambiguous)
and use commit.Sha (string objectish) instead of passing the Commit
object directly to Tags.Add, removing any overload resolution ambiguity.
Also use var to avoid shadowing the Commit type with a same-named variable.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
Adds three tests alongside the existing annotated-tag regression test:

- GetTags_WithLightweightTag_ReturnsTagName: tag.Target is Commit directly,
  while-loop in GetTaggedCommit never iterates.
- GetTags_WithNestedAnnotatedTag_ReturnsTagName: outer TagAnnotation → inner
  TagAnnotation → Commit, loop iterates twice (multi-level peeling).
- GetTags_WithTagNotPointingToCommit_IsStillReturned: tag points to a blob,
  GetTaggedCommit returns null, tag is still present sorted last.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
@NormandErwan NormandErwan changed the title fix: peel through TagAnnotation in GetTags() to avoid NRE on annotated tags fix: handle annotated tags in GetTags() to prevent NullReferenceException May 2, 2026
Three of the four tests shared the same 5-line commit-creation block
(signature, write file, stage, write index, commit). Extracted into a
private CreateCommit() helper returning the commit and signature tuple.

https://claude.ai/code/session_01WNaTJnpDwNjqyfL1uhYqJ4
@NormandErwan NormandErwan force-pushed the claude/security-audit-plan-SKyrF branch from aef2ec5 to 84a565c Compare May 2, 2026 19:32
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