-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.sh
More file actions
172 lines (151 loc) · 7.23 KB
/
Copy pathsetup.sh
File metadata and controls
172 lines (151 loc) · 7.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/usr/bin/env bash
# setup.sh - provision a fresh Debian OrbStack machine as a coding sandbox.
# Run as root inside the machine (the sandbox wrapper does this for you).
set -euo pipefail
GO_VERSION="${GO_VERSION:-1.26.0}"
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends \
git curl wget ca-certificates gnupg jq ripgrep less procps make unzip \
chromium fonts-liberation build-essential pkg-config
# --- Go toolchain ---
arch="$(dpkg --print-architecture)" # arm64 on Apple silicon
case "$arch" in arm64|amd64) ;; *) echo "error: unsupported arch: $arch" >&2; exit 1 ;; esac
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${arch}.tar.gz" \
| tar -C /usr/local -xz
ln -sf /usr/local/go/bin/go /usr/local/bin/go
ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
# Go dev tools, installed system-wide
export CGO_ENABLED=0
GOBIN=/usr/local/bin go install github.com/air-verse/air@latest
GOBIN=/usr/local/bin go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
GOBIN=/usr/local/bin go install github.com/pressly/goose/v3/cmd/goose@latest
GOBIN=/usr/local/bin go install github.com/go-jet/jet/v2/cmd/jet@latest
GOBIN=/usr/local/bin go install github.com/a-h/templ/cmd/templ@latest
GOBIN=/usr/local/bin go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@v2.4.1
rm -rf /root/go /root/.cache/go-build
# --- Tailwind standalone CLI (Linux build; Makefile's is darwin) ---
case "$arch" in
arm64) tw_asset=tailwindcss-linux-arm64; mp_asset=mailpit-linux-arm64.tar.gz ;;
amd64) tw_asset=tailwindcss-linux-x64; mp_asset=mailpit-linux-amd64.tar.gz ;;
esac
curl -fsSL -o /usr/local/bin/tailwindcss \
"https://github.com/tailwindlabs/tailwindcss/releases/latest/download/${tw_asset}"
chmod +x /usr/local/bin/tailwindcss
# --- Python toolchain ---
apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv python3-dev pipx
# --- Node 22 + package managers ---
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y nodejs
corepack enable
# --- Claude Code ---
runuser -u "$SETUP_USER" -- bash -lc 'curl -fsSL https://claude.ai/install.sh | bash'
# --- Claude Code: subscription token + bypass-permissions by default ---
# Token: run `claude setup-token`
if [ -n "${CLAUDE_TOKEN:-}" ]; then
cat > /etc/profile.d/claude-token.sh << EOF
export CLAUDE_CODE_OAUTH_TOKEN=${CLAUDE_TOKEN}
EOF
chmod 644 /etc/profile.d/claude-token.sh
fi
# Every sandbox is the containment, so bypass is the default posture here.
if [ -n "${SETUP_USER:-}" ]; then
userhome="/home/${SETUP_USER}"
mkdir -p "${userhome}/.claude"
cat > "${userhome}/.claude/settings.json" << 'EOF'
{
"permissions": { "defaultMode": "bypassPermissions" },
"skipDangerousModePermissionPrompt": true
}
EOF
echo '{"hasCompletedOnboarding": true}' > "${userhome}/.claude.json"
chown -R "${SETUP_USER}:${SETUP_USER}" "${userhome}/.claude"
chown "${SETUP_USER}:${SETUP_USER}" "${userhome}/.claude.json"
fi
# --- pi coding agent (used by Pi/Local sandboxes) ---
npm install -g @earendil-works/pi-coding-agent
# oMLX picker: per-user package, so install as the login user, not root.
# Default base URL http://127.0.0.1:8000/v1 matches the reverse tunnel.
if [ -n "${SETUP_USER:-}" ]; then
runuser -u "$SETUP_USER" -- bash -lc 'pi install npm:pi-omlx-picker' \
|| echo "warn: pi-omlx-picker install failed — inside a sandbox run: pi install npm:pi-omlx-picker" >&2
fi
# --- Default .pi agent config (auth.json + settings.json) ---
if [ -n "${SETUP_USER:-}" ]; then
mkdir -p "/home/${SETUP_USER}/.pi/agent"
printf '{}\n' > "/home/${SETUP_USER}/.pi/agent/auth.json"
jq '.omlx = { "access": "can-not-be-empty", "refresh": "", "expires": null, "baseUrl": "http://127.0.0.1:8000/v1", "type": "oauth" }' \
"/home/${SETUP_USER}/.pi/agent/auth.json" > /tmp/auth.json.tmp && mv /tmp/auth.json.tmp \
"/home/${SETUP_USER}/.pi/agent/auth.json"
touch "/home/${SETUP_USER}/.pi/agent/settings.json"
jq ' .defaultProvider = "omlx" | .defaultModel = "Qwen3.6-35B-A3B-4bit" | .defaultThinkingLevel = "medium" ' \
"/home/${SETUP_USER}/.pi/agent/settings.json" > /tmp/settings.json.tmp && mv /tmp/settings.json.tmp \
"/home/${SETUP_USER}/.pi/agent/settings.json"
chown -R "${SETUP_USER}:${SETUP_USER}" "/home/${SETUP_USER}/.pi"
fi
# --- Git defaults (system-wide, applies to the login user) ---
git config --system --add safe.directory /workspace
git config --system user.name "Phase Agent"
git config --system user.email "no-reply@phase.se"
# --- Browser env for Playwright/Puppeteer reuse ---
cat > /etc/profile.d/sandbox.sh << 'EOF'
export CHROME_BIN=/usr/bin/chromium
export PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
export PIP_BREAK_SYSTEM_PACKAGES=1
EOF
# --- PostgreSQL 17, pinned via the official PGDG repo ---
apt-get install -y postgresql-common
/usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y
apt-get install -y postgresql-17 postgresql-client-17
systemctl enable --now postgresql
# Superuser role + default db for the login user (peer auth on localhost socket)
if [ -n "${SETUP_USER:-}" ]; then
sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='${SETUP_USER}'" | grep -q 1 \
|| sudo -u postgres createuser --superuser "${SETUP_USER}"
sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='${SETUP_USER}'" | grep -q 1 \
|| sudo -u postgres createdb -O "${SETUP_USER}" "${SETUP_USER}"
fi
# --- Egress firewall: allow internet, block LAN (static nftables) ---
# Accepts OrbStack's internal ranges before the private-range reject:
# 192.168.138.0/23 = "IP range" in OrbStack Settings > Network (default),
# 198.18.0.0/15 = OrbStack machine network. If you change that setting,
# update the accept line to match. Traffic to other machines/host in these
# ranges is still blocked one layer down by --isolate-network.
apt-get install -y nftables
cat > /etc/nftables.conf << 'EOF'
#!/usr/sbin/nft -f
flush ruleset
table inet sandbox {
chain output {
type filter hook output priority 0; policy accept;
oifname "lo" accept
ct state established,related accept
meta l4proto ipv6-icmp accept
ip daddr { 192.168.138.0/23, 198.18.0.0/15 } accept comment "orbstack internal"
ip daddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16,
169.254.0.0/16, 100.64.0.0/10 } counter reject
ip6 daddr { fc00::/7, fe80::/10 } counter reject
}
}
EOF
systemctl enable --now nftables
# --- Project-specific extras (EDIT TO TASTE) ---
# apt-get install -y redis-server
apt-get install -y sqlite3 zip dnsutils
# fd
apt-get install -y fd-find
ln -sf "$(command -v fdfind)" /usr/local/bin/fd # debian names the binary fdfind
# --- sshd for host->guest tunnels: orb's multiplexed SSH server does not
# support -R (orbstack#31), so tunnels target this in-guest sshd via
# <name>.orb.local. Inbound-only; agent (no sudo) cannot reconfigure it.
apt-get install -y openssh-server
if [ -n "${PUBKEY:-}" ] && [ -n "${SETUP_USER:-}" ]; then
h="/home/$SETUP_USER"
install -d -m 700 -o "$SETUP_USER" -g "$SETUP_USER" "$h/.ssh"
printf '%s\n' "$PUBKEY" > "$h/.ssh/authorized_keys"
chown "$SETUP_USER:$SETUP_USER" "$h/.ssh/authorized_keys"
chmod 600 "$h/.ssh/authorized_keys"
fi
apt-get clean
echo "sandbox provisioned: go $(go version | cut -d' ' -f3), node $(node --version)"