libverify-core 0.13.0

Platform-agnostic SDLC verification engine — evidence model, controls, assessment
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
pub mod agent_spec_conformance;
pub mod behavioral_regression;
pub mod branch_history_integrity;
pub mod branch_protection_enforcement;
pub mod build_isolation;
pub mod build_provenance;
pub mod change_request_size;
pub mod code_scanning_alerts_resolved;
pub mod codeowners_coverage;
pub mod container_provenance;
pub mod container_signature;
pub mod conventional_title;
pub mod coverage_threshold;
pub mod dependency_completeness;
pub mod dependency_provenance;
pub mod dependency_signature;
pub mod dependency_signer_verified;
pub mod deployment_health;
pub mod description_quality;
pub mod harness_gate;
pub mod hosted_build_platform;
pub mod issue_linkage;
pub mod license_compliance;
pub mod mcp_scope_check;
pub mod merge_commit_policy;
pub mod network_egress_audit;
pub mod privileged_operation_audit;
pub mod privileged_workflow_detection;
pub mod provenance_authenticity;
pub mod release_asset_attestation;
pub mod release_traceability;
pub mod required_status_checks;
pub mod review_independence;
pub mod sbom_completeness;
pub mod scoped_change;
pub mod secret_scanning;
pub mod security_file_change;
pub mod security_policy;
pub mod security_test_in_ci;
pub mod source_authenticity;
pub mod stale_review;
pub mod test_coverage;
pub mod two_party_review;
pub mod vulnerability_scanning;
use crate::control::{Control, builtin};
use crate::slsa::{SlsaLevel, SlsaTrack};

use self::container_provenance::ContainerProvenanceControl;
use self::container_signature::ContainerSignatureControl;

