feat(hololake): project resident PNCC state
This commit is contained in:
parent
fa9c2043c1
commit
9736563262
13 changed files with 325 additions and 11 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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())?;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Reference in a new issue