Fail closed before Domain Store mutations

This commit is contained in:
ms2k 2026-07-19 04:26:35 +09:00
commit bfe21dfb3f
2 changed files with 45 additions and 10 deletions

View file

@ -266,7 +266,7 @@ impl HostCoordinatorDomainStore {
if mutations.is_empty() {
return Ok(());
}
self.validate_metadata()?;
self.validate_document()?;
let write = self.database.begin_write()?;
for mutation in mutations {
apply_row_mutation(&write, mutation)?;
@ -305,7 +305,7 @@ impl HostCoordinatorDomainStore {
/// Refuses an invalid, foreign, or already-present intent.
pub fn begin_state_reset(&self, intent: &StateResetIntentV1) -> Result<(), DomainStoreError> {
intent.validate()?;
self.validate_metadata()?;
self.validate_document()?;
let write = self.database.begin_write()?;
require_transaction_domain(&write, intent.domain_id)?;
{
@ -329,7 +329,7 @@ impl HostCoordinatorDomainStore {
expected: &StateResetIntentV1,
) -> Result<(), DomainStoreError> {
expected.validate()?;
self.validate_metadata()?;
self.validate_document()?;
let write = self.database.begin_write()?;
require_transaction_domain(&write, expected.domain_id)?;
{
@ -370,6 +370,10 @@ impl HostCoordinatorDomainStore {
Ok(())
}
fn validate_document(&self) -> Result<(), DomainStoreError> {
self.snapshot().map(|_| ())
}
fn write_snapshot(&self, snapshot: &DomainStore) -> Result<(), DomainStoreError> {
let write = self.database.begin_write()?;
{

View file

@ -87,6 +87,17 @@ fn mailbox(state: ParticipantState) -> Mailbox {
}
}
fn mailbox_row_bytes(store: &HostCoordinatorDomainStore) -> Vec<u8> {
let read = store.database.begin_read().unwrap();
let table = read.open_table(MAILBOXES).unwrap();
table
.get(generation(DurableDecision::None).generation_id.get())
.unwrap()
.unwrap()
.value()
.to_vec()
}
fn bare_terminal(state: SessionTerminalState) -> SessionTerminal {
SessionTerminal::snapshot(SessionTerminalFields {
generation_id: GenerationId::new(7),
@ -250,8 +261,8 @@ fn row_local_mutations_match_the_snapshot_reference_engine() {
}
#[test]
fn row_local_mutation_does_not_rewrite_an_unrelated_invalid_row() {
let directory = TestDirectory::new("unrelated-row");
fn row_local_mutation_refuses_an_unrelated_invalid_row() {
let directory = TestDirectory::new("invalid-unrelated-row");
let store = open_store(&directory);
store
.apply(&[DomainStoreMutation::PutGeneration(generation(
@ -266,11 +277,10 @@ fn row_local_mutation_does_not_rewrite_an_unrelated_invalid_row() {
}
write.commit().unwrap();
store
.apply(&[DomainStoreMutation::PutGeneration(generation(
DurableDecision::Preparing,
))])
.unwrap();
let result = store.apply(&[DomainStoreMutation::PutGeneration(generation(
DurableDecision::Preparing,
))]);
assert!(matches!(result, Err(DomainStoreError::Codec(_))));
let read = store.database.begin_read().unwrap();
let table = read.open_table(MAILBOXES).unwrap();
@ -280,6 +290,27 @@ fn row_local_mutation_does_not_rewrite_an_unrelated_invalid_row() {
assert!(matches!(store.snapshot(), Err(DomainStoreError::Codec(_))));
}
#[test]
fn row_local_mutation_preserves_an_unrelated_valid_row_byte_for_byte() {
let directory = TestDirectory::new("valid-unrelated-row");
let store = open_store(&directory);
store
.apply(&[
DomainStoreMutation::PutGeneration(generation(DurableDecision::None)),
DomainStoreMutation::PutMailbox(mailbox(ParticipantState::Intent)),
])
.unwrap();
let before = mailbox_row_bytes(&store);
store
.apply(&[DomainStoreMutation::PutGeneration(generation(
DurableDecision::Preparing,
))])
.unwrap();
assert_eq!(mailbox_row_bytes(&store), before);
}
#[test]
fn reset_intent_is_typed_transactional_and_domain_bound() {
let directory = TestDirectory::new("state-reset");