feat(hololake): project resident PNCC state

This commit is contained in:
冰朔 2026-08-16 02:52:55 +08:00
commit 9736563262
13 changed files with 325 additions and 11 deletions

View file

@ -1345,7 +1345,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hololake-native-desktop"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"base64 0.22.1",
"dirs",

View file

@ -1,6 +1,6 @@
[package]
name = "hololake-native-desktop"
version = "0.1.0"
version = "0.2.0"
description = "HoloLake native desktop foundation"
authors = ["HoloLake"]
license = "AGPL-3.0-or-later"

View file

@ -6,6 +6,7 @@ mod local_development_bridge;
mod pncc_receipt_projection;
mod pncc_remote_git;
mod pncc_repository_binding;
mod pncc_server_projection;
mod release_trust;
mod release_update;
@ -37,6 +38,7 @@ pub fn run() {
pncc_repository_binding::select_pncc_repository_candidate,
pncc_repository_binding::confirm_pncc_repository_mount,
pncc_receipt_projection::query_pncc_receipt_projection,
pncc_server_projection::query_jd_pncc_server_projection,
])
.setup(|app| {
let broker = direct_local_broker::start(app.handle())?;

View file

@ -0,0 +1,193 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
use serde::{Deserialize, Serialize};
use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};
const SSH_TARGET: &str = "jd-fd-primary";
const EXPECTED_NODE_ID: &str = "JD-FD-PRIMARY";
const EXPECTED_PERSONA_ID: &str = "ICE-P-ZY001";
const REMOTE_STATUS_COMMAND: &str =
"curl --fail --silent --show-error --max-time 3 http://127.0.0.1:3923/v1/status";
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct RuntimeStatusEvidence {
schema: String,
state: String,
persona_id: String,
human_responsibility_subject: String,
node_id: String,
boot_id: String,
git_head: String,
repository_receipt_id: String,
carrier_binding_state: String,
persona_carrier_bound: bool,
model_inference_started: bool,
reality_execution_allowed: bool,
primary_lease_held: bool,
event_count: usize,
event_chain_head: String,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ServerPnccProjection {
schema: &'static str,
state: String,
persona_id: String,
human_responsibility_subject: String,
node_id: String,
boot_id: String,
git_head: String,
carrier_binding_state: String,
persona_carrier_bound: bool,
model_inference_started: bool,
reality_execution_allowed: bool,
primary_lease_held: bool,
event_count: usize,
event_chain_head: String,
observed_at_unix_ms: u128,
transport: &'static str,
repository_content_exposed: bool,
write_authority: bool,
}
fn exact_lower_hex(value: &str, length: usize) -> bool {
value.len() == length
&& value
.bytes()
.all(|byte| byte.is_ascii_hexdigit() && !byte.is_ascii_uppercase())
}
fn bounded_text(value: &str, maximum: usize) -> bool {
!value.is_empty()
&& value.len() <= maximum
&& value.trim() == value
&& !value.chars().any(char::is_control)
}
fn parse_projection(bytes: &[u8]) -> Result<ServerPnccProjection, String> {
if bytes.is_empty() || bytes.len() > 16 * 1024 {
return Err("PNCC_SERVER_PROJECTION_SIZE_INVALID".into());
}
let evidence: RuntimeStatusEvidence = serde_json::from_slice(bytes)
.map_err(|_| "PNCC_SERVER_PROJECTION_JSON_INVALID".to_string())?;
if evidence.schema != "guanghu.pncc-runtime-status/v1"
|| evidence.node_id != EXPECTED_NODE_ID
|| evidence.persona_id != EXPECTED_PERSONA_ID
|| evidence.state != "RESIDENT_BOUND_CARRIER_UNBOUND"
|| evidence.carrier_binding_state != "UNBOUND_EVIDENCE_REQUIRED"
|| evidence.persona_carrier_bound
|| evidence.model_inference_started
|| evidence.reality_execution_allowed
|| !evidence.primary_lease_held
|| !exact_lower_hex(&evidence.git_head, 40)
|| !exact_lower_hex(&evidence.repository_receipt_id, 64)
|| !exact_lower_hex(&evidence.event_chain_head, 64)
|| !bounded_text(&evidence.human_responsibility_subject, 256)
|| !bounded_text(&evidence.boot_id, 64)
|| evidence.event_count == 0
{
return Err("PNCC_SERVER_PROJECTION_EVIDENCE_REJECTED".into());
}
let observed_at_unix_ms = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_err(|_| "PNCC_LOCAL_CLOCK_INVALID".to_string())?
.as_millis();
Ok(ServerPnccProjection {
schema: "hololake.pncc-server-projection/v1",
state: evidence.state,
persona_id: evidence.persona_id,
human_responsibility_subject: evidence.human_responsibility_subject,
node_id: evidence.node_id,
boot_id: evidence.boot_id,
git_head: evidence.git_head,
carrier_binding_state: evidence.carrier_binding_state,
persona_carrier_bound: false,
model_inference_started: false,
reality_execution_allowed: false,
primary_lease_held: true,
event_count: evidence.event_count,
event_chain_head: evidence.event_chain_head,
observed_at_unix_ms,
transport: "DEDICATED_SSH_LOOPBACK_READ_ONLY",
repository_content_exposed: false,
write_authority: false,
})
}
#[tauri::command]
pub async fn query_jd_pncc_server_projection() -> Result<ServerPnccProjection, String> {
tauri::async_runtime::spawn_blocking(|| {
let output = Command::new("/usr/bin/ssh")
.args([
"-o",
"BatchMode=yes",
"-o",
"ConnectTimeout=5",
"-o",
"ConnectionAttempts=1",
"-o",
"ClearAllForwardings=yes",
"-o",
"PermitLocalCommand=no",
"-o",
"StrictHostKeyChecking=yes",
SSH_TARGET,
REMOTE_STATUS_COMMAND,
])
.output()
.map_err(|_| "PNCC_SERVER_BRIDGE_UNAVAILABLE".to_string())?;
if !output.status.success() {
return Err("PNCC_SERVER_BRIDGE_UNAVAILABLE".into());
}
parse_projection(&output.stdout)
})
.await
.map_err(|_| "PNCC_SERVER_BRIDGE_TASK_FAILED".to_string())?
}
#[cfg(test)]
mod tests {
use super::*;
fn evidence() -> Vec<u8> {
serde_json::to_vec(&serde_json::json!({
"schema": "guanghu.pncc-runtime-status/v1",
"state": "RESIDENT_BOUND_CARRIER_UNBOUND",
"personaId": "ICE-P-ZY001",
"humanResponsibilitySubject": "HUMAN-BINGSHUO-001",
"nodeId": "JD-FD-PRIMARY",
"bootId": "1170988c-5390-4f47-b89a-e9f88b2c5bbb",
"gitHead": "1".repeat(40),
"repositoryReceiptId": "2".repeat(64),
"carrierBindingState": "UNBOUND_EVIDENCE_REQUIRED",
"personaCarrierBound": false,
"modelInferenceStarted": false,
"realityExecutionAllowed": false,
"primaryLeaseHeld": true,
"eventCount": 4,
"eventChainHead": "3".repeat(64)
}))
.unwrap()
}
#[test]
fn accepts_only_the_minimum_live_unbound_projection() {
let projection = parse_projection(&evidence()).unwrap();
assert_eq!(projection.node_id, EXPECTED_NODE_ID);
assert!(!projection.repository_content_exposed);
assert!(!projection.write_authority);
}
#[test]
fn refuses_identity_or_authority_escalation() {
let mut value: serde_json::Value = serde_json::from_slice(&evidence()).unwrap();
value["personaCarrierBound"] = true.into();
assert!(parse_projection(&serde_json::to_vec(&value).unwrap()).is_err());
value["personaCarrierBound"] = false.into();
value["realityExecutionAllowed"] = true.into();
assert!(parse_projection(&serde_json::to_vec(&value).unwrap()).is_err());
}
}

View file

@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "HoloLake",
"version": "0.1.0",
"version": "0.2.0",
"identifier": "world.guanghu.hololake",
"build": {
"frontendDist": "../dist",