feat: PUT /file/<absolute-path> -- scriptable file-write route - #7
Merged
Conversation
Same reach a pty on this connection already has (arbitrary write as the server's user, sudo included) -- this isn't a new capability, just a clean one-shot call for a script instead of driving a terminal to do the same thing (shell-escaping/base64 a binary body through a VT100 stream to write a file, then scraping rendered output to infer success). The URL suffix after /file is used directly as the destination path (e.g. PUT /file/run/secrets/gh/hosts.yml -> /run/secrets/gh/hosts.yml). No configurable root, no sandboxing -- deliberately: this route doesn't cross a trust boundary the terminal doesn't already cross, so restricting it would add friction without adding protection. Always writes 0600, no caller-supplied mode/owner param: there's no other user to own it as (can't chown without root), and defaulting restrictive costs nothing. `save -f` (no `-r`) silently corrupted binary content -- confirmed via hash mismatch on round-tripped random bytes. Fixed with `-r/--raw`; a real secret/credential file would have been mangled without this. Also: --dev only works via cargo run from inside a checkout (the path it reads is a Rust compile-time constant, baked in wherever the binary was built) -- doesn't work on an installed/downloaded release binary. Wasn't documented; found it while debugging why --dev failed on a prebuilt binary.
…sions umask is process-wide state; scoping it around one request's write in a server handling concurrent requests would also affect other in-flight requests' unrelated file creation. chmod-after only narrows the exposure window to this one destination path.
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.
Adds one route:
PUT /file/<absolute-path>writes the request body to that path,mkdir -p'ing the parent first. No new capability -- a pty on this connection can already write anywhere as the server's user (sudo included). This is a clean one-shot call for a script to do the same thing, instead of driving a terminal (shell-escaping/base64-ing a body through a VT100 stream, then scraping rendered output to infer success).Deliberately no configurable root and no path sandboxing -- there's no trust boundary here to protect that the terminal doesn't already cross, so restricting it would be friction without protection.
Also documents a real gap I hit building this:
--devdoesn't work on an installed/downloaded release binary.$CARGO_MANIFEST_DIR(the path--devreads) is a Rust compile-time constant baked in wherever the binary was built -- for a release build that's GitHub Actions' checkout path, which doesn't exist anywhere else. Confirmed empirically:Tested locally: valid write round-trips correctly, overwrite works, bad/empty paths 400, wrong method falls through cleanly. Built from this checkout with
cargo build --release,cargo check/build clean.