Skip to content

Synthesize SarifLogger invocation only when the run has none - #3136

Open
Sukanth Gunda (sukanth) wants to merge 1 commit into
microsoft:mainfrom
sukanth:sukanthgunda-microsoft-fix-sariflogger-duplicate-invocation
Open

Synthesize SarifLogger invocation only when the run has none#3136
Sukanth Gunda (sukanth) wants to merge 1 commit into
microsoft:mainfrom
sukanth:sukanthgunda-microsoft-fix-sariflogger-duplicate-invocation

Conversation

@sukanth

Copy link
Copy Markdown
Contributor

Summary

SarifLogger.EnhanceRun unconditionally created a new Invocation and appended it to run.Invocations every time the logger enhanced a run. When a caller supplied a Run that already carried one or more Invocation objects, the logger appended a second, machine-synthesized invocation — duplicating invocation data the caller had already provided and producing a SARIF run with a spurious trailing invocation.

This change makes the synthesis conditional: SarifLogger now synthesizes and appends an Invocation only when run.Invocations is null or empty. When the caller already supplied at least one invocation, the logger leaves the caller's invocations untouched.

Fixes #2519.

Details

EnhanceRun still normalizes _run.Invocations to a non-null list (??= new List<Invocation>()) because downstream code paths — Dispose/AnalysisStopped end-time stamping, the notification writers, SARIF v1 conversion, and ResultProvenance.InvocationIndex — read Invocations[0] / Invocations.Count and would NullReferenceException against a null list. Only the creation of a new invocation (plus its redaction and append) is now guarded by if (_run.Invocations.Count == 0).

  • The index-0 caller-supplied invocation is fully preserved, so end-time stamping, v1 conversion, and provenance indexing continue to operate on the caller's object.
  • Redaction was never applied to caller-supplied invocations before this change, so scoping redaction to the synthesized invocation is not a behavioral regression.

Tests

  • SarifLogger_DoesNotAddInvocationWhenRunAlreadyHasInvocation — asserts no second invocation is appended when the caller supplies one.
  • SarifLogger_RetainsAllCallerSuppliedInvocations — asserts multiple caller-supplied invocations are all retained and none are added.
  • SarifLogger_EnhancesRunWithInvocation — refactored to share a private helper (RunSarifLoggerOverRun) with the new tests; still asserts the synthesized-invocation path for a run that starts with none.

Per repo convention, the new coverage is expressed as multiple [Fact] methods delegating to a shared helper (no [Theory]/[InlineData]). All SarifLoggerTests pass locally (33/33); the solution builds clean.

Validation

The change was validated with a design review before implementation and an independent diff review afterward across two model families (OpenAI GPT-5.6 and Anthropic Claude Opus 4.8); both reached approve with no blocking findings.

SarifLogger.EnhanceRun always created and appended a synthesized
Invocation, even when the caller supplied a Run that already carried one
or more. That duplicated the caller's invocation in the emitted run and
left downstream consumers reading a phantom trailing invocation.

Guard the synthesis behind a check for an empty invocation collection so
an invocation is created only when the caller supplied none. The
null-coalescing initialization of the invocation list is kept ahead of
the guard because Dispose, AnalysisStopped, and the notification writers
index the first invocation and read its count, and would throw on a null
list.

Add tests covering the single caller-supplied invocation and multiple
caller-supplied invocations, extracting a shared helper reused by the
existing empty-run test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
// by a dedicated rewriting visitor or some other approach.

if (invocation.EnvironmentVariables != null)
if (invocationTokensToRedact != null)

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.

You've created some API confusion here as now arguments such as 'invocationsToRedact' are only used in cases where an invocation is created by this code. So, if you provide a non-null Invocations list and also invocationTokensToRedact, this latter argument goes silently unused. There are two obvious possibilities, attempt to apply invocationsToRedact over all invocations, whether passed in or created or enforce that arguments such as invocationsToRedact are only provided when the incoming invocation list is null or empty.

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.

SarifLogger always add a new Invocation when SarifLogger is used

2 participants