operations tier

operations-block-imaging

Forensic block capture: write-block-gated acquisition, capacity preflight, dual-digest signed manifest, and the CaptureReceipt/VerifiedCapture pair that is the only way to authorize what runs after a capture

Forensic block capture: write-block-gated acquisition, capacity preflight, dual-digest signed manifest, and the CaptureReceipt/VerifiedCapture pair that is the only way to authorize what runs after a capture

Tieroperations
Rolecapability
Pathcrates/operations/block-imaging
Edition2021
Targetsoperations_block_imaging, adapters, capture_order, token, verify_roundtrip, write_block_adapter
Public items34 across 0 modules
Tests24

What it is for

operations-block-imaging — forensic block capture, and the proof that authorizes everything downstream of it.

Two things live here, and the second is why the first is worth having.

Acquisition (capture) reads a suspect device in one fixed order: the write-block is confirmed, the destination is proven large enough, and only then is a byte read. Both gates refuse before the reader is touched — on a disk you are not allowed to write to, "it returned an error afterwards" is not the same guarantee. A capture that fails mid-stream keeps what it read and never publishes the final artifact name, because deleting a partial acquisition can destroy the only readable data a failing disk will ever give up.

Proof (CaptureReceipt and VerifiedCapture) is the ordering invariant expressed as a type rather than as a file on disk. verify, triage and reinstall are separate process invocations, so the thing that crosses between them is the signed, serializable CaptureReceipt; the VerifiedCapture token is reconstructed inside the consuming process by VerifiedCapture::from_receipt, which is its only constructor and which re-hashes the artifact for itself. A receipt assembled by hand, signed by an untrusted key, replayed from another case or another device, or covering an artifact that has since changed, yields no token — so a caller cannot hold one without the capture having actually happened, for this case, on this device.

What this does NOT claim: against code already running as root on the same host, no userspace mechanism here holds. The guarantee is detection through the signed digest, not prevention.

Testability

The device, the destination and the write-blocker are traits (SourceReader, ArtifactSink, WriteBlockCheck), so every refusal above is proven against fixtures without touching hardware — the same seam idiom operations-device-safety uses for operations_device_safety::DeviceResolver.

Capabilities

crate root

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
fn capacity_sufficient(source_bytes : u64, free_bytes : u64, reserve_bytes : u64) -> bool
fn digest_hex(bytes : & u8) -> String
fn capture <W, S, K>(spec : & CaptureSpec, blocker : & mut W, reader : & mut S, sink : & mut K,) -> Result <CaptureManifest, BlockImagingError> where W : WriteBlockCheck + ? Sized, S : SourceReader + ? Sized, K : ArtifactSink + ? Sized,
fn verify <R : ArtifactReader + ? Sized>(manifest : & CaptureManifest, artifact : & mut R, key : & SigningKey,) -> Result <CaptureReceipt, BlockImagingError>

ArtifactReader

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub trait ArtifactReader

ArtifactSink

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub trait ArtifactSink

BlockImagingError

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub enum BlockImagingError

BlockdevWriteBlock

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct BlockdevWriteBlock
BlockdevWriteBlock :: fn new(blockdev_bin : impl Into <PathBuf>, device_path : impl Into <String>) -> Self
BlockdevWriteBlock :: fn confirm_read_only(& mut self, _device : & DeviceId) -> Result <bool, BlockImagingError>

CaptureManifest

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct CaptureManifest

CaptureReceipt

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct CaptureReceipt
CaptureReceipt :: fn sign(manifest : CaptureManifest, key : & SigningKey) -> Self
CaptureReceipt :: fn manifest(& self) -> & CaptureManifest

CaptureSpec

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct CaptureSpec

DeviceReader

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct DeviceReader
DeviceReader :: fn open(path : impl AsRef <Path>) -> Result <Self, BlockImagingError>
DeviceReader :: fn size_bytes(& self) -> u64
DeviceReader :: fn read_chunk(& mut self, buf : & mut u8) -> Result <usize, BlockImagingError>
DeviceReader :: fn read_chunk(& mut self, buf : & mut u8) -> Result <usize, BlockImagingError>

FileArtifactSink

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct FileArtifactSink
FileArtifactSink :: fn create(final_path : impl AsRef <Path>, free_bytes : u64,) -> Result <Self, BlockImagingError>
FileArtifactSink :: fn partial_path(& self) -> & Path
FileArtifactSink :: fn free_bytes(& self) -> u64
FileArtifactSink :: fn write(& mut self, bytes : & u8) -> Result <(), BlockImagingError>
FileArtifactSink :: fn promote(& mut self) -> Result <(), BlockImagingError>

