matrix: the agent's daemon pulls its linked accounts from bao itself
hive-matrix-daemon now learns which external matrix accounts it has from the swarm secret store, under the agent's own certificate, and the hive push chain for matrix is gone. The daemon lists swarm/agents/<agent>/matrix/ (the `list` its policy grants on its own metadata subtree), reads each account's homeserver from its credential, and brings the accounts up with their tokens from the store. Every two minutes it lists again and exits with 75 when the set of linked accounts changed; the unit restarts on 75 without counting a failure. A listed name whose credential reads as absent is skipped and logged once. At start it removes the matrix-token-<a> / matrix-account-<a>.json pairs a hive delivered (a sidecar marks a pair as delivered; a declared tokenFile keeps its token). Removed: CredentialNotice and the $SWARM.credential.* subject and NATS grant, the controller's publish and its queue precondition on the PUT route, hive-c0re's credential subscription arm and workers/credential.rs, priv_client::write_agent_matrix_token, hive-priv's WriteAgentMatrixToken and its helpers, and the daemon's state-dir account discovery. Kept: WriteAgentGithubToken and the external-forge path (WriteAgentExtraForgeAccount, extra_forges.rs) are untouched, and a declared matrixAccounts tokenFile is still read when the store has no token for that account. Refs #4348
This commit is contained in:
parent
e04616eb70
commit
97fb76ce99
22 changed files with 553 additions and 813 deletions
|
|
@ -202,6 +202,32 @@ impl SecretStore {
|
|||
}
|
||||
}
|
||||
|
||||
/// The keys stored directly under `path`, or none when nothing is.
|
||||
///
|
||||
/// A key ending in `/` is a directory below `path` rather than an object;
|
||||
/// keys come back as the store spells them, so a caller wanting objects
|
||||
/// filters those out.
|
||||
///
|
||||
/// Addresses `secret/metadata/<path>`, which the store ACLs separately
|
||||
/// from the `secret/data/<path>` that [`read`][Self::read] uses: a token
|
||||
/// that may read every object under a path is refused here until its
|
||||
/// policy grants `list` on the metadata path too.
|
||||
///
|
||||
/// **Only a 404 is "none"**, as in [`read_optional`][Self::read_optional]:
|
||||
/// the store answers a `LIST` on an empty directory with a 404, and a
|
||||
/// denial stays an error.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::Vault`] for anything that is not a 404: a denial, or an
|
||||
/// unreachable store.
|
||||
pub async fn list(&self, path: &str) -> Result<Vec<String>, Error> {
|
||||
match vaultrs::kv2::list(&self.inner, MOUNT, path).await {
|
||||
Ok(keys) => Ok(keys),
|
||||
Err(e) if is_absent(&e) => Ok(Vec::new()),
|
||||
Err(e) => Err(e.into()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Write `value` at `path`, creating a new version.
|
||||
///
|
||||
/// # Errors
|
||||
|
|
|
|||
|
|
@ -21,9 +21,18 @@ use crate::{
|
|||
/// `[A-Za-z0-9_-]`, which is what keeps one agent's name from addressing
|
||||
/// another agent's secret.
|
||||
pub fn account_path(agent: &str, account: &str) -> Result<String, Error> {
|
||||
let prefix = principal_prefix(Kind::Agent, agent)?;
|
||||
checked_segment("account", account)?;
|
||||
Ok(format!("{prefix}/matrix/{account}"))
|
||||
Ok(format!("{}/{account}", accounts_dir(agent)?))
|
||||
}
|
||||
|
||||
/// The directory every one of `agent`'s [`account_path`]s is under, in the
|
||||
/// form [`crate::SecretStore::list`] takes.
|
||||
///
|
||||
/// # Errors
|
||||
/// [`Error::PathSegment`] when `agent` contains anything but `[A-Za-z0-9_-]`.
|
||||
pub fn accounts_dir(agent: &str) -> Result<String, Error> {
|
||||
let prefix = principal_prefix(Kind::Agent, agent)?;
|
||||
Ok(format!("{prefix}/matrix"))
|
||||
}
|
||||
|
||||
/// The localpart `hive` acts as on the homeserver, and the `sender_localpart`
|
||||
|
|
@ -117,10 +126,9 @@ pub fn swarm_appservice_token_path() -> Result<String, Error> {
|
|||
|
||||
/// What an account's path holds: the token, plus the homeserver it belongs to.
|
||||
///
|
||||
/// The homeserver rides with the token rather than on the queue notice that
|
||||
/// triggers a delivery, because a notice is not persistence — re-delivering a
|
||||
/// credential has to reconstruct it, and the store is the only thing that keeps
|
||||
/// it.
|
||||
/// The homeserver rides with the token because the agent's daemon learns both
|
||||
/// from this one object: an account it finds by listing [`accounts_dir`] has
|
||||
/// no other place its homeserver is written down.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Credential {
|
||||
/// `glue-matrix-bao-token.nix` reads the store with
|
||||
|
|
|
|||
Loading…
Reference in a new issue