Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
29 changes: 28 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,20 @@

SHELL ["/bin/bash", "-c"]

# --------------------------------------------
# Build args (opt-in toggles)
# --------------------------------------------
ARG COPILOT_CLI_ENABLED=false
ARG COPILOT_CLI_MCP_SEED=false
ARG COPILOT_CLI_INSTALL_METHOD=auto
ARG COPILOT_CLI_VERSION=
ARG COPILOT_CLI_PREFIX=/usr/local
ARG BROWSERS_ENABLED=false

# --------------------------------------------
# ENV Defaults (override with Docker Compose or CLI)
# --------------------------------------------
ENV LANGUAGES=node,python,java \

Check warning on line 31 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "GITLAB_PERSONAL_ACCESS_TOKEN") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 31 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "OPENAI_API_KEY") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/

Check warning on line 31 in Dockerfile

View workflow job for this annotation

GitHub Actions / build

Sensitive data should not be used in the ARG or ENV commands

SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data (ENV "VSCODE_PASSWORD") More info: https://docs.docker.com/go/dockerfile/rule/secrets-used-in-arg-or-env/
NODE_VERSION=20.11.1 \
ASDF_VERSION=v0.14.0 \
PYTHON_VERSION=3.12.1 \
Expand All @@ -28,7 +38,13 @@
VSCODE_PASSWORD=agent \
OPENAI_API_KEY=your_openai_api_key_here \
OPENAI_MODEL=gpt-4 \
GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token_here
GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token_here \
COPILOT_CLI_ENABLED=${COPILOT_CLI_ENABLED} \
COPILOT_CLI_MCP_SEED=${COPILOT_CLI_MCP_SEED} \
COPILOT_CLI_INSTALL_METHOD=${COPILOT_CLI_INSTALL_METHOD} \
COPILOT_CLI_VERSION=${COPILOT_CLI_VERSION} \
COPILOT_CLI_PREFIX=${COPILOT_CLI_PREFIX} \
BROWSERS_ENABLED=${BROWSERS_ENABLED}

