-
Notifications
You must be signed in to change notification settings - Fork 89
refactor(vscode-web): migrate to VS Code CLI with code serve-web #627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
matifali
commented
Dec 31, 2025
- Replace code-server with official VS Code CLI
- Download CLI from code.visualstudio.com using cli-alpine-* URLs
- Add release_channel variable (stable/insiders)
- Add commit_id variable to pin specific VS Code versions
- Support offline mode with fallback to code-server or cached vscode-server
- Add comprehensive bun tests for settings, extensions, and CLI arguments
- Add Terraform tests for variable validation
- Replace code-server with official VS Code CLI - Download CLI from code.visualstudio.com using cli-alpine-* URLs - Add release_channel variable (stable/insiders) - Add commit_id variable to pin specific VS Code versions - Support offline mode with fallback to code-server or cached vscode-server - Add comprehensive bun tests for settings, extensions, and CLI arguments - Add Terraform tests for variable validation
|
@codex review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| PLATFORM=$(uname -s) | ||
| case "$PLATFORM" in | ||
| Linux) | ||
| PLATFORM="alpine" | ||
| ;; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linux CLI download uses alpine build and fails on glibc hosts
The platform detection forces PLATFORM="alpine" for any Linux host, so the download URL later resolves to cli-alpine-* instead of the normal cli-linux-*. On standard Debian/Ubuntu (glibc) images the alpine binary requires the musl loader (/lib/ld-musl-*.so.1) and will not execute, so the script exits before VS Code starts. This makes the module unusable on the default glibc-based images; the detection should only pick the alpine build on Alpine and use the linux build elsewhere.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refactors the vscode-web module to use the official VS Code CLI instead of code-server, enabling better version control and alignment with official VS Code tooling.
- Migrates from code-server to official VS Code CLI with
code serve-webcommand - Adds
release_channelvariable to support stable/insiders releases - Implements comprehensive offline mode with fallback to code-server or cached vscode-server
- Adds extensive test coverage with 21 new integration tests
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| main.tf | Removes platform variable, adds release_channel and repositions commit_id variable with updated description |
| run.sh | Complete rewrite to download and use VS Code CLI instead of code-server, with offline fallback mechanisms |
| main.test.ts | Adds comprehensive test suite with 21 tests covering script generation, settings management, extension installation, and container integration |
| vscode-web.tftest.hcl | New Terraform validation tests for variable constraints and URL generation |
| README.md | Updates documentation to reflect VS Code CLI usage and new configuration options |
| if command -v curl > /dev/null 2>&1; then | ||
| curl -fsSL "$CLI_URL" -o "/tmp/vscode-cli.tar.gz" | ||
| elif command -v wget > /dev/null 2>&1; then | ||
| wget -q "$CLI_URL" -O "/tmp/vscode-cli.tar.gz" | ||
| else | ||
| echo "Neither curl nor wget is available. Please install one of them." | ||
| exit 1 | ||
| ;; | ||
| esac | ||
|
|
||
| # Detect the platform | ||
| if [ -n "${PLATFORM}" ]; then | ||
| DETECTED_PLATFORM="${PLATFORM}" | ||
| elif [ -f /etc/alpine-release ] || grep -qi 'ID=alpine' /etc/os-release 2> /dev/null || command -v apk > /dev/null 2>&1; then | ||
| DETECTED_PLATFORM="alpine" | ||
| elif [ "$(uname -s)" = "Darwin" ]; then | ||
| DETECTED_PLATFORM="darwin" | ||
| else | ||
| DETECTED_PLATFORM="linux" | ||
| fi | ||
| fi |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The curl and wget commands don't check for download failures. If the download fails (e.g., network issue, 404 error), the script continues to the tar extraction which will fail with a confusing error message. Add error checking after the download commands to provide a clear error message.
| fi | ||
| printf "$${BOLD}VS Code Web commit id version $HASH.\n" | ||
| # Extract CLI | ||
| tar -xzf /tmp/vscode-cli.tar.gz -C "${INSTALL_PREFIX}/bin" |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tar extraction command doesn't check for errors. If the extraction fails (e.g., corrupted archive, insufficient disk space), the script will proceed to check for the binary and provide a generic "Failed to install VS Code CLI" error. Consider checking the exit status of tar and providing a more specific error message for extraction failures.
| tar -xzf /tmp/vscode-cli.tar.gz -C "${INSTALL_PREFIX}/bin" | |
| if ! tar -xzf /tmp/vscode-cli.tar.gz -C "${INSTALL_PREFIX}/bin"; then | |
| echo "Error extracting VS Code CLI archive. The download may be corrupted or there may be insufficient disk space." | |
| rm -f /tmp/vscode-cli.tar.gz | |
| exit 1 | |
| fi |
| esac | ||
|
|
||
| # Detect platform | ||
| # Note: VS Code CLI uses 'alpine' for all Linux distributions |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment states "VS Code CLI uses 'alpine' for all Linux distributions," but this is misleading. The URL format "cli-alpine-*" is used for the musl-based CLI download, which works across all Linux distributions (not just Alpine). Consider clarifying the comment to explain that this refers to the download URL format rather than suggesting Alpine-specific functionality.
| # Note: VS Code CLI uses 'alpine' for all Linux distributions | |
| # Note: For Linux, the VS Code CLI download URL uses the 'cli-alpine-*' (musl) build, | |
| # which is intended to work across common Linux distributions (not just Alpine). |
| ARGS="serve-web --port ${PORT} --host 127.0.0.1 --accept-server-license-terms --without-connection-token --telemetry-level ${TELEMETRY_LEVEL}" | ||
|
|
||
| if [ -n "$EXTENSION_ARG" ]; then | ||
| ARGS="$ARGS $EXTENSION_ARG" | ||
| fi | ||
|
|
||
| # Install each extension... | ||
| IFS=',' read -r -a EXTENSIONLIST <<< "$${EXTENSIONS}" | ||
| # shellcheck disable=SC2066 | ||
| for extension in "$${EXTENSIONLIST[@]}"; do | ||
| if [ -z "$extension" ]; then | ||
| continue | ||
| if [ -n "$SERVER_BASE_PATH_ARG" ]; then | ||
| ARGS="$ARGS $SERVER_BASE_PATH_ARG" | ||
| fi | ||
| printf "🧩 Installing extension $${CODE}$extension$${RESET}...\n" | ||
| output=$($VSCODE_WEB "$EXTENSION_ARG" --install-extension "$extension" --force) | ||
| if [ $? -ne 0 ]; then | ||
| echo "Failed to install extension: $extension: $output" | ||
|
|
||
| if [ -n "$DISABLE_TRUST_ARG" ]; then | ||
| ARGS="$ARGS $DISABLE_TRUST_ARG" | ||
| fi | ||
| done | ||
|
|
||
| if [ "${AUTO_INSTALL_EXTENSIONS}" = true ]; then | ||
| if ! command -v jq > /dev/null; then | ||
| echo "jq is required to install extensions from a workspace file." | ||
| else | ||
| # Prefer WORKSPACE if set and points to a file | ||
| if [ -n "${WORKSPACE}" ] && [ -f "${WORKSPACE}" ]; then | ||
| printf "🧩 Installing extensions from %s...\n" "${WORKSPACE}" | ||
| # Strip single-line comments then parse .extensions.recommendations[] | ||
| extensions=$(sed 's|//.*||g' "${WORKSPACE}" | jq -r '(.extensions.recommendations // [])[]') | ||
| for extension in $extensions; do | ||
| $VSCODE_WEB "$EXTENSION_ARG" --install-extension "$extension" --force | ||
| done | ||
| if [ -n "${COMMIT_ID}" ]; then | ||
| ARGS="$ARGS --commit-id ${COMMIT_ID}" | ||
| fi | ||
|
|
||
| printf "Starting VS Code Web on port ${PORT}...\n" | ||
| printf "Check logs at ${LOG_PATH}\n" | ||
|
|
||
| # shellcheck disable=SC2086 | ||
| "$CODE_CMD" $ARGS > "${LOG_PATH}" 2>&1 & |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The run_vscode_web_cli function builds a single ARGS string with values like EXTENSION_ARG, SERVER_BASE_PATH_ARG, and COMMIT_ID and then invokes "$CODE_CMD" $ARGS, which expands ARGS unquoted. If any of these inputs contain shell metacharacters (such as ;, &, backticks, or $()), the shell will interpret them, allowing command injection and arbitrary command execution in the workspace process. To mitigate this, construct the CLI invocation using a properly quoted argument list (arrays) or ensure that all interpolated variables are safely quoted/escaped so that user-controlled data cannot break out of its argument context.
| # Build arguments for code-server | ||
| ARGS="--port ${PORT} --host 127.0.0.1 --auth none" | ||
|
|
||
| if [ -n "$EXTENSION_ARG" ]; then | ||
| ARGS="$ARGS $EXTENSION_ARG" | ||
| fi | ||
|
|
||
| # shellcheck disable=SC2086 | ||
| "$SERVER_CMD" $ARGS > "${LOG_PATH}" 2>&1 & |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The run_code_server function constructs an ARGS string incorporating EXTENSION_ARG and then calls "$SERVER_CMD" $ARGS, expanding ARGS without quotes. An attacker who can influence EXTENSIONS_DIR (and therefore EXTENSION_ARG) can inject shell metacharacters to execute additional commands alongside code-server, leading to arbitrary command execution. Use a safely quoted argument list or pass EXTENSION_ARG as a separate, quoted argument so that its contents cannot be parsed as shell syntax.
| # Build arguments for code-server | |
| ARGS="--port ${PORT} --host 127.0.0.1 --auth none" | |
| if [ -n "$EXTENSION_ARG" ]; then | |
| ARGS="$ARGS $EXTENSION_ARG" | |
| fi | |
| # shellcheck disable=SC2086 | |
| "$SERVER_CMD" $ARGS > "${LOG_PATH}" 2>&1 & | |
| # Build arguments for code-server using an array to avoid word splitting | |
| local args=(--port "${PORT}" --host 127.0.0.1 --auth none) | |
| if [ -n "$EXTENSION_ARG" ]; then | |
| args+=("$EXTENSION_ARG") | |
| fi | |
| "$SERVER_CMD" "${args[@]}" > "${LOG_PATH}" 2>&1 & |
| ARGS="--port ${PORT} --host 127.0.0.1 --without-connection-token --accept-server-license-terms --telemetry-level ${TELEMETRY_LEVEL}" | ||
|
|
||
| if [ -n "$EXTENSION_ARG" ]; then | ||
| ARGS="$ARGS $EXTENSION_ARG" | ||
| fi | ||
|
|
||
| if [ -n "$SERVER_BASE_PATH_ARG" ]; then | ||
| ARGS="$ARGS $SERVER_BASE_PATH_ARG" | ||
| fi | ||
|
|
||
| # shellcheck disable=SC2086 | ||
| "$SERVER_CMD" serve-local $ARGS > "${LOG_PATH}" 2>&1 & |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The run_vscode_server function similarly builds an ARGS string with EXTENSION_ARG, SERVER_BASE_PATH_ARG, and telemetry/port values and then invokes "$SERVER_CMD" serve-local $ARGS with ARGS unquoted. If any of these components contain shell metacharacters (for example via a malicious SERVER_BASE_PATH or EXTENSIONS_DIR), the shell will interpret them as control characters, enabling command injection before vscode-server starts. This should be refactored to pass arguments in a quoted list (e.g., using arrays) or otherwise ensure that user-controlled values cannot alter the shell command structure.
| output=$("$CODE_CMD" $EXTENSION_ARG --install-extension "$extension" --force 2>&1) | ||
| if [ $? -ne 0 ]; then |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In install_extensions, the call "$CODE_CMD" $EXTENSION_ARG --install-extension "$extension" --force expands EXTENSION_ARG without quotes. A crafted EXTENSIONS_DIR value (propagating into EXTENSION_ARG) containing shell metacharacters could break out of the intended argument and cause arbitrary shell commands to run when installing extensions. Quote EXTENSION_ARG (or build a positional argument list/array) so that its contents are always treated as a single argument to the CLI rather than executable shell syntax.