Skip to content

feat: Heavily improve machine readable evidence and expose more evidence#6

Merged
math280h merged 1 commit intomainfrom
feat/machine-readable-decisions
Feb 26, 2026
Merged

feat: Heavily improve machine readable evidence and expose more evidence#6
math280h merged 1 commit intomainfrom
feat/machine-readable-decisions

Conversation

@math280h
Copy link
Copy Markdown
Owner

No description provided.

@math280h math280h self-assigned this Feb 26, 2026
Copilot AI review requested due to automatic review settings February 26, 2026 00:39
@math280h math280h merged commit 58ed2e3 into main Feb 26, 2026
4 of 5 checks passed
@math280h math280h deleted the feat/machine-readable-decisions branch February 26, 2026 00:39
@github-actions
Copy link
Copy Markdown

Coverage

Coverage Report

Metric Value
Total lines 5148
Covered lines 4334
Missed lines 814
Coverage 84.19%
Tests passed 160
Tests failed 0
Tests ignored 0
Coverage command exit 0
Per-file coverage (top 40 by missed lines)
File Stmts Miss Cover Missing
/home/runner/work/safe-pkgs/safe-pkgs/src/custom_rules.rs 191 116 39.27% 42, 71, 72, 81, 82, 83, 84, 97, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/service.rs 251 109 56.57% 36, 37, 38, 39, 40, 41, 80, 81, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/config/custom_rules.rs 155 67 56.77% 132, 159, 165, 172, 175, 194, 195, 197, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/staleness/src/lib.rs 205 54 73.66% 50, 51, 52, 53, 54, 55, 56, 57, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/main.rs 93 44 52.69% 42, 114, 115, 117, 118, 119, 120, 121, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/core/src/lib.rs 347 37 89.34% 82, 83, 84, 100, 101, 102, 118, 119, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/npm/src/registry.rs 292 33 88.70% 64, 90, 91, 94, 95, 96, 97, 98, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/mcp/server.rs 97 32 67.01% 104, 105, 106, 128, 129, 131, 132, 133, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/checks.rs 393 31 92.11% 136, 150, 151, 152, 153, 154, 155, 156, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/pypi/src/registry.rs 225 25 88.89% 47, 48, 49, 54, 55, 56, 71, 72, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/pypi/src/lockfile.rs 393 25 93.64% 26, 27, 28, 43, 44, 45, 62, 63, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/cache.rs 123 22 82.11% 25, 26, 27, 28, 29, 30, 31, 32, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/config/mod.rs 171 20 88.30% 196, 197, 198, 209, 295, 296, 297, 298, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/cargo/src/registry.rs 201 20 90.05% 36, 37, 38, 43, 44, 45, 60, 61, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/cargo/src/lockfile.rs 308 20 93.51% 27, 28, 29, 44, 45, 46, 60, 67, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/bin/safe-pkgs-mcp.rs 37 16 56.76% 12, 13, 14, 15, 16, 18, 21, 22, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/osv/src/lib.rs 162 14 91.36% 9, 10, 11, 12, 13, 14, 15, 16, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/npm/src/lockfile.rs 294 13 95.58% 27, 28, 29, 44, 45, 46, 57, 93, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/typosquat/src/lib.rs 116 13 88.79% 64, 75, 78, 79, 87, 112, 154, 155, ...
/home/runner/work/safe-pkgs/safe-pkgs/src/registries/mod.rs 152 9 94.08% 58, 59, 60, 134, 154, 163, 164, 165, ...
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/existence/src/lib.rs 48 3 93.75% 36, 37, 38
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/advisory/src/lib.rs 116 3 97.41% 68, 129, 142
/home/runner/work/safe-pkgs/safe-pkgs/src/audit_log.rs 53 2 96.23% 60, 109
/home/runner/work/safe-pkgs/safe-pkgs/src/support_map.rs 142 1 99.30% 58
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/pypi/src/lib.rs 13 0 100.00% -
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/npm/src/lib.rs 13 0 100.00% -
/home/runner/work/safe-pkgs/safe-pkgs/crates/registry/cargo/src/lib.rs 13 0 100.00% -
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/version-age/src/lib.rs 65 0 100.00% -
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/popularity/src/lib.rs 80 0 100.00% -
/home/runner/work/safe-pkgs/safe-pkgs/crates/checks/install-script/src/lib.rs 55 0 100.00% -

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request adds comprehensive machine-readable evidence to all package check responses, enabling downstream automation and policy evaluation. The changes introduce a structured Evidence type with stable identifiers, severity levels, human-readable messages, and typed fact dictionaries. All checks, custom rules, policy decisions, and runtime errors now emit evidence alongside existing human-readable reasons.

