ops-jrz1/scripts/dev-add.sh
Dan 74cf842afd Improve dev onboarding: devs group, npm setup, AGENTS.md
- Add users.groups.devs for shared resources
- dev-add: check devs group exists before creating user
- dev-add: use .profile for login shell PATH setup
- dev-add: configure npm prefix and .npm-global directory
- dev-add: create AGENTS.md with friendly capability guide
- Update onboarding message with npm install examples
- Add docs/server-AGENTS.md for reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 17:11:03 -08:00

224 lines
6.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# dev-add.sh - Add a new dev user account
# Usage: dev-add.sh <username> <ssh-pubkey>
#
# Creates:
# - Unix user account with SSH key
# - Adds to devs group (Slack token access)
# - Outputs onboarding instructions
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
usage() {
echo "Usage: $0 <username> <ssh-pubkey>"
echo ""
echo "Arguments:"
echo " username - Dev's username (alphanumeric, 3-16 chars)"
echo " ssh-pubkey - SSH public key (starts with ssh-ed25519, ssh-rsa, etc.)"
echo ""
echo "Example:"
echo " $0 alice 'ssh-ed25519 AAAA... alice@laptop'"
exit 1
}
validate_username() {
local username="$1"
if [[ ! "$username" =~ ^[a-z][a-z0-9_-]{2,15}$ ]]; then
log_error "Invalid username: must be 3-16 chars, start with letter, alphanumeric/underscore/dash only"
exit 1
fi
# Check if user already exists
if id "$username" &>/dev/null; then
log_error "User '$username' already exists"
exit 1
fi
}
validate_ssh_key() {
local key="$1"
if [[ ! "$key" =~ ^ssh-(ed25519|rsa|ecdsa) ]]; then
log_error "Invalid SSH key: must start with ssh-ed25519, ssh-rsa, or ssh-ecdsa"
exit 1
fi
}
create_user() {
local username="$1"
local ssh_key="$2"
log_info "Creating user '$username'..."
# Create user with home directory
# NixOS: don't specify shell (uses default), group is 'users'
useradd -m -g users "$username"
# Make home directory private (not world-readable)
chmod 700 "/home/$username"
# Add to devs group for Slack token access
usermod -aG devs "$username"
# Set up SSH key
local ssh_dir="/home/$username/.ssh"
mkdir -p "$ssh_dir"
echo "$ssh_key" > "$ssh_dir/authorized_keys"
chmod 700 "$ssh_dir"
chmod 600 "$ssh_dir/authorized_keys"
chown -R "$username:users" "$ssh_dir"
# Set up user's shell config (may not exist on NixOS)
# .profile = login shells (SSH), .bashrc = interactive non-login
local profile="/home/$username/.profile"
{
echo '# npm global packages (gemini-cli, etc.)'
echo "export PATH=\"\$HOME/.npm-global/bin:\$PATH\""
echo ''
echo '# Slack bot development tokens'
echo '[ -f /etc/slack-dev.env ] && source /etc/slack-dev.env'
} > "$profile"
chown "$username:users" "$profile"
# Pre-create npm global directory and configure npm prefix
local npm_global="/home/$username/.npm-global"
local npmrc="/home/$username/.npmrc"
mkdir -p "$npm_global"
echo "prefix=$npm_global" > "$npmrc"
chown "$username:users" "$npm_global" "$npmrc"
# Create AGENTS.md for AI coding assistants
cat > "/home/$username/AGENTS.md" << 'AGENTS_EOF'
# AGENTS.md - Dev Server Guide
Shared NixOS dev server. This guide helps AI coding agents work effectively here.
## Possible Right Now
**Install packages:**
```bash
npm install -g @google/gemini-cli # JS tools
nix profile install nixpkgs#go # System tools (go, rust, etc.)
uv venv && uv pip install <pkg> # Python packages
```
**Run services:**
```bash
python -m http.server 8080 # Dev servers on high ports
pm2 start app.js # Process manager (npm install -g pm2)
tmux / screen # Persistent sessions
```
**Available tools:** python3, uv, node, npm, git, vim, curl, tmux, opencode, bd
## Not Possible Right Now
| Want | Why | Workaround |
|------|-----|------------|
| sudo / root | Shared server security | Use nix profile or npm install -g |
| apt / yum | NixOS uses nix | `nix profile install nixpkgs#<pkg>` |
| Port 80/443 | Needs root | Use high port + SSH tunnel |
| Docker | Security isolation | Use nix for dependencies |
| systemd system services | Needs root | Use pm2, screen, or tmux |
## Resource Limits
Per-user limits to keep the server stable:
- **Memory**: ~1GB (50% of system)
- **Processes**: 200 max
- **Network**: 30 new connections/min
Heavy processes may be killed automatically.
## Environment
- **OS**: NixOS (not Debian/Ubuntu)
- **Shell**: bash
- **Home**: ~/ (private, 700)
- **Temp**: /tmp (fast, cleared on reboot)
AGENTS_EOF
chown "$username:users" "/home/$username/AGENTS.md"
log_info "User created with SSH access"
}
print_onboarding() {
local username="$1"
local server_ip
# NixOS: use ip command instead of hostname -I
server_ip=$(ip -4 addr show scope global | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -1)
echo ""
echo "=========================================="
echo " Dev Environment Ready: $username"
echo "=========================================="
echo ""
echo "## SSH Config (~/.ssh/config on your laptop)"
echo ""
echo " Host dev-server"
echo " HostName ${server_ip:-<server-ip>}"
echo " User $username"
echo " LocalForward 8080 127.0.0.1:8080"
echo ""
echo "## Quick Start"
echo ""
echo "1. SSH in:"
echo " ssh dev-server"
echo ""
echo "2. Install AI tools (pick one or more):"
echo " npm install -g @anthropic-ai/claude-cli # Claude"
echo " npm install -g @google/gemini-cli # Gemini"
echo ""
echo "3. Authenticate and start coding:"
echo " claude # or: gemini"
echo " # Follow prompts to authenticate"
echo ""
echo "## Tools Available"
echo " System: python3, uv, git, node, opencode, bd"
echo " Install more: npm install -g <package>"
echo " nix profile install nixpkgs#<package>"
echo ""
echo "=========================================="
}
main() {
if [[ $# -lt 2 ]]; then
usage
fi
local username="$1"
local ssh_key="$2"
# Must run as root
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root"
exit 1
fi
validate_username "$username"
validate_ssh_key "$ssh_key"
# Check devs group exists (created by NixOS config)
if ! getent group devs >/dev/null; then
log_error "Required group 'devs' does not exist"
log_error "Ensure users.groups.devs = {} is in NixOS config and deployed"
exit 1
fi
create_user "$username" "$ssh_key"
print_onboarding "$username"
log_info "Dev user '$username' setup complete!"
}
main "$@"