Skip to main content

FindingReport

Struct FindingReport 

Source
pub struct FindingReport { /* private fields */ }
Expand description

A set of findings and what the scan that produced them managed to look at.

A lenient read rejects no image, so an empty report means the image is conformant to what its family’s writer emits and a non-empty one is a list of findings, not a failure. has_fatal applies a ReadPolicy threshold back to those findings, and to_json, to_sarif, and to_table project them for a machine or a person.

A report says through is_truncated when the scan stopped at its findings cap with the image still unfinished.

§Two serializations, and which is the document

to_json and to_sarif emit documents: a shape this crate versions through FINDINGS_SCHEMA_VERSION, leading with that version and with the verdict and count computed from the findings. That is what a consumer parses.

The serde implementation is something else, and deliberately: it serializes the Rust value as it stands, so a caller embedding a report inside a structure of its own gets the fields the type has and nothing derived. It carries no schema version, because it is not the schema. Where the two describe the same thing they agree — a severity and a family are spelled the same in both — and a Coordinate is a tuple in one and an object in the other because in one it is a Rust tuple and in the other it is a document field.

Implementations§

Source§

impl FindingReport

Source

pub const MAX_FINDINGS: usize = 10_000

The default of Limits::max_findings: the most findings one report holds unless a caller names another cap.

A scan reads an image it has no reason to trust, and how many findings that image yields is the image’s own claim: a handful of crafted structures can name the same blocks over and over, and each faulty one is a finding carrying an owned description. The cap is what keeps a report’s memory a property of this crate rather than of the bytes it was pointed at, and it is far past the count anyone reads: a filesystem with ten thousand findings is diagnosed by its first ten.

Source

pub fn new(findings: Vec<Finding>, truncated: bool, cap: usize) -> Self

A report holding findings, from a scan that ran under cap and stopped early if truncated.

A family builds one of these from its own taxonomy; nothing else needs to.

Source

pub fn findings(&self) -> &[Finding]

The findings, in the order the scan walked them.

Source

pub fn is_truncated(&self) -> bool

Whether the scan stopped at its findings cap with the image still unfinished.

A truncated report is a floor, not a full accounting: the image holds at least these findings, and the scan did not look at the rest of it. Everything derived from the report — worst_severity, has_fatal — is likewise a floor, and is_clean is false whatever the report holds, since a scan that stopped short has seen nothing that would let it call an image clean.

Source

pub fn is_clean(&self) -> bool

Whether the scan looked at the whole image and found nothing.

A truncated report is never clean, however few findings it holds. The cap can be set low enough that a scan stops before reporting anything — at zero, before reading a single structure — and an empty report from a scan that stopped is an absence of looking, not an absence of faults.

Source

pub fn worst_severity(&self) -> Option<Severity>

The severity of the most serious finding, or None when the report is clean.

Source

pub fn has_fatal(&self, policy: ReadPolicy) -> bool

Whether any finding is fatal under policy — the same threshold ReadPolicy::Strict enforces when opening an image. Under ReadPolicy::Lenient it is always false.

Source

pub fn to_json(&self) -> String

Render the report as a JSON object: schema, clean (bool), count, truncated (bool), and a findings array. A projection computed here, not a stored wire format.

truncated is always present, true or false: a consumer must be able to tell a complete report from one that stopped at its findings cap, and an absent field would read as complete.

The document opens with "schema", holding FINDINGS_SCHEMA_VERSION. A downstream parser has a contract that no Rust signature describes, so the emitted shape names its own version rather than leaving a change to be discovered by a parse failure.

Source

pub fn to_sarif(&self, artifact_uri: Option<&str>) -> String

Render the report as a SARIF 2.1.0 log: a single run whose tool is this crate and whose results are the findings, one per finding, for a static-analysis or forensic pipeline that speaks SARIF.

Severity maps onto SARIF’s three actionable levels — structural and integrity are error, conformance is warning, cosmetic is note — and the exact severity, family, subsystem, byte offset, and coordinates ride in each result’s properties, so nothing the level collapse would lose is lost. The coordinates become a SARIF logical location, and a known byte offset becomes the physical location’s address. Like to_json, the document is a pure function of the report — no tool version or timestamp enters it — so identical findings render identical bytes.

A report that stopped at its findings cap carries a warning-level toolExecutionNotifications entry saying so, naming the cap that applied, which is where SARIF records something about the run rather than about the artifact. A complete report emits no invocations at all, so the document a clean or short scan renders is unchanged by the cap existing.

artifact_uri, when set, becomes each result’s physical artifact location: a reader reads an anonymous stream, so the image’s identity is the caller’s to supply. It is written through unchanged, which makes it a precondition that the string is already a URI reference as RFC 3986 defines one. A host path is not: a space is not allowed in a URI at all, and #, ?, and % each mean something else, so a strict SARIF consumer rejects a document carrying one. Percent-encode a path — every byte outside A-Z, a-z, 0-9, -, ., _, ~, keeping / — before passing it here.

Source

pub fn to_table(&self) -> String

Render the report as a fixed-column human table: a header row, then one line per finding with its severity, category, location, and detail. A clean report renders a single no findings line.

A truncated report ends with the notice saying so, whether or not it holds findings — an empty one is the case where saying so matters most, since no findings on its own would read as a verdict the scan never reached.

Trait Implementations§

Source§

impl Clone for FindingReport

Source§

fn clone(&self) -> FindingReport

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for FindingReport

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for FindingReport

Source§

fn default() -> Self

An empty report from a scan under the default limits.

Source§

impl PartialEq for FindingReport

Source§

fn eq(&self, other: &FindingReport) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for FindingReport

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Eq for FindingReport

Source§

impl StructuralPartialEq for FindingReport

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.