Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Work around duplicate locations bug in diagnostics export #1605

Merged
merged 6 commits into from
Mar 27, 2023

Conversation

henrymercer
Copy link
Contributor

This PR works around a bug in diagnostics export that could lead to an invalid SARIF file being produced by database interpret-results or database export-diagnostics.

The bug lies in the CLI functionality that groups diagnostics together. When grouping together multiple diagnostics that have the same location a, the CLI produced a single diagnostic with multiple identical locations [a, ..., a]. This is not valid SARIF, as the spec mandates that the locations for each notification object are distinct.

To allow us to roll out diagnostics export without waiting for a new CLI release, we workaround this bug in the CodeQL Action. To do this, when diagnostics export is enabled, we go through the SARIF file produced by database interpret-results and database export-diagnostics and remove any duplicate locations from the runs[].invocations[].toolExecutionNotifications property.

We add unit tests and integration tests, as well as an environment variable CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX to disable this functionality if unexpected problems arise.

Merge / deployment checklist

  • Confirm this change is backwards compatible with existing workflows.
  • Confirm the readme has been updated if necessary.
  • Confirm the changelog has been updated if necessary.

@henrymercer henrymercer requested a review from a team as a code owner March 24, 2023 20:37
@henrymercer henrymercer requested a review from angelapwen March 24, 2023 20:38
Only tests the property we are looking for and avoids problems with
different cross-platform behavior.
@aeisenberg
Copy link
Contributor

I haven't had a chance to review yet, but a general question. Are we fairly sure the fix will be available in the next CLI? If so, should we be gating this functionality on the CLI version as well? I.e., use the original behaviour of version is greater than 2.12.x?

@angelapwen
Copy link
Contributor

angelapwen commented Mar 24, 2023

Are we fairly sure the fix will be available in the next CLI? If so, should we be gating this functionality on the CLI version as well? I.e., use the original behaviour of version is greater than 2.12.x?

The fix has already been merged and patched in the CLI (I backlinked it as it's an internal PR), so I don't believe we need to add an additional gate.

EDIT — I think I see what you mean: we only need to do this post-processing if we're at a version < than the 2.12.6.

Copy link
Contributor

@angelapwen angelapwen left a comment

Choose a reason for hiding this comment

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

Looked through and makes sense to me. Approving but will wait for Andrew's review too!

src/util.ts Show resolved Hide resolved
Comment on lines +1051 to +1057

// Fix invalid notifications in the SARIF file output by CodeQL.
let sarif = JSON.parse(
fs.readFileSync(intermediateSarifFile, "utf8")
) as util.SarifFile;
sarif = util.fixInvalidNotifications(sarif, logger);
fs.writeFileSync(sarifFile, JSON.stringify(sarif));
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be worthwhile to pull this out into a separate function to make sure that the logic remains the same between here and in diagnostics export?

Copy link
Contributor

@aeisenberg aeisenberg left a comment

Choose a reason for hiding this comment

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

I have a handful of questions and a stylistic suggestion. Though, I think this generally looks good assuming we don't want a full feature flag.

Comment on lines +61 to +62
export const CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX =
"CODEQL_ACTION_DISABLE_DUPLICATE_LOCATION_FIX";
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth turning this into a full feature flag so we can centrally manage enablement of the behaviour?

src/util.ts Show resolved Hide resolved
);
return sarif;
}
if (!(sarif.runs instanceof Array)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor: using Array.isArray is generally better. However, in this particular case instanceof is fine. It's only really necessary when using iframes in DOM.

Suggested change
if (!(sarif.runs instanceof Array)) {
if (!Array.isArray(sarif.runs)) {

https://stackoverflow.com/questions/22289727/difference-between-using-array-isarray-and-instanceof-array

runs: sarif.runs.map((run) => {
if (
run.tool?.driver?.name !== "CodeQL" ||
!(run.invocations instanceof Array)
Copy link
Contributor

Choose a reason for hiding this comment

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

minor: as above

Suggested change
!(run.invocations instanceof Array)
!(Array.isArray(run.invocations))

return {
...run,
invocations: run.invocations.map((invocation) => {
if (!(invocation.toolExecutionNotifications instanceof Array)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (!(invocation.toolExecutionNotifications instanceof Array)) {
if (!Array.isArray(invocation.toolExecutionNotifications)) {

...invocation,
toolExecutionNotifications:
invocation.toolExecutionNotifications.map((notification) => {
if (!(notification.locations instanceof Array)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (!(notification.locations instanceof Array)) {
if (!Array.isArray(notification.locations)) {

@henrymercer
Copy link
Contributor Author

Thanks folks for the review. I'll address these improvements as followup to avoid blocking this on another review cycle.

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.

3 participants