Skip to content

Commit 691373d

Browse files
committed
Merge remote-tracking branch 'origin/claude/new-session-th4e9w' into claude/new-session-th4e9w-clippy
2 parents 5cdd1df + 0e6febb commit 691373d

9 files changed

Lines changed: 105 additions & 15 deletions

File tree

‎src/aggregate/mod.rs‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,11 @@ pub fn run(config: AggregateConfig) -> Result<AggregateReport> {
394394
})
395395
}
396396

397+
/// Write the aggregate report as pretty-printed JSON, creating parent directories
398+
/// and replacing any existing file at `path`.
399+
///
400+
/// # Errors
401+
/// Returns directory creation, JSON serialisation and file write errors.
397402
pub fn write_report(report: &AggregateReport, path: &Path) -> Result<()> {
398403
if let Some(parent) = path.parent() {
399404
if !parent.as_os_str().is_empty() {
@@ -493,6 +498,8 @@ fn has_metavar_hole(text: &str) -> bool {
493498
false
494499
}
495500

501+
/// Look for case-sensitive proof or declaration substrings as a closure heuristic;
502+
/// a match does not verify that the text contains a valid proof.
496503
fn has_proof_keyword(text: &str) -> bool {
497504
const KW: &[&str] = &[
498505
"theorem", "lemma", "Theorem", "Lemma", "Proof", "proof", "where", ":=", "data ", "record ",
@@ -606,6 +613,10 @@ fn scan_covers(text: &str) -> Vec<Coverage> {
606613

607614
/// Parse `[claim:]kind:value`, e.g. `sound:category:UnsafeCode`,
608615
/// `safe:file:src/foo.rs`, `category:PanicPath`, `free:my-lemma`.
616+
///
617+
/// A bare token other than `safe` or `sound` becomes free-form coverage with an
618+
/// unspecified claim. Returns `None` for an empty first field, an unrecognised
619+
/// kind or an unsupported field layout. Values are retained without trimming.
609620
pub fn parse_coverage_spec(spec: &str) -> Option<Coverage> {
610621
let mut parts: Vec<&str> = spec.splitn(3, ':').collect();
611622
if parts.is_empty() || parts[0].is_empty() {
@@ -692,6 +703,7 @@ fn summarise(findings: &[FindingLite]) -> FindingSummary {
692703
}
693704
}
694705

706+
/// Count findings selected by the coverage annotation; free-form coverage matches none.
695707
fn count_matching(findings: &[FindingLite], cov: &Coverage) -> usize {
696708
findings.iter().filter(|f| matches_coverage(f, cov)).count()
697709
}

‎src/assail/analyzer.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,10 @@ impl Analyzer {
941941
// Original language analyzers
942942
// ============================================================
943943

944+
/// Accumulate Rust statistics and append heuristic findings for `file_path`.
945+
/// Dangerous-pattern checks exclude string contents, comments, `cfg`-selected
946+
/// test bodies and `should_panic` bodies. Panic counts and findings also exclude
947+
/// test paths and build scripts.
944948
fn analyze_rust(
945949
&self,
946950
content: &str,
@@ -1767,6 +1771,9 @@ impl Analyzer {
17671771
false
17681772
}
17691773

1774+
/// Accumulate C/C++ statistics and append heuristic findings for `file_path`.
1775+
/// Unchecked malloc findings include one-based line numbers for suppression
1776+
/// and omit allocations with a recognised nearby null check.
17701777
fn analyze_c_cpp(
17711778
&self,
17721779
content: &str,
@@ -2012,6 +2019,8 @@ impl Analyzer {
20122019
Ok(())
20132020
}
20142021

2022+
/// Accumulate Go statistics and append heuristic concurrency, unsafe pointer,
2023+
/// command execution and cryptography findings located at `file_path`.
20152024
fn analyze_go(
20162025
&self,
20172026
content: &str,
@@ -2141,6 +2150,8 @@ impl Analyzer {
21412150
Ok(())
21422151
}
21432152

2153+
/// Accumulate Python I/O and threading counts and append heuristic loop,
2154+
/// code execution, deserialisation, command and cryptography findings for `file_path`.
21442155
fn analyze_python(
21452156
&self,
21462157
content: &str,
@@ -3168,6 +3179,9 @@ impl Analyzer {
31683179
}
31693180
}
31703181

3182+
/// Accumulate OCaml statistics and append heuristic findings for `file_path`.
3183+
/// Classify `Obj.magic` as proof drift when Coq extraction markers are present,
3184+
/// or as unsafe type coercion otherwise.
31713185
fn analyze_ocaml(
31723186
&self,
31733187
content: &str,
@@ -4320,6 +4334,8 @@ impl Analyzer {
43204334
Ok(())
43214335
}
43224336

4337+
/// Accumulate Odin operation counts and append a Medium unsafe-code finding
4338+
/// at `file_path` when `rawptr` occurs in the content.
43234339
fn analyze_odin(
43244340
&self,
43254341
content: &str,
@@ -4498,6 +4514,9 @@ impl Analyzer {
44984514
// Config languages (Nickel, Nix)
44994515
// ============================================================
45004516

4517+
/// Accumulate Nix/Nickel I/O counts and append Nix command and unpinned-flake findings.
4518+
/// Uses `file_path` for file-type checks, finding locations and the sibling
4519+
/// `flake.lock` lookup on disk.
45014520
fn analyze_config(
45024521
&self,
45034522
content: &str,
@@ -4602,6 +4621,9 @@ impl Analyzer {
46024621
// Shell scripting
46034622
// ============================================================
46044623

4624+
/// Accumulate shell I/O counts and append heuristic command, permission and
4625+
/// temporary-path findings for `file_path`. Unquoted expansion findings require
4626+
/// more than 20 `$VAR` matches after quoted string contents are removed.
46054627
fn analyze_shell(
46064628
&self,
46074629
content: &str,
@@ -5035,6 +5057,8 @@ impl Analyzer {
50355057
// Cross-language security checks (run on ALL files)
50365058
// ============================================================
50375059

5060+
/// Append heuristic protocol, hardcoded secret and excessive comment-marker
5061+
/// findings located at `file_path`, independently of the detected language.
50385062
fn analyze_cross_language(
50395063
&self,
50405064
content: &str,

‎src/assail/mod.rs‎

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -402,21 +402,22 @@ pub fn apply_suppression(report: &mut AssailReport) {
402402
report.suppressed_count = count;
403403
}
404404

405-
/// v2.5.5 context-aware FP suppression pass — applies four checks per
405+
/// v2.5.5 context-aware FP suppression pass — applies three checks per
406406
/// finding:
407407
/// 1. Inline `panic-attack: accepted` marker on the same or
408-
/// preceding line ([[comment_marker]]).
408+
/// preceding line, when `wp.line` is known ([[comment_marker]]).
409409
/// 2. PanicPath finding in a TestOnly or Doc test_context
410410
/// ([[test_context]]).
411411
/// 3. UnsafeFFI finding where the file's [[ffi_kind]] is
412412
/// `BuildSystem` or `TestMock` (audit-accepted by default).
413-
/// 4. (jit_context wire-up handled inline in analyzer.rs:1117..1129
414-
/// already; not duplicated here.)
415413
///
416-
/// Sets `wp.test_context` for every finding with a known file path so
414+
/// JIT context handling remains inline in analyzer.rs:1117..1129.
415+
///
416+
/// Fills missing `wp.test_context` for findings with a known file path so
417417
/// downstream audit consumers can render it. Returns the number of
418418
/// findings newly flipped from `suppressed=false` to `suppressed=true`
419419
/// (already-suppressed findings are NOT re-counted).
420+
/// File read errors disable marker checks and use path-only context classification.
420421
pub fn apply_v255_context_suppression(report: &mut AssailReport) -> usize {
421422
use crate::comment_marker;
422423
use crate::ffi_kind::FfiKind;

‎src/assay/mod.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ pub fn run(config: AssayConfig) -> Result<AssayReport> {
277277
})
278278
}
279279

280+
/// Write the assay report as pretty-printed JSON, creating parent directories
281+
/// and replacing any existing file at `path`.
282+
///
283+
/// # Errors
284+
/// Returns directory creation, JSON serialisation and file write errors.
280285
pub fn write_report(report: &AssayReport, path: &Path) -> Result<()> {
281286
if let Some(parent) = path.parent() {
282287
if !parent.as_os_str().is_empty() {
@@ -348,6 +353,20 @@ pub struct AssimilateConfig {
348353
pub dry_run: bool,
349354
}
350355

356+
/// Apply selected proven-module substitutions and return provenance records and notes.
357+
///
358+
/// `apply_all` selects offered candidates; otherwise `candidate_id` is required.
359+
/// Already-applied candidates are skipped. The `from` override requires exactly
360+
/// one selected candidate. Call sites are returned for manual rewiring.
361+
///
362+
/// Unless `dry_run` is set, copy replacement files, preserve existing `.orig`
363+
/// backups and write provenance under the target's `.assimilated/` directory.
364+
/// Dry runs still resolve and hash sources and existing destination files.
365+
///
366+
/// # Errors
367+
/// Returns survey errors, invalid candidate or source selection errors, and errors
368+
/// from hashing, directory creation, file copying or provenance serialisation/writing.
369+
/// Earlier file changes remain in place if a later operation fails.
351370
pub fn assimilate(config: AssimilateConfig) -> Result<AssimilationOutcome> {
352371
let assay = run(AssayConfig {
353372
target: config.target.clone(),

‎src/diagnostics.rs‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,8 +193,11 @@ fn check_watcher(label: &'static str, env_key: &str) -> Diagnostic {
193193
/// Verifies:
194194
/// 1. Bot directives file exists at `.machine_readable/bot_directives/panicbot.scm`
195195
/// 2. JSON output contract: AssailReport serialises with the fields panicbot expects
196-
/// (`program_path`, `weak_points`, `language`, `statistics`)
196+
/// (`program_path`, `weak_points`, `language`)
197197
/// 3. WeakPointCategory and Severity serialise in PascalCase (no serde rename_all)
198+
///
199+
/// Failed JSON checks, including serialisation errors, yield an error diagnostic;
200+
/// missing directives alone yield a warning.
198201
fn check_panicbot_readiness() -> Diagnostic {
199202
let directive_path = Path::new(PANICBOT_DIRECTIVE_PATH);
200203
let has_directives = directive_path.is_file();

‎src/ffi_kind.rs‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ fn is_build_system_path(p: &str) -> bool {
8787
|| p.contains("build.cargo/")
8888
}
8989

90+
/// Recognise test mock paths by case-sensitive test-scope and mock/stub substrings.
9091
fn is_test_mock_path(p: &str) -> bool {
9192
// Test mocks live under tests/ AND have "mock" or "stub" in the
9293
// path. Plain test files are still RuntimeAbi if they call the
@@ -120,9 +121,11 @@ fn is_runtime_abi_path(p: &str) -> bool {
120121
/// project's pre-approved FFI boundary audit (typically
121122
/// `audits/audit-ffi-unsafe.md`).
122123
///
123-
/// Implementation note: this is a placeholder that parses the audit
124-
/// file when present and returns false otherwise. Wire-in to the
125-
/// analyzer happens in the follow-up PR.
124+
/// Reads the supplied `audit_text` without accessing the filesystem. Section
125+
/// headings `Approved boundaries`, `Approved FFI boundaries` and `Pre-approved
126+
/// boundaries` are recognised case-insensitively at Markdown level two. Within
127+
/// them, the first token after an optional list marker is compared exactly with
128+
/// `file_path`, ignoring surrounding backticks. Returns false if no token matches.
126129
pub fn is_audited_boundary(audit_text: &str, file_path: &str) -> bool {
127130
// The audit file's convention is a `## Approved boundaries` section
128131
// with a markdown list of `- file/path/here.zig — rationale` lines.

‎src/jit_context.rs‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub fn classify_rust(content: &str) -> JitContext {
8181
}
8282
}
8383

84+
/// Recognise Cranelift imports or JIT API usage by case-sensitive substring matches.
8485
fn is_cranelift(content: &str) -> bool {
8586
content.contains("cranelift_jit::JITModule")
8687
|| content.contains("cranelift_module::Module")
@@ -113,9 +114,10 @@ fn is_javascript_embedding(content: &str) -> bool {
113114
|| (content.contains("v8::") && content.contains("Function::call"))
114115
}
115116

116-
/// True if a `mem::transmute` (or `transmute_copy`) in this content
117-
/// targets a function-pointer type. Pattern-matches the standard
118-
/// turbofish forms and let-binding forms documented in
117+
/// Look for `transmute` syntax suggesting a function-pointer target.
118+
/// Recognises selected turbofish forms or a function-pointer annotation occurring
119+
/// anywhere alongside a `transmute(` call, without verifying they belong to the
120+
/// same expression. `transmute_copy` is not recognised. See the related forms in
119121
/// `src/assail/analyzer.rs:1110..1129`.
120122
pub fn transmute_targets_fn_ptr(content: &str) -> bool {
121123
// Turbofish forms — unambiguous.

‎src/main.rs‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,13 @@ fn main() -> Result<()> {
13651365
result
13661366
}
13671367

1368+
/// Parse process arguments and execute the selected command, including its output
1369+
/// and requested persistence. Default manifest settings are used if loading fails.
1370+
/// Argument parsing exits the process for help or invalid CLI syntax.
1371+
///
1372+
/// # Errors
1373+
/// Returns command validation errors and propagates I/O, serialisation and
1374+
/// operation errors that are not handled by a command-specific fallback.
13681375
fn run_main() -> Result<()> {
13691376
let cli = Cli::parse();
13701377
let manifest = match Manifest::load_default() {

‎src/scan/cargodeny.rs‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,15 @@ fn code_to_category(code: &str) -> WeakPointCategory {
112112
}
113113
}
114114

115-
/// Run cargo-deny check and parse output
115+
/// Run `cargo deny check` in the configured workspace and return its diagnostic findings.
116+
///
117+
/// Standard output must be UTF-8 JSON matching `DenyOutput`, regardless of
118+
/// `config.format`. A non-zero exit status still yields findings if parsing succeeds.
119+
/// Missing severity and code fields default to Medium and Advisory respectively.
120+
/// `config.deny_toml` is currently ignored.
121+
///
122+
/// # Errors
123+
/// Returns process execution errors, invalid UTF-8 errors and JSON deserialisation errors.
116124
pub fn run_cargo_deny(config: &CargoDenyConfig) -> Result<Vec<WeakPoint>> {
117125
let workspace_root = &config.workspace_root;
118126

@@ -257,7 +265,13 @@ impl From<WeakPoint> for CargoDenyWeakPoint {
257265
}
258266
}
259267

260-
/// Parse cargo-deny SARIF output (alternative to JSON)
268+
/// Convert cargo-deny SARIF results into findings, using only the first location
269+
/// of each result. Missing levels default to Medium severity; missing or
270+
/// unrecognised rule IDs default to Advisory.
271+
///
272+
/// # Errors
273+
/// Returns JSON parsing errors, or an error if `runs` or any run's `results` is
274+
/// absent or is not an array. Empty `runs` and `results` arrays are valid.
261275
#[cfg(feature = "sarif")]
262276
pub fn parse_sarif_output(sarif_json: &str) -> Result<Vec<WeakPoint>> {
263277
use serde_json::Value;
@@ -344,7 +358,12 @@ pub fn parse_sarif_output(sarif_json: &str) -> Result<Vec<WeakPoint>> {
344358
Ok(weak_points)
345359
}
346360

347-
/// High-level function to scan a workspace and emit cargo-deny weak points
361+
/// Scan a workspace with cargo-deny's JSON defaults and return diagnostic findings.
362+
/// The `deny_toml` argument currently has no effect.
363+
///
364+
/// # Errors
365+
/// Propagates execution, UTF-8 decoding and JSON deserialisation errors from
366+
/// [`run_cargo_deny`]. A non-zero cargo-deny exit status alone is not an error.
348367
pub fn scan_workspace(workspace_root: &Path, deny_toml: Option<&Path>) -> Result<Vec<WeakPoint>> {
349368
let config = CargoDenyConfig {
350369
workspace_root: workspace_root.to_path_buf(),

0 commit comments

Comments
 (0)