Skip to content

Commit a1d7029

Browse files
claudebranchseer
authored andcommitted
refactor: address PR review comments
- Remove speculative seccomp comment from CI workflow - Use .node-version file for Node.js version in Alpine CI - Remove [env] CC wrapper vars from .cargo/config.toml and CI sed - Revert O_DIRECTORY check in seccomp handler; instead consume a dir entry in the rust_std test so getdents64 fires - Fix misleading "musl does not support cdylib" comment; update fspy README with musl section - Revert to plain #[ctor::ctor] in command_for_fn! macro; remove linkme distributed slice infrastructure and subprocess_dispatch_ctor - Keep /proc/self/cmdline fallback for musl arg reading in init_impl - Remove all requires_fspy from snapshot toml files and Rust code https://claude.ai/code/session_01Cqj3gbQjb7yFe49f1tfwYv
1 parent 950b19d commit a1d7029

File tree

23 files changed

+48
-194
lines changed

23 files changed

+48
-194
lines changed

.cargo/config.toml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,3 @@ rustflags = ["-C", "linker=.cargo/zigcc-x86_64-unknown-linux-musl"]
1111

1212
[target.aarch64-unknown-linux-musl]
1313
rustflags = ["-C", "linker=.cargo/zigcc-aarch64-unknown-linux-musl"]
14-
15-
# CC wrappers for crates with C build scripts (e.g. stackalloc via cc-rs).
16-
# The linker flags above only cover rustc linking; cc-rs needs its own compiler.
17-
[env]
18-
CC_x86_64_unknown_linux_musl = { value = ".cargo/zigcc-x86_64-unknown-linux-musl", relative = true }
19-
CC_aarch64_unknown_linux_musl = { value = ".cargo/zigcc-aarch64-unknown-linux-musl", relative = true }

.github/workflows/ci.yml

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -140,26 +140,24 @@ jobs:
140140
runs-on: ubuntu-latest
141141
container:
142142
image: alpine:3.21
143-
# fspy uses seccomp user notifications which require unconfined seccomp
144-
# fspy uses seccomp user notifications and shared memory IPC
145143
options: --security-opt seccomp=unconfined --shm-size=256m
146144
steps:
147145
- name: Install Alpine dependencies
148146
shell: sh {0}
149147
run: apk add --no-cache bash curl git musl-dev gcc g++ python3
150148

149+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
150+
with:
151+
persist-credentials: false
152+
submodules: true
153+
151154
# Alpine's Node.js package is compiled without TypeScript type-stripping.
152155
# Install the official Node.js musl binary which includes full TypeScript support.
153156
- name: Install Node.js from official distribution
154157
run: |
155-
NODE_VERSION=$(curl -fsSL https://unofficial-builds.nodejs.org/download/release/index.json | python3 -c "import sys,json; print(next(d['version'] for d in json.load(sys.stdin) if d['version'].startswith('v22.')))")
158+
NODE_VERSION=v$(cat .node-version)
156159
curl -fsSL "https://unofficial-builds.nodejs.org/download/release/${NODE_VERSION}/node-${NODE_VERSION}-linux-x64-musl.tar.gz" | tar -xz -C /usr/local --strip-components=1
157160
158-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
159-
with:
160-
persist-credentials: false
161-
submodules: true
162-
163161
- name: Install Rust
164162
run: |
165163
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain nightly-2026-03-05
@@ -171,11 +169,9 @@ jobs:
171169
pnpm install
172170
173171
# Remove the zig cross-compilation config from .cargo/config.toml — in Alpine,
174-
# the system cc is already musl-based, so no cross-compilation linker or CC is needed.
172+
# the system cc is already musl-based, so no cross-compilation linker is needed.
175173
- name: Remove zig linker config for native musl
176-
run: |
177-
sed -i '/\[target.*musl\]/,/^$/d' .cargo/config.toml
178-
sed -i '/\[env\]/,/^$/d' .cargo/config.toml
174+
run: sed -i '/\[target.*musl\]/,/^$/d' .cargo/config.toml
179175

180176
- run: cargo test --no-fail-fast
181177

Cargo.lock

Lines changed: 0 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ diff-struct = "0.5.3"
7171
directories = "6.0.0"
7272
elf = { version = "0.8.0", default-features = false }
7373
flate2 = "1.0.35"
74-
linkme = "0.3"
7574
fspy = { path = "crates/fspy" }
7675
fspy_detours_sys = { path = "crates/fspy_detours_sys" }
7776
fspy_preload_unix = { path = "crates/fspy_preload_unix", artifact = "cdylib" }

crates/fspy/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ tempfile = { workspace = true }
4848
anyhow = { workspace = true }
4949
csv-async = { workspace = true }
5050
ctor = { workspace = true }
51-
linkme = { workspace = true }
5251
subprocess_test = { workspace = true, features = ["fspy"] }
5352
test-log = { workspace = true }
5453
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "fs", "io-std"] }
@@ -72,4 +71,4 @@ workspace = true
7271
doctest = false
7372

