Skip to main content

max / makenotwork

3.9 KB · 108 lines History Blame Raw
1 //! Seal: the paths the systemd unit provisions are the paths the binary writes.
2 //!
3 //! `sando/deploy/bootstrap-node.sh` is the only writer of the makenotwork unit,
4 //! and the unit's sandbox makes every path outside `ReadWritePaths` and the
5 //! `StateDirectory` set read-only. So a constant in `makenotwork::constants`
6 //! that names a directory the unit does not provision is not a compile error
7 //! and not a failing request: it is an EPERM on a live box, at the moment a
8 //! creator adds an SSH key or the scanner spools an upload.
9 //!
10 //! Both directions are checked. A path the code names must appear in the
11 //! script, and every `StateDirectory` entry the script declares must be named
12 //! by a constant, so a directory provisioned for nothing is caught too.
13 //!
14 //! Run with: cargo test --test unit_paths_seal
15
16 use std::path::PathBuf;
17
18 use makenotwork::constants::{KEYS_REBUILD_MARKER, SCAN_SPOOL_DIR};
19
20 /// systemd puts every `StateDirectory=` entry under this root.
21 const STATE_DIRECTORY_ROOT: &str = "/var/lib/";
22
23 fn bootstrap_script() -> Option<String> {
24 let path: PathBuf = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
25 .join("../sando/deploy/bootstrap-node.sh")
26 .components()
27 .collect();
28 std::fs::read_to_string(path).ok()
29 }
30
31 /// The `StateDirectory=` entries the script declares, as absolute paths.
32 fn declared_state_directories(script: &str) -> Vec<String> {
33 script
34 .lines()
35 .filter_map(|line| line.trim().strip_prefix("StateDirectory="))
36 .flat_map(|value| value.split_whitespace())
37 .map(|entry| format!("{STATE_DIRECTORY_ROOT}{entry}"))
38 .collect()
39 }
40
41 #[test]
42 fn every_provisioned_path_the_code_names_is_written_by_bootstrap() {
43 let Some(script) = bootstrap_script() else {
44 // A checkout of the server crate alone has no sibling sando. Nothing to
45 // seal against, and failing here would only punish that layout.
46 return;
47 };
48
49 let declared = declared_state_directories(&script);
50 assert!(
51 !declared.is_empty(),
52 "bootstrap-node.sh declares no StateDirectory; the unit template moved"
53 );
54
55 for (name, path) in [
56 ("SCAN_SPOOL_DIR", SCAN_SPOOL_DIR),
57 ("KEYS_REBUILD_MARKER", KEYS_REBUILD_MARKER),
58 ] {
59 assert!(
60 declared.iter().any(|dir| path.starts_with(dir)),
61 "{name} = {path} is under no StateDirectory bootstrap-node.sh declares \
62 ({declared:?}). The sandbox makes it read-only, so the first write EPERMs."
63 );
64 }
65 }
66
67 #[test]
68 fn the_rebuild_marker_the_unit_watches_is_the_one_the_server_writes() {
69 let Some(script) = bootstrap_script() else {
70 return;
71 };
72
73 assert!(
74 script.contains(&format!("KEYS_MARKER=\"{KEYS_REBUILD_MARKER}\"")),
75 "the .path unit watches a different file than KEYS_REBUILD_MARKER ({KEYS_REBUILD_MARKER}); \
76 adding an SSH key would never reach sshd"
77 );
78 assert!(
79 script.contains("Unit=makenotwork-rebuild-keys.service"),
80 "the marker is watched by no unit, so nothing rebuilds authorized_keys"
81 );
82 let sudo_rebuild = script
83 .lines()
84 .find(|line| line.contains("NOPASSWD") && line.contains("rebuild-keys"));
85 assert!(
86 sudo_rebuild.is_none(),
87 "bootstrap installs a sudoers rule for rebuild-keys ({sudo_rebuild:?}); the unit's \
88 sandbox implies NoNewPrivileges, so sudo cannot run from inside it"
89 );
90 }
91
92 #[test]
93 fn every_declared_state_directory_has_a_constant_that_names_it() {
94 let Some(script) = bootstrap_script() else {
95 return;
96 };
97
98 for dir in declared_state_directories(&script) {
99 assert!(
100 [SCAN_SPOOL_DIR, KEYS_REBUILD_MARKER]
101 .iter()
102 .any(|path| path.starts_with(&dir)),
103 "bootstrap-node.sh provisions {dir} and no constant names it. Either the code \
104 that used it was deleted, or a constant drifted off the provisioned path."
105 );
106 }
107 }
108