diff --git a/src/ttyd/.devcontainer.json b/src/ttyd/.devcontainer.json new file mode 100644 index 00000000..af79527e --- /dev/null +++ b/src/ttyd/.devcontainer.json @@ -0,0 +1,27 @@ +{ + "name": "ttyd", + "dockerComposeFile": "docker-compose.yaml", + "service": "app", + "runServices": ["app"], + "shutdownAction": "none", + "workspaceFolder": "/workspace", + "postCreateCommand": + "./startupscript/post-startup.sh abc /config \"${templateOption:cloud}\" \"${templateOption:login}\"; ./sudo-passwordless.sh abc", + "postStartCommand": [ + "./startupscript/remount-on-restart.sh", + "abc", + "/config", + "${templateOption:cloud}", + "${templateOption:login}" + ], + "features": { + "ghcr.io/anthropics/devcontainer-features/claude-code@sha256:cfc2e7d3e9fd3b9b01f8d5cb158508a884c8c0ede2e23ed10f32dea5d4ffe69a": {}, + "ghcr.io/ar90n/devcontainer-features/ttyd:1": {}, + "./.devcontainer/features/workbench-tools": { + "cloud": "${templateOption:cloud}", + "username": "abc", + "userHomeDir": "/config" + } + }, + "remoteUser": "root" +} diff --git a/src/ttyd/README.md b/src/ttyd/README.md new file mode 100644 index 00000000..b26d785a --- /dev/null +++ b/src/ttyd/README.md @@ -0,0 +1,3 @@ +# ttyd + +Custom Workbench application based on ttyd diff --git a/src/ttyd/devcontainer-template.json b/src/ttyd/devcontainer-template.json new file mode 100644 index 00000000..dc527d9c --- /dev/null +++ b/src/ttyd/devcontainer-template.json @@ -0,0 +1,23 @@ +{ + "id": "ttyd", + "description": "ttyd is a simple command-line tool for sharing terminal over the web", + "version": "0.9.1", + "name": "Workbench minimal ttyd", + "documentationURL": "https://github.com/verily-src/workbench-app-devcontainers/tree/add-ttyd-devcontainer/src/ttyd", + "licenseURL": "https://github.com/verily-src/workbench-app-devcontainers/blob/master/LICENSE", + "options": { + "cloud": { + "type": "string", + "description": "VM cloud environment", + "proposals": ["gcp", "aws"], + "default": "gcp" + }, + "login": { + "type": "string", + "description": "Whether to log in to workbench CLI", + "proposals": ["true", "false"], + "default": "false" + } + }, + "platforms": ["Any"] +} diff --git a/src/ttyd/docker-compose.yaml b/src/ttyd/docker-compose.yaml new file mode 100644 index 00000000..4ae2da91 --- /dev/null +++ b/src/ttyd/docker-compose.yaml @@ -0,0 +1,32 @@ +services: + app: + # The container name must be "application-server" + container_name: "application-server" + # This can be either a pre-existing image or built from a Dockerfile + image: "ubuntu:24.04" + restart: always + volumes: + - .:/workspace:cached + command: ["ttyd", "-W", "-p", "8888", "bash"] + # The port specified here will be forwarded and accessible from the + # Workbench UI. + ports: + - 8888:8888 + environment: + USER: "abc" + DEFAULT_WORKSPACE: "/config" + SUDO_PASSWORD: "pwd" + # The service must be connected to the "app-network" Docker network + networks: + - app-network + security_opt: + - apparmor:unconfined + +volumes: + work: + +networks: + # The Docker network must be named "app-network". This is an external network + # that is created outside of this docker-compose file. + app-network: + external: true diff --git a/src/ttyd/sudo-passwordless.sh b/src/ttyd/sudo-passwordless.sh new file mode 100755 index 00000000..d14bd0a1 --- /dev/null +++ b/src/ttyd/sudo-passwordless.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# This script is used to set up passwordless sudo for the core user on the VM. +# It requires to be run with root priviledges and USER_NAME to be set in the environment. +# It is typically called from post-startup.sh. + +USER_NAME="${1}" + +if [[ -z "${USER_NAME}" ]]; then + echo "Usage: $0 " + exit 1 +fi + +sudoers_file="/etc/sudoers" +sudoers_d_file="/etc/sudoers.d/${USER_NAME}" + +# Make sure user exists +if ! id "${USER_NAME}" &>/dev/null; then + echo "User ${USER_NAME} does not exist." + exit 1 +fi + +# Check if there's an old rule in the main sudoers file that requires a password +if grep -q "^${USER_NAME} ALL=(ALL:ALL) ALL" "${sudoers_file}"; then + echo "Found password-requiring rule for ${USER_NAME} in /etc/sudoers. Commenting it out." + + # Comment out the old rule in /etc/sudoers + sed -i "s/^${USER_NAME} ALL=(ALL:ALL) ALL/# ${USER_NAME} ALL=(ALL:ALL) ALL/" "${sudoers_file}" +fi + +echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" > "${sudoers_d_file}" +chmod 440 "${sudoers_d_file}" + +echo "User ${USER_NAME} has been given passwordless sudo access."