fix(cog-person-count): emit real signed manifest from CLI (ADR-159 A4)
cmd_manifest emitted a null skeleton (binary_sha256: null) while the real signed manifest existed on disk at cog/artifacts/manifests/<arch>/manifest.json. - New manifest module include_str!-embeds the real signed manifests (x86_64 + arm), selected by build target arch. - cmd_manifest parses-then-emits the embedded signed manifest, mirroring cog-pose-estimation manifest_roundtrips. CLI now reports the real binary_sha256, weights_sha256, Ed25519 signature, and honest build_metadata (training_class1_accuracy = 0.343). Failing-on-old test: manifest::tests::embedded_manifest_has_non_null_binary_sha256 (+ embedded_manifest_is_signed, embedded_manifest_id_matches_cog). Verified end-to-end: cog-person-count manifest -> non-null sha256. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
2400216920
commit
6b5fd3cf25
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
pub mod fusion;
|
pub mod fusion;
|
||||||
pub mod inference;
|
pub mod inference;
|
||||||
|
pub mod manifest;
|
||||||
pub mod publisher;
|
pub mod publisher;
|
||||||
pub mod runtime;
|
pub mod runtime;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ use cog_person_count::{
|
||||||
publisher, COG_ID, COG_VERSION,
|
publisher, COG_ID, COG_VERSION,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::{json, Value};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
|
|
@ -83,19 +82,11 @@ fn cmd_version() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cmd_manifest() -> Result<(), Box<dyn std::error::Error>> {
|
fn cmd_manifest() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
println!(
|
// Emit the real, signed manifest embedded at compile time (ADR-159 §A4) —
|
||||||
"{}",
|
// not the old hollow null skeleton. Parse-then-emit so a malformed embedded
|
||||||
serde_json::to_string_pretty(&json!({
|
// artifact fails loudly and the output is canonical JSON.
|
||||||
"id": COG_ID,
|
let spec = cog_person_count::manifest::embedded_manifest_value()?;
|
||||||
"version": COG_VERSION,
|
println!("{}", serde_json::to_string_pretty(&spec)?);
|
||||||
"binary_url": Value::Null,
|
|
||||||
"binary_bytes": Value::Null,
|
|
||||||
"binary_sha256": Value::Null,
|
|
||||||
"binary_signature": Value::Null,
|
|
||||||
"installed_at": Value::Null,
|
|
||||||
"status": Value::Null,
|
|
||||||
}))?
|
|
||||||
);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
//! Embedded signed cog manifest (ADR-100 §"manifest.json", ADR-159 §A4).
|
||||||
|
//!
|
||||||
|
//! The `cog-person-count manifest` subcommand emits the **real, signed**
|
||||||
|
//! manifest the release pipeline produced — byte-for-byte the artifact served
|
||||||
|
//! from GCS, with a real `binary_sha256`, `weights_sha256`, Ed25519
|
||||||
|
//! `binary_signature`, and honest `build_metadata` (e.g. `training_class1_accuracy
|
||||||
|
//! = 0.343`, not inflated). The previous implementation printed a hollow
|
||||||
|
//! skeleton with `binary_sha256: null`, which made the CLI look unsigned even
|
||||||
|
//! though the signed manifest existed on disk.
|
||||||
|
//!
|
||||||
|
//! The matching manifest for the build's target arch is selected via `cfg!`.
|
||||||
|
|
||||||
|
/// Real signed manifest for `x86_64-unknown-linux-gnu`.
|
||||||
|
pub const MANIFEST_X86_64: &str =
|
||||||
|
include_str!("../cog/artifacts/manifests/x86_64/manifest.json");
|
||||||
|
|
||||||
|
/// Real signed manifest for `aarch64`/`arm` (the Seed appliance).
|
||||||
|
pub const MANIFEST_ARM: &str = include_str!("../cog/artifacts/manifests/arm/manifest.json");
|
||||||
|
|
||||||
|
/// The embedded signed manifest matching the build's target arch.
|
||||||
|
pub fn embedded_manifest_str() -> &'static str {
|
||||||
|
if cfg!(any(target_arch = "aarch64", target_arch = "arm")) {
|
||||||
|
MANIFEST_ARM
|
||||||
|
} else {
|
||||||
|
MANIFEST_X86_64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse the embedded manifest into canonical JSON. Returns an error if the
|
||||||
|
/// embedded artifact is malformed (so the CLI fails loudly rather than printing
|
||||||
|
/// garbage).
|
||||||
|
pub fn embedded_manifest_value() -> Result<serde_json::Value, serde_json::Error> {
|
||||||
|
serde_json::from_str(embedded_manifest_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// ADR-159 §A4 — the embedded manifest the CLI emits must carry a real
|
||||||
|
/// `binary_sha256` (the field the old hollow `cmd_manifest` left null).
|
||||||
|
#[test]
|
||||||
|
fn embedded_manifest_has_non_null_binary_sha256() {
|
||||||
|
let v = embedded_manifest_value().expect("embedded manifest parses");
|
||||||
|
let sha = v.get("binary_sha256").and_then(|s| s.as_str());
|
||||||
|
assert!(
|
||||||
|
sha.is_some(),
|
||||||
|
"embedded manifest must have a non-null binary_sha256 (got {:?})",
|
||||||
|
v.get("binary_sha256")
|
||||||
|
);
|
||||||
|
let sha = sha.unwrap();
|
||||||
|
assert_eq!(sha.len(), 64, "binary_sha256 must be a 32-byte hex digest");
|
||||||
|
assert!(
|
||||||
|
sha.chars().all(|c| c.is_ascii_hexdigit()),
|
||||||
|
"binary_sha256 must be hex"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn embedded_manifest_is_signed() {
|
||||||
|
let v = embedded_manifest_value().expect("parse");
|
||||||
|
assert!(
|
||||||
|
v.get("binary_signature").and_then(|s| s.as_str()).is_some(),
|
||||||
|
"embedded manifest must carry an Ed25519 binary_signature"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
v.get("sig_algo").and_then(|s| s.as_str()),
|
||||||
|
Some("Ed25519")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn embedded_manifest_id_matches_cog() {
|
||||||
|
let v = embedded_manifest_value().expect("parse");
|
||||||
|
assert_eq!(v.get("id").and_then(|s| s.as_str()), Some(crate::COG_ID));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue