feat: reconcile GLS registry into runtime manifest v2

This commit is contained in:
冰朔 2026-08-17 16:49:39 +08:00
commit ca5d6f3f58
7 changed files with 4615 additions and 121 deletions

View file

@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
const EMBEDDED_REGISTRY: &str = include_str!("../../contracts/gls-runtime-registry.json");
const EXPECTED_SCHEMA: &str = "hololake.gls-protocol-runtime-registry/v1";
const EXPECTED_SCHEMA: &str = "hololake.gls-runtime-manifest/v2";
const EXPECTED_SOURCE_COMMIT: &str = "2598fbfba8caf64c7ab9740a3036c5aab977502e";
#[derive(Clone, Debug, Deserialize)]
@ -15,6 +15,7 @@ struct GlsRuntimeRegistry {
schema: String,
source: GlsSource,
compiler: GlsCompilerBoundary,
reconciliation: GlsReconciliation,
protocol_count: usize,
executable_projection_count: usize,
inventoried_not_executable_count: usize,
@ -26,6 +27,14 @@ struct GlsSource {
repository: String,
commit: String,
root: String,
authority_files: Vec<GlsAuthorityFile>,
}
#[derive(Clone, Debug, Deserialize)]
struct GlsAuthorityFile {
authority_kind: String,
source_path: String,
source_sha256: String,
}
#[derive(Clone, Debug, Deserialize)]
@ -34,18 +43,51 @@ struct GlsCompilerBoundary {
arbitrary_protocol_code_allowed: bool,
executable_projection_requires_explicit_adapter: bool,
unprojected_protocol_behavior: String,
dependency_cycles: String,
legacy_untyped_dependency_behavior: String,
runtime_graph_source: String,
runtime_dependency_cycles: String,
unknown_protocol: String,
}
#[derive(Clone, Debug, Deserialize)]
struct GlsReconciliation {
numbered_protocol_count: usize,
protocol_registry_id_count: usize,
existing_registered_count: usize,
registered_draft_count: usize,
registered_draft_not_started_count: usize,
legacy_dependency_target_count: usize,
dependencies_not_in_protocol_registry: Vec<String>,
dependencies_without_numbered_source: Vec<String>,
numbered_sources_not_in_protocol_registry: Vec<String>,
legacy_dependency_cycles: Vec<Vec<String>>,
discovered_unreconciled_count: usize,
authority_conflict_count: usize,
}
#[derive(Clone, Debug, Deserialize)]
struct GlsRegistration {
state: String,
}
#[derive(Clone, Debug, Deserialize)]
struct GlsDependencyEdge {
target: String,
edge_kind: String,
enters_runtime_graph: bool,
}
#[derive(Clone, Debug, Deserialize)]
struct GlsProtocol {
id: String,
source_sha256: String,
registration: GlsRegistration,
projection_state: String,
adapter: Option<String>,
event_kinds: Vec<String>,
dependencies: Vec<String>,
dependency_edges: Vec<GlsDependencyEdge>,
activation_blockers: Vec<String>,
}
#[derive(Clone, Debug, Serialize)]
@ -58,6 +100,14 @@ pub struct GlsProtocolRuntimeSnapshot {
pub protocol_count: usize,
pub executable_projection_count: usize,
pub inventoried_not_executable_count: usize,
pub protocol_registry_id_count: usize,
pub registered_draft_count: usize,
pub registered_draft_not_started_count: usize,
pub legacy_dependency_target_count: usize,
pub dependency_gap_count: usize,
pub legacy_dependency_cycle_count: usize,
pub discovered_unreconciled_count: usize,
pub authority_conflict_count: usize,
pub active_adapters: Vec<String>,
pub raw_protocol_text_executed: bool,
pub arbitrary_protocol_code_allowed: bool,
@ -76,14 +126,34 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
|| registry.source.repository != "REPO-012"
|| registry.source.commit != EXPECTED_SOURCE_COMMIT
|| registry.source.root != "gls"
|| registry.source.authority_files.len() != 4
|| registry.compiler.raw_protocol_text_executed
|| registry.compiler.arbitrary_protocol_code_allowed
|| !registry
.compiler
.executable_projection_requires_explicit_adapter
|| registry.compiler.unprojected_protocol_behavior != "INVENTORIED_NOT_EXECUTABLE"
|| registry.compiler.dependency_cycles != "REJECT"
|| registry.compiler.legacy_untyped_dependency_behavior
!= "AUDIT_ONLY_BLOCKS_NEW_ACTIVATION"
|| registry.compiler.runtime_graph_source != "EXPLICIT_EXECUTABLE_PROJECTIONS_ONLY"
|| registry.compiler.runtime_dependency_cycles != "REJECT"
|| registry.compiler.unknown_protocol != "FAIL_CLOSED"
|| registry.reconciliation.numbered_protocol_count != registry.protocol_count
|| registry.reconciliation.protocol_registry_id_count != 52
|| registry.reconciliation.existing_registered_count != 19
|| registry.reconciliation.registered_draft_count != 33
|| registry.reconciliation.registered_draft_not_started_count != 21
|| registry.reconciliation.legacy_dependency_target_count != 57
|| registry.reconciliation.dependencies_not_in_protocol_registry.len() != 19
|| registry.reconciliation.dependencies_without_numbered_source.len() != 24
|| registry
.reconciliation
.numbered_sources_not_in_protocol_registry
.len()
!= 31
|| registry.reconciliation.legacy_dependency_cycles.len() != 3
|| registry.reconciliation.discovered_unreconciled_count != 0
|| registry.reconciliation.authority_conflict_count != 0
|| registry.protocol_count != registry.protocols.len()
|| registry.protocol_count
!= registry.executable_projection_count + registry.inventoried_not_executable_count
@ -91,6 +161,20 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
return Err("HOLOLAKE_GLS_RUNTIME_BOUNDARY_INVALID".into());
}
let mut authority_kinds = HashSet::new();
for authority in &registry.source.authority_files {
if !authority_kinds.insert(authority.authority_kind.as_str())
|| !authority.source_path.starts_with("gls/")
|| authority.source_sha256.len() != 64
|| !authority
.source_sha256
.chars()
.all(|character| character.is_ascii_hexdigit())
{
return Err("HOLOLAKE_GLS_AUTHORITY_SOURCE_INVALID".into());
}
}
let mut ids = HashSet::new();
let mut executable = 0;
for protocol in &registry.protocols {
@ -109,6 +193,7 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
executable += 1;
if protocol.adapter.as_deref().unwrap_or("").is_empty()
|| protocol.event_kinds.is_empty()
|| !protocol.activation_blockers.is_empty()
{
return Err("HOLOLAKE_GLS_EXECUTABLE_ADAPTER_REQUIRED".into());
}
@ -123,6 +208,33 @@ fn validate_registry(registry: &GlsRuntimeRegistry) -> Result<(), String> {
}
_ => return Err("HOLOLAKE_GLS_PROJECTION_STATE_UNKNOWN".into()),
}
if !matches!(
protocol.registration.state.as_str(),
"REGISTERED_PROTOCOL_REGISTRY" | "REGISTERED_OTHER_CANONICAL_INDEX"
) {
return Err("HOLOLAKE_GLS_REGISTRATION_NOT_RECONCILED".into());
}
for edge in &protocol.dependency_edges {
match edge.edge_kind.as_str() {
"RUNTIME_REQUIRES" if edge.enters_runtime_graph => {}
"LEGACY_UNTYPED_REFERENCE" if !edge.enters_runtime_graph => {}
_ => return Err("HOLOLAKE_GLS_DEPENDENCY_EDGE_INVALID".into()),
}
}
let runtime_edges = protocol
.dependency_edges
.iter()
.filter(|edge| edge.enters_runtime_graph)
.map(|edge| edge.target.as_str())
.collect::<HashSet<_>>();
let runtime_dependencies = protocol
.dependencies
.iter()
.map(String::as_str)
.collect::<HashSet<_>>();
if runtime_edges != runtime_dependencies {
return Err("HOLOLAKE_GLS_RUNTIME_DEPENDENCY_MISMATCH".into());
}
}
if executable != registry.executable_projection_count {
return Err("HOLOLAKE_GLS_EXECUTABLE_COUNT_MISMATCH".into());
@ -212,6 +324,19 @@ pub async fn get_gls_protocol_runtime() -> Result<GlsProtocolRuntimeSnapshot, St
protocol_count: registry.protocol_count,
executable_projection_count: registry.executable_projection_count,
inventoried_not_executable_count: registry.inventoried_not_executable_count,
protocol_registry_id_count: registry.reconciliation.protocol_registry_id_count,
registered_draft_count: registry.reconciliation.registered_draft_count,
registered_draft_not_started_count: registry
.reconciliation
.registered_draft_not_started_count,
legacy_dependency_target_count: registry.reconciliation.legacy_dependency_target_count,
dependency_gap_count: registry
.reconciliation
.dependencies_without_numbered_source
.len(),
legacy_dependency_cycle_count: registry.reconciliation.legacy_dependency_cycles.len(),
discovered_unreconciled_count: registry.reconciliation.discovered_unreconciled_count,
authority_conflict_count: registry.reconciliation.authority_conflict_count,
active_adapters,
raw_protocol_text_executed: registry.compiler.raw_protocol_text_executed,
arbitrary_protocol_code_allowed: registry.compiler.arbitrary_protocol_code_allowed,
@ -228,6 +353,10 @@ mod tests {
let registry = load_registry().unwrap();
assert_eq!(registry.protocol_count, 75);
assert_eq!(registry.executable_projection_count, 4);
assert_eq!(registry.reconciliation.protocol_registry_id_count, 52);
assert_eq!(registry.reconciliation.legacy_dependency_target_count, 57);
assert_eq!(registry.reconciliation.legacy_dependency_cycles.len(), 3);
assert_eq!(registry.reconciliation.authority_conflict_count, 0);
assert!(!registry.compiler.raw_protocol_text_executed);
assert!(!registry.compiler.arbitrary_protocol_code_allowed);
}
@ -249,4 +378,26 @@ mod tests {
"HOLOLAKE_GLS_EXECUTABLE_ADAPTER_NOT_REGISTERED"
);
}
#[test]
fn registration_and_dependency_manifest_tampering_fail_closed() {
let mut registration_tamper = load_registry().unwrap();
registration_tamper.reconciliation.authority_conflict_count = 1;
assert_eq!(
validate_registry(&registration_tamper).unwrap_err(),
"HOLOLAKE_GLS_RUNTIME_BOUNDARY_INVALID"
);
let mut dependency_tamper = load_registry().unwrap();
let numbering = dependency_tamper
.protocols
.iter_mut()
.find(|protocol| protocol.id == "GLS-0253")
.unwrap();
numbering.dependency_edges[0].edge_kind = "LEGACY_UNTYPED_REFERENCE".into();
assert_eq!(
validate_registry(&dependency_tamper).unwrap_err(),
"HOLOLAKE_GLS_DEPENDENCY_EDGE_INVALID"
);
}
}