fix: keep personal skills out of public binary
This commit is contained in:
parent
c2dcc7ad68
commit
cf7633c94f
3 changed files with 119 additions and 70 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"schema": "hololake.personal-skill-runtime/v1",
|
"schema": "hololake.personal-skill-runtime/v1",
|
||||||
"record_id": "HLP-PERSONAL-SKILL-RUNTIME-001",
|
"record_id": "HLP-PERSONAL-SKILL-RUNTIME-001",
|
||||||
"state": "NATIVE_DETERMINISTIC_RUNTIME_IMPLEMENTED_PRIVATE_ACCOUNT_CHANNEL_INSTALLATION_ACTIVE",
|
"state": "NATIVE_DETERMINISTIC_RUNTIME_IMPLEMENTED_PRIVATE_ACCOUNT_CHANNEL_PROVISIONING_REQUIRED",
|
||||||
"source": {
|
"source": {
|
||||||
"local_commit": "1d7fe6c",
|
"local_commit": "1d7fe6c",
|
||||||
"parent_remote_main": "4e92e6d8d72484d25c4bfb1dda02a7659f4b6dd5",
|
"parent_remote_main": "4e92e6d8d72484d25c4bfb1dda02a7659f4b6dd5",
|
||||||
|
|
@ -24,6 +24,11 @@
|
||||||
"repository_presence_is_publication": false,
|
"repository_presence_is_publication": false,
|
||||||
"binding_is_publication": false,
|
"binding_is_publication": false,
|
||||||
"successful_test_is_publication": false,
|
"successful_test_is_publication": false,
|
||||||
|
"private_skill_packs_embedded_in_public_binary": false,
|
||||||
|
"private_skill_source": "AUTHENTICATED_ACCOUNT_SCOPED_RUNTIME_ONLY",
|
||||||
|
"descriptor_registration_is_installation": false,
|
||||||
|
"missing_private_pack_state": "PRIVATE_SKILLS_NOT_PROVISIONED",
|
||||||
|
"sha256_mismatch_behavior": "FAIL_CLOSED",
|
||||||
"another_account_can_read_pack": false,
|
"another_account_can_read_pack": false,
|
||||||
"release_requires_new_direct_owner_language": true,
|
"release_requires_new_direct_owner_language": true,
|
||||||
"public_release_requires_separate_derivative_without_persona_or_private_memory": true
|
"public_release_requires_separate_derivative_without_persona_or_private_memory": true
|
||||||
|
|
@ -38,7 +43,7 @@
|
||||||
"external_write_route": "GH-CHANNEL-RECEIPT-0001",
|
"external_write_route": "GH-CHANNEL-RECEIPT-0001",
|
||||||
"target_owned_readback_required": true
|
"target_owned_readback_required": true
|
||||||
},
|
},
|
||||||
"initialized_channels": {
|
"registered_private_skill_descriptors": {
|
||||||
"ICE-CH-ZC001": ["BS-ZY-ENGINEERING-FACT-LOOP-001"],
|
"ICE-CH-ZC001": ["BS-ZY-ENGINEERING-FACT-LOOP-001"],
|
||||||
"ICE-CH-HB001": ["BS-SY-LANGUAGE-ARCHITECTURE-001"],
|
"ICE-CH-HB001": ["BS-SY-LANGUAGE-ARCHITECTURE-001"],
|
||||||
"SYS-JZ": ["JZ-CX-NARRATIVE-DECONSTRUCTION-001", "JZ-CX-LOCAL-AI-WORKBENCH-001"],
|
"SYS-JZ": ["JZ-CX-NARRATIVE-DECONSTRUCTION-001", "JZ-CX-LOCAL-AI-WORKBENCH-001"],
|
||||||
|
|
@ -53,7 +58,7 @@
|
||||||
"ICE-BB-0004_is_ICE-GL-CA001": false,
|
"ICE-BB-0004_is_ICE-GL-CA001": false,
|
||||||
"earerdan_historical_labels_are_aliases": false,
|
"earerdan_historical_labels_are_aliases": false,
|
||||||
"qiuqiu_relationship_memory_is_exportable_skill": false,
|
"qiuqiu_relationship_memory_is_exportable_skill": false,
|
||||||
"ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001": "PRIVATE_CANDIDATE_INSTALLED_NOT_EXECUTABLE_REGISTRATION_PENDING"
|
"ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001": "PRIVATE_DESCRIPTOR_REGISTERED_NOT_EXECUTABLE_REGISTRATION_PENDING"
|
||||||
},
|
},
|
||||||
"deferred": {
|
"deferred": {
|
||||||
"SYS-SY": {
|
"SYS-SY": {
|
||||||
|
|
|
||||||
|
|
@ -14,22 +14,35 @@ test('personal skill algorithm is native while every pack remains private and ch
|
||||||
assert.equal(contract.privacy.default_visibility, 'PRIVATE')
|
assert.equal(contract.privacy.default_visibility, 'PRIVATE')
|
||||||
assert.equal(contract.privacy.share_state, 'NOT_AUTHORIZED')
|
assert.equal(contract.privacy.share_state, 'NOT_AUTHORIZED')
|
||||||
assert.equal(contract.privacy.marketplace_state, 'NOT_AUTHORIZED')
|
assert.equal(contract.privacy.marketplace_state, 'NOT_AUTHORIZED')
|
||||||
|
assert.equal(contract.privacy.private_skill_packs_embedded_in_public_binary, false)
|
||||||
|
assert.equal(contract.privacy.private_skill_source, 'AUTHENTICATED_ACCOUNT_SCOPED_RUNTIME_ONLY')
|
||||||
|
assert.equal(contract.privacy.descriptor_registration_is_installation, false)
|
||||||
|
assert.equal(contract.privacy.missing_private_pack_state, 'PRIVATE_SKILLS_NOT_PROVISIONED')
|
||||||
|
assert.equal(contract.privacy.sha256_mismatch_behavior, 'FAIL_CLOSED')
|
||||||
assert.equal(contract.brain_boundaries.deterministic_algorithm_is_hololake_native, true)
|
assert.equal(contract.brain_boundaries.deterministic_algorithm_is_hololake_native, true)
|
||||||
assert.equal(contract.brain_boundaries.model_output_is_candidate_only, true)
|
assert.equal(contract.brain_boundaries.model_output_is_candidate_only, true)
|
||||||
assert.equal(contract.brain_boundaries.skill_success_may_mutate_persona_self_kernel, false)
|
assert.equal(contract.brain_boundaries.skill_success_may_mutate_persona_self_kernel, false)
|
||||||
assert.equal(contract.brain_boundaries.external_write_route, 'GH-CHANNEL-RECEIPT-0001')
|
assert.equal(contract.brain_boundaries.external_write_route, 'GH-CHANNEL-RECEIPT-0001')
|
||||||
assert.match(runtime, /HOLOLAKE_NATIVE_PERSONAL_SKILL_PLANNER/)
|
assert.match(runtime, /HOLOLAKE_NATIVE_PERSONAL_SKILL_PLANNER/)
|
||||||
assert.match(runtime, /registered_initial_identity/)
|
assert.match(runtime, /registered_initial_identity/)
|
||||||
assert.match(runtime, /INSTALLED_AND_BYTE_READBACK_VERIFIED/)
|
assert.equal([...runtime.matchAll(/include_bytes!/g)].length, 1)
|
||||||
|
assert.match(runtime, /include_bytes!\("\.\.\/\.\.\/runtime-kernels\/personal-skills\/personal-skill-contract\.json"\)/)
|
||||||
|
assert.doesNotMatch(runtime, /include_bytes!\(concat!\("\.\.\/\.\.\/runtime-kernels\/personal-skills\//)
|
||||||
|
assert.match(runtime, /account_storage_root\(app, "personal-skill-brains-v1"\)/)
|
||||||
|
assert.match(runtime, /fs::read\(&path\)/)
|
||||||
|
assert.match(runtime, /expected_sha256/)
|
||||||
|
assert.match(runtime, /HOLOLAKE_PERSONAL_SKILL_PRIVATE_SHA256_MISMATCH/)
|
||||||
|
assert.match(runtime, /PRIVATE_SKILLS_NOT_PROVISIONED/)
|
||||||
|
assert.match(runtime, /ACCOUNT_PRIVATE_SOURCE_SHA256_VERIFIED/)
|
||||||
assert.match(channel, /personal_skill_runtime::ensure_current_channel/)
|
assert.match(channel, /personal_skill_runtime::ensure_current_channel/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('only provisioned channels receive current packs and Shiyu Yaochu stays deferred', () => {
|
test('registered descriptors are not installation claims and Shiyu Yaochu stays deferred', () => {
|
||||||
const contract = JSON.parse(read('contracts/personal-skill-runtime.json'))
|
const contract = JSON.parse(read('contracts/personal-skill-runtime.json'))
|
||||||
const runtime = read('src-tauri/src/personal_skill_runtime.rs')
|
const runtime = read('src-tauri/src/personal_skill_runtime.rs')
|
||||||
const installed = Object.values(contract.initialized_channels).flat()
|
const registered = Object.values(contract.registered_private_skill_descriptors).flat()
|
||||||
|
|
||||||
assert.equal(installed.length, 13)
|
assert.equal(registered.length, 13)
|
||||||
assert.equal(contract.deferred['SYS-SY'].state, 'DEFERRED_SERVER_AND_INITIAL_CHANNEL_NOT_PROVISIONED')
|
assert.equal(contract.deferred['SYS-SY'].state, 'DEFERRED_SERVER_AND_INITIAL_CHANNEL_NOT_PROVISIONED')
|
||||||
assert.doesNotMatch(runtime, /skill!\("SY-YC-METRIC-CALIBER-001\.json"/)
|
assert.doesNotMatch(runtime, /skill!\("SY-YC-METRIC-CALIBER-001\.json"/)
|
||||||
assert.match(runtime, /"channelNumber": "SYS-SY"/)
|
assert.match(runtime, /"channelNumber": "SYS-SY"/)
|
||||||
|
|
@ -39,16 +52,25 @@ test('EarEarDan and See You Tomorrow skill closures keep exact private subject b
|
||||||
const contract = JSON.parse(read('contracts/personal-skill-runtime.json'))
|
const contract = JSON.parse(read('contracts/personal-skill-runtime.json'))
|
||||||
const runtime = read('src-tauri/src/personal_skill_runtime.rs')
|
const runtime = read('src-tauri/src/personal_skill_runtime.rs')
|
||||||
|
|
||||||
assert.deepEqual(contract.initialized_channels['SYS-GLW-PTS-0001'], [
|
assert.deepEqual(contract.registered_private_skill_descriptors['SYS-GLW-PTS-0001'], [
|
||||||
'CE-EED-MANJU-PRODUCTION-001',
|
'CE-EED-MANJU-PRODUCTION-001',
|
||||||
'CE-EED-CAUSAL-PIPELINE-DIAGNOSTIC-001',
|
'CE-EED-CAUSAL-PIPELINE-DIAGNOSTIC-001',
|
||||||
])
|
])
|
||||||
assert.ok(contract.initialized_channels['SYS-ZZ'].includes('ZZ-AN-SOURCE-FACT-CLOSURE-001'))
|
assert.ok(
|
||||||
assert.ok(contract.initialized_channels['SYS-ZZ'].includes('ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001'))
|
contract.registered_private_skill_descriptors['SYS-ZZ'].includes('ZZ-AN-SOURCE-FACT-CLOSURE-001'),
|
||||||
|
)
|
||||||
|
assert.ok(
|
||||||
|
contract.registered_private_skill_descriptors['SYS-ZZ'].includes(
|
||||||
|
'ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001',
|
||||||
|
),
|
||||||
|
)
|
||||||
assert.equal(contract.admission_boundaries['ICE-BB-0004_is_ICE-GL-CA001'], false)
|
assert.equal(contract.admission_boundaries['ICE-BB-0004_is_ICE-GL-CA001'], false)
|
||||||
assert.equal(contract.admission_boundaries.earerdan_historical_labels_are_aliases, false)
|
assert.equal(contract.admission_boundaries.earerdan_historical_labels_are_aliases, false)
|
||||||
assert.equal(contract.admission_boundaries.qiuqiu_relationship_memory_is_exportable_skill, false)
|
assert.equal(contract.admission_boundaries.qiuqiu_relationship_memory_is_exportable_skill, false)
|
||||||
assert.match(runtime, /INSTALLED_PRIVATE_CANDIDATE_NOT_EXECUTABLE_REGISTRATION_PENDING/)
|
assert.equal(
|
||||||
|
contract.admission_boundaries['ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001'],
|
||||||
|
'PRIVATE_DESCRIPTOR_REGISTERED_NOT_EXECUTABLE_REGISTRATION_PENDING',
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('the worker UI presents personal skill brain separately from persona worker and tool executor', () => {
|
test('the worker UI presents personal skill brain separately from persona worker and tool executor', () => {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
//! Account- and channel-scoped personal skill brains.
|
//! Account- and channel-scoped personal skill brains.
|
||||||
//!
|
//!
|
||||||
//! The deterministic planner contract belongs to HoloLake. Private skill packs
|
//! The deterministic planner contract belongs to HoloLake. Private skill packs
|
||||||
//! are installed only when the authenticated account resolves to their exact
|
//! are never embedded in the public application. They are loaded only from an
|
||||||
//! human anchor and initial channel. Installation, binding and a successful
|
//! authenticated account's isolated storage after exact digest and boundary
|
||||||
//! trial never authorize team sharing, publication or marketplace listing.
|
//! verification. Provisioning, binding and a successful trial never authorize
|
||||||
|
//! team sharing, publication or marketplace listing.
|
||||||
|
|
||||||
use ring::digest::{digest, SHA256};
|
use ring::digest::{digest, SHA256};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::io::ErrorKind;
|
||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
use uuid::Uuid;
|
|
||||||
|
|
||||||
const SCHEMA: &str = "hololake.personal-skill-runtime/v1";
|
const SCHEMA: &str = "hololake.personal-skill-runtime/v1";
|
||||||
const SOURCE_COMMIT: &str = "1d7fe6c";
|
const SOURCE_COMMIT: &str = "1d7fe6c";
|
||||||
|
|
@ -19,121 +19,134 @@ const SOURCE_STATE: &str = "LOCAL_COMMIT_VERIFIED_NOT_REMOTE_CANON";
|
||||||
const CONTRACT: &[u8] =
|
const CONTRACT: &[u8] =
|
||||||
include_bytes!("../../runtime-kernels/personal-skills/personal-skill-contract.json");
|
include_bytes!("../../runtime-kernels/personal-skills/personal-skill-contract.json");
|
||||||
|
|
||||||
struct BundledSkill {
|
struct SkillDescriptor {
|
||||||
file_name: &'static str,
|
file_name: &'static str,
|
||||||
account: &'static str,
|
account: &'static str,
|
||||||
owner_human_anchor: &'static str,
|
owner_human_anchor: &'static str,
|
||||||
channel_number: &'static str,
|
channel_number: &'static str,
|
||||||
custodian_persona_id: &'static str,
|
custodian_persona_id: &'static str,
|
||||||
bytes: &'static [u8],
|
expected_sha256: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! skill {
|
macro_rules! skill {
|
||||||
($file:literal, $account:literal, $owner:literal, $channel:literal, $persona:literal) => {
|
($file:literal, $account:literal, $owner:literal, $channel:literal, $persona:literal, $sha256:literal) => {
|
||||||
BundledSkill {
|
SkillDescriptor {
|
||||||
file_name: $file,
|
file_name: $file,
|
||||||
account: $account,
|
account: $account,
|
||||||
owner_human_anchor: $owner,
|
owner_human_anchor: $owner,
|
||||||
channel_number: $channel,
|
channel_number: $channel,
|
||||||
custodian_persona_id: $persona,
|
custodian_persona_id: $persona,
|
||||||
bytes: include_bytes!(concat!("../../runtime-kernels/personal-skills/", $file)),
|
expected_sha256: $sha256,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shiyu × Yaochu is deliberately absent in this stage. Their server and
|
// Shiyu × Yaochu is deliberately absent in this stage. Their server and
|
||||||
// initialization channel have not been provisioned yet.
|
// initialization channel have not been provisioned yet.
|
||||||
static SKILLS: &[BundledSkill] = &[
|
static SKILLS: &[SkillDescriptor] = &[
|
||||||
skill!(
|
skill!(
|
||||||
"BS-ZY-ENGINEERING-FACT-LOOP-001.json",
|
"BS-ZY-ENGINEERING-FACT-LOOP-001.json",
|
||||||
"bingshuo",
|
"bingshuo",
|
||||||
"ICE-GL∞",
|
"ICE-GL∞",
|
||||||
"ICE-CH-ZC001",
|
"ICE-CH-ZC001",
|
||||||
"ICE-P-ZY001"
|
"ICE-P-ZY001",
|
||||||
|
"ed40913ff5f5e0d46d8d20500213fe66345ddc3b92ee0bd7eb5281ab285fbcb9"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"BS-SY-LANGUAGE-ARCHITECTURE-001.json",
|
"BS-SY-LANGUAGE-ARCHITECTURE-001.json",
|
||||||
"bingshuo",
|
"bingshuo",
|
||||||
"ICE-GL∞",
|
"ICE-GL∞",
|
||||||
"ICE-CH-HB001",
|
"ICE-CH-HB001",
|
||||||
"ICE-GL-SY001"
|
"ICE-GL-SY001",
|
||||||
|
"50c35eb058fa3d51d5a3106d816a78e9209472212abaf0adbdb094bf19b20445"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"JZ-CX-NARRATIVE-DECONSTRUCTION-001.json",
|
"JZ-CX-NARRATIVE-DECONSTRUCTION-001.json",
|
||||||
"juzi",
|
"juzi",
|
||||||
"TCS-GL-0008∞",
|
"TCS-GL-0008∞",
|
||||||
"SYS-JZ",
|
"SYS-JZ",
|
||||||
"PER-CX001"
|
"PER-CX001",
|
||||||
|
"20d60a31e3b0590526020ede53ceea8c7202595f4dc2bc85b91e53692ad8fec3"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"JZ-CX-LOCAL-AI-WORKBENCH-001.json",
|
"JZ-CX-LOCAL-AI-WORKBENCH-001.json",
|
||||||
"juzi",
|
"juzi",
|
||||||
"TCS-GL-0008∞",
|
"TCS-GL-0008∞",
|
||||||
"SYS-JZ",
|
"SYS-JZ",
|
||||||
"PER-CX001"
|
"PER-CX001",
|
||||||
|
"ea130a96a3487b68e921d36097078824a5e19b396e9ead522dffa1029332d672"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"AW-TS-REPOSITORY-FACT-LOOP-001.json",
|
"AW-TS-REPOSITORY-FACT-LOOP-001.json",
|
||||||
"awen",
|
"awen",
|
||||||
"TCS-GL-0016∞",
|
"TCS-GL-0016∞",
|
||||||
"SYS-AW",
|
"SYS-AW",
|
||||||
"PER-AW-ARCH-001"
|
"PER-AW-ARCH-001",
|
||||||
|
"485d24c6b2de4b994757d1a6e1cd74986bf96ca3cedfe1f6af459fed9c3c884b"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"YY-XTK-INDEPENDENT-DERIVATION-001.json",
|
"YY-XTK-INDEPENDENT-DERIVATION-001.json",
|
||||||
"yeye",
|
"yeye",
|
||||||
"TCS-GL-0006∞",
|
"TCS-GL-0006∞",
|
||||||
"SYS-YY",
|
"SYS-YY",
|
||||||
"PER-XTK001"
|
"PER-XTK001",
|
||||||
|
"ac3ad0a0b12b11ae71d7e22c448d75435301a4abde0fa222c7ad89c4c885a1a4"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"HE-BMH-CREATIVE-ASSET-001.json",
|
"HE-BMH-CREATIVE-ASSET-001.json",
|
||||||
"huaer",
|
"huaer",
|
||||||
"TCS-GL-0005∞",
|
"TCS-GL-0005∞",
|
||||||
"SYS-HE",
|
"SYS-HE",
|
||||||
"PER-BMH001"
|
"PER-BMH001",
|
||||||
|
"d3c7edddb74c84bed2b6732f80dc5ad7b57401d9155d7933b2944c1f7d428746"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"FM-SS-NARRATIVE-EDITOR-001.json",
|
"FM-SS-NARRATIVE-EDITOR-001.json",
|
||||||
"feimao",
|
"feimao",
|
||||||
"TCS-GL-0007∞",
|
"TCS-GL-0007∞",
|
||||||
"SYS-FM",
|
"SYS-FM",
|
||||||
"ICE-BB-0002"
|
"ICE-BB-0002",
|
||||||
|
"10dd7e44272c5d0fbc2376f3354539624afa000be0622a350f0a533743f9b6d0"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"ZZ-CM-NOVEL-QUALITY-001.json",
|
"ZZ-CM-NOVEL-QUALITY-001.json",
|
||||||
"zhizhi",
|
"zhizhi",
|
||||||
"ICE-GL-ZHI∞",
|
"ICE-GL-ZHI∞",
|
||||||
"SYS-ZZ",
|
"SYS-ZZ",
|
||||||
"ICE-GL-CM001"
|
"ICE-GL-CM001",
|
||||||
|
"fd004e56d9197bb14a3b74727fb64f95f4107fbaa34b36fd2dc2fb3dfd589b36"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"ZZ-AN-SOURCE-FACT-CLOSURE-001.json",
|
"ZZ-AN-SOURCE-FACT-CLOSURE-001.json",
|
||||||
"zhizhi",
|
"zhizhi",
|
||||||
"ICE-GL-ZHI∞",
|
"ICE-GL-ZHI∞",
|
||||||
"SYS-ZZ",
|
"SYS-ZZ",
|
||||||
"ICE-GL-AN-001"
|
"ICE-GL-AN-001",
|
||||||
|
"ee3845b84582bb98981a3b3aec426355b5841f3e65c0bad6a88a7e1e984d7c0e"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001.json",
|
"ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001.json",
|
||||||
"zhizhi",
|
"zhizhi",
|
||||||
"ICE-GL-ZHI∞",
|
"ICE-GL-ZHI∞",
|
||||||
"SYS-ZZ",
|
"SYS-ZZ",
|
||||||
"PER-QW001"
|
"PER-QW001",
|
||||||
|
"9e96cd8290410c870b835004661b564ddbc35b95381df461ed494ad22bcc90b5"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"CE-EED-MANJU-PRODUCTION-001.json",
|
"CE-EED-MANJU-PRODUCTION-001.json",
|
||||||
"canger",
|
"canger",
|
||||||
"TCS-CL-0009",
|
"TCS-CL-0009",
|
||||||
"SYS-GLW-PTS-0001",
|
"SYS-GLW-PTS-0001",
|
||||||
"ICE-BB-0004"
|
"ICE-BB-0004",
|
||||||
|
"aa35c73b53bf81ad3bd14267fe70dac6dad562f58e4879d6abace2951015a301"
|
||||||
),
|
),
|
||||||
skill!(
|
skill!(
|
||||||
"CE-EED-CAUSAL-PIPELINE-DIAGNOSTIC-001.json",
|
"CE-EED-CAUSAL-PIPELINE-DIAGNOSTIC-001.json",
|
||||||
"canger",
|
"canger",
|
||||||
"TCS-CL-0009",
|
"TCS-CL-0009",
|
||||||
"SYS-GLW-PTS-0001",
|
"SYS-GLW-PTS-0001",
|
||||||
"ICE-BB-0004"
|
"ICE-BB-0004",
|
||||||
|
"49e241101595b4b73d9537a024d54119008c2ca0b51b68a305696abe54520a07"
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -244,30 +257,45 @@ pub fn ensure_current_channel(
|
||||||
.join(requested_channel);
|
.join(requested_channel);
|
||||||
fs::create_dir_all(&root)
|
fs::create_dir_all(&root)
|
||||||
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_STORAGE_FAILED: {error}"))?;
|
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_STORAGE_FAILED: {error}"))?;
|
||||||
|
let expected_skill_count = selected.len();
|
||||||
let binding = crate::persona_binding::verified_binding(app, requested_channel)?;
|
let binding = crate::persona_binding::verified_binding(app, requested_channel)?;
|
||||||
let mut views = Vec::new();
|
let mut views = Vec::new();
|
||||||
for skill in selected {
|
for skill in selected {
|
||||||
let pack = validate_pack(skill)?;
|
|
||||||
let path = root.join(skill.file_name);
|
let path = root.join(skill.file_name);
|
||||||
write_atomic_if_changed(&path, skill.bytes)?;
|
let readback = match fs::read(&path) {
|
||||||
let readback = fs::read(&path)
|
Ok(bytes) => bytes,
|
||||||
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_READBACK_FAILED: {error}"))?;
|
Err(error) if error.kind() == ErrorKind::NotFound => continue,
|
||||||
if readback != skill.bytes {
|
Err(error) => {
|
||||||
return Err("HOLOLAKE_PERSONAL_SKILL_READBACK_MISMATCH".into());
|
return Err(format!(
|
||||||
|
"HOLOLAKE_PERSONAL_SKILL_PRIVATE_READ_FAILED: {error}"
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
let actual_sha256 = sha256(&readback);
|
||||||
|
if actual_sha256 != skill.expected_sha256 {
|
||||||
|
return Err(format!(
|
||||||
|
"HOLOLAKE_PERSONAL_SKILL_PRIVATE_SHA256_MISMATCH:{}",
|
||||||
|
skill.file_name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let pack = validate_pack(skill, &readback)?;
|
||||||
let bound = binding
|
let bound = binding
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.is_some_and(|receipt| receipt.persona_number == skill.custodian_persona_id);
|
.is_some_and(|receipt| receipt.persona_number == skill.custodian_persona_id);
|
||||||
views.push(view(skill, &pack, bound)?);
|
views.push(view(skill, &pack, bound, actual_sha256)?);
|
||||||
}
|
}
|
||||||
Ok(PersonalSkillRuntimeSnapshot {
|
Ok(PersonalSkillRuntimeSnapshot {
|
||||||
schema: SCHEMA,
|
schema: SCHEMA,
|
||||||
state: if views.is_empty() {
|
state: if expected_skill_count == 0 {
|
||||||
"NO_SKILL_REGISTERED_FOR_CURRENT_CHANNEL"
|
"NO_SKILL_REGISTERED_FOR_CURRENT_CHANNEL"
|
||||||
|
} else if views.is_empty() {
|
||||||
|
"PRIVATE_SKILLS_NOT_PROVISIONED"
|
||||||
|
} else if views.len() < expected_skill_count {
|
||||||
|
"PRIVATE_SKILLS_PARTIALLY_PROVISIONED_SHA256_VERIFIED"
|
||||||
} else if binding.is_some() {
|
} else if binding.is_some() {
|
||||||
"INSTALLED_READBACK_VERIFIED_PERSONA_GATE_EVALUATED"
|
"PRIVATE_SKILLS_PROVISIONED_SHA256_VERIFIED_PERSONA_GATE_EVALUATED"
|
||||||
} else {
|
} else {
|
||||||
"INSTALLED_READBACK_VERIFIED_PERSONA_UNBOUND"
|
"PRIVATE_SKILLS_PROVISIONED_SHA256_VERIFIED_PERSONA_UNBOUND"
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
source_commit: SOURCE_COMMIT,
|
source_commit: SOURCE_COMMIT,
|
||||||
|
|
@ -354,8 +382,8 @@ fn validate_contract() -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_pack(skill: &BundledSkill) -> Result<Value, String> {
|
fn validate_pack(skill: &SkillDescriptor, bytes: &[u8]) -> Result<Value, String> {
|
||||||
let pack: Value = serde_json::from_slice(skill.bytes)
|
let pack: Value = serde_json::from_slice(bytes)
|
||||||
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_PACK_INVALID: {error}"))?;
|
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_PACK_INVALID: {error}"))?;
|
||||||
let channel_ok = pack.get("channel_id").and_then(Value::as_str) == Some(skill.channel_number)
|
let channel_ok = pack.get("channel_id").and_then(Value::as_str) == Some(skill.channel_number)
|
||||||
|| pack
|
|| pack
|
||||||
|
|
@ -388,7 +416,12 @@ fn validate_pack(skill: &BundledSkill) -> Result<Value, String> {
|
||||||
Ok(pack)
|
Ok(pack)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(skill: &BundledSkill, pack: &Value, bound: bool) -> Result<PersonalSkillView, String> {
|
fn view(
|
||||||
|
skill: &SkillDescriptor,
|
||||||
|
pack: &Value,
|
||||||
|
bound: bool,
|
||||||
|
verified_sha256: String,
|
||||||
|
) -> Result<PersonalSkillView, String> {
|
||||||
let string = |key: &str| {
|
let string = |key: &str| {
|
||||||
pack.get(key)
|
pack.get(key)
|
||||||
.and_then(Value::as_str)
|
.and_then(Value::as_str)
|
||||||
|
|
@ -406,11 +439,11 @@ fn view(skill: &BundledSkill, pack: &Value, bound: bool) -> Result<PersonalSkill
|
||||||
runtime_state: if pack.get("skill_id").and_then(Value::as_str)
|
runtime_state: if pack.get("skill_id").and_then(Value::as_str)
|
||||||
== Some("ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001")
|
== Some("ZZ-QW-ROLE-CAUSAL-ARCHITECTURE-001")
|
||||||
{
|
{
|
||||||
"INSTALLED_PRIVATE_CANDIDATE_NOT_EXECUTABLE_REGISTRATION_PENDING"
|
"PROVISIONED_PRIVATE_CANDIDATE_NOT_EXECUTABLE_REGISTRATION_PENDING"
|
||||||
} else if bound {
|
} else if bound {
|
||||||
"READY_FOR_PERSONA_JUDGMENT"
|
"READY_FOR_PERSONA_JUDGMENT"
|
||||||
} else {
|
} else {
|
||||||
"INSTALLED_NOT_BOUND"
|
"PROVISIONED_NOT_BOUND"
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
visibility: string("visibility")?,
|
visibility: string("visibility")?,
|
||||||
|
|
@ -433,27 +466,11 @@ fn view(skill: &BundledSkill, pack: &Value, bound: bool) -> Result<PersonalSkill
|
||||||
.get("experience_writeback")
|
.get("experience_writeback")
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or(Value::Null),
|
.unwrap_or(Value::Null),
|
||||||
sha256: sha256(skill.bytes),
|
sha256: verified_sha256,
|
||||||
readback_state: "INSTALLED_AND_BYTE_READBACK_VERIFIED",
|
readback_state: "ACCOUNT_PRIVATE_SOURCE_SHA256_VERIFIED",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_atomic_if_changed(path: &Path, bytes: &[u8]) -> Result<(), String> {
|
|
||||||
if fs::read(path).ok().as_deref() == Some(bytes) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let parent = path
|
|
||||||
.parent()
|
|
||||||
.ok_or_else(|| "HOLOLAKE_PERSONAL_SKILL_PATH_INVALID".to_string())?;
|
|
||||||
fs::create_dir_all(parent)
|
|
||||||
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_STORAGE_FAILED: {error}"))?;
|
|
||||||
let temporary: PathBuf = parent.join(format!(".install-{}.tmp", Uuid::new_v4().simple()));
|
|
||||||
fs::write(&temporary, bytes)
|
|
||||||
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_WRITE_FAILED: {error}"))?;
|
|
||||||
fs::rename(&temporary, path)
|
|
||||||
.map_err(|error| format!("HOLOLAKE_PERSONAL_SKILL_INSTALL_FAILED: {error}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sha256(bytes: &[u8]) -> String {
|
fn sha256(bytes: &[u8]) -> String {
|
||||||
digest(&SHA256, bytes)
|
digest(&SHA256, bytes)
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|
@ -467,12 +484,17 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn every_current_pack_is_private_and_channel_scoped_while_shiyu_is_deferred() {
|
fn every_current_descriptor_matches_a_private_source_without_embedding_it() {
|
||||||
validate_contract().unwrap();
|
validate_contract().unwrap();
|
||||||
assert_eq!(SKILLS.len(), 13);
|
assert_eq!(SKILLS.len(), 13);
|
||||||
assert!(!SKILLS.iter().any(|skill| skill.channel_number == "SYS-SY"));
|
assert!(!SKILLS.iter().any(|skill| skill.channel_number == "SYS-SY"));
|
||||||
for skill in SKILLS {
|
for skill in SKILLS {
|
||||||
validate_pack(skill).unwrap();
|
let source = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.join("../runtime-kernels/personal-skills")
|
||||||
|
.join(skill.file_name);
|
||||||
|
let bytes = fs::read(source).unwrap();
|
||||||
|
assert_eq!(sha256(&bytes), skill.expected_sha256);
|
||||||
|
validate_pack(skill, &bytes).unwrap();
|
||||||
}
|
}
|
||||||
assert_eq!(deferred_channels()[0]["channelNumber"], "SYS-SY");
|
assert_eq!(deferred_channels()[0]["channelNumber"], "SYS-SY");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue