coreason-urn-authority 0.45.1

Epistemic Ledger & OCI Trust Anchor for CoReason URNs.
Documentation
// Copyright (c) 2026 CoReason, Inc.
// All rights reserved.

use sha2::{Digest, Sha256};
use std::fs;
use std::path::Path;

pub fn calculate_epistemic_root(
    project_path: &Path,
    manifest_version: Option<&str>,
) -> Result<String, String> {
    // Component 1 (H_ontology)
    let schema_path = project_path.join("coreason_ontology.schema.json");
    let h_ontology = if schema_path.exists() {
        let content =
            fs::read(&schema_path).map_err(|e| format!("Failed to read ontology schema: {}", e))?;
        let mut hasher = Sha256::new();
        hasher.update(&content);
        hex::encode(hasher.finalize())
    } else {
        let mut hasher = Sha256::new();
        hasher.update(b"");
        hex::encode(hasher.finalize())
    };

    // Component 2 (H_env)
    let version = match manifest_version {
        Some(v) => v.to_string(),
        None => {
            let py_exec = std::env::var("PYTHON").unwrap_or_else(|_| "python".to_string());
            let output = std::process::Command::new(py_exec)
                .args([
                    "-c",
                    "import importlib.metadata; print(importlib.metadata.version('coreason-manifest'))",
                ])
                .output();
            match output {
                Ok(out) if out.status.success() => {
                    String::from_utf8_lossy(&out.stdout).trim().to_string()
                }
                _ => "unknown".to_string(),
            }
        }
    };

    let env_str = format!(
        "coreason-manifest=={}\ncoreason-runtime=={}\n",
        version, version
    );
    let mut hasher = Sha256::new();
    hasher.update(env_str.as_bytes());
    let h_env = hex::encode(hasher.finalize());

    // Component 3 (H_capabilities)
    let ledger_path = project_path
        .join(".coreason")
        .join("capability_ledger.json");
    let h_capabilities = if ledger_path.exists() {
        let content = fs::read(&ledger_path)
            .map_err(|e| format!("Failed to read capability ledger: {}", e))?;
        let mut hasher = Sha256::new();
        hasher.update(&content);
        hex::encode(hasher.finalize())
    } else {
        let mut hasher = Sha256::new();
        hasher.update(b"{}");
        hex::encode(hasher.finalize())
    };

    // The Merkle Root
    let combined = format!("{}{}{}", h_ontology, h_env, h_capabilities);
    let mut hasher = Sha256::new();
    hasher.update(combined.as_bytes());
    Ok(hex::encode(hasher.finalize()))
}