fix(blob_consistency): raise a finding if decipher fails
This commit is contained in:
@@ -251,6 +251,12 @@ impl RecoverableJobHandler for BlobsConsistencyCheck {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Snapshot "is this a Fresh run?" BEFORE the resume_cursor
|
||||||
|
// match consumes it — otherwise the `is_none()` check later
|
||||||
|
// borrows a partially-moved value. Fresh = no cursor bytes
|
||||||
|
// at all; Resumed = cursor bytes present (possibly empty).
|
||||||
|
let is_fresh = resume_cursor.is_none();
|
||||||
|
|
||||||
// Cursor = the last-visited `hash` string, UTF-8-encoded. On
|
// Cursor = the last-visited `hash` string, UTF-8-encoded. On
|
||||||
// resume, we walk `WHERE hash > $cursor` in ASC order. First
|
// resume, we walk `WHERE hash > $cursor` in ASC order. First
|
||||||
// batch: NULL cursor → start from the smallest hash.
|
// batch: NULL cursor → start from the smallest hash.
|
||||||
@@ -272,10 +278,49 @@ impl RecoverableJobHandler for BlobsConsistencyCheck {
|
|||||||
// `record_finding` on each emission).
|
// `record_finding` on each emission).
|
||||||
let mut finding_count = 0u64;
|
let mut finding_count = 0u64;
|
||||||
|
|
||||||
// Deep mode = re-hash bytes for bit-rot detection. Logged
|
// Deep mode is a per-run flag with two consumers:
|
||||||
// once at run start so operators tailing tracing know why the
|
// 1. This handler — decides whether to re-hash bytes.
|
||||||
// scan is taking hours.
|
// 2. The admin panel — needs to display whether the run
|
||||||
if args.deep {
|
// was deep so operators know what the scan actually
|
||||||
|
// verified.
|
||||||
|
//
|
||||||
|
// On a Fresh run we take it from `deep` (the trigger
|
||||||
|
// endpoint stamps `?deep=true` onto the args) and stash it
|
||||||
|
// in `params.deep` so:
|
||||||
|
// * Resume picks up the same mode (would previously become
|
||||||
|
// non-deep on Resume — a Paused deep scan silently lost
|
||||||
|
// its `deep` intent).
|
||||||
|
// * The admin panel run-detail view can render
|
||||||
|
// `params.deep = "true"` alongside `target_name`,
|
||||||
|
// `progress_kind`, etc.
|
||||||
|
//
|
||||||
|
// Persist BEFORE the walk so a mid-fresh-batch crash still
|
||||||
|
// leaves a Paused row with the right mode marker.
|
||||||
|
let deep = if is_fresh {
|
||||||
|
let deep = args.deep;
|
||||||
|
let v = if deep { "true" } else { "false" };
|
||||||
|
if let Err(e) = store.set_string_param("deep", v).await {
|
||||||
|
return RunOutcome::Failed {
|
||||||
|
message: format!("failed to persist deep flag to params: {e}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
deep
|
||||||
|
} else {
|
||||||
|
// Resumed run — read the persisted flag. Default to
|
||||||
|
// false (fast mode) if the row is a pre-K3.5 Paused
|
||||||
|
// scan without the param stashed.
|
||||||
|
match store.get_string_param("deep").await {
|
||||||
|
Ok(Some(v)) => v == "true",
|
||||||
|
Ok(None) => false,
|
||||||
|
Err(e) => {
|
||||||
|
return RunOutcome::Failed {
|
||||||
|
message: format!("read `deep` from params: {e}"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if deep {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
target: "oxicloud::consistency",
|
target: "oxicloud::consistency",
|
||||||
event = "blobs_consistency.deep_mode_active",
|
event = "blobs_consistency.deep_mode_active",
|
||||||
@@ -377,7 +422,7 @@ impl RecoverableJobHandler for BlobsConsistencyCheck {
|
|||||||
event = "blobs_consistency.completed",
|
event = "blobs_consistency.completed",
|
||||||
run_id = %store.run_id(),
|
run_id = %store.run_id(),
|
||||||
finding_count = finding_count,
|
finding_count = finding_count,
|
||||||
deep = args.deep,
|
deep = deep,
|
||||||
"blobs_consistency completed with {} finding(s)",
|
"blobs_consistency completed with {} finding(s)",
|
||||||
finding_count
|
finding_count
|
||||||
);
|
);
|
||||||
@@ -472,7 +517,7 @@ impl RecoverableJobHandler for BlobsConsistencyCheck {
|
|||||||
// `expected_hash` was NOT reused as a name to
|
// `expected_hash` was NOT reused as a name to
|
||||||
// avoid mistaking it for "the hash we expect to
|
// avoid mistaking it for "the hash we expect to
|
||||||
// see on disk (i.e. what will fix this)".
|
// see on disk (i.e. what will fix this)".
|
||||||
if args.deep {
|
if deep {
|
||||||
match recompute_hash(backend.as_ref(), &row.hash).await {
|
match recompute_hash(backend.as_ref(), &row.hash).await {
|
||||||
Ok(computed_hash) if computed_hash == row.hash => {}
|
Ok(computed_hash) if computed_hash == row.hash => {}
|
||||||
Ok(computed_hash) => {
|
Ok(computed_hash) => {
|
||||||
@@ -524,7 +569,7 @@ impl RecoverableJobHandler for BlobsConsistencyCheck {
|
|||||||
event = "blobs_consistency.completed",
|
event = "blobs_consistency.completed",
|
||||||
run_id = %store.run_id(),
|
run_id = %store.run_id(),
|
||||||
finding_count = finding_count,
|
finding_count = finding_count,
|
||||||
deep = args.deep,
|
deep = deep,
|
||||||
"blobs_consistency completed with {} finding(s)",
|
"blobs_consistency completed with {} finding(s)",
|
||||||
finding_count
|
finding_count
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user