feat(cli): add azureclaw ingress command for inter-agent access control#23
feat(cli): add azureclaw ingress command for inter-agent access control#23johnsonshi wants to merge 491 commits into
azureclaw ingress command for inter-agent access control#23Conversation
Major TUI upgrade:
Security Controls panel (per-selected-agent, live polling):
Infrastructure: isolation, seccomp profile, NetworkPolicy,
iptables, forward proxy, admin auth, router readyz
Egress Control: mode (learning/enforcing), blocklist domain
count (52K+), allowlist count
Token Usage: requests (ok/err), input/output tokens,
total, average latency — parsed from Prometheus /metrics
AGT Governance: enabled, audit chain entries + integrity,
known agents count
Other improvements:
- Arrow key fix: manual ↑/↓/j/k wired to table.rows.select()
- Per-cluster view: shows kubectl context in header, --context flag
- Health indicators: ● green/yellow/red per agent in table
- Spinner animation during refresh (braille frames)
- Activity sparkline (agent count over time)
- Parallel security state + egress fetch per refresh
- Prometheus text parser for azureclaw_* metrics
- 3-column bottom layout: Security | Egress | Log+Sparkline
Endpoints polled per sandbox:
/readyz, /blocklist/status, /agt/status,
/egress/allowlist, /egress/learned, /metrics
+ kubectl: NetworkPolicy, router-admin-token secret
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Disable built-in keys/vi on tables — the table's internal handler and our screen.key handler both fired on the same keypress, causing double-movement and selection desync. Now only our moveSelection() drives ↑/↓/j/k navigation, which also correctly updates the security panel on each move. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously streaming (SSE) requests only recorded the request counter — no token usage, no latency. This was because the stream was piped directly to the client without inspection. Fix: - Inject stream_options.include_usage=true into request body so Azure OpenAI sends a final SSE chunk with usage data - Wrap byte stream with map() that inspects each chunk for 'usage' JSON field in SSE data lines - Record azureclaw_tokens_total (input/output) and azureclaw_inference_latency_seconds on the final chunk Prometheus /metrics now exposes all three metric families for both buffered AND streaming inference requests. 12/12 tests pass, clippy clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Egress panel now filters to the currently selected agent - Fetches both /egress/learned and /egress/allowlist per sandbox - Shows status column: P (pending/learned) vs ✓ (approved) - Pending domains sorted first, then approved - Approve/deny only works on pending domains (state=learned) - Added Shift+A shortcut: approve all learned domains for selected agent - Egress panel label shows agent name dynamically - Agent selection change (up/down in agents panel) refreshes egress view Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a cluster health overlay accessible via the 'c' key that shows: - Node table per pool (clawpool, system) with Ready/NotReady status - Live CPU/Memory usage per node from kubectl top (bar charts with color) - API server health with latency measurement - Resource quotas per namespace (if any exist) - PVC status (bound/pending counts) - Recent Warning events with severity color coding Implementation details: - ClusterHealth interface with nodes, quotas, PVCs, warnings - fetchClusterHealth() runs 6 kubectl queries in parallel via Promise.allSettled - Cluster overlay uses free-floating blessed boxes that toggle with agent detail panels - makeBar() renders colored bar charts (green <50%, yellow <80%, red >80%) - Header now shows cluster status indicator (API dot + node count) in both views - Status bar adapts to show relevant shortcuts per view mode Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ress Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Egress panel now uses blessed.list with tag support for per-item colors - Pending domains: yellow ● P with domain name - Approved domains: green ✓ A with domain name - Panel label shows legend: ●P=count ✓A=count - Updated moveSelection/tab/approve/deny to work with blessed.list Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fixed: was calling 'azureclaw rm' (doesn't exist) → now 'azureclaw destroy' - Replaced blessed.question (broken keyboard) with custom dialog - Dialog has [ Yes ] / [ Cancel ] buttons navigable with ←→/Tab/Enter - Mouse click on buttons also works - Escape dismisses the dialog Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Without -y, the destroy command's own confirmation prompt hangs when piped (stdio: pipe), exiting silently without destroying. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Reads azureclaw.azure.com/parent label from ClawSandbox CRDs - Controllers shown with ◆, sub-agents with ⤷ and └ tree indent - Sorted: controllers first, then sub-agents grouped under parent - Header shows ◆2 ⤷1 controller/sub-agent counts - Switched fetchSandboxes from jsonpath to full JSON parsing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sub-agents now display as: └ kernel-agent (sub:azureclaw-aks-t..) Restores Isolation column in table. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Hierarchy fix: - Sub-agents now sort directly under their parent controller - Orphaned sub-agents (parent deleted) go at the end Spawn wizard (n key): - Multi-field form: Name, Model, Isolation, Channel, TG Token, Egress - ↑↓ navigate fields, ←→ cycle options (isolation/channel/egress) - Enter edits text fields or advances, Tab launches immediately - Isolation: enhanced/standard/confidential (←→ cycle) - Channel: none/telegram/slack/discord (←→ cycle) - Telegram token field appears dynamically when telegram selected - Egress: learn mode on/off (←→ toggle) - Passes all flags to 'azureclaw add' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All global keyboard handlers (↑↓, tab, a/d/e/n/m/l/c/r) now check dialogOpen flag. Spawn, delete, and model dialogs set it on open and clear on close. Prevents arrow keys from moving the agent table while a dialog is active. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Spawn wizard rewrite: - Cleaner state machine: editing flag blocks nav during text input - Text input via editBox at bottom of dialog, saves reliably on submit - Auto-advances cursor after text entry - Dynamic fields: TG token only shown when telegram channel selected - Launch button at bottom, Enter to confirm - Esc to cancel at any time Header: simplified to just 'N agent(s) 3✓' — no controller/sub-agent legend Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
blessed's readInput callback is unreliable when reusing textboxes. Now creates a fresh textbox for each text field edit, uses submit/cancel events to capture the value, then destroys the textbox. Value is saved and displayed in the form after Enter. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Controller: - Fixed runtimeClassName: kata-vm-isolation → kata-mshv-vm-isolation (matches the RuntimeClass that AKS creates for KataMshvVmIsolation) - Updated test assertion CLI add command: - Pre-flight check when --isolation confidential: verifies nodes with label azureclaw.azure.com/pool=sandbox-kata exist - If no Kata nodes found: prints error + exact az aks nodepool add command using cached context (RG + cluster name) - Exits with code 1 instead of creating a pod that stays Pending forever Operator TUI spawn wizard: - Same pre-flight check when launching with confidential isolation - Shows error in activity log with remediation hint Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When --isolation confidential is used and no Kata nodes exist: - If cached context (RG + cluster) available: prompt to auto-provision - Runs az aks nodepool add with Standard_D4as_v6, AzureLinux, KataMshvVmIsolation, correct labels and taints - 10 min timeout for Azure provisioning - Proceeds to sandbox creation after nodepool is ready - Falls back to error message if no cached context Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When focused on agent table, pressing Enter: - Suspends blessed TUI (switches to normal terminal buffer) - Runs kubectl exec -it into the openclaw container - User gets full interactive shell (can run openclaw tui, etc.) - Typing 'exit' resumes the operator dashboard seamlessly - Activity log shows return confirmation Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two changes ensure sub-agents inherit their parent's isolation level: 1. Controller: exports SANDBOX_ISOLATION env var to pod, so the inference router knows the parent's isolation level at spawn time. 2. spawn.rs: uses parent's isolation as default (instead of 'enhanced') when the spawn request doesn't specify isolation. Also blocks downgrading — a confidential parent cannot spawn non-confidential sub-agents (returns error). This closes a security gap where a confidential Kata-isolated agent could spawn a sub-agent running on a standard container (different kernel, no VM boundary). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The embeddings endpoint was using the chat model (gpt-4.1) as the deployment name, causing Azure to reject the request with 'OperationNotSupported'. Now extracts the model from the request body (e.g. text-embedding-3-small) and uses it as the deployment, so embeddings route to the correct Azure OpenAI deployment. Strips azure/ and azure-openai/ prefixes from model names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Launches 'openclaw tui' instead of dropping to bash shell - Uses spawnSync to block — avoids async blessed interference - Proper terminal state save/restore (lsaveCursor/lrestoreCursor) - Direct process.stdin.setRawMode for clean PTY handoff - No more terminal corruption on return Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Uses 'openclaw agent --local --session-id operator-{name}' instead of
'openclaw tui' — conversation persists across connect/disconnect
- Reconnecting to the same agent resumes the same session
- Traps SIGINT in parent process so Ctrl+C only kills kubectl exec,
not the operator itself
- Treats SIGINT exit as normal return (session is preserved)
- Explicit terminal reset escape codes for cleaner buffer switch
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All dialog cleanup functions now defer dialogOpen=false by 50ms, preventing the global Enter handler from firing in the same event loop tick as the dialog's Enter handler. Fixes: pressing Enter on delete/spawn/model dialogs no longer accidentally triggers connect. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
openclaw agent --local requires -m flag and isn't interactive. Now drops to bash --login with a welcome banner showing agent info and instructions. User can run 'openclaw tui' for chat or use any other command. Type 'exit' to return to operator dashboard. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Removes the intermediate bash shell. Enter on an agent launches openclaw tui directly via kubectl exec. Quit the TUI to return to the operator dashboard — no 'exit' confusion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
README: - Added operator dashboard section with TUI screenshot and keybindings - Added azureclaw operator to CLI reference table - Updated confidential isolation to note sub-agent inheritance - Updated 'Add Agents' to note auto-provisioning of Kata nodepool docs/architecture.md: - Fixed RuntimeClass: kata-vm-isolation → kata-mshv-vm-isolation docs/security.md: - Added RuntimeClass name, isolation inheritance, auto-provisioning - Removed stale AKS preview feature reference Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pinned-Dependencies (0 → ~8): - Pin all GitHub Actions to SHA hashes (20 actions across 3 workflows) - Pin Docker base images to digest (mcr.microsoft.com/azurelinux/base/core:3.0) Token-Permissions (0 → 10): - Move security-events:write to job level in ci.yml - Move contents:write to job level in blocklist-refresh.yml - Move packages:write + id-token:write to job level in image-sign-sbom.yml - All workflows now have contents:read at top level only Vulnerabilities (5 → 10): - Upgrade prometheus 0.13 → 0.14 (drops protobuf 2.x CVE RUSTSEC-2024-0437) - Fix with_label_values API change in proxy.rs for prometheus 0.14 - cargo audit: 0 vulnerabilities Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…o-gen
Operator TUI:
- PTY-based agent connection with Ctrl+\ detach (node-pty)
- Parallel sandbox discovery (Promise.allSettled)
- Tiered refresh: sandboxes every 10s, security every 30s, cluster every 60s
- Mesh health indicators in header (relay/registry pod status)
- Topology view rewrite with fixed-width columns
- Trust scores filtered against live sandboxes (4 locations)
- Background refresh paused during agent connection
Trust cleanup on destroy:
- Router: DELETE /agt/trust/{agent_id} endpoint with admin auth
- Router: DELETE method support in sidecar forward
- Plugin: destroy handler cleans trust + AMID caches
Infrastructure:
- Auto-generate postgres credentials in azureclaw up (crypto.randomBytes)
- Remove placeholder secret from deploy/agentmesh.yaml (footgun)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add fetchAgtQuick() that runs /agt/status on non-TIER_DETAIL cycles, keeping trust scores, mesh counters, and audit entries updated every 10s instead of every 30s. Full security refresh still runs on TIER_DETAIL (30s) for egress, blocklist, metrics, and reputation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
10 diagrams covering: - Sandbox pod architecture (3-container layout, UID mapping) - Network access matrix (what each UID can reach) - Agent creation flow (CLI → Azure → K8s → Controller) - Controller reconciliation (all K8s resources created) - Sub-agent spawn flow (CRD → registry discovery) - E2E encrypted communication (KNOCK → X3DH → Double Ratchet) - Trust gate decision flow - Inference request flow (4 gates: governance, budget, auth, safety) - Egress control flow (iptables → proxy → blocklist → learn/enforce) - Full deployment flow (azureclaw up) - Multi-agent topology - Defense-in-depth layers (10 layers) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
up --dry-run now checks required CLI tools (az, kubectl, helm, docker) and validates Azure login + subscription before printing the plan. Interactive prompts (region, name, isolation, subscription selection) are still skipped in dry-run. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The flag was defined in config.ts and supported in the interactive flow but was missing from the update subcommand's option list and env mapping. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bug 1: Shift+L confirm popup lost focus to agent TUI on Enter. The screen-level Enter handler (connectToAgent) was the only key handler missing the dialogOpen guard, so it fired instead of the popup callback. Bug 2: Topology box content used .padEnd()/.length which measures JS string length, not terminal visual width. Replaced with fitVis/visualLen helpers that count emoji (surrogate pairs) as 2 cells, ensuring arrows and counters align correctly in each box. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MeshMetrics counters (messages_sent, messages_received) were declared but never incremented. The WebSocket relay bridge maintained its own local counters that were only logged at disconnect and never synced to the shared MeshMetrics. This caused /agt/status to always report 0 for mesh_messages_sent and mesh_messages_received, making the operator TUI topology view show ↑0 ↓0 for all agents. Fix: pass mesh_metrics Arc into the relay bridge and increment alongside the per-connection local counters. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sources: OISD small, URLhaus hostfile Generated: 2026-04-08T04:47:34Z
…le, escape during dialog
Three fixes in the operator TUI:
1. Garbled text on topology box lines with emoji: blessed's internal
width calculation doesn't match terminal rendering for 🔒/📖 emoji.
Replaced with blessed-tagged colored text ({green-fg}enforce{/},
{yellow-fg}learn{/}). Updated visualLen/fitVis to strip blessed tags.
2. Learn/enforce toggle (Shift+L) not confirming: blessed.question
widget doesn't handle input correctly when screen-level key handlers
exist. Replaced with a simple blessed.box + explicit y/escape key
handlers that self-cleanup via screen.unkey().
3. Pressing escape while confirm dialog was open would quit the app:
the quit handler (q/escape) was missing the dialogOpen guard.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When toggling learn/enforce via Shift+L, the mode was only changed in-memory on the router (POST /egress/learn or /egress/enforce). On pod restart the controller reconciled from the CRD which still had the original value, reverting the mode. Now enforceEgress/learnEgress also patch the ClawSandbox CRD's spec.networkPolicy.learnEgress field so the controller preserves the mode across restarts. The CRD patch is best-effort (.catch) so a toggle still works even if RBAC doesn't allow CRD writes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The .sqlx/ directory was gitignored, so cloners couldn't build the agentmesh-registry Docker image — COPY .sqlx ./.sqlx failed because the directory didn't exist. The .sqlx cache is required for sqlx offline mode (SQLX_OFFLINE=true) during Docker builds where no database is available. Fixes #17 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The ACR name was derived as baseName+'acr' (e.g. 'azureclawacr'), which is globally unique in Azure DNS. Different users deploying with the default baseName would hit 'AlreadyInUse' errors. Now the Bicep template appends uniqueString(resourceGroup().id) to produce a deterministic per-RG suffix (e.g. 'azureclaw3kf2a1'). The CLI reads the actual ACR name from Bicep outputs instead of computing it locally, with a fallback to acrLoginServer for older deployments. Fixes #16 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ncements (#18) * feat(router): add native AGT governance module (Phase 1) Add governance.rs wrapping the agentmesh crate (v3.0.2) with: - PolicyEngine integration with YAML policy loading from AGT_POLICY_DIR - TrustManager with sidecar-compatible clamping (±200 delta, 500 max new) - AuditLogger with hash-chain integrity verification - AgentIdentity with Ed25519 DID generation - BehaviorMonitor for burst/failure detection - RateLimiter with per-agent token bucket - GovernanceMetrics with atomic counters for eval stats - JSON builders matching existing /agt/* API contract - 14 unit tests covering all governance primitives Not yet wired into routes (Phase 2). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(router): wire native governance into all routes (Phase 2) Replace all SidecarProxy.forward() calls with direct governance module calls: - agt_evaluate: native policy evaluation with metrics tracking - agt_trust_*: native trust management with clamping - agt_audit/verify: native audit log with hash-chain integrity - agt_status: enriched status with eval counters, latency, DID - agt_reputation: local trust from governance instead of sidecar - agt_trust_update: native trust update with admin token auth - Inference routes: synchronous policy eval (no HTTP round-trip) - Spawn route: synchronous policy eval - Content flag reporting: direct governance call in safety.rs - Image generation: synchronous policy eval All sidecar.forward() calls eliminated. SidecarProxy kept as dead code (will be removed in Phase 3). Net -167 lines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor: remove AGT governance sidecar from infrastructure (Phase 3) Eliminate the Python governance sidecar (UID 1002) from all layers: Controller: - Remove governance_sidecar_image field and AGT_SIDECAR_IMAGE env - Remove agt-governance container injection (3rd container → 2 containers) - Remove AGT_SIDECAR_URL env var injection (router reads policies natively) - Keep AGT_POLICY_DIR + agt-data volume (router uses them directly) - Update tests: 2-container assertions, remove 8 sidecar-specific tests Sandbox image: - Remove COPY server.py and vendor/agt-wheels from Dockerfile - Replace sidecar startup in entrypoint.sh with trust dir setup - Set AGT_GOVERNANCE_ENABLED=true by default (native, always-on) - Pass AGT_POLICY_DIR and AGT_TRUST_THRESHOLD to router env Helm: - Remove agtGovernance values section (image, resources) - Remove AGT_SIDECAR_IMAGE env from controller deployment CLI: - Remove sidecar image from push.ts build targets - Remove sidecar build+push from up.ts - Remove agtGovernance helm --set values from deployment Pod structure is now: init:egress-guard → openclaw (UID 1000) → inference-router (UID 1001) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: delete sidecar.rs and update CLI tests (Phase 4-6 cleanup) - Delete inference-router/src/sidecar.rs (298 lines) - Remove SidecarProxy from AppState and all imports - Update push.test.ts: 5 images instead of 6, remove sidecar filter test - All 127 Rust tests + 159 CLI tests pass Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: Prometheus governance metrics, policy hot-reload, TUI enrichment, docs update Phase 5 — Enhancements: - Add 7 Prometheus governance metrics (policy evals, latency, trust, audit, content flags, behavior alerts, policy rules) to /metrics endpoint - Add policy YAML hot-reload: periodic mtime watcher on AGT_POLICY_DIR - Enrich operator TUI: security panel shows native governance stats (eval counts, deny rate, latency, behavior alerts, content flags) - Full AGT overlay now shows Policy Engine section with eval stats Phase 6 — Cleanup: - Delete sidecar-images/agt-governance/ (Dockerfile, server.py, tests) - Delete vendor/agt-wheels/ (~3.8 MB of Python wheels) - Update README.md: 2-container pod diagram, remove all sidecar references, update components table (5 images), security tables, project structure - Update plugin.ts: replace sidecar terminology with router/governance All 286 tests pass (74 controller + 53 router + 159 CLI), clippy clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: purge all sidecar references from active codebase Comprehensive cosmetic cleanup replacing 'sidecar' terminology with accurate descriptions across the entire codebase: - Mermaid diagrams: 3-container → 2-container pod layout, removed agt-governance (UID 1002, :8081) from all diagrams - Critical fix: plugin.ts port 8081 → 8443/agt/evaluate (4 instances) - Removed AGT Sidecar from GitHub issue templates - Updated BACKLOG, CONTRIBUTING, deployment skill, copilot instructions - Updated .instructions.md, agt-e2e-encryption skill - Cleaned comments in Rust (controller + router), CLI, infra files - Removed python-lint CI job, sidecar Makefile targets, CODEOWNERS entry - 36 files, net -45 lines Tests: 127 Rust + 159 CLI pass, clippy clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test: add 26 integration tests for AGT governance HTTP endpoints Exercise all /agt/* routes end-to-end via tower::ServiceExt::oneshot: - POST /agt/evaluate: policy allow, agent_id defaults, explicit context - GET /agt/trust: empty list, populated list, per-agent lookup - POST /agt/trust: no-auth, admin header, Bearer token, wrong token, self-trust rejection, score clamping - DELETE /agt/trust: auth enforcement, successful deletion - GET /agt/audit: empty state, entries after evaluations - GET /agt/audit/verify: empty chain, valid chain after 5 evaluations - GET /agt/status: all expected fields present, counters reflect evals - GET /agt/mesh/inbox: empty by default - GET /agt/reputation: graceful degradation without registry - Full lifecycle: evaluate → trust update → audit → verify → status - Trust CRUD: create → list → delete Infrastructure changes: - Add lib.rs to expose modules for integration tests - Update main.rs to use library re-exports - Add Default impls for WorkloadIdentityAuth, GovernanceMetrics, MeshInbox, MeshMetrics (clippy new_without_default) - Add Blocklist::is_empty() (clippy len_without_is_empty) All 153 Rust tests pass (74 controller + 53 router + 26 integration). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * ci: fix container scan runner + blocklist refresh permissions + cargo fmt - Container Image Scan: ubuntu-latest-xl → ubuntu-latest (xl runner unavailable in this org, causing perpetual queue timeout) - Added timeout-minutes: 30 to prevent runaway builds - Blocklist Refresh: added pull-requests: write permission so gh pr create can access the GraphQL API - Fixed cargo fmt import ordering in governance.rs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: symlink grammy into top-level node_modules for OpenClaw ≥2026.4 OpenClaw 2026.4.8 hoists Telegram bundle chunks (allowed-updates-*.js) to dist/ but grammy remains in extensions/telegram/node_modules/. Node's require() can't resolve it from the top-level context, causing a fatal crash when TELEGRAM_BOT_TOKEN is set. Fix: symlink grammy + @grammyjs from the extension's node_modules into the top-level node_modules after npm install. Conditional — no-ops when OpenClaw fixes their packaging upstream. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: symlink all 13 missing OpenClaw channel extension deps (openclaw#62749) OpenClaw 2026.4.x ships with stageRuntimeDependencies broken for npm installs — channel plugin deps (grammy, @buape/carbon, @slack/bolt, etc.) are only present under dist/extensions/*/node_modules/ but bundle chunks that import them are hoisted to dist/. Expand the previous grammy-only workaround to cover all 13 affected packages across Telegram (3), Discord (6), Slack (3), and Feishu (1) using a reusable link_pkg() helper. Each symlink is conditional (no-op when the package already exists at top level or when upstream fixes it). Reference: openclaw/openclaw#62749, openclaw/openclaw#61787 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add Foundry governance + fix policy YAML to match agentmesh schema - Rewrite azureclaw-default.yaml to use agentmesh PolicyProfile format (version, agent, policies[] with type/allowed_actions/denied_actions) instead of the custom condition/operator/value format that was silently failing to parse (missing 'version' field → 0 rules loaded) - Add foundry:* action patterns covering all 9 Foundry tool categories (web_search, code_execute, file_search, memory, image_generation, conversations, evaluations, deployments, agents) - Wire governance evaluation into foundry_proxy handler so Foundry API calls are no longer ungoverned — each request gets an action like foundry:memory:search_memories evaluated against the policy - Fix flaky trust integration tests (shared /tmp/agt/trust_scores.json) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: increment mesh_sessions counter on relay WebSocket connect The MeshMetrics.sessions counter was defined and read in /agt/status but never incremented — it always showed 0 regardless of active relay connections. Add fetch_add(1) when the relay WebSocket bridge successfully connects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: use record_success/record_failure for trust updates (tracks interactions) update_trust was calling set_trust() which sets the score but never increments the interaction counter. This caused the TUI to show 'interactions: 0' and 'No peer agents yet' even after sub-agents connected and exchanged messages. Now: new agents get set_trust(500) + record_success() (bootstrap + first interaction), subsequent updates use record_success/record_failure which properly bump interactions and apply the SDK's reward/penalty/ decay logic. The TUI topology view now shows real peer info. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(operator): enrich AGT panel + faster dev refresh AGT panel now shows: - Policy engine stats: rules loaded, evals, deny%, rate-limited count - Eval latency (µs avg) - Safety counters: behavior alerts + content flags (color-coded) - All existing: mesh topology, trust scores, audit chain, reputation Dev mode refresh: 3s default (was 10s), detail tier every cycle instead of every 3rd. Local Docker has negligible overhead so near-realtime operator view is practical. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: policy_rule_count reports actual rules, not file count load_policies_from_dir was incrementing total_rules per YAML file loaded, not per rule inside the file. With 1 file containing 10 rules, the dashboard showed '1 rules loaded'. Now parses the policies array from each file to count individual rules. Falls back to 1 if parsing fails. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: behavior alert reasons + dynamic rate-limit endpoint Behavior alerts now show WHY they fired instead of just a count: - TUI shows per-agent reasons (burst, consecutive failures, denials) - /agt/status includes behavior_alerts_detail array with agent, reasons, and current counters - Green ✓ when clean, red ⚠ with explanation when triggered - Rate-limited calls no longer count as capability denials (was causing false-positive behavior alerts from the inference rate-limit rule) Dynamic rate limits: - GET /agt/rate-limit — current token-bucket config - PUT /agt/rate-limit — update at runtime (admin token required) Body: { global_rate, global_capacity, per_agent_rate, per_agent_capacity } All fields optional, only provided fields change Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: exclude all rate-limit denials from behavior monitoring Both token-bucket (router-level) and policy-engine rate limits were feeding into behavior.record(false), inflating capability_denials and triggering false-positive behavior alerts. Rate limiting is normal flow control, not anomalous behavior. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: reputation diagnostics — log failures instead of spoofing identity - Vendor patch #7: submitReputation logs actual HTTP error instead of silent catch { return false } (both ESM and CJS chunks) - Router: log reputation submission failures in registry proxy - Plugin: check submitReputation return value, log accepted=true/false - Plugin: await recordMeshSession calls (were fire-and-forget) - Router: extract lookup_parent_amid helper, deduplicate from agt_reputation - Remove identity-spoofing proxy rewrite (security issue) - Remove self-review reciprocal submission (silently ignored by registry) Short-lived sub-agents: reputation doesn't matter (they die). Long-lived sub-agents: both registered, direct rating works. Parent feedback_count: needs diagnosis — SDK now surfaces the actual error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(operator): show dynamically spawned sub-agents as peers The peer filter required agents to exist in the sandboxes list, but sub-agents spawned via azureclaw_spawn are dynamic and not in that list. Now shows peers that are either known sandboxes OR recently active (lastSeen within 30 minutes), filtering out stale entries from old runs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(registry): feedback_count always 0 — wrong table name Root cause: handlers.rs submit_reputation() stores into 'reputation_feedback' (migration 001), but reputation.rs get_feedback_stats() queried 'reputation_feedbacks' (migration 006) — a table that was never written to. Fixed get_feedback_stats, get_tag_aggregates, and get_reputation_leaderboard to query the correct table. Converted from sqlx::query! (compile-time checked against stale .sqlx cache) to sqlx::query_as (dynamic) to avoid schema mismatch. Also added workspace.exclude for vendored crates so they can be built independently. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(operator): visual reputation — score bar, star rating, tag badges Reputation panel now shows: - Score bar (10 blocks, colored green/yellow/red) - Star rating from avg feedback (★★★★☆ style, 0-5 stars) - Tag badges from registry (#reliable×2 #fast_response×1) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * style: cargo fmt — fix formatting for CI Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Pal Lakatos-Toth <pallakatos@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…cleanup - Use REST API (gh api) instead of gh pr create (uses GraphQL which is blocked by enterprise GITHUB_TOKEN restrictions) - Add graceful fallback with warning if PR creation still fails - Clean up old blocklist branches before pushing new one - Force-push to reuse branch name if same-day refresh runs twice Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- codeql-action/upload-sarif upgraded from v3 (deprecated Dec 2026) to v4 (SHA c10b8064) - trivy-action comment corrected: SHA was already v0.35.0 (safe per supply chain advisory) but was labeled as 'master' - container-scan upload changed from if:success() to if:always() so SARIF results upload even when Trivy finds vulnerabilities - Removes 'Code scanning configuration error' on security tab Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Resolves ~52 Trivy CVEs from outdated tool binaries in the sandbox image. Remaining CVEs are from upstream OpenClaw dependencies (npm, hono, tar) which we cannot patch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…for vendor exclusion - npm audit fix: resolved defu prototype pollution (GHSA-737v) - Dockerfile: npm install -g npm@latest after Node.js install to fix tar/minimatch/glob CVEs in bundled npm - CodeQL config: exclude vendor/ source from analysis (upstream code) - CodeQL workflow: custom workflow with security-and-quality queries, replaces default setup that scanned vendor files - Remaining unfixable: lodash/xml2js (blessed-contrib transitive), op CLI Go deps (upstream 1Password), diff (tsdown transitive) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…conditionals
CLI (cli/src/):
- Remove 18 unused variables/imports across commands and tests
- Fix 4 useless conditionals: typeof always-defined var, || false, ? true : false
- Fix 2 trivially-true conditionals in dev.ts health loop
- Remove dead test helpers (createMockResponse/createMockRequest)
- Remove unused deploymentMap, gadgetMap, bold, hostname, threshold, padC
Vendor SDK (vendor/agentmesh-sdk/src/):
- Remove 11 unused imports (ValidationError, SessionError, CryptoError,
NetworkError, RateLimitError, hkdfSimple, deserializePrekeyBundle, etc.)
- Remove 2 unused functions (toArrayBuffer, serializeIntent)
- Fix 1 unused loop iteration variable (cap → removed from destructuring)
- Prefix 3 unused variables with _ (signatureBytes, messageBytes, reason)
- Fix 10 unused catch parameters across storage files (catch (error) → catch {})
All 159 tests pass, typecheck clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
is only set to true immediately before break, so the guard never evaluates to false. Remove the if-wrapper while keeping the variable for the status display line. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Greenfield builds were broken because .gitignore excluded files needed by Docker builds: - cli/package-lock.json (sandbox image) - vendor/agentmesh-sdk/package-lock.json (sandbox image npm install) - vendor/agentmesh-registry/frontend/package-lock.json (registry image npm ci) - vendor/agentmesh-registry/migrations/ (registry database setup) Added ! exception rules in .gitignore and force-added all files. Also fixes 3 AI code suggestions: - Rename misleading md5_hash() to hash_for_id() in blocklist.rs (uses SipHash) - Fix Kata nodepool SKU in add.ts to DC4as_v5 (matches up.ts confidential path) - Fix Go version comment in Dockerfile (1.25 doesn't exist, use 1.23) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…trol Add operator-facing CLI command and router endpoints for managing which agents can communicate with a sandbox via the AGT mesh: Router (inference-router/src/ingress.rs): - IngressAcl struct with per-agent block/allow lists and dynamic trust threshold - GET /ingress/status — overview (threshold, known agents, blocked/allowed counts) - GET /ingress/agents — all known agents with trust scores + ACL status - POST /ingress/block — block an agent from communicating - POST /ingress/unblock — remove agent from block list - POST /ingress/allow — explicitly allow (bypasses trust threshold) - GET /ingress/blocked — list blocked agents - GET /ingress/allowed — list explicitly allowed agents - POST /ingress/threshold — update trust threshold at runtime (0-1000) - All endpoints behind admin token auth (protected routes) - 3 unit tests for ACL logic CLI (cli/src/commands/ingress.ts): - Mirrors azureclaw egress UX pattern (Docker + K8s auto-detection) - --block/--unblock/--allow/--blocked/--allowed/--agents/--threshold/--status - Default (no flags) shows status overview with help commands Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
||
| // Default: show status | ||
| try { | ||
| const [status, blocked, allowed, agents] = await Promise.all([ |
|
|
||
| // Default: show status | ||
| try { | ||
| const [status, blocked, allowed, agents] = await Promise.all([ |
|
Thanks for this @johnsonshi — the ingress CLI + router pattern mirrors egress nicely and the coverage is solid. A few items to address before merge: CI failureThe Rust build is failing. Likely cause: TOCTOU race in IngressAcl
Merge conflictThe PR conflicts with main on Nit: enriched vec moved after useIn let count = enriched.len();
Json(serde_json::json!({ "agents": enriched, "count": count, ... }))OverallThe design is clean — 8 endpoints, mirrors egress UX, proper admin auth on K8s. Once the build is green and the race is addressed, this is good to go. 👍 |
Summary
Adds an operator-facing
azureclaw ingressCLI command and corresponding router endpoints for managing which agents can communicate with a sandbox via the AGT mesh.Motivation
Inter-agent communication controls (KNOCK trust threshold, per-agent block/allow,
mesh:receivepolicy) exist in the router but are only configurable via env vars (AGT_TRUST_THRESHOLD,AGT_TRUSTED_PEERS) and policy YAML. There's no operator-friendly way to manage them at runtime — unlikeazureclaw egresswhich has a full CLI.Changes
Router (
inference-router/src/ingress.rs):IngressAclstruct with per-agent block/allow sets and dynamic trust thresholdGET /ingress/status— overviewGET /ingress/agents— all known agents with trust + ACL statusPOST /ingress/block/POST /ingress/unblock— block/unblock agentsPOST /ingress/allow— explicitly allow (bypasses threshold)GET /ingress/blocked/GET /ingress/allowed— list ACL entriesPOST /ingress/threshold— update trust threshold at runtime (0–1000)CLI (
cli/src/commands/ingress.ts):azureclaw egressUX (Docker + K8s auto-detection, admin token auth)--block,--unblock,--allow,--blocked,--allowed,--agents,--threshold,--statusTesting
cargo test --package azureclaw-inference-router— 29 tests pass (26 existing + 3 new ingress)npx tsc --noEmit— typecheck cleannpx oxlint --deny unused— 0 errorsnpx vitest run— 159 tests passUsage