Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .copilot_here/runtime.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
auto
55 changes: 49 additions & 6 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Project Overview

This is a secure, portable Docker environment for running the GitHub Copilot CLI. It provides sandboxed execution with automatic authentication, token validation, and multiple specialized image variants for different development scenarios.
This is a secure, portable container environment for running the GitHub Copilot CLI. It provides sandboxed execution with automatic authentication, token validation, and multiple specialized image variants for different development scenarios. Supports Docker, OrbStack, and Podman container runtimes with automatic detection.

## Code Repos/Name locations part of this "platform"

Expand Down Expand Up @@ -88,7 +88,7 @@ grep "BuildDate = " app/Infrastructure/BuildInfo.cs
- **Base OS**: Debian (node:20-slim)
- **Runtime**: Node.js 20
- **CLI Tool**: GitHub Copilot CLI (@github/copilot)
- **Container**: Docker (Multi-arch: AMD64 & ARM64)
- **Container**: Docker, OrbStack, or Podman (Multi-arch: AMD64 & ARM64)
- **CI/CD**: GitHub Actions
- **Registry**: GitHub Container Registry (ghcr.io)

Expand All @@ -99,7 +99,8 @@ grep "BuildDate = " app/Infrastructure/BuildInfo.cs
The core CLI is a .NET 10 Native AOT application that:

- Validates GitHub authentication and token scopes
- Manages Docker image selection and pulling
- Detects and manages container runtime (Docker, OrbStack, or Podman)
- Manages container image selection and pulling
- Configures mounts, airlock, and container settings
- Builds and executes Docker Compose configurations
- Handles both safe mode (confirmation required) and YOLO mode (auto-approve)
Expand All @@ -108,8 +109,10 @@ The core CLI is a .NET 10 Native AOT application that:

- `Program.cs` - Entry point, argument parsing, command routing
- `Commands/Run/RunCommand.cs` - Main execution logic
- `Commands/Runtime/` - Runtime configuration commands
- `Infrastructure/GitHubAuth.cs` - Token validation and scope checking
- `Infrastructure/DockerRunner.cs` - Docker process management
- `Infrastructure/ContainerRunner.cs` - Container process management
- `Infrastructure/ContainerRuntimeConfig.cs` - Runtime detection and configuration
- `Infrastructure/AirlockRunner.cs` - Network proxy mode
- `Infrastructure/DebugLogger.cs` - Debug logging infrastructure

Expand Down Expand Up @@ -168,6 +171,40 @@ Extends the Playwright image with:

**Use Case**: .NET development, building and testing .NET applications with web testing capabilities

## Container Runtime Support

The CLI supports multiple container runtimes with automatic detection:

### Supported Runtimes

1. **Docker** - Standard Docker Engine or Docker Desktop
2. **OrbStack** - Automatically detected when Docker context is set to OrbStack
3. **Podman** - Open-source alternative with rootless support

### Runtime Detection

- **Auto-detection**: Tries Docker first, then Podman
- **Configuration**: Users can override via config files or commands
- **Per-project**: Different projects can use different runtimes

### Configuration System

**Priority order:**
1. Local config (`.copilot_here/runtime.conf`)
2. Global config (`~/.config/copilot_here/runtime.conf`)
3. Auto-detection

**Commands:**
- `--show-runtime` - Display current runtime configuration
- `--list-runtimes` - List all available runtimes on the system
- `--set-runtime <runtime>` - Set local runtime preference
- `--set-runtime-global <runtime>` - Set global runtime preference

**Implementation:**
- `Infrastructure/ContainerRuntimeConfig.cs` - Runtime detection and configuration
- `Commands/Runtime/` - Runtime management commands
- All container operations use `ContainerRunner` (formerly `DockerRunner`)

## Airlock Network Proxy

Airlock is a security feature that provides network request monitoring and control:
Expand Down Expand Up @@ -195,7 +232,7 @@ Airlock is a security feature that provides network request monitoring and contr
**Technical implementation:**

- Proxy: mitmproxy-based container (`docker/Dockerfile.proxy`)
- Runner: `Infrastructure/AirlockRunner.cs` orchestrates Docker Compose setup
- Runner: `Infrastructure/AirlockRunner.cs` orchestrates container compose setup
- Certificates: CA cert shared between proxy and app containers
- Logging: Network activity logged to `.copilot_here/logs/`

Expand Down Expand Up @@ -378,6 +415,10 @@ dotnet test
- Follow .NET naming conventions (PascalCase for public members)
- Add XML documentation comments for public APIs
- Use AOT-compatible patterns (avoid reflection, dynamic code generation)
- **NEVER use `[Obsolete]` attribute** - just remove or refactor code instead
- Obsolete attributes clutter the codebase and create compiler warnings
- If something needs to change, change it - don't mark it as obsolete
- If you need to maintain backward compatibility, keep both approaches working

### Configuration Priority