7473
[package.metadata.cargo-shear]
75-
ignored = ["ctor", "linkme", "fspy_test_bin"]
74+
ignored = ["ctor", "fspy_test_bin"]

crates/fspy/README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Run a command and capture all the paths it tries to access.
44

5-
## macOS/Linux implementation
5+
## macOS/Linux (glibc) implementation
66

77
It uses `DYLD_INSERT_LIBRARIES` on macOS and `LD_PRELOAD` on Linux to inject a shared library that intercepts file system calls.
88
The injection process is almost identical on both platforms other than the environment variable name. The implementation is in `src/unix`.
@@ -11,6 +11,10 @@ The injection process is almost identical on both platforms other than the envir
1111

1212
For fully static binaries (such as `esbuild`), `LD_PRELOAD` does not work. In this case, `seccomp_unotify` is used to intercept direct system calls. The handler is implemented in `src/unix/syscall_handler`.
1313

14+
## Linux musl implementation
15+
16+
On musl targets, only `seccomp_unotify`-based tracking is used (no preload library).
17+
1418
## Windows implementation
1519

1620
It uses [Detours](https://github.com/microsoft/Detours) to intercept file system calls. The implementation is in `src/windows`.

crates/fspy/src/unix/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ const PRELOAD_CDYLIB_BINARY: &[u8] = include_bytes!(env!("CARGO_CDYLIB_FILE_FSPY
4545
impl SpyImpl {
4646
/// Initialize the fs access spy by writing the preload library on disk.
4747
///
48-
/// On musl targets, the preload library is not available (musl does not support cdylib),
49-
/// so only seccomp-based tracking is used.
48+
/// On musl targets, we don't build a preload library —
49+
/// only seccomp-based tracking is used.
5050
pub fn init_in(#[cfg_attr(target_env = "musl", allow(unused))] dir: &Path) -> io::Result<Self> {
5151
#[cfg(not(target_env = "musl"))]
5252
let preload_path = {

crates/fspy/src/unix/syscall_handler/mod.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,14 @@ impl SyscallHandler {
5757
}
5858
path = Cow::Owned(resolved_path);
5959
}
60-
let mut mode = match flags & libc::O_ACCMODE {
61-
libc::O_RDWR => AccessMode::READ | AccessMode::WRITE,
62-
libc::O_WRONLY => AccessMode::WRITE,
63-
_ => AccessMode::READ,
64-
};
65-
if flags & libc::O_DIRECTORY != 0 {
66-
mode.insert(AccessMode::READ_DIR);
67-
}
68-
self.arena.add(PathAccess { mode, path: path.as_os_str().into() });
60+
self.arena.add(PathAccess {
61+
mode: match flags & libc::O_ACCMODE {
62+
libc::O_RDWR => AccessMode::READ | AccessMode::WRITE,
63+
libc::O_WRONLY => AccessMode::WRITE,
64+
_ => AccessMode::READ,
65+
},
66+
path: path.as_os_str().into(),
67+
});
6968
Ok(())
7069
}
7170

crates/fspy/tests/rust_std.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ async fn readdir() -> anyhow::Result<()> {
5252

5353
let accesses = track_fn!(tmpdir_path.to_str().unwrap().to_owned(), |tmpdir_path: String| {
5454
std::env::set_current_dir(tmpdir_path).unwrap();
55-
let _ = std::fs::read_dir("hello_dir");
55+
// Consume at least one entry so that getdents64 fires on seccomp targets.
56+
let _ = std::fs::read_dir("hello_dir").unwrap().next();
5657
})
5758
.await?;
5859
assert_contains(&accesses, tmpdir_path.join("hello_dir").as_path(), AccessMode::READ_DIR);

crates/fspy/tests/test_utils/mod.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
subprocess_test::subprocess_dispatch_ctor!();
2-
31
use std::path::{Path, PathBuf, StripPrefixError};
42

53
use fspy::{AccessMode, PathAccessIterable};

0 commit comments

Comments
 (0)