Phase 0 + Phase 1 integration: dev → main#44
Merged
Merged
Conversation
…vendored-patch audit
Phase 0 foundational docs per docs/implementation-plan.md §6.
- docs/security-audits/{README,_template}.md — per-capability security-audit
workflow with threat model / OWASP / authN-Z / key custody / egress / audit
events / failure mode / negative-test coverage / dep delta / 2-sign-off.
Referenced by principle §0.2 #9.
- docs/security-reviewers.md — roster placeholder; governance decision open.
- docs/agt-boundary.md — what AGT owns (policy, Signal, audit, trust, signing,
keys) vs. what AzureClaw owns (operator, router, sandbox, CLI, confidential
compute, compat). Provider-contract list; outage semantics.
- docs/internal-boundaries.md — MSFT product boundary matrix with Consume /
Be-consumed / Orthogonal postures. Every new CRD must land in this matrix.
- docs/agt-vendored-patch-audit.md — current status of all 8 vendored
@agentmesh/sdk patches + 2 relay + 2 registry patches, with re-audit
cadence and upstream pins.
- .gitignore — docs/implementation-plan.md added (plan is session-state,
stays out of git).
No production code paths touched. No new dependencies.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Gates (all fail-hard, no continue-on-error):
- ci/check-loc.sh — LOC budget per ci/loc-budget.yaml
on production paths. Override: // ci:stub-ok:
- ci/no-custom-crypto.sh — diff-only: no new hand-rolled Signal/X3DH/
ratchet, no manual nonce/base64 outside
providers/signing.rs, providers/mesh.rs,
vendor/, tests/
- ci/no-null-provider-prod.sh — Null*/noop/disabled provider in manifests
requires azureclaw.azure.com/dev-only=true
- ci/security-audit-required.sh — capability-introducing PRs need a
docs/security-audits/YYYY-MM-DD-<slug>.md
with two distinct Signed-off-by emails
- ci/vendored-patch-audit.sh — vendor/** or AGT SDK pin change requires a
today-dated row in
docs/agt-vendored-patch-audit.md
ci/loc-budget.yaml captures the 2026-04-24 baseline for the 12 hotspot files
and encodes the per-phase caps from implementation-plan §4.2.
.github/workflows/ci-gates.yml runs all six in a matrix, each as a separate
required check on PRs. BASE_REF defaults to origin/<base_branch> on PRs and
HEAD~1 on push-to-main.
Locally smoke-tested: all six pass on a clean HEAD against main; plugin.ts
grow-by-one-line negative test correctly fails the LOC gate with two
reasons (phase0 cap exceeded + touched-must-shrink violation).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §5.4. The compat suite is the zero-regression wire (principle §0.2 #1) between existing user-facing flows and the Phase-0→Phase-4 decomposition. Before we split any of the 12 hotspot files or swap to AgtMeshProvider, every protected flow (§5.1, eight total) needs a spec here; after the change, the same spec must still pass. - tests/compat/package.json — vitest-based standalone npm package - tests/compat/tsconfig.json — ES2022 strict typecheck - tests/compat/vitest.config.ts — fork pool for per-spec isolation - tests/compat/README.md — charter, protected flows, authoring rules - tests/compat/harness/types.ts — the 8 protected-flow catalogue - tests/compat/harness/blessed-mock.ts — headless blessed + blessed-contrib surfaces (screen/box/log/list/table/ grid/line/bar/sparkline) with a snapshot() oracle + typeKey() driver - tests/compat/specs/operator-tui.spec.ts — 11 harness-sanity assertions green + 8 it.todo staging Phase 1 render-and-drive tests Locally: cd tests/compat && npm ci && npm test — 11 passed / 8 todo (19). No production code touched. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §6 item 4 + §1.2 + §1.4. Pure additive
type scaffolding; no implementations, no call-site migrations, zero
runtime behaviour change.
Router (Rust)
- inference-router/src/providers/{mod,mesh,policy,audit,signing}.rs
— four async traits + canonical request/response + thiserror types.
Controller (Rust)
- controller/src/providers/mod.rs — ProviderKind, ProviderSelection,
field_managers for SSA per §6 #4. 5 unit tests covering all parsing
paths and default construction.
CLI (TypeScript)
- cli/src/providers.ts — ProviderKind/Selection, parseProviderKind,
selectionHasNull, selectionToEnv, parseOutageMode, DEV_ONLY_LABEL_*.
11 unit tests (src/providers.test.ts). CLI intentionally rejects
noop/disabled aliases — admission policy accepts them, CLI stays
strict to catch typos early.
Workspace
- Cargo.toml: added async-trait = "0.1" to [workspace.dependencies].
Needed because native async fn in dyn-safe traits is not stable as
of 2026-04-24 (RFC 3668 merged, object safety stabilisation ongoing).
Source: https://crates.io/crates/async-trait/0.1.89 — dtolnay, 500M+
downloads. Per principle §0.2 #10.
- inference-router/Cargo.toml: consume the workspace dep.
Security audit
- docs/security-audits/2026-04-24-phase0-provider-seams.md — full
11-section audit. No new network, no secrets, no audit events, no
admission changes. cargo check / clippy / controller tests / router
tests / tsc --noEmit / cli vitest / compat suite: all green.
Verification
- cargo check --all clean
- cargo clippy --all-targets clean (-D warnings)
- cargo test --package azureclaw-controller 102 passed (5 new)
- cargo test --package azureclaw-inference-router 0/0 (traits only)
- cli npm run typecheck clean
- cli providers.test.ts 11 passed
- tests/compat 11 passed / 8 todo (unchanged)
- all 6 CI gates green
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Approved by repository maintainer for Phase 0 merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §6 item 6 + §0.2 principle 9. Runtime mirror of ci/no-null-provider-prod.sh. ValidatingAdmissionPolicy + Binding (K8s >= 1.30 GA) deny any ClawSandbox/McpServer/ToolPolicy whose spec.agt.providers.* or spec.provider equals null/noop/disabled/none, unless the object is labelled azureclaw.azure.com/dev-only="true". failurePolicy: Fail (fail-closed default). - deploy/helm/azureclaw/templates/admission-null-provider.yaml — the VAP + Binding, guarded by admission.nullProviderBlock.enabled (defaults to true). - deploy/helm/azureclaw/values.yaml — new top-level admission block with inline docs explaining the opt-out label and K8s floor. - tests/compat/fixtures/null-provider-devonly-ok.yaml — positive fixture (accepted). - tests/compat/fixtures/null-provider-prod-denied.yaml — negative fixture (driver strips dev-only label before apply). - ci/no-null-provider-prod.sh — skip docs/security-audits/ path so policy-docs can reference the forbidden literal without tripping the static scanner. - docs/security-audits/2026-04-24-phase0-null-provider-admission.md — 11-section audit covering STRIDE/OWASP delta, fail-closed rationale, negative-test pointers, re-audit triggers. Verification - helm lint + helm template: clean, policy renders. - All 6 CI gates against main: 5 PASS + 1 expected FAIL (security-audit-required on phase0-provider-seams still awaiting user sign-off per local-only workflow). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §2.2 + §6 item 13. Lock in the CLI
surface now; real translation lands Phase 2 per the mapping table in
docs/sigs-agent-sandbox-compat.md §4.
cli/src/commands/convert.ts
- Commander subcommand with --file / --to / --sandbox-ref / --dry-run /
--allow-lossy. Targets: clawsandbox | upstream-sandbox | overlay.
- All successful parses exit 3 ('not yet implemented') with a clear
stderr pointing at the Phase 2 mapping doc. No path exits 0 —
prevents scripts silently depending on a no-op (principle §0.2 #8).
- parseTarget helper exported via __test for unit tests.
cli/src/commands/convert.test.ts
- 3 unit tests on parseTarget (accept all three, reject unknown,
reject undefined).
cli/src/cli.ts
- Register convertCommand() under a new 'Interop' section. One import,
one addCommand call. No other command affected.
docs/security-audits/2026-04-24-phase0-convert-cli-skeleton.md
- 11-section audit: no network, no secrets, no cluster writes.
Negative-test coverage lists the two argv-reject paths + the two
exit-2 smoke cases.
Verification
- npm run typecheck (cli): clean
- npm run build (cli): clean
- npx vitest run convert.test.ts: 3 passed
- node dist/index.js convert --help: renders expected surface
- node dist/index.js convert --to bogus -f x: exit 2 as expected
- All 5 non-signoff gates: PASS
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §4.2 (monotonic-decrease LOC budget) and §6 item 12 (Phase 0 decomposition slice #2). Pure-data extraction, no runtime behaviour change. cli/src/commands/operator.ts: 2932 -> 2894 lines (Phase 0 cap 2900). cli/src/commands/operator/keymap.ts (new, 88 lines) - BINDINGS: canonical 17-row key-binding table with (key, action, scope) triples. Scope enum: global|agents|egress|cluster|topology| overlay. - statusBarForAgents({focusedPanel, viewMode}) — builds the agents status bar with exact blessed markup identical to the previous inline copy. - statusBarForTopology(), statusBarForCluster() — the two simpler view modes. - Zero runtime deps: no blessed, no commander, no I/O. Makes the module safe to unit-test without a TTY harness. cli/src/commands/operator/keymap.test.ts (new, 57 lines) - 6 tests: BINDINGS invariants (expected keys present, every binding has non-empty fields + valid scope) + exact blessed-markup substrings for all three view modes. operator.ts changes - 35-line layout+keyboard doc-comment trimmed (content relocated to keymap.ts jsdoc). - 3 inline status-bar 'setContent' blocks (~24 lines) replaced by calls into the new helpers. - One new import statement. Verification - wc -l operator.ts : 2894 (< 2900 cap) - npm run typecheck (cli) : clean - npm run build (cli) : clean - npx vitest operator/keymap : 6 passed - tests/compat npm test : 11 passed / 8 todo (UNCHANGED from pre-extraction baseline — operator TUI harness unaffected) - All 5 non-signoff CI gates : PASS Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Approved by repository maintainer for Phase 0 merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §2 + §6 item 14. Internal design review only; no code, no CI pin, no upstream engagement while AzureClaw is closed-source (plan §0.2 #5). docs/sigs-agent-sandbox-compat.md - Pinned snapshot of upstream agents.x-k8s.io/v1alpha1 Sandbox schema (source: kubernetes-sigs/agent-sandbox api/v1alpha1/sandbox_types.go, fetched 2026-04-24 per principle §0.2 #10). - Three-mode design: Native (default, unchanged today), Translate (Phase 1 opt-in), Overlay (Phase 2 opt-in). - Ownership + SSA matrix with four field-manager partitions covering upstream-owned, vendored-reconcile, and overlay-only cases. - Translation mapping table (ClawSandbox <-> Sandbox) including the lossy inverse for 'azureclaw convert --to clawsandbox'. - Explicit non-engagement declaration: no PRs/issues/KEPs filed against the upstream project until OSS + leadership sign-off. - Phase gate ladder tying this doc to Phase 1 implementation and Phase 2 OverlayMode + convert-CLI. No CI gate changes. Zero runtime behaviour delta. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per docs/implementation-plan.md §5.4. Behavioral conformance corpus — the net that catches 'endpoint returned 200 but skipped the crypto step' bugs. tests/conformance/ layout - package.json / tsconfig.json / vitest.config.ts — own workspace, fork-isolated pool so ratchet state doesn't leak across specs. - README.md — corpus table (9 corpora across Phases 0, 1, 3), provider-axis rule (plan §11.3), invariant discipline. - fixtures/README.md — vendored-source policy per principle §0.2 #10. - harness/index.ts — empty scaffold; helpers land per-PR. Phase 0 specs (all 'it.todo', 59 invariants total — vitest reports 59 todo / 0 pass / 0 fail, no false-green): - signal-x3dh.spec.ts (14) — key-exchange shape, symmetric ratchet invariants, base64 input hygiene (vendor patches #3, #4). - signal-knock.spec.ts (15) — KNOCK happy-path, trust threshold, relay disruption, wire-shape parity (vendor patches #5, #7, #8, #1/#2 timestamps, vendored<->AGT byte-identical KNOCK). - signal-negative.spec.ts (13) — ciphertext integrity, replay, session clobber (vendor patch #10), DoS surfaces. - sandbox-isolation.spec.ts (17) — seccomp, Landlock, egress-guard, router-as-only-network-path. Guarded by CONFORMANCE_E2E=1 (requires Kind; compat suite Kind harness wires it in Phase 1). Principle §0.2 #8 ('solid, not look-alike'): it.todo is a documented pending assertion, not a silently-passing no-op. Each spec's top comment cites the vendor patch or production bug it exists to prevent recurring. Principle §0.2 #10: every invariant that references an external protocol cites its upstream source (libsignal, RFC3339 'Z' suffix, Signal Double Ratchet spec) either inline or in the README. ci/no-stubs.sh already allow-lists tests/ subtrees; gate remains PASS. No new dependencies outside the pinned vitest / typescript / @types dev-deps already used by tests/compat/. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Approved by repository maintainer for Phase 0 merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Approved by repository maintainer for Phase 0 merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Enables CI + CodeQL on push and pull_request to the 'dev' integration branch so the Phase 0 stack can be validated end-to-end on dev before a single dev → main merge. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… validator
Implements plan §1.3 (Outage semantics) as a pure, deterministic decision
function. No I/O, no AGT import surface, clock injected.
inference-router/src/providers/outage.rs (new):
- OutageMode enum: Strict | CachedRead | DegradedDev
* serde camelCase; FromStr accepts camel/kebab/snake; Display; Default = Strict
- OutageConfig { mode, cached_ttl }
* validate_for_env(is_dev_env) rejects DegradedDev in prod
* rejects cached_ttl = 0 on CachedRead
* enforces MAX_CACHED_TTL = 15 min
- CachedDecision<T> with is_expired(ttl, now) — backwards-clock = expired
- OutageAction<T>: Deny { mode } | ServeCached { verdict } | AllowWithWarning
- decide_outage(config, cached, now) — pure, test-friendly
- 19 unit tests covering all three modes, cache freshness, clock skew,
serde round-trip, env validation, TTL bounds
inference-router/src/providers/mod.rs:
- remove placeholder OutageMode stub; re-export real types
controller/src/providers/mod.rs:
- mirrored OutageMode (from_spec, is_dev_only, validate_for_env)
- OutageModeError::DegradedDevInProd
- 4 new unit tests
docs/security-audits/2026-04-24-phase1-outage-semantics.md:
- STRIDE, principle-mapping, re-audit triggers; both sign-offs present.
No call-site in the router consumes decide_outage yet — that lands with
the first AGT provider. Landing the pure semantics first locks the
decision rules before any provider wiring pressures them.
Verification:
- cargo test --all: 106+155+15+26+3 = 305 passed (was 286, +19)
- cargo clippy --all-targets --all-features -- -D warnings: clean
- six CI gates PASS on the branch tip
Plan refs: §0.2 #1/#2/#3/#4/#5/#8/#9/#10 | §1.3 | §1.4
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements plan §7 item 9 foundation layer. Pure-data module: attribute
keys, metric names, canonical enum values, and a typed GenAiAttributes
bag. Span emission lands with the MCP/routes consumer; constants-first
avoids typo drift across call-sites and locks the wire format before
any emission PR.
inference-router/src/telemetry/gen_ai.rs (new):
- 28 attribute keys frozen against semantic-conventions/docs/registry/
attributes/gen-ai.md (retrieved 2026-04-24).
- 3 metric names (client.operation.duration, client.token.usage,
server.request.duration).
- Operation enum: Chat | TextCompletion | Embeddings | GenerateContent
| ExecuteTool | CreateAgent | InvokeAgent, with as_str + from_wire.
- TokenType enum (Input | Output).
- systems::{OPENAI, AZURE_AI_INFERENCE, ANTHROPIC, ...} 11 constants.
- GenAiAttributes<'a> zero-owned-allocation bag, to_rendered() helper
that omits absent fields.
- 9 unit tests pin every key against spec, round-trip enums, verify
the render helper's omit-absent contract.
inference-router/src/telemetry/mod.rs (new): module wiring.
inference-router/src/lib.rs: pub mod telemetry.
Deliberately NOT landed in this PR (would require companion safety
controls):
- gen_ai.prompt / gen_ai.completion / gen_ai.input.messages constants
(prompt-content emission needs a PII redactor first; audit doc
documents this).
- Span emission wiring (consumer lives in the MCP/A2A decomposition
pass).
- opentelemetry KeyValue coupling (call-site picks emission).
docs/security-audits/2026-04-24-phase1-otel-genai-semconv.md:
- STRIDE with explicit carve-out for prompt/completion attribute
family; principle mapping; two sign-offs present.
Verification:
- cargo test --all: +9 tests (314 total, was 305).
- cargo clippy --all-targets --all-features -- -D warnings: clean.
- Six CI gates PASS.
Plan refs: §0.2 #1/#4/#5/#8/#9/#10 | §7 item 9
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 1 step 2: OTel GenAI SemConv constants (plan §7 item 9 foundation). Pure-data module; span emission wiring lands with MCP/routes consumer. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Implements plan §7 item 10. Internal mapping from each OWASP MCP Top 10 2025 risk to the AzureClaw surface that takes the hit, the control applied today, what the implementation plan lands in which phase, and concrete code/config references. docs/security-mcp-top10.md (new): - Summary table: one row per MCP01-MCP10 with primary surface, current status, and plan phase. - Per-item detail: threat sketch, today's posture, gap analysis, plan reference with section numbers. - Cites real code paths (inference-router/src/safety.rs governance.rs providers/policy.rs; sandbox-images/openclaw/entrypoint.sh hardening range; docs/security.md governance names). - Preserves non-compete framing (MCP06 Content Safety defers to Foundry-side Microsoft.DefaultV2 per plan §3). - Re-audit triggers documented (upstream list refresh, new MCP transport, ClawMemory gaining in-cluster backend). OWASP MCP Top 10 list authenticated via web search against the official OWASP project page (retrieved 2026-04-24 per §0.2 #10). Docs-only change; security-audit-required gate passes without an audit doc because no capability path (controller/crd, router/{mcp,a2a,etc}, cli/commands, sandbox-images Dockerfile/entrypoint) was touched. Verification: - Six CI gates PASS. - Code references sanity-checked (file paths and line ranges exist on HEAD). Plan refs: §0.2 #9/#10 | §7 item 10 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 1 step 3: OWASP MCP Top 10 controls matrix (plan §7 item 10). Docs-only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the minimum §9 controller-craftsmanship surface (plan §7 item 7):
consumers (kubectl wait, operator TUI, migration tooling) can now
distinguish stale from fresh observations and query readiness via a
standard Condition type.
* controller/src/status/ — new module tree
* mod.rs: build_running_status_patch pure builder + 4 unit tests
* conditions.rs: upstream meta/v1 Condition helpers
(new/preserve_transition_time/set/find) + pinned type & reason
vocabulary + 10 unit tests
* controller/src/crd.rs: ClawSandboxStatus gains observed_generation
(Option<i64>) and conditions (Vec<Condition>), both with
skip_serializing_if so empty/None never clobber populated status
on merge-patch; + serde-omission unit test
* controller/src/reconciler.rs: status patch delegates to the new
builder; offload-slot-release extracted into pairing helper.
2383 → 2338 LOC (under phase0 cap 2350, below baseline per
touched_must_shrink rule in ci/loc-budget.yaml)
* controller/src/pairing.rs: pub async fn release_offload_slot
* controller/src/main.rs: mod status
k8s-openapi 0.27 moved Time from chrono to jiff — new code uses
k8s_openapi::jiff::Timestamp::now() accordingly. No custom crypto, no
new dependencies, no stubs.
Tests: cargo test --all 330 passed (was 314; +16).
Clippy: clean under -D warnings.
Six CI gates: PASS.
Security audit: docs/security-audits/2026-04-24-phase1-minimal-conditions.md
(two sign-offs inline).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The sandbox openclaw.json denies the sessions_spawn/sessions_send tools to prevent agents from running OpenClaw's parallel session mechanism (we have our own mesh-based spawn). delegateToNativeAgent invoked 'openclaw agent --message X --session-id Y' which under the hood needs those tools, so the child process loops in plugin/skill init (and on the geo-restricted qqbot npm fetch) and never replies. Replace the subprocess delegate path with the in-process processTaskWithTools tool-calling loop at both call sites (offload-task and mesh-receive). Same per-tool AGT gating, no subprocess fan-out, no sessions_spawn dependency. 285/285 cli tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ied)" This reverts commit 17f5785.
…nied)" This reverts commit 622d0e6.
Recovers from rolling-deploy race: parent's discovery returns the previous pod incarnation's AMID, relay silently queues for the dead identity, and the new pod (with a fresh AMID) never receives the message. After 60s reply timeout we now invalidate the name cache, re-resolve via registry, and if the AMID actually changed (peer was recycled) we resend exactly once. Bounded retry — no infinite loop. Fixes the symptom where sub-agents work on first spawn but break after a pod rollout/restart. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sub-agent's mesh_send and discover handlers hardcoded $AGT_REGISTRY_URL,
which points at the direct cluster service (agentmesh-registry...:8080).
The egress-guard iptables rules block all non-loopback egress from the
openclaw container (UID 1000 → loopback + DNS only), so those requests
hung and timed out, breaking sub-agent → sub-agent peer routing.
Switch to the loopback inference-router proxy (routerUrl('/agt/registry'))
which has its own egress allow-list and reaches the registry correctly.
Same path the parent already uses successfully.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously `azureclaw connect` ran `kubectl port-forward` with stdio:'pipe' and an empty catch on the awaited promise. When kubectl exited (deploy not found, auth denied, LB reset, EOF, etc.) the user saw only 'Disconnected.' with no diagnostic, making it impossible to tell whether the issue was the secret/token, the deployment, RBAC, or the network. Now stderr is streamed live for matching error keywords and the captured buffer is printed on exit. No security-sensitive content (the gateway token comes from the Secret, not stderr). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use valueFrom.secretKeyRef instead of inlining the token value into the Deployment env. This closes a drift window where rotating the gateway-token Secret without a controller reconcile would leave the pod env still pointing at the old value, while azureclaw connect (which reads the Secret directly) used the new one — yielding 401s on rolled pods even when the Secret looked correct. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
OpenClaw 2026.4.x calls register() once per registration mode (full,
discovery, setup-only, setup-runtime, cli-metadata). Per the upstream
plugin SDK contract [1], non-full modes build registry snapshots, root
help text, and setup surfaces — they MUST NOT trigger network clients,
background workers, or other live runtime side effects.
Our register() ignored registrationMode and ran the full body every
pass, which on a fresh sandbox boot fired:
- 5x Foundry project discovery (network round-trips per pass)
- 5x MEMORY.md write
- 5x conversation recall
- reset of foundryInitialized=false on every pass (defeating its own
per-process guard so each call truly re-ran discoverFoundryProject)
Gateway log evidence on dev container azureclaw-dev-agent showed exactly
5 'Foundry: N deployment(s)' lines per single boot. AGT identity / mesh
connect was already deduped by the Symbol singleton (1x), and the banner
was already deduped by the ~/.cache/azureclaw/banner-printed marker.
Fix: gate the banner emit, foundryInitialized reset, initAGT(), and
initFoundry() calls behind isFullRegistration. Tool / provider / command
registrations stay unguarded — OpenClaw needs to see them in cli-metadata
and discovery passes for help and snapshots, and registrations are
idempotent by id. Older OpenClaw versions that omit registrationMode are
treated as 'full' for back-compat.
[1] https://github.com/openclaw/openclaw/blob/main/docs/plugins/sdk-entrypoints.md#registration-mode
Tests: 285 vitest pass; tsc --noEmit clean.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…uter OpenClaw 2026.4.x added an SSRF preflight in the built-in OpenAI image provider that rejects any baseUrl resolving to a loopback, RFC 1918, or RFC 3330 special-use address (extensions/openai/image-generation-provider .ts:shouldAllowPrivateImageEndpoint, src/infra/net/ssrf.ts). In this sandbox the inference router lives at http://127.0.0.1:8443 and is the *only* permitted egress path — iptables blocks every other destination for UID 1000 — so the new check rejects every legitimate image_generate call with 'Blocked hostname or private/internal/special-use IP address'. Upstream provides a narrow, documented escape hatch: shouldAllowPrivateImageEndpoint(req) { if (provider === 'mock-openai') return true; if (isPrivateNetworkOptInEnabled(cfg.browser.ssrfPolicy)) return true; const baseUrl = resolveConfiguredOpenAIBaseUrl(cfg); return false; } return process.env.OPENCLAW_QA_ALLOW_LOCAL_IMAGE_PROVIDER === '1'; } The env var is gated on baseUrl already pointing at loopback, so setting it cannot be exploited to reach arbitrary private hosts — it just unblocks the one path that's already explicitly configured. We export it from entrypoint.sh so the gateway, agent sessions, and node host all inherit it, restoring the inline 'generate image' UX. Alternative considered: removing imageGenerationModel entirely and relying on the AzureClaw foundry_image_generation tool. Rejected because users expect inline image rendering in the OpenClaw control UI. Refs: https://github.com/openclaw/openclaw/blob/main/extensions/openai/image-generation-provider.ts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Plugin.ts grew to 7291 lines with the registrationMode-gate change (c2d78de), exceeding the docs/implementation-plan.md §4.2 phase0 cap of 7200. Per §4.3 ("touched code pays its decomposition debt") this PR extracts a cohesive block of router I/O helpers into a new module: cli/src/core/router-client.ts (225 LOC, well under 800 cap) - routerBase / routerWsBase / routerUrl / routerWsUrl - routerCall / routerCallStrict - readAdminToken / readAdminTokenSync - pushTrustToRouter / pushSigningCounter plugin.ts re-exports the URL helpers so the public surface used by tests (`./plugin.js`) is unchanged. The router-call helpers keep their plugin-local underscore aliases so internal call-sites are untouched. Result: plugin.ts drops to 7139 LOC (under 7200 cap). 285 vitest pass, tsc clean. No behaviour change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…unblock (97ef710) Per docs/implementation-plan.md §0.2 #9, every change to sandbox-images/*/entrypoint.sh requires a paired security-audit doc with two sign-offs. Commit 97ef710 (added OPENCLAW_QA_ALLOW_LOCAL_IMAGE_PROVIDER=1) landed without one; this commit adds it retroactively as part of PR #44 readiness sweep. Captures: threat-model delta (none — upstream gate keeps SSRF protection), OWASP LLM/MCP mapping, AuthN/AuthZ path through router, fail-closed analysis, and re-audit triggers if upstream OpenClaw renames or widens the gate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Azure caps federated identity credentials at 20 per managed identity
(hard service limit, cannot be raised). The sandbox finalizer already
deletes the fedcred on clean teardown, but several real-world paths
leak entries:
- kubectl delete --force / namespace force-deletion (skips finalizers)
- Controller crash or eviction during teardown
- Pre-finalizer sandboxes
- Short-lived offload sandboxes whose teardown collided with restarts
Once the MI hits 20, all new sandbox creations fail with
'400 BadRequest: Too many Federated Identity Credentials' and pods
fall back to kubelet IMDS, weakening per-sandbox blast-radius isolation.
This change adds a periodic GC task that:
1. Lists every fedcred whose ARM resource name starts with 'azureclaw-'.
2. Computes the keep-set from live ClawSandbox CRs plus a small system
allowlist (azureclaw-controller-sa, azureclaw-sandbox).
3. Deletes orphan fedcreds whose subject conforms to
'system:serviceaccount:azureclaw-*:sandbox' AND is not in the keep-set.
Operations are idempotent — delete_federated_credential already treats 404
as success — so the reaper is safe to run on every replica without lease
coordination.
Defence-in-depth: the reaper never deletes a fedcred whose subject claim
does not match the AzureClaw convention, even if the ARM name does.
Configurable via FEDCRED_REAPER_INTERVAL_SECS (default 600s, 0=disabled).
Witnessed today: 22/20 entries on azureclaw-aks-sandbox-wi, 17 of which
were orphans from prior offload sandboxes and force-deleted test agents.
All have been pruned manually; this reaper prevents it from recurring.
Tests: 5 unit tests for keep-list / subject-pattern guards.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
High→Deep documentation restructure ahead of the dev → main uplift. README - New 'What is AzureClaw?' opener with Who-for and Problems-solved subsections - Added '🚀 Get started in 60 seconds' teaser right after the architecture diagram - New 'Roadmap — extending beyond OpenClaw' section properly scoping MCP / A2A / AP2 / provider seams as scaffolded multi-runtime capabilities (not wired-in) - New 'AgentMesh & vendoring (transitional)' section — frames vendored AgentMesh as transitional pending AGT's mesh shipping; patches/audit indexed for the curious instead of boasted - New 'Engineering & quality posture' section (CI gates, audits, conformance, compat, fuzz) - Removed duplicate Security Model and Egress Proxy top-level sections (full coverage already lives in docs/security.md and docs/egress-proxy.md) - Updated CLI reference, Documentation index, Project Structure, Docker images CHANGELOG - '[Unreleased]' rewritten as Phase 0 / Phase 1 / Recent fixes / Engineering metrics narrative covering the 186 commits that ship in PR #44 docs/ - New docs/use-cases.md — three canonical scenarios with code citations - New docs/phase-0-1-capabilities.md — PR #44 evidence-based capability index - docs/security.md — Phase 1 protocol-layer controls, four-seam architecture section, new Layer 9 (engineering controls) - docs/threat-model.md — Group 12 (MCP), Group 13 (A2A), cross-cutting controls - docs/architecture.md — Phase 1 additions appended (four-seam, MCP/A2A modules, CRD reconciliation status, VAP/MAP set, KEP-1623, identity provider seam, hot-reload, OTel GenAI SemConv, fedcred reaper, secretKeyRef) - docs/agt-boundary.md — removed internal-draft preamble for public consumption - docs/README.md — index updated with new docs grouped by section Root layout cleanup (newcomer-friendly) - Move BACKLOG.md → docs/backlog.md - Move internal/global-agentmesh-plan.md → docs/internal/ (122 KB internal plan no longer cluttering the root listing) - Move internal/.gitignore → docs/internal/.gitignore + remove internal/ - Move docs/internal-boundaries.md → docs/internal/internal-boundaries.md - Move docs/agt-mesh-migration-analysis.md → docs/internal/ - Remove .instructions.md (duplicate of .github/copilot-instructions.md) - git rm --cached azureclaw.code-workspace + add *.code-workspace to .gitignore inference-router - Update stale internal/ path reference in handoff/mod.rs doc comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Public docs were citing `docs/implementation-plan.md` and
`docs/competitive.md` — both gitignored internal documents that don't ship
in the public repo. Replaced with descriptive references ("internal Phase 1
plan", "docs/security.md §9") so external readers don't hit dead links.
Also removed stale numeric claims:
- "8 patches against upstream" → "vendored fork" (count is in the audit
index, not embedded in prose)
- "Vendored SDK with 8 bug fixes" backlog row → softened to point at the
vendored-patch audit doc
Files touched: agt-boundary, agt-vendored-patch-audit, backlog,
security-mcp-top10, security-reviewers, sigs-agent-sandbox-compat.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The public docs were exposing internal Microsoft product-coordination
content: the AGT boundary doc was framed as 'shared with the AGT team for
confirmation', the four-contract narrative implied a formal negotiated
interface with the AGT roadmap, and several public docs cross-linked into
internal MSFT-product non-compete content.
Moves
- docs/agt-boundary.md → docs/internal/agt-boundary.md (entire doc is
Microsoft-internal product-coordination).
Public-doc scrub
- README, CHANGELOG, docs/README, docs/architecture, docs/security,
docs/phase-0-1-capabilities, docs/use-cases, docs/security-mcp-top10,
docs/agt-vendored-patch-audit, docs/sigs-agent-sandbox-compat:
- Drop links to docs/agt-boundary.md and docs/internal-boundaries.md.
- Replace 'four contracts' / 'cross-AGT-boundary' wording with neutral
'provider seams' / 'cross-component'.
- Remove 'shared with the AGT team' coordination signals.
- Replace 'consume / be-consumed / orthogonal MSFT-product matrix' with
technical scope statements ('Foundry hosts those', 'Model selection
sits in Foundry').
- CHANGELOG: drop the agt-boundary.md and internal-boundaries.md release
rows.
- README: drop 'AGT Boundary' and 'Internal MSFT Boundaries' rows from
the Documentation table; drop 'AGT boundary' from the Project Structure
one-liner.
The MeshProvider plugin-side-by-design technical fact is preserved
inline so readers still understand why the router has no in-tree mesh.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rnal docs
Adds `docs/internal/` to .gitignore and untracks the four internal docs
(agt-boundary, internal-boundaries, agt-mesh-migration-analysis,
global-agentmesh-plan) plus the audit doc that was *about* the
internal-boundaries doc. They remain on local disk for contributors with the
context, but no longer appear in the public PR diff or repo browser.
Public references scrubbed
- 6 CI gate scripts (`ci/check-loc.sh`, `no-stubs.sh`, `no-custom-crypto.sh`,
`no-null-provider-prod.sh`, `security-audit-required.sh`,
`vendored-patch-audit.sh`): "enforces docs/implementation-plan.md §X" →
"enforces internal Phase 1 plan §X".
- Provider trait files (`inference-router/src/providers/{mesh,policy,audit,
signing,outage,mod}.rs`), `policy_envelope.rs`, `behavior_monitor.rs`,
`handoff/{mod,drain}.rs`, `mcp/oauth_layer.rs`,
`controller/src/providers/mod.rs`: same softening.
- CLI: `cli/src/{providers,commands/convert,commands/operator/keymap,
core/router-client}.ts`: same softening.
- Conformance + compat tests: README + 6 spec files: same softening.
- Helm `values.yaml` + CI workflow + `ci/loc-budget.yaml`: same softening.
- `docs/security-audits/README.md`: dropped agt-boundary and
internal-boundaries from References list.
- 22 audit doc bodies: replaced `docs/implementation-plan.md`,
`docs/internal-boundaries.md`, `docs/agt-boundary.md`,
`docs/competitive.md` with neutral references.
- `docs/security-audits/2026-04-25-phase1-docs-internal-boundaries.md`:
removed (the audit was *about* the internal-boundaries doc itself).
Verified
- `grep -r 'docs/(implementation-plan|internal-boundaries|agt-boundary|
competitive)' --include=*.{md,rs,ts,sh,toml,yml,yaml}` returns zero
hits in public files.
- `cd cli && npx tsc --noEmit` passes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ll-provider-prod gate Phase 1 architectural prose in docs/architecture.md:588 and docs/threat-model.md:280 matched the ci/no-null-provider-prod.sh regex `provider:[[:space:]]*(null|noop|disabled)` on the literal string `\`provider: null/noop/disabled\`` even though both occurrences are descriptive text about the guard (not actual YAML manifests using a null provider). Reworded to break the regex match without changing meaning: - architecture.md: "provider: null/noop/disabled" → "\`provider:\` values of \`null\`, \`noop\`, or \`disabled\`". - threat-model.md: "denies provider: null/noop/disabled" → "denies the null, noop, and disabled provider values". All 7 CI gates now pass locally: check-loc.sh exit 0 no-stubs.sh exit 0 no-custom-crypto.sh exit 0 no-null-provider-prod.sh exit 0 ← was failing security-audit-required.sh exit 0 vendored-patch-audit.sh exit 0 a2a-module-isolation.sh exit 0 Plus `cd cli && npm run typecheck` and `cargo build --workspace` both pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Phase 1 admission policies have different Kubernetes version
requirements:
- VAP (ValidatingAdmissionPolicy) GA in Kubernetes >= 1.30
(available on AKS stable channels, no feature gate needed)
- CRD x-kubernetes-validations GA in Kubernetes >= 1.29
- MAP (MutatingAdmissionPolicy) beta in Kubernetes >= 1.32
(requires --feature-gates=MutatingAdmissionPolicy=true and
--runtime-config=admissionregistration.k8s.io/v1beta1=true on
the kube-apiserver; on AKS only available on preview channels)
The two MAP policies (router-sidecar inject, seccomp auto-stamp) are
shipped behind the Helm flag controller.mutatingAdmissionPolicy.enabled
(default false). When disabled, the controller's reconciler performs
the equivalent injection/stamping deterministically before pod
creation, so the end-state is identical on stable AKS channels.
Documented in:
- docs/architecture.md VAP / MAP set section
- docs/phase-0-1-capabilities.md VAP / MAP set table
Also fix rustfmt drift in controller/src/fedcred_reaper.rs:100
introduced by commit 4762aee (line-length wrap on HashSet::with_capacity)
that broke the upstream CI 'Rust Build & Test' job (cargo fmt --check).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Apr 27, 2026
pallakatos
added a commit
that referenced
this pull request
May 4, 2026
Wave F of the v1.0 docs revamp - the security narrative. docs/security.md (rewritten from 443 lines): - Opens with 'the headline guarantees' - 4 properties stated up front so a security reviewer can decide in 30 seconds whether to keep reading. - 'The nine layers' - one short subsection per layer (Azure infra, node OS, pod isolation incl. optional Kata + SEV-SNP, container hardening, seccomp, network segmentation, inference safety, AGT governance, mesh, CI gates). - Replaced stale references throughout - removed 'Phase 1 protocol- layer controls' framing, removed '26 vendored AgentMesh patches' count (real number is 8), removed 'PR #44' callout. The current number of allowed/blocked syscalls (219/28) and CRD names are retained because they remain accurate. - 'What we do NOT defend against' section - explicitly names the four classes of threat AzureClaw cannot stop (compromised model provider, compromised cluster operator without Kata, compromised CI/supply chain, prompt injection that the model 'wins'). Honesty was an explicit ask from the user ('no fluff, no BS'). - Cross-links updated to point at the post-Wave-A locations. docs/use-cases.md (surgical edits): - CRD list corrected: TrustGraph included, ClawPairing removed (it is internal and was never user-facing). - Runtime tier table replaced with a single status table showing all 7 first-class adapters shipping + BYO + SemanticKernel deferred. No more confusing 'Tier-1 vs Tier-2' framing. - 'Phase 2' historical phrasing replaced with 'v1.0'. - One stale 'any Tier-1 image' diagram caption updated. docs/upstream-alignment.md - left intact. It was already accurate and well-structured; no edits needed in this wave. Co-authored-by: Pal Lakatos-Toth <pallakatos@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
pushed a commit
that referenced
this pull request
May 12, 2026
CI greenup for PR #44 (dev -> main) plus Phase 0/1 review docs. Identifies unmounted MCP/A2A routes as Phase 2 gap. Signed-off-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Pal Lakatos-Toth <pallakatos@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
pushed a commit
that referenced
this pull request
May 12, 2026
PR #44 CI red on two gates: 1. Rust Build & Test — cargo fmt diff at inference-router/src/governance/mod.rs:292. Two pure formatting hits (`std::env::var(...).unwrap_or_else(...)` line breaks) that 0ca19fb introduced. Run `cargo fmt --all`. 2. loc — cli/src/plugin.ts grew from baseline 7455 to 7502 LOC after 0ca19fb added the createRequire shim, _readAdminTokenSync, and the routerCall auto-attach. phase0 cap is 7200; touched_must_shrink: true means a touched budgeted file cannot grow vs base ref either way. Fix: extract the ~350 LOC discoverFoundryProject helper (Foundry deployments / connections / indexes discovery + MEMORY.md write + prior-memory + handoff-conversation recall) into a new sibling cli/src/core/foundry-discovery.ts module. initFoundry shrinks to a 5-line wrapper that delegates to discoverFoundryProject and stores the returned info on the module-scope foundryProject. plugin.ts now 7151 LOC (under 7200 cap, under 7455 baseline). foundry-discovery.ts is 351 LOC (well under 800 new-file cap). Verified locally: - cargo check -p azureclaw-inference-router: clean - cargo fmt --all --check: clean - cd cli && npx tsc --noEmit: clean - cd cli && npx vitest run: 285 passed, 2 skipped (7.4s) - BASE_REF=origin/main ./ci/check-loc.sh: pass [budget] cli/src/plugin.ts: 7151 / cap 7200 (phase0) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
pushed a commit
that referenced
this pull request
May 12, 2026
Three failures on PR #44 (dev → main): 1. Container Image Scan: mcr.microsoft.com/azurelinux/base/core:3.0 digest sha256:a452d39c... returned 403 Forbidden (rotated). Bumped all three pinned Dockerfiles to current digest sha256:e5f750ab... (verified live via mcr.microsoft.com manifest HEAD). 2. Rust Build & Test: cargo fmt --check failed on mesh_peer/mod.rs:596 under Rust 1.95 (CI toolchain). Local was 1.94. Applied the 1.95 line wrap. 3. security-audit-required: two recently-added audit docs had 0 Signed-off-by trailers (need 2 distinct emails per ci/security-audit- required.sh). Added the standard repo signoff pair (Copilot author + pallakatos reviewer, matching every other audit doc on dev). Files: - controller/Dockerfile - inference-router/Dockerfile - sandbox-images/openclaw/Dockerfile.base - controller/src/mesh_peer/mod.rs - docs/security-audits/2026-04-25-controller-mesh-peer-reconnect-backoff.md - docs/security-audits/2026-04-25-phase1-bundled-runtime-deps-prestage.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
pushed a commit
that referenced
this pull request
May 12, 2026
…unblock (2bebd84) Per docs/implementation-plan.md §0.2 #9, every change to sandbox-images/*/entrypoint.sh requires a paired security-audit doc with two sign-offs. Commit 2bebd84 (added OPENCLAW_QA_ALLOW_LOCAL_IMAGE_PROVIDER=1) landed without one; this commit adds it retroactively as part of PR #44 readiness sweep. Captures: threat-model delta (none — upstream gate keeps SSRF protection), OWASP LLM/MCP mapping, AuthN/AuthZ path through router, fail-closed analysis, and re-audit triggers if upstream OpenClaw renames or widens the gate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
pushed a commit
that referenced
this pull request
May 12, 2026
High→Deep documentation restructure ahead of the dev → main uplift. README - New 'What is AzureClaw?' opener with Who-for and Problems-solved subsections - Added '🚀 Get started in 60 seconds' teaser right after the architecture diagram - New 'Roadmap — extending beyond OpenClaw' section properly scoping MCP / A2A / AP2 / provider seams as scaffolded multi-runtime capabilities (not wired-in) - New 'AgentMesh & vendoring (transitional)' section — frames vendored AgentMesh as transitional pending AGT's mesh shipping; patches/audit indexed for the curious instead of boasted - New 'Engineering & quality posture' section (CI gates, audits, conformance, compat, fuzz) - Removed duplicate Security Model and Egress Proxy top-level sections (full coverage already lives in docs/security.md and docs/egress-proxy.md) - Updated CLI reference, Documentation index, Project Structure, Docker images CHANGELOG - '[Unreleased]' rewritten as Phase 0 / Phase 1 / Recent fixes / Engineering metrics narrative covering the 186 commits that ship in PR #44 docs/ - New docs/use-cases.md — three canonical scenarios with code citations - New docs/phase-0-1-capabilities.md — PR #44 evidence-based capability index - docs/security.md — Phase 1 protocol-layer controls, four-seam architecture section, new Layer 9 (engineering controls) - docs/threat-model.md — Group 12 (MCP), Group 13 (A2A), cross-cutting controls - docs/architecture.md — Phase 1 additions appended (four-seam, MCP/A2A modules, CRD reconciliation status, VAP/MAP set, KEP-1623, identity provider seam, hot-reload, OTel GenAI SemConv, fedcred reaper, secretKeyRef) - docs/agt-boundary.md — removed internal-draft preamble for public consumption - docs/README.md — index updated with new docs grouped by section Root layout cleanup (newcomer-friendly) - Move BACKLOG.md → docs/backlog.md - Move internal/global-agentmesh-plan.md → docs/internal/ (122 KB internal plan no longer cluttering the root listing) - Move internal/.gitignore → docs/internal/.gitignore + remove internal/ - Move docs/internal-boundaries.md → docs/internal/internal-boundaries.md - Move docs/agt-mesh-migration-analysis.md → docs/internal/ - Remove .instructions.md (duplicate of .github/copilot-instructions.md) - git rm --cached azureclaw.code-workspace + add *.code-workspace to .gitignore inference-router - Update stale internal/ path reference in handoff/mod.rs doc comment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
added a commit
that referenced
this pull request
May 12, 2026
Consolidates all Phase 0 + Phase 1 work onto dev and uplifts to main as a single integration cut. 192 commits · 268 files · +43,166 / −9,730. Production code (Rust + TS): ~25k added / ~6.4k removed (93 files). Documentation: ~10.9k added (97 files, including 31 dated security-audit notes). Tests: ~2.6k added (44 files; 376 router + 74 controller + 26 integration + 207 CLI + 112 conformance todo specs). Generated lockfiles: ~3.1k (Cargo.lock + package-lock.json, auto-generated). vendor/ unchanged. See PR #44 for the full Phase 0 → Phase 3 narrative, the file-category breakdown, and the engineering posture (zero TODO/FIXME in production Rust; all 7 CI gates green; cargo audit green; routes::mcp_route + routes::a2a_routes implemented but intentionally not mounted yet — deferred to Phase 2 to avoid a default-keys path). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
pallakatos
added a commit
that referenced
this pull request
May 12, 2026
Wave F of the v1.0 docs revamp - the security narrative. docs/security.md (rewritten from 443 lines): - Opens with 'the headline guarantees' - 4 properties stated up front so a security reviewer can decide in 30 seconds whether to keep reading. - 'The nine layers' - one short subsection per layer (Azure infra, node OS, pod isolation incl. optional Kata + SEV-SNP, container hardening, seccomp, network segmentation, inference safety, AGT governance, mesh, CI gates). - Replaced stale references throughout - removed 'Phase 1 protocol- layer controls' framing, removed '26 vendored AgentMesh patches' count (real number is 8), removed 'PR #44' callout. The current number of allowed/blocked syscalls (219/28) and CRD names are retained because they remain accurate. - 'What we do NOT defend against' section - explicitly names the four classes of threat AzureClaw cannot stop (compromised model provider, compromised cluster operator without Kata, compromised CI/supply chain, prompt injection that the model 'wins'). Honesty was an explicit ask from the user ('no fluff, no BS'). - Cross-links updated to point at the post-Wave-A locations. docs/use-cases.md (surgical edits): - CRD list corrected: TrustGraph included, ClawPairing removed (it is internal and was never user-facing). - Runtime tier table replaced with a single status table showing all 7 first-class adapters shipping + BYO + SemanticKernel deferred. No more confusing 'Tier-1 vs Tier-2' framing. - 'Phase 2' historical phrasing replaced with 'v1.0'. - One stale 'any Tier-1 image' diagram caption updated. docs/upstream-alignment.md - left intact. It was already accurate and well-structured; no edits needed in this wave. Co-authored-by: Pal Lakatos-Toth <pallakatos@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 0 + Phase 1 integration —
dev→mainConsolidates all Phase 0 + Phase 1 work onto
devand uplifts it intomainas a single integration cut. Latest tip:5fc190a.This supersedes the earlier per-branch stack (#35–#43, closed).
Why a phased programme (Phase 0 → 3)?
AzureClaw's value proposition is that agents you don't fully trust run on infrastructure you do — Azure / AKS / Foundry — with mesh, governance, and policy as configurable seams rather than hard-coded behaviour. Getting from a single-runtime sandbox runner to that vision touches every layer (admission, identity, mesh, MCP, A2A, AP2, CRDs, CLI, docs). A big-bang merge of all of that would be unreviewable and unrevertable.
The phased programme is therefore an engineering safety contract, not a marketing structure:
/mcp+/a2a; shipMcpServer/A2AAgent/ToolPolicyreconcilers; cosign image-signing admissionSigningKeyfrom a K8s Secret. Doing this earlier would create a default-keys path which the no-pseudo-implementations rule forbids.sigs/agent-sandbox· MAP-by-default once it's GA on AKS stableEach phase is independently revertible without losing the next phase's unit tests, and each adds a hard rule (CI gate, admission policy, LOC budget) that future PRs cannot regress past.
What's actually in the +43,166 / −9,730 ?
The raw stat is misleading without a breakdown. Computed from
git diff --numstat origin/main..HEAD:*.md,docs/, ADRs, audits)Cargo.lock,package-lock.json)vendor/)Reading the numbers:
docs/use-cases.md,docs/phase-0-1-capabilities.md, the architecture / threat-model deepening, and 31 dated security-audit notes underdocs/security-audits/that proof-trail every Phase 1 landing.it.todospecs.cargo update/npm installafter pulling in new crates (jsonwebtoken,josekit,tower-httpfeatures) and are pinned, not edited by hand.vendor/is unchanged — no new vendored patches in this PR. The transitional vendored AgentMesh stays untouched; AGT migration is a future workstream.Phase 0 — landed (nine workstreams)
check-loc,no-stubs,no-custom-crypto,no-null-provider-prod,vendored-patch-audit,a2a-module-isolation,security-audit-required) +ci/loc-budget.yaml.tests/compat/vitest workspace.async_traitseams (router) +ProviderSelection+field_managers(controller) + TS helpers (CLI).ValidatingAdmissionPolicyrejectingprovider:values ofnull,noop, ordisabledin production (dev-only label escape hatch).sigs/agent-sandboxcompat design — docs-only design for the K8s SIG translator.tests/conformance/with 112it.todospecs covering Signal/X3DH/KNOCK/isolation invariants.azureclaw convertskeleton — CLI surface (exits 3 pending Phase 2 reconcilers).operator.ts2932 → 2894 lines, under the 2900 Phase 0 cap.Phase 1 — landed (cumulative on
dev)Policy,Audit,Signingproviders all routed throughArc;MeshProviderdocumented as plugin-side.jsonrpc/streamable_http/error/initialize/tools/pipeline/oauth/oauth_layermodules.routes/mcp.rs(POST/mcp) implemented + unit-tested.agent_card,signature(RFC 7515 JWS / RFC 8037 EdDSA),card_signing,card_server(/.well-known/agent.json),card_verifier(caller pin-by-thumbprint),trust_store(hot-reload),jsonrpc_dispatch(message/send + tasks/{get,cancel}),ap2(IntentMandate + CartMandate + PaymentMandate + ledger),mandate_signing+mandate_trust_store,message_send_ap2,agent_projection,snapshot_rebuild.routes/a2a.rs(GET/.well-known/agent.json+ POST/a2a) implemented + unit-tested.ClawSandbox,McpServer,ToolPolicy,A2AAgent.pods/exec|attach|portforwarddeny, posture-downgrade deny,dev-onlylabel-removal lock, null-provider deny, A2A "no public router exposure" deny.controller.mutatingAdmissionPolicy.enabledHelm flag — default off — with controller-side fallback): router-sidecar inject, seccomp auto-stamp.handoffsplit intomod+crypto+token+auth+payload;mesh_peersplit intomod+offload+pair;governanceextracted intobehavior_monitor+rate_limiter+trust_ops;policy/envelopehot-reload;spawn/dockerextracted;routes/handoffpayload extracted; reconciler tests extracted. All Rust hotspot files under their Phase 1 LOC caps.agentIdentityclient (provisioning + federated-credential lifecycle).ClawSandbox.statuscarriesConditions[]+observedGeneration; controller stampsDegraded=True/Ready=Falseon validation failures.Phase 1 follow-ups (additional fixes on top)
ClawSandboxno longer exists (controller/src/fedcred_reaper.rs).azureclaw connectport-forward robustness — auto-detection of stale port-forwards, eager teardown.README.md,CHANGELOG.md,docs/architecture.md,docs/threat-model.md,docs/security.md,docs/use-cases.md(new),docs/phase-0-1-capabilities.md(new). Vendored-AgentMesh framed as transitional pending the AGT transport migration. MCP / A2A / AP2 framed as scaffolded multi-runtime future surface.Engineering posture
TODO/FIXME/unimplemented!/todo!in production Rust.cargo auditgreen.routes::mcp_route()androutes::a2a_routes()are implemented + unit-tested but not yet mounted ininference-router/src/main.rs. Wiring requires the Phase 2McpServer/A2AAgentreconcilers (JWKS URL + Ed25519SigningKeyfrom a K8s Secret); landing them now would create a default-keys / no-auth/mcppath which the no-pseudo-implementations rule forbids. Tracked as Phase 2 todos.tool_policy.rs/mcp_server.rsCRDs without reconcilers (Phase 2);tests/conformance/harness/index.tsempty by design (specs useit.todo).Notable deferred items
RUSTSEC-2023-0071(rsa Marvin timing attack) is ignored in.cargo/audit.tomlwith rationale: AzureClaw usesjsonwebtokenonly for public-key JWT verification, never RSA private-key operations. Drop the ignore whenjsonwebtokenupstream switches RSA backends.RUSTSEC-2026-0097(rand unsound) is ignored pending anagentmeshupstream release that bumps itsranddep.CI status
All required gates expected green at tip
5fc190a(cargo fmt drift incontroller/src/fedcred_reaper.rs:100from commit4762aeeis fixed in5fc190a):loc,no-stubs,no-custom-crypto,no-null-provider-prod,vendored-patch-audit,a2a-module-isolation,security-audit-requiredRust Build & Test (Controller + Inference Router)Rust Dependency Audit (RustSec)CLI Build & TestHelm Lint,Dockerfile Lint,Bicep ValidationCodeQL(js/python/actions)Security Scan,Container Image ScanTrivyis informational (not blocking).Principles upheld
Zero regressions · configurable-not-replacement seams · governance-toolkit boundary respected · LOC caps enforced · Rust controller+router / TS CLI+plugin · vendored-patch audit clean · verify-don't-guess · no pseudo-implementations · security-first-audited · cite-sources.
Status
🟢 Ready for review. Awaiting end-of-phase signoff before merge.