Two root-cause fixes for the sandbox failure where an inline Dockerfile
came back from the store as `ARG REDACTED` and the Daytona snapshot
build died on the unset variable.
Entropy redaction measures values, not assignment pairs. The detector
matched `NAME=value` as one token, so an uppercase name merged its
charset into a pure-hex value (which alone can never exceed 4.0 bits)
and pushed the pair over the 4.5-bit threshold — then replaced the
whole pair, destroying the name. `find_entropy_regions` now strips an
identifier-shaped `NAME=` prefix before measuring and redacts only the
value, matching the gitleaks layer's `key=REDACTED` shape.
Execution no longer reads redacted content. Every stored event passes
through the redaction sink, and `load_from_store` rehydrated the
worker's RunSpec from the projection folded from those events — so a
redactor false positive silently rewrote the spec the sandbox builds
from (and changed its snapshot identity). The creation path now writes
the exact spec bytes to the content-addressed blob store and records
`spec_blob` on run.created; `load_from_store` loads the spec from the
blob, keeping the event stream authoritative for run identity,
provenance, and event-recorded blob ids. Retry and fork carry the
source run's `spec_blob` forward, so derived runs stop inheriting the
redacted copy. Runs created before the blob existed fall back to the
folded spec.
The projection and every API surface keep serving the redacted fold;
blobs were already stored unredacted (the workflow bundle carries the
same bytes), so this adds no new exposure at rest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The entropy redactor rewrites NAME=<hex> assignment pairs to a bare
REDACTED, and the worker rehydrates its executable RunSpec from the
projection folded from redacted stored events. Together these broke
Daytona snapshot builds for any run definition whose inline Dockerfile
pins a git SHA: the spec came back as `ARG REDACTED`, the build died on
the unset variable under `set -eu`, and the environment's snapshot
identity silently changed.
Pin the intended contracts with red tests:
- fabro-redact: an assignment whose value alone is below the entropy
threshold survives redaction (pure hex cannot exceed 4.0 bits; only
the name+value charset merge crosses 4.5), and a genuinely
high-entropy value is redacted without destroying the key name.
- fabro-workflow: the spec that load_from_store rehydrates round-trips
byte-identical through the store, including content that looks like
a secret — event redaction must not reach execution.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>