firstboot: Add shell-ssh.sh module and restore shell-system.sh
- Create new shell-ssh.sh module for SSH key installation and password setup * Install SSH public keys to authorized_keys (root + clawdie) * Configure sshd: disable password auth if key provided, enable if not * Set system user passwords (auto-generate or use provided) * Save emergency root password to root/.firstboot-emergency-password - Restore shell-system.sh (was accidentally overwritten during rename) Enables secure SSH-key-first access with password fallback. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
640d44b5fe
commit
ae11ae03ff
2 changed files with 460 additions and 199 deletions
260
firstboot/shell-ssh.sh
Normal file
260
firstboot/shell-ssh.sh
Normal file
|
|
@ -0,0 +1,260 @@
|
|||
#!/bin/sh
|
||||
# Clawdie Shell — SSH & System User Password Module
|
||||
# Purpose: Configure SSH keys and system user passwords
|
||||
# Author: Clawdie Project
|
||||
# POSIX-compliant (no bash-isms)
|
||||
|
||||
set -eu
|
||||
|
||||
# Configuration (can be overridden for testing)
|
||||
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
|
||||
PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"
|
||||
EMERGENCY_PASSWORD_FILE="${EMERGENCY_PASSWORD_FILE:-/root/.firstboot-emergency-password}"
|
||||
|
||||
# Derived from wizard/build inputs (caller sets these)
|
||||
# SSH_PUBLIC_KEY - Optional SSH public key (ssh-ed25519 or ssh-rsa)
|
||||
# ROOT_PASSWORD - Optional root password (if empty, auto-generate)
|
||||
# CLAWDIE_USER_PASSWORD - Optional clawdie user password (if empty, auto-generate)
|
||||
|
||||
# ============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# ============================================================================
|
||||
|
||||
clawdie_shell_ssh_setup() {
|
||||
# Main orchestrator
|
||||
# 1. Configure SSH keys (if provided)
|
||||
# 2. Set system passwords (if provided or auto-generate)
|
||||
# 3. Configure SSH auth methods (key-only or key+password)
|
||||
|
||||
log_msg "[ssh] Starting SSH and password setup"
|
||||
|
||||
# Generate emergency root password if not provided
|
||||
if [ -z "${ROOT_PASSWORD:-}" ]; then
|
||||
ROOT_PASSWORD=$(gen_secret)
|
||||
fi
|
||||
|
||||
# Generate clawdie user password if not provided
|
||||
if [ -z "${CLAWDIE_USER_PASSWORD:-}" ]; then
|
||||
CLAWDIE_USER_PASSWORD=$(gen_secret)
|
||||
fi
|
||||
|
||||
# Setup SSH keys if provided
|
||||
if [ -n "${SSH_PUBLIC_KEY:-}" ]; then
|
||||
clawdie_shell_ssh_install_pubkey
|
||||
clawdie_shell_ssh_disable_password_auth
|
||||
log_msg "[ssh] SSH public key installed, password auth disabled"
|
||||
else
|
||||
clawdie_shell_ssh_enable_password_auth
|
||||
log_msg "[ssh] No SSH key provided, password auth enabled (less secure)"
|
||||
fi
|
||||
|
||||
# Set system user passwords
|
||||
clawdie_shell_ssh_set_passwords "$ROOT_PASSWORD" "$CLAWDIE_USER_PASSWORD"
|
||||
log_msg "[ssh] System user passwords set"
|
||||
|
||||
# Save emergency root password to file
|
||||
clawdie_shell_ssh_save_emergency_password "$ROOT_PASSWORD"
|
||||
log_msg "[ssh] Emergency root password saved"
|
||||
|
||||
echo "[SSH] COMPLETE" >> "$PROGRESS_FILE"
|
||||
log_msg "[ssh] SSH setup complete"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SSH PUBLIC KEY INSTALLATION
|
||||
# ============================================================================
|
||||
|
||||
clawdie_shell_ssh_install_pubkey() {
|
||||
# Install SSH_PUBLIC_KEY to authorized_keys for both root and clawdie user
|
||||
|
||||
local root_ssh_dir="/root/.ssh"
|
||||
local clawdie_ssh_dir="/home/clawdie/.ssh"
|
||||
|
||||
# Setup root authorized_keys
|
||||
if [ ! -d "$root_ssh_dir" ]; then
|
||||
mkdir -p "$root_ssh_dir"
|
||||
chmod 700 "$root_ssh_dir"
|
||||
fi
|
||||
|
||||
echo "$SSH_PUBLIC_KEY" >> "$root_ssh_dir/authorized_keys" 2>/dev/null || {
|
||||
log_msg "[ssh] ERROR: Failed to install SSH key for root"
|
||||
return 1
|
||||
}
|
||||
|
||||
chmod 600 "$root_ssh_dir/authorized_keys"
|
||||
log_msg "[ssh] Installed SSH key for root user"
|
||||
|
||||
# Setup clawdie authorized_keys
|
||||
if [ ! -d "$clawdie_ssh_dir" ]; then
|
||||
mkdir -p "$clawdie_ssh_dir"
|
||||
chmod 700 "$clawdie_ssh_dir"
|
||||
fi
|
||||
|
||||
echo "$SSH_PUBLIC_KEY" >> "$clawdie_ssh_dir/authorized_keys" 2>/dev/null || {
|
||||
log_msg "[ssh] ERROR: Failed to install SSH key for clawdie"
|
||||
return 1
|
||||
}
|
||||
|
||||
chmod 600 "$clawdie_ssh_dir/authorized_keys"
|
||||
chown -R clawdie:clawdie "$clawdie_ssh_dir"
|
||||
log_msg "[ssh] Installed SSH key for clawdie user"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SSH AUTH METHOD CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
clawdie_shell_ssh_disable_password_auth() {
|
||||
# Disable password authentication in sshd_config
|
||||
# Keep PubkeyAuthentication enabled
|
||||
|
||||
local sshd_config="/etc/ssh/sshd_config"
|
||||
|
||||
if [ ! -f "$sshd_config" ]; then
|
||||
log_msg "[ssh] WARNING: sshd_config not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Ensure PubkeyAuthentication is enabled
|
||||
if grep -q "^#*PubkeyAuthentication" "$sshd_config"; then
|
||||
sed -i '' 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' "$sshd_config"
|
||||
else
|
||||
echo "PubkeyAuthentication yes" >> "$sshd_config"
|
||||
fi
|
||||
|
||||
# Disable PasswordAuthentication
|
||||
if grep -q "^#*PasswordAuthentication" "$sshd_config"; then
|
||||
sed -i '' 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' "$sshd_config"
|
||||
else
|
||||
echo "PasswordAuthentication no" >> "$sshd_config"
|
||||
fi
|
||||
|
||||
# Disable PermitRootLogin with password (allow pubkey only)
|
||||
if grep -q "^#*PermitRootLogin" "$sshd_config"; then
|
||||
sed -i '' 's/^#*PermitRootLogin.*/PermitRootLogin prohibit-password/' "$sshd_config"
|
||||
else
|
||||
echo "PermitRootLogin prohibit-password" >> "$sshd_config"
|
||||
fi
|
||||
|
||||
log_msg "[ssh] Disabled password auth in sshd_config"
|
||||
return 0
|
||||
}
|
||||
|
||||
clawdie_shell_ssh_enable_password_auth() {
|
||||
# Enable password authentication in sshd_config (fallback)
|
||||
# Less secure but prevents lockout if user loses SSH key
|
||||
|
||||
local sshd_config="/etc/ssh/sshd_config"
|
||||
|
||||
if [ ! -f "$sshd_config" ]; then
|
||||
log_msg "[ssh] WARNING: sshd_config not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Enable PasswordAuthentication
|
||||
if grep -q "^#*PasswordAuthentication" "$sshd_config"; then
|
||||
sed -i '' 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' "$sshd_config"
|
||||
else
|
||||
echo "PasswordAuthentication yes" >> "$sshd_config"
|
||||
fi
|
||||
|
||||
# Allow root login with password
|
||||
if grep -q "^#*PermitRootLogin" "$sshd_config"; then
|
||||
sed -i '' 's/^#*PermitRootLogin.*/PermitRootLogin yes/' "$sshd_config"
|
||||
else
|
||||
echo "PermitRootLogin yes" >> "$sshd_config"
|
||||
fi
|
||||
|
||||
log_msg "[ssh] WARNING: Password auth enabled (less secure)"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# PASSWORD MANAGEMENT
|
||||
# ============================================================================
|
||||
|
||||
clawdie_shell_ssh_set_passwords() {
|
||||
local root_pwd="$1"
|
||||
local clawdie_pwd="$2"
|
||||
|
||||
# Set root password using echo | pw usermod
|
||||
echo "$root_pwd" | pw usermod root -h 0 2>/dev/null || {
|
||||
log_msg "[ssh] ERROR: Failed to set root password"
|
||||
return 1
|
||||
}
|
||||
|
||||
log_msg "[ssh] Root password set"
|
||||
|
||||
# Set clawdie user password
|
||||
# Create user if it doesn't exist
|
||||
if ! id clawdie >/dev/null 2>&1; then
|
||||
pw useradd -n clawdie -u 1000 -g wheel -m -s /bin/sh 2>/dev/null || {
|
||||
log_msg "[ssh] ERROR: Failed to create clawdie user"
|
||||
return 1
|
||||
}
|
||||
log_msg "[ssh] Created clawdie user"
|
||||
fi
|
||||
|
||||
echo "$clawdie_pwd" | pw usermod clawdie -h 0 2>/dev/null || {
|
||||
log_msg "[ssh] ERROR: Failed to set clawdie password"
|
||||
return 1
|
||||
}
|
||||
|
||||
log_msg "[ssh] Clawdie user password set"
|
||||
return 0
|
||||
}
|
||||
|
||||
clawdie_shell_ssh_save_emergency_password() {
|
||||
local root_pwd="$1"
|
||||
|
||||
# Save emergency password to file (root-only, readable only by root)
|
||||
{
|
||||
echo "EMERGENCY ROOT PASSWORD"
|
||||
echo "=============================="
|
||||
echo ""
|
||||
echo "Generated at: $(date)"
|
||||
echo "Password: $root_pwd"
|
||||
echo ""
|
||||
echo "Access:"
|
||||
echo " ssh root@<domain>"
|
||||
echo ""
|
||||
echo "WARNING: Store this securely."
|
||||
echo "This file should be moved to secure storage and deleted from this system."
|
||||
} > "$EMERGENCY_PASSWORD_FILE" 2>/dev/null || {
|
||||
log_msg "[ssh] WARNING: Could not save emergency password file"
|
||||
return 1
|
||||
}
|
||||
|
||||
chmod 600 "$EMERGENCY_PASSWORD_FILE"
|
||||
log_msg "[ssh] Emergency password saved to $EMERGENCY_PASSWORD_FILE"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# UTILITY: Logging & Secret Generation
|
||||
# ============================================================================
|
||||
|
||||
log_msg() {
|
||||
local msg="$1"
|
||||
echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
gen_secret() {
|
||||
openssl rand -base64 32 | tr -d '\n/+=' | head -c 32
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Export for use by firstboot.sh
|
||||
# ============================================================================
|
||||
|
||||
case "${0##*/}" in
|
||||
shell-ssh.sh)
|
||||
# Direct execution (for testing)
|
||||
clawdie_shell_ssh_setup
|
||||
;;
|
||||
*)
|
||||
# Sourced from another script — functions available
|
||||
;;
|
||||
esac
|
||||
|
|
@ -1,232 +1,233 @@
|
|||
#!/bin/sh
|
||||
# Unit tests for clawdie-shell-system.sh
|
||||
# Run: sh test-clawdie-shell-system.sh
|
||||
# POSIX-compliant
|
||||
# Clawdie Shell — System Configuration Module
|
||||
# Purpose: System-level config (rc.conf, hostname, services, environment)
|
||||
# Author: Clawdie Project
|
||||
# POSIX-compliant (no bash-isms)
|
||||
|
||||
set -u
|
||||
set -eu
|
||||
# FreeBSD /bin/sh doesn't support trap ERR
|
||||
|
||||
TESTDIR="/tmp/clawdie-test-system-$$"
|
||||
mkdir -p "$TESTDIR"
|
||||
cd "$TESTDIR"
|
||||
# Configuration (can be overridden for testing)
|
||||
RC_CONF="${RC_CONF:-/etc/rc.conf}"
|
||||
HOSTNAME_FILE="${HOSTNAME_FILE:-/etc/hostname}"
|
||||
PROFILE_DIR="${PROFILE_DIR:-/etc/profile.d}"
|
||||
LOG_FILE="${LOG_FILE:-/var/log/clawdie-firstboot.log}"
|
||||
PROGRESS_FILE="${PROGRESS_FILE:-/var/log/clawdie-firstboot.progress}"
|
||||
|
||||
# Setup test environment
|
||||
mkdir -p "$TESTDIR/etc/profile.d"
|
||||
mkdir -p "$TESTDIR/var/log"
|
||||
# Derived from wizard inputs (caller sets these)
|
||||
# TZ - Timezone (e.g., "Europe/Ljubljana")
|
||||
# AGENT_DOMAIN - FQDN (e.g., "clawdie.local")
|
||||
# DETECTED_GPU - GPU vendor from gpu module (intel, amd, nvidia, vmware, vesa)
|
||||
|
||||
# Create test rc.conf
|
||||
touch "$TESTDIR/etc/rc.conf"
|
||||
# ============================================================================
|
||||
# MAIN ENTRY POINT
|
||||
# ============================================================================
|
||||
|
||||
# Environment overrides
|
||||
export RC_CONF="$TESTDIR/etc/rc.conf"
|
||||
export HOSTNAME_FILE="$TESTDIR/etc/hostname"
|
||||
export PROFILE_DIR="$TESTDIR/etc/profile.d"
|
||||
export LOG_FILE="$TESTDIR/var/log/clawdie-system-test.log"
|
||||
export PROGRESS_FILE="$TESTDIR/var/log/clawdie-system-progress-test"
|
||||
clawdie_shell_system_config() {
|
||||
# Main orchestrator
|
||||
|
||||
# Test inputs
|
||||
export TZ="Europe/Ljubljana"
|
||||
export AGENT_DOMAIN="clawdie.local"
|
||||
export DETECTED_GPU="intel"
|
||||
log_msg "[system] Starting system configuration"
|
||||
|
||||
# Initialize log/progress files
|
||||
touch "$LOG_FILE"
|
||||
touch "$PROGRESS_FILE"
|
||||
|
||||
# Source the module
|
||||
. "$(dirname "$0")/clawdie-shell-system.sh"
|
||||
|
||||
# Color codes
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Test counter
|
||||
TESTS_PASSED=0
|
||||
TESTS_FAILED=0
|
||||
|
||||
# Helper: assert
|
||||
assert_eq() {
|
||||
local name="$1"
|
||||
local expected="$2"
|
||||
local actual="$3"
|
||||
|
||||
if [ "$expected" = "$actual" ]; then
|
||||
echo "${GREEN}✓${NC} $name"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
else
|
||||
echo "${RED}✗${NC} $name"
|
||||
echo " Expected: $expected"
|
||||
echo " Actual: $actual"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
if [ -z "${TZ:-}" ]; then
|
||||
echo "ERROR: TZ not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "${AGENT_DOMAIN:-}" ]; then
|
||||
echo "ERROR: AGENT_DOMAIN not set" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Write rc.conf with timezone and services
|
||||
clawdie_shell_system_write_rcconf
|
||||
log_msg "[system] Updated rc.conf"
|
||||
|
||||
# Set hostname
|
||||
clawdie_shell_system_set_hostname
|
||||
log_msg "[system] Set hostname"
|
||||
|
||||
# Setup environment
|
||||
clawdie_shell_system_setup_env
|
||||
log_msg "[system] Setup environment"
|
||||
|
||||
# Enable services
|
||||
clawdie_shell_system_enable_services
|
||||
log_msg "[system] Enabled services"
|
||||
|
||||
echo "[SYSTEM] COMPLETE" >> "$PROGRESS_FILE"
|
||||
log_msg "[system] System configuration complete"
|
||||
}
|
||||
|
||||
assert_file_exists() {
|
||||
local name="$1"
|
||||
local file="$2"
|
||||
# ============================================================================
|
||||
# RC.CONF CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
if [ -f "$file" ]; then
|
||||
echo "${GREEN}✓${NC} $name"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
else
|
||||
echo "${RED}✗${NC} $name (file not found: $file)"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
clawdie_shell_system_write_rcconf() {
|
||||
# Update /etc/rc.conf with:
|
||||
# - timezone
|
||||
# - service configurations (dbus, hald, seatd, lightdm)
|
||||
# - Lumina desktop settings
|
||||
|
||||
if [ ! -f "$RC_CONF" ]; then
|
||||
log_msg "[system] Creating $RC_CONF"
|
||||
touch "$RC_CONF"
|
||||
fi
|
||||
|
||||
# Helper to set or update rc.conf variable
|
||||
clawdie_shell_system_sysrc "timezone=$TZ"
|
||||
clawdie_shell_system_sysrc "dbus_enable=YES"
|
||||
clawdie_shell_system_sysrc "hald_enable=YES"
|
||||
clawdie_shell_system_sysrc "seatd_enable=YES"
|
||||
clawdie_shell_system_sysrc "display_manager=lightdm"
|
||||
clawdie_shell_system_sysrc "lightdm_enable=YES"
|
||||
|
||||
log_msg "[system] Wrote rc.conf configuration"
|
||||
}
|
||||
|
||||
assert_file_contains() {
|
||||
local name="$1"
|
||||
local file="$2"
|
||||
local pattern="$3"
|
||||
clawdie_shell_system_sysrc() {
|
||||
# Add or update a variable in rc.conf
|
||||
# Input: VAR=VALUE
|
||||
|
||||
if [ -f "$file" ] && grep -q "$pattern" "$file"; then
|
||||
echo "${GREEN}✓${NC} $name"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
local var_assignment="$1"
|
||||
local var_name var_value
|
||||
|
||||
var_name=$(echo "$var_assignment" | cut -d= -f1)
|
||||
var_value=$(echo "$var_assignment" | cut -d= -f2-)
|
||||
|
||||
# Check if var already set (idempotence)
|
||||
if grep -q "^${var_name}=" "$RC_CONF" 2>/dev/null; then
|
||||
# Update existing (use | as delimiter to avoid issues with / in values)
|
||||
sed -i '' "s|^${var_name}=.*|${var_assignment}|" "$RC_CONF"
|
||||
else
|
||||
echo "${RED}✗${NC} $name"
|
||||
echo " File: $file"
|
||||
echo " Pattern: $pattern"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
# Append new
|
||||
echo "$var_assignment" >> "$RC_CONF"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# TEST SUITE
|
||||
# HOSTNAME CONFIGURATION
|
||||
# ============================================================================
|
||||
|
||||
echo "=== Clawdie Shell System Module Tests ==="
|
||||
echo ""
|
||||
clawdie_shell_system_set_hostname() {
|
||||
# Set /etc/hostname and apply live
|
||||
|
||||
# Test 1: RC.CONF Configuration
|
||||
echo "Test Group: RC.CONF Configuration"
|
||||
clawdie_shell_system_write_rcconf
|
||||
if [ ! -f "$HOSTNAME_FILE" ]; then
|
||||
touch "$HOSTNAME_FILE"
|
||||
fi
|
||||
|
||||
assert_file_contains "rc.conf contains timezone" "$RC_CONF" "timezone=Europe/Ljubljana"
|
||||
assert_file_contains "rc.conf contains dbus_enable" "$RC_CONF" "dbus_enable=YES"
|
||||
assert_file_contains "rc.conf contains hald_enable" "$RC_CONF" "hald_enable=YES"
|
||||
assert_file_contains "rc.conf contains seatd_enable" "$RC_CONF" "seatd_enable=YES"
|
||||
assert_file_contains "rc.conf contains display_manager" "$RC_CONF" "display_manager=lightdm"
|
||||
assert_file_contains "rc.conf contains lightdm_enable" "$RC_CONF" "lightdm_enable=YES"
|
||||
echo ""
|
||||
# Write to file
|
||||
echo "$AGENT_DOMAIN" > "$HOSTNAME_FILE"
|
||||
|
||||
# Test 2: RC.CONF Idempotence
|
||||
echo "Test Group: RC.CONF Idempotence"
|
||||
rm -f "$TESTDIR/etc/rc.conf"
|
||||
touch "$TESTDIR/etc/rc.conf"
|
||||
# Apply live (if not in chroot)
|
||||
if command -v hostname >/dev/null 2>&1; then
|
||||
hostname "$AGENT_DOMAIN" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# Write multiple times
|
||||
clawdie_shell_system_write_rcconf
|
||||
clawdie_shell_system_write_rcconf
|
||||
|
||||
# Should only have one timezone line
|
||||
timezone_count=$(grep -c "^timezone=" "$RC_CONF" || true)
|
||||
assert_eq "Timezone appears only once" "1" "$timezone_count"
|
||||
|
||||
dbus_count=$(grep -c "^dbus_enable=" "$RC_CONF" || true)
|
||||
assert_eq "dbus_enable appears only once" "1" "$dbus_count"
|
||||
echo ""
|
||||
|
||||
# Test 3: Hostname Configuration
|
||||
echo "Test Group: Hostname Configuration"
|
||||
clawdie_shell_system_set_hostname
|
||||
|
||||
assert_file_exists "Hostname file created" "$HOSTNAME_FILE"
|
||||
assert_file_contains "Hostname file contains domain" "$HOSTNAME_FILE" "clawdie.local"
|
||||
echo ""
|
||||
|
||||
# Test 4: Environment Setup
|
||||
echo "Test Group: Environment Setup"
|
||||
clawdie_shell_system_setup_env
|
||||
|
||||
assert_file_exists "clawdie.sh profile created" "$PROFILE_DIR/clawdie.sh"
|
||||
assert_file_contains "Profile has npm_config_prefix" "$PROFILE_DIR/clawdie.sh" "npm_config_prefix"
|
||||
assert_file_contains "Profile has PATH export" "$PROFILE_DIR/clawdie.sh" "PATH"
|
||||
echo ""
|
||||
|
||||
# Test 5: Full Setup Flow
|
||||
echo "Test Group: Full Setup Flow"
|
||||
rm -f "$TESTDIR/etc/rc.conf" "$TESTDIR/etc/hostname" "$PROGRESS_FILE"
|
||||
touch "$TESTDIR/etc/rc.conf"
|
||||
touch "$PROGRESS_FILE"
|
||||
|
||||
clawdie_shell_system_config 2>/dev/null
|
||||
|
||||
assert_file_exists "rc.conf exists" "$RC_CONF"
|
||||
assert_file_exists "hostname file exists" "$HOSTNAME_FILE"
|
||||
assert_file_exists "profile exists" "$PROFILE_DIR/clawdie.sh"
|
||||
|
||||
if grep -q "\[SYSTEM\] COMPLETE" "$PROGRESS_FILE"; then
|
||||
echo "${GREEN}✓${NC} Progress checkpoint logged"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
else
|
||||
echo "${RED}✗${NC} Progress checkpoint not found"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 6: Validation
|
||||
echo "Test Group: Validation"
|
||||
if clawdie_shell_system_validate 2>/dev/null; then
|
||||
echo "${GREEN}✓${NC} Validation passes"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
else
|
||||
echo "${RED}✗${NC} Validation failed"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 7: SYSRC Update Behavior
|
||||
echo "Test Group: SYSRC Update Behavior"
|
||||
# Already tested above, but verify update specifically
|
||||
rm -f "$TESTDIR/etc/rc.conf"
|
||||
touch "$TESTDIR/etc/rc.conf"
|
||||
|
||||
clawdie_shell_system_sysrc "update_test=oldvalue"
|
||||
clawdie_shell_system_sysrc "update_test=newvalue"
|
||||
|
||||
# Ensure only one line exists
|
||||
update_count=$(grep -c "^update_test=" "$TESTDIR/etc/rc.conf" || true)
|
||||
if [ "$update_count" = "1" ]; then
|
||||
echo "${GREEN}✓${NC} SYSRC properly updates existing vars"
|
||||
TESTS_PASSED=$((TESTS_PASSED + 1))
|
||||
else
|
||||
echo "${RED}✗${NC} SYSRC created duplicate entries ($update_count lines)"
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 8: SYSRC Helper Function
|
||||
echo "Test Group: SYSRC Helper"
|
||||
rm -f "$TESTDIR/etc/rc.conf"
|
||||
touch "$TESTDIR/etc/rc.conf"
|
||||
|
||||
clawdie_shell_system_sysrc "test_var=value1"
|
||||
assert_file_contains "New var added" "$RC_CONF" "test_var=value1"
|
||||
|
||||
clawdie_shell_system_sysrc "test_var=value2"
|
||||
test_count=$(grep -c "^test_var=" "$RC_CONF" || true)
|
||||
assert_eq "SYSRC updates existing var" "1" "$test_count"
|
||||
|
||||
actual_value=$(grep "^test_var=" "$RC_CONF" | cut -d= -f2)
|
||||
assert_eq "SYSRC sets correct value" "value2" "$actual_value"
|
||||
echo ""
|
||||
log_msg "[system] Set hostname to $AGENT_DOMAIN"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SUMMARY
|
||||
# ENVIRONMENT SETUP
|
||||
# ============================================================================
|
||||
|
||||
echo "=== Test Results ==="
|
||||
echo "${GREEN}Passed: $TESTS_PASSED${NC}"
|
||||
echo "${RED}Failed: $TESTS_FAILED${NC}"
|
||||
echo ""
|
||||
clawdie_shell_system_setup_env() {
|
||||
# Create /etc/profile.d/clawdie.sh for environment variables
|
||||
# Sets up npm global paths and other Clawdie-specific variables
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$TESTDIR"
|
||||
if [ ! -d "$PROFILE_DIR" ]; then
|
||||
mkdir -p "$PROFILE_DIR"
|
||||
fi
|
||||
|
||||
if [ $TESTS_FAILED -eq 0 ]; then
|
||||
echo "${GREEN}✓ All tests passed!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo "${RED}✗ Some tests failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
local clawdie_profile="$PROFILE_DIR/clawdie.sh"
|
||||
|
||||
cat > "$clawdie_profile" <<'EOF'
|
||||
# Clawdie-AI environment setup
|
||||
# Adds npm global bin directory to PATH
|
||||
|
||||
export npm_config_prefix="${HOME}/.npm-global"
|
||||
export PATH="${HOME}/.npm-global/bin:${PATH}"
|
||||
EOF
|
||||
|
||||
chmod 644 "$clawdie_profile"
|
||||
log_msg "[system] Created $clawdie_profile"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# SERVICE ENABLEMENT
|
||||
# ============================================================================
|
||||
|
||||
clawdie_shell_system_enable_services() {
|
||||
# Enable and start required services
|
||||
# Safe to fail if running in chroot (first boot)
|
||||
|
||||
local services="dbus hald seatd lightdm"
|
||||
|
||||
for service in $services; do
|
||||
if command -v service >/dev/null 2>&1; then
|
||||
# Try to start service
|
||||
service "$service" onestart 2>/dev/null || {
|
||||
log_msg "[system] Could not start $service (expected in chroot)"
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
log_msg "[system] Service enablement complete"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# VALIDATION
|
||||
# ============================================================================
|
||||
|
||||
clawdie_shell_system_validate() {
|
||||
# Verify system configuration completed
|
||||
|
||||
if [ ! -f "$RC_CONF" ]; then
|
||||
echo "ERROR: rc.conf not found" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check timezone is set
|
||||
if ! grep -q "^timezone=" "$RC_CONF"; then
|
||||
echo "ERROR: timezone not set in rc.conf" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check hostname file exists
|
||||
if [ ! -f "$HOSTNAME_FILE" ]; then
|
||||
echo "ERROR: $HOSTNAME_FILE not created" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check environment profile exists
|
||||
if [ ! -f "$PROFILE_DIR/clawdie.sh" ]; then
|
||||
echo "ERROR: $PROFILE_DIR/clawdie.sh not created" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_msg "[system] Validation passed"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# UTILITY: Logging
|
||||
# ============================================================================
|
||||
|
||||
log_msg() {
|
||||
local msg="$1"
|
||||
echo "$msg" >> "$LOG_FILE" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Export for use by firstboot.sh
|
||||
# ============================================================================
|
||||
|
||||
case "${0##*/}" in
|
||||
clawdie-shell-system.sh)
|
||||
# Direct execution (for testing)
|
||||
clawdie_shell_system_config
|
||||
clawdie_shell_system_validate
|
||||
;;
|
||||
*)
|
||||
# Sourced from another script — functions available
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue