Repository navigation
Conversation
## Problem The box shell's `touch` did not change the times of an existing file. It opened the file for append and closed it. Nothing was written, so no time changed, and `touch` exited 0. An agent that uses `touch` to mark a file as changed, for example for `make`, saw success and got nothing. `touch` also refused every option except `--help`, so `touch -d`, `-r`, `-t`, `-a`, `-m`, and `-c` all failed with `invalid option`. The vendored shell had no operation that sets a file's times. Fixes strands-agents#361. ## Solution - The vendored shell gets a time operation on the same path as `chmod`: `Kernel::set_times(proc, Resolved, FileTimes)`, `Mediated::set_times`, `io::set_times`, and the effect `FsOperation::SetTimes`, admitted with `Follow::Yes`. `FileTimes` holds one `TimeChange` (`Keep`, `Now`, or `To(SystemTime)`) for each of the two times. - On a host bind, `VfsKernel` calls `utimensat` pinned to the identity that admission checked, as `set_permissions` does. A read-only bind refuses it. On the in-memory VFS, permission follows `utimensat`: the owner can set any time, and a writer can set the current time. - `touch` accepts `-a`, `-m`, `-c`/`--no-create`, `-d`/`--date` (ISO 8601 and `@SECONDS`), `-r`/`--reference`, and `-t STAMP`. A missing file is created without truncation. A failure on one file names that file, and `touch` continues and exits 1. - The policy adapter maps `SetTimes` to the existing `fs:write` operation `write_content`. A rule that permits writing a file also permits touching it. The authored policy vocabulary does not change. - Interfaces that moved, all in the vendored `strands-shell` crate: the required trait method `Kernel::set_times`; the types `FileTimes` and `TimeChange`; the variant `FsOperation::SetTimes`; the field `FileStat::accessed`; and the field `vfs::Inode::atime`. The new `Inode` field breaks a struct literal of `Inode` outside the crate; no code in this repository builds one. The user approved each of these. Box's call kernel passes `set_times` through. - `crates/shell/UPSTREAM.md` records the divergence, and `docs/user/shell.md` states that `touch` requests `fs:write` / `write_content`. ## Tests - `crates/shell/tests/touch_times.rs` (11 cases) pins `-d`, `-t`, `-a`, `-m`, `-r`, and `-c` on a host bind, creation of a missing file, a read-only bind refused while the next file still updates, and `-d`, `-a`, and `-r` on the in-memory VFS. With the host branch made a no-op, seven cases fail. With the in-memory branch keeping the access time, `touch_a_changes_only_the_access_time_of_an_in_memory_file` and `touch_r_copies_the_reference_times_of_an_in_memory_file` fail. - `commands::touch::tests` pins the `-t` and `-d` parsers. `an_invalid_date_is_refused` includes non-ASCII dates; without the ASCII check it panics. - `crates/policy/tests/shell_fs_vocabulary.rs` shows that a rule on `write_content` decides `touch`. `admission_window_guard_present.rs` and `kernel_effect_interception.rs` list the new operation. - Ran on Linux x86_64: `cargo build`, `test`, `clippy`, and `fmt --check` for `strands-shell`, `strands-box-policy`, and `strands-box` with `--all-features`, and the site-manifest test. `strands-box` fails one test, `a_leafs_shebang_resolves_past_the_alias_directory`, because `/usr/bin/env` on this host is a link to the multicall `/usr/bin/coreutils`. The change does not touch that code. - Not run: the macOS build, `test-integ/run.sh`, and an end-to-end run in a box.
# Conflicts: # crates/shell/UPSTREAM.md
9 of 10 tasks
Collaborator
|
Thanks Mackenzie! Box no longer vendors Shell since #414, so the Shell half of this lives in strands-agents/shell#303 now. The Box half, sending a time change through the policy check as a write, still needs doing, but against the new |
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.
Description
The box shell's
touchreported success on an existing file and changed nothing: it opened the file for append and closed it, which writes no byte and so moves no time. It also refused every option, sotouch -d,-r,-t,-a,-m, and-cfailed withinvalid option. An agent that touches a file to mark it changed, for example formake, got exit 0 and stale times.The vendored shell had no way to set a file's times, so this adds one along the same path
chmodtakes: aKernel::set_timesmethod, aFsOperation::SetTimeseffect that admission sees, and a host branch that callsutimensaton the identity admission approved.touchthen parses its options on top of that.Decisions this depends on (both approved by @zastrowm before implementation):
SetTimesmaps to the existingfs:writeoperationwrite_content, so the authored policy vocabulary does not change. A rule that permits writing a file also permits touching it. The cost: an operator cannot permit writes but forbid time changes. A newBox::FsWriteOperation::"set_times"value was the alternative; it would add to the frozen policy vocabulary for a distinction nobody has asked for.vfs::Inodegains a publicatimefield. The in-memory VFS recorded no access time, sotouch -aand-rcould not work there. A struct literal ofInodeoutside the crate no longer compiles; nothing in this repo builds one outsidevfs.rs. A private side table inVfsKernelwas the alternative; it is more code for the same behavior.Interfaces that moved, all in the vendored
strands-shellcrate: the required trait methodKernel::set_times; the typesFileTimesandTimeChange;FsOperation::SetTimes;FileStat::accessed;vfs::Inode::atime. Box's own frozen surfaces are unchanged.crates/shell/UPSTREAM.mdrecords the divergence.Limits:
-daccepts ISO 8601 and@SECONDSonly, since the crate has no date parser; a date with no zone is UTC, asdateassumes. The macOSfile-attributesswitch does not govern this: the shell runs in box's trusted process, outside the agent's Seatbelt profile.Related Issues
Fixes #361
Type of Change
Bug fix
Testing
crates/shell/tests/touch_times.rs(12 cases) covers every option on a host bind, creating a missing file without truncation, a read-only bind refused while the next file still updates, and-d,-a,-rand creating a file at a date on the in-memory VFS.touch_creates_a_missing_in_memory_file_at_the_datefails unlesstouchwaits for the new file's write (settle_writes) before setting its times; that write would otherwise reset the modification time to now. With the host branch made a no-op, 7 fail; with the in-memory branch keeping the access time, the 2 in-memory-a/-rcases fail.an_invalid_date_is_refusedincludes non-ASCII dates; without the ASCII checkparse_datepanics on them.crates/policy/tests/shell_fs_vocabulary.rsshows a rule onwrite_contentdecidestouch.On Linux x86_64 after merging
main: build, test, clippy, andfmt --checkwith--all-featuresforstrands-shell(2050 passed),strands-box-policy(676 passed), andstrands-box(994 passed, 1 failed), plus the site-manifest test. The one failure,a_leafs_shebang_resolves_past_the_alias_directory, comes from this host's/usr/bin/envbeing a link to the multicall/usr/bin/coreutils; this change does not touch containment. Clippy reports no warnings in changed files.Not yet run (why this is a draft): an end-to-end
touchinside a real box on Linux aarch64 and on macOS, and the macOS build.I ran the relevant suites (
just check, orcargo test --workspace --all-features)If I touched Rust, I ran
cargo fmt --allandcargo clippy --workspace --all-targets --all-features -- -D warningsChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Agent-assisted PR.