diff --git a/README.md b/README.md index 4803dbd..2aea0eb 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # GitHub Copilot Sandbox -Presentation materials and demo automation for running GitHub Copilot CLI in Docker Sandboxes and Azure Container Apps (ACA) Sandboxes. +Presentation materials and demo for running GitHub Copilot CLI in Docker Sandboxes and Azure Container Apps (ACA) Sandboxes. -The primary presentation was prepared for various conferences and meetups, and covers local microVM isolation, remote sandbox lifecycle automation, and Java application modernization with GitHub Copilot CLI. +The primary presentation was prepared for various conferences and meetups, and covers local microVM isolation, remote sandbox lifecycle automation, and Java/.NET application modernization with GitHub Copilot CLI. ## Repository contents @@ -19,13 +19,13 @@ The primary presentation was prepared for various conferences and meetups, and c ## Demo guides -The [demo documentation index](docs/README.md) provides two complete, -sequential walkthroughs: +The [demo documentation index](docs/README.md) provides two complete, sequential walkthroughs: -| Demo | Setup | Runbook | Validation and recovery | -| ----------------------------------------- | ----------------------------- | --------------------------------- | ---------------------------------------------------- | -| 1. Java modernization in a Docker Sandbox | [Setup](docs/demo-1-setup.md) | [Runbook](docs/demo-1-runbook.md) | [Validation](docs/demo-1-validation-and-recovery.md) | -| 2. Copilot CLI in an ACA Sandbox | [Setup](docs/demo-2-setup.md) | [Runbook](docs/demo-2-runbook.md) | [Validation](docs/demo-2-validation-and-recovery.md) | +| Demo | Setup | Runbook | Validation and recovery | +| ----------------------------------------- | ----------------------------- | ---------------------------------------- | ----------------------------------------------------------- | +| 1. Java modernization in a Docker Sandbox | [Setup](docs/demo-1-setup.md) | [Runbook](docs/demo-1-runbook-java.md) | [Validation](docs/demo-1-validation-and-recovery-java.md) | +| 1. .NET modernization in a Docker Sandbox | [Setup](docs/demo-1-setup.md) | [Runbook](docs/demo-1-runbook-dotnet.md) | [Validation](docs/demo-1-validation-and-recovery-dotnet.md) | +| 2. Copilot CLI in an ACA Sandbox | [Setup](docs/demo-2-setup.md) | [Runbook](docs/demo-2-runbook.md) | [Validation](docs/demo-2-validation-and-recovery.md) | ## Preview the presentation @@ -57,4 +57,4 @@ sequential walkthroughs: npx serve . ``` -1. Open a web browser and navigate to `http://localhost:3000` to see the presentation. \ No newline at end of file +1. Open a web browser and navigate to `http://localhost:3000` to see the presentation. diff --git a/docs/README.md b/docs/README.md index ca914ba..4f4062b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,48 +1,33 @@ # AI agent sandboxing demo guides -These documents support the live demos in -[`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). +These documents support the live demos in [`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). -## Demo 1: Java modernization in a Docker Sandbox +## Demo 1: App modernization in a Docker Sandbox -1. [Environment setup](demo-1-setup.md) - install `sbx`, prepare credentials, - clone the sample, and establish a clean baseline. -2. [Live demo runbook](demo-1-runbook.md) - create the clone-mode sandbox, - modernize the Java application, and show the isolation evidence. -3. [Validation and recovery](demo-1-validation-and-recovery.md) - inspect, - preserve, troubleshoot, and clean up the result. - -## Demo 2: Copilot CLI in an ACA Sandbox - -1. [Environment setup](demo-2-setup.md) - install `aca`, prepare Azure RBAC and - credentials, and verify the Copilot disk image. -2. [Live demo runbook](demo-2-runbook.md) - create the managed sandbox, - generate a UI design plan, and prove that state survives stop and resume. -3. [Validation and recovery](demo-2-validation-and-recovery.md) - export - evidence, snapshot state, troubleshoot failures, and clean up Azure - resources. +1. [Environment setup](demo-1-setup.md) - install `sbx`, prepare credentials, clone either sample, and establish a clean baseline. +2. Choose the [Java live demo runbook](demo-1-runbook-java.md) or the [.NET live demo runbook](demo-1-runbook-dotnet.md). +3. Continue with [Java validation and recovery](demo-1-validation-and-recovery-java.md) or [.NET validation and recovery](demo-1-validation-and-recovery-dotnet.md). ## Demo 1 outcome The demo should make four points visible: - Copilot CLI runs inside an isolated microVM. -- The modernization agent assesses, plans, and executes the Java upgrade. +- The modernization agent assesses, plans, and executes a Java or .NET upgrade. - The agent uses a private Git clone and cannot write to the host repository. - The sandbox has its own Docker daemon and policy-controlled network access. -The sample application is -[`UW-Madison-DoIT/uportal-messaging`](https://github.com/UW-Madison-DoIT/uportal-messaging). -Its current baseline makes the change easy to explain: Java 8, Spring Boot -1.5.9.RELEASE, Maven, WAR packaging, and an OpenJDK 8 Travis CI build. +The sample applications are [`UW-Madison-DoIT/uportal-messaging`](https://github.com/UW-Madison-DoIT/uportal-messaging) for Java and [`Azure-Samples/dotnet-migration-copilot-samples`](https://github.com/Azure-Samples/dotnet-migration-copilot-samples) for .NET. + +## Demo 2: Copilot CLI in an ACA Sandbox + +1. [Environment setup](demo-2-setup.md) - install `aca`, prepare Azure RBAC and credentials, and verify the Copilot disk image. +2. [Live demo runbook](demo-2-runbook.md) - create the managed sandbox, generate a UI design plan, and prove that state survives stop and resume. +3. [Validation and recovery](demo-2-validation-and-recovery.md) - export evidence, snapshot state, troubleshoot failures, and clean up Azure resources. ## Demo 2 outcome -Demo 2 runs Copilot CLI in an Azure Container Apps Sandbox, asks it to create a -design-only plan for -[`devkimchi/battle-school-lunch`](https://github.com/devkimchi/battle-school-lunch), -stops the remote sandbox, and resumes the same sandbox with its filesystem -state intact. +Demo 2 runs Copilot CLI in an Azure Container Apps Sandbox, asks it to create a design-only plan for [`devkimchi/battle-school-lunch`](https://github.com/devkimchi/battle-school-lunch), stops the remote sandbox, and resumes the same sandbox with its filesystem state intact. ## References @@ -51,6 +36,4 @@ state intact. - [Docker Sandbox installation](https://docs.docker.com/ai/sandboxes/install/) - [Docker Sandbox isolation](https://docs.docker.com/ai/sandboxes/security/isolation/) - [Modernize Java apps with GitHub Copilot modernization](https://learn.microsoft.com/azure/developer/java/migration/github-copilot-app-modernization-for-java-copilot-cli) - -Commands and prerequisites were checked against the linked documentation on -August 24, 2026. +- [Assess and migrate a .NET project with GitHub Copilot modernization for .NET](https://learn.microsoft.com/dotnet/azure/migration/appmod/quickstart?pivots=copilot-cli) diff --git a/docs/demo-1-runbook-dotnet.md b/docs/demo-1-runbook-dotnet.md new file mode 100644 index 0000000..2d4bfe7 --- /dev/null +++ b/docs/demo-1-runbook-dotnet.md @@ -0,0 +1,244 @@ +# Demo 1: .NET app modernization in a Docker Sandbox + +This runbook follows the Demo 1 sequence in [`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). Use two terminals: Terminal A for Copilot CLI and Terminal B for inspection. + +> [!IMPORTANT] +> Run this demo in clone mode. Direct mode protects the host operating system, but it gives the agent read-write access to the host working tree. + +## What the demo proves + +- Copilot CLI runs inside an isolated microVM. +- The modernization agent assesses, plans, and executes the .NET upgrade. +- The agent works in a private clone and cannot write to the host repository. +- The sandbox has its own Docker daemon and policy-controlled network access. + +## Before you begin + +Complete the [Demo 1 environment setup](demo-1-setup.md) for .NET. Confirm that: + +- `sbx`, GitHub CLI, and Git are available. +- Docker and GitHub authentication succeed. +- The **Balanced** network policy is active. +- The host checkout is `dotnet-migration-copilot-samples`. + +## 1. Start Copilot in a private clone + +> [!NOTE] +> Copilot's Docker Sandbox template starts with its approval-skipping mode. This does not remove the microVM, workspace, credential, Docker daemon, or network boundaries. + +From the host checkout of `dotnet-migration-copilot-samples`, run in Terminal A: + +```bash +sbx secret set github --command 'gh auth token' +sbx run --clone --name dotnet-appmod copilot . +``` + +On first use, choose the **Balanced** network preset when prompted. + +`--clone` is the important boundary: + +- `/run/sandbox/source` is a read-only mount of the host repository. +- Copilot works in a separate read-write clone inside the microVM. +- `sbx` adds a `sandbox-dotnet-appmod` Git remote to the host repository. +- Nothing reaches the host working tree until an explicit fetch, checkout, or push. + +Run the following command in Terminal B to confirm the `sandbox-dotnet-appmod` remote: + +```bash +git remote -v +``` + +Enter the sandbox from Terminal B and check whether the .NET SDK is installed: + +```bash +sbx exec -it dotnet-appmod bash +dotnet --list-sdks +``` + +If it is not installed, install the .NET 10 SDK inside the sandbox: + +```bash +sudo apt update && \ + sudo apt install -y dotnet-sdk-10.0 +``` + +Then exit the inspection shell and restart the sandbox and Copilot CLI session: + +```bash +# Terminal B +exit +sbx stop dotnet-appmod + +# Terminal A +sbx run --name dotnet-appmod +``` + +## 2. Prepare the modernization agent + +### Install the plugin + +In the Copilot CLI session, enter: + +```text +/plugin marketplace add microsoft/github-copilot-modernization +/plugin install github-copilot-modernization@github-copilot-modernization +``` + +If the MCP server included with the plugin fails to start, enter: + +```text +Starting `appmod-mcp-server` fails. Fix it. +``` + +Once it is fixed, restart GitHub Copilot CLI: + +```text +/restart +``` + +Check that the MCP server is running: + +```text +/mcp show +``` + +Then list the installed plugins: + +```text +/plugin list +``` + +Confirm that the list contains: + +```text +github-copilot-modernization@github-copilot-modernization +``` + +### Select the orchestrator + +Enter `/agent`, then select: + +```text +github-copilot-modernization:modernize +``` + +Do not run the upgrade with the default Copilot agent. The `modernize` agent provides the assessment, planning, specialized executors, retries, and per-task commits used in this demo. + +## 3. Run the modernization + +Use this prompt: + +```text +modernize my application +``` + +The expected workflow is: + +1. **Assessment** - discovers the .NET version, framework, dependencies, and risks; writes `.github/modernize/assessment/`. +2. **Planning** - writes `.github/modernize//plan.md` and `tasks.json`. +3. **Execution** - delegates tasks, updates the application, verifies the build, and creates detailed task commits. + +A specific upgrade prompt can go directly to planning and execution. Asking for assessment explicitly keeps all three phases visible for the demo. + +## 4. Inspect the sandbox while the agent works + +In Terminal B: + +```bash +sbx ls +sbx policy ls +sbx exec -it dotnet-appmod bash +``` + +Inside the sandbox shell: + +```bash +pwd +node --version +dotnet --info +git branch --show-current +git status --short +docker info +find .github/modernize -maxdepth 3 -type f -print 2>/dev/null +``` + +Show that the host source mount is read-only: + +```bash +touch /run/sandbox/source/__sandbox-write-test +``` + +The command should fail with a read-only filesystem error. Do not use a path inside the private clone for this test; the private clone is intentionally writable. + +Show the isolated Docker daemon without changing the host: + +```bash +docker run hello-world +docker ps -a +``` + +Exit the inspection shell: + +```bash +exit +``` + +Run `sbx` with no arguments on the host to open the dashboard. Switch to its network panel to show allowed and denied outbound connections and the rules that made each decision. + +## 5. Prove that the host stayed clean + +While the agent's commits remain in the private clone, run from the host checkout: + +```bash +git status --short +git branch --show-current +git remote --verbose +``` + +Expected result: + +- `git status --short` prints nothing. +- The host remains on `main`. +- The `sandbox-dotnet-appmod` remote is present. + +## 6. Verify the result + +After the modernization agent finishes, use the inspection shell or ask the agent to report: + +```bash +git branch --show-current +git status --short +git --no-pager log --oneline --decorate -15 +find .github/modernize -maxdepth 3 -type f -print +``` + +Confirm that the branch is `modernize/dotnet-*`, the expected assessment and plan artifacts exist, verification results are reported, and task commits are present. + +> [!NOTE] +> `*` may refer to a timestamp or a random string + +## 7. Preserve evidence and clean up + +Continue with [Demo 1 .NET validation and recovery](demo-1-validation-and-recovery-dotnet.md) to: + +1. Fetch the private modernization branch. +2. Review application, build, CI, and modernization artifacts. +3. Materialize only the reviewed branch on the host. +4. Stop and remove the sandbox after its work is preserved. + +## Troubleshooting + +Use the [Demo 1 .NET troubleshooting guide](demo-1-validation-and-recovery-dotnet.md#troubleshooting) for plugin installation, .NET discovery, network policy, build failures, sandbox mode, and fetch failures. + +## References + +- [Get started with Docker Sandboxes](https://docs.docker.com/ai/sandboxes/get-started/) +- [Run GitHub Copilot in a Docker Sandbox](https://docs.docker.com/ai/sandboxes/agents/copilot/) +- [Docker Sandbox isolation](https://docs.docker.com/ai/sandboxes/security/isolation/) +- [Use Git with Docker Sandboxes](https://docs.docker.com/ai/sandboxes/workflows/git/) +- [Assess and migrate a .NET project with GitHub Copilot modernization for .NET](https://learn.microsoft.com/dotnet/azure/migration/appmod/quickstart?pivots=copilot-cli) + +## Navigation + +[Previous: Demo 1 environment setup](demo-1-setup.md) | +[Next: Demo 1 .NET validation and recovery](demo-1-validation-and-recovery-dotnet.md) \ No newline at end of file diff --git a/docs/demo-1-runbook.md b/docs/demo-1-runbook-java.md similarity index 55% rename from docs/demo-1-runbook.md rename to docs/demo-1-runbook-java.md index 86ef6f6..d8da0db 100644 --- a/docs/demo-1-runbook.md +++ b/docs/demo-1-runbook-java.md @@ -1,12 +1,9 @@ -# Demo 1: Java modernization in a Docker Sandbox +# Demo 1: Java app modernization in a Docker Sandbox -This runbook follows the Demo 1 sequence in -[`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). Use two terminals: -Terminal A for Copilot CLI and Terminal B for inspection. +This runbook follows the Demo 1 sequence in [`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). Use two terminals: Terminal A for Copilot CLI and Terminal B for inspection. > [!IMPORTANT] -> Run this demo in clone mode. Direct mode protects the host operating system, -> but it gives the agent read-write access to the host working tree. +> Run this demo in clone mode. Direct mode protects the host operating system, but it gives the agent read-write access to the host working tree. ## What the demo proves @@ -17,21 +14,23 @@ Terminal A for Copilot CLI and Terminal B for inspection. ## Before you begin -Complete the [Demo 1 environment setup](demo-1-setup.md). Confirm that: +Complete the [Demo 1 environment setup](demo-1-setup.md) for Java. Confirm that: - `sbx`, GitHub CLI, and Git are available. - Docker and GitHub authentication succeed. - The **Balanced** network policy is active. -- `uportal-messaging` is clean and checked out on `demo/baseline`. -- No stale `java-modernize` sandbox contains unpreserved work. +- The host checkout is `uportal-messaging`. ## 1. Start Copilot in a private clone +> [!NOTE] +> Copilot's Docker Sandbox template starts with its approval-skipping mode. This does not remove the microVM, workspace, credential, Docker daemon, or network boundaries. + From the host checkout of `uportal-messaging`, run in Terminal A: -```powershell +```bash sbx secret set github --command 'gh auth token' -sbx run --clone --name java-modernize copilot . +sbx run --clone --name java-appmod copilot . ``` On first use, choose the **Balanced** network preset when prompted. @@ -40,13 +39,14 @@ On first use, choose the **Balanced** network preset when prompted. - `/run/sandbox/source` is a read-only mount of the host repository. - Copilot works in a separate read-write clone inside the microVM. -- `sbx` adds a `sandbox-java-modernize` Git remote to the host repository. -- Nothing reaches the host working tree until an explicit fetch, checkout, or - push. +- `sbx` adds a `sandbox-java-appmod` Git remote to the host repository. +- Nothing reaches the host working tree until an explicit fetch, checkout, or push. -Copilot's Docker Sandbox template starts with its approval-skipping mode. This -does not remove the microVM, workspace, credential, Docker daemon, or network -boundaries. +Run the following command in Terminal B to confirm the `sandbox-java-appmod` remote: + +```bash +git remote -v +``` ## 2. Prepare the modernization agent @@ -57,20 +57,36 @@ In the Copilot CLI session, enter: ```text /plugin marketplace add microsoft/github-copilot-modernization /plugin install github-copilot-modernization@github-copilot-modernization -/plugin list ``` -Confirm that the list contains: +If the MCP server included with the plugin fails to start, enter: ```text -github-copilot-modernization@github-copilot-modernization +Starting `appmod-mcp-server` fails. Fix it. ``` -The equivalent non-interactive shell commands are: +Once it is fixed, restart GitHub Copilot CLI: -```bash -copilot plugin marketplace add microsoft/github-copilot-modernization -copilot plugin install github-copilot-modernization@github-copilot-modernization +```text +/restart +``` + +Check that the MCP server is running: + +```text +/mcp show +``` + +Then list the installed plugins: + +```text +/plugin list +``` + +Confirm that the list contains: + +```text +github-copilot-modernization@github-copilot-modernization ``` ### Select the orchestrator @@ -81,42 +97,32 @@ Enter `/agent`, then select: github-copilot-modernization:modernize ``` -Do not run the upgrade with the default Copilot agent. The `modernize` agent -provides the assessment, planning, specialized executors, retries, and -per-task commits used in this demo. +Do not run the upgrade with the default Copilot agent. The `modernize` agent provides the assessment, planning, specialized executors, retries, and per-task commits used in this demo. ## 3. Run the modernization Use this prompt: ```text -Before making changes, create and switch to a branch named demo/modernized. -Upgrade this application to Java 21 and Spring Boot 4.1. Assess the current -application, create a reviewable plan, execute the plan, update tests and build -configuration, run the relevant Maven verification, check dependencies for -known vulnerabilities, and commit each completed task separately. Do not push -the branch or open a pull request. +modernize my application ``` The expected workflow is: -1. **Assessment** - discovers Java version, framework, dependencies, and risks; - writes `.github/modernize/assessment/`. +1. **Assessment** - discovers the Java version, framework, dependencies, and risks; writes `.github/modernize/assessment/`. 2. **Planning** - writes `.github/modernize//plan.md` and `tasks.json`. -3. **Execution** - delegates tasks, updates the application, verifies the - build, and creates detailed task commits. +3. **Execution** - delegates tasks, updates the application, verifies the build, and creates detailed task commits. -A specific upgrade prompt can go directly to planning and execution. Asking -for assessment explicitly keeps all three phases visible for the demo. +A specific upgrade prompt can go directly to planning and execution. Asking for assessment explicitly keeps all three phases visible for the demo. ## 4. Inspect the sandbox while the agent works In Terminal B: -```powershell +```bash sbx ls sbx policy ls -sbx exec -it java-modernize bash +sbx exec -it java-appmod bash ``` Inside the sandbox shell: @@ -124,6 +130,7 @@ Inside the sandbox shell: ```bash pwd node --version +java -version git branch --show-current git status --short docker info @@ -136,36 +143,28 @@ Show that the host source mount is read-only: touch /run/sandbox/source/__sandbox-write-test ``` -The command should fail with a read-only filesystem error. Do not use a path -inside the private clone for this test; the private clone is intentionally -writable. +The command should fail with a read-only filesystem error. Do not use a path inside the private clone for this test; the private clone is intentionally writable. Show the isolated Docker daemon without changing the host: ```bash -docker run --rm hello-world +docker run hello-world docker ps -a ``` -The container and image exist only in the sandbox's Docker Engine. Docker -Sandboxes do not mount the host Docker socket. - Exit the inspection shell: ```bash exit ``` -Run `sbx` with no arguments on the host to open the dashboard. Switch to its -network panel to show allowed and denied outbound connections and the rules -that made each decision. +Run `sbx` with no arguments on the host to open the dashboard. Switch to its network panel to show allowed and denied outbound connections and the rules that made each decision. ## 5. Prove that the host stayed clean -While the agent's commits remain in the private clone, run from the host -checkout: +While the agent's commits remain in the private clone, run from the host checkout: -```powershell +```bash git status --short git branch --show-current git remote --verbose @@ -174,13 +173,12 @@ git remote --verbose Expected result: - `git status --short` prints nothing. -- The host remains on `demo/baseline`. -- A `sandbox-java-modernize` remote is present. +- The host remains on `master`. +- The `sandbox-java-appmod` remote is present. ## 6. Verify the result -After the modernization agent finishes, use the inspection shell or ask the -agent to report: +After the modernization agent finishes, use the inspection shell or ask the agent to report: ```bash git branch --show-current @@ -189,26 +187,23 @@ git --no-pager log --oneline --decorate -15 find .github/modernize -maxdepth 3 -type f -print ``` -Confirm that the branch is `demo/modernized`, the expected assessment and plan -artifacts exist, verification results are reported, and task commits are -present. +Confirm that the branch is `modernize/java-*`, the expected assessment and plan artifacts exist, verification results are reported, and task commits are present. + +> [!NOTE] +> `*` may refer to a timestamp or a random string ## 7. Preserve evidence and clean up -Continue with -[Demo 1 validation and recovery](demo-1-validation-and-recovery.md) to: +Continue with [Demo 1 Java validation and recovery](demo-1-validation-and-recovery-java.md) to: -1. Fetch `sandbox-java-modernize/demo/modernized`. +1. Fetch the private modernization branch. 2. Review application, build, CI, and modernization artifacts. 3. Materialize only the reviewed branch on the host. 4. Stop and remove the sandbox after its work is preserved. ## Troubleshooting -Use the -[Demo 1 troubleshooting guide](demo-1-validation-and-recovery.md#troubleshooting) -for plugin installation, Java discovery, network policy, Maven, sandbox mode, -and fetch failures. +Use the [Demo 1 Java troubleshooting guide](demo-1-validation-and-recovery-java.md#troubleshooting) for plugin installation, Java discovery, network policy, Maven, sandbox mode, and fetch failures. ## References @@ -218,10 +213,7 @@ and fetch failures. - [Use Git with Docker Sandboxes](https://docs.docker.com/ai/sandboxes/workflows/git/) - [Modernize Java apps with GitHub Copilot modernization](https://learn.microsoft.com/azure/developer/java/migration/github-copilot-app-modernization-for-java-copilot-cli) -Commands and behavior were checked against the linked documentation on -August 24, 2026. - ## Navigation [Previous: Demo 1 environment setup](demo-1-setup.md) | -[Next: Demo 1 validation and recovery](demo-1-validation-and-recovery.md) +[Next: Demo 1 Java validation and recovery](demo-1-validation-and-recovery-java.md) \ No newline at end of file diff --git a/docs/demo-1-setup.md b/docs/demo-1-setup.md index c16852a..6d147bb 100644 --- a/docs/demo-1-setup.md +++ b/docs/demo-1-setup.md @@ -1,32 +1,26 @@ -# Demo 1 environment setup +# Demo 1: Environment setup Complete this setup before presenting the live runbook. ## 1. Check the host -Docker Sandboxes do not require Docker Desktop or Docker Engine on the host. -The supported host requirements are: +Docker Sandboxes do not require Docker Desktop or Docker Engine on the host. The supported host requirements are: -| Platform | Requirement | -| --- | --- | -| Windows | Windows 11, 64-bit Intel or AMD CPU, Windows Hypervisor Platform | -| macOS | macOS Sonoma 14 or later on Apple silicon | -| Linux | Ubuntu 24.04 or later with KVM enabled | +| Platform | Requirement | +| -------- | ---------------------------------------------------------------- | +| Windows | Windows 11, 64-bit Intel or AMD CPU, Windows Hypervisor Platform | +| macOS | macOS Sonoma 14 or later on Apple silicon | +| Linux | Ubuntu 24.04 or later with KVM enabled | -On Windows, enable Windows Hypervisor Platform from an elevated PowerShell -session, then restart if Windows requests it: +On Windows, enable Windows Hypervisor Platform from an elevated PowerShell session, then restart if Windows requests it: ```powershell Enable-WindowsOptionalFeature -Online -FeatureName HypervisorPlatform -All ``` -The Java modernization plugin requires a GitHub Copilot subscription. If the -subscription is organization-managed, the organization must enable its -Copilot CLI policy. An Azure account is not required for a source upgrade. +The app modernization plugin requires a GitHub Copilot subscription. If the subscription is organization-managed, the organization must enable its Copilot CLI policy. An Azure account is not required for a source upgrade. -The Copilot sandbox template supplies Copilot CLI and its runtime. The -modernization plugin's documented standalone prerequisite is Node.js 22 or -later; verify the template before the demo: +The Copilot sandbox template supplies Copilot CLI and its runtime. The modernization plugin's documented standalone prerequisite is Node.js 22 or later; verify the template before the demo: ```powershell sbx --version @@ -62,90 +56,63 @@ sbx login ## 3. Store the GitHub credential -Authenticate GitHub CLI on the host first. Store the resulting token through -the sandbox secret mechanism rather than copying it into the microVM: +Authenticate GitHub CLI on the host first. Store the resulting token through the sandbox secret mechanism rather than copying it into the microVM: ```powershell gh auth login sbx secret set github --command 'gh auth token' ``` -The host-side proxy injects supported credentials into outbound requests. The -token is not exposed to the agent as a file or environment variable. +The host-side proxy injects supported credentials into outbound requests. The token is not exposed to the agent as a file or environment variable. ## 4. Initialize a network policy -Use the **Balanced** preset for the demo. It is default-deny with a baseline -allowlist for common AI providers, code hosts, package registries, and -development services. +Use the **Balanced** preset for the demo. It is default-deny with a baseline allowlist for common AI providers, code hosts, package registries, and development services. ```powershell sbx policy init balanced sbx policy ls ``` -If a preset already exists, do not reset it during the demo. The -`sbx policy reset` command stops running sandboxes. - -Do not switch to the Open preset to resolve a single blocked dependency. Add a -narrow rule only after confirming the denied host in the dashboard: - -```powershell -sbx policy allow network --sandbox java-modernize artifacts.doit.wisc.edu -sbx policy allow network --sandbox java-modernize artifactorydoit.jfrog.io -``` - -The sample `pom.xml` declares both hosts. A build might not contact them if all -required artifacts resolve from Maven Central. - ## 5. Prepare the sample repository -Use the main checkout, not a linked Git worktree: clone mode does not support a -secondary worktree as its primary workspace. +Use the main checkout, not a linked Git worktree: clone mode does not support a secondary worktree as its primary workspace. -```powershell +```bash +# Java git clone https://github.com/UW-Madison-DoIT/uportal-messaging.git -Set-Location uportal-messaging -git switch -c demo/baseline -git status --short +cd uportal-messaging ``` -The final command should produce no output. Clone mode follows the host's -checked-out ref when the sandbox is created, but it does not create a task -branch automatically. - -Record the baseline for the audience: - -```powershell -git --no-pager grep -n '\|spring-boot-starter-parent' -git --no-pager log -1 --oneline +```bash +# .NET +git clone https://github.com/Azure-Samples/dotnet-migration-copilot-samples.git +cd dotnet-migration-copilot-samples ``` -The repository's `pom.xml` declares Java 8 and Spring Boot 1.5.9.RELEASE. The -live target from Demo 1 is Java 21 and Spring Boot 4.1. - ## 6. Preflight Run these checks before presenting: -```powershell +```bash +# Java sbx ls -sbx policy check network github.com -sbx policy check network repo.maven.apache.org +sbx policy check network "**.github.com" + +sbx policy allow network "**.apache.org" ``` -If a stale `java-modernize` sandbox exists, preserve any work before removing -it: +```bash +# .NET +sbx ls +sbx policy check network "**.github.com" -```powershell -git fetch sandbox-java-modernize -sbx stop java-modernize -sbx rm java-modernize +sbx policy allow network "**.nuget.org" +sbx policy allow network "**.microsoft.com" +sbx policy allow network "**.azure.com" +sbx policy allow network aka.ms ``` -Do not remove a clone-mode sandbox until its commits have been fetched or -pushed. Removing it deletes the private clone. - ## Navigation -Next: [Demo 1 live runbook](demo-1-runbook.md) +Next: [Demo 1 Java live runbook](demo-1-runbook-java.md) | [Demo 1 .NET live runbook](demo-1-runbook-dotnet.md) diff --git a/docs/demo-1-validation-and-recovery-dotnet.md b/docs/demo-1-validation-and-recovery-dotnet.md new file mode 100644 index 0000000..b78c7d0 --- /dev/null +++ b/docs/demo-1-validation-and-recovery-dotnet.md @@ -0,0 +1,177 @@ +# Demo 1: .NET validation and recovery + +Use this guide after the agent finishes, or when the live path needs recovery. + +## Preserve and review the private branch + +Keep the sandbox running while fetching because its Git daemon is available only while the sandbox runs. + +From the host `dotnet-migration-copilot-samples` checkout: + +```bash +git fetch sandbox-dotnet-appmod +git --no-pager log --oneline --decorate sandbox-dotnet-appmod/modernize/dotnet-* +git --no-pager diff --stat main..sandbox-dotnet-appmod/modernize/dotnet-* +git --no-pager diff main..sandbox-dotnet-appmod/modernize/dotnet-* +``` + +Review executable and trust-sensitive changes in addition to application code: + +```bash +git --no-pager diff --name-status main..sandbox-dotnet-appmod/modernize/dotnet-* +git --no-pager diff main..sandbox-dotnet-appmod/modernize/dotnet-* -- ContosoUniversity/Web.config ContosoUniversity/appsettings.json +``` + +> [!NOTE] +> `*` may refer to a timestamp or a random string + +Pay particular attention to: + +- Target frameworks, SDK versions, NuGet dependencies, and package sources in solution, project, `packages.config`, and `NuGet.config` files. +- Migration of `Web.config` settings to `appsettings.json`, environment variables, middleware, and the modern hosting model. +- CI definitions and automation under `.github/`. +- `.github/modernize/assessment/`, `plan.md`, and `tasks.json`. +- Newly added scripts, Dockerfiles, agent configuration, and Git hooks. +- Build and vulnerability-scan output reported by the agent. + +Clone mode prevents writes to the host, but the source mount is readable. Do not keep `.env`, tokens, private keys, or other secrets inside the repository, even when they are ignored by Git. + +## Materialize the reviewed branch + +After reviewing the remote-tracking branch: + +```bash +git switch -c modernized --track sandbox-dotnet-appmod/modernize/dotnet-* +git status +``` + +Run host-side build or test commands only after reviewing the changes as untrusted code. The demo can stop at the diff if executing fetched code on the host is outside the presentation's safety boundary. + +## Validation checklist + +| Evidence | Expected result | +| ------------------------------------------------- | --------------------------------------------------------------- | +| `git status --short` on the host before fetch | No output | +| Write under `/run/sandbox/source` | Fails as read-only | +| `docker info` in the sandbox | Reports the sandbox's Docker Engine | +| `sbx policy ls` and dashboard | Balanced policy and connection decisions visible | +| Modernization artifacts | Assessment, `plan.md`, and `tasks.json` present | +| Git history | Separate modernization task commits | +| .NET build and test verification | Result reported; failures have a specific cause and next action | +| Vulnerability check | Result or explicit tool limitation reported | + +## Troubleshooting + +### The plugin is missing + +From a sandbox shell: + +```bash +copilot plugin marketplace list +copilot plugin marketplace add microsoft/github-copilot-modernization +copilot plugin install github-copilot-modernization@github-copilot-modernization +``` + +Back in Copilot CLI, run `/plugin list`, then select `github-copilot-modernization:modernize` again with `/agent`. + +### No .NET application is found + +Confirm that Copilot started in the private clone root: + +```bash +pwd +find . -maxdepth 3 \( -name '*.sln' -o -name '*.csproj' \) -print +dotnet --info +git rev-parse --show-toplevel +``` + +Start the modernization agent from the repository root or the directory containing the solution or project file. + +### A network request is denied + +Use the dashboard's network panel to identify the exact host, then check its decision: + +```bash +sbx policy check network --sandbox dotnet-appmod example.com +``` + +If the host is required and approved, add only that host: + +```bash +sbx policy allow network --sandbox dotnet-appmod example.com +``` + +If organization governance is active, local allow rules cannot expand the organization policy. Ask the organization administrator to allow the host. Local deny rules still apply. + +For this sample, package and SDK downloads might require scoped rules for hosts such as: + +```bash +sbx policy check network --sandbox dotnet-appmod api.nuget.org +sbx policy check network --sandbox dotnet-appmod packages.microsoft.com +sbx policy check network --sandbox dotnet-appmod aka.ms +``` + +### The .NET build fails + +Do not present a failed build as a completed modernization. Capture: + +```bash +dotnet --info +dotnet restore +dotnet build --no-restore +dotnet test --no-build +``` + +Classify the failure before retrying: + +- A denied hostname requires a reviewed policy rule. +- A restore failure might require updating a package source or replacing an obsolete or incompatible NuGet dependency. +- A legacy .NET Framework project might not build on Linux until its target framework and project format are modernized. +- Compilation errors require another modernization task and commit. +- Test failures require either a fix or an explicit, documented blocker. + +### The sandbox reused the wrong mode or state + +Clone mode is fixed when the sandbox is created. Preserve useful commits, then recreate it: + +```bash +git fetch sandbox-dotnet-appmod +sbx stop dotnet-appmod +sbx rm dotnet-appmod +sbx run --clone --name dotnet-appmod copilot . +``` + +### Fetch fails + +The private clone's Git daemon is unavailable while the sandbox is stopped. Restart it and fetch again: + +```bash +sbx run --name dotnet-appmod +git fetch sandbox-dotnet-appmod +``` + +If the agent used a different branch name, inspect branches inside the sandbox: + +```bash +sbx exec -it dotnet-appmod bash +``` + +```bash +git branch --all +``` + +## Cleanup + +Fetch or push every branch you want to preserve before cleanup: + +```bash +git fetch sandbox-dotnet-appmod +sbx stop dotnet-appmod +sbx rm dotnet-appmod +``` + +Removing the sandbox deletes its microVM, private clone, installed tools, Docker images and containers, and the `sandbox-dotnet-appmod` host remote. It does not modify the host working tree. + +## Navigation + +Previous: [Demo 1 .NET live runbook](demo-1-runbook-dotnet.md) diff --git a/docs/demo-1-validation-and-recovery-java.md b/docs/demo-1-validation-and-recovery-java.md new file mode 100644 index 0000000..3740c7e --- /dev/null +++ b/docs/demo-1-validation-and-recovery-java.md @@ -0,0 +1,172 @@ +# Demo 1: Java validation and recovery + +Use this guide after the agent finishes, or when the live path needs recovery. + +## Preserve and review the private branch + +Keep the sandbox running while fetching because its Git daemon is available only while the sandbox runs. + +From the host `uportal-messaging` checkout: + +```bash +git fetch sandbox-java-appmod +git --no-pager log --oneline --decorate sandbox-java-appmod/modernize/java-* +git --no-pager diff --stat master..sandbox-java-appmod/modernize/java-* +git --no-pager diff master..sandbox-java-appmod/modernize/java-* +``` + +Review executable and trust-sensitive changes in addition to application code: + +```bash +git --no-pager diff --name-status master..sandbox-java-appmod/modernize/java-* +git --no-pager diff master..sandbox-java-appmod/modernize/java-* -- pom.xml .github +``` + +> [!NOTE] +> `*` may refer to a timestamp or a random string + +Pay particular attention to: + +- Maven plugins, repositories, and dependency versions in `pom.xml`. +- CI definitions and automation under `.github/`. +- `.github/modernize/assessment/`, `plan.md`, and `tasks.json`. +- Newly added scripts, Dockerfiles, agent configuration, and Git hooks. +- Build and vulnerability-scan output reported by the agent. + +Clone mode prevents writes to the host, but the source mount is readable. Do not keep `.env`, tokens, private keys, or other secrets inside the repository, even when they are ignored by Git. + +## Materialize the reviewed branch + +After reviewing the remote-tracking branch: + +```bash +git switch -c modernized --track sandbox-java-appmod/modernize/java-* +git status +``` + +Run host-side build or test commands only after reviewing the changes as untrusted code. The demo can stop at the diff if executing fetched code on the host is outside the presentation's safety boundary. + +## Validation checklist + +| Evidence | Expected result | +| ------------------------------------------------- | --------------------------------------------------------------- | +| `git status --short` on the host before fetch | No output | +| Write under `/run/sandbox/source` | Fails as read-only | +| `docker info` in the sandbox | Reports the sandbox's Docker Engine | +| `sbx policy ls` and dashboard | Balanced policy and connection decisions visible | +| Modernization artifacts | Assessment, `plan.md`, and `tasks.json` present | +| Git history | Separate modernization task commits | +| Maven verification | Result reported; failures have a specific cause and next action | +| Vulnerability check | Result or explicit tool limitation reported | + +## Troubleshooting + +### The plugin is missing + +From a sandbox shell: + +```bash +copilot plugin marketplace list +copilot plugin marketplace add microsoft/github-copilot-modernization +copilot plugin install github-copilot-modernization@github-copilot-modernization +``` + +Back in Copilot CLI, run `/plugin list`, then select `github-copilot-modernization:modernize` again with `/agent`. + +### No Java application is found + +Confirm that Copilot started in the private clone root: + +```bash +pwd +test -f pom.xml && echo "pom.xml found" +git rev-parse --show-toplevel +``` + +Start the modernization agent from the directory containing `pom.xml`. + +### A network request is denied + +Use the dashboard's network panel to identify the exact host, then check its decision: + +```bash +sbx policy check network --sandbox java-appmod example.com +``` + +If the host is required and approved, add only that host: + +```bash +sbx policy allow network --sandbox java-appmod example.com +``` + +If organization governance is active, local allow rules cannot expand the organization policy. Ask the organization administrator to allow the host. Local deny rules still apply. + +For this sample, legacy Maven repositories that might require a scoped rule include: + +```bash +sbx policy check network --sandbox java-appmod artifacts.doit.wisc.edu +sbx policy check network --sandbox java-appmod artifactorydoit.jfrog.io +``` + +### The Maven build fails + +Do not present a failed build as a completed modernization. Capture: + +```bash +java -version +mvn -version +mvn -U verify +``` + +Classify the failure before retrying: + +- A denied hostname requires a reviewed policy rule. +- A missing legacy artifact might require replacing or removing the obsolete repository or dependency as part of the modernization plan. +- Compilation errors require another modernization task and commit. +- Test failures require either a fix or an explicit, documented blocker. + +### The sandbox reused the wrong mode or state + +Clone mode is fixed when the sandbox is created. Preserve useful commits, then recreate it: + +```bash +git fetch sandbox-java-appmod +sbx stop java-appmod +sbx rm java-appmod +sbx run --clone --name java-appmod copilot . +``` + +### Fetch fails + +The private clone's Git daemon is unavailable while the sandbox is stopped. Restart it and fetch again: + +```bash +sbx run --name java-appmod +git fetch sandbox-java-appmod +``` + +If the agent used a different branch name, inspect branches inside the sandbox: + +```bash +sbx exec -it java-appmod bash +``` + +```bash +git branch --all +``` + +## Cleanup + +Fetch or push every branch you want to preserve before cleanup: + +```bash +git fetch sandbox-java-appmod +sbx stop java-appmod +sbx rm java-appmod +``` + +Removing the sandbox deletes its microVM, private clone, installed tools, Docker images and containers, and the `sandbox-java-appmod` host remote. It does not modify the host working tree. + +## Navigation + +Previous: [Demo 1 Java live runbook](demo-1-runbook-java.md) diff --git a/docs/demo-1-validation-and-recovery.md b/docs/demo-1-validation-and-recovery.md deleted file mode 100644 index 6893cbf..0000000 --- a/docs/demo-1-validation-and-recovery.md +++ /dev/null @@ -1,184 +0,0 @@ -# Demo 1 validation and recovery - -Use this guide after the agent finishes, or when the live path needs recovery. - -## Preserve and review the private branch - -Keep the sandbox running while fetching because its Git daemon is available -only while the sandbox runs. - -From the host `uportal-messaging` checkout: - -```powershell -git fetch sandbox-java-modernize -git --no-pager log --oneline --decorate sandbox-java-modernize/demo/modernized -git --no-pager diff --stat demo/baseline..sandbox-java-modernize/demo/modernized -git --no-pager diff demo/baseline..sandbox-java-modernize/demo/modernized -``` - -Review executable and trust-sensitive changes in addition to application code: - -```powershell -git --no-pager diff --name-status demo/baseline..sandbox-java-modernize/demo/modernized -git --no-pager diff demo/baseline..sandbox-java-modernize/demo/modernized -- pom.xml .github -``` - -Pay particular attention to: - -- Maven plugins, repositories, and dependency versions in `pom.xml`. -- CI definitions and automation under `.github/`. -- `.github/modernize/assessment/`, `plan.md`, and `tasks.json`. -- Newly added scripts, Dockerfiles, agent configuration, and Git hooks. -- Build and vulnerability-scan output reported by the agent. - -Clone mode prevents writes to the host, but the source mount is readable. Do -not keep `.env`, tokens, private keys, or other secrets inside the repository, -even when they are ignored by Git. - -## Materialize the reviewed branch - -After reviewing the remote-tracking branch: - -```powershell -git switch -c demo/modernized --track sandbox-java-modernize/demo/modernized -git status -``` - -Run host-side build or test commands only after reviewing the changes as -untrusted code. The demo can stop at the diff if executing fetched code on the -host is outside the presentation's safety boundary. - -## Validation checklist - -| Evidence | Expected result | -| --- | --- | -| `git status --short` on the host before fetch | No output | -| Write under `/run/sandbox/source` | Fails as read-only | -| `docker info` in the sandbox | Reports the sandbox's Docker Engine | -| `sbx policy ls` and dashboard | Balanced policy and connection decisions visible | -| Modernization artifacts | Assessment, `plan.md`, and `tasks.json` present | -| Git history | Separate modernization task commits | -| Maven verification | Result reported; failures have a specific cause and next action | -| Vulnerability check | Result or explicit tool limitation reported | - -## Troubleshooting - -### The plugin is missing - -From a sandbox shell: - -```bash -copilot plugin marketplace list -copilot plugin marketplace add microsoft/github-copilot-modernization -copilot plugin install github-copilot-modernization@github-copilot-modernization -``` - -Back in Copilot CLI, run `/plugin list`, then select -`github-copilot-modernization:modernize` again with `/agent`. - -### No Java application is found - -Confirm that Copilot started in the private clone root: - -```bash -pwd -test -f pom.xml && echo "pom.xml found" -git rev-parse --show-toplevel -``` - -Start the modernization agent from the directory containing `pom.xml`. - -### A network request is denied - -Use the dashboard's network panel to identify the exact host, then check its -decision: - -```powershell -sbx policy check network --sandbox java-modernize example.com -``` - -If the host is required and approved, add only that host: - -```powershell -sbx policy allow network --sandbox java-modernize example.com -``` - -If organization governance is active, local allow rules cannot expand the -organization policy. Ask the organization administrator to allow the host. -Local deny rules still apply. - -For this sample, legacy Maven repositories that might require a scoped rule -include: - -```powershell -sbx policy check network --sandbox java-modernize artifacts.doit.wisc.edu -sbx policy check network --sandbox java-modernize artifactorydoit.jfrog.io -``` - -### The Maven build fails - -Do not present a failed build as a completed modernization. Capture: - -```bash -java -version -mvn -version -mvn -U verify -``` - -Classify the failure before retrying: - -- A denied hostname requires a reviewed policy rule. -- A missing legacy artifact might require replacing or removing the obsolete - repository or dependency as part of the modernization plan. -- Compilation errors require another modernization task and commit. -- Test failures require either a fix or an explicit, documented blocker. - -### The sandbox reused the wrong mode or state - -Clone mode is fixed when the sandbox is created. Preserve useful commits, then -recreate it: - -```powershell -git fetch sandbox-java-modernize -sbx stop java-modernize -sbx rm java-modernize -sbx run --clone --name java-modernize copilot . -``` - -### Fetch fails - -The private clone's Git daemon is unavailable while the sandbox is stopped. -Restart it and fetch again: - -```powershell -sbx run --name java-modernize -git fetch sandbox-java-modernize -``` - -If the agent used a different branch name, inspect branches inside the sandbox: - -```powershell -sbx exec -it java-modernize bash -``` - -```bash -git branch --all -``` - -## Cleanup - -Fetch or push every branch you want to preserve before cleanup: - -```powershell -git fetch sandbox-java-modernize -sbx stop java-modernize -sbx rm java-modernize -``` - -Removing the sandbox deletes its microVM, private clone, installed tools, -Docker images and containers, and the `sandbox-java-modernize` host remote. It -does not modify the host working tree. - -## Navigation - -Previous: [Demo 1 live runbook](demo-1-runbook.md) diff --git a/docs/demo-2-runbook.md b/docs/demo-2-runbook.md index 2141105..de5d1ec 100644 --- a/docs/demo-2-runbook.md +++ b/docs/demo-2-runbook.md @@ -1,25 +1,17 @@ # Demo 2: Copilot CLI in an ACA Sandbox -This runbook follows the Demo 2 sequence in -[`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). It runs GitHub Copilot -CLI against -[`devkimchi/battle-school-lunch`](https://github.com/devkimchi/battle-school-lunch) -and proves that `design-update.md` survives a stop and resume cycle. +This runbook follows the Demo 2 sequence in [`ai-agent-sandboxing.md`](../ai-agent-sandboxing.md). It runs GitHub Copilot CLI against +[`devkimchi/battle-school-lunch`](https://github.com/devkimchi/battle-school-lunch) and proves that `design-update.md` survives a stop and resume cycle. > [!IMPORTANT] -> Use the same sandbox ID throughout the stop and resume sequence. -> `aca sandbox create` creates a different environment and does not prove state -> restoration. +> Use the same sandbox ID throughout the stop and resume sequence. `aca sandbox create` creates a different environment and does not prove state restoration. ## What the demo proves - A sandbox group is the Azure resource, RBAC, image, and policy boundary. -- Each sandbox is a hardware-isolated microVM with its own filesystem and - lifecycle. -- Copilot CLI can work inside the remote sandbox without placing its token in - the repository. -- Stopping the sandbox suspends compute while retaining state according to its - suspend mode. +- Each sandbox is a hardware-isolated microVM with its own filesystem and lifecycle. +- Copilot CLI can work inside the remote sandbox without placing its token in the repository. +- Stopping the sandbox suspends compute while retaining state according to its suspend mode. - Resuming the same sandbox restores the repository and generated design plan. ## Before you begin @@ -30,74 +22,104 @@ Complete the [Demo 2 environment setup](demo-2-setup.md). Confirm that: - `aca doctor` passes all group, region, and RBAC checks. - The GitHub Copilot provider credential is configured. - The `copilot` public disk is available. -- No stale `copilot-demo` sandbox contains unpreserved work. +- No stale `ghcp-demo` sandbox contains unpreserved work. ## 1. Create and harden the sandbox Create a labeled sandbox and capture its ID: -```powershell -aca sandbox create ` - --disk copilot ` - --label name=copilot-demo +```bash +# zsh/bash +CredentialId=$(aca sandboxgroup credential list \ + | jq -r 'first(.[] | select(.type == "github-copilot") | .id)') + +aca sandbox create --disk copilot --credential $CredentialId --label name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json +``` -$SandboxId = ( - aca sandbox list -l "name=copilot-demo" -o json | - ConvertFrom-Json -)[0].id +```powershell +# PowerShell +$CredentialId = (aca sandboxgroup credential list ` + | ConvertFrom-Json | Where-Object { $_.type -eq "github-copilot" })[0].id -$SandboxId -aca sandbox get --id $SandboxId -o json +aca sandbox create --disk copilot --credential $CredentialId --label name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json ``` The expected state is `Running`. -For production agent workloads, use deny-by-default egress and add only -reviewed destinations. This baseline covers the public repository and common -Copilot endpoints: +For production agent workloads, use deny-by-default egress and add only reviewed destinations. This baseline covers the public repository and common Copilot endpoints: + +```bash +# zsh/bash +aca sandbox egress set \ + --default Deny \ + --rule "*.github.com:Allow" \ + --rule "*.githubusercontent.com:Allow" \ + --rule "*.microsoft.com:Allow" \ + --rule "*.azure.com:Allow" \ + --traffic-inspection Full \ + -l name=ghcp-demo + +aca sandbox egress show -l name=ghcp-demo +``` ```powershell +# PowerShell aca sandbox egress set ` - --id $SandboxId ` - --default Deny ` - --rule "github.com:Allow" ` - --rule "api.github.com:Allow" ` - --rule "api.githubcopilot.com:Allow" ` - --rule "*.githubusercontent.com:Allow" ` - --traffic-inspection Full - -aca sandbox egress show --id $SandboxId + --default Deny ` + --rule "*.github.com:Allow" ` + --rule "*.githubusercontent.com:Allow" ` + --rule "*.microsoft.com:Allow" ` + --rule "*.azure.com:Allow" ` + --traffic-inspection Full ` + -l name=ghcp-demo + +aca sandbox egress show -l name=ghcp-demo ``` -If the portal reports another denied Copilot or GitHub hostname, review it and -add that exact hostname rather than changing the default to Allow. +If the portal reports another denied Copilot or GitHub hostname, review it and add that exact hostname rather than changing the default to Allow. Set an explicit memory suspend policy for the state-restoration demonstration: +```bash +# zsh/bash +aca sandbox lifecycle set \ + --auto-suspend enable \ + --mode Memory \ + --idle-timeout-seconds 900 \ + -l name=ghcp-demo + +aca sandbox lifecycle show -l name=ghcp-demo +``` + ```powershell +# PowerShell aca sandbox lifecycle set ` - --id $SandboxId ` - --auto-suspend enable ` - --mode Memory ` - --idle-timeout-seconds 900 + --auto-suspend enable ` + --mode Memory ` + --idle-timeout-seconds 900 ` + -l name=ghcp-demo + +aca sandbox lifecycle show -l name=ghcp-demo ``` ## 2. Prepare Copilot in the interactive shell -Open a real PTY using the label from the presentation: +Enter the sandbox using the label: -```powershell -aca sandbox shell -l "name=copilot-demo" +```bash +aca sandbox shell -l name=ghcp-demo ``` -There is no SSH daemon in an ACA Sandbox. Use `aca sandbox shell` for an -interactive terminal or `aca sandbox exec` for a one-shot command. +There is no SSH daemon in an ACA Sandbox. Use `aca sandbox shell` for an interactive terminal or `aca sandbox exec` for a one-shot command. Inside the sandbox: ```bash git --version copilot --version +cd /workspaces git clone https://github.com/devkimchi/battle-school-lunch.git cd battle-school-lunch git status --short @@ -109,19 +131,12 @@ TypeScript, and Tailwind v4 web UI under `src/web`. ## 3. Run the design-planning task -Use the prompt from the presentation: - -```text -이 프로젝트의 Web UI를 Brutal Design 스타일로 변경하려고 해. 코드는 수정하지 -말고, 변경 계획을 design-update.md 파일로 작성해 줘 -``` - -An English equivalent is: +Use the prompt: ```text -I want to restyle this project's web UI using Brutalist design. Do not modify -any source code. Inspect the existing UI and write a concrete implementation -plan to design-update.md at the repository root. +I'd like to update the current Web UI design style to Brutal Design. +Inspect the existing UI and generate a concrete implementation plan to `design-update.md`. +DO NOT change the codebase. ``` ## 4. Inspect the sandbox result @@ -129,57 +144,70 @@ plan to design-update.md at the repository root. Exit Copilot after it finishes, then verify from the sandbox shell: ```bash -test -f design-update.md -sed -n '1,160p' design-update.md +test -f design-update.md && echo "File exists" git status --short ``` -Expected result: `design-update.md` exists and source files remain unchanged. -The only `git status --short` entry should be the untracked plan file. +Expected result: `design-update.md` exists and source files remain unchanged. The only `git status --short` entry should be the untracked plan file. Record the working directory and checksum: ```bash -pwd sha256sum design-update.md -git diff --name-only exit ``` -`git diff --name-only` does not list untracked files, so use it together with -`git status --short`. - ## 5. Prove the stop and resume lifecycle Back in the host PowerShell session, capture the original identity and state: +```bash +# zsh/bash +aca sandbox get -l name=ghcp-demo -o json | jq -r "{id, state}" +``` + ```powershell -$Before = aca sandbox get --id $SandboxId -o json | ConvertFrom-Json -$Before.id -$Before.state +# PowerShell +aca sandbox get -l name=ghcp-demo -o json ` + | ConvertFrom-Json | Select-Object id, state | ConvertTo-Json ``` Stop the sandbox: +```bash +# zsh/bash +aca sandbox stop -l name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json | jq -r "{id, state}" +``` + ```powershell -aca sandbox stop --id $SandboxId -(aca sandbox get --id $SandboxId -o json | ConvertFrom-Json).state +# PowerShell +aca sandbox stop -l name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json ` + | ConvertFrom-Json | Select-Object id, state | ConvertTo-Json ``` -Wait for `Stopped`. In this state, CPU and memory compute charges stop; stored -state and related resources can still incur charges. +Wait for `Stopped`. In this state, CPU and memory compute charges stop; stored state and related resources can still incur charges. Resume the same sandbox: +```bash +# zsh/bash +aca sandbox resume -l name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json | jq -r "{id, state}" +``` + ```powershell -aca sandbox resume --id $SandboxId -(aca sandbox get --id $SandboxId -o json | ConvertFrom-Json).state +# PowerShell +aca sandbox resume -l name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json ` + | ConvertFrom-Json | Select-Object id, state | ConvertTo-Json ``` Wait for `Running`, then reconnect: ```powershell -aca sandbox shell --id $SandboxId +aca sandbox shell -l name=ghcp-demo ``` ## 6. Verify the resumed state @@ -188,11 +216,9 @@ Inside the resumed sandbox: ```bash cd battle-school-lunch -pwd -test -f design-update.md -sha256sum design-update.md -sed -n '1,40p' design-update.md +test -f design-update.md && echo "File exists" git status --short +sha256sum design-update.md exit ``` @@ -203,13 +229,11 @@ Confirm that: - `design-update.md` is present with the same checksum. - No application source file was modified. -Memory suspend mode also preserves running-process state. This demo validates -filesystem state because it is deterministic and visible to the audience. +Memory suspend mode also preserves running-process state. This demo validates filesystem state because it is deterministic and visible to the audience. ## 7. Preserve evidence and clean up -Continue with -[Demo 2 validation and recovery](demo-2-validation-and-recovery.md) to: +Continue with [Demo 2 validation and recovery](demo-2-validation-and-recovery.md) to: 1. Export `design-update.md`. 2. Review the state and validation evidence. @@ -218,10 +242,7 @@ Continue with ## Troubleshooting -Use the -[Demo 2 troubleshooting guide](demo-2-validation-and-recovery.md#troubleshooting) -for RBAC, disk image, Copilot authentication, egress, lifecycle, and preview -CLI failures. +Use the [Demo 2 troubleshooting guide](demo-2-validation-and-recovery.md#troubleshooting) for RBAC, disk image, Copilot authentication, egress, lifecycle, and preview CLI failures. ## References @@ -230,9 +251,6 @@ CLI failures. - [Interactive shell](https://sandboxes.azure.com/docs/sandboxes/sandbox/interactive-shell) - [Sandbox lifecycle](https://sandboxes.azure.com/docs/sandboxes/sandbox/lifecycle) -Commands and preview behavior were checked against the linked documentation on -August 24, 2026. - ## Navigation [Previous: Demo 2 environment setup](demo-2-setup.md) | diff --git a/docs/demo-2-setup.md b/docs/demo-2-setup.md index ea43841..6cfa44a 100644 --- a/docs/demo-2-setup.md +++ b/docs/demo-2-setup.md @@ -1,22 +1,12 @@ -# Demo 2 environment setup +# Demo 2: Environment setup -Complete this setup before presenting -[Demo 2](demo-2-runbook.md). The demo uses Azure Container Apps Sandboxes, -GitHub Copilot CLI, and -[`devkimchi/battle-school-lunch`](https://github.com/devkimchi/battle-school-lunch). - -> [!IMPORTANT] -> Azure Container Apps Sandboxes and the dedicated `aca` CLI are in public -> preview. Commands and resources created during preview can change or require -> recreation. Run `aca --help` against the installed version during -> rehearsal. +Complete this setup before presenting [Demo 2](demo-2-runbook.md). The demo uses Azure Container Apps Sandboxes, GitHub Copilot CLI, and [`devkimchi/battle-school-lunch`](https://github.com/devkimchi/battle-school-lunch). ## 1. Install the preview CLI -The `aca` CLI is separate from both Azure CLI and `az containerapp`. It uses -the Azure CLI identity for authentication. +The `aca` CLI is separate from both Azure CLI and `az containerapp`. It uses the Azure CLI identity for authentication. -### Windows PowerShell +### Windows ```powershell irm https://aka.ms/aca-cli-install-ps | iex @@ -30,106 +20,95 @@ curl -fsSL https://aka.ms/aca-cli-install | sh aca --version ``` -The same install path can also be used inside sandboxes and containers for -agent-driven self-installs. +The same install path can also be used inside sandboxes and containers for agent-driven self-installs. -Authenticate only when the current sessions are missing: +Login to Azure: ```powershell -az account show -o none 2>$null -if ($LASTEXITCODE -ne 0) { - az login -} - -aca auth status -if ($LASTEXITCODE -ne 0) { - aca auth login -} +az login ``` -Select the intended subscription: +Only Microsoft Entra ID accounts can access ACA Sandboxes. Personal Microsoft accounts are not supported. -```powershell -$SubscriptionId = az account show --query id -o tsv -az account set --subscription $SubscriptionId -``` +## 2. Create the sandbox group -Only Microsoft Entra ID accounts can access ACA Sandboxes. Personal Microsoft -accounts are not supported. +Create the sandbox group. This demo uses "Korea Central", but you can choose any region taht supports ACA Sandboxes. -## 2. Create the sandbox group +```bash +# zsh/bash +ResourceGroup="rg-ghcp-sandbox-demo" +SandboxGroup="ghcp-sandbox-demo" +Location="koreacentral" -Choose a supported region. Demo 2 uses Korea Central: +az group create --name $ResourceGroup --location $Location +aca sandboxgroup create --name $SandboxGroup --location $Location -g $ResourceGroup --set-config +``` ```powershell +# PowerShell $ResourceGroup = "rg-ghcp-sandbox-demo" $SandboxGroup = "ghcp-sandbox-demo" $Location = "koreacentral" -az group create ` - --name $ResourceGroup ` - --location $Location - -aca sandboxgroup create ` - --name $SandboxGroup ` - --location $Location ` - --set-config +az group create --name $ResourceGroup --location $Location +aca sandboxgroup create --name $SandboxGroup --location $Location -g $ResourceGroup --set-config ``` -`--set-config` stores the subscription, resource group, group, and region for -later `aca sandbox` commands. +`--set-config` stores the subscription, resource group, group, and region for later `aca sandbox` commands. -The caller needs permission to create the `Microsoft.App/SandboxGroups` -resource. Sandbox data-plane operations require **Container Apps SandboxGroup -Data Owner**. Group creation grants that role to the caller by default. Grant -it explicitly only to an additional presenter or automation principal: +The caller needs permission to create the `Microsoft.App/SandboxGroups` resource. Sandbox data-plane operations require **Container Apps SandboxGroup Data Owner**. Group creation grants that role to the caller by default. Grant it explicitly only to an additional presenter or automation principal: + +```bash +# zsh/bash +PrincipalId=$(az ad user list --upn "" --query "[0].id" -o tsv) + +aca sandboxgroup role create \ + --group $SandboxGroup \ + --role "Container Apps SandboxGroup Data Owner" \ + --principal-id $PrincipalId +``` ```powershell -$PrincipalId = az ad signed-in-user show --query id -o tsv +# PowerShell +$PrincipalId = az ad user list --upn "" --query "[0].id" -o tsv aca sandboxgroup role create ` - --group $SandboxGroup ` - --role "Container Apps SandboxGroup Data Owner" ` - --principal-id $PrincipalId + --group $SandboxGroup ` + --role "Container Apps SandboxGroup Data Owner" ` + --principal-id $PrincipalId ``` Treat a clean `aca doctor` result as the gate for the rest of the demo: -```powershell +```bash aca doctor aca config show ``` -RBAC changes can take several minutes to propagate. Retry `aca doctor` before -changing the role assignment. +RBAC changes can take several minutes to propagate. Retry `aca doctor` before changing the role assignment. ## 3. Configure the Copilot provider credential -Create a fine-grained GitHub personal access token with Copilot access. It must -start with `github_pat_`; classic `ghp_` tokens are not supported. +Create a fine-grained GitHub personal access token with Copilot access. It must start with `github_pat_`; classic `ghp_` tokens are not supported. -1. Open [ACA Sandboxes](https://sandboxes.azure.com/sandbox-groups). -2. Open `ghcp-sandbox-demo`. -3. Open **Credentials** and select **Set Token** for **GitHub Copilot**. -4. Paste the fine-grained token and save it. -5. Confirm that its status is **Configured**. - -Provider credentials are stored as sandbox-group connections. The platform -injects authentication for the provider when a sandbox starts; the saved token -is not displayed again in the portal. Recreate or restart sandboxes after -rotating the token. - -The presentation slide includes this older preview command shape: +```bash +# zsh/bash +GH_PAT="github_pat_*" +CredentialId=$(aca sandboxgroup credential create \ + --type github-copilot --token "$GH_PAT" -o json | jq -r .id) +``` -```text -aca sandbox create --disk copilot --credential +```powershell +# PowerShell +$GH_PAT = "github_pat_*" +$CredentialId = aca sandboxgroup credential create ` + --type github-copilot --token "$GH_PAT" -o json | jq -r .id ``` -The current preview credential documentation configures the credential at -group scope, and the current published CLI reference does not document -`--credential`. Use `aca sandbox create --help` during rehearsal. Add the -flag only if the installed CLI documents it and the portal supplies a -connection ID; never pass the raw PAT on the command line. +> [!NOTE] +> `*` is the rest part of your GitHub PAT. + +Provider credentials are stored as sandbox-group connections. The platform injects authentication for the provider when a sandbox starts; Recreate or restart sandboxes after rotating the token. ## 4. Verify the Copilot disk image @@ -139,13 +118,7 @@ List the public disk names accepted by `--disk`: aca sandboxgroup disk list-public ``` -Confirm that `copilot` is present. Public images use `--disk `. Private -or committed images use `--disk-id `. - -If the public `copilot` image is unavailable in the selected region or CLI -release, stop the rehearsal and choose a supported region or a reviewed custom -disk image. Do not silently substitute `ubuntu`: Demo 2 expects Copilot CLI to -be preinstalled and authenticated. +Confirm that `copilot` is present. Public images use `--disk `. ## 5. Preflight @@ -157,7 +130,6 @@ aca auth status aca doctor aca config show aca sandboxgroup disk list-public -aca sandbox list -l "name=copilot-demo" ``` The expected result is: @@ -166,11 +138,6 @@ The expected result is: - `aca doctor` reports a valid group and Data Owner role. - The configured group is `ghcp-sandbox-demo`. - The `copilot` public disk is available. -- No stale `copilot-demo` sandbox contains state that must be preserved. - -If a stale sandbox exists, follow -[Demo 2 validation and recovery](demo-2-validation-and-recovery.md) before -deleting it. ## References @@ -180,9 +147,6 @@ deleting it. - [Provider credentials](https://sandboxes.azure.com/docs/sandboxes/credentials) - [Disk images](https://sandboxes.azure.com/docs/sandboxes/disk-images) -Commands and preview behavior were checked against the linked documentation on -August 24, 2026. - ## Navigation Next: [Demo 2 live runbook](demo-2-runbook.md) diff --git a/docs/demo-2-validation-and-recovery.md b/docs/demo-2-validation-and-recovery.md index 6f07ccd..d10f78d 100644 --- a/docs/demo-2-validation-and-recovery.md +++ b/docs/demo-2-validation-and-recovery.md @@ -1,4 +1,4 @@ -# Demo 2 validation and recovery +# Demo 2: Validation and recovery Use this guide after the Demo 2 run, or when the live path needs recovery. @@ -6,127 +6,176 @@ Use this guide after the Demo 2 run, or when the live path needs recovery. Confirm the repository path inside the sandbox: +```bash +# zsh/bash +aca sandbox exec \ + -l name=ghcp-demo \ + -c "cd /workspaces/battle-school-lunch && pwd && sha256sum design-update.md" +``` + ```powershell +# PowerShell aca sandbox exec ` - --id $SandboxId ` - -c "cd battle-school-lunch && pwd && sha256sum design-update.md" + -l name=ghcp-demo ` + -c "cd /workspaces/battle-school-lunch && pwd && sha256sum design-update.md" ``` Export the generated plan with the data-plane file API rather than `scp`: +```bash +# zsh/bash +aca sandbox fs cat \ + -l name=ghcp-demo \ + --path /workspaces/battle-school-lunch/design-update.md \ + > ./design-update.md +``` + ```powershell +# PowerShell aca sandbox fs cat ` - --id $SandboxId ` - --path /home/coder/battle-school-lunch/design-update.md | - Set-Content -Encoding utf8 .\design-update.md + -l name=ghcp-demo ` + --path /workspaces/battle-school-lunch/design-update.md ` + | Set-Content ./design-update.md -Encoding utf8 -Force ``` -Adjust `--path` if `pwd` shows that the `copilot` image uses a different home -directory. +> [!CAUTION] +> Adjust `--path` if `pwd` shows that the `copilot` image uses a different directory. ## Snapshot the remote state -Snapshot before deletion when the repository and sandbox state are worth -preserving: +Snapshot before deletion when the repository and sandbox state are worth preserving: + +```bash +# zsh/bash +aca sandbox snapshot \ + -l name=ghcp-demo \ + --name ghcp-demo-complete +``` ```powershell +# PowerShell aca sandbox snapshot ` - --id $SandboxId ` - --name demo2-complete + -l name=ghcp-demo ` + --name ghcp-demo-complete ``` -A snapshot preserves state independently of the running sandbox. A new sandbox -can be created from it: +A snapshot preserves state independently of the running sandbox. A new sandbox can be created from it: ```powershell -aca sandbox create --snapshot demo2-complete +aca sandbox create --snapshot ghcp-demo-complete --label name=ghcp-demo-from-snapshot +aca sandbox shell -l name=ghcp-demo-from-snapshot ``` ## Validation checklist -| Evidence | Expected result | -| --- | --- | -| `aca doctor` | Group configuration and Data Owner role pass | -| Initial sandbox state | `Running` | -| Copilot authentication | Starts without placing a token in the repository | -| Repository status before the task | Clean | -| Generated artifact | `design-update.md` exists | -| Source changes | No application source file changed | -| State after stop | `Stopped` | -| State after resume | `Running` | -| Sandbox identity | Same ID before and after resume | -| Plan checksum | Same before and after resume | +| Evidence | Expected result | +| --------------------------------- | ------------------------------------------------ | +| `aca doctor` | Group configuration and Data Owner role pass | +| Initial sandbox state | `Running` | +| Copilot authentication | Starts without placing a token in the repository | +| Repository status before the task | Clean | +| Generated artifact | `design-update.md` exists | +| Source changes | No application source file changed | +| State after stop | `Stopped` | +| State after resume | `Running` | +| Sandbox identity | Same ID before and after resume | +| Plan checksum | Same before and after resume | ## Troubleshooting ### `aca doctor` reports an RBAC failure -Verify that the presenter has **Container Apps SandboxGroup Data Owner** at the -group or parent scope. Wait for propagation, then rerun `aca doctor`. +Verify that the presenter has **Container Apps SandboxGroup Data Owner** at the group or parent scope. Wait for propagation, then rerun `aca doctor`. ### `copilot` is not a public disk Run: -```powershell +```bash aca sandboxgroup disk list-public ``` -Preview image availability can vary by release and region. Use a supported -region or build a reviewed custom disk from an OCI image: +Preview image availability can vary by release and region. Use a supported region or build a reviewed custom disk from an OCI image: + +```bash +# zsh/bash +aca sandboxgroup disk create \ + --image docker/sandbox-templates:copilot-docker \ + --name ghcp-demo-image + +aca sandboxgroup disk list +``` ```powershell +# PowerShell aca sandboxgroup disk create ` - --image /: ` - --name copilot-demo-image + --image docker/sandbox-templates:copilot-docker ` + --name ghcp-demo-image aca sandboxgroup disk list ``` Create from the returned private image ID with `--disk-id`, not `--disk`. +```bash +# zsh/bash +DiskId=$(aca sandboxgroup disk list -o json | jq -r "first(.[] | .id)") +aca sandbox create --disk-id $DiskId --label name=custom-ghcp-demo +aca sandbox shell -l name=custom-ghcp-demo +``` + +```powershell +# PoewrShell +$DiskId = (aca sandboxgroup disk list -o json | ConvertFrom-Json)[0].id +aca sandbox create --disk-id $DiskId --label name=custom-ghcp-demo +aca sandbox shell -l name=custom-ghcp-demo +``` + +> [!NOTE] +> You may find out official Docker Sandbox images from [Docker Hub](https://hub.docker.com/r/docker/sandbox-templates/tags). + ### Copilot authentication fails -Confirm that the group credential status is **Configured**, the token is a -fine-grained `github_pat_` token with Copilot access, and the sandbox was -created after the credential was saved. Recreate the sandbox after credential -rotation. +Confirm that the group credential status is **Configured**, the token is a fine-grained `github_pat_` token with Copilot access, and the sandbox was created after the credential was saved. Recreate the sandbox after credential rotation. ### Git clone or Copilot traffic is blocked Inspect the sandbox egress policy: ```powershell -aca sandbox egress show --id $SandboxId +aca sandbox egress show -l name=ghcp-demo ``` -Review denied connection decisions and add only the required hostname. Do not -disable deny-by-default policy to work around one missing rule. +Review denied connection decisions and add only the required hostname. Do not disable deny-by-default policy to work around one missing rule. ### The plan disappears after resume Confirm that the same sandbox ID was resumed: ```powershell -$SandboxId -aca sandbox get --id $SandboxId -o json +aca sandbox get -l name=ghcp-demo -o json ``` -Confirm that the shell returned to the same repository path. The -`aca sandbox create` command creates a different sandbox; -`aca sandbox resume --id $SandboxId` resumes the existing one. +Confirm that the shell returned to the same repository path. The `aca sandbox create` command creates a different sandbox; `aca sandbox resume ...` resumes the existing one. ### The sandbox remains stopped Resume it explicitly and wait for `Running`: +```bash +# zsh/bash +aca sandbox resume -l name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json | jq -r "{id, state}" +``` + ```powershell -aca sandbox resume --id $SandboxId -(aca sandbox get --id $SandboxId -o json | ConvertFrom-Json).state +# PowerShell +aca sandbox resume -l name=ghcp-demo +aca sandbox get -l name=ghcp-demo -o json ` + | ConvertFrom-Json | Select-Object id, state | ConvertTo-Json ``` -If resume fails, inspect the Azure activity log and retry only after identifying -the provisioning or policy error. +If resume fails, inspect the Azure activity log and retry only after identifying the provisioning or policy error. ### A preview command rejects a flag @@ -143,35 +192,36 @@ Do not mix commands from different preview releases. ## Cleanup -Export or snapshot every artifact you want to preserve before deletion. -Deleting a sandbox is destructive: +Export or snapshot every artifact you want to preserve before deletion. Deleting a sandbox is destructive: ```powershell -aca sandbox delete --id $SandboxId --yes +aca sandbox delete -l name=ghcp-deno --yes ``` Confirm that the labeled sandbox is gone: ```powershell -aca sandbox list -l "name=copilot-demo" +aca sandbox list -l "name=ghcp-demo" ``` -If the whole demo environment is no longer needed, deleting its group also -deletes all remaining sandboxes, snapshots, disk images, volumes, secrets, -identities, and connector attachments: +If the whole demo environment is no longer needed, deleting its group also deletes all remaining sandboxes, snapshots, disk images, volumes, secrets, identities, and connector attachments: + +```bash +# zsh/bash +ResourceGroup="rg-ghcp-sandbox-demo" +SandboxGroup="ghcp-sandbox-demo" + +aca sandboxgroup delete --name $SandboxGroup --yes +az group delete --name $ResourceGroup --yes --no-wait +``` ```powershell +# PowerShell $ResourceGroup = "rg-ghcp-sandbox-demo" $SandboxGroup = "ghcp-sandbox-demo" -aca sandboxgroup delete ` - --name $SandboxGroup ` - --yes - -az group delete ` - --name $ResourceGroup ` - --yes ` - --no-wait +aca sandboxgroup delete --name $SandboxGroup --yes +az group delete --name $ResourceGroup --yes --no-wait ``` ## Navigation