use self::agent_spec_conformance::AgentSpecConformanceControl;
use self::behavioral_regression::BehavioralRegressionControl;
use self::branch_history_integrity::BranchHistoryIntegrityControl;
use self::branch_protection_enforcement::BranchProtectionEnforcementControl;
use self::build_isolation::BuildIsolationControl;
use self::build_provenance::BuildProvenanceControl;
use self::change_request_size::ChangeRequestSizeControl;
use self::code_scanning_alerts_resolved::CodeScanningAlertsResolvedControl;
use self::codeowners_coverage::CodeownersCoverageControl;
use self::conventional_title::ConventionalTitleControl;
use self::coverage_threshold::CoverageThresholdControl;
use self::dependency_completeness::DependencyCompletenessControl;
use self::dependency_provenance::DependencyProvenanceControl;
use self::dependency_signature::DependencySignatureControl;
use self::dependency_signer_verified::DependencySignerVerifiedControl;
use self::deployment_health::DeploymentHealthControl;
use self::description_quality::DescriptionQualityControl;
use self::harness_gate::HarnessGateControl;
use self::hosted_build_platform::HostedBuildPlatformControl;
use self::issue_linkage::IssueLinkageControl;
use self::license_compliance::LicenseComplianceControl;
use self::mcp_scope_check::McpScopeCheckControl;
use self::merge_commit_policy::MergeCommitPolicyControl;
use self::network_egress_audit::NetworkEgressAuditControl;
use self::privileged_operation_audit::PrivilegedOperationAuditControl;
use self::privileged_workflow_detection::PrivilegedWorkflowDetectionControl;
use self::provenance_authenticity::ProvenanceAuthenticityControl;
use self::release_asset_attestation::ReleaseAssetAttestationControl;
use self::release_traceability::ReleaseTraceabilityControl;
use self::required_status_checks::RequiredStatusChecksControl;
use self::review_independence::ReviewIndependenceControl;
use self::sbom_completeness::SbomCompletenessControl;
use self::scoped_change::ScopedChangeControl;
use self::secret_scanning::SecretScanningControl;
use self::security_file_change::SecurityFileChangeControl;
use self::security_policy::SecurityPolicyControl;
use self::security_test_in_ci::SecurityTestInCiControl;
use self::source_authenticity::SourceAuthenticityControl;
use self::stale_review::StaleReviewControl;
use self::test_coverage::TestCoverageControl;
use self::two_party_review::TwoPartyReviewControl;
use self::vulnerability_scanning::VulnerabilityScanningControl;
/// Instantiates a control by its string ID.
fn instantiate(id: &str) -> Option<Box<dyn Control>> {
    match id {
        builtin::SOURCE_AUTHENTICITY => Some(Box::new(SourceAuthenticityControl)),
        builtin::REVIEW_INDEPENDENCE => Some(Box::new(ReviewIndependenceControl)),
        builtin::BRANCH_HISTORY_INTEGRITY => Some(Box::new(BranchHistoryIntegrityControl)),
        builtin::BRANCH_PROTECTION_ENFORCEMENT => {
            Some(Box::new(BranchProtectionEnforcementControl))
        }
        builtin::TWO_PARTY_REVIEW => Some(Box::new(TwoPartyReviewControl)),
        builtin::BUILD_PROVENANCE => Some(Box::new(BuildProvenanceControl)),
        builtin::REQUIRED_STATUS_CHECKS => Some(Box::new(RequiredStatusChecksControl)),
        builtin::HOSTED_BUILD_PLATFORM => Some(Box::new(HostedBuildPlatformControl)),
        builtin::PROVENANCE_AUTHENTICITY => Some(Box::new(ProvenanceAuthenticityControl)),
        builtin::BUILD_ISOLATION => Some(Box::new(BuildIsolationControl)),
        builtin::DEPENDENCY_SIGNATURE => Some(Box::new(DependencySignatureControl)),
        builtin::DEPENDENCY_PROVENANCE_CHECK => Some(Box::new(DependencyProvenanceControl)),
        builtin::DEPENDENCY_SIGNER_VERIFIED => Some(Box::new(DependencySignerVerifiedControl)),
        builtin::DEPENDENCY_COMPLETENESS => Some(Box::new(DependencyCompletenessControl)),
        builtin::CHANGE_REQUEST_SIZE => Some(Box::new(ChangeRequestSizeControl)),
        builtin::TEST_COVERAGE => Some(Box::new(TestCoverageControl)),
        builtin::SCOPED_CHANGE => Some(Box::new(ScopedChangeControl)),
        builtin::ISSUE_LINKAGE => Some(Box::new(IssueLinkageControl)),
        builtin::STALE_REVIEW => Some(Box::new(StaleReviewControl)),
        builtin::DESCRIPTION_QUALITY => Some(Box::new(DescriptionQualityControl)),
        builtin::MERGE_COMMIT_POLICY => Some(Box::new(MergeCommitPolicyControl)),
        builtin::CONVENTIONAL_TITLE => Some(Box::new(ConventionalTitleControl)),
        builtin::SECURITY_FILE_CHANGE => Some(Box::new(SecurityFileChangeControl)),
        builtin::RELEASE_TRACEABILITY => Some(Box::new(ReleaseTraceabilityControl)),
        builtin::CODEOWNERS_COVERAGE => Some(Box::new(CodeownersCoverageControl)),
        builtin::SECRET_SCANNING => Some(Box::new(SecretScanningControl)),
        builtin::VULNERABILITY_SCANNING => Some(Box::new(VulnerabilityScanningControl)),
        builtin::SECURITY_POLICY => Some(Box::new(SecurityPolicyControl)),
        builtin::CODE_SCANNING_ALERTS_RESOLVED => Some(Box::new(CodeScanningAlertsResolvedControl)),
        builtin::RELEASE_ASSET_ATTESTATION => Some(Box::new(ReleaseAssetAttestationControl)),
        builtin::PRIVILEGED_WORKFLOW_DETECTION => {
            Some(Box::new(PrivilegedWorkflowDetectionControl))
        }
        builtin::SECURITY_TEST_IN_CI => Some(Box::new(SecurityTestInCiControl)),
        builtin::LICENSE_COMPLIANCE => Some(Box::new(LicenseComplianceControl)),
        builtin::SBOM_COMPLETENESS => Some(Box::new(SbomCompletenessControl)),
        builtin::AGENT_SPEC_CONFORMANCE => Some(Box::new(AgentSpecConformanceControl)),
        builtin::PRIVILEGED_OPERATION_AUDIT => Some(Box::new(PrivilegedOperationAuditControl)),
        builtin::MCP_SCOPE_CHECK => Some(Box::new(McpScopeCheckControl)),
        builtin::NETWORK_EGRESS_AUDIT => Some(Box::new(NetworkEgressAuditControl)),
        builtin::HARNESS_GATE => Some(Box::new(HarnessGateControl)),
        builtin::COVERAGE_THRESHOLD => Some(Box::new(CoverageThresholdControl)),
        builtin::CONTAINER_SIGNATURE => Some(Box::new(ContainerSignatureControl)),
        builtin::CONTAINER_PROVENANCE => Some(Box::new(ContainerProvenanceControl)),
        builtin::BEHAVIORAL_REGRESSION => Some(Box::new(BehavioralRegressionControl)),
        builtin::DEPLOYMENT_HEALTH => Some(Box::new(DeploymentHealthControl)),
        _ => None,
    }
}

