c0re: dedupe chown_to_agent into lifecycle (argus #678)
This commit is contained in:
parent
0cf703a939
commit
ef968c11dd
3 changed files with 19 additions and 34 deletions
|
|
@ -162,24 +162,6 @@ fn extract_token(output: &str) -> Option<String> {
|
||||||
.map(str::to_owned)
|
.map(str::to_owned)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Best-effort chown `path` to the agent's container-local uid/gid.
|
|
||||||
/// Closes the gap where c0re (running as root on the host) writes
|
|
||||||
/// per-agent state files that the agent's non-root unix user then
|
|
||||||
/// can't read until the next container activation runs the chown
|
|
||||||
/// fixup in `harness-base.nix` (#673).
|
|
||||||
///
|
|
||||||
/// Silently no-ops when the container hasn't been built yet (passwd
|
|
||||||
/// file absent) or when the chown syscall fails — the activation
|
|
||||||
/// script remains the safety net.
|
|
||||||
fn chown_to_agent(name: &str, path: &Path) {
|
|
||||||
let Some((uid, gid)) = crate::lifecycle::agent_uid_gid(name) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if let Err(e) = std::os::unix::fs::chown(path, Some(uid), Some(gid)) {
|
|
||||||
tracing::debug!(%name, path = %path.display(), error = %e, "forge: chown to agent failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Canonical email address for a hive agent's Forgejo account.
|
/// Canonical email address for a hive agent's Forgejo account.
|
||||||
/// Must match the `user.email` set by `meta::render_flake` so commits
|
/// Must match the `user.email` set by `meta::render_flake` so commits
|
||||||
/// by the agent link back to their Forgejo profile page.
|
/// by the agent link back to their Forgejo profile page.
|
||||||
|
|
@ -353,7 +335,7 @@ async fn mint_and_persist_token(name: &str, path: &Path, scopes: &str) -> Result
|
||||||
std::fs::write(path, format!("{token}\n"))
|
std::fs::write(path, format!("{token}\n"))
|
||||||
.with_context(|| format!("write token to {}", path.display()))?;
|
.with_context(|| format!("write token to {}", path.display()))?;
|
||||||
let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600));
|
let _ = std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o600));
|
||||||
chown_to_agent(name, path);
|
crate::lifecycle::chown_to_agent(name, path, "forge");
|
||||||
tracing::info!(%name, path = %path.display(), "forge: persisted access token");
|
tracing::info!(%name, path = %path.display(), "forge: persisted access token");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,23 @@ pub fn agent_uid_gid(agent_name: &str) -> Option<(u32, u32)> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Best-effort `chown(path, agent_uid, agent_gid)`. Resolves the agent's
|
||||||
|
/// uid/gid via [`agent_uid_gid`] and shells out to `std::os::unix::fs::chown`.
|
||||||
|
/// Silently no-ops when the container isn't built yet (`None` from
|
||||||
|
/// [`agent_uid_gid`]) and logs at debug on chown syscall failure — the
|
||||||
|
/// activation script in `harness-base.nix` is the steady-state safety
|
||||||
|
/// net. Used by per-agent state writers in `forge` + `matrix` so the
|
||||||
|
/// agent can read the file without waiting for the next container
|
||||||
|
/// rebuild (#673).
|
||||||
|
pub fn chown_to_agent(name: &str, path: &Path, subsystem: &str) {
|
||||||
|
let Some((uid, gid)) = agent_uid_gid(name) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if let Err(e) = std::os::unix::fs::chown(path, Some(uid), Some(gid)) {
|
||||||
|
tracing::debug!(%name, %subsystem, path = %path.display(), error = %e, "chown to agent failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn validate(name: &str) -> Result<()> {
|
fn validate(name: &str) -> Result<()> {
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
bail!("agent name must not be empty");
|
bail!("agent name must not be empty");
|
||||||
|
|
|
||||||
|
|
@ -274,25 +274,11 @@ pub async fn ensure_user_for(
|
||||||
std::fs::write(&path, format!("{access_token}\n"))
|
std::fs::write(&path, format!("{access_token}\n"))
|
||||||
.with_context(|| format!("matrix: write token to {}", path.display()))?;
|
.with_context(|| format!("matrix: write token to {}", path.display()))?;
|
||||||
let _ = std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600));
|
let _ = std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600));
|
||||||
chown_to_agent(name, &path);
|
crate::lifecycle::chown_to_agent(name, &path, "matrix");
|
||||||
tracing::info!(%name, path = %path.display(), "matrix: registered user + persisted access token");
|
tracing::info!(%name, path = %path.display(), "matrix: registered user + persisted access token");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Best-effort chown `path` to the agent's container-local uid/gid.
|
|
||||||
/// Mirrors `forge::chown_to_agent` for the matrix access-token write —
|
|
||||||
/// closes the gap where c0re (root on host) writes a file the agent's
|
|
||||||
/// non-root unix user then can't read until the next activation runs
|
|
||||||
/// the harness-base.nix chown fixup (#673).
|
|
||||||
fn chown_to_agent(name: &str, path: &Path) {
|
|
||||||
let Some((uid, gid)) = crate::lifecycle::agent_uid_gid(name) else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if let Err(e) = std::os::unix::fs::chown(path, Some(uid), Some(gid)) {
|
|
||||||
tracing::debug!(%name, path = %path.display(), error = %e, "matrix: chown to agent failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a matrix account for `name` with the supplied `password`
|
/// Register a matrix account for `name` with the supplied `password`
|
||||||
/// and return the freshly-minted access token. Unlike [`ensure_user_for`],
|
/// and return the freshly-minted access token. Unlike [`ensure_user_for`],
|
||||||
/// the token is **not** persisted to disk — the caller is responsible
|
/// the token is **not** persisted to disk — the caller is responsible
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue