From aacf9743f66f7ab5b757f1609e79a183a1a0f9b4 Mon Sep 17 00:00:00 2001 From: lamemustafa Date: Thu, 23 Jul 2026 01:03:13 +0530 Subject: [PATCH] feat(tally): seal canary readback runtime --- .../compatibility/compatibility-matrix.json | 2 +- .../compatibility/compatibility-surface.json | 6 +- src-tauri/src/tally/connection.rs | 142 +++++++++++++++++- src-tauri/src/tally/runtime.rs | 46 +++++- 4 files changed, 187 insertions(+), 9 deletions(-) diff --git a/docs/tally/compatibility/compatibility-matrix.json b/docs/tally/compatibility/compatibility-matrix.json index f7828ef..46d530a 100644 --- a/docs/tally/compatibility/compatibility-matrix.json +++ b/docs/tally/compatibility/compatibility-matrix.json @@ -1,7 +1,7 @@ { "schema_version": 1, "bridge_commit_sha": "be1c20cc3fd66fa1ece196505c69f26e555e4b8e", - "compatibility_surface_sha256": "4af73dde3130e886e54d969d1bf66f32f6697ba31c560353ebe90ae56050031c", + "compatibility_surface_sha256": "540328895ce1d619208a573bb3a2b834ac73bb416b6cff7ba5d52a18bce04d32", "claims": [ { "claim_id": "erp9-6-6-3-windows-education-xml-one-company", diff --git a/docs/tally/compatibility/compatibility-surface.json b/docs/tally/compatibility/compatibility-surface.json index 3f35ea8..57b0cfd 100644 --- a/docs/tally/compatibility/compatibility-surface.json +++ b/docs/tally/compatibility/compatibility-surface.json @@ -319,7 +319,7 @@ }, { "path": "src-tauri/src/tally/connection.rs", - "sha256": "18512da8f2b7d9cb300a8ffa638e50b7bab0d56dc51db208685fc77fab2085f0" + "sha256": "4101249e083862e8ec5a1d9252a20a724ae88db0dbdee5a71625d89e5bf29616" }, { "path": "src-tauri/src/tally/connector.rs", @@ -331,7 +331,7 @@ }, { "path": "src-tauri/src/tally/runtime.rs", - "sha256": "05a349822619d2ba46695d21fd46bd6ebd0c767e6e6901ff691c7990c4427c91" + "sha256": "38e7f9510e860de33e7051a0e51c7db09dfea2738d5c89e04fa491cbdc5011f9" }, { "path": "src-tauri/src/tally/serial_queue.rs", @@ -362,5 +362,5 @@ "sha256": "5a5c6eaaba234c3cbda52dfa040ed3314f79e535f744b87bc14d8d76a2299811" } ], - "manifest_sha256": "4af73dde3130e886e54d969d1bf66f32f6697ba31c560353ebe90ae56050031c" + "manifest_sha256": "540328895ce1d619208a573bb3a2b834ac73bb416b6cff7ba5d52a18bce04d32" } diff --git a/src-tauri/src/tally/connection.rs b/src-tauri/src/tally/connection.rs index e49cf74..c2c9b0d 100644 --- a/src-tauri/src/tally/connection.rs +++ b/src-tauri/src/tally/connection.rs @@ -18,8 +18,13 @@ use bridge_tally_core::{ }; use bridge_tally_protocol::{ parse_companies_for_interactive_discovery, parse_ledger_source_records_with_evidence, - parse_selected_voucher_source_records_with_evidence, parse_standard_ledger_catalog, - parse_standard_ledger_identity_observation, verify_selected_voucher_window_context, + parse_ledger_write_readback_with_evidence, parse_selected_voucher_source_records_with_evidence, + parse_standard_ledger_catalog, parse_standard_ledger_identity_observation, + verify_company_context, verify_selected_voucher_window_context, + xml_read_profiles::{ + ReadOnlyProfile, ValidatedCanaryLedgerName, ValidatedCompanyName, + ValidatedIdentityQuerySha256, + }, TallyTextEncoding, BRIDGE_LEDGER_EXPORT_SCHEMA, BRIDGE_SELECTED_VOUCHER_EXPORT_SCHEMA, }; use bridge_tally_transport::{ @@ -29,6 +34,30 @@ use bridge_tally_transport::{ pub type TallyConfig = TallyEndpointConfig; +/// An exact, validated write-canary readback. Its XML remains crate-private to +/// the future write coordinator and is never returned to the UI or persisted. +#[allow( + dead_code, + reason = "the sealed runtime seam is intentionally staged before the write coordinator" +)] +pub(crate) struct LedgerCanaryReadbackXml(String); + +impl LedgerCanaryReadbackXml { + #[allow( + dead_code, + reason = "only the future crate-internal write coordinator may inspect sealed XML" + )] + pub(crate) fn as_xml(&self) -> &str { + &self.0 + } +} + +impl std::fmt::Debug for LedgerCanaryReadbackXml { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("LedgerCanaryReadbackXml([redacted])") + } +} + #[derive(Debug, Clone, Serialize)] pub enum TallyProduct { TallyPrime, @@ -477,6 +506,38 @@ impl TallyClient { Ok(parsed.records) } + /// Executes the closed canary-readback profile and admits its response only + /// when the company, query commitment, and at-most-one exact ledger agree. + #[allow( + dead_code, + reason = "the sealed runtime seam is intentionally staged before the write coordinator" + )] + pub(crate) async fn fetch_ledger_canary_readback( + &self, + company: ValidatedCompanyName, + ledger_name: ValidatedCanaryLedgerName, + identity_query_sha256: ValidatedIdentityQuerySha256, + expected_company_guid: &str, + ) -> anyhow::Result { + let xml = self + .post_xml( + ReadOnlyProfile::LedgerCanaryReadbackV1 { + company: &company, + ledger_name: &ledger_name, + identity_query_sha256: &identity_query_sha256, + } + .render(), + ) + .await?; + validate_ledger_canary_readback( + &xml, + ledger_name.as_str(), + identity_query_sha256.as_str(), + expected_company_guid, + )?; + Ok(LedgerCanaryReadbackXml(xml)) + } + /// Reads the documented standard ledger collection as an explicitly limited /// compatibility catalog. It is not a fallback for Bridge's custom export /// and cannot establish snapshot, voucher, or write capability. @@ -718,6 +779,40 @@ fn validate_selected_ledgers( Ok(()) } +#[allow( + dead_code, + reason = "the sealed runtime seam is intentionally staged before the write coordinator" +)] +fn validate_ledger_canary_readback( + xml: &str, + expected_ledger_name: &str, + expected_identity_query_sha256: &str, + expected_company_guid: &str, +) -> anyhow::Result<()> { + let parsed = parse_ledger_write_readback_with_evidence(xml)?; + verify_company_context(&parsed.evidence, expected_company_guid)?; + if parsed + .evidence + .company_context + .as_ref() + .and_then(|context| context.query_identity_set_sha256.as_deref()) + != Some(expected_identity_query_sha256) + { + anyhow::bail!("Tally canary readback query commitment did not match the request"); + } + if parsed.records.len() > 1 { + anyhow::bail!("Tally canary readback returned more than one ledger"); + } + if parsed + .records + .first() + .is_some_and(|record| record.record.name != expected_ledger_name) + { + anyhow::bail!("Tally canary readback ledger name did not match the request"); + } + Ok(()) +} + fn verify_selected_company_name( evidence: &bridge_tally_protocol::ExportEvidence, expected_name: &str, @@ -797,8 +892,8 @@ fn detect_product(text: &str) -> TallyProduct { mod tests { use super::{ canonical_loopback_origin, decode_xml_bytes, detect_product, - normalize_discovered_companies, tally_endpoint, unique_company_guids, TallyClient, - TallyConfig, TallyProduct, + normalize_discovered_companies, tally_endpoint, unique_company_guids, + validate_ledger_canary_readback, TallyClient, TallyConfig, TallyProduct, }; use bridge_tally_core::{ CapabilityFeatureId, CapabilityPackId, CapabilityState, EvidenceConfidence, TransportId, @@ -807,6 +902,45 @@ mod tests { use tokio::io::{AsyncReadExt, AsyncWriteExt}; use tokio::net::TcpListener; + const CANARY_QUERY_DIGEST: &str = + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + + fn canary_readback(ledger_name: &str, company_guid: &str, query_digest: &str) -> String { + format!( + r#"
1
BRIDGE SYNTHETIC GROUP0
"# + ) + } + + #[test] + fn canary_readback_requires_exact_company_commitment_and_ledger_name() { + let ledger_name = "BRIDGE-CANARY-LEDGER-001"; + let xml = canary_readback(ledger_name, "company-guid", CANARY_QUERY_DIGEST); + validate_ledger_canary_readback(&xml, ledger_name, CANARY_QUERY_DIGEST, "company-guid") + .expect("exact synthetic canary readback is accepted"); + + assert!(validate_ledger_canary_readback( + &xml, + "BRIDGE-CANARY-LEDGER-002", + CANARY_QUERY_DIGEST, + "company-guid", + ) + .is_err()); + assert!(validate_ledger_canary_readback( + &xml, + ledger_name, + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "company-guid", + ) + .is_err()); + assert!(validate_ledger_canary_readback( + &xml, + ledger_name, + CANARY_QUERY_DIGEST, + "other-company-guid", + ) + .is_err()); + } + #[test] fn detects_tallyprime_status() { assert!(matches!( diff --git a/src-tauri/src/tally/runtime.rs b/src-tauri/src/tally/runtime.rs index 2c78c4b..a080f5e 100644 --- a/src-tauri/src/tally/runtime.rs +++ b/src-tauri/src/tally/runtime.rs @@ -1,7 +1,12 @@ use super::{ConnectionStatus, TallyClient, TallyCompany, TallyConfig, TallyLedger}; use super::{TallyProbeResult, TallyVoucher}; -use crate::tally::connection::{canonical_loopback_origin, SelectedReadObservation}; +use crate::tally::connection::{ + canonical_loopback_origin, LedgerCanaryReadbackXml, SelectedReadObservation, +}; use crate::tally::connector::SealedReadRequest; +use bridge_tally_protocol::xml_read_profiles::{ + ValidatedCanaryLedgerName, ValidatedCompanyName, ValidatedIdentityQuerySha256, +}; use bridge_tally_runtime::{ BodyBytesObservation, EndpointCircuitState, EndpointIdentity, EndpointRuntimeSnapshot, PortableReadRuntime, ReadAttempt, ReadExecutionError, ReadFailureClass, ReadOperation, @@ -803,6 +808,45 @@ impl TallyRuntime { .await } + /// Executes one sealed, serial canary readback. This remains a read-only + /// internal primitive for the future write coordinator; it never exposes + /// response XML to commands, the UI, or persistence. + #[allow( + dead_code, + reason = "the sealed runtime seam is intentionally staged before the write coordinator" + )] + pub(crate) async fn fetch_ledger_canary_readback( + &self, + config: TallyConfig, + company: ValidatedCompanyName, + ledger_name: ValidatedCanaryLedgerName, + identity_query_sha256: ValidatedIdentityQuerySha256, + expected_company_guid: String, + ) -> anyhow::Result { + self.execute( + config, + ReadOperation::MasterExport, + ReadRetryPolicy::SINGLE_ATTEMPT, + move |client| { + let company = company.clone(); + let ledger_name = ledger_name.clone(); + let identity_query_sha256 = identity_query_sha256.clone(); + let expected_company_guid = expected_company_guid.clone(); + async move { + client + .fetch_ledger_canary_readback( + company, + ledger_name, + identity_query_sha256, + &expected_company_guid, + ) + .await + } + }, + ) + .await + } + pub async fn qualify_selected_ledgers( &self, config: TallyConfig,