@@ -147,6 +147,10 @@ jobs:
147147
148148 - name : Test configuration changes
149149 run : |
150+ # Record gateway token before any config changes
151+ TOKEN_BEFORE=$(juju ssh openclaw/0 'jq -r .gateway.auth.token /home/ubuntu/.openclaw/openclaw.json')
152+ echo "Gateway token before config change: $TOKEN_BEFORE"
153+
150154 # Change gateway port
151155 juju config openclaw gateway-port=18790
152156
@@ -156,6 +160,16 @@ jobs:
156160 # Verify port change
157161 juju ssh openclaw/0 'ss -tulpn | grep 18790' || echo "Port change test (may not bind without valid key)"
158162
163+ # Verify gateway token is unchanged after config-changed
164+ TOKEN_AFTER=$(juju ssh openclaw/0 'jq -r .gateway.auth.token /home/ubuntu/.openclaw/openclaw.json')
165+ echo "Gateway token after config change: $TOKEN_AFTER"
166+ if [ "$TOKEN_AFTER" = "$TOKEN_BEFORE" ]; then
167+ echo "✓ Gateway token preserved across config-changed"
168+ else
169+ echo "✗ Gateway token changed after config-changed"
170+ exit 1
171+ fi
172+
159173 # Change back
160174 juju config openclaw gateway-port=18789
161175
@@ -217,7 +231,8 @@ jobs:
217231 --config ai-provider="anthropic" \
218232 --config ai-model="claude-sonnet-3-5" \
219233 --config ai-api-key="test-key" \
220- --config telegram-bot-token="123456:TEST"
234+ --config telegram-bot-token="123456:TEST" \
235+ --config control-ui-allowed-origins="http://192.168.1.50:18789"
221236
222237 - name : Wait for deployment
223238 run : |
@@ -234,13 +249,202 @@ jobs:
234249 echo "✗ Channel configuration missing"
235250 exit 1
236251 fi
252+
253+ origins=$(jq -r '.gateway.controlUi.allowedOrigins[0]' config.json)
254+ echo "allowedOrigins[0]: $origins"
255+ if [ "$origins" = "http://192.168.1.50:18789" ]; then
256+ echo "✓ control-ui-allowed-origins written correctly"
257+ else
258+ echo "✗ control-ui-allowed-origins mismatch (got: $origins)"
259+ exit 1
260+ fi
237261
238262 - name : Cleanup
239263 if : always()
240264 run : |
241265 juju destroy-model test-channels -y --force --no-wait || true
242266 juju destroy-controller test-controller -y --destroy-all-models --force --no-wait || true
243267
268+ test-config-preservation :
269+ name : Test Config Preservation
270+ runs-on : ubuntu-24.04
271+ needs : build
272+ steps :
273+ - name : Checkout code
274+ uses : actions/checkout@v6
275+
276+ - name : Download charm artifact
277+ uses : actions/download-artifact@v7
278+ with :
279+ name : openclaw-charm
280+
281+ - name : Set up LXD
282+ uses : canonical/setup-lxd@main
283+ with :
284+ channel : latest/stable
285+
286+ - name : Install Juju
287+ run : |
288+ sudo snap install juju --channel=3/stable
289+ sudo snap install juju-wait --classic
290+
291+ - name : Bootstrap Juju
292+ run : |
293+ lxc network set lxdbr0 ipv6.address none
294+ juju bootstrap localhost test-controller
295+
296+ - name : Create test model
297+ run : |
298+ juju add-model test-config-preservation
299+
300+ - name : Deploy charm
301+ run : |
302+ CHARM_FILE=$(ls openclaw_*.charm | head -1)
303+ juju deploy ./$CHARM_FILE \
304+ --config ai-provider="anthropic" \
305+ --config ai-model="claude-sonnet-3-5" \
306+ --config ai-api-key="test-key" \
307+ --config control-ui-allowed-origins="http://10.0.0.1:18789,http://10.0.0.2:18789"
308+
309+ - name : Wait for deployment
310+ run : |
311+ juju-wait -v -m test-config-preservation -t 900
312+
313+ - name : Verify control-ui-allowed-origins written to openclaw.json
314+ run : |
315+ config=$(juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json')
316+ origins=$(echo "$config" | jq -r '.gateway.controlUi.allowedOrigins | length')
317+ echo "allowedOrigins count: $origins"
318+ if [ "$origins" = "2" ]; then
319+ echo "✓ gateway.controlUi.allowedOrigins contains 2 entries"
320+ else
321+ echo "✗ Expected 2 entries, got: $origins"
322+ echo "$config" | jq '.gateway.controlUi'
323+ exit 1
324+ fi
325+ origin0=$(echo "$config" | jq -r '.gateway.controlUi.allowedOrigins[0]')
326+ origin1=$(echo "$config" | jq -r '.gateway.controlUi.allowedOrigins[1]')
327+ echo "Origin 0: $origin0"
328+ echo "Origin 1: $origin1"
329+ if [ "$origin0" = "http://10.0.0.1:18789" ] && [ "$origin1" = "http://10.0.0.2:18789" ]; then
330+ echo "✓ Origins match expected values"
331+ else
332+ echo "✗ Origins mismatch"
333+ exit 1
334+ fi
335+
336+ - name : Record gateway token before config change
337+ run : |
338+ TOKEN=$(juju ssh openclaw/0 'jq -r .gateway.auth.token /home/ubuntu/.openclaw/openclaw.json')
339+ echo "token_before=$TOKEN" >> "$GITHUB_ENV"
340+ echo "Gateway token recorded: $TOKEN"
341+
342+ - name : Inject user-managed field into openclaw.json
343+ run : |
344+ juju ssh openclaw/0 'jq '\''.user_custom_field = "preserve-me-12345"'\'' \
345+ /home/ubuntu/.openclaw/openclaw.json > /tmp/oc.tmp && \
346+ mv /tmp/oc.tmp /home/ubuntu/.openclaw/openclaw.json'
347+ echo "✓ Injected user_custom_field into openclaw.json"
348+
349+ - name : Trigger config-changed via juju config update
350+ run : |
351+ juju config openclaw log-level=debug
352+ sleep 30
353+ juju config openclaw log-level=info
354+ sleep 30
355+
356+ - name : Verify user field and gateway token survive config-changed
357+ run : |
358+ config=$(juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json')
359+
360+ custom=$(echo "$config" | jq -r '.user_custom_field')
361+ echo "user_custom_field after config-changed: $custom"
362+ if [ "$custom" = "preserve-me-12345" ]; then
363+ echo "✓ User-managed field preserved across config-changed"
364+ else
365+ echo "✗ User-managed field was lost (got: $custom)"
366+ exit 1
367+ fi
368+
369+ token_after=$(echo "$config" | jq -r '.gateway.auth.token')
370+ echo "Gateway token after config-changed: $token_after"
371+ if [ "$token_after" = "${{ env.token_before }}" ]; then
372+ echo "✓ Gateway token preserved across config-changed"
373+ else
374+ echo "✗ Gateway token changed (before: ${{ env.token_before }}, after: $token_after)"
375+ exit 1
376+ fi
377+
378+ - name : Clear control-ui-allowed-origins and verify key removed
379+ run : |
380+ juju config openclaw control-ui-allowed-origins=""
381+ sleep 30
382+ config=$(juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json')
383+ origins=$(echo "$config" | jq '.gateway.controlUi.allowedOrigins')
384+ echo "allowedOrigins after clearing: $origins"
385+ if [ "$origins" = "null" ]; then
386+ echo "✓ gateway.controlUi.allowedOrigins removed when config is empty"
387+ else
388+ echo "✗ gateway.controlUi.allowedOrigins still present: $origins"
389+ exit 1
390+ fi
391+
392+ - name : Restart container and verify persistence
393+ run : |
394+ unit_machine=$(juju status openclaw --format=json | jq -r '.applications.openclaw.units | to_entries[0].value["machine"]')
395+ container_name=$(juju status --format=json | jq -r --arg m "$unit_machine" '.machines[$m]["instance-id"]')
396+ echo "Restarting container: $container_name"
397+ lxc restart "$container_name"
398+
399+ sleep 45
400+ timeout 120 bash -c '
401+ while true; do
402+ s=$(juju status openclaw --format=json 2>/dev/null | jq -r ".applications.openclaw.units | to_entries[0].value[\"workload-status\"].current" 2>/dev/null || echo "unknown")
403+ echo "Status: $s"
404+ [ "$s" = "active" ] && break
405+ sleep 5
406+ done
407+ '
408+ sleep 10
409+
410+ config=$(juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json')
411+
412+ token_restart=$(echo "$config" | jq -r '.gateway.auth.token')
413+ echo "Gateway token after restart: $token_restart"
414+ if [ "$token_restart" = "${{ env.token_before }}" ]; then
415+ echo "✓ Gateway token preserved across container restart"
416+ else
417+ echo "✗ Gateway token changed after restart"
418+ exit 1
419+ fi
420+
421+ custom_restart=$(echo "$config" | jq -r '.user_custom_field')
422+ echo "user_custom_field after restart: $custom_restart"
423+ if [ "$custom_restart" = "preserve-me-12345" ]; then
424+ echo "✓ User-managed field preserved across container restart"
425+ else
426+ echo "✗ User-managed field lost after restart (got: $custom_restart)"
427+ exit 1
428+ fi
429+
430+ - name : Collect logs on failure
431+ if : failure()
432+ run : |
433+ echo "=== Juju Status ==="
434+ juju status --format=yaml
435+
436+ echo "=== Debug Log ==="
437+ juju debug-log --replay --no-tail --limit 500
438+
439+ echo "=== OpenClaw Config ==="
440+ juju ssh openclaw/0 'cat /home/ubuntu/.openclaw/openclaw.json' || true
441+
442+ - name : Cleanup
443+ if : always()
444+ run : |
445+ juju destroy-model test-config-preservation -y --force --no-wait || true
446+ juju destroy-controller test-controller -y --destroy-all-models --force --no-wait || true
447+
244448 test-upgrade :
245449 name : Test Charm Upgrade
246450 runs-on : ubuntu-24.04
0 commit comments