/// Returns the SARIF-friendly description for a built-in control ID.
/// Falls back to "Custom control" for unknown IDs.
pub fn control_description(id: &str) -> &'static str {
    match instantiate(id) {
        Some(c) => c.description(),
        None => "Custom control",
    }
}

/// Returns all SLSA controls required for the given track up to the given level.
pub fn slsa_controls_for_level(track: SlsaTrack, level: SlsaLevel) -> Vec<Box<dyn Control>> {
    crate::slsa::controls_for_level(track, level)
        .into_iter()
        .filter_map(|id| instantiate(id.as_str()))
        .collect()
}

/// Returns all SLSA controls across both tracks up to the given levels.
pub fn slsa_controls(source_level: SlsaLevel, build_level: SlsaLevel) -> Vec<Box<dyn Control>> {
    let mut controls = slsa_controls_for_level(SlsaTrack::Source, source_level);
    controls.extend(slsa_controls_for_level(SlsaTrack::Build, build_level));
    controls
}

/// Returns all SLSA controls (Source L4 + Build L3 + Dependencies L4).
pub fn all_slsa_controls() -> Vec<Box<dyn Control>> {
    let mut controls = slsa_controls(SlsaLevel::L4, SlsaLevel::L3);
    controls.extend(slsa_controls_for_level(
        SlsaTrack::Dependencies,
        SlsaLevel::L4,
    ));
    controls
}

/// Returns compliance controls (non-SLSA, SOC2/ASPM mapped).
pub fn compliance_controls() -> Vec<Box<dyn Control>> {
    vec![
        Box::new(ChangeRequestSizeControl),
        Box::new(TestCoverageControl),
        Box::new(ScopedChangeControl),
        Box::new(IssueLinkageControl),
        Box::new(StaleReviewControl),
        Box::new(DescriptionQualityControl),
        Box::new(MergeCommitPolicyControl),
        Box::new(ConventionalTitleControl),
        Box::new(SecurityFileChangeControl),
        Box::new(ReleaseTraceabilityControl),
        Box::new(CodeownersCoverageControl),
        Box::new(SecretScanningControl),
        Box::new(VulnerabilityScanningControl),
        Box::new(SecurityPolicyControl),
        Box::new(CodeScanningAlertsResolvedControl),
        Box::new(ReleaseAssetAttestationControl),
        Box::new(PrivilegedWorkflowDetectionControl),
        Box::new(SecurityTestInCiControl),
        Box::new(LicenseComplianceControl),
        Box::new(SbomCompletenessControl),
        Box::new(HarnessGateControl),
        Box::new(CoverageThresholdControl),
        Box::new(ContainerSignatureControl),
        Box::new(ContainerProvenanceControl),
        Box::new(BehavioralRegressionControl),
        Box::new(DeploymentHealthControl),
    ]
}

