///|
/// Severity attached to one audit diagnostic.
pub(all) enum DiagnosticLevel {
Information
Warning
Failure
} derive(Eq, Debug)
///|
/// A stable diagnostic produced without raising an exception.
pub(all) struct AuditDiagnostic {
level : DiagnosticLevel
code : String
message : String
offset : Int
} derive(Eq, Debug)
///|
/// Conservative resource figures derived from a parsed delta.
pub(all) struct ResourceEstimate {
input_size : Int
declared_output_size : Int
largest_window_size : Int
largest_dictionary_size : Int
total_instructions : Int
estimated_peak_bytes : Int
} derive(Eq, Debug)
///|
/// Non-throwing validation result for untrusted VCDIFF bytes.
pub(all) struct AuditReport {
structurally_valid : Bool
decodable : Bool
decoded_size : Int
summary : DeltaSummary?
resources : ResourceEstimate
diagnostics : Array[AuditDiagnostic]
} derive(Eq, Debug)
///|
fn empty_resource_estimate(input_size : Int) -> ResourceEstimate {
{
input_size,
declared_output_size: 0,
largest_window_size: 0,
largest_dictionary_size: 0,
total_instructions: 0,
estimated_peak_bytes: input_size,
}
}
///|
fn diagnostic(
level : DiagnosticLevel,
code : String,
message : String,
offset : Int,
) -> AuditDiagnostic {
{ level, code, message, offset }
}
///|
fn checked_estimate_add(current : Int, amount : Int) -> Int {
if amount < 0 || current > MAX_PORTABLE_INT - amount {
MAX_PORTABLE_INT
} else {
current + amount
}
}
///|
fn estimate_resources(summary : DeltaSummary) -> ResourceEstimate {
let mut largest_window_size = 0
let mut largest_dictionary_size = 0
let mut total_instructions = 0
for window in summary.windows {
if window.target_size > largest_window_size {
largest_window_size = window.target_size
}
if window.source_size > largest_dictionary_size {
largest_dictionary_size = window.source_size
}
total_instructions = checked_estimate_add(
total_instructions,
window.add_count + window.run_count + window.copy_count,
)
}
let working = checked_estimate_add(
largest_window_size, largest_dictionary_size,
)
{
input_size: summary.file_size,
declared_output_size: summary.target_size,
largest_window_size,
largest_dictionary_size,
total_instructions,
estimated_peak_bytes: checked_estimate_add(summary.file_size, working),
}
}
///|
fn append_policy_diagnostics(
summary : DeltaSummary,
limits : DecodeLimits,
diagnostics : Array[AuditDiagnostic],
) -> Unit {
if summary.window_count == 0 {
diagnostics.push(
diagnostic(
Information,
"empty_delta",
"the delta contains no target windows",
summary.header_size,
),
)
}
if summary.file_size >= summary.target_size && summary.target_size > 0 {
diagnostics.push(
diagnostic(
Information,
"no_size_reduction",
"the delta is not smaller than its declared target",
0,
),
)
}
if summary.window_count > limits.max_windows {
diagnostics.push(
diagnostic(
Failure,
"window_limit",
"declared window count exceeds the configured limit",
summary.header_size,
),
)
}
if summary.target_size > limits.max_output_size {
diagnostics.push(
diagnostic(
Failure,
"output_limit",
"declared output size exceeds the configured limit",
summary.header_size,
),
)
}
for window in summary.windows {
if window.target_size > limits.max_window_size {
diagnostics.push(
diagnostic(
Failure,
"window_size_limit",
"declared target window exceeds the configured limit",
window.offset,
),
)
}
let operations = window.add_count + window.run_count + window.copy_count
if operations > limits.max_instructions_per_window {
diagnostics.push(
diagnostic(
Failure,
"instruction_limit",
"window instruction count exceeds the configured limit",
window.offset,
),
)
}
if window.source_kind == SourceDictionary && window.source_size == 0 {
diagnostics.push(
diagnostic(
Warning,
"empty_source_segment",
"VCD_SOURCE selects an empty dictionary segment",
window.offset,
),
)
}
if window.copy_count > 0 && window.address_size == 0 {
diagnostics.push(
diagnostic(
Failure,
"missing_addresses",
"COPY instructions exist but the address section is empty",
window.offset,
),
)
}
}
}
///|
fn failed_audit(input_size : Int, error : VcdiffError) -> AuditReport {
{
structurally_valid: false,
decodable: false,
decoded_size: 0,
summary: None,
resources: empty_resource_estimate(input_size),
diagnostics: [
diagnostic(Failure, error.code(), error.message(), error.offset()),
],
}
}
///|
fn decoding_failed_audit(
input_size : Int,
summary : DeltaSummary,
diagnostics : Array[AuditDiagnostic],
error : VcdiffError,
) -> AuditReport {
ignore(input_size)
diagnostics.push(
diagnostic(Failure, error.code(), error.message(), error.offset()),
)
{
structurally_valid: true,
decodable: false,
decoded_size: 0,
summary: Some(summary),
resources: estimate_resources(summary),
diagnostics,
}
}
///|
fn catch_decode_for_audit(
source : Bytes,
delta : Bytes,
limits : DecodeLimits,
summary : DeltaSummary,
diagnostics : Array[AuditDiagnostic],
) -> AuditReport {
let decoded = decode(source, delta, limits) catch {
InvalidMagic(offset~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidMagic(offset~),
)
UnsupportedVersion(offset~, version~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
UnsupportedVersion(offset~, version~),
)
UnsupportedFeature(offset~, feature~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
UnsupportedFeature(offset~, feature~),
)
TruncatedInput(offset~, needed~, available~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
TruncatedInput(offset~, needed~, available~),
)
InvalidVarint(offset~, reason~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidVarint(offset~, reason~),
)
IntegerOverflow(offset~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
IntegerOverflow(offset~),
)
InvalidHeader(offset~, reason~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidHeader(offset~, reason~),
)
InvalidWindow(offset~, reason~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidWindow(offset~, reason~),
)
InvalidInstruction(offset~, reason~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidInstruction(offset~, reason~),
)
InvalidAddress(offset~, address~, limit~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidAddress(offset~, address~, limit~),
)
MissingSource(offset~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
MissingSource(offset~),
)
ResourceLimit(offset~, resource~, limit~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
ResourceLimit(offset~, resource~, limit~),
)
LengthMismatch(offset~, expected~, actual~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
LengthMismatch(offset~, expected~, actual~),
)
VerificationMismatch(offset~, expected_size~, actual_size~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
VerificationMismatch(offset~, expected_size~, actual_size~),
)
InvalidOption(option~, reason~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
InvalidOption(option~, reason~),
)
Io(path~, reason~) =>
return decoding_failed_audit(
delta.length(),
summary,
diagnostics,
Io(path~, reason~),
)
}
{
structurally_valid: true,
decodable: true,
decoded_size: decoded.length(),
summary: Some(summary),
resources: estimate_resources(summary),
diagnostics,
}
}
///|
/// Audits untrusted delta bytes without raising VCDIFF errors.
///
/// Structural validity is reported separately from source-dependent
/// decodability, and successful reports include conservative memory figures.
pub fn audit(
source : Bytes,
delta : Bytes,
limits : DecodeLimits,
) -> AuditReport {
let summary = inspect(delta) catch {
InvalidMagic(offset~) =>
return failed_audit(delta.length(), InvalidMagic(offset~))
UnsupportedVersion(offset~, version~) =>
return failed_audit(delta.length(), UnsupportedVersion(offset~, version~))
UnsupportedFeature(offset~, feature~) =>
return failed_audit(delta.length(), UnsupportedFeature(offset~, feature~))
TruncatedInput(offset~, needed~, available~) =>
return failed_audit(
delta.length(),
TruncatedInput(offset~, needed~, available~),
)
InvalidVarint(offset~, reason~) =>
return failed_audit(delta.length(), InvalidVarint(offset~, reason~))
IntegerOverflow(offset~) =>
return failed_audit(delta.length(), IntegerOverflow(offset~))
InvalidHeader(offset~, reason~) =>
return failed_audit(delta.length(), InvalidHeader(offset~, reason~))
InvalidWindow(offset~, reason~) =>
return failed_audit(delta.length(), InvalidWindow(offset~, reason~))
InvalidInstruction(offset~, reason~) =>
return failed_audit(delta.length(), InvalidInstruction(offset~, reason~))
InvalidAddress(offset~, address~, limit~) =>
return failed_audit(
delta.length(),
InvalidAddress(offset~, address~, limit~),
)
MissingSource(offset~) =>
return failed_audit(delta.length(), MissingSource(offset~))
ResourceLimit(offset~, resource~, limit~) =>
return failed_audit(
delta.length(),
ResourceLimit(offset~, resource~, limit~),
)
LengthMismatch(offset~, expected~, actual~) =>
return failed_audit(
delta.length(),
LengthMismatch(offset~, expected~, actual~),
)
VerificationMismatch(offset~, expected_size~, actual_size~) =>
return failed_audit(
delta.length(),
VerificationMismatch(offset~, expected_size~, actual_size~),
)
InvalidOption(option~, reason~) =>
return failed_audit(delta.length(), InvalidOption(option~, reason~))
Io(path~, reason~) =>
return failed_audit(delta.length(), Io(path~, reason~))
}
let diagnostics : Array[AuditDiagnostic] = []
append_policy_diagnostics(summary, limits, diagnostics)
catch_decode_for_audit(source, delta, limits, summary, diagnostics)
}
///|
fn DiagnosticLevel::name(self : DiagnosticLevel) -> String {
match self {
Information => "info"
Warning => "warning"
Failure => "error"
}
}
///|
/// Renders a concise audit report for logs and command-line tools.
pub fn AuditReport::to_text(self : AuditReport) -> String {
let builder = StringBuilder()
builder <+ "structurally valid: \{self.structurally_valid}\n"
builder <+ "decodable: \{self.decodable}\n"
builder <+ "decoded size: \{self.decoded_size}\n"
builder <+ "estimated peak bytes: \{self.resources.estimated_peak_bytes}\n"
for item in self.diagnostics {
builder <+ "[\{item.level.name()}] \{item.code}"
if item.offset >= 0 {
builder <+ " at byte \{item.offset}"
}
builder <+ ": \{item.message}\n"
}
builder.to_string()
}