Skip to content

Commit 92c8c4c

Browse files
committed
fix: propagate errors
1 parent 262248d commit 92c8c4c

1 file changed

Lines changed: 64 additions & 34 deletions

File tree

crates/dry_run_core/src/history/filesystem_store.rs

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::Arc;
55
use async_trait::async_trait;
66
use chrono::{DateTime, Utc};
77
use serde::{Deserialize, Serialize};
8+
use sha2::{Digest, Sha256};
89
use tracing::{debug, info};
910

1011
use crate::error::{Error, Result};
@@ -191,11 +192,13 @@ fn get_kind(
191192
Ok(StoredSnapshot::Schema(bundle.schema))
192193
}
193194
SnapshotKind::Planner => {
194-
let mut bundles: Vec<(DateTime<Utc>, Bundle)> = entries
195-
.into_iter()
196-
.filter_map(|(ts, _, p)| read_bundle(&p).ok().map(|b| (ts, b)))
197-
.filter(|(_, b)| b.planner.is_some())
198-
.collect();
195+
let mut bundles: Vec<(DateTime<Utc>, Bundle)> = Vec::new();
196+
for (ts, _, p) in entries {
197+
let b = read_bundle(&p)?;
198+
if b.planner.is_some() {
199+
bundles.push((ts, b));
200+
}
201+
}
199202
bundles.sort_by_key(|(ts, _)| std::cmp::Reverse(*ts));
200203
let chosen = match &at {
201204
SnapshotRef::Latest => bundles.into_iter().next(),
@@ -208,11 +211,13 @@ fn get_kind(
208211
Ok(StoredSnapshot::Planner(bundle.planner.expect("filtered")))
209212
}
210213
SnapshotKind::Activity { node_label } => {
211-
let mut bundles: Vec<(DateTime<Utc>, Bundle)> = entries
212-
.into_iter()
213-
.filter_map(|(ts, _, p)| read_bundle(&p).ok().map(|b| (ts, b)))
214-
.filter(|(_, b)| b.activity.contains_key(node_label))
215-
.collect();
214+
let mut bundles: Vec<(DateTime<Utc>, Bundle)> = Vec::new();
215+
for (ts, _, p) in entries {
216+
let b = read_bundle(&p)?;
217+
if b.activity.contains_key(node_label) {
218+
bundles.push((ts, b));
219+
}
220+
}
216221
bundles.sort_by_key(|(ts, _)| std::cmp::Reverse(*ts));
217222
let chosen = match &at {
218223
SnapshotRef::Latest => bundles.into_iter().next(),
@@ -239,10 +244,7 @@ fn list_kind(
239244

240245
let mut out: Vec<SnapshotSummary> = Vec::new();
241246
for (_schema_ts, _schema_hash, path) in entries {
242-
let bundle = match read_bundle(&path) {
243-
Ok(b) => b,
244-
Err(_) => continue,
245-
};
247+
let bundle = read_bundle(&path)?;
246248
if let Some(s) = bundle_summary_for_kind(&bundle, key, kind) {
247249
if range.from.is_none_or(|f| s.timestamp >= f)
248250
&& range.to.is_none_or(|t| s.timestamp < t)
@@ -268,10 +270,7 @@ fn delete_before(
268270
match kind {
269271
SnapshotKind::Schema => {
270272
for (_ts, _h, path) in entries {
271-
let bundle = match read_bundle(&path) {
272-
Ok(b) => b,
273-
Err(_) => continue,
274-
};
273+
let bundle = read_bundle(&path)?;
275274
if bundle.schema.timestamp < cutoff {
276275
std::fs::remove_file(&path)
277276
.map_err(|e| Error::History(format!("remove {}: {e}", path.display())))?;
@@ -281,10 +280,7 @@ fn delete_before(
281280
}
282281
SnapshotKind::Planner => {
283282
for (_ts, _h, path) in entries {
284-
let mut bundle = match read_bundle(&path) {
285-
Ok(b) => b,
286-
Err(_) => continue,
287-
};
283+
let mut bundle = read_bundle(&path)?;
288284
let drop = bundle
289285
.planner
290286
.as_ref()
@@ -298,10 +294,7 @@ fn delete_before(
298294
}
299295
SnapshotKind::Activity { node_label } => {
300296
for (_ts, _h, path) in entries {
301-
let mut bundle = match read_bundle(&path) {
302-
Ok(b) => b,
303-
Err(_) => continue,
304-
};
297+
let mut bundle = read_bundle(&path)?;
305298
let drop = bundle
306299
.activity
307300
.get(node_label)
@@ -329,10 +322,7 @@ fn list_kinds_sync(root: &Path, key: &SnapshotKey) -> Result<Vec<SnapshotKind>>
329322
let mut activity_labels: std::collections::BTreeSet<String> = Default::default();
330323

331324
for (_ts, _h, path) in entries {
332-
let bundle = match read_bundle(&path) {
333-
Ok(b) => b,
334-
Err(_) => continue,
335-
};
325+
let bundle = read_bundle(&path)?;
336326
has_schema = true;
337327
if bundle.planner.is_some() {
338328
has_planner = true;
@@ -403,10 +393,7 @@ fn bundle_summary_for_kind(
403393

404394
fn find_bundle_by_schema_hash(dir: &Path, schema_hash: &str) -> Result<Option<(PathBuf, Bundle)>> {
405395
for (_, _, path) in read_stream_entries(dir)? {
406-
let bundle = match read_bundle(&path) {
407-
Ok(b) => b,
408-
Err(_) => continue,
409-
};
396+
let bundle = read_bundle(&path)?;
410397
if bundle.schema.content_hash == schema_hash {
411398
return Ok(Some((path, bundle)));
412399
}
@@ -455,6 +442,10 @@ fn verify_bundle_hash(path: &Path, bundle: &Bundle) -> Result<()> {
455442
))
456443
})?;
457444

445+
if !is_sha256_hex(&expected) {
446+
return Ok(());
447+
}
448+
458449
if bundle.schema.content_hash != expected {
459450
return Err(Error::History(format!(
460451
"corrupt snapshot {}: filename hash {} != stored schema.content_hash {}",
@@ -482,9 +473,48 @@ fn verify_bundle_hash(path: &Path, bundle: &Bundle) -> Result<()> {
482473
recomputed,
483474
)));
484475
}
476+
477+
if let Some(planner) = &bundle.planner {
478+
let mut p = planner.clone();
479+
p.content_hash = String::new();
480+
let recomputed = sha256_hex_of_serialized(&p)?;
481+
if recomputed != planner.content_hash {
482+
return Err(Error::History(format!(
483+
"corrupt snapshot {}: planner content_hash {} != recomputed {}",
484+
path.display(),
485+
planner.content_hash,
486+
recomputed,
487+
)));
488+
}
489+
}
490+
491+
for (label, activity) in &bundle.activity {
492+
let mut a = activity.clone();
493+
a.content_hash = String::new();
494+
let recomputed = sha256_hex_of_serialized(&a)?;
495+
if recomputed != activity.content_hash {
496+
return Err(Error::History(format!(
497+
"corrupt snapshot {}: activity[{}] content_hash {} != recomputed {}",
498+
path.display(),
499+
label,
500+
activity.content_hash,
501+
recomputed,
502+
)));
503+
}
504+
}
485505
Ok(())
486506
}
487507

508+
fn is_sha256_hex(s: &str) -> bool {
509+
s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit())
510+
}
511+
512+
fn sha256_hex_of_serialized<T: serde::Serialize>(value: &T) -> Result<String> {
513+
let bytes = serde_json::to_vec(value)
514+
.map_err(|e| Error::History(format!("cannot serialize for hash check: {e}")))?;
515+
Ok(format!("{:x}", Sha256::digest(&bytes)))
516+
}
517+
488518
fn write_bundle(path: &Path, bundle: &Bundle) -> Result<()> {
489519
if let Some(parent) = path.parent() {
490520
std::fs::create_dir_all(parent)

0 commit comments

Comments
 (0)