dkp_core/validate/
gate8.rs1use crate::{
2 okf::parser::parse_okf_dir,
3 pack::loader::Pack,
4 validate::gates::{CheckResult, GateResult, GateStatus},
5};
6
7pub fn run(pack: &Pack) -> GateResult {
9 if !pack.has_okf() {
10 return GateResult {
11 gate: 8,
12 status: GateStatus::NotApplicable,
13 checks: vec![CheckResult::skip("okf/ layer (not present)")],
14 message: Some("OKF layer absent; gate 8 not applicable".to_string()),
15 };
16 }
17
18 let mut checks = Vec::new();
19
20 match parse_okf_dir(&pack.okf_dir()) {
22 Ok(concepts) => {
23 let n = concepts.len();
24 checks.push(CheckResult::pass(format!("OKF concept files: {n} parsed")));
25
26 let missing_type: Vec<String> = concepts
28 .iter()
29 .filter(|c| c.frontmatter.get("type").is_none())
30 .map(|c| {
31 c.path
32 .file_name()
33 .unwrap_or_default()
34 .to_string_lossy()
35 .into_owned()
36 })
37 .collect();
38
39 if missing_type.is_empty() {
40 checks.push(CheckResult::pass(format!(
41 "OKF frontmatter: all {n} files have 'type' field"
42 )));
43 } else {
44 checks.push(CheckResult::fail(
45 "OKF frontmatter: 'type' field required",
46 format!("missing 'type': {}", missing_type.join(", ")),
47 ));
48 }
49 }
50 Err(e) => {
51 checks.push(CheckResult::fail("OKF concept files parse", e.to_string()));
52 }
53 }
54
55 let bundle_sig = pack.okf_dir().join("bundle.sig");
57 if bundle_sig.exists() {
58 checks.push(CheckResult::pass("bundle.sig present"));
59 } else {
60 checks.push(CheckResult::skip("bundle.sig (not present)"));
61 }
62
63 let failed = checks.iter().any(|c| c.status == GateStatus::Fail);
64 GateResult {
65 gate: 8,
66 status: if failed {
67 GateStatus::Fail
68 } else {
69 GateStatus::Pass
70 },
71 checks,
72 message: None,
73 }
74}