microsoft/TypeAgent

Public

mirrored from https://github.com/microsoft/TypeAgentAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
973b32f09e62b03379ec82dc7b9665c84dd6d53b

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

.devcontainer/scripts/post-create.sh

259lines · modecode

1#!/bin/bash
2# Copyright (c) Microsoft Corporation.
3# Licensed under the MIT License.
4
5#
6# TypeAgent DevContainer Post-Create Script
7# Runs once when the container is first created
8#
9
10set -euo pipefail
11
12echo "╔══════════════════════════════════════════════════════════════╗"
13echo "║ TypeAgent DevContainer Setup ║"
14echo "╚══════════════════════════════════════════════════════════════╝"
15echo ""
16
17# Detect environment
18detect_env() {
19 if [[ "${CODESPACES:-}" == "true" ]]; then
20 echo "codespaces"
21 elif [[ -n "${WSL_DISTRO_NAME:-}" ]] || grep -qi "wsl" /proc/version 2>/dev/null; then
22 if [[ -n "${WAYLAND_DISPLAY:-}" ]] || [[ -n "${DISPLAY:-}" ]]; then
23 echo "wsl2-gui"
24 else
25 echo "wsl2"
26 fi
27 else
28 echo "standard"
29 fi
30}
31
32ENV=$(detect_env)
33echo "Environment: $ENV"
34echo ""
35
36# Fix ownership of Docker named-volume mount points.
37# Named volumes mounted into the container are owned by root:root by default,
38# which prevents the non-root `codespace` user from writing into them
39# (e.g. `pnpm install` -> EACCES on ts/node_modules).
40echo "Fixing ownership of mounted volume directories..."
41VOLUME_PATHS=(
42 "/home/codespace/.local/share/pnpm"
43 "/home/codespace/.local/share/pnpm/store"
44 "/home/codespace/.claude"
45 "/home/codespace/.copilot"
46)
47# Discover the workspace ts/node_modules path dynamically (works for worktrees
48# and for variants that mount the workspace outside /workspaces, e.g. the
49# `agent` devcontainer that bind-mounts the host path verbatim).
50WS_TS_DIR=""
51_REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
52if [[ -n "$_REPO_ROOT" ]] && [[ -d "$_REPO_ROOT/ts" ]]; then
53 WS_TS_DIR="$_REPO_ROOT/ts"
54elif [[ -d "$(pwd)/ts" ]]; then
55 WS_TS_DIR="$(pwd)/ts"
56elif [[ -d "/workspaces/TypeAgent/ts" ]]; then
57 WS_TS_DIR="/workspaces/TypeAgent/ts"
58else
59 WS_TS_DIR=$(find /workspaces -maxdepth 2 -type d -name "ts" 2>/dev/null | head -1)
60fi
61if [[ -n "$WS_TS_DIR" ]]; then
62 VOLUME_PATHS+=("$WS_TS_DIR/node_modules")
63fi
64
65for p in "${VOLUME_PATHS[@]}"; do
66 if [[ -e "$p" ]]; then
67 if sudo chown -R codespace:codespace "$p"; then
68 echo " chowned $p"
69 else
70 if [[ "$p" == *"/pnpm/store" ]] || [[ "$p" == *"/node_modules" ]]; then
71 echo "Error: failed to chown critical path $p" >&2
72 exit 1
73 fi
74 echo " warn: could not chown $p"
75 fi
76 fi
77done
78echo ""
79
80# Navigate to TypeScript workspace
81echo "Looking for TypeScript workspace..."
82REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
83if [[ -n "$REPO_ROOT" ]] && [[ -d "$REPO_ROOT/ts" ]]; then
84 cd "$REPO_ROOT/ts"
85 echo "Found: $REPO_ROOT/ts"
86else
87 # Try glob pattern
88 TS_DIR=$(find /workspaces -maxdepth 2 -type d -name "ts" 2>/dev/null | head -1)
89 if [[ -n "$TS_DIR" ]]; then
90 cd "$TS_DIR"
91 echo "Found: $TS_DIR"
92 else
93 echo "Warning: Could not find ts directory in /workspaces"
94 echo "Listing /workspaces contents:"
95 ls -la /workspaces/ 2>/dev/null || echo " /workspaces not accessible"
96 echo ""
97 echo "Skipping dependency installation. Run manually after container starts:"
98 echo " cd ts && pnpm install"
99 exit 0
100 fi
101fi
102
103# Enable pnpm
104echo ""
105echo "Enabling corepack and pnpm..."
106if command -v corepack &> /dev/null; then
107 corepack enable || echo "Warning: corepack enable failed"
108 # Use the pnpm version pinned in package.json (packageManager field)
109 corepack install || echo "Warning: corepack install failed"
110else
111 echo "Warning: corepack not found, checking for pnpm..."
112 if ! command -v pnpm &> /dev/null; then
113 echo "Installing pnpm via npm..."
114 npm install -g pnpm || { echo "Failed to install pnpm"; exit 1; }
115 fi
116fi
117
118# Verify pnpm is available
119if ! command -v pnpm &> /dev/null; then
120 echo "Error: pnpm is not available after setup"
121 exit 1
122fi
123
124echo "pnpm version: $(pnpm --version)"
125
126# Point pnpm store at the Docker named volume so it persists across rebuilds
127pnpm config set store-dir /home/codespace/.local/share/pnpm/store --global
128echo "pnpm store-dir: $(pnpm store path)"
129
130echo ""
131echo "Installing system libraries required by TypeAgent..."
132# libsecret is required by keytar / native credential storage used by some
133# TypeAgent packages (libsecret-1.so.0 at runtime, libsecret-1-dev for builds).
134APT_PACKAGES=(
135 libsecret-1-0
136 libsecret-1-dev
137)
138# Skip if already baked into the image (via .devcontainer/Dockerfile)
139MISSING_PKGS=()
140for pkg in "${APT_PACKAGES[@]}"; do
141 if ! dpkg -s "$pkg" &>/dev/null; then
142 MISSING_PKGS+=("$pkg")
143 fi
144done
145if [[ ${#MISSING_PKGS[@]} -gt 0 ]]; then
146 if command -v apt-get &> /dev/null; then
147 if ! sudo DEBIAN_FRONTEND=noninteractive apt-get update -y; then
148 echo " warn: apt-get update failed"
149 fi
150 if ! sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${MISSING_PKGS[@]}"; then
151 echo " warn: failed to install: ${MISSING_PKGS[*]}"
152 fi
153 else
154 echo " warn: apt-get not available, skipping system library install"
155 fi
156else
157 echo " all packages already installed"
158fi
159
160echo ""
161echo "Configuring Git identity..."
162CURRENT_GIT_NAME=$(git config --global --get user.name 2>/dev/null || true)
163CURRENT_GIT_EMAIL=$(git config --global --get user.email 2>/dev/null || true)
164DESIRED_GIT_NAME="${LOCAL_GIT_USER_NAME:-}"
165DESIRED_GIT_EMAIL="${LOCAL_GIT_USER_EMAIL:-}"
166
167if [[ -n "$CURRENT_GIT_NAME" ]]; then
168 echo " git user.name already set"
169elif [[ -n "$DESIRED_GIT_NAME" ]]; then
170 git config --global user.name "$DESIRED_GIT_NAME"
171 echo " git user.name set"
172fi
173
174if [[ -n "$CURRENT_GIT_EMAIL" ]]; then
175 echo " git user.email already set"
176elif [[ -n "$DESIRED_GIT_EMAIL" ]]; then
177 git config --global user.email "$DESIRED_GIT_EMAIL"
178 echo " git user.email set"
179fi
180
181if [[ -z "$CURRENT_GIT_NAME" && -z "$DESIRED_GIT_NAME" ]] || \
182 [[ -z "$CURRENT_GIT_EMAIL" && -z "$DESIRED_GIT_EMAIL" ]]; then
183 echo ""
184 echo " Warning: no host git identity provided."
185 echo " Start the container via .devcontainer/scripts/start-devcontainer.sh"
186 echo " to inherit host ~/.gitconfig, or set it manually inside the container:"
187 echo " git config --global user.name \"Your Name\""
188 echo " git config --global user.email \"you@example.com\""
189fi
190
191# Install dependencies
192echo ""
193echo "Installing pnpm dependencies..."
194echo "This may take a few minutes on first run..."
195if ! pnpm install; then
196 echo ""
197 echo "Error: pnpm install failed." >&2
198 echo "This is often due to network issues or missing system dependencies." >&2
199 exit 1
200fi
201
202# - Security hardening: restrict sudo to a minimal allowlist
203# During post-create we needed unrestricted root access to install
204# packages and fix volume ownership. Now that setup is done, replace
205# the blanket NOPASSWD:ALL rule with only the ssh service commands.
206# apt-get, dpkg, chown, and mkdir are intentionally excluded — all
207# package installation and ownership fixes happen above during setup,
208# and allowing them at runtime exposes privilege-escalation vectors
209# (e.g. apt-get -o hook injection, chown on /etc/shadow).
210echo ""
211echo "Hardening sudo access..."
212SUDOERS_FILE="/etc/sudoers.d/codespace-restricted"
213sudo tee "$SUDOERS_FILE" > /dev/null << 'SUDOERS'
214# Restricted sudo for the codespace user (post-setup hardening).
215# Only allow managing the SSH service — nothing else.
216codespace ALL=(root) NOPASSWD: /usr/sbin/service ssh start, \
217 /usr/sbin/service ssh stop, \
218 /usr/sbin/service ssh restart, \
219 /usr/sbin/service ssh status, \
220 /usr/sbin/service sshd start, \
221 /usr/sbin/service sshd stop, \
222 /usr/sbin/service sshd restart, \
223 /usr/sbin/service sshd status
224SUDOERS
225sudo chmod 0440 "$SUDOERS_FILE"
226# Remove the blanket rule that grants unrestricted root. The common-utils
227# devcontainer feature writes it to /etc/sudoers.d/codespace (filename
228# matches the username).
229if [[ -f /etc/sudoers.d/codespace ]]; then
230 sudo rm /etc/sudoers.d/codespace
231 echo " Removed blanket NOPASSWD:ALL rule"
232fi
233echo " Sudo restricted to: service ssh/sshd only"
234
235echo ""
236echo "╔══════════════════════════════════════════════════════════════╗"
237echo "║ Setup Complete! ║"
238echo "╚══════════════════════════════════════════════════════════════╝"
239echo ""
240echo "Next steps:"
241echo " cd ts"
242echo " pnpm run build"
243echo ""
244
245case $ENV in
246 wsl2-gui)
247 echo "GUI Support: WSLg detected - 'pnpm run shell' will work!"
248 ;;
249 codespaces)
250 echo "GUI Support: Use VNC at http://localhost:6080"
251 ;;
252 *)
253 echo "GUI Support: For Electron, use hybrid approach:"
254 echo " Container: pnpm run server"
255 echo " Host: pnpm run shell"
256 ;;
257esac
258
259echo ""
260