Changes:

  • Introduced Evidence and EvidenceKind types with stable ID conventions for checks, custom rules, policy, and runtime evidence
  • Updated all check implementations to use CheckFinding::new() builder pattern with reason_code and structured facts
  • Added evidence collection and propagation through check orchestration, service layer, and MCP responses
  • Updated documentation and removed completed roadmap item for structured evidence
  • Added comprehensive test coverage for evidence schema validation across registries

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/types.rs Defines core Evidence and EvidenceKind types for API responses
crates/core/src/lib.rs Extends CheckFinding with reason_code, facts, and FindingValue enum
src/checks.rs Orchestrates evidence collection from checks/custom rules, generates policy evidence
src/custom_rules.rs Wraps custom rule findings with rule_id for evidence generation
src/service.rs Propagates evidence through service layer, adds runtime error evidence
src/audit_log.rs Adds evidence field to audit log records
src/mcp/server.rs Updates tool descriptions to document evidence format
crates/checks/*/src/lib.rs Updates all 7 checks to emit structured findings with facts
tests/mcp_stdio.rs Adds evidence schema validation helpers and integration tests
tests/check_package_mock_http.rs Tests multi-signal evidence scenarios
src/tests/*.rs Updates unit tests to verify evidence in reports
README.md Documents evidence format, examples, and removes completed roadmap item

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/service.rs
Comment on lines 167 to +168
reasons: vec![reason],
evidence: vec![runtime_error_evidence(&err.to_string())],
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runtime error evidence message is inconsistent between the package result (line 158) and the audit log (line 168). Line 151 creates a formatted reason with "package check failed: " prefix, which is used in the package result evidence on line 158. However, the audit log on line 168 creates evidence directly from err.to_string() without the prefix. This means the same error will have different evidence messages in different contexts, which could be confusing for downstream consumers expecting stable evidence content. Consider using the same reason variable for both evidence creations to maintain consistency.

Suggested change
reasons: vec![reason],
evidence: vec![runtime_error_evidence(&err.to_string())],
reasons: vec![reason.clone()],
evidence: vec![runtime_error_evidence(&reason)],

Copilot uses AI. Check for mistakes.
Comment thread tests/mcp_stdio.rs
Comment on lines +73 to +99
fn assert_evidence_item_shape(item: &serde_json::Value) {
assert_eq!(
item.get("kind").and_then(serde_json::Value::as_str),
Some("check")
);
assert!(
item.get("id")
.and_then(serde_json::Value::as_str)
.map(|value| !value.is_empty())
.unwrap_or(false)
);
assert!(
item.get("severity")
.and_then(serde_json::Value::as_str)
.is_some()
);
assert!(
item.get("message")
.and_then(serde_json::Value::as_str)
.is_some()
);
assert!(
item.get("facts")
.map(serde_json::Value::is_object)
.unwrap_or(false)
);
}
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function name assert_evidence_item_shape is misleading because it specifically asserts that the evidence kind is "check" (line 76), but the name suggests it validates the general shape of any evidence item. While the current usages are correct (both are for check evidence), this could cause issues if someone tries to use this helper for policy, custom_rule, or runtime evidence in the future. Consider either renaming to assert_check_evidence_item_shape to be more specific, or making the function more generic by not asserting a specific kind.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants