commit 243d1666ac66b28f0e11fd9f91c4d76b457993c0
parent f46cc3c510853f0df6efe3660ad4726fb4f086e0
Author: triesap <tyson@radroots.org>
Date: Sun, 13 Sep 2026 15:48:59 +0000
publication: qualify durable signing preparation
- Verify exact preimages and signer bindings before callbacks
- Prove SQLite writes remain available during suspended signing
- Preserve reserved identity across denial lock and restart recovery
- Regenerate provenance and verify standalone native consumers
Diffstat:
10 files changed, 344 insertions(+), 48 deletions(-)
diff --git a/TeraFFI/provenance.json b/TeraFFI/provenance.json
@@ -92,19 +92,19 @@
"sha256": "7fbf82a5f8eb2117ef95fc6354eb267c306c66419883ea57d756f0979362ab06"
},
{
- "bytes": 93630,
+ "bytes": 93938,
"path": "source/aarch64-apple-darwin.json",
- "sha256": "6dab65c86e208238359c15eed8ebd012fe0baba0f57ac3474bc72136da028903"
+ "sha256": "f6e0b65ea1dc8dc7767c71671078bd4eaba364b1a8f22815468ebdda58baafce"
},
{
- "bytes": 93474,
+ "bytes": 93782,
"path": "source/aarch64-apple-ios-sim.json",
- "sha256": "c1161a538eca24768b9a2bf478a4770dcebecf4145a3cfb132349a3f99aa7d8f"
+ "sha256": "241534777c5ba0b4b2146966b0aeee06de009542ed9941fdf6dbf09340a0b9a8"
},
{
- "bytes": 93470,
+ "bytes": 93778,
"path": "source/aarch64-apple-ios.json",
- "sha256": "0540e662f1a1e1a093c003059a7e5c4d858aadd6133e1b263b289557ca330e3a"
+ "sha256": "2ecaa6943e11241ad646751f814760451825c777abde9d634264a5143923f87e"
}
],
"language": "swift",
@@ -112,7 +112,7 @@
"schema": "radroots.artifact-manifest.v2",
"source": {
"repository": "https://github.com/radrootslabs/tera",
- "tree": "b7c0e8adcd745dc848f8ab8f5f55da12e49e2384"
+ "tree": "b3f79cda46bad95581c429bf99ba63555c782cd5"
},
"source_records": {
"aarch64-apple-darwin": "source/aarch64-apple-darwin.json",
@@ -174,19 +174,19 @@
"sha256": "79c86a44fd77c30b5b55d209cf356d01e6c4b60fe6d1f8aa33cccc5029a58aa4"
},
{
- "bytes": 93630,
+ "bytes": 93938,
"path": "TeraFFI/source/aarch64-apple-darwin.json",
- "sha256": "6dab65c86e208238359c15eed8ebd012fe0baba0f57ac3474bc72136da028903"
+ "sha256": "f6e0b65ea1dc8dc7767c71671078bd4eaba364b1a8f22815468ebdda58baafce"
},
{
- "bytes": 93474,
+ "bytes": 93782,
"path": "TeraFFI/source/aarch64-apple-ios-sim.json",
- "sha256": "c1161a538eca24768b9a2bf478a4770dcebecf4145a3cfb132349a3f99aa7d8f"
+ "sha256": "241534777c5ba0b4b2146966b0aeee06de009542ed9941fdf6dbf09340a0b9a8"
},
{
- "bytes": 93470,
+ "bytes": 93778,
"path": "TeraFFI/source/aarch64-apple-ios.json",
- "sha256": "0540e662f1a1e1a093c003059a7e5c4d858aadd6133e1b263b289557ca330e3a"
+ "sha256": "2ecaa6943e11241ad646751f814760451825c777abde9d634264a5143923f87e"
}
],
"schema": "tera.installed-native-artifacts.v1"
diff --git a/TeraFFI/source.lock b/TeraFFI/source.lock
@@ -1,7 +1,7 @@
schema = "tera.installed-source.v1"
repository = "https://github.com/radrootslabs/tera"
-source_tree = "b7c0e8adcd745dc848f8ab8f5f55da12e49e2384"
-manifest_sha256 = "6fc6194a31471995521cf2f6d4b47e0e3d966b99fdf54fc696ce131a0b2beaab"
+source_tree = "b3f79cda46bad95581c429bf99ba63555c782cd5"
+manifest_sha256 = "c0c31f9335fdcbe6e6d4bb68fa3f82e9d8f8e1966b0f2db651dec666ea4d1667"
source_date_epoch = 1787871027
[foundation]
diff --git a/TeraFFI/source/aarch64-apple-darwin.json b/TeraFFI/source/aarch64-apple-darwin.json
@@ -861,10 +861,10 @@
"sha256": "76e3bddfc237dac63293d264d68991b489585136fe377e39dbba72aa3a1181f4"
},
"core/crates/tera_core/src/runtime/product_surface/submission.rs": {
- "bytes": 5744,
- "git_blob": "388bc937587f9a7f4c2ea4f33ca2b050a3f5dc2d",
+ "bytes": 5788,
+ "git_blob": "34a2c45d8ccd63504fd018f866d31c9c5d7aad74",
"mode": "100644",
- "sha256": "fde343558bab6cca019fd59e09ab693746e6ee721a371d30665f08a486d61b15"
+ "sha256": "43b9e796aa3c954961c714af9b9a397f1bf66b3ef92b14ab67cc432627c32dd7"
},
"core/crates/tera_core/src/runtime/product_surface/submission/atomic_fault_store.rs": {
"bytes": 3189,
@@ -1011,10 +1011,10 @@
"sha256": "34053a01079a939b54615f9c39e9f97314f9741bb1ff70fd309257c24ba00acc"
},
"core/crates/tera_core/src/runtime/product_surface/submission/operation_test_support.rs": {
- "bytes": 6425,
- "git_blob": "b035c31234de26dd50a9533b1103ff7caf501b24",
+ "bytes": 6891,
+ "git_blob": "6a0a792fc2dec4ae04f83ab818024275db55e8e6",
"mode": "100644",
- "sha256": "83ec90cbadc617260a9b23e492e2a6fabfbe789eee12a4f237c9390ed9767c4d"
+ "sha256": "ba8e0fd8b4c85437d89049c3652ce2ba8f05771c114c91a8c4c638bf59aa7ce6"
},
"core/crates/tera_core/src/runtime/product_surface/submission/operation_tests.rs": {
"bytes": 10339,
@@ -1046,6 +1046,12 @@
"mode": "100644",
"sha256": "5d05ddf11b0ce9040f9221b7158a50374e4df6c344ce23faa1e14ce2d6c91122"
},
+ "core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs": {
+ "bytes": 9603,
+ "git_blob": "edebc427e882cbacb50419de84ebbebe772af990",
+ "mode": "100644",
+ "sha256": "202c93a99d2132ae72b0333a5b3f32e65ce84205537d51f3ba4b872ea5dfd7de"
+ },
"core/crates/tera_core/src/runtime/product_surface/submission/sqlite_tests.rs": {
"bytes": 5247,
"git_blob": "fb83a8fd521dce82d91bf1269682fb5731283013",
@@ -2001,13 +2007,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 134234,
- "git_blob": "d87127249e1943580e522e8c70769062fcc91ad3",
+ "bytes": 134540,
+ "git_blob": "65653d77a42b56e472da03e38dbc76f568a84340",
"mode": "100644",
- "sha256": "dfe64e685cae9a5fec5cb311a590b10415d570a406296dca5fc3998cce9372b5"
+ "sha256": "0a5f18d3ce7fcdec536dd72504b1e1556d9458d8e215bb54bfd888ad582d7e8c"
}
},
"policy": "staged_inputs",
- "tree": "b7c0e8adcd745dc848f8ab8f5f55da12e49e2384"
+ "tree": "b3f79cda46bad95581c429bf99ba63555c782cd5"
}
}
diff --git a/TeraFFI/source/aarch64-apple-ios-sim.json b/TeraFFI/source/aarch64-apple-ios-sim.json
@@ -857,10 +857,10 @@
"sha256": "76e3bddfc237dac63293d264d68991b489585136fe377e39dbba72aa3a1181f4"
},
"core/crates/tera_core/src/runtime/product_surface/submission.rs": {
- "bytes": 5744,
- "git_blob": "388bc937587f9a7f4c2ea4f33ca2b050a3f5dc2d",
+ "bytes": 5788,
+ "git_blob": "34a2c45d8ccd63504fd018f866d31c9c5d7aad74",
"mode": "100644",
- "sha256": "fde343558bab6cca019fd59e09ab693746e6ee721a371d30665f08a486d61b15"
+ "sha256": "43b9e796aa3c954961c714af9b9a397f1bf66b3ef92b14ab67cc432627c32dd7"
},
"core/crates/tera_core/src/runtime/product_surface/submission/atomic_fault_store.rs": {
"bytes": 3189,
@@ -1007,10 +1007,10 @@
"sha256": "34053a01079a939b54615f9c39e9f97314f9741bb1ff70fd309257c24ba00acc"
},
"core/crates/tera_core/src/runtime/product_surface/submission/operation_test_support.rs": {
- "bytes": 6425,
- "git_blob": "b035c31234de26dd50a9533b1103ff7caf501b24",
+ "bytes": 6891,
+ "git_blob": "6a0a792fc2dec4ae04f83ab818024275db55e8e6",
"mode": "100644",
- "sha256": "83ec90cbadc617260a9b23e492e2a6fabfbe789eee12a4f237c9390ed9767c4d"
+ "sha256": "ba8e0fd8b4c85437d89049c3652ce2ba8f05771c114c91a8c4c638bf59aa7ce6"
},
"core/crates/tera_core/src/runtime/product_surface/submission/operation_tests.rs": {
"bytes": 10339,
@@ -1042,6 +1042,12 @@
"mode": "100644",
"sha256": "5d05ddf11b0ce9040f9221b7158a50374e4df6c344ce23faa1e14ce2d6c91122"
},
+ "core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs": {
+ "bytes": 9603,
+ "git_blob": "edebc427e882cbacb50419de84ebbebe772af990",
+ "mode": "100644",
+ "sha256": "202c93a99d2132ae72b0333a5b3f32e65ce84205537d51f3ba4b872ea5dfd7de"
+ },
"core/crates/tera_core/src/runtime/product_surface/submission/sqlite_tests.rs": {
"bytes": 5247,
"git_blob": "fb83a8fd521dce82d91bf1269682fb5731283013",
@@ -1997,13 +2003,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 134234,
- "git_blob": "d87127249e1943580e522e8c70769062fcc91ad3",
+ "bytes": 134540,
+ "git_blob": "65653d77a42b56e472da03e38dbc76f568a84340",
"mode": "100644",
- "sha256": "dfe64e685cae9a5fec5cb311a590b10415d570a406296dca5fc3998cce9372b5"
+ "sha256": "0a5f18d3ce7fcdec536dd72504b1e1556d9458d8e215bb54bfd888ad582d7e8c"
}
},
"policy": "staged_inputs",
- "tree": "b7c0e8adcd745dc848f8ab8f5f55da12e49e2384"
+ "tree": "b3f79cda46bad95581c429bf99ba63555c782cd5"
}
}
diff --git a/TeraFFI/source/aarch64-apple-ios.json b/TeraFFI/source/aarch64-apple-ios.json
@@ -857,10 +857,10 @@
"sha256": "76e3bddfc237dac63293d264d68991b489585136fe377e39dbba72aa3a1181f4"
},
"core/crates/tera_core/src/runtime/product_surface/submission.rs": {
- "bytes": 5744,
- "git_blob": "388bc937587f9a7f4c2ea4f33ca2b050a3f5dc2d",
+ "bytes": 5788,
+ "git_blob": "34a2c45d8ccd63504fd018f866d31c9c5d7aad74",
"mode": "100644",
- "sha256": "fde343558bab6cca019fd59e09ab693746e6ee721a371d30665f08a486d61b15"
+ "sha256": "43b9e796aa3c954961c714af9b9a397f1bf66b3ef92b14ab67cc432627c32dd7"
},
"core/crates/tera_core/src/runtime/product_surface/submission/atomic_fault_store.rs": {
"bytes": 3189,
@@ -1007,10 +1007,10 @@
"sha256": "34053a01079a939b54615f9c39e9f97314f9741bb1ff70fd309257c24ba00acc"
},
"core/crates/tera_core/src/runtime/product_surface/submission/operation_test_support.rs": {
- "bytes": 6425,
- "git_blob": "b035c31234de26dd50a9533b1103ff7caf501b24",
+ "bytes": 6891,
+ "git_blob": "6a0a792fc2dec4ae04f83ab818024275db55e8e6",
"mode": "100644",
- "sha256": "83ec90cbadc617260a9b23e492e2a6fabfbe789eee12a4f237c9390ed9767c4d"
+ "sha256": "ba8e0fd8b4c85437d89049c3652ce2ba8f05771c114c91a8c4c638bf59aa7ce6"
},
"core/crates/tera_core/src/runtime/product_surface/submission/operation_tests.rs": {
"bytes": 10339,
@@ -1042,6 +1042,12 @@
"mode": "100644",
"sha256": "5d05ddf11b0ce9040f9221b7158a50374e4df6c344ce23faa1e14ce2d6c91122"
},
+ "core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs": {
+ "bytes": 9603,
+ "git_blob": "edebc427e882cbacb50419de84ebbebe772af990",
+ "mode": "100644",
+ "sha256": "202c93a99d2132ae72b0333a5b3f32e65ce84205537d51f3ba4b872ea5dfd7de"
+ },
"core/crates/tera_core/src/runtime/product_surface/submission/sqlite_tests.rs": {
"bytes": 5247,
"git_blob": "fb83a8fd521dce82d91bf1269682fb5731283013",
@@ -1997,13 +2003,13 @@
"sha256": "b052a73a824e8f8b26af2646a4758f13655e04de9551a8271890d3cf2b63209d"
},
"test-fixtures/legacy-identifiers.v1.json": {
- "bytes": 134234,
- "git_blob": "d87127249e1943580e522e8c70769062fcc91ad3",
+ "bytes": 134540,
+ "git_blob": "65653d77a42b56e472da03e38dbc76f568a84340",
"mode": "100644",
- "sha256": "dfe64e685cae9a5fec5cb311a590b10415d570a406296dca5fc3998cce9372b5"
+ "sha256": "0a5f18d3ce7fcdec536dd72504b1e1556d9458d8e215bb54bfd888ad582d7e8c"
}
},
"policy": "staged_inputs",
- "tree": "b7c0e8adcd745dc848f8ab8f5f55da12e49e2384"
+ "tree": "b3f79cda46bad95581c429bf99ba63555c782cd5"
}
}
diff --git a/core/crates/tera_core/src/runtime/product_surface/submission.rs b/core/crates/tera_core/src/runtime/product_surface/submission.rs
@@ -38,6 +38,8 @@ mod operation_test_support;
#[cfg(test)]
mod operation_tests;
#[cfg(test)]
+mod signing_preparation_tests;
+#[cfg(test)]
mod test_support;
#[cfg(test)]
mod transaction_test_support;
diff --git a/core/crates/tera_core/src/runtime/product_surface/submission/operation_test_support.rs b/core/crates/tera_core/src/runtime/product_surface/submission/operation_test_support.rs
@@ -29,6 +29,8 @@ pub(super) struct CountingSigner {
pub calls: AtomicUsize,
pub statuses: AtomicUsize,
pub kinds: std::sync::Mutex<Vec<u32>>,
+ pub requests: std::sync::Mutex<Vec<radroots_signing::SignRequest>>,
+ pub failure: std::sync::Mutex<Option<radroots_signing::error::Kind>>,
pub pause: AtomicBool,
pub entered: Notify,
pub resume: Notify,
@@ -47,6 +49,8 @@ impl CountingSigner {
calls: AtomicUsize::new(0),
statuses: AtomicUsize::new(0),
kinds: std::sync::Mutex::new(Vec::new()),
+ requests: std::sync::Mutex::new(Vec::new()),
+ failure: std::sync::Mutex::new(None),
pause: AtomicBool::new(false),
entered: Notify::new(),
resume: Notify::new(),
@@ -71,10 +75,14 @@ impl Signer for CountingSigner {
Box::pin(async move {
self.calls.fetch_add(1, Ordering::SeqCst);
self.kinds.lock().unwrap().push(request.kind());
+ self.requests.lock().unwrap().push(request.clone());
if self.pause.swap(false, Ordering::SeqCst) {
self.entered.notify_one();
self.resume.notified().await;
}
+ if let Some(kind) = self.failure.lock().unwrap().take() {
+ return Err(radroots_signing::Error::new(kind));
+ }
self.inner.sign(request).await
})
}
diff --git a/core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs b/core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs
@@ -0,0 +1,260 @@
+//! Qualify the application consumer of the shared durable signing owner.
+
+use std::{sync::atomic::Ordering, time::Duration};
+
+use radroots_signing::{SignRequest, error::Kind};
+use radroots_storage::authored::SigningState;
+
+use super::{operation_test_support::*, test_support::*, *};
+use crate::runtime::product_surface::{AddCommandType, ComposerEditSequence, ComposerPartialForm};
+
+fn assert_frozen(request: &SignRequest, status: &SubmissionOperationStatus) {
+ let artifact = status.push().artifact();
+ let persisted = artifact.plan().unwrap().decode().unwrap().into_plan();
+ assert_eq!(request.authored_plan(), Some(&persisted));
+ assert_eq!(
+ *request.expected_author(),
+ status.receipt().request().scope().author()
+ );
+ assert_eq!(request.expected_event_id(), persisted.expected_event_id());
+ assert_eq!(
+ request.created_at(),
+ status.receipt().captured_at_unix_ms() / 1000
+ );
+ assert_eq!(
+ request.intent_id().operation_id().as_bytes(),
+ status.receipt().operation_id().as_bytes()
+ );
+ assert_eq!(
+ request.intent_id().artifact_id().as_bytes(),
+ artifact.artifact_id().as_bytes()
+ );
+}
+
+#[tokio::test]
+async fn signing_preparation_sqlite_is_committed_and_unlocked_before_callback() {
+ let root = tempfile::tempdir().unwrap();
+ let signer = CountingSigner::new();
+ signer.pause.store(true, Ordering::SeqCst);
+ let runtime = runtime(Some(root.path()), signer.clone(), "ws://127.0.0.1:19999").await;
+ let request = request();
+ prepare(&runtime, &request, false).await;
+ let original = runtime.submission_operation_status(&request).await.unwrap();
+ assert_eq!(signer.count(), 0);
+ let task = {
+ let runtime = runtime.clone();
+ let request = request.clone();
+ tokio::spawn(async move { runtime.submission_advance(&request, 1).await })
+ };
+ tokio::time::timeout(Duration::from_secs(5), signer.entered.notified())
+ .await
+ .unwrap();
+ let waiting = tokio::time::timeout(
+ Duration::from_secs(5),
+ runtime.submission_operation_status(&request),
+ )
+ .await
+ .unwrap()
+ .unwrap();
+ let callback = signer.requests.lock().unwrap()[0].clone();
+ assert_frozen(&callback, &waiting);
+ assert_eq!(
+ waiting.push().artifact().plan(),
+ original.push().artifact().plan()
+ );
+ assert!(waiting.push().artifact().signing_claim().is_some());
+ assert!(waiting.push().artifact().signed().is_none());
+ assert!(waiting.push().delivery_plan().attempts().is_empty());
+ // A real write on the same SQLite owner must finish while the signer remains suspended.
+ let later = tokio::time::timeout(
+ Duration::from_secs(5),
+ runtime.composer_save(
+ request.scope(),
+ request.composer_id(),
+ request.expected_revision(),
+ ComposerEditSequence::new(2).unwrap(),
+ ComposerPartialForm::new(input(AddCommandType::CreateAsk)).unwrap(),
+ ),
+ )
+ .await
+ .unwrap()
+ .unwrap();
+ task.abort();
+ assert!(task.await.unwrap_err().is_cancelled());
+ runtime.shutdown().await.unwrap();
+ drop(runtime);
+ let reopened = self::runtime(Some(root.path()), signer.clone(), "ws://127.0.0.1:19998").await;
+ let recovered = reopened
+ .submission_operation_status(&request)
+ .await
+ .unwrap();
+ assert_eq!(recovered, waiting);
+ assert_frozen(&callback, &recovered);
+ assert_eq!(
+ reopened
+ .composer_load(request.scope(), request.composer_id())
+ .await
+ .unwrap(),
+ *later.draft()
+ );
+ assert_eq!(signer.count(), 1);
+ reopened.shutdown().await.unwrap();
+}
+
+#[tokio::test]
+async fn signing_preparation_lock_and_denial_preserve_exact_request_across_restart() {
+ for failure in [
+ Kind::SignerUnavailable,
+ Kind::AuthorizationDenied,
+ Kind::SignerRejected,
+ ] {
+ let root = tempfile::tempdir().unwrap();
+ let signer = CountingSigner::new();
+ signer.pause.store(true, Ordering::SeqCst);
+ let runtime = runtime(Some(root.path()), signer.clone(), "ws://127.0.0.1:19999").await;
+ let request = request();
+ prepare(&runtime, &request, false).await;
+ let before = runtime.submission_operation_status(&request).await.unwrap();
+ let task = {
+ let runtime = runtime.clone();
+ let request = request.clone();
+ tokio::spawn(async move { runtime.submission_advance(&request, 1).await })
+ };
+ tokio::time::timeout(Duration::from_secs(5), signer.entered.notified())
+ .await
+ .unwrap();
+ // Model a lock/denial after status was ready and the durable claim was installed.
+ *signer.failure.lock().unwrap() = Some(failure);
+ signer.resume.notify_one();
+ assert!(task.await.unwrap().is_err());
+ let failed = runtime.submission_operation_status(&request).await.unwrap();
+ let callback = signer.requests.lock().unwrap()[0].clone();
+ assert_frozen(&callback, &failed);
+ assert_eq!(
+ failed.push().artifact().plan(),
+ before.push().artifact().plan()
+ );
+ assert!(failed.push().artifact().signed().is_none());
+ assert!(failed.push().delivery_plan().attempts().is_empty());
+ runtime.shutdown().await.unwrap();
+ drop(runtime);
+ let reopened =
+ self::runtime(Some(root.path()), signer.clone(), "ws://127.0.0.1:19998").await;
+ let recovered = reopened
+ .submission_operation_status(&request)
+ .await
+ .unwrap();
+ assert_eq!(recovered, failed);
+ assert_frozen(&callback, &recovered);
+ assert!(
+ reopened
+ .submission_prepare(&request, vec![])
+ .await
+ .unwrap()
+ .is_replay()
+ );
+ if failure == Kind::SignerUnavailable {
+ assert_eq!(
+ recovered.push().artifact().signing_state(),
+ SigningState::Retryable
+ );
+ tokio::time::sleep(Duration::from_millis(1100)).await;
+ let (loaded, _) = reopened.load_submission_operation(&request).await.unwrap();
+ reopened
+ .sync()
+ .unwrap()
+ .sign_prepared(loaded.request)
+ .await
+ .unwrap();
+ let retried = signer.requests.lock().unwrap()[1].clone();
+ assert_frozen(&retried, &recovered);
+ assert_eq!(retried.signer_request_id(), callback.signer_request_id());
+ assert_eq!(retried.intent_id(), callback.intent_id());
+ let signed = reopened
+ .submission_operation_status(&request)
+ .await
+ .unwrap();
+ assert_eq!(
+ signed.push().artifact().signing_state(),
+ SigningState::Signed
+ );
+ assert!(signed.push().delivery_plan().attempts().is_empty());
+ assert_eq!(signer.count(), 2);
+ } else {
+ assert_eq!(
+ recovered.push().artifact().signing_state(),
+ SigningState::FailedTerminal
+ );
+ let after = reopened
+ .submission_advance(&request, recovered.intent().revision().get())
+ .await
+ .unwrap();
+ assert_eq!(after, recovered);
+ assert_eq!(signer.count(), 1);
+ }
+ reopened.shutdown().await.unwrap();
+ }
+}
+
+#[tokio::test]
+async fn signing_preparation_restart_before_commit_retains_reserved_time_and_author() {
+ let root = tempfile::tempdir().unwrap();
+ let signer = CountingSigner::new();
+ let runtime = runtime(Some(root.path()), signer.clone(), "ws://127.0.0.1:19999").await;
+ let request = request();
+ runtime
+ .composer_create(
+ request.scope(),
+ request.composer_id(),
+ ComposerEditSequence::INITIAL,
+ ComposerPartialForm::new(input(AddCommandType::CreateUpdate)).unwrap(),
+ )
+ .await
+ .unwrap();
+ let captured = runtime.submission_capture(&request, vec![]).await.unwrap();
+ let plan = captured.plan().clone();
+ assert!(
+ runtime
+ .submission_recover(&request)
+ .await
+ .unwrap()
+ .is_none()
+ );
+ assert_eq!(signer.count(), 0);
+ runtime.shutdown().await.unwrap();
+ drop(runtime);
+ let reopened = self::runtime(Some(root.path()), signer.clone(), "ws://127.0.0.1:19999").await;
+ assert!(
+ reopened
+ .submission_recover(&request)
+ .await
+ .unwrap()
+ .is_none()
+ );
+ let recaptured = reopened.submission_capture(&request, vec![]).await.unwrap();
+ assert_eq!(recaptured.plan(), &plan);
+ let committed = reopened.submission_commit(&recaptured).await.unwrap();
+ let status = reopened
+ .submission_operation_status(&request)
+ .await
+ .unwrap();
+ assert_eq!(
+ status
+ .push()
+ .artifact()
+ .plan()
+ .unwrap()
+ .decode()
+ .unwrap()
+ .into_plan(),
+ plan
+ );
+ assert_eq!(
+ committed.captured_at_unix_ms(),
+ captured.reservation().reserved_at_unix_ms()
+ );
+ assert_eq!(signer.count(), 0);
+ assert!(status.push().artifact().signing_claim().is_none());
+ assert!(status.push().delivery_plan().attempts().is_empty());
+ reopened.shutdown().await.unwrap();
+}
diff --git a/release/provenance.json b/release/provenance.json
@@ -2,7 +2,7 @@
"artifacts": {
"app_api_sha256": "020924097c0d7efc33128cb8fd3d3b2026d95f57c44da71880e585aff80f070b",
"ffi_api_sha256": "79c86a44fd77c30b5b55d209cf356d01e6c4b60fe6d1f8aa33cccc5029a58aa4",
- "ffi_provenance_sha256": "6fc6194a31471995521cf2f6d4b47e0e3d966b99fdf54fc696ce131a0b2beaab",
+ "ffi_provenance_sha256": "c0c31f9335fdcbe6e6d4bb68fa3f82e9d8f8e1966b0f2db651dec666ea4d1667",
"info_plist_sha256": "15ef08b1cdd1096cfb9eeaf5be5bf8f814807a7ca9350bbbb47860fa72ec13ef",
"privacy_manifest_sha256": "a331d51864743ebe4e00dd22360b4a538b6b3ac26a6b3eb54094e60a36959a12",
"sbom_sha256": "97f830c291d866596afa339171e4f83c5e7b1dc04451e6d87eac1cfb4bfb33ea",
@@ -22,7 +22,7 @@
"lib_revision": "041d7ba7b732ed8f8c1da869172297771435d5ff",
"source_date_epoch": 1787871027,
"swift_package_lock_sha256": "9b831ccdd3a6c697d142f1e865913eeed9553cb2dc97b492b229771c7669571f",
- "tera_ffi_source_tree": "b7c0e8adcd745dc848f8ab8f5f55da12e49e2384",
+ "tera_ffi_source_tree": "b3f79cda46bad95581c429bf99ba63555c782cd5",
"xcode_package_lock_sha256": "1a703864d2eb2f4fcb23e78c8552cfe93036af255de866e49756fa59381e730c"
},
"version": "0.1.0-alpha"
diff --git a/test-fixtures/legacy-identifiers.v1.json b/test-fixtures/legacy-identifiers.v1.json
@@ -4776,7 +4776,11 @@
},
{
"path": "core/crates/tera_core/src/runtime/product_surface/submission/operation_test_support.rs",
- "count": 6
+ "count": 9
+ },
+ {
+ "path": "core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs",
+ "count": 1
},
{
"path": "core/crates/tera_ffi/Cargo.toml",
@@ -4937,6 +4941,10 @@
"count": 1
},
{
+ "path": "core/crates/tera_core/src/runtime/product_surface/submission/signing_preparation_tests.rs",
+ "count": 1
+ },
+ {
"path": "core/crates/tera_core/src/runtime/product_surface/submission/transaction_test_support.rs",
"count": 1
},