Expand Down Expand Up @@ -474,11 +515,13 @@ var deduplicated = RemoveDuplicates(items);
│ │ ├── Run/ # Main run command
│ │ ├── Images/ # Image management
│ │ ├── Mounts/ # Mount configuration
│ │ ├── Runtime/ # Runtime configuration
│ │ └── Airlock/ # Network proxy
│ ├── Infrastructure/ # Core services
│ │ ├── AppPaths.cs # Path resolution
│ │ ├── GitHubAuth.cs # Authentication
│ │ ├── DockerRunner.cs # Docker management
│ │ ├── ContainerRunner.cs # Container management
│ │ ├── ContainerRuntimeConfig.cs # Runtime detection
│ │ ├── AirlockRunner.cs # Proxy mode
│ │ └── DebugLogger.cs # Debug logging
│ ├── Program.cs # Entry point
Expand Down
54 changes: 30 additions & 24 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ jobs:
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: .
file: ./docker/Dockerfile.base
file: ./docker/tools/github-copilot/Dockerfile
platforms: linux/amd64,linux/arm64
push: false
load: false
Expand All @@ -412,12 +412,13 @@ jobs:
uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
with:
context: .
file: ./docker/Dockerfile.base
file: ./docker/tools/github-copilot/Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/${{ steps.repo.outputs.name }}:latest
ghcr.io/${{ steps.repo.outputs.name }}:sha-${{ github.sha }}
ghcr.io/${{ steps.repo.outputs.name }}:copilot-latest
ghcr.io/${{ steps.repo.outputs.name }}:copilot-sha-${{ github.sha }}
labels: project=copilot_here
build-args: |
COPILOT_VERSION=${{ steps.versions.outputs.copilot_version }}
Expand All @@ -436,25 +437,25 @@ jobs:
include:
- variant: rust
dockerfile: ./docker/variants/Dockerfile.rust
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}"
- variant: golang
dockerfile: ./docker/variants/Dockerfile.golang
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}"
- variant: playwright
dockerfile: ./docker/variants/Dockerfile.playwright
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}\nPLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}\nPLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION"
- variant: dotnet-8
dockerfile: ./docker/variants/Dockerfile.dotnet8
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}\nDOTNET_SDK_8_VERSION=$DOTNET_8_VERSION"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}\nDOTNET_SDK_8_VERSION=$DOTNET_8_VERSION"
- variant: dotnet-9
dockerfile: ./docker/variants/Dockerfile.dotnet9
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}\nDOTNET_SDK_9_VERSION=$DOTNET_9_VERSION"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}\nDOTNET_SDK_9_VERSION=$DOTNET_9_VERSION"
- variant: dotnet-10
dockerfile: ./docker/variants/Dockerfile.dotnet10
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}\nDOTNET_SDK_10_VERSION=$DOTNET_10_VERSION"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}\nDOTNET_SDK_10_VERSION=$DOTNET_10_VERSION"
- variant: dotnet
dockerfile: ./docker/variants/Dockerfile.dotnet
build_args: "BASE_IMAGE_TAG=sha-${{ github.sha }}\nDOTNET_SDK_8_VERSION=$DOTNET_8_VERSION\nDOTNET_SDK_9_VERSION=$DOTNET_9_VERSION\nDOTNET_SDK_10_VERSION=$DOTNET_10_VERSION"
build_args: "BASE_IMAGE_TAG=copilot-sha-${{ github.sha }}\nDOTNET_SDK_8_VERSION=$DOTNET_8_VERSION\nDOTNET_SDK_9_VERSION=$DOTNET_9_VERSION\nDOTNET_SDK_10_VERSION=$DOTNET_10_VERSION"
steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
Expand Down Expand Up @@ -494,7 +495,8 @@ jobs:
push: true
tags: |
ghcr.io/${{ needs.build-base.outputs.repo_name }}:${{ matrix.variant }}
ghcr.io/${{ needs.build-base.outputs.repo_name }}:${{ matrix.variant }}-sha-${{ github.sha }}
ghcr.io/${{ needs.build-base.outputs.repo_name }}:copilot-${{ matrix.variant }}
ghcr.io/${{ needs.build-base.outputs.repo_name }}:copilot-${{ matrix.variant }}-sha-${{ github.sha }}
labels: project=copilot_here
build-args: ${{ steps.args.outputs.build_args }}
cache-from: type=registry,ref=ghcr.io/${{ needs.build-base.outputs.repo_name }}:${{ matrix.variant }},mode=max
Expand All @@ -512,10 +514,10 @@ jobs:
include:
- variant: dotnet-playwright
dockerfile: ./docker/compound-variants/Dockerfile.dotnet-playwright
build_args: "DOTNET_IMAGE_TAG=dotnet-sha-${{ github.sha }}\nPLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION"
build_args: "DOTNET_IMAGE_TAG=copilot-dotnet-sha-${{ github.sha }}\nPLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION"
- variant: dotnet-rust
dockerfile: ./docker/compound-variants/Dockerfile.dotnet-rust
build_args: "DOTNET_IMAGE_TAG=dotnet-sha-${{ github.sha }}"
build_args: "DOTNET_IMAGE_TAG=copilot-dotnet-sha-${{ github.sha }}"
steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
Expand Down Expand Up @@ -551,7 +553,8 @@ jobs:
push: true
tags: |
ghcr.io/${{ needs.build-base.outputs.repo_name }}:${{ matrix.variant }}
ghcr.io/${{ needs.build-base.outputs.repo_name }}:${{ matrix.variant }}-sha-${{ github.sha }}
ghcr.io/${{ needs.build-base.outputs.repo_name }}:copilot-${{ matrix.variant }}
ghcr.io/${{ needs.build-base.outputs.repo_name }}:copilot-${{ matrix.variant }}-sha-${{ github.sha }}
labels: project=copilot_here
build-args: ${{ steps.args.outputs.build_args }}
cache-from: type=registry,ref=ghcr.io/${{ needs.build-base.outputs.repo_name }}:${{ matrix.variant }},mode=max
Expand Down Expand Up @@ -585,17 +588,20 @@ jobs:

