feat: expose HoloLake development lane to authenticated carriers

This commit is contained in:
冰朔 2026-08-17 15:41:04 +08:00
commit 96769846ac
7 changed files with 324 additions and 9 deletions

View file

@ -1,14 +1,20 @@
use crate::circular_lake_membrane::{receive_at as receive_language_at, ReceiveLanguageInput};
use crate::direct_local_session::{
append_event_at, authenticate_privileged_at, direct_session_root, issue_ticket_at, open_at,
resume_at, AppendSessionEventInput, AuthenticateSessionInput, DirectSessionReceipt,
IssueDiscoveryTicketInput, OpenSessionInput, ResumeSessionInput,
append_event_at, authenticate_context_at, authenticate_privileged_at, direct_session_root,
issue_ticket_at, open_at, resume_at, AppendSessionEventInput, AuthenticateSessionInput,
AuthenticatedSessionContext, DirectSessionReceipt, IssueDiscoveryTicketInput, OpenSessionInput,
ResumeSessionInput,
};
use crate::dynamic_capability_routing::{
install_trusted_registry_at, record_health_at, resolve_at as resolve_capability_route_at,
routing_root as dynamic_routing_root, DynamicNodeRegistry, ResolveCapabilityRouteInput,
SignedNodeHealth,
};
use crate::local_development_bridge::{
account_key_for as development_account_key_for, acquire_at as acquire_development_lane_at,
inspect_at as inspect_development_lane_at, release_at as release_development_lane_at,
AcquireWriteLaneInput, ReleaseWriteLaneInput,
};
use crate::persona_time_authority::{
beijing_time_coordinate, issue_authenticated_at, IssuePersonaTimeTicketInput,
};
@ -119,6 +125,7 @@ struct BrokerStorageRoots {
pncc_projection: PathBuf,
language_inbox: PathBuf,
persona_time: PathBuf,
development: PathBuf,
}
impl Drop for DirectLocalBrokerHandle {
@ -154,6 +161,9 @@ enum BrokerRequest {
QueryPnccReceiptProjection(AuthenticatedPnccProjectionQueryInput),
GetBeijingTime,
IssuePersonaTimeTicket(IssuePersonaTimeTicketInput),
AcquireDevelopmentWriteLane(AuthenticatedDevelopmentLaneInput),
InspectDevelopmentWriteLane(AuthenticatedDevelopmentInspectInput),
ReleaseDevelopmentWriteLane(AuthenticatedDevelopmentReleaseInput),
}
#[derive(Clone, Debug, Deserialize)]
@ -232,6 +242,27 @@ struct AuthenticatedPnccProjectionQueryInput {
query: QueryPnccReceiptProjectionInput,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct AuthenticatedDevelopmentLaneInput {
session: AuthenticateSessionInput,
lane: AcquireWriteLaneInput,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct AuthenticatedDevelopmentInspectInput {
session: AuthenticateSessionInput,
account_id: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
struct AuthenticatedDevelopmentReleaseInput {
session: AuthenticateSessionInput,
lane: ReleaseWriteLaneInput,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct BrokerResponse {
@ -408,6 +439,9 @@ fn start_at(
.parent()
.ok_or("HOLOLAKE_BROKER_PERSONA_TIME_STORAGE_BOUNDARY_INVALID")?
.join("persona-time-authority-v1");
let development_root = development_root_from_session_root(&session_root)?;
fs::create_dir_all(&development_root)
.map_err(|error| format!("HOLOLAKE_BRIDGE_STORAGE_UNAVAILABLE: {error}"))?;
if let Some(parent) = socket_path.parent() {
fs::create_dir_all(parent)
.map_err(|error| format!("HOLOLAKE_BROKER_RUNTIME_DIR_FAILED: {error}"))?;
@ -463,6 +497,7 @@ fn start_at(
pncc_projection: pncc_projection_root,
language_inbox: language_inbox_root,
persona_time: persona_time_root,
development: development_root,
},
&worker_shutdown,
&worker_authenticated_connections,
@ -586,6 +621,7 @@ fn dispatch(roots: &BrokerStorageRoots, bytes: &[u8]) -> BrokerResponse {
let pncc_projection_root = &roots.pncc_projection;
let language_inbox_root = &roots.language_inbox;
let persona_time_root = &roots.persona_time;
let development_root = &roots.development;
let request: BrokerRequest = match serde_json::from_slice(bytes) {
Ok(request) => request,
Err(error) => {
@ -682,6 +718,41 @@ fn dispatch(roots: &BrokerStorageRoots, bytes: &[u8]) -> BrokerResponse {
issue_authenticated_at(persona_time_root, session_root, input)
.and_then(|ticket| serde_json::to_value(ticket).map_err(|error| error.to_string()))
}
BrokerRequest::AcquireDevelopmentWriteLane(input) => {
authenticate_development_request(session_root, &input.session, &input.lane.account_id)
.and_then(|context| {
if context.lane_id != input.lane.lane_id
|| context.client_instance_id != input.lane.owner_instance_id
{
return Err("HOLOLAKE_DEVELOPMENT_LANE_SESSION_MISMATCH".into());
}
acquire_development_lane_at(development_root, input.lane)
})
.and_then(|receipt| {
serde_json::to_value(receipt).map_err(|error| error.to_string())
})
}
BrokerRequest::InspectDevelopmentWriteLane(input) => {
authenticate_development_request(session_root, &input.session, &input.account_id)
.and_then(|_| inspect_development_lane_at(development_root, &input.account_id))
.and_then(|receipt| {
serde_json::to_value(receipt).map_err(|error| error.to_string())
})
}
BrokerRequest::ReleaseDevelopmentWriteLane(input) => {
authenticate_development_request(session_root, &input.session, &input.lane.account_id)
.and_then(|context| {
if context.lane_id != input.lane.lane_id
|| context.client_instance_id != input.lane.owner_instance_id
{
return Err("HOLOLAKE_DEVELOPMENT_LANE_SESSION_MISMATCH".into());
}
release_development_lane_at(development_root, input.lane)
})
.and_then(|receipt| {
serde_json::to_value(receipt).map_err(|error| error.to_string())
})
}
};
match result {
Ok(value) => BrokerResponse::success(value),
@ -689,6 +760,32 @@ fn dispatch(roots: &BrokerStorageRoots, bytes: &[u8]) -> BrokerResponse {
}
}
fn authenticate_development_request(
session_root: &Path,
session: &AuthenticateSessionInput,
account_id: &str,
) -> Result<AuthenticatedSessionContext, String> {
let context = authenticate_context_at(session_root, session)?;
if context.account_key != development_account_key_for(account_id)? {
return Err("HOLOLAKE_DEVELOPMENT_ACCOUNT_SESSION_MISMATCH".into());
}
Ok(context)
}
fn development_root_from_session_root(session_root: &Path) -> Result<PathBuf, String> {
let account_root = session_root
.parent()
.ok_or("HOLOLAKE_BROKER_DEVELOPMENT_STORAGE_BOUNDARY_INVALID")?;
if session_root.file_name().and_then(|name| name.to_str()) == Some("direct-local-session-v1") {
let app_data = account_root
.parent()
.and_then(Path::parent)
.ok_or("HOLOLAKE_BROKER_DEVELOPMENT_STORAGE_BOUNDARY_INVALID")?;
return Ok(app_data.join("local-development-bridge-v1"));
}
Ok(account_root.join("local-development-bridge-v1"))
}
fn open_visitor_session_at(
session_root: &Path,
input: OpenVisitorSessionInput,
@ -1152,6 +1249,157 @@ mod tests {
assert_eq!(verified["result"]["returnedEventCount"], 0);
}
#[test]
fn authenticated_connector_can_acquire_and_inspect_the_hololake_development_lane() {
let temp = TempDir::new().unwrap();
let socket = temp.path().join("runtime/broker.sock");
let descriptor = temp.path().join("broker.json");
let sessions = temp
.path()
.join("accounts-v1/test-account/direct-local-session-v1");
let routes = temp.path().join("routes");
fs::create_dir_all(&sessions).unwrap();
fs::create_dir_all(&routes).unwrap();
let _broker = start_at(sessions.clone(), routes, descriptor, socket.clone()).unwrap();
let ticket = issue_ticket_at(
&sessions,
IssueDiscoveryTicketInput {
account_id: "human-1".into(),
lane_id: "hololake-zero-core-runtime-20260817".into(),
client_instance_id: "codex-1".into(),
},
)
.unwrap();
let opened = request(
&socket,
serde_json::json!({
"operation": "OPEN_SESSION",
"input": {
"accountId": "human-1",
"laneId": "hololake-zero-core-runtime-20260817",
"clientInstanceId": "codex-1",
"discoveryTicket": ticket.discovery_ticket
}
}),
);
let session = serde_json::json!({
"accountId": "human-1",
"sessionId": opened["result"]["sessionId"],
"resumeSecret": opened["result"]["resumeSecret"]
});
let acquired = request(
&socket,
serde_json::json!({
"operation": "ACQUIRE_DEVELOPMENT_WRITE_LANE",
"input": {
"session": session,
"lane": {
"accountId": "human-1",
"laneId": "hololake-zero-core-runtime-20260817",
"ownerInstanceId": "codex-1",
"resumeToken": null
}
}
}),
);
assert_eq!(acquired["ok"], true);
assert_eq!(acquired["result"]["state"], "ACQUIRED");
let inspected = request(
&socket,
serde_json::json!({
"operation": "INSPECT_DEVELOPMENT_WRITE_LANE",
"input": {
"session": session,
"accountId": "human-1"
}
}),
);
assert_eq!(inspected["ok"], true);
assert_eq!(inspected["result"]["state"], "ACTIVE");
assert_eq!(
inspected["result"]["laneId"],
"hololake-zero-core-runtime-20260817"
);
assert_eq!(inspected["result"]["ownerInstanceId"], "codex-1");
let released = request(
&socket,
serde_json::json!({
"operation": "RELEASE_DEVELOPMENT_WRITE_LANE",
"input": {
"session": session,
"lane": {
"accountId": "human-1",
"laneId": "hololake-zero-core-runtime-20260817",
"ownerInstanceId": "codex-1",
"resumeToken": acquired["result"]["resumeToken"]
}
}
}),
);
assert_eq!(released["ok"], true);
assert_eq!(released["result"]["state"], "RELEASED");
let available = request(
&socket,
serde_json::json!({
"operation": "INSPECT_DEVELOPMENT_WRITE_LANE",
"input": {
"session": session,
"accountId": "human-1"
}
}),
);
assert_eq!(available["result"]["state"], "AVAILABLE");
}
#[test]
fn expression_only_visitor_cannot_acquire_a_development_lane() {
let temp = TempDir::new().unwrap();
let socket = temp.path().join("runtime/broker.sock");
let descriptor = temp.path().join("broker.json");
let sessions = temp
.path()
.join("accounts-v1/test-account/direct-local-session-v1");
let routes = temp.path().join("routes");
fs::create_dir_all(&sessions).unwrap();
fs::create_dir_all(&routes).unwrap();
let _broker = start_at(sessions, routes, descriptor, socket.clone()).unwrap();
let opened = request(
&socket,
serde_json::json!({
"operation": "OPEN_VISITOR_SESSION",
"input": {"clientInstanceId": "generic-ai-1"}
}),
);
let acquired = request(
&socket,
serde_json::json!({
"operation": "ACQUIRE_DEVELOPMENT_WRITE_LANE",
"input": {
"session": {
"accountId": opened["result"]["accountId"],
"sessionId": opened["result"]["session"]["sessionId"],
"resumeSecret": opened["result"]["session"]["resumeSecret"]
},
"lane": {
"accountId": opened["result"]["accountId"],
"laneId": "unauthorized-development",
"ownerInstanceId": "generic-ai-1",
"resumeToken": null
}
}
}),
);
assert_eq!(acquired["ok"], false);
assert_eq!(
acquired["error"],
"HOLOLAKE_VISITOR_SESSION_HAS_NO_SYSTEM_AUTHORITY"
);
}
#[test]
fn only_an_authenticated_persistent_connector_counts_as_online() {
let temp = TempDir::new().unwrap();

View file

@ -116,7 +116,10 @@ fn bridge_root(app: &AppHandle) -> Result<PathBuf, String> {
.map_err(|error| format!("HOLOLAKE_BRIDGE_STORAGE_UNAVAILABLE: {error}"))
}
fn acquire_at(root: &Path, input: AcquireWriteLaneInput) -> Result<WriteLaneReceipt, String> {
pub(crate) fn acquire_at(
root: &Path,
input: AcquireWriteLaneInput,
) -> Result<WriteLaneReceipt, String> {
validate_identifier(&input.account_id, "ACCOUNT")?;
validate_identifier(&input.lane_id, "LANE")?;
validate_identifier(&input.owner_instance_id, "OWNER")?;
@ -186,7 +189,7 @@ fn resume_existing(
Ok(receipt_for("RESUMED", &record, None, observed_at))
}
fn inspect_at(root: &Path, account_id: &str) -> Result<InspectWriteLaneReceipt, String> {
pub(crate) fn inspect_at(root: &Path, account_id: &str) -> Result<InspectWriteLaneReceipt, String> {
validate_identifier(account_id, "ACCOUNT")?;
let account_key = sha256_hex(account_id.as_bytes());
let active_path = root
@ -217,7 +220,10 @@ fn inspect_at(root: &Path, account_id: &str) -> Result<InspectWriteLaneReceipt,
})
}
fn release_at(root: &Path, input: ReleaseWriteLaneInput) -> Result<WriteLaneReceipt, String> {
pub(crate) fn release_at(
root: &Path,
input: ReleaseWriteLaneInput,
) -> Result<WriteLaneReceipt, String> {
validate_identifier(&input.account_id, "ACCOUNT")?;
validate_identifier(&input.lane_id, "LANE")?;
validate_identifier(&input.owner_instance_id, "OWNER")?;
@ -339,6 +345,11 @@ fn sha256_hex(value: &[u8]) -> String {
.collect()
}
pub(crate) fn account_key_for(account_id: &str) -> Result<String, String> {
validate_identifier(account_id, "ACCOUNT")?;
Ok(sha256_hex(account_id.as_bytes()))
}
#[cfg(test)]
mod tests {
use super::*;