Merge nucleic/rustic-meadow-koala-wtwq into dev

This commit is contained in:
2026-07-27 02:26:30 -07:00
parent 1d6b240dbb
commit 195ac00d0b
4 changed files with 457 additions and 25 deletions
+56 -6
View File
@@ -105,6 +105,20 @@ enum Event {
},
#[serde(rename = "dropped", rename_all = "camelCase")]
Dropped { seq: u64, ts: u64, count: u64 },
/// An operator lever nash was asked to act on (docs/NASH.md §4.3). `action` is
/// `ignored` for a lever that arrived through the environment — the channel the
/// observed process controls, which nash refuses — and `honored` for one the
/// trusted policy file set. Either way it becomes a feed row, so a shell going
/// dark is a visible event rather than an absence of events.
#[serde(rename = "policy", rename_all = "camelCase")]
Policy {
seq: u64,
ts: u64,
lever: String,
value: String,
action: String,
note: String,
},
}
/// The pipeline stage an exec event belongs to (docs/NASH.md §5.1). `id` is the same
@@ -181,17 +195,31 @@ fn parse_hook_url(url: &str) -> Option<HookUrl> {
}
impl Config {
fn from_env() -> Option<Self> {
if std::env::var("NUCLEIC_SHELL_CAPTURE").as_deref() == Ok("off") {
/// Read transport config from the environment.
///
/// `require_observation` comes from the trusted policy file (docs/NASH.md §4.3) and
/// closes the quietest bypass there was: `NUCLEIC_SHELL_CAPTURE=off`, or simply
/// `env -u NUCLEIC_SHELL_HOOK_URL …`, used to leave nash running as an ordinary
/// shell that reported nothing — no fallback event, no trace, from a process that
/// merely rewrote its own environment. Under the policy, `off` from the environment
/// is refused and a missing transport falls back to `fallback_spool`, which the
/// host's spool drain already collects. An operator who genuinely wants a surface
/// silent turns the policy's `require_observation` off (or omits the file) rather
/// than setting a variable the agent could have set for them.
fn from_env(require_observation: bool, fallback_spool: &Path) -> Option<Self> {
if std::env::var("NUCLEIC_SHELL_CAPTURE").as_deref() == Ok("off") && !require_observation {
return None;
}
let socket = std::env::var_os("NUCLEIC_SHELL_SOCKET").map(PathBuf::from);
let hook_url = std::env::var("NUCLEIC_SHELL_HOOK_URL")
.ok()
.and_then(|u| parse_hook_url(&u));
let spool = std::env::var_os("NUCLEIC_SHELL_SPOOL").map(PathBuf::from);
let mut spool = std::env::var_os("NUCLEIC_SHELL_SPOOL").map(PathBuf::from);
if socket.is_none() && hook_url.is_none() && spool.is_none() {
return None;
if !require_observation {
return None;
}
spool = Some(fallback_spool.to_path_buf());
}
Some(Self {
socket,
@@ -716,10 +744,14 @@ fn flusher(cfg: Config, shell_id: String, parent_shell: Option<String>, rx: mpsc
/// configured, installs the recording gate into brush-core and starts the
/// flusher thread. Returns whether observation is active.
///
/// `require_observation` / `fallback_spool` come from the trusted policy file
/// (docs/NASH.md §4.3): with it set, an environment that says "don't observe"
/// no longer wins, because that environment belongs to the observed process.
///
/// Also threads shell lineage: reads `NUCLEIC_SHELL_PARENT` as this shell's
/// parent and re-exports it as this shell's own id for child shells.
pub fn install_from_env() -> bool {
let Some(cfg) = Config::from_env() else {
pub fn install_from_env(require_observation: bool, fallback_spool: &Path) -> bool {
let Some(cfg) = Config::from_env(require_observation, fallback_spool) else {
return false;
};
@@ -759,6 +791,24 @@ pub fn flush_sync() {
}
}
/// Records an operator-lever event (docs/NASH.md §4.3): a lever nash refused to take
/// from the environment (`action: "ignored"`) or one the trusted policy set
/// (`action: "honored"`). Not flushed here — callers that are about to `exec` away
/// call [`flush_sync`] themselves, and the ordinary path flushes at exit.
pub fn report_policy(lever: &str, value: &str, action: &str, note: &str) {
let Some(obs) = OBSERVER.get() else { return };
obs.send(Event::Policy {
seq: obs.seq(),
ts: now_millis(),
lever: lever.to_string(),
// Bounded like any other agent-authored string on this path: the value is
// whatever the command line put there.
value: value.chars().take(512).collect(),
action: action.to_string(),
note: note.to_string(),
});
}
/// Records a compat-fallback event (docs/NASH.md §4.1): nash is about to
/// re-exec the real bash because it could not handle `input`.
pub fn report_fallback(reason: &str, input: &str) {