/// Returns repository-posture controls only (no PR-scoped compliance controls).
///
/// These evaluate repository-level security configuration:
/// CODEOWNERS, secret scanning, vulnerability scanning, and security policy.
pub fn posture_controls() -> Vec<Box<dyn Control>> {
    vec![
        Box::new(CodeownersCoverageControl),
        Box::new(SecretScanningControl),
        Box::new(VulnerabilityScanningControl),
        Box::new(SecurityPolicyControl),
        Box::new(CodeScanningAlertsResolvedControl),
        Box::new(ReleaseAssetAttestationControl),
        Box::new(PrivilegedWorkflowDetectionControl),
        Box::new(SecurityTestInCiControl),
        Box::new(LicenseComplianceControl),
        Box::new(SbomCompletenessControl),
    ]
}

/// Returns AI-ops agent safety controls (Layers 1, 2, 4).
pub fn aiops_controls() -> Vec<Box<dyn Control>> {
    vec![
        Box::new(AgentSpecConformanceControl),
        Box::new(PrivilegedOperationAuditControl),
        Box::new(McpScopeCheckControl),
        Box::new(NetworkEgressAuditControl),
    ]
}

/// Returns all controls (all SLSA + compliance + aiops).
pub fn all_controls() -> Vec<Box<dyn Control>> {
    let mut controls = all_slsa_controls();
    controls.extend(compliance_controls());
    controls.extend(aiops_controls());
    controls
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::control::builtin;
    use crate::slsa::control_slsa_mapping;

    #[test]
    fn slsa_l1_returns_l1_controls_only() {
        let controls = slsa_controls(SlsaLevel::L1, SlsaLevel::L1);
        for c in &controls {
            let mapping = control_slsa_mapping(&c.id()).expect("should be SLSA-mapped");
            assert!(
                mapping.level <= SlsaLevel::L1,
                "{:?} is L{:?} but should be L1 or below",
                c.id(),
                mapping.level
            );
        }
    }

    #[test]
    fn all_slsa_includes_l3_build_and_l4_source() {
        let controls = all_slsa_controls();
        let ids: Vec<_> = controls.iter().map(|c| c.id()).collect();
        assert!(
            ids.iter()
                .any(|id| id.as_str() == builtin::TWO_PARTY_REVIEW)
        );
        assert!(ids.iter().any(|id| id.as_str() == builtin::BUILD_ISOLATION));
    }

    #[test]
    fn all_controls_includes_compliance() {
        let controls = all_controls();
        let ids: Vec<_> = controls.iter().map(|c| c.id()).collect();
        assert!(
            ids.iter()
                .any(|id| id.as_str() == builtin::CHANGE_REQUEST_SIZE)
        );
        assert!(ids.iter().any(|id| id.as_str() == builtin::ISSUE_LINKAGE));
    }

    #[test]
    fn compliance_plus_slsa_plus_aiops_equals_all() {
        use crate::control::builtin;
        let compliance = compliance_controls();
        let slsa = all_slsa_controls();
        let aiops = aiops_controls();
        assert_eq!(
            compliance.len() + slsa.len() + aiops.len(),
            builtin::ALL.len(),
            "compliance + SLSA + aiops controls must cover all built-in controls"
        );
    }

    #[test]
    fn compliance_controls_are_not_slsa_mapped() {
        use crate::slsa::control_slsa_mapping;
        let controls = compliance_controls();
        for c in &controls {
            assert!(
                control_slsa_mapping(&c.id()).is_none(),
                "{:?} should not be SLSA-mapped",
                c.id()
            );
        }
    }

    #[test]
    fn compliance_controls_have_unique_ids() {
        let controls = compliance_controls();
        let mut ids: Vec<_> = controls.iter().map(|c| c.id()).collect();
        let original_len = ids.len();
        ids.sort_by_key(|id| id.as_str().to_string());
        ids.dedup();
        assert_eq!(
            ids.len(),
            original_len,
            "all compliance control IDs must be unique"
        );
    }

    #[test]
    fn all_controls_count() {
        let slsa = all_slsa_controls();
        let compliance = compliance_controls();
        let aiops = aiops_controls();
        let all = all_controls();
        assert_eq!(
            all.len(),
            slsa.len() + compliance.len() + aiops.len(),
            "all_controls = SLSA + compliance + aiops"
        );
    }

    #[test]
    fn slsa_controls_for_level_source_l2() {
        let controls = slsa_controls_for_level(SlsaTrack::Source, SlsaLevel::L2);
        let ids: Vec<_> = controls.iter().map(|c| c.id()).collect();
        assert!(
            ids.iter()
                .any(|id| id.as_str() == builtin::BRANCH_HISTORY_INTEGRITY)
        );
        assert!(
            !ids.iter()
                .any(|id| id.as_str() == builtin::BRANCH_PROTECTION_ENFORCEMENT)
        );
    }

    #[test]
    fn slsa_controls_for_level_build_l2() {
        let controls = slsa_controls_for_level(SlsaTrack::Build, SlsaLevel::L2);
        let ids: Vec<_> = controls.iter().map(|c| c.id()).collect();
        assert!(
            ids.iter()
                .any(|id| id.as_str() == builtin::HOSTED_BUILD_PLATFORM)
        );
        assert!(
            ids.iter()
                .any(|id| id.as_str() == builtin::PROVENANCE_AUTHENTICITY)
        );
        assert!(!ids.iter().any(|id| id.as_str() == builtin::BUILD_ISOLATION));
    }

    #[test]
    fn all_controls_have_meaningful_description() {
        let controls = all_controls();
        for c in &controls {
            let desc = c.description();
            assert!(
                !desc.is_empty() && desc.len() > 10,
                "control {} has too short description: '{}'",
                c.id(),
                desc,
            );
            // description must contain a keyword related to the control's purpose
            let id = c.id();
            let id_str = id.as_str();
            let has_relevant_keyword = desc.to_lowercase().contains("must")
                || desc.to_lowercase().contains("should")
                || desc.to_lowercase().contains("agent")
                || desc.to_lowercase().contains("ci")
                || desc.to_lowercase().contains("review")
                || desc.to_lowercase().contains("sign")
                || desc.to_lowercase().contains("branch")
                || desc.to_lowercase().contains("build")
                || desc.to_lowercase().contains("depend")
                || desc.to_lowercase().contains("secur")
                || desc.to_lowercase().contains("test")
                || desc.to_lowercase().contains("change")
                || desc.to_lowercase().contains("scan")
                || desc.to_lowercase().contains("release")
                || desc.to_lowercase().contains("code")
                || desc.to_lowercase().contains("permission")
                || desc.to_lowercase().contains("privileged")
                || desc.to_lowercase().contains("action")
                || desc.to_lowercase().contains("harness")
                || desc.to_lowercase().contains("environment")
                || desc.to_lowercase().contains("workflow")
                || desc.to_lowercase().contains("tag")
                || desc.to_lowercase().contains("license")
                || desc.to_lowercase().contains("sbom")
                || desc.to_lowercase().contains("attest")
                || desc.to_lowercase().contains("owner")
                || desc.to_lowercase().contains("provenance")
                || desc.to_lowercase().contains("deploy")
                || desc.to_lowercase().contains("metric");
            assert!(
                has_relevant_keyword,
                "control {} description '{}' lacks a relevant keyword",
                id_str, desc,
            );
        }
    }
}