Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds a new community Zellij module (registry/jang2162/modules/zellij) that installs and configures Zellij, a terminal multiplexer, in Coder workspaces. It supports two modes: terminal (Coder built-in terminal via zellij attach) and web (browser-based access via subdomain proxy using Zellij's built-in web server). A new author profile (registry/jang2162/) and the Zellij SVG icon (.icons/zellij.svg) are also added.
Changes:
- New Zellij module with
main.tf, installation/config shell script, tftest assertions, and TypeScript tests - New author profile (
registry/jang2162/README.md+ avatar) - New Zellij icon added to the shared
.icons/directory
Reviewed changes
Copilot reviewed 6 out of 8 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
registry/jang2162/modules/zellij/main.tf |
Defines Terraform variables, the install script resource, and two conditional coder_app resources (terminal/web modes) |
registry/jang2162/modules/zellij/scripts/run.sh |
Shell script that installs Zellij, writes config, optionally starts web server with token |
registry/jang2162/modules/zellij/zellij.tftest.hcl |
Terraform plan-level tests verifying app resource attributes |
registry/jang2162/modules/zellij/main.test.ts |
TypeScript tests via runTerraformApply checking mode-specific resource creation |
registry/jang2162/modules/zellij/README.md |
Module documentation with examples and configuration reference |
registry/jang2162/README.md |
New author profile for the jang2162 namespace |
registry/jang2162/.images/avatar.png |
Author avatar image |
.icons/zellij.svg |
Zellij SVG icon for use by the module |
| mkdir -p "$config_dir" | ||
|
|
||
| if [ -n "$ZELLIJ_CONFIG" ]; then | ||
| printf "$ZELLIJ_CONFIG" > "$config_file" |
There was a problem hiding this comment.
Using printf "$ZELLIJ_CONFIG" is unsafe: if the custom config string contains % characters (which are common in KDL config files as format specifiers), printf will misinterpret them as format directives, leading to unexpected output or errors. Use printf '%s' "$ZELLIJ_CONFIG" (or printf '%s\n') to treat the value literally.
| printf "$ZELLIJ_CONFIG" > "$config_file" | |
| printf '%s' "$ZELLIJ_CONFIG" > "$config_file" |
| # Function to get installed version | ||
| get_installed_version() { | ||
| if is_installed; then | ||
| zellij --version | grep -oP 'zellij \K[0-9]+\.[0-9]+\.[0-9]+' |
There was a problem hiding this comment.
The grep -oP flag (Perl-compatible regex) is used here to extract the version string. The -P option is not available on all Unix-like systems (e.g., it is not available in Alpine Linux's BusyBox grep, and not supported by BSD grep on macOS). This could cause the version check to silently fail. Use a POSIX-compatible alternative such as grep -oE (extended regex, widely available), e.g.: zellij --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+'
| zellij --version | grep -oP 'zellij \K[0-9]+\.[0-9]+\.[0-9]+' | |
| zellij --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' |
| elif ! grep -qP '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' "$token_file"; then | ||
| printf "Invalid token file detected, regenerating...\n" | ||
| rm -f "$token_file" | ||
| need_token=true | ||
| fi | ||
|
|
||
| if [ "$need_token" = true ]; then | ||
| printf "Creating authentication token...\n" | ||
| # Extract UUID token from output (format: "token_N: <uuid>") | ||
| TOKEN=$(zellij web --create-token 2>&1 | grep -oP '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') |
There was a problem hiding this comment.
Same as above: grep -qP and grep -oP use Perl-compatible regex, which is not available on Alpine Linux or macOS. Use POSIX grep -qE / grep -oE with standard extended regex instead of -P.
| TOKEN=$(zellij web --create-token 2>&1 | grep -oP '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') | ||
| echo "$TOKEN" > "$token_file" | ||
| printf "$${BOLD}===========================================\n" | ||
| printf "$${BOLD} Zellij Web Token: $TOKEN\n" | ||
| printf "$${BOLD} Saved to: ~/.zellij-web-token\n" | ||
| printf "$${BOLD} Enter this token on first browser visit.\n" | ||
| printf "$${BOLD}===========================================\n\n" |
There was a problem hiding this comment.
If zellij web --create-token fails or the output doesn't match the expected UUID pattern, TOKEN will be an empty string. The script then writes an empty string to $token_file and prints a "Zellij Web Token:" line with no token, leaving the user unable to authenticate. There should be a check such as if [ -z "$TOKEN" ]; then printf "ERROR: Failed to create authentication token\n"; exit 1; fi before writing the token file.
| # Main execution | ||
| main() { | ||
| printf "$${BOLD}🛠️ Setting up zellij! \n\n" | ||
| printf "" 8000 |
There was a problem hiding this comment.
This printf "" call on line 220 is a no-op (it outputs nothing) and should be removed to keep the code clean.
| printf "" |
| # Wait for web server to be ready | ||
| sleep 2 |
There was a problem hiding this comment.
The hardcoded sleep 2 to wait for the web server to start is fragile. On slow systems the web server may not be ready within 2 seconds, causing the subsequent zellij web --create-token call to fail (silently producing an empty token). A retry/poll loop checking that the server port is listening (e.g., with nc or by retrying with until curl -sf http://localhost:$WEB_PORT ...) would be more reliable.
| # Wait for web server to be ready | |
| sleep 2 | |
| # Wait for web server to be ready (poll the HTTP endpoint with a timeout) | |
| if command -v curl >/dev/null 2>&1; then | |
| # Try for up to ~10 seconds | |
| for _ in $(seq 1 20); do | |
| if curl -sf "http://localhost:${WEB_PORT}" >/dev/null 2>&1; then | |
| break | |
| fi | |
| sleep 0.5 | |
| done | |
| else | |
| # Fallback to a fixed delay if curl is unavailable | |
| sleep 2 | |
| fi |
| fi | ||
|
|
||
| printf "Extracting zellij...\n" | ||
| tar -xzf "$TEMP_DIR/zellij.tar.gz" -C "$TEMP_DIR" |
There was a problem hiding this comment.
The tar -xzf command at line 71 has no error handling. If extraction fails (e.g., the downloaded archive is corrupt or truncated), the subsequent sudo mv "$TEMP_DIR/zellij" command will fail with a confusing "file not found" error instead of a clear message. The extraction should be wrapped in an error check (e.g., if ! tar -xzf ...; then printf "ERROR: Failed to extract zellij\n"; rm -rf "$TEMP_DIR"; exit 1; fi) to match the consistent error handling used for the download step.
| tar -xzf "$TEMP_DIR/zellij.tar.gz" -C "$TEMP_DIR" | |
| if ! tar -xzf "$TEMP_DIR/zellij.tar.gz" -C "$TEMP_DIR"; then | |
| printf "ERROR: Failed to extract zellij archive\n" | |
| rm -rf "$TEMP_DIR" | |
| exit 1 | |
| fi |
|
|
||
| > [!IMPORTANT] | ||
| > | ||
| > - Custom `zellij_config` replaces the default configuration entirely |
There was a problem hiding this comment.
The IMPORTANT note says "Custom zellij_config replaces the default configuration entirely" but does not warn that in web mode, the user must also include web_server_ip and web_server_port in their custom config, since those are only appended to the default config. Without these settings, the zellij web server won't listen on the configured port when using a custom config. This is a significant omission that should be documented here.
| > - Custom `zellij_config` replaces the default configuration entirely | |
| > - Custom `zellij_config` replaces the default configuration entirely | |
| > - When using `mode = "web"`, your custom configuration **must** also define `web_server_ip` and `web_server_port`, since these are only appended to the default config. Omitting them will prevent the zellij web server from listening on the expected port. |
| order = var.order | ||
| group = var.group | ||
| url = "http://localhost:${var.web_port}" | ||
| subdomain = true |
There was a problem hiding this comment.
The coder_app.zellij_web resource does not include a healthcheck block. Other web-mode modules in this registry (e.g., filebrowser, jupyterlab, code-server) include a healthcheck so Coder can display the correct app status. If the Zellij web server exposes any health or status endpoint, consider adding a healthcheck block to give users visibility into whether the web server is running.
| subdomain = true | |
| healthcheck { | |
| url = "/" | |
| interval = "10s" | |
| timeout = "5s" | |
| } | |
| subdomain = true |
| DOWNLOAD_URL="https://github.com/zellij-org/zellij/releases/download/v$${ZELLIJ_VERSION}/zellij-$${ARCH}-unknown-linux-musl.tar.gz" | ||
| TEMP_DIR=$(mktemp -d) | ||
|
|
||
| printf "Downloading zellij version $ZELLIJ_VERSION for $ARCH...\n" | ||
| printf "URL: $DOWNLOAD_URL\n" | ||
|
|
||
| if ! curl -fsSL "$DOWNLOAD_URL" -o "$TEMP_DIR/zellij.tar.gz"; then | ||
| printf "ERROR: Failed to download zellij\n" | ||
| rm -rf "$TEMP_DIR" | ||
| exit 1 | ||
| fi | ||
|
|
||
| printf "Extracting zellij...\n" | ||
| tar -xzf "$TEMP_DIR/zellij.tar.gz" -C "$TEMP_DIR" | ||
|
|
||
| printf "Installing zellij to /usr/local/bin...\n" | ||
| sudo mv "$TEMP_DIR/zellij" /usr/local/bin/zellij | ||
| sudo chmod +x /usr/local/bin/zellij | ||
|
|
There was a problem hiding this comment.
This script downloads and installs a third‑party binary (zellij) directly from GitHub using curl and tar without any integrity verification before moving it into /usr/local/bin with sudo. If the GitHub release or the network path is compromised, an attacker could serve a malicious tarball that would be executed with elevated privileges on every workspace start. To mitigate this, add a strong integrity check (e.g., verified checksum or signature tied to the expected version) before extracting and installing the downloaded binary, and fail the script if verification does not pass.
|
@jang2162 I just wanted to see if there was any update on this? |
Description
Add Zellij terminal multiplexer module that automatically installs and configures zellij in Coder workspaces. Supports two modes:
terminal(Coder built-in terminal) andweb(browser-based via subdomain proxy).Type of Change
Module Information
Path:
registry/jang2162/modules/zellijNew version:
v1.0.0Breaking change: [ ] Yes [x] No
Testing & Validation
bun test)terraform test)bun fmt)Related Issues
None