direxio-deployer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +92 -0
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/README_zh.md +218 -0
- package/SKILL.md +722 -0
- package/agents/README.md +25 -0
- package/agents/openai.yaml +12 -0
- package/bin/direxio-deployer.mjs +375 -0
- package/package.json +28 -0
- package/references/agent-targets.md +128 -0
- package/references/architecture.md +44 -0
- package/references/bug-history.md +78 -0
- package/references/deployment-lessons.md +218 -0
- package/references/deployment-optimization-audit.md +317 -0
- package/references/deployment-workflow.md +341 -0
- package/references/iam-policy.json +52 -0
- package/references/runtime-wiring.md +209 -0
- package/references/state-machine.md +46 -0
- package/references/token-refresh.md +81 -0
- package/references/tooling.md +106 -0
- package/references/troubleshooting.md +26 -0
- package/references/user-journey.md +75 -0
- package/references/verification-recovery.md +84 -0
- package/references/voip-turn-runbook.md +154 -0
- package/references/windows-deployment-notes.md +119 -0
- package/scripts/aws-credentials.sh +195 -0
- package/scripts/cloud-init/Caddyfile +48 -0
- package/scripts/cloud-init/docker-compose.yml +125 -0
- package/scripts/cloud-init/init-tokens.sh +238 -0
- package/scripts/cloud-init/user-data.yaml +40 -0
- package/scripts/destroy.ps1 +77 -0
- package/scripts/destroy.sh +589 -0
- package/scripts/lib/aws.sh +73 -0
- package/scripts/lib/domain.sh +175 -0
- package/scripts/lib/operation_report.sh +240 -0
- package/scripts/lib/ops.sh +230 -0
- package/scripts/lib/paths.sh +35 -0
- package/scripts/lib/state.sh +137 -0
- package/scripts/mcp-tools-list.mjs +95 -0
- package/scripts/orchestrate.ps1 +112 -0
- package/scripts/orchestrate.sh +1126 -0
- package/scripts/phases/s0_prereq_aws.sh +39 -0
- package/scripts/phases/s1_preflight.sh +72 -0
- package/scripts/phases/s2_domain.sh +103 -0
- package/scripts/phases/s3_provision.sh +421 -0
- package/scripts/phases/s4_bootstrap_stack.sh +38 -0
- package/scripts/phases/s5_init_tokens.sh +118 -0
- package/scripts/phases/s6_wire_local.sh +1435 -0
- package/scripts/phases/s7_verify_e2e.sh +136 -0
- package/scripts/pricing-estimate.sh +256 -0
- package/scripts/render/render-userdata.sh +86 -0
- package/scripts/reset-app-data.sh +40 -0
- package/scripts/update.sh +30 -0
- package/tests/aws_credentials_test.sh +139 -0
- package/tests/connect_daemon_runtime_check_test.sh +120 -0
- package/tests/default_paths_test.sh +58 -0
- package/tests/destroy_local_bridge_test.sh +154 -0
- package/tests/destroy_root_identity_test.sh +91 -0
- package/tests/destroy_route53_zone_test.sh +80 -0
- package/tests/domain_authoritative_dns_test.sh +49 -0
- package/tests/mcp_doctor_runtime_check_test.sh +86 -0
- package/tests/mcp_smoke_runtime_check_test.sh +121 -0
- package/tests/mcp_tools_runtime_check_test.sh +123 -0
- package/tests/npm_skill_distribution_test.sh +95 -0
- package/tests/operation_report_test.sh +258 -0
- package/tests/orchestrate_status_recovery_test.sh +91 -0
- package/tests/phase_timeout_test.sh +88 -0
- package/tests/pricing_estimate_test.sh +159 -0
- package/tests/render_userdata_remote_nodes_test.sh +40 -0
- package/tests/root_volume_tracking_test.sh +41 -0
- package/tests/route53_overwrite_guard_test.sh +86 -0
- package/tests/route53_zone_auto_create_test.sh +66 -0
- package/tests/runtime_summary_check_test.sh +203 -0
- package/tests/s6_wire_local_test.sh +405 -0
- package/tests/skill_structure_test.sh +298 -0
- package/tests/update_reset_ops_test.sh +230 -0
- package/tests/user_confirmation_gates_test.sh +152 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# S5 INIT_TOKENS - fetch AS-written bootstrap credentials from the instance.
|
|
3
|
+
# Also verify owner.json so the client does not report Portal as undeployed.
|
|
4
|
+
|
|
5
|
+
run_phase() {
|
|
6
|
+
phase_set S5_INIT_TOKENS in_progress "fetching tokens"
|
|
7
|
+
local domain pubip keyfile
|
|
8
|
+
domain=$(state_get domain)
|
|
9
|
+
pubip=$(res_get public_ip)
|
|
10
|
+
keyfile=$(res_get key_file)
|
|
11
|
+
local out="$P2P_WORKDIR/outputs.json" raw
|
|
12
|
+
raw=$(mktemp)
|
|
13
|
+
trap 'rm -f "${raw:-}"; trap - RETURN' RETURN
|
|
14
|
+
|
|
15
|
+
log "Fetching /opt/p2p/bootstrap.json ..."
|
|
16
|
+
if ! poll_until "read bootstrap.json" "${TOKEN_POLL_INTERVAL:-10}" "${TOKEN_POLL_MAX:-12}" \
|
|
17
|
+
_read_remote_bootstrap "$keyfile" "$pubip" "$raw"; then
|
|
18
|
+
phase_set S5_INIT_TOKENS failed "failed to fetch bootstrap.json"
|
|
19
|
+
warn "Could not read /opt/p2p/bootstrap.json. Check whether message-server wrote credentials:"
|
|
20
|
+
warn " ssh -i $keyfile ubuntu@$pubip 'sudo cat /opt/p2p/bootstrap.json 2>/dev/null; cd /opt/p2p; sudo docker compose logs message-server | tail -40'"
|
|
21
|
+
return 1
|
|
22
|
+
fi
|
|
23
|
+
if ! _normalize_bootstrap_output "$domain" "$raw" "$out"; then
|
|
24
|
+
phase_set S5_INIT_TOKENS failed "invalid bootstrap.json"
|
|
25
|
+
fail "bootstrap.json could not be normalized."
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
# Verify owner.json; missing file makes the client report Portal as undeployed.
|
|
29
|
+
if _healthz_ok_ownerjson "$domain"; then
|
|
30
|
+
log "owner.json 200 OK (Portal discovery healthy)"
|
|
31
|
+
else
|
|
32
|
+
warn "/.well-known/portal/owner.json did not return 200. The client may report Portal as undeployed."
|
|
33
|
+
warn " Check Caddy file_server and /opt/p2p/wellknown/owner.json generation."
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
local password token access_token asurl agent_room_id
|
|
37
|
+
if ! IFS=$'\t' read -r password token access_token < <(_extract_output_tokens "$out"); then
|
|
38
|
+
phase_set S5_INIT_TOKENS failed "bootstrap.json missing password/access/agent credentials"
|
|
39
|
+
fail "bootstrap.json must contain password as an eight-digit initialization-code string plus access_token and agent_token."
|
|
40
|
+
fi
|
|
41
|
+
asurl=$(jq -r --arg domain "$domain" '.as_url // ("https://" + $domain)' "$out")
|
|
42
|
+
agent_room_id=$(jq -r '.agent_room_id // empty' "$out")
|
|
43
|
+
if [ -z "$agent_room_id" ] || [[ "$agent_room_id" == \!agent:* ]]; then
|
|
44
|
+
phase_set S5_INIT_TOKENS failed "bootstrap.json missing real agent_room_id"
|
|
45
|
+
fail "bootstrap.json must contain a real Matrix agent_room_id; legacy !agent:<domain> ids are not supported."
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Store tokens in state for S6. state.json is local-only and chmod 0600.
|
|
49
|
+
state_set as_url "$asurl"
|
|
50
|
+
state_set password "$password"
|
|
51
|
+
state_set agent_token "$token"
|
|
52
|
+
state_set access_token "$access_token"
|
|
53
|
+
state_set agent_room_id "$agent_room_id"
|
|
54
|
+
|
|
55
|
+
phase_set S5_INIT_TOKENS done "got password (len=${#password}) as_url=$asurl agent_room_id=$agent_room_id"
|
|
56
|
+
ok "Tokens fetched from bootstrap.json."
|
|
57
|
+
return 0
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
_extract_output_tokens() {
|
|
61
|
+
local out=$1 password token access_token
|
|
62
|
+
password=$(jq -r 'if (.password | type) == "string" then .password else empty end' "$out")
|
|
63
|
+
token=$(jq -r '.agent_token // empty' "$out")
|
|
64
|
+
access_token=$(jq -r '.access_token // empty' "$out")
|
|
65
|
+
[ -n "$password" ] && [ -n "$token" ] && [ -n "$access_token" ] || return 1
|
|
66
|
+
printf '%s' "$password" | grep -Eq '^[0-9]{8}$' || return 1
|
|
67
|
+
printf '%s\t%s\t%s\n' "$password" "$token" "$access_token"
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
_read_remote_bootstrap() {
|
|
71
|
+
local keyfile=$1 pubip=$2 out=$3
|
|
72
|
+
local ssh_args cmd timeout_seconds
|
|
73
|
+
ssh_args=(
|
|
74
|
+
-i "$keyfile"
|
|
75
|
+
-o StrictHostKeyChecking=accept-new
|
|
76
|
+
-o ConnectTimeout="${SSH_CONNECT_TIMEOUT:-10}"
|
|
77
|
+
-o BatchMode=yes
|
|
78
|
+
-o ServerAliveInterval="${SSH_SERVER_ALIVE_INTERVAL:-5}"
|
|
79
|
+
-o ServerAliveCountMax="${SSH_SERVER_ALIVE_COUNT_MAX:-2}"
|
|
80
|
+
)
|
|
81
|
+
cmd=(ssh "${ssh_args[@]}" ubuntu@"$pubip" "sudo test -s /opt/p2p/bootstrap.json && sudo cat /opt/p2p/bootstrap.json")
|
|
82
|
+
timeout_seconds=${SSH_COMMAND_TIMEOUT:-30}
|
|
83
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
84
|
+
timeout "$timeout_seconds" "${cmd[@]}" > "$out" 2>/dev/null
|
|
85
|
+
else
|
|
86
|
+
"${cmd[@]}" > "$out" 2>/dev/null
|
|
87
|
+
fi
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
_normalize_bootstrap_output() {
|
|
91
|
+
local domain=$1 src=$2 out=$3
|
|
92
|
+
local tmp
|
|
93
|
+
tmp=$(mktemp)
|
|
94
|
+
if ! jq --arg domain "$domain" --arg asurl "https://$domain" '
|
|
95
|
+
. + {
|
|
96
|
+
domain: (.domain // $domain),
|
|
97
|
+
as_url: (.as_url // $asurl),
|
|
98
|
+
p2p_url: (.p2p_url // $asurl),
|
|
99
|
+
user_id: (.user_id // .owner_user_id // ""),
|
|
100
|
+
bot_mxid: (.bot_mxid // .owner_user_id // .user_id // ("@owner:" + $domain)),
|
|
101
|
+
access_token: (.access_token // ""),
|
|
102
|
+
agent_token: (.agent_token // ""),
|
|
103
|
+
agent_room_id: (.agent_room_id // "")
|
|
104
|
+
}
|
|
105
|
+
' "$src" > "$tmp"; then
|
|
106
|
+
rm -f "$tmp"
|
|
107
|
+
return 1
|
|
108
|
+
fi
|
|
109
|
+
mv "$tmp" "$out"
|
|
110
|
+
chmod 600 "$out" 2>/dev/null || true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
_healthz_ok_ownerjson() {
|
|
114
|
+
local domain=$1 pubip args=()
|
|
115
|
+
pubip=$(res_get public_ip)
|
|
116
|
+
[ -n "$pubip" ] && args=(--resolve "$domain:443:$pubip")
|
|
117
|
+
[ "$(curl -sk "${args[@]}" -o /dev/null -w '%{http_code}' "https://$domain/.well-known/portal/owner.json" 2>/dev/null)" = "200" ]
|
|
118
|
+
}
|