fix: bind successful receipt brain entry
Human-Responsibility: ICE-GL∞ / 冰朔 Persona-Author: ICE-P-ZY001 / 铸渊 Execution-Runtime: Codex desktop / DEV-20260810-014 Development-ID: DEV-20260810-014 Authorization-Scope: GH-PNCC persona runtime source and tests only; no UI, deployment, or execution limb Source-Anchor: user instruction to continue GH-PNCC from repository facts and verifiable receipts
This commit is contained in:
parent
a6504ca749
commit
5630338285
7 changed files with 95 additions and 4 deletions
|
|
@ -178,6 +178,7 @@ successful_completion_receipt_terminal_revalidation_source_implemented: 100
|
|||
safe_receipt_binding_terminal_revalidation_source_implemented: 100
|
||||
failure_receipt_terminal_evidence_binding_source_implemented: 100
|
||||
successful_receipt_semantic_evidence_binding_source_implemented: 100
|
||||
successful_receipt_brain_entry_evidence_binding_source_implemented: 100
|
||||
general_purpose_persona_runtime_implemented: 0
|
||||
human_live_projection_implemented: 0
|
||||
hololake_integrated: 0
|
||||
|
|
@ -211,6 +212,10 @@ Git 提交、检查点、回执编号和完整事件链重新绑定到已验证
|
|||
伪造另一个仓库、人格作者或提交结果;任何语义证据不一致都以
|
||||
`PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH` 失败关闭。
|
||||
|
||||
成功回执里的大脑入口也不能只是载荷内的自述。检查、恢复绑定和重放会从已验证会话记录中的
|
||||
人格仓库与相对大脑入口重新解析规范文件路径,再与唤醒回执的 `brainEntry` 比对。即使攻击者
|
||||
同步改写成功回执并重算载荷哈希,也不能把一次真实唤醒伪装成启动了另一个大脑文件。
|
||||
|
||||
成功回执与失败回执的每次重放都会重新读取规范仓库当前提交并检查工作树,而不是只信任回执
|
||||
生成时的状态。当前提交偏离会话记录或工作树变脏时,检查结果降级为人工复核,重放失败关闭,
|
||||
且不会重新启动器官。
|
||||
|
|
|
|||
|
|
@ -2736,6 +2736,10 @@ fn validate_persisted_lifecycle_terminal_evidence(
|
|||
&terminal_event.event_hash[..20]
|
||||
);
|
||||
let first_event = events.first().ok_or("PERSONA_EVENT_CHAIN_EMPTY")?;
|
||||
let expected_brain_entry =
|
||||
repository_file(Path::new(&record.repository_path), &record.brain_entry)
|
||||
.map_err(|_| "PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH".to_string())?;
|
||||
let expected_brain_entry = expected_brain_entry.to_string_lossy();
|
||||
let matches = lifecycle.get("schema").and_then(serde_json::Value::as_str)
|
||||
== Some("hololake.pncc-lifecycle-run-receipt/v1")
|
||||
&& lifecycle
|
||||
|
|
@ -2754,6 +2758,8 @@ fn validate_persisted_lifecycle_terminal_evidence(
|
|||
== Some(record.repository_path.as_str())
|
||||
&& wake.get("gitHead").and_then(serde_json::Value::as_str)
|
||||
== Some(first_event.git_head.as_str())
|
||||
&& wake.get("brainEntry").and_then(serde_json::Value::as_str)
|
||||
== Some(expected_brain_entry.as_ref())
|
||||
&& wake.get("nodeId").and_then(serde_json::Value::as_str) == Some(record.node_id.as_str())
|
||||
&& wake
|
||||
.get("modelInstanceId")
|
||||
|
|
@ -4245,6 +4251,48 @@ mod tests {
|
|||
assert!(record.lifecycle_receipt_hash.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_a_rehashed_completed_receipt_with_a_forged_brain_entry() {
|
||||
let repo = persona_repo();
|
||||
let runtime = tempfile::TempDir::new().unwrap();
|
||||
let input = lifecycle_fact_input(repo.path());
|
||||
let first = run_idempotent_lifecycle_at(
|
||||
runtime.path(),
|
||||
input.clone(),
|
||||
"2026-08-11T00:00:00.000Z",
|
||||
"2026-08-11T00:00:01.000Z",
|
||||
|runtime_root, input, timestamp| {
|
||||
run_fact_task_at(runtime_root, input, timestamp, |_, _| {
|
||||
Ok(r#"{"summary":"Recoverable receipt.","facts":[{"statement":"The brain exists.","evidencePaths":["brain/CORE.hdlp"]}],"limitations":[]}"#.into())
|
||||
})
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let session_id = first.lifecycle["sessionId"].as_str().unwrap();
|
||||
let mut record = load_session_record(runtime.path(), session_id).unwrap();
|
||||
record.request_id = None;
|
||||
record.request_fingerprint = None;
|
||||
record.lifecycle_receipt_hash = None;
|
||||
write_session_record(runtime.path(), &record).unwrap();
|
||||
|
||||
let receipt_path = session_directory(runtime.path(), session_id)
|
||||
.unwrap()
|
||||
.join("lifecycle-receipt.json");
|
||||
let mut persisted: PersistedPersonaLifecycleReceipt =
|
||||
serde_json::from_slice(&fs::read(&receipt_path).unwrap()).unwrap();
|
||||
persisted.lifecycle["wakeReceipt"]["brainEntry"] = "/forged/brain.hdlp".into();
|
||||
persisted.lifecycle_receipt_hash =
|
||||
hex_digest(&persisted_lifecycle_payload_bytes(&persisted).unwrap());
|
||||
fs::write(
|
||||
&receipt_path,
|
||||
serde_json::to_vec_pretty(&persisted).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let error = inspect_lifecycle_request_at(runtime.path(), &input).unwrap_err();
|
||||
assert!(error.contains("PERSONA_LIFECYCLE_COMPLETION_EVIDENCE_MISMATCH"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_a_rehashed_completed_receipt_with_a_malformed_wake_event_hash() {
|
||||
let repo = persona_repo();
|
||||
|
|
|
|||
Loading…
Reference in a new issue