Skip to content

phase2-migrate-mode-switch: azureclaw migrate mode-switch CLI (Phase 2 S9.1) - #62

Merged
Pal Lakatos-Toth (pallakatos) merged 1 commit into
devfrom
phase2-migrate-mode-switch
Apr 28, 2026
Merged

Pal Lakatos-Toth (pallakatos) merged 1 commit into
devfrom
phase2-migrate-mode-switch

Conversation

@pallakatos

Copy link
Copy Markdown
Collaborator

Operator-facing tool to flip a ClawSandbox between the four upstream-compatibility modes that S8 (#57) shipped on the controller side. Drives the day-zero adoption story: take an existing upstream sigs.k8s.io/agent-sandbox Sandbox and bolt AzureClaw governance on without rewriting the YAML.

Real workflow this unlocks

# operator already has an upstream Sandbox CR called 'legacy-agent';
# wraps it with AzureClaw governance:
$ azureclaw migrate to-overlay legacy --upstream-ref legacy-agent
  legacy: native → overlay (upstream sandbox 'legacy-agent')
  ✓ patched

# later: drop the upstream, return to native AzureClaw
$ azureclaw migrate from-overlay legacy
  legacy: overlay → native
  ✓ patched

Subcommands

Command Effect
migrate to-overlay <name> --upstream-ref <upstream> OverlayMode (governance overlay only; upstream owns Pod)
migrate from-overlay <name> Revert to native (controller resumes Pod ownership)
migrate to-translate <name> SandboxClaim translate mode
migrate to-observe <name> Status-mirror mode
migrate to-native <name> Alias for native (off)

All five accept --namespace, --dry-run, --format human|json.

Reuse-first (§0.2 #11)

  • No new CRD field, no controller change. OverlayMode reconciler logic shipped in S8 (phase2-overlaymode: sigs/agent-sandbox OverlayMode reconciler branch #57); this is the operator-facing tool that drives it.
  • Pure helpers (validateMode, buildModePatch, readCurrentMode, summariseTransition, modeDisplay) — unit-testable without a cluster.
  • JSON merge patch (RFC 7396) with explicit null for upstreamSandboxRef removal — matches Option<...>::skip_serializing_if round-trip on the controller side. Asserted directly in tests.

Exit codes (CI-friendly)

  • 0 — success or no-op (already in target state)
  • 1 — kubectl failure (RBAC, network, missing CR)
  • 2 — validation failure (operator typo: missing --upstream-ref, ref on wrong subcommand, etc.)

Pre-flight transition summary

Before applying, the orchestrator runs kubectl get clawsandbox <name> and prints current → target. If already in the target state, it skips the patch as a no-op (JSON: { noop: true }).

Out of scope (S9.2 — follow-up PR)

  • azureclaw migrate from-kagent (Solo.io kagent CR → ClawSandbox translator)
  • Real azureclaw convert YAML translator (currently exit-3 skeleton)
  • migrate verify <name> (consistency check against upstream Sandbox CR)

Verification

  • cd cli && npx tsc --noEmit ✅
  • cd cli && npm test — 337 passed | 2 skipped (was 315+2; +22 from this slice) ✅
  • cd cli && npm run lint ✅ (preexisting warnings only)
  • BASE_REF=origin/dev bash ci/no-stubs.sh ✅
  • BASE_REF=origin/dev bash ci/no-custom-crypto.sh ✅
  • BASE_REF=origin/dev bash ci/check-loc.sh ✅
  • End-to-end smoke: node dist/index.js migrate to-overlay demo --upstream-ref legacy --dry-run prints the expected JSON merge patch.

Phase 2 progress on dev after merge: ✅ S1 #51, S2 #52, S3 #53, S4 #54, S5 #55, S6 #56, S8 #57, S11 #59, S11.1 #61, S9.1 (this PR) — 10 of ~14 slices.

Operator-facing tool to flip a ClawSandbox between the four upstream-
compatibility modes that S8 (#57) shipped on the controller side.
Drives the day-zero adoption story discussed in S11.1: take an
existing upstream sigs.k8s.io/agent-sandbox Sandbox and bolt
AzureClaw governance on without rewriting the YAML.

Real workflow:

    # operator already has an upstream Sandbox CR called 'legacy-agent'
    $ azureclaw migrate to-overlay legacy --upstream-ref legacy-agent
      legacy: native → overlay (upstream sandbox 'legacy-agent')
      ✓ patched

    # later: drop the upstream, return to native AzureClaw
    $ azureclaw migrate from-overlay legacy
      legacy: overlay → native
      ✓ patched

Subcommands:
  - migrate to-overlay <name> --upstream-ref <upstream>
  - migrate from-overlay <name>
  - migrate to-translate <name>
  - migrate to-observe <name>
  - migrate to-native <name>

All accept --namespace, --dry-run, --format human|json.

Reuse-first design (§0.2 #11):
  - No new CRD field, no controller change. OverlayMode reconciler
    logic already shipped in S8; this is the operator-facing tool.
  - Pure helpers (validateMode, buildModePatch, readCurrentMode,
    summariseTransition, modeDisplay) — fully unit-testable without
    a cluster.
  - JSON merge patch (RFC 7396) with explicit `null` for
    upstreamSandboxRef removal (matches Option::skip_serializing_if
    round-trip on the controller side). Asserted directly in tests.
  - Exit codes: 0 success/noop, 1 kubectl failure, 2 validation
    failure (CI gate can distinguish operator typo from infra error).

Pre-flight + transition summary: orchestrator runs `kubectl get`
first, reads current mode + ref, prints `current → target`. If
already in target state, skips the patch as a no-op (JSON output
sets `noop: true`).

Out of scope (S9.2 — separate PR): from-kagent translator, real
convert YAML translator, migrate verify against upstream Sandbox CR.

Tests: CLI workspace 315 → 337 (+22). 6 validateMode + 4 buildModePatch
+ 4 readCurrentMode + 5 summariseTransition + 3 modeDisplay. tsc
--noEmit + vitest + oxlint green; ci/no-stubs.sh + ci/no-custom-
crypto.sh + ci/check-loc.sh green with BASE_REF=origin/dev. End-to-
end smoke verified via `node dist/index.js migrate to-overlay demo
--upstream-ref legacy --dry-run`.

Audit: docs/security-audits/2026-04-28-phase2-migrate-mode-switch.md.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pallakatos
Pal Lakatos-Toth (pallakatos) merged commit d090bcc into dev Apr 28, 2026
14 of 15 checks passed
@pallakatos
Pal Lakatos-Toth (pallakatos) deleted the phase2-migrate-mode-switch branch April 28, 2026 08:24
Pal Lakatos-Toth (pallakatos) added a commit that referenced this pull request May 12, 2026
…62)

Operator-facing tool to flip a ClawSandbox between the four upstream-
compatibility modes that S8 (#57) shipped on the controller side.
Drives the day-zero adoption story discussed in S11.1: take an
existing upstream sigs.k8s.io/agent-sandbox Sandbox and bolt
AzureClaw governance on without rewriting the YAML.

Real workflow:

    # operator already has an upstream Sandbox CR called 'legacy-agent'
    $ azureclaw migrate to-overlay legacy --upstream-ref legacy-agent
      legacy: native → overlay (upstream sandbox 'legacy-agent')
      ✓ patched

    # later: drop the upstream, return to native AzureClaw
    $ azureclaw migrate from-overlay legacy
      legacy: overlay → native
      ✓ patched

Subcommands:
  - migrate to-overlay <name> --upstream-ref <upstream>
  - migrate from-overlay <name>
  - migrate to-translate <name>
  - migrate to-observe <name>
  - migrate to-native <name>

All accept --namespace, --dry-run, --format human|json.

Reuse-first design (§0.2 #11):
  - No new CRD field, no controller change. OverlayMode reconciler
    logic already shipped in S8; this is the operator-facing tool.
  - Pure helpers (validateMode, buildModePatch, readCurrentMode,
    summariseTransition, modeDisplay) — fully unit-testable without
    a cluster.
  - JSON merge patch (RFC 7396) with explicit `null` for
    upstreamSandboxRef removal (matches Option::skip_serializing_if
    round-trip on the controller side). Asserted directly in tests.
  - Exit codes: 0 success/noop, 1 kubectl failure, 2 validation
    failure (CI gate can distinguish operator typo from infra error).

Pre-flight + transition summary: orchestrator runs `kubectl get`
first, reads current mode + ref, prints `current → target`. If
already in target state, skips the patch as a no-op (JSON output
sets `noop: true`).

Out of scope (S9.2 — separate PR): from-kagent translator, real
convert YAML translator, migrate verify against upstream Sandbox CR.

Tests: CLI workspace 315 → 337 (+22). 6 validateMode + 4 buildModePatch
+ 4 readCurrentMode + 5 summariseTransition + 3 modeDisplay. tsc
--noEmit + vitest + oxlint green; ci/no-stubs.sh + ci/no-custom-
crypto.sh + ci/check-loc.sh green with BASE_REF=origin/dev. End-to-
end smoke verified via `node dist/index.js migrate to-overlay demo
--upstream-ref legacy --dry-run`.

Audit: docs/security-audits/2026-04-28-phase2-migrate-mode-switch.md.

Co-authored-by: Pal Lakatos-Toth <pallakatos@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant