audit-labs/audit-tools

A collection of scripts, queries, and other goodies you can use in an audit.

clone: git clone https://gitbay.org/audit-labs/audit-tools.git

319d5488bc0b7b0fadecca4d341a87d7c728f616

verified · cmc

author: Christian Cleberg <hello@cleberg.net> · 2026-07-29T05:15:07Z

feat: add Azure and Azure DevOps as coming-soon TUI placeholders

Show Azure (cloud, AWS counterpart) and Azure DevOps (source platform, GitHub
counterpart) as disabled "coming soon" entries in the platform menu. Make the
Platform runner fields optional so a placeholder needs only key/label/enabled.
Add a test asserting both are present and disabled.
 tui/README.md         |  6 +++---
 tui/platforms.py      | 25 ++++++++++++++++---------
 tui/tests/test_app.py | 13 +++++++++++++
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/tui/README.md b/tui/README.md
index 2b765fc..f9f51f9 100644
--- a/tui/README.md
+++ b/tui/README.md
@@ -4,9 +4,9 @@ A terminal UI that walks you through running an audit. It presents a platform
 menu, collects connection details and check selection, then runs the existing
 collectors with live progress.
 
-GitHub, GitLab, and AWS are supported. Adding a platform is a matter of writing
-a runner and a `Platform` descriptor in `tui/platforms.py` — the screens are
-platform-agnostic.
+GitHub, GitLab, and AWS are supported. Azure and Azure DevOps are stubbed in the
+menu as *coming soon*. Adding a platform is a matter of writing a runner and a
+`Platform` descriptor in `tui/platforms.py` — the screens are platform-agnostic.
 
 | Pick a platform | Choose checks | Watch it run |
 |---|---|---|
diff --git a/tui/platforms.py b/tui/platforms.py
index ee95288..9e7f7d6 100644
--- a/tui/platforms.py
+++ b/tui/platforms.py
@@ -31,14 +31,15 @@ class Field:
 class Platform:
     key: str
     label: str
-    subject: Callable[
-        [dict], str
-    ]  # (settings) -> audit subject shown on the run screen
-    fields: list[Field]
-    checks: list[Check]
-    default_selection: list[str]
-    output_dir: Callable[[dict], str]  # (settings) -> path
-    run: Callable[..., object]  # (settings, output_dir, selected_keys, on_event)
+    # The fields below drive the audit flow. A disabled ("coming soon")
+    # placeholder platform needs only key/label/enabled, so they default to
+    # empty and are never used while enabled is False.
+    subject: Callable[[dict], str] | None = None  # (settings) -> run-screen subject
+    fields: list[Field] = field(default_factory=list)
+    checks: list[Check] = field(default_factory=list)
+    default_selection: list[str] = field(default_factory=list)
+    output_dir: Callable[[dict], str] | None = None  # (settings) -> path
+    run: Callable[..., object] | None = None  # (settings, out, keys, on_event)
     enabled: bool = True
     note: str = field(default="")
 
@@ -183,7 +184,13 @@ AWS = Platform(
     run=_aws_run,
 )
 
-PLATFORMS = [GITHUB, GITLAB, AWS]
+# Coming soon — placeholders shown as disabled entries in the menu. Azure is the
+# cloud counterpart to AWS; Azure DevOps is the source-platform counterpart to
+# GitHub/GitLab.
+AZURE = Platform(key="azure", label="Azure", enabled=False)
+AZURE_DEVOPS = Platform(key="azure_devops", label="Azure DevOps", enabled=False)
+
+PLATFORMS = [GITHUB, GITLAB, AWS, AZURE, AZURE_DEVOPS]
 
 
 def prefill(f: Field) -> str:
diff --git a/tui/tests/test_app.py b/tui/tests/test_app.py
index ffa69e9..9fba7aa 100644
--- a/tui/tests/test_app.py
+++ b/tui/tests/test_app.py
@@ -165,3 +165,16 @@ def test_aws_navigation(monkeypatch):
             assert app.screen.query_one("#menu", Button).disabled is False
 
     _run(scenario())
+
+
+def test_azure_platforms_coming_soon():
+    async def scenario():
+        app = AuditApp()
+        async with app.run_test(size=(120, 40)) as pilot:
+            await pilot.pause()
+            for key in ("azure", "azure_devops"):
+                btn = app.screen.query_one(f"#{key}", Button)
+                assert btn.disabled is True
+                assert "coming soon" in str(btn.label).lower()
+
+    _run(scenario())