SourceReader

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub trait SourceReader

VerifiedCapture

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub struct VerifiedCapture
VerifiedCapture :: fn from_receipt <R : ArtifactReader + ? Sized>(receipt : & CaptureReceipt, trusted : & VerifyingKey, expected_case : & str, expected_device : & DeviceId, artifact : & mut R,) -> Result <Self, BlockImagingError>
VerifiedCapture :: fn case_id(& self) -> & str
VerifiedCapture :: fn source_device(& self) -> & DeviceId
VerifiedCapture :: fn artifact_sha256(& self) -> & str
VerifiedCapture :: fn raw_sha256(& self) -> & str

WriteBlockCheck

operations-block-imaging — forensic block capture, and the proof that authorizes

Item
pub trait WriteBlockCheck

How to use it

No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.

Module structure

No public modules: the crate root is its whole surface.

Public surface

`crate root`

ItemWhat it is
pub enum BlockImagingErrorEverything that can go wrong acquiring or proving a capture.
pub trait SourceReaderReads the suspect device
pub trait ArtifactSinkReceives the artifact
pub trait ArtifactReaderReads an already-written artifact back, so its digest can be recomputed independently.
pub trait WriteBlockCheckReports whether the source is confirmed read-only
pub struct CaptureSpecWhat a capture is asked to do.
pub struct CaptureManifestWhat a capture attests
pub struct CaptureReceiptA signed, serializable attestation that a capture happened and verified
CaptureReceipt :: fn sign(manifest : CaptureManifest, key : & SigningKey) -> SelfSign a manifest with the case key.
CaptureReceipt :: fn manifest(& self) -> & CaptureManifestWhat this receipt attests, unverified
pub struct VerifiedCaptureProof that a capture happened, verified, and belongs to this case and this device
VerifiedCapture :: fn from_receipt <R : ArtifactReader + ? Sized>(receipt : & CaptureReceipt, trusted : & VerifyingKey, expected_case : & str, expected_device : & DeviceId, artifact : & mut R,) -> Result <Self, BlockImagingError>Rebuild the token from a receipt, inside the process that intends to act on it
VerifiedCapture :: fn case_id(& self) -> & strThe engagement this proof belongs to.
VerifiedCapture :: fn source_device(& self) -> & DeviceIdThe device this proof covers.
VerifiedCapture :: fn artifact_sha256(& self) -> & strDigest of the persisted artifact.
VerifiedCapture :: fn raw_sha256(& self) -> & strDigest of the bytes read from the device.
fn capacity_sufficient(source_bytes : u64, free_bytes : u64, reserve_bytes : u64) -> boolWhether a destination can hold source_bytes plus reserve_bytes
fn digest_hex(bytes : & u8) -> StringSHA-256 of bytes, lowercase hex
fn capture <W, S, K>(spec : & CaptureSpec, blocker : & mut W, reader : & mut S, sink : & mut K,) -> Result <CaptureManifest, BlockImagingError> where W : WriteBlockCheck + ? Sized, S : SourceReader + ? Sized, K : ArtifactSink + ? Sized,Acquire spec.source_device into sink, in the one order that is safe
fn verify <R : ArtifactReader + ? Sized>(manifest : & CaptureManifest, artifact : & mut R, key : & SigningKey,) -> Result <CaptureReceipt, BlockImagingError>Independently re-read artifact and, only if it still hashes to what manifest attests, sign a CaptureReceipt for it
pub struct DeviceReaderReads a block device — or, for tests and for imaging a file-backed source, any file
DeviceReader :: fn open(path : impl AsRef <Path>) -> Result <Self, BlockImagingError>Open path read-only and learn its size
DeviceReader :: fn size_bytes(& self) -> u64
DeviceReader :: fn read_chunk(& mut self, buf : & mut u8) -> Result <usize, BlockImagingError>
DeviceReader :: fn read_chunk(& mut self, buf : & mut u8) -> Result <usize, BlockImagingError>
pub struct FileArtifactSinkWrites an artifact to a .partial name and publishes the final one only on promote
FileArtifactSink :: fn create(final_path : impl AsRef <Path>, free_bytes : u64,) -> Result <Self, BlockImagingError>Create the .partial companion of final_path
FileArtifactSink :: fn partial_path(& self) -> & PathWhere the in-progress bytes are landing.
FileArtifactSink :: fn free_bytes(& self) -> u64
FileArtifactSink :: fn write(& mut self, bytes : & u8) -> Result <(), BlockImagingError>
FileArtifactSink :: fn promote(& mut self) -> Result <(), BlockImagingError>
pub struct BlockdevWriteBlockPuts a real blockdev behind capture's first refusal, by driving infrastructure_write_blocker::enable_and_verify — which sets read-only and then checks that it took effect, rather than trusting that the request succeeded
BlockdevWriteBlock :: fn new(blockdev_bin : impl Into <PathBuf>, device_path : impl Into <String>) -> SelfBind to a blockdev binary and the /dev path it should act on
BlockdevWriteBlock :: fn confirm_read_only(& mut self, _device : & DeviceId) -> Result <bool, BlockImagingError>

