running-process-probe 4.10.13

Sidecar / file-hook tier for running-process (#539 follow-up #551)
Documentation
[package]
name = "running-process-probe"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
homepage.workspace = true
description = "Sidecar / file-hook tier for running-process (#539 follow-up #551)"
# Published, because `running-process`'s `probe` feature depends on it and
# cargo requires every dependency of a published crate to resolve from the
# registry. Leaving this false is why `cargo publish -p running-process`
# fails today with "dependency `running-process-probe` does not specify a
# version".
publish = true

# Slice 1 scaffold: the helper binary is an inert placeholder that prints
# its version banner. Real injection vehicles (DLL/dylib + retour-rs /
# LD_PRELOAD / DYLD_INSERT_LIBRARIES) land in slices 4–6 of #551.
#
# CRITICAL: this crate is the ONLY place injection symbols may live. The
# main `running-process` crate must stay clean of `CreateRemoteThread`,
# `dlopen` of interposer libraries, etc. — static AV exposure mitigation
# per the original #539 design. Enforced via `objdump`/`dumpbin` assertion
# in PR 2 (embed-and-extract machinery).
[[bin]]
name = "running-process-probe-agent"
path = "src/bin/helper.rs"

[features]
default = []

# Opt-in feature flag for the embed-and-extract machinery (slice 2 of
# #551). When `off`, the crate compiles to an empty stub — consumers
# don't pay the binary-size cost or expose any sidecar symbols.
# When `on`, the cache + extract functions (`helper_cache_dir`,
# `extract_helper_blob`) are exposed and the dependencies on `dirs`
# + `blake3` come along. Slice 2b will wire `include_bytes!` of the
# actually-built helper binary; today the function is generic over
# the blob bytes so the build-dep chain can be deferred without
# changing the API.
embed-helper = ["dep:dirs", "dep:blake3"]

[dependencies]
# Slice 2 adds the cache + extract machinery dependencies, both gated
# behind the off-by-default `embed-helper` feature so consumers that
# don't opt in pay zero binary-size + zero static-AV-surface cost.
dirs = { version = "6", optional = true }
blake3 = { version = "1.8.7", optional = true }

# The probe_diag.v1 schema (#630) is always compiled — it is the crate's
# wire, not an opt-in. `prost` is non-optional; the "no injection symbols"
# invariant constrains the MAIN crate, not this one, and the interposer
# crates don't depend on this crate so they pay nothing.
#
# Must stay in this cross-platform `[dependencies]` table. It previously sat
# below the `[target.'cfg(target_os = "windows")'.dependencies]` header,
# which silently scoped it to Windows — the crate then built here but failed
# every Linux/macOS lane with "could not find `prost`".
prost = "0.14"
# #635: typed snapshot errors.
thiserror = { workspace = true }
framehop = "0.13"
# #636: cross-platform SIGSEGV/SIGBUS/SIGILL/SIGFPE/SIGABRT/SEH
# interception. The callback only copies into a fixed buffer and performs one
# OS write; all allocation and stack capture happens on a sampler thread.
crash-handler = "0.7"
getrandom = "0.4"

[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
# #635 cooperative capture uses realtime signals/ucontext on Linux and Mach
# thread APIs on macOS. This must be a normal dependency: snapshot capture is
# production code, not only a test seam.
libc = "0.2"
# Parse unwind sections only after every captured thread is running again.
# Keeping parsers out of the signal/suspend window is the safety boundary.
object = { version = "0.36", default-features = false, features = ["read", "std"] }

[target.'cfg(target_os = "macos")'.dependencies]
# libc exposes thread_info but not the suspend/state/Mach-VM APIs or
# architecture state structs needed for cooperative capture.
mach2 = "0.4"

# Slice 6d adds the Windows-side injection vehicle
# (`CreateRemoteThread(LoadLibraryW, dll_path)`). Gated on
# `target_os = "windows"` so the rest of the workspace doesn't pull
# `windows-sys` in on non-Windows hosts.
[target.'cfg(target_os = "windows")'.dependencies]
libc = "0.2"
windows-sys = { version = "0.61", features = [
    "Win32_Foundation",
    "Win32_Security",
    "Win32_System_Diagnostics_Debug",
    "Win32_System_Kernel",
    "Win32_System_IO",
    "Win32_System_LibraryLoader",
    "Win32_System_Memory",
    "Win32_Storage_FileSystem",
    "Win32_System_SystemInformation",
    "Win32_System_Threading",
] }

# #635: cooperative all-thread capture. `processthreadsapi` for
# Suspend/Resume/GetThreadContext, `tlhelp32` to enumerate our own threads,
# `memoryapi` to bound the stack copy at the committed region. Deliberately NO
# `dbghelp`: its process-global lock has no place in a capture path that runs
# with threads suspended.
winapi = { version = "0.3", features = [
    "handleapi",
    "memoryapi",
    "processthreadsapi",
    "psapi",
    "tlhelp32",
    "winnt",
] }

[build-dependencies]
prost-build = "0.14"
protox = "0.9"

[dev-dependencies]
# `tempfile` for tests that exercise the cache-extract machinery
# against per-test directories instead of the shared
# `helper_cache_dir()` (which would race across parallel tests).
tempfile = "3"
libc = "0.2"
# Framing primitives for the wire round-trip tests. The probe wire reuses
# the broker's framing codec rather than re-deriving the 16 MiB cap.
running-process = { path = "../running-process", default-features = false, features = [
    "client",
] }
proptest = "1"

[lints]
workspace = true