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

Add support for relatedLocations in SARIF format #140

Open
jamacku opened this issue Aug 24, 2023 · 0 comments
Open

Add support for relatedLocations in SARIF format #140

jamacku opened this issue Aug 24, 2023 · 0 comments

Comments

@jamacku
Copy link
Member

jamacku commented Aug 24, 2023

Description

SARIF format allows specifying related locations to the root defect. GitHub is able to parse this location data and show them in a semi-usable way (examples below).

relatedLocations[] - A set of locations relevant to this result. Code scanning will link to related locations when they are embedded in the result message. For more information, see the location object.

Note: This feature requires the support for region data to be implemented first: #136

Example of relatedLocations used in SARIF

I'm using ShellCheck as an example, but I believe that this might be useful also for other static analyzers.

The shell script used in the example:

#!/bin/bash

echo "I'm innocent script, just pass the name of the directory as parameter and I'll remove it for you..."

DIR_SUFFIX="*"
UNUSED_VAR=""

echo "I'm going to remove directory $1/$DIR_SUFFIX"

#! FIXME - Call rm -rf $1/$DIR_SUFFIX

echo "<img src="foo.png" />" > file.html

files='file1 file2'
combined_file=`cat ${files}`
echo "${combined_file}"

rm $1

echo $1                           # Unquoted variables
find . -name *.ogg                # Unquoted find/grep patterns
rm "~/my file.txt"                # Quoted tilde expansion
v='--verbose="true"'; cmd $v      # Literal quotes in variables
{
  "ruleId": "SHELLCHECK_WARNING: style[SC2006]",
  "locations": [
    {
      "id": 0,
      "physicalLocation": {
        "artifactLocation": {
          "uri": "innocent-script.sh"
        },
        "region": {
          "startLine": 15
        }
      }
    }
  ],
  "message": {
    "text": "Use $(...) notation instead of legacy backticks `...`."
  },
  "codeFlows": [
    {
      "threadFlows": [
        {
          "locations": [
            {
              "location": {
                "id": 0,
                "physicalLocation": {
                  "artifactLocation": {
                    "uri": "innocent-script.sh"
                  },
                  "region": {
                    "startLine": 15
                  }
                },
                "message": {
                  "text": "Use $(...) notation instead of legacy backticks `...`.  Suggestions: use [`$(`](1), use [`)`](2)"
                }
              },
              "nestingLevel": 0,
              "kinds": [
                "style[SC2006]"
              ]
            }
          ]
        }
      ]
    }
  ],
  "relatedLocations": [
    {
      "id": 1,
      "physicalLocation": {
        "artifactLocation": {
          "uri": "innocent-script.sh"
        },
        "region": {
          "endColumn": 16,
          "endLine": 15,
          "startColumn": 15,
          "startLine": 15
        }
      },
      "message": {
        "text": "$("
      }
    },
    {
      "id": 2,
      "physicalLocation": {
        "artifactLocation": {
          "uri": "innocent-script.sh"
        },
        "region": {
          "endColumn": 29,
          "endLine": 15,
          "startColumn": 28,
          "startLine": 15
        }
      },
      "message": {
        "text": ")"
      }
    }
  ]
},

The GitHub requires links torelatedLocations directly in the message.text string. Otherwise, it doesn't show them in UI.

{
  "text": "Use $(...) notation instead of legacy backticks `...`.  Suggestions: use [`$(`](1), use [`)`](2)"
}

Data for relatedLocations can be gathered when using ShellCheck JSON1 format.

