fix: provision Debian cell with rogee SSH access
This commit is contained in:
@@ -9,12 +9,67 @@ set -euo pipefail
|
||||
: "${RTP_CONF_B64:?missing rtp.conf payload}"
|
||||
: "${EXTENSIONS_CONF_B64:?missing extensions.conf payload}"
|
||||
|
||||
ROGEE_USER="rogee"
|
||||
ROGEE_PUBLIC_KEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPoGJTH1JrXbWu+ZhIgaHMhume0oWQiWmadhTwbk75Ny rogee@ipao.vip"
|
||||
ASTERISK_CONFIG_DIR="/opt/agent-call/asterisk/generated"
|
||||
ASTERISK_CONFIG_GID="${ASTERISK_CONFIG_GID:-1000}"
|
||||
|
||||
if [[ "$(id -u)" != 0 ]]; then
|
||||
echo 'ECS user-data must run as root' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
if ! command -v docker >/dev/null 2>&1 || ! command -v sshd >/dev/null 2>&1 || ! command -v sudo >/dev/null 2>&1; then
|
||||
while fuser /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock >/dev/null 2>&1; do
|
||||
sleep 5
|
||||
done
|
||||
until apt-get update; do
|
||||
sleep 10
|
||||
done
|
||||
until apt-get install -y --no-install-recommends ca-certificates curl docker.io docker-cli openssh-server sudo; do
|
||||
sleep 10
|
||||
done
|
||||
fi
|
||||
|
||||
if ! getent group sudo >/dev/null 2>&1; then
|
||||
groupadd --system sudo
|
||||
fi
|
||||
if ! getent group docker >/dev/null 2>&1; then
|
||||
groupadd --system docker
|
||||
fi
|
||||
if ! id -u "$ROGEE_USER" >/dev/null 2>&1; then
|
||||
useradd --create-home --shell /bin/bash "$ROGEE_USER"
|
||||
fi
|
||||
usermod --shell /bin/bash "$ROGEE_USER"
|
||||
usermod --append --groups sudo "$ROGEE_USER"
|
||||
usermod --append --groups docker "$ROGEE_USER"
|
||||
install -d -o "$ROGEE_USER" -g "$ROGEE_USER" -m 0700 "/home/$ROGEE_USER/.ssh"
|
||||
printf '%s\n' "$ROGEE_PUBLIC_KEY" >"/home/$ROGEE_USER/.ssh/authorized_keys"
|
||||
chown "$ROGEE_USER:$ROGEE_USER" "/home/$ROGEE_USER/.ssh/authorized_keys"
|
||||
chmod 0600 "/home/$ROGEE_USER/.ssh/authorized_keys"
|
||||
cat >/etc/sudoers.d/agent-call-rogee <<'EOF'
|
||||
rogee ALL=(root) NOPASSWD: /usr/bin/systemctl, /usr/bin/journalctl, /usr/bin/docker, /usr/bin/apt-get, /usr/bin/apt-cache
|
||||
EOF
|
||||
chmod 0440 /etc/sudoers.d/agent-call-rogee
|
||||
visudo -cf /etc/sudoers.d/agent-call-rogee >/dev/null
|
||||
cat >/etc/ssh/sshd_config.d/99-agent-call-rogee.conf <<'EOF'
|
||||
Port 22
|
||||
PubkeyAuthentication yes
|
||||
PasswordAuthentication no
|
||||
KbdInteractiveAuthentication no
|
||||
ChallengeResponseAuthentication no
|
||||
PermitRootLogin no
|
||||
AllowUsers rogee
|
||||
EOF
|
||||
sshd -t
|
||||
systemctl enable --now ssh
|
||||
systemctl reload ssh
|
||||
ASTERISK_CONFIG_GID="$(id -g "$ROGEE_USER")"
|
||||
|
||||
install -d -m 0750 "$ASTERISK_CONFIG_DIR"
|
||||
write_config() {
|
||||
local name="$1" payload="$2" path="$ASTERISK_CONFIG_DIR/$1"
|
||||
local payload="$2" path="$ASTERISK_CONFIG_DIR/$1"
|
||||
printf '%s' "$payload" | base64 --decode >"$path"
|
||||
chgrp "$ASTERISK_CONFIG_GID" "$path"
|
||||
chmod 0640 "$path"
|
||||
@@ -25,19 +80,6 @@ write_config pjsip.conf "$PJSIP_CONF_B64"
|
||||
write_config rtp.conf "$RTP_CONF_B64"
|
||||
write_config extensions.conf "$EXTENSIONS_CONF_B64"
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
while fuser /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock >/dev/null 2>&1; do
|
||||
sleep 5
|
||||
done
|
||||
until apt-get update; do
|
||||
sleep 10
|
||||
done
|
||||
until apt-get install -y ca-certificates curl docker.io; do
|
||||
sleep 10
|
||||
done
|
||||
fi
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now docker
|
||||
until docker info >/dev/null 2>&1; do
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"schema_version": "1.0",
|
||||
"status": "FAIL",
|
||||
"mode": "real",
|
||||
"deployment": {
|
||||
"os": "Debian 13.6",
|
||||
"instance_id": "i-2ze2fzfwnv1zqy2ztsk0",
|
||||
"ssh_user": "rogee",
|
||||
"ssh_key_only": true,
|
||||
"root_ssh": false,
|
||||
"password_login": false,
|
||||
"asterisk_container": "healthy",
|
||||
"one_command_script": "scripts/test_ai_call.py call"
|
||||
},
|
||||
"authorization": {
|
||||
"scope": "one controlled real LLM voice call after Debian 13 redeployment",
|
||||
"callee": "15003164745",
|
||||
"max_rounds": 3,
|
||||
"automatic_retry": false
|
||||
},
|
||||
"execution": {
|
||||
"execution_id": "exec_cell_1789442841024036608_1",
|
||||
"call_id": "call_d54be5d0007e433ea696b9d0a9797f2a",
|
||||
"event_id": "exec_cell_1789442841024036608_1:call.finished",
|
||||
"tenant_id": "tenant-demo",
|
||||
"tenant_key": "tenant-demo-key",
|
||||
"connected": true,
|
||||
"duration_ms": 11070.761288999165,
|
||||
"reason_code": "RTP_RECEIVE_FAILED",
|
||||
"turns": 0,
|
||||
"media_packets_in": 0,
|
||||
"media_packets_out": 0
|
||||
},
|
||||
"sip": {
|
||||
"codec": "PCMA/8000",
|
||||
"result": "SIP answer was received; the Cell then terminated the call after media receive timeout",
|
||||
"external_media": "UnicastRTP channel created and joined the bridge",
|
||||
"rtp_and_recording": "no inbound RTP; WAV contains only a 44-byte header"
|
||||
},
|
||||
"bailian": {
|
||||
"text_probe": "PASS",
|
||||
"audio_probe": "PASS",
|
||||
"llm_model": "qwen-plus",
|
||||
"tts_configured_model": "cosyvoice-v3.5-plus",
|
||||
"tts_provider_echoed_model": false,
|
||||
"asr_model": "fun-asr-realtime"
|
||||
},
|
||||
"acceptance": {
|
||||
"real_sip_connected": true,
|
||||
"bidirectional_rtp_verified": false,
|
||||
"real_asr_llm_tts_turns": false,
|
||||
"three_round_conversation": false,
|
||||
"human_listening": false,
|
||||
"oss_recording_handoff": false,
|
||||
"production_saas_rabbitmq": false
|
||||
},
|
||||
"note": "The new Debian 13 host, rogee SSH path, Asterisk, RabbitMQ test broker, and real Bailian file probes were verified. The one-command real call reached SIP answer but produced no inbound RTP, so no AI turn or valid recording was established. No automatic retry was issued. Credentials, provider URLs, SIP addresses, and API keys are omitted."
|
||||
}
|
||||
@@ -272,6 +272,19 @@ class AsteriskTests(unittest.TestCase):
|
||||
with self.assertRaises(ValueError):
|
||||
user_data.immutable_image("registry.example/asterisk:latest")
|
||||
|
||||
def test_bootstrap_enforces_rogee_key_only_ssh(self):
|
||||
content = Path("deploy/asterisk_bootstrap.sh").read_text()
|
||||
for marker in (
|
||||
"ROGEE_USER=\"rogee\"",
|
||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPoGJTH1JrXbWu+ZhIgaHMhume0oWQiWmadhTwbk75Ny rogee@ipao.vip",
|
||||
"PasswordAuthentication no",
|
||||
"KbdInteractiveAuthentication no",
|
||||
"PermitRootLogin no",
|
||||
"AllowUsers rogee",
|
||||
"systemctl enable --now ssh",
|
||||
):
|
||||
self.assertIn(marker, content)
|
||||
|
||||
def test_codec_profile_is_rendered_without_global_fallback(self):
|
||||
cfg = self.cfg()
|
||||
cfg["primary"]["codec_profile"] = {
|
||||
|
||||
Reference in New Issue
Block a user