ops-jrz1/scripts/dev-add.sh
Dan bc81b4ec15 Rename learner to dev across codebase
- scripts/learner-*.sh → scripts/dev-*.sh
- docs/learner-*.md → docs/dev-*.md
- tests/test-learner-env.sh → tests/test-dev-env.sh
- Update all internal references

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

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

153 lines
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"
# Add Slack env vars to bashrc
{
echo ''
echo '# Slack bot development tokens'
echo 'source /etc/slack-dev.env'
} >> "/home/$username/.bashrc"
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. Authenticate Claude (first time only):"
echo " claude"
echo " # Opens localhost URL - paste in your local browser"
echo " # Complete OAuth, token flows back automatically"
echo ""
echo "3. Start coding:"
echo " mkdir mybot && cd mybot"
echo " claude 'create a slack bot that responds to hello'"
echo ""
echo "## Tools Available"
echo " python3, uv, go (nix profile install nixpkgs#go)"
echo " Slack tokens: \$SLACK_BOT_TOKEN, \$SLACK_APP_TOKEN"
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"
create_user "$username" "$ssh_key"
print_onboarding "$username"
log_info "Dev user '$username' setup complete!"
}
main "$@"