fix(util): honor the requested random output path - #877
Merged
Conversation
kvinwang
force-pushed
the
codex/fix-util-random-output-path
branch
from
August 4, 2026 04:24
15beff3 to
3796c60
Compare
`dstack-util rand` parsed `-o/--output` and then ignored it, always writing to stdout. The command reported success while the requested file was never created. Write the file through `safe_write_with_mode`, which the workspace already depends on, rather than hand-rolling the write: - The output is key material, so it is created 0600 and never exists under wider permissions. - The replacement is a single rename, and both the file and its directory are fsynced. A truncated random file is a silently weak secret — it looks exactly like a successful result, and nothing downstream can tell the difference. - If any step fails, nothing is left behind. A hand-rolled `create_new` + write leaves a short file that the next run then refuses to replace, so a transient ENOSPC would wedge the command with a partial secret in place. Re-running replaces the file rather than failing on an existing one, matching `openssl rand -out`. If a no-clobber mode is wanted later it should be an explicit flag rather than the implicit default. Four tests, all confirmed to fail against the previous behaviour: the file is created at the requested path with no temporary left behind, it is 0600, `-x` doubles the length and emits hex, and a re-run replaces it.
kvinwang
force-pushed
the
codex/fix-util-random-output-path
branch
from
August 4, 2026 04:26
3796c60 to
1d46575
Compare
kvinwang
enabled auto-merge
August 4, 2026 04:27
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
dstack-util randparsed-o/--outputand then ignored it, always writing to stdout. The command reported success while the requested file was never created.Fix
Write the file through
safe_write_with_mode, which this crate already depends on (dstack-util/Cargo.toml:65, andsystem_setup.rsin the same crate already usessafe_write), rather than hand-rolling the write:Why not a hand-rolled
create_new+write_all+sync_allThat was the first version of this PR. Three problems, measured rather than assumed:
create_newrefuses the file the failed run left behind. A transientENOSPCwedges the command permanently, with the partial secret still on disk.sync_allalone is not durable. It flushes the file's contents but not the directory entry, so a crash can leave the data on disk with nothing pointing at it — the exact failuresafe-writeexists to prevent.safe_write_with_modecreates the file 0600 before any content is written, publishes it in a single rename, fsyncs both the file and its parent directory, and removes the temporary file on every error path.It also drops the
fs_err::os::unix::fs::OpenOptionsExtimport entirely, so the second commit of the original branch is no longer needed. The two commits have been squashed into one.Behaviour note
Re-running now replaces an existing file instead of failing, matching
openssl rand -out. The previouscreate_newwas introduced by this PR rather than inherited, so nothing depended on it. If a no-clobber mode is wanted it should be an explicit flag, not the implicit default.Verification
Four tests, all confirmed to fail against the previous behaviour rather than merely passing:
rand_writes_to_the_requested_output_pathrand_output_is_owner_onlyrand_hex_output_is_twice_as_longrand_replaces_an_existing_output62 tests pass in
dstack-util,cargo fmt --checkis clean and clippy reports 0 warnings. Rebased onto currentmaster.Related
The
safe-writebehind this call is pinned at0.1.3, which has known correctness bugs of its own. #989 upgrades the workspace to0.2.0and switchesdstack-cli-core::fsutilonto it. This PR is correct either way — the call site does not change — but the guarantees described above only fully hold once #989 lands.