if [[ "${{ needs.build-base.outputs.push_needed }}" == "true" ]]; then
echo "**Images Published:**" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:latest\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:latest\` (legacy)" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:copilot-latest\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:proxy\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:rust\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:golang\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:playwright\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:dotnet\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:dotnet-8\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:dotnet-9\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:dotnet-10\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:dotnet-playwright\`" >> $GITHUB_STEP_SUMMARY
echo "- \`ghcr.io/${{ needs.build-base.outputs.repo_name }}:dotnet-rust\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Variants (with copilot- prefix):**" >> $GITHUB_STEP_SUMMARY
echo "- \`rust\`, \`copilot-rust\`" >> $GITHUB_STEP_SUMMARY
echo "- \`golang\`, \`copilot-golang\`" >> $GITHUB_STEP_SUMMARY
echo "- \`playwright\`, \`copilot-playwright\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dotnet\`, \`copilot-dotnet\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dotnet-8\`, \`copilot-dotnet-8\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dotnet-9\`, \`copilot-dotnet-9\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dotnet-10\`, \`copilot-dotnet-10\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dotnet-playwright\`, \`copilot-dotnet-playwright\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dotnet-rust\`, \`copilot-dotnet-rust\`" >> $GITHUB_STEP_SUMMARY
else
echo "**Images:** No changes, skipped publishing" >> $GITHUB_STEP_SUMMARY
fi
Expand Down
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The `copilot_here` shell function is a lightweight wrapper around a Docker conta
## ✅ Prerequisites

Before you start, make sure you have the following installed and configured on your machine:
- [Docker Desktop](https://www.docker.com/products/docker-desktop/) (or Docker Engine on Linux).
- **Container Runtime**: [Docker Desktop](https://www.docker.com/products/docker-desktop/), [OrbStack](https://orbstack.dev/), or [Podman](https://podman.io/). The system will auto-detect your available runtime.
- The [GitHub CLI (`gh`)](https://cli.github.com/).
- You must be logged in to the GitHub CLI. You can check by running `gh auth status`. Your token **must** have the `copilot` and `read:packages` scopes. If it doesn't, run `gh auth refresh -h github.com -s copilot,read:packages` to add them.

Expand Down Expand Up @@ -129,6 +129,30 @@ You can configure the default AI model to use so you don't have to pass `--model
**Configuration Priority:**
1. CLI argument (`--model <model-id>`)
2. Local config (`.copilot_here/model.conf`)

### Container Runtime Management

`copilot_here` supports multiple container runtimes: **Docker**, **OrbStack**, and **Podman**. The system automatically detects the available runtime, but you can also configure a preferred runtime.

**Management Commands:**
- `--show-runtime` - Show current container runtime configuration
- `--list-runtimes` - List all available container runtimes on your system
- `--set-runtime <runtime>` - Set runtime in local config (values: `docker`, `podman`, or `auto`)
- `--set-runtime-global <runtime>` - Set runtime in global config

**Configuration Files:**
- Global: `~/.config/copilot_here/runtime.conf`
- Local: `.copilot_here/runtime.conf`

**Configuration Priority:**
1. Local config (`.copilot_here/runtime.conf`)
2. Global config (`~/.config/copilot_here/runtime.conf`)
3. Auto-detection (tries Docker first, then Podman)

**Supported Runtimes:**
- **Docker** - Standard Docker Engine or Docker Desktop
- **OrbStack** - Automatically detected when Docker context is set to OrbStack
- **Podman** - Open-source container runtime (auto-detects compose support)
3. Global config (`~/.config/copilot_here/model.conf`)
4. Default (GitHub Copilot CLI default)

Expand Down
Loading