{
  "file": "innocent-script.sh",
  "line": 15,
  "endLine": 15,
  "column": 15,
  "endColumn": 29,
  "level": "style",
  "code": 2006,
  "message": "Use $(...) notation instead of legacy backticks `...`.",
  "fix": {
    "replacements": [
      {
        "column": 15,
        "endColumn": 16,
        "endLine": 15,
        "insertionPoint": "afterEnd",
        "line": 15,
        "precedence": 8,
        "replacement": "$("
      },
      {
        "column": 28,
        "endColumn": 29,
        "endLine": 15,
        "insertionPoint": "beforeStart",
        "line": 15,
        "precedence": 8,
        "replacement": ")"
      }
    ]
  }
}
Full ShellCheck JSON1
{
  "comments": [
    {
      "file": "innocent-script.sh",
      "line": 6,
      "endLine": 6,
      "column": 1,
      "endColumn": 11,
      "level": "warning",
      "code": 2034,
      "message": "UNUSED_VAR appears unused. Verify use (or export if used externally).",
      "fix": null
    },
    {
      "file": "innocent-script.sh",
      "line": 12,
      "endLine": 12,
      "column": 17,
      "endColumn": 24,
      "level": "warning",
      "code": 2140,
      "message": "Word is of the form \"A\"B\"C\" (B indicated). Did you mean \"ABC\" or \"A\\\"B\\\"C\"?",
      "fix": null
    },
    {
      "file": "innocent-script.sh",
      "line": 15,
      "endLine": 15,
      "column": 15,
      "endColumn": 29,
      "level": "style",
      "code": 2006,
      "message": "Use $(...) notation instead of legacy backticks `...`.",
      "fix": {
        "replacements": [
          {
            "column": 15,
            "endColumn": 16,
            "endLine": 15,
            "insertionPoint": "afterEnd",
            "line": 15,
            "precedence": 8,
            "replacement": "$("
          },
          {
            "column": 28,
            "endColumn": 29,
            "endLine": 15,
            "insertionPoint": "beforeStart",
            "line": 15,
            "precedence": 8,
            "replacement": ")"
          }
        ]
      }
    },
    {
      "file": "innocent-script.sh",
      "line": 21,
      "endLine": 21,
      "column": 14,
      "endColumn": 19,
      "level": "warning",
      "code": 2061,
      "message": "Quote the parameter to -name so the shell won't interpret it.",
      "fix": null
    },
    {
      "file": "innocent-script.sh",
      "line": 21,
      "endLine": 21,
      "column": 14,
      "endColumn": 15,
      "level": "info",
      "code": 2035,
      "message": "Use ./*glob* or -- *glob* so names with dashes won't become options.",
      "fix": null
    },
    {
      "file": "innocent-script.sh",
      "line": 22,
      "endLine": 22,
      "column": 5,
      "endColumn": 18,
      "level": "warning",
      "code": 2088,
      "message": "Tilde does not expand in quotes. Use $HOME.",
      "fix": null
    },
    {
      "file": "innocent-script.sh",
      "line": 23,
      "endLine": 23,
      "column": 3,
      "endColumn": 21,
      "level": "warning",
      "code": 2089,
      "message": "Quotes/backslashes will be treated literally. Use an array.",
      "fix": null
    },
    {
      "file": "innocent-script.sh",
      "line": 23,
      "endLine": 23,
      "column": 27,
      "endColumn": 29,
      "level": "warning",
      "code": 2090,
      "message": "Quotes/backslashes in this variable will not be respected.",
      "fix": null
    }
  ]
}
Full edited csgrep SARIF
{
  "$schema": "https://json.schemastore.org/sarif-2.1.0.json",
  "version": "2.1.0",
  "runs": [
    {
      "tool": {
        "driver": {
          "name": "csdiff",
          "version": "3.0.3",
          "informationUri": "https://github.com/csutils/csdiff",
          "rules": [
            {
              "id": "SHELLCHECK_WARNING: info[SC2035]",
              "name": "SC2035",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2035",
                "markdown": "Defect reference: [SC2035](https://github.com/koalaman/shellcheck/wiki/SC2035)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: style[SC2006]",
              "name": "SC2006",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2006",
                "markdown": "Defect reference: [SC2006](https://github.com/koalaman/shellcheck/wiki/SC2006)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: warning[SC2034]",
              "name": "SC2034",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2034",
                "markdown": "Defect reference: [SC2034](https://github.com/koalaman/shellcheck/wiki/SC2034)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: warning[SC2061]",
              "name": "SC2061",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2061",
                "markdown": "Defect reference: [SC2061](https://github.com/koalaman/shellcheck/wiki/SC2061)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: warning[SC2088]",
              "name": "SC2088",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2088",
                "markdown": "Defect reference: [SC2088](https://github.com/koalaman/shellcheck/wiki/SC2088)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: warning[SC2089]",
              "name": "SC2089",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2089",
                "markdown": "Defect reference: [SC2089](https://github.com/koalaman/shellcheck/wiki/SC2089)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: warning[SC2090]",
              "name": "SC2090",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2090",
                "markdown": "Defect reference: [SC2090](https://github.com/koalaman/shellcheck/wiki/SC2090)"
              }
            },
            {
              "id": "SHELLCHECK_WARNING: warning[SC2140]",
              "name": "SC2140",
              "properties": {
                "tags": [
                  "ShellCheck"
                ]
              },
              "help": {
                "text": "Defect reference: https://github.com/koalaman/shellcheck/wiki/SC2140",
                "markdown": "Defect reference: [SC2140](https://github.com/koalaman/shellcheck/wiki/SC2140)"
              }
            }
          ]
        }
      },
      "results": [
        {
          "ruleId": "SHELLCHECK_WARNING: warning[SC2034]",
          "level": "warning",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 6
                }
              }
            }
          ],
          "message": {
            "text": "UNUSED_VAR appears unused. Verify use (or export if used externally)."
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 6
                          }
                        },
                        "message": {
                          "text": "UNUSED_VAR appears unused. Verify use (or export if used externally)."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "warning[SC2034]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: warning[SC2140]",
          "level": "warning",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 12
                }
              }
            }
          ],
          "message": {
            "text": "Word is of the form \"A\"B\"C\" (B indicated). Did you mean \"ABC\" or \"A\\\"B\\\"C\"?"
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 12
                          }
                        },
                        "message": {
                          "text": "Word is of the form \"A\"B\"C\" (B indicated). Did you mean \"ABC\" or \"A\\\"B\\\"C\"?"
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "warning[SC2140]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: style[SC2006]",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 15
                }
              }
            }
          ],
          "message": {
            "text": "Use $(...) notation instead of legacy backticks `...`.  Suggestions: use [`$(`](1), use [`)`](2)"
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 15
                          }
                        },
                        "message": {
                          "text": "Use $(...) notation instead of legacy backticks `...`."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "style[SC2006]"
                      ]
                    }
                  ]
                }
              ]
            }
          ],
          "relatedLocations": [
            {
              "id": 1,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "endColumn": 16,
                  "endLine": 15,
                  "startColumn": 15,
                  "startLine": 15
                }
              },
              "message": {
                "text": "$("
              }
            },
            {
              "id": 2,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "endColumn": 29,
                  "endLine": 15,
                  "startColumn": 28,
                  "startLine": 15
                }
              },
              "message": {
                "text": ")"
              }
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: warning[SC2061]",
          "level": "warning",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 21
                }
              }
            }
          ],
          "message": {
            "text": "Quote the parameter to -name so the shell won't interpret it."
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 21
                          }
                        },
                        "message": {
                          "text": "Quote the parameter to -name so the shell won't interpret it."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "warning[SC2061]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: info[SC2035]",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 21
                }
              }
            }
          ],
          "message": {
            "text": "Use ./*glob* or -- *glob* so names with dashes won't become options."
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 21
                          }
                        },
                        "message": {
                          "text": "Use ./*glob* or -- *glob* so names with dashes won't become options."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "info[SC2035]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: warning[SC2088]",
          "level": "warning",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 22
                }
              }
            }
          ],
          "message": {
            "text": "Tilde does not expand in quotes. Use $HOME."
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 22
                          }
                        },
                        "message": {
                          "text": "Tilde does not expand in quotes. Use $HOME."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "warning[SC2088]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: warning[SC2089]",
          "level": "warning",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 23
                }
              }
            }
          ],
          "message": {
            "text": "Quotes/backslashes will be treated literally. Use an array."
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 23
                          }
                        },
                        "message": {
                          "text": "Quotes/backslashes will be treated literally. Use an array."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "warning[SC2089]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "ruleId": "SHELLCHECK_WARNING: warning[SC2090]",
          "level": "warning",
          "locations": [
            {
              "id": 0,
              "physicalLocation": {
                "artifactLocation": {
                  "uri": "innocent-script.sh"
                },
                "region": {
                  "startLine": 23
                }
              }
            }
          ],
          "message": {
            "text": "Quotes/backslashes in this variable will not be respected."
          },
          "codeFlows": [
            {
              "threadFlows": [
                {
                  "locations": [
                    {
                      "location": {
                        "id": 0,
                        "physicalLocation": {
                          "artifactLocation": {
                            "uri": "innocent-script.sh"
                          },
                          "region": {
                            "startLine": 23
                          }
                        },
                        "message": {
                          "text": "Quotes/backslashes in this variable will not be respected."
                        }
                      },
                      "nestingLevel": 0,
                      "kinds": [
                        "warning[SC2090]"
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

GitHub UI

Screenshot from 2023-08-24 08-57-26

Upon clicking on the link with suggestions, the pop-up box shows the location (not visible enough IMHO):

Screenshot from 2023-08-24 08-57-39

Screenshot from 2023-08-24 08-57-47

The data can be used to show suggestions in console output as well. For example sarif-fmt tool shows:

Screenshot from 2023-08-24 08-58-35

Related to:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant