pub mod common;
pub mod local_debug;
pub mod local_files;
pub mod local_lock;
pub mod local_prefs;
pub mod local_serve;
pub mod local_status;
pub mod passthrough;
pub mod tailnet_devices;
pub mod tailnet_dns;
pub mod tailnet_invites;
pub mod tailnet_keys;
pub mod tailnet_logging;
pub mod tailnet_oauth;
pub mod tailnet_org;
pub mod tailnet_policy;
pub mod tailnet_posture;
pub mod tailnet_services;
pub mod tailnet_settings;
pub mod tailnet_users;
pub mod tailnet_webhooks;
pub fn entries() -> Vec<crate::registry::ToolEntry> {
let mut all = Vec::new();
all.extend(local_status::entries());
all.extend(local_prefs::entries());
all.extend(local_serve::entries());
all.extend(local_files::entries());
all.extend(local_lock::entries());
all.extend(local_debug::entries());
all.extend(passthrough::entries());
all.extend(tailnet_devices::entries());
all.extend(tailnet_dns::entries());
all.extend(tailnet_policy::entries());
all.extend(tailnet_keys::entries());
all.extend(tailnet_invites::entries());
all.extend(tailnet_users::entries());
all.extend(tailnet_settings::entries());
all.extend(tailnet_posture::entries());
all.extend(tailnet_webhooks::entries());
all.extend(tailnet_services::entries());
all.extend(tailnet_oauth::entries());
all.extend(tailnet_logging::entries());
all.extend(tailnet_org::entries());
all
}
#[cfg(test)]
mod tests {
use super::*;
use crate::registry::Registry;
#[test]
fn the_whole_table_forms_a_valid_registry() {
Registry::new(entries()).expect("the tool table is valid");
}
#[test]
fn every_tool_refuses_an_argument_it_does_not_take() {
let args = serde_json::json!({"not_an_argument": 1});
let open: Vec<&str> = entries()
.iter()
.filter(|entry| {
let schema = (entry.schema)().expect("every schema builds");
let schema = serde_json::Value::Object(schema.as_ref().clone());
crate::registry::unknown_argument_in(&schema, &args).is_none()
})
.map(|entry| entry.meta.name)
.collect();
assert!(open.is_empty(), "these accept any argument: {open:?}");
}
#[test]
fn every_tailnet_tool_ends_in_a_known_verb() {
use crate::meta::{Surface, TAILNET_VERBS};
for entry in entries() {
let name = entry.meta.name;
if entry.meta.surface() != Surface::Tailnet {
continue;
}
let verb = name.rsplit('_').next().expect("a name has a last word");
assert!(
TAILNET_VERBS.contains(&verb),
"`{name}` ends in `{verb}`, which is not one of {TAILNET_VERBS:?}"
);
assert!(
name.matches('_').count() >= 2,
"`{name}` needs a resource between the prefix and the verb"
);
}
}
}