No pub use re-exports: every item above is declared in this crate.

Boundary

Reaches into foundation, infrastructure.

Shares tier operations with 40 other crates: operations-approval-workflow, operations-assessments, operations-boot-media, operations-browser-agent-worker, operations-camera-discovery, operations-camera-liveview, operations-camera-registry, operations-compliance, … (40 total).

_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._

Where it sits

Tier (ontology)operations
Architectural role (taxonomy)capability
Locationcrates/operations/block-imaging
Vocabulary in force (lexicon)current

Tier flow. Which tiers this crate's own edges cross.

flowchart LR
  n_operations["operations"] --> n_foundation["foundation"]
  n_operations["operations"] --> n_infrastructure["infrastructure"]

Dependencies

Runtime, in this workspace.

CrateTierOptionalOnly on
`foundation-audit-log`foundationnoalways
`foundation-bounded-io`foundationnoalways
`foundation-crypto-sign`foundationnoalways
`infrastructure-write-blocker`infrastructurenoalways
`operations-device-safety`operationsnoalways

Runtime, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
serde^1derivenoalways
serde_json^1noalways
thiserror^2noalways
tokio^1full, rtnoalways

Development, in this workspace.

CrateTierOptionalOnly on
`foundation-crypto-sign`foundationnoalways

Development, from outside the workspace.

CrateRequirementFeaturesOptionalOnly on
rand_core^0.6getrandomnoalways

Build. None.

Depended on by. 1 workspace crate.

Signal flow — what reaches this crate, and what it reaches.

flowchart LR
  n_tools_ir_triage["tools-ir-triage"] -->|uses| SELF
  SELF["operations-block-imaging"]
  SELF -->|development| n_foundation_crypto_sign["foundation-crypto-sign"]
  SELF -->|runtime| n_foundation_audit_log["foundation-audit-log"]
  SELF -->|runtime| n_foundation_bounded_io["foundation-bounded-io"]
  SELF -->|runtime| n_foundation_crypto_sign["foundation-crypto-sign"]
  SELF -->|runtime| n_infrastructure_write_blocker["infrastructure-write-blocker"]
  SELF -->|runtime| n_operations_device_safety["operations-device-safety"]
  classDef self fill:#1f883d,stroke:#1f883d,color:#fff;
  class SELF self;

Feature flags

No Cargo features are defined: every capability is unconditional, so no consumer can receive a half-wired crate.

Targets

KindNameSource
liboperations_block_imaging`src/lib.rs`
testadapters`tests/adapters.rs`
testcapture_order`tests/capture_order.rs`
testtoken`tests/token.rs`
testverify_roundtrip`tests/verify_roundtrip.rs`
testwrite_block_adapter`tests/write_block_adapter.rs`

Error model

Error typeNamed by
BlockImagingErrorcapture, verify

Operational characteristics

PropertyEvidence
async public surfacenone detected
async runtimeyes
database accessnone detected
network I/Onone detected
unsafe codenone detected
environment variablesnone detected

No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.

Configuration

No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.

1 workspace crate depends on this one: tools-ir-triage.

Verification

KindCount
Unit tests2
Integration tests22
Examples0
Doctests0

Evidence by module. How often each public module is named by something executable.

ModuleTestsExamplesConsumers
crate root16010

What the tests establish, by name:

Documentation coverage

MeasureDocumentedTotal
Public items with rustdoc2734
Public modules with a //! block00
pie showData
    title Public items with rustdoc
    "Documented" : 27
    "No rustdoc detected" : 7

Metrics

MetricValue
Rust source files1
Source lines654
Code lines391
Public API items34
Public modules0
Tests24
Examples0
Cargo features0
Direct runtime dependencies9
Workspace reverse dependencies1
pie showData
    title Public API by kind
    "enum" : 1
    "function" : 4
    "method" : 18
    "struct" : 7
    "trait" : 4
pie showData
    title Rust source composition
    "Code" : 391
    "Blank or comment" : 263

Generation

Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.

All operations · Manual