diff --git a/pkgs/clan-cli/clan_lib/api/directory.py b/pkgs/clan-cli/clan_lib/api/directory.py index 1b723e716..8097bb906 100644 --- a/pkgs/clan-cli/clan_lib/api/directory.py +++ b/pkgs/clan-cli/clan_lib/api/directory.py @@ -69,7 +69,7 @@ def blk_from_dict(data: dict) -> BlkInfo: @API.register -def list_block_devices() -> Blockdevices: +def list_system_storage_devices() -> Blockdevices: """ List local block devices by running `lsblk`. diff --git a/pkgs/clan-cli/clan_lib/api/mdns_discovery.py b/pkgs/clan-cli/clan_lib/api/mdns_discovery.py index dfbaacb30..c121ef7ed 100644 --- a/pkgs/clan-cli/clan_lib/api/mdns_discovery.py +++ b/pkgs/clan-cli/clan_lib/api/mdns_discovery.py @@ -88,7 +88,7 @@ def parse_avahi_output(output: str) -> DNSInfo: @API.register -def list_mdns_services() -> DNSInfo: +def list_system_services_mdns() -> DNSInfo: """List mDNS/DNS-SD services on the local network. Returns: DNSInfo: A dictionary containing discovered mDNS/DNS-SD services. @@ -111,7 +111,7 @@ def list_mdns_services() -> DNSInfo: def mdns_command(args: argparse.Namespace) -> None: - dns_info = list_mdns_services() + dns_info = list_system_services_mdns() for name, info in dns_info.services.items(): print(f"Hostname: {name} - ip: {info.ip}") diff --git a/pkgs/clan-cli/clan_lib/api/tasks.py b/pkgs/clan-cli/clan_lib/api/tasks.py index 7ba8e58d2..fbe89c14e 100644 --- a/pkgs/clan-cli/clan_lib/api/tasks.py +++ b/pkgs/clan-cli/clan_lib/api/tasks.py @@ -33,7 +33,7 @@ def delete_task(task_id: str) -> None: @API.register -def run_blocking_task(somearg: str) -> str: +def run_task_blocking(somearg: str) -> str: """A long blocking task that simulates a long-running operation.""" time.sleep(1) ctx = get_async_ctx() diff --git a/pkgs/clan-cli/openapi.py b/pkgs/clan-cli/openapi.py index 720ed9385..441623a4b 100644 --- a/pkgs/clan-cli/openapi.py +++ b/pkgs/clan-cli/openapi.py @@ -29,6 +29,25 @@ COMMON_VERBS = { } +# !!! IMPORTANT !!! +# AVOID ADDING RESOUCRCES IN THIS LIST +# Think twice before adding a new resource. +# If you need a new resource, consider if it can be a sub-resource of an existing +# resource instead. +# If you need a new top-level resource, create an issue to discuss it first. +TOP_LEVEL_RESOURCES = { + "clan", # clan management + "machine", # machine management + "task", # task management + "file", # file operations + "secret", # sops & key operations + "log", # log operations + "generator", # vars generators operations + "module", # module (clan.service) management + "system", # system operations +} + + def is_verb(word: str) -> bool: return word in COMMON_VERBS @@ -60,12 +79,19 @@ def normalize_op_name(op_name: str) -> list[str]: def check_operation_name(op_name: str, normalized: list[str]) -> list[str]: verb = normalized[0] - _nouns = normalized[1:] + nouns = normalized[1:] warnings = [] if not is_verb(verb): warnings.append( f"""Verb '{verb}' of API operation {op_name} is not allowed. Use one of: {", ".join(COMMON_VERBS)} +""" + ) + top_level_noun = nouns[0] if nouns else None + if top_level_noun is None or top_level_noun.lower() not in TOP_LEVEL_RESOURCES: + warnings.append( + f"""Top-level resource '{top_level_noun}' of API operation {op_name} is not allowed. +Use one of: {", ".join(TOP_LEVEL_RESOURCES)} """ ) return warnings