Repository navigation
feat(sarif): describe the rules, give each result its confidence and related locations - #274
Merged
Merged
Conversation
Each SARIF rule repeats its id as its only text, so GitHub code scanning, an IDE or CoreTrace's merged log can show a finding's message but cannot explain its rule. Every rule the usage guide documents, and unsupported-syntax, must have a title other than its id and a description; a rule without one, from a third-party plugin, keeps its id alone. Refs #270
coretrace_python.findings.rules gives a title and a description for each rule the usage guide documents, and for unsupported-syntax, for a report to explain the rule behind a finding. A rule a third-party plugin reports has none. Refs #270
A SARIF rule now carries its title as shortDescription and what it detects as fullDescription. A rule the analyzer does not describe, from a third-party plugin, keeps its id alone instead of repeating it as a title. Refs #270
The finding model rates each finding low, medium or high, but the SARIF log drops it. Each result must carry it as the confidence property, as CoreTrace's merged log spells it, beside the injection, context and origin properties. Refs #271
Each SARIF result now carries its finding's confidence, low, medium or high, as the confidence property, so that a consumer can rank it; CoreTrace's merged log spells it the same way. The tests that compared a result's properties exactly now expect the confidence beside the injection, context and origin they check, and still nothing else. Refs #271
A finding has a single span. RelatedLocation names another place, a source span and a short message, and Finding.related lists them, empty by default. Nothing fills them yet. Refs #271
…lves A finding's related locations, such as the sink a flow reaches inside a project function, must become the result's relatedLocations, each with its span and message, numbered from 0; a finding without any has none. Refs #271
Each related location of a finding becomes an entry of the result's relatedLocations, numbered from 0, with its file and region and its message, so that GitHub code scanning shows it as a link next to the alert. The region of a span is now built in one place for both. Refs #271
…st be a related location A flow reaching eval inside a project function is reported at the call, its sink line only in metadata. The sink must be a related location of the finding, with a message saying the input reaches it there; a sink in the function itself needs none. Refs #271
The cache, which the parallel analysis also goes through, encoded a finding without its related locations, so a second run or a parallel one would report them without the places they involve. They are now encoded with their span and message, and CACHE_FORMAT goes to 18 so that an older cache, which has none, is rebuilt. Refs #271
…nction A flow reaching its sink inside a project function is reported at the call, the sink's line only in metadata. The sink is now a related location of the finding, with the message 'the input reaches <sink> here, in <function>', so that the SARIF log links to it. Refs #271
relatedLocations is filled but the message never references them, so GitHub code scanning shows no link. In SARIF only, the message must end with an embedded link [text](id) to each related location, with literal brackets and backslashes escaped around them. Refs #271
…as the sink's function For run -> relay -> evaluate -> eval, the related location points into evaluate but said 'here, in relay': through names the first call the flow goes through, not where the sink is. It must say the sink is reached via relay. Refs #271
A result with related locations now ends its message with an embedded link [text](id) to each, which GitHub code scanning renders as a link to the place; brackets and backslashes of the text around the links are escaped, as SARIF requires. A result without related locations, and the text and JSON reports, keep the message as it is. Refs #271
The related location of a flow through project functions said 'the input reaches <sink> here, in <through>', but through is the first call the flow goes through: two calls away, it named a function the sink is not in. The message is now 'sink <sink>, reached via <through>', which holds at any depth and also reads as a link. Refs #271
The SARIF reporter only looked up a central table, so a third-party plugin had no way to describe its rules: they came out as their id alone. A plugin declaring the description of its rule must see it in the SARIF log, and a plugin declaring nothing must still load and report by id. Refs #270
Plugin.rules maps each rule id the plugin reports to its RuleDescription, a title and what it detects, for a report to explain the findings. It is optional and empty by default, so existing plugins load unchanged and their rules are listed by id alone. RuleDescription is exported from coretrace_python.findings. Refs #270
The SARIF reporter looked up a central table, so only the rules that table knew were described. A check now gathers the descriptions its loaded plugins declare, ProjectAnalysis and FileAnalysis carry them as rules, engine.report and the command line pass them to the Report, and the SARIF reporter reads report.rules only. The central table still seeds the engine's descriptions until the bundled plugins declare their own. The check that every documented rule is described now runs through a check with the bundled plugins, and the reporter's own test gives the report its descriptions. Refs #270
…rts it The descriptions lived in one central table. Each bundled plugin now declares those of the rules it reports in its rules attribute, SecretDetector those of the three secret rules, and the engine its own two (unsupported-syntax, exploitable-vulnerability) in ENGINE_RULES; the central table is gone, and coretrace_python.findings.rules keeps RuleDescription only. The reports are unchanged. Refs #270
…ne's notes included The documented rules were described, but the engine's own notes, syntax-error and ambiguous-module, came out as their id alone. Every rule id the code gives a finding, read from the sources (a rule_id class attribute or argument, the first argument of Finding or of the engine's _note), must be described by the bundled plugins or the engine. Refs #270
syntax-error, a file that could not be read or parsed, and ambiguous-module, a file whose import name another file shares, are notes the engine reports itself; ENGINE_RULES now describes them, beside unsupported-syntax and exploitable-vulnerability, so that no rule the code reports comes out as its id alone. Refs #270
This was referenced Oct 22, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #270. Closes #271.
In the SARIF log, each rule's only text was its id, the confidence the model rates every finding with was dropped, and a finding could not point at a second place. GitHub code scanning, an IDE or CoreTrace's merged log could show a finding's message, but not explain its rule, rank it, or link to where the problem happens.
Changes
Plugin.rules, a mapping from rule id toRuleDescription(a title and what the rule detects). It is optional, so existing plugins load unchanged and their rules are listed by id alone.engine.ENGINE_RULES:unsupported-syntax,syntax-error,ambiguous-moduleandexploitable-vulnerability.SecretDetectordeclares the three secret rules.engine.rule_descriptions).ProjectAnalysisandFileAnalysiscarry them asrules, and the command line passes them toReport.rules.report.rulesonly. A SARIF rule then carries the title asshortDescriptionand the description asfullDescription.low,medium,high) as theconfidenceproperty, as CoreTrace's merged log spells it.RelatedLocation(a span and a message) andFinding.relatedlet a finding name other places. The SARIF reporter writes them asrelatedLocations, numbered from 0.[text](id), with brackets and backslashes escaped around them. The text and JSON reports keep the message as it is.sink python.builtins.eval, reached via relay, whererelayis the call the flow goes through, at any depth. Thethroughandsink_linemetadata are kept.CACHE_FORMATgoes to 18, so caches miss once.Compatibility
propertiesis now present on every result, with the confidence besideinjection,contextandorigin.propertiesexactly. They now expect the confidence beside the properties they check, and still nothing else, so the guarantee that no other metadata is exported holds.Tests
Each new test was committed before its implementation and failed for the expected reason:
test_rule_descriptions:syntax-errorandambiguous-module.test_reporters:test_code_injection: the sink inside a project function is a related location, reached via the first call even two calls away; a sink in the function itself gives none.test_cacheandtest_parallelcaught that the cache dropped the related locations, before the codec kept them.Results:
pytest: 2464 passed, 19 regression tests deselected (network).mypyandruff check .are clean.