failproofai 0.0.15 → 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +9 -9
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0id_xf7._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +4 -4
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0114ewg._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__06b4trb._.js → [root-of-the-server]__0259h38._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ath6v_._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zj-87g._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_0hs_5mh.js → node_modules_html-to-image_es_index_1-upb14.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +11 -11
- package/.next/standalone/.next/static/chunks/{1_v8b8mxhk25s.js → 0ip1n8xmgxarv.js} +1 -1
- package/.next/standalone/.next/static/chunks/{33rm-y-i4uzvv.js → 0u9hc6oxx-gpj.js} +1 -1
- package/.next/standalone/.next/static/chunks/{11qhtpk2cvoxv.js → 1d6ncspjagm53.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2f4mxqkkoa_7d.js → 1grd7y94-igz9.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3m8wmvlhsy1mx.js → 1s-_swlc80y43.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0kf9j0pf_j9-0.js → 29k6ef49zppxj.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2h7vw-ojgr9fz.js → 29ydr-8q0zis6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1-ng45379-ztb.js → 2vr7aazw6k2-n.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2geh8s7d3ead-.js → 3wrgbih-516uj.js} +1 -1
- package/.next/standalone/Cargo.lock +428 -0
- package/.next/standalone/Cargo.toml +9 -0
- package/.next/standalone/crates/PROTOCOL.md +122 -0
- package/.next/standalone/crates/failproofaid/Cargo.toml +18 -0
- package/.next/standalone/crates/failproofaid/src/lock.rs +81 -0
- package/.next/standalone/crates/failproofaid/src/main.rs +83 -0
- package/.next/standalone/crates/failproofaid/src/paths.rs +172 -0
- package/.next/standalone/crates/failproofaid/src/server.rs +502 -0
- package/.next/standalone/crates/failproofaid/src/worker.rs +400 -0
- package/.next/standalone/crates/failproofaid/tests/daemon_e2e.rs +241 -0
- package/.next/standalone/crates/fpai-ipc/Cargo.toml +16 -0
- package/.next/standalone/crates/fpai-ipc/src/envelope.rs +175 -0
- package/.next/standalone/crates/fpai-ipc/src/framing.rs +177 -0
- package/.next/standalone/crates/fpai-ipc/src/lib.rs +10 -0
- package/.next/standalone/crates/fpai-ipc/src/peer.rs +80 -0
- package/.next/standalone/package.json +5 -3
- package/.next/standalone/rust-toolchain.toml +4 -0
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai-worker.mjs +51 -0
- package/bin/failproofai.mjs +68 -1
- package/bin/failproofaid-shim.mjs +67 -0
- package/dist/cli.mjs +1202 -624
- package/dist/worker.mjs +8441 -0
- package/package.json +5 -3
- package/src/hooks/builtin-policies.ts +37 -13
- package/src/hooks/configure-wizard.ts +73 -1
- package/src/hooks/daemon-client.ts +199 -0
- package/src/hooks/daemon-download.ts +152 -0
- package/src/hooks/daemon-service.ts +449 -0
- package/src/hooks/handler.ts +231 -195
- package/src/hooks/normalize-cli-payload.ts +61 -0
- package/src/hooks/policy-types.ts +15 -0
- package/src/hooks/read-stdin.ts +48 -0
- package/src/hooks/worker-server.ts +154 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1is3glr._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0fopait._.js +0 -3
- /package/.next/standalone/.next/static/{ePKMmXXfXxThNsxwv1EiF → 7Lxtd352rSaHB-pmm6G8M}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ePKMmXXfXxThNsxwv1EiF → 7Lxtd352rSaHB-pmm6G8M}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ePKMmXXfXxThNsxwv1EiF → 7Lxtd352rSaHB-pmm6G8M}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
mod lock;
|
|
2
|
+
mod paths;
|
|
3
|
+
mod server;
|
|
4
|
+
mod worker;
|
|
5
|
+
|
|
6
|
+
use std::sync::Arc;
|
|
7
|
+
use std::sync::atomic::{AtomicBool, Ordering};
|
|
8
|
+
|
|
9
|
+
fn main() {
|
|
10
|
+
let args: Vec<String> = std::env::args().collect();
|
|
11
|
+
if args.iter().any(|a| a == "--version" || a == "-v") {
|
|
12
|
+
println!("failproofaid {}", env!("CARGO_PKG_VERSION"));
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if let Err(err) = run() {
|
|
17
|
+
eprintln!("[failproofaid] {err}");
|
|
18
|
+
std::process::exit(1);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
|
23
|
+
let lock_path = paths::lock_path()?;
|
|
24
|
+
paths::ensure_run_dir()?;
|
|
25
|
+
let _singleton = lock::acquire(&lock_path)?;
|
|
26
|
+
|
|
27
|
+
let socket_path = paths::socket_path()?;
|
|
28
|
+
let worker_socket_path = paths::worker_socket_path()?;
|
|
29
|
+
let worker = Arc::new(worker::Worker::new(
|
|
30
|
+
worker_socket_path,
|
|
31
|
+
worker::WorkerCommand::from_env(),
|
|
32
|
+
));
|
|
33
|
+
// Pre-warm off the startup path: the socket must be accepting
|
|
34
|
+
// connections promptly (a service manager / health check shouldn't wait
|
|
35
|
+
// on a Node cold start), but a request that arrives before warm-up
|
|
36
|
+
// finishes still gets a correct, just slightly slower, answer — `call()`
|
|
37
|
+
// -> `ensure_started()` shares the same lock and simply waits for
|
|
38
|
+
// whichever spawn (this one or its own) is already in flight.
|
|
39
|
+
{
|
|
40
|
+
let warm_worker = worker.clone();
|
|
41
|
+
std::thread::spawn(move || warm_worker.warm());
|
|
42
|
+
}
|
|
43
|
+
let srv = server::Server::bind(&socket_path, worker)?;
|
|
44
|
+
eprintln!("[failproofaid] listening on {}", socket_path.display());
|
|
45
|
+
|
|
46
|
+
let shutdown = Arc::new(AtomicBool::new(false));
|
|
47
|
+
install_signal_handler(shutdown.clone());
|
|
48
|
+
|
|
49
|
+
srv.run_until(shutdown)?;
|
|
50
|
+
Ok(())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/// Requests a clean shutdown (socket file removal, lock release via Drop)
|
|
54
|
+
/// on SIGTERM/SIGINT instead of dying mid-accept-loop — this is how a
|
|
55
|
+
/// systemd `stop`/launchd unload is expected to end the process.
|
|
56
|
+
fn install_signal_handler(shutdown: Arc<AtomicBool>) {
|
|
57
|
+
static SHUTDOWN_REQUESTED: AtomicBool = AtomicBool::new(false);
|
|
58
|
+
|
|
59
|
+
extern "C" fn handle_signal(_sig: libc::c_int) {
|
|
60
|
+
SHUTDOWN_REQUESTED.store(true, Ordering::Relaxed);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
unsafe {
|
|
64
|
+
libc::signal(
|
|
65
|
+
libc::SIGTERM,
|
|
66
|
+
handle_signal as *const () as libc::sighandler_t,
|
|
67
|
+
);
|
|
68
|
+
libc::signal(
|
|
69
|
+
libc::SIGINT,
|
|
70
|
+
handle_signal as *const () as libc::sighandler_t,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
std::thread::spawn(move || {
|
|
75
|
+
loop {
|
|
76
|
+
if SHUTDOWN_REQUESTED.load(Ordering::Relaxed) {
|
|
77
|
+
shutdown.store(true, Ordering::Relaxed);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
std::thread::sleep(std::time::Duration::from_millis(50));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
//! Resolves where failproofaid's runtime state lives on disk.
|
|
2
|
+
//!
|
|
3
|
+
//! User-scope only (per the plan: no elevation, everything under the
|
|
4
|
+
//! invoking user's home directory) — Linux and macOS only, matching the
|
|
5
|
+
//! rest of this crate.
|
|
6
|
+
|
|
7
|
+
use std::fs;
|
|
8
|
+
use std::io;
|
|
9
|
+
use std::os::unix::fs::PermissionsExt;
|
|
10
|
+
use std::path::PathBuf;
|
|
11
|
+
|
|
12
|
+
/// `~/.failproofai/run` — directory holding the socket and singleton lock
|
|
13
|
+
/// file. Overridable via `FAILPROOFAI_DAEMON_SOCKET`'s parent for local dev
|
|
14
|
+
/// (see `run_dir_override`), so a `bun run daemon:dev` loop never touches a
|
|
15
|
+
/// real installed daemon's state.
|
|
16
|
+
pub fn run_dir() -> io::Result<PathBuf> {
|
|
17
|
+
if let Some(socket_override) = std::env::var_os("FAILPROOFAI_DAEMON_SOCKET") {
|
|
18
|
+
let path = PathBuf::from(socket_override);
|
|
19
|
+
return path
|
|
20
|
+
.parent()
|
|
21
|
+
.map(PathBuf::from)
|
|
22
|
+
.ok_or_else(|| io::Error::other("FAILPROOFAI_DAEMON_SOCKET has no parent directory"));
|
|
23
|
+
}
|
|
24
|
+
let home = std::env::var_os("HOME")
|
|
25
|
+
.ok_or_else(|| io::Error::other("HOME is not set; failproofaid is user-scope only"))?;
|
|
26
|
+
Ok(PathBuf::from(home).join(".failproofai").join("run"))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
pub fn socket_path() -> io::Result<PathBuf> {
|
|
30
|
+
if let Some(socket_override) = std::env::var_os("FAILPROOFAI_DAEMON_SOCKET") {
|
|
31
|
+
return Ok(PathBuf::from(socket_override));
|
|
32
|
+
}
|
|
33
|
+
Ok(run_dir()?.join("failproofaid.sock"))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn lock_path() -> io::Result<PathBuf> {
|
|
37
|
+
Ok(run_dir()?.join("failproofaid.lock"))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/// Where the daemon tells the worker subprocess to listen — a second
|
|
41
|
+
/// socket, distinct from `socket_path()`, that only this process ever
|
|
42
|
+
/// connects to. Overridable via `FAILPROOFAI_WORKER_SOCKET` for local dev
|
|
43
|
+
/// (mirrors `FAILPROOFAI_DAEMON_SOCKET`'s override for the client-facing
|
|
44
|
+
/// socket).
|
|
45
|
+
pub fn worker_socket_path() -> io::Result<PathBuf> {
|
|
46
|
+
if let Some(socket_override) = std::env::var_os("FAILPROOFAI_WORKER_SOCKET") {
|
|
47
|
+
return Ok(PathBuf::from(socket_override));
|
|
48
|
+
}
|
|
49
|
+
Ok(run_dir()?.join("worker.sock"))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Creates the run directory (`0700`) if it doesn't exist yet. This
|
|
53
|
+
/// directory holds a socket that evaluates security-relevant decisions, so
|
|
54
|
+
/// a freshly created one is always locked to owner-only.
|
|
55
|
+
///
|
|
56
|
+
/// If the directory already exists, this deliberately does **not** chmod
|
|
57
|
+
/// it into shape — only a directory failproofaid created itself gets its
|
|
58
|
+
/// permissions enforced. `FAILPROOFAI_DAEMON_SOCKET` is a raw path (dev/test
|
|
59
|
+
/// override; see `run_dir`), and blindly tightening permissions on whatever
|
|
60
|
+
/// pre-existing directory its parent happens to resolve to would let a
|
|
61
|
+
/// misconfigured override silently reach out and chmod an unrelated shared
|
|
62
|
+
/// directory (worst case, something like `/tmp` itself). Failing loudly is
|
|
63
|
+
/// the safe default; a real deployment's `~/.failproofai/run` is always
|
|
64
|
+
/// failproofaid's own directory and will simply be created fresh the first
|
|
65
|
+
/// time, taking the safe branch below.
|
|
66
|
+
pub fn ensure_run_dir() -> io::Result<PathBuf> {
|
|
67
|
+
let dir = run_dir()?;
|
|
68
|
+
if dir.exists() {
|
|
69
|
+
let mode = fs::metadata(&dir)?.permissions().mode() & 0o777;
|
|
70
|
+
if mode != 0o700 {
|
|
71
|
+
return Err(io::Error::other(format!(
|
|
72
|
+
"run directory {} already exists with permissions {:o} (expected 0700) — \
|
|
73
|
+
refusing to modify a directory failproofaid did not create itself",
|
|
74
|
+
dir.display(),
|
|
75
|
+
mode
|
|
76
|
+
)));
|
|
77
|
+
}
|
|
78
|
+
return Ok(dir);
|
|
79
|
+
}
|
|
80
|
+
fs::create_dir_all(&dir)?;
|
|
81
|
+
fs::set_permissions(&dir, fs::Permissions::from_mode(0o700))?;
|
|
82
|
+
Ok(dir)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#[cfg(test)]
|
|
86
|
+
mod tests {
|
|
87
|
+
use super::*;
|
|
88
|
+
use std::sync::Mutex;
|
|
89
|
+
|
|
90
|
+
// std::env::set_var affects the whole process, so these tests must not
|
|
91
|
+
// run concurrently with each other or with other tests reading these
|
|
92
|
+
// vars.
|
|
93
|
+
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
|
94
|
+
|
|
95
|
+
#[test]
|
|
96
|
+
fn socket_override_takes_precedence_over_home() {
|
|
97
|
+
let _guard = ENV_LOCK.lock().unwrap();
|
|
98
|
+
unsafe {
|
|
99
|
+
std::env::set_var("FAILPROOFAI_DAEMON_SOCKET", "/tmp/example/daemon.sock");
|
|
100
|
+
}
|
|
101
|
+
assert_eq!(
|
|
102
|
+
socket_path().unwrap(),
|
|
103
|
+
PathBuf::from("/tmp/example/daemon.sock")
|
|
104
|
+
);
|
|
105
|
+
assert_eq!(run_dir().unwrap(), PathBuf::from("/tmp/example"));
|
|
106
|
+
unsafe {
|
|
107
|
+
std::env::remove_var("FAILPROOFAI_DAEMON_SOCKET");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#[test]
|
|
112
|
+
fn default_socket_path_lives_under_home_dot_failproofai_run() {
|
|
113
|
+
let _guard = ENV_LOCK.lock().unwrap();
|
|
114
|
+
unsafe {
|
|
115
|
+
std::env::remove_var("FAILPROOFAI_DAEMON_SOCKET");
|
|
116
|
+
std::env::set_var("HOME", "/home/example-user");
|
|
117
|
+
}
|
|
118
|
+
assert_eq!(
|
|
119
|
+
socket_path().unwrap(),
|
|
120
|
+
PathBuf::from("/home/example-user/.failproofai/run/failproofaid.sock")
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
#[test]
|
|
125
|
+
fn ensure_run_dir_creates_it_with_owner_only_permissions() {
|
|
126
|
+
let _guard = ENV_LOCK.lock().unwrap();
|
|
127
|
+
let tmp =
|
|
128
|
+
std::env::temp_dir().join(format!("failproofaid-paths-test-{}", std::process::id()));
|
|
129
|
+
unsafe {
|
|
130
|
+
std::env::set_var(
|
|
131
|
+
"FAILPROOFAI_DAEMON_SOCKET",
|
|
132
|
+
tmp.join("run").join("failproofaid.sock"),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
let dir = ensure_run_dir().unwrap();
|
|
136
|
+
let mode = fs::metadata(&dir).unwrap().permissions().mode() & 0o777;
|
|
137
|
+
assert_eq!(mode, 0o700);
|
|
138
|
+
fs::remove_dir_all(&tmp).ok();
|
|
139
|
+
unsafe {
|
|
140
|
+
std::env::remove_var("FAILPROOFAI_DAEMON_SOCKET");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#[test]
|
|
145
|
+
fn ensure_run_dir_refuses_to_touch_a_preexisting_directory_with_the_wrong_permissions() {
|
|
146
|
+
let _guard = ENV_LOCK.lock().unwrap();
|
|
147
|
+
let tmp = std::env::temp_dir().join(format!(
|
|
148
|
+
"failproofaid-paths-test-preexisting-{}",
|
|
149
|
+
std::process::id()
|
|
150
|
+
));
|
|
151
|
+
// Simulate FAILPROOFAI_DAEMON_SOCKET being pointed at some
|
|
152
|
+
// unrelated, already-existing directory (e.g. a misconfigured
|
|
153
|
+
// override resolving to a shared temp dir) — this must error
|
|
154
|
+
// instead of silently chmod-ing a directory failproofaid doesn't
|
|
155
|
+
// own.
|
|
156
|
+
fs::create_dir_all(&tmp).unwrap();
|
|
157
|
+
fs::set_permissions(&tmp, fs::Permissions::from_mode(0o755)).unwrap();
|
|
158
|
+
unsafe {
|
|
159
|
+
std::env::set_var("FAILPROOFAI_DAEMON_SOCKET", tmp.join("failproofaid.sock"));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
let result = ensure_run_dir();
|
|
163
|
+
assert!(result.is_err(), "expected an error, got {result:?}");
|
|
164
|
+
let mode_after = fs::metadata(&tmp).unwrap().permissions().mode() & 0o777;
|
|
165
|
+
assert_eq!(mode_after, 0o755, "permissions must be left untouched");
|
|
166
|
+
|
|
167
|
+
fs::remove_dir_all(&tmp).ok();
|
|
168
|
+
unsafe {
|
|
169
|
+
std::env::remove_var("FAILPROOFAI_DAEMON_SOCKET");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|