# --------------------------------------------
# Locale setup
Expand Down Expand Up @@ -71,6 +87,11 @@
COPY src/scripts /opt/scripts/
RUN chmod +x /opt/scripts/*.sh || true

# --------------------------------------------
# Copilot CLI MCP templates
# --------------------------------------------
COPY src/copilot /opt/copilot/

# --------------------------------------------
# Install languages
# --------------------------------------------
Expand All @@ -80,6 +101,12 @@
# Source bashrc to load asdf and installed languages
RUN . ~/.bashrc

# --------------------------------------------
# Optional: browsers + Copilot CLI
# --------------------------------------------
RUN bash /opt/scripts/install_browsers.sh
RUN bash /opt/scripts/install_copilot_cli.sh
Comment on lines +96 to +100
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

install_browsers.sh and install_copilot_cli.sh run at image build time, but the PR only wires COPILOT_CLI_ENABLED/BROWSERS_ENABLED via runtime docker-compose environment variables. As a result, these opt-in installs can’t be enabled via compose as documented. Use ARG + ENV in the Dockerfile and build.args in docker-compose.yml (or move these installs to container startup).

Copilot uses AI. Check for mistakes.

# --------------------------------------------
# VS Code + extensions + MCPs + settings
# --------------------------------------------
Expand Down
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,61 @@ Each script should support:

---

## 🤖 Copilot CLI + MCP (opt-in)

This image can optionally install GitHub Copilot CLI and seed a CLI-level MCP config for WebdriverIO MCP.

### Enable during build

Use build args (recommended) to enable the install and seed the MCP config:

```bash
COPILOT_CLI_ENABLED=true \
COPILOT_CLI_MCP_SEED=true \
docker compose -f docker-compose.yml up --build
```
Comment on lines +142 to +148
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Enable during build” snippet sets env vars for docker compose up --build, but the compose file doesn’t pass these as build.args, and the Dockerfile doesn’t declare ARGs for them. This means the Copilot/browser installs won’t actually be enabled during build as documented. Update the docs to show the correct build-arg usage (or update compose/Dockerfile to match the documented flow).

Copilot uses AI. Check for mistakes.

Optional build flags:

- `COPILOT_CLI_INSTALL_METHOD` = `auto` | `script` | `npm`
- `COPILOT_CLI_VERSION` = specific version (optional)
- `COPILOT_CLI_PREFIX` = install prefix (default `/usr/local`)
- `BROWSERS_ENABLED=true` to install Chromium for MCP browser automation

### MCP seed template

The template lives at [src/copilot/mcp-config.json](src/copilot/mcp-config.json) and is copied to:

```
~/.copilot/mcp-config.json
```

### Authenticate and verify

Inside the container:

```bash
copilot --version
copilot
```

If prompted, run `/login` and follow the instructions. You can also set `GH_TOKEN` or `GITHUB_TOKEN`.

### Minimal demo (headless browser + screenshot)

With MCP seeded and browsers enabled, run a simple flow from Copilot CLI:

1. Start a session
2. Navigate to a URL
3. Take a screenshot
4. Close the session

Example prompt to Copilot CLI:

"Use wdio-mcp to open a headless browser, navigate to https://example.com, take a screenshot at /workspace/example.png, then close the session."

---

---

## 📄 Roadmap
Expand Down
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ services:
build:
context: .
dockerfile: Dockerfile
args:
COPILOT_CLI_ENABLED: "${COPILOT_CLI_ENABLED:-false}"
COPILOT_CLI_MCP_SEED: "${COPILOT_CLI_MCP_SEED:-false}"
COPILOT_CLI_INSTALL_METHOD: "${COPILOT_CLI_INSTALL_METHOD:-auto}"
COPILOT_CLI_VERSION: "${COPILOT_CLI_VERSION:-}"
COPILOT_CLI_PREFIX: "${COPILOT_CLI_PREFIX:-/usr/local}"
BROWSERS_ENABLED: "${BROWSERS_ENABLED:-false}"
container_name: aw-dev-node
ports:
- "${VSCODE_PORT:-8443}:${VSCODE_PORT:-8443}"
Expand All @@ -18,6 +25,12 @@ services:
OPENAI_API_KEY: "${OPENAI_API_KEY}"
OPENAI_MODEL: "${OPENAI_MODEL}"
GITLAB_PERSONAL_ACCESS_TOKEN: "${GITLAB_PERSONAL_ACCESS_TOKEN}"
COPILOT_CLI_ENABLED: "${COPILOT_CLI_ENABLED:-false}"
COPILOT_CLI_MCP_SEED: "${COPILOT_CLI_MCP_SEED:-false}"
COPILOT_CLI_INSTALL_METHOD: "${COPILOT_CLI_INSTALL_METHOD:-auto}"
COPILOT_CLI_VERSION: "${COPILOT_CLI_VERSION:-}"
COPILOT_CLI_PREFIX: "${COPILOT_CLI_PREFIX:-/usr/local}"
BROWSERS_ENABLED: "${BROWSERS_ENABLED:-false}"
Comment on lines +20 to +25
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These variables are set under environment: (container runtime), but the Copilot/Chrome installs happen during docker build (Dockerfile RUN bash /opt/scripts/...). As written, toggling COPILOT_CLI_ENABLED / BROWSERS_ENABLED here won’t change what gets installed in the image. Add build.args for these flags (and consume them via ARG in the Dockerfile), or perform the installs at container startup.

Copilot uses AI. Check for mistakes.
volumes:
- ./src/workspace:/workspace
tty: true
10 changes: 10 additions & 0 deletions env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ VSCODE_PASSWORD=agent
OPENAI_API_KEY=your_openai_api_key_here
OPENAI_MODEL=gpt-4

# Copilot CLI (opt-in, build args recommended)
COPILOT_CLI_ENABLED=false
COPILOT_CLI_MCP_SEED=false
COPILOT_CLI_INSTALL_METHOD=auto
COPILOT_CLI_VERSION=
COPILOT_CLI_PREFIX=/usr/local

# Browser runtime for MCPs (opt-in, build args recommended)
BROWSERS_ENABLED=false

# MCP - sequentialthinking
DISABLE_THOUGHT_LOGGING=false

Expand Down
19 changes: 19 additions & 0 deletions src/copilot/mcp-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"mcpServers": {
"wdio-mcp": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@wdio/mcp"],
"tools": [
"start_browser",
"navigate",
"get_visible_elements",
"click_element",
"set_value",
"scroll",
"take_screenshot",
"close_session"
]
}
}
}
50 changes: 50 additions & 0 deletions src/scripts/install_browsers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail

echo "Installing browser runtime (opt-in)"

: "${BROWSERS_ENABLED:=false}"

if [[ "${BROWSERS_ENABLED}" != "true" ]]; then
echo "BROWSERS_ENABLED is not true; skipping browser install."
exit 0
fi

apt-get update

# Try Chromium first; fall back between package names across distros
if ! apt-get install -y --no-install-recommends \
chromium-browser \
libnss3 \
libatk-bridge2.0-0 \
libgtk-3-0 \
libx11-xcb1 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
libgbm1 \
libasound2 \
fonts-liberation; then
apt-get install -y --no-install-recommends \
chromium \
libnss3 \
libatk-bridge2.0-0 \
libgtk-3-0 \
libx11-xcb1 \
libxcomposite1 \
libxdamage1 \
libxrandr2 \
libgbm1 \
libasound2 \
fonts-liberation
fi

apt-get clean && rm -rf /var/lib/apt/lists/*

if command -v chromium-browser >/dev/null 2>&1; then
echo "Chromium installed: $(chromium-browser --version || true)"
elif command -v chromium >/dev/null 2>&1; then
echo "Chromium installed: $(chromium --version || true)"
else
echo "Browser install completed, but no Chromium binary found on PATH." >&2
fi
66 changes: 66 additions & 0 deletions src/scripts/install_copilot_cli.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env bash
set -euo pipefail

echo "Installing GitHub Copilot CLI (opt-in)"

: "${COPILOT_CLI_ENABLED:=false}"
: "${COPILOT_CLI_INSTALL_METHOD:=auto}"
: "${COPILOT_CLI_INSTALL_URL:=https://gh.io/copilot-install}"
: "${COPILOT_CLI_PREFIX:=/usr/local}"
: "${COPILOT_CLI_VERSION:=}"
: "${COPILOT_CLI_MCP_SEED:=false}"
: "${COPILOT_CLI_MCP_CONFIG_TEMPLATE:=/opt/copilot/mcp-config.json}"
: "${COPILOT_CLI_MCP_CONFIG_PATH:=/root/.copilot/mcp-config.json}"

Comment on lines +14 to +15
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COPILOT_GITHUB_TOKEN default value has trailing spaces and a } (your_github_personal_access_token_here }). This won’t match the placeholder check later and can cause an unintended auth attempt with an invalid token. Make the default empty (or make the placeholder string consistent with the later comparison).

Copilot uses AI. Check for mistakes.
if [[ "${COPILOT_CLI_ENABLED}" != "true" ]]; then
echo "COPILOT_CLI_ENABLED is not true; skipping Copilot CLI installation."
exit 0
fi

install_via_script() {
echo "Installing Copilot CLI via official install script..."
if [[ -n "${COPILOT_CLI_VERSION}" ]]; then
curl -fsSL "${COPILOT_CLI_INSTALL_URL}" | VERSION="${COPILOT_CLI_VERSION}" PREFIX="${COPILOT_CLI_PREFIX}" bash
else
curl -fsSL "${COPILOT_CLI_INSTALL_URL}" | PREFIX="${COPILOT_CLI_PREFIX}" bash
Comment on lines +24 to +26
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The install_via_script function downloads a remote shell script via curl from COPILOT_CLI_INSTALL_URL and pipes it directly into bash without any integrity or authenticity verification. If the URL, DNS, or network is compromised—or if COPILOT_CLI_INSTALL_URL is overridden to a malicious endpoint—an attacker-controlled script will execute with build-time privileges and can fully compromise the resulting image and any secrets available during the build. To mitigate this, fetch a specific, pinned installer artifact and verify it using a checksum or vendor signature before execution instead of executing the HTTP response body directly via a pipe.

Copilot uses AI. Check for mistakes.
fi
}

install_via_npm() {
echo "Installing Copilot CLI via npm..."
if ! command -v npm >/dev/null 2>&1; then
echo "npm not found; cannot install Copilot CLI via npm." >&2
return 1
fi
if [[ -n "${COPILOT_CLI_VERSION}" ]]; then
npm install -g "@github/copilot@${COPILOT_CLI_VERSION}"
else
npm install -g @github/copilot
fi
}

if [[ "${COPILOT_CLI_INSTALL_METHOD}" == "script" ]]; then
install_via_script
elif [[ "${COPILOT_CLI_INSTALL_METHOD}" == "npm" ]]; then
install_via_npm
else
install_via_script || install_via_npm
fi

if command -v copilot >/dev/null 2>&1; then
echo "Copilot CLI installed: $(copilot --version)"
else
echo "Copilot CLI installation finished, but 'copilot' is not on PATH." >&2
fi

if [[ "${COPILOT_CLI_MCP_SEED}" == "true" ]]; then
if [[ -f "${COPILOT_CLI_MCP_CONFIG_TEMPLATE}" ]]; then
echo "Seeding Copilot CLI MCP config..."
mkdir -p "$(dirname "${COPILOT_CLI_MCP_CONFIG_PATH}")"
cp "${COPILOT_CLI_MCP_CONFIG_TEMPLATE}" "${COPILOT_CLI_MCP_CONFIG_PATH}"
else
echo "MCP config template not found at ${COPILOT_CLI_MCP_CONFIG_TEMPLATE}; skipping seed." >&2
fi
else
echo "COPILOT_CLI_MCP_SEED is not true; skipping MCP config seed."
fi