mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-19 07:54:10 +00:00
Stabilize managed hot-dev startup
This commit is contained in:
parent
7d6b447c59
commit
fbcb77d635
8 changed files with 138 additions and 52 deletions
|
|
@ -63,46 +63,47 @@ server-side update execution surfaces.
|
|||
38. `scripts/hot-dev-bg.sh`
|
||||
39. `scripts/hot-dev.sh`
|
||||
40. `scripts/lib/hot-dev-runtime.sh`
|
||||
40. `scripts/install-container-agent.sh`
|
||||
41. `install.sh`
|
||||
42. `scripts/install.ps1`
|
||||
43. `scripts/install.sh`
|
||||
44. `scripts/install-mcp.sh`
|
||||
45. `scripts/install-mcp.ps1`
|
||||
46. `cmd/pulse-mcp/`
|
||||
47. `scripts/pulse-auto-update.sh`
|
||||
48. `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`
|
||||
49. `scripts/release_control/record_rc_to_ga_rehearsal.py`
|
||||
50. `scripts/release_control/release_promotion_policy_support.py`
|
||||
51. `scripts/release_control/resolve_release_promotion.py`
|
||||
52. `scripts/release_ldflags.sh`
|
||||
53. `scripts/run_cloud_public_signup_smoke.sh`
|
||||
54. `scripts/run_demo_public_browser_smoke.sh`
|
||||
55. `scripts/demo_public_browser_smoke.cjs`
|
||||
56. `scripts/run_hosted_staging_smoke.sh`
|
||||
57. `scripts/trigger-release-dry-run.sh`
|
||||
58. `scripts/trigger-release.sh`
|
||||
59. `scripts/toggle-mock.sh`
|
||||
60. `deploy/helm/pulse/`
|
||||
61. `tests/integration/playwright.config.ts`
|
||||
62. `tests/integration/QUICK_START.md`
|
||||
63. `tests/integration/README.md`
|
||||
64. `tests/integration/scripts/bootstrap-hosted-mobile-onboarding.mjs`
|
||||
65. `tests/integration/scripts/hosted-mobile-token-runtime.mjs`
|
||||
66. `tests/integration/scripts/hosted-tenant-approval-store.mjs`
|
||||
67. `tests/integration/scripts/hosted-tenant-runtime.mjs`
|
||||
68. `tests/integration/scripts/hosted-tenant-runtime-restart.mjs`
|
||||
69. `tests/integration/scripts/managed-dev-runtime.mjs`
|
||||
70. `tests/integration/scripts/relay-mobile-token-helper.go`
|
||||
71. `tests/integration/tests/helpers.ts`
|
||||
72. `tests/integration/tests/runtime-defaults.ts`
|
||||
73. `docker-compose.yml`
|
||||
74. `scripts/install-docker.sh`
|
||||
75. `scripts/validate-published-release.sh`
|
||||
76. `scripts/validate-release.sh`
|
||||
77. `scripts/release_asset_common.sh`
|
||||
78. `scripts/backfill-release-assets.sh`
|
||||
79. `.github/workflows/backfill-release-assets.yml`
|
||||
41. `scripts/lib/hot-dev-auth.sh`
|
||||
42. `scripts/install-container-agent.sh`
|
||||
43. `install.sh`
|
||||
44. `scripts/install.ps1`
|
||||
45. `scripts/install.sh`
|
||||
46. `scripts/install-mcp.sh`
|
||||
47. `scripts/install-mcp.ps1`
|
||||
48. `cmd/pulse-mcp/`
|
||||
49. `scripts/pulse-auto-update.sh`
|
||||
50. `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`
|
||||
51. `scripts/release_control/record_rc_to_ga_rehearsal.py`
|
||||
52. `scripts/release_control/release_promotion_policy_support.py`
|
||||
53. `scripts/release_control/resolve_release_promotion.py`
|
||||
54. `scripts/release_ldflags.sh`
|
||||
55. `scripts/run_cloud_public_signup_smoke.sh`
|
||||
56. `scripts/run_demo_public_browser_smoke.sh`
|
||||
57. `scripts/demo_public_browser_smoke.cjs`
|
||||
58. `scripts/run_hosted_staging_smoke.sh`
|
||||
59. `scripts/trigger-release-dry-run.sh`
|
||||
60. `scripts/trigger-release.sh`
|
||||
61. `scripts/toggle-mock.sh`
|
||||
62. `deploy/helm/pulse/`
|
||||
63. `tests/integration/playwright.config.ts`
|
||||
64. `tests/integration/QUICK_START.md`
|
||||
65. `tests/integration/README.md`
|
||||
66. `tests/integration/scripts/bootstrap-hosted-mobile-onboarding.mjs`
|
||||
67. `tests/integration/scripts/hosted-mobile-token-runtime.mjs`
|
||||
68. `tests/integration/scripts/hosted-tenant-approval-store.mjs`
|
||||
69. `tests/integration/scripts/hosted-tenant-runtime.mjs`
|
||||
70. `tests/integration/scripts/hosted-tenant-runtime-restart.mjs`
|
||||
71. `tests/integration/scripts/managed-dev-runtime.mjs`
|
||||
72. `tests/integration/scripts/relay-mobile-token-helper.go`
|
||||
73. `tests/integration/tests/helpers.ts`
|
||||
74. `tests/integration/tests/runtime-defaults.ts`
|
||||
75. `docker-compose.yml`
|
||||
76. `scripts/install-docker.sh`
|
||||
77. `scripts/validate-published-release.sh`
|
||||
78. `scripts/validate-release.sh`
|
||||
79. `scripts/release_asset_common.sh`
|
||||
80. `scripts/backfill-release-assets.sh`
|
||||
81. `.github/workflows/backfill-release-assets.yml`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -170,7 +171,7 @@ server-side update execution surfaces.
|
|||
enrollment runtime tokens while keeping deploy binding metadata limited to
|
||||
deploy facts such as cluster, job, target, source agent, and expected node.
|
||||
4. Add or change server update transport through `internal/api/updates.go` and `frontend-modern/src/api/updates.ts`
|
||||
5. Add or change local dev-runtime orchestration, managed ownership, browser-runtime proof wiring, frontend/backend coherence diagnostics, canonical developer entry wrappers, dependency manifest floors, frontend build chunking, or dev-runtime helper control surfaces through `scripts/hot-dev.sh`, `scripts/hot-dev-bg.sh`, `scripts/lib/hot-dev-runtime.sh`, `scripts/dev-deploy-agent.sh`, `Makefile`, `package.json`, `package-lock.json`, `frontend-modern/package.json`, `frontend-modern/package-lock.json`, `frontend-modern/vite.config.ts`, `go.mod`, `go.sum`, `scripts/dev-check.sh`, `scripts/toggle-mock.sh`, `scripts/clean-mock-alerts.sh`, `scripts/dev-launchd-setup.sh`, `scripts/dev-launchd-wrapper.sh`, `scripts/run_demo_public_browser_smoke.sh`, `scripts/demo_public_browser_smoke.cjs`, `scripts/com.pulse.hot-dev.plist.template`, `tests/integration/scripts/managed-dev-runtime.mjs`, `tests/integration/playwright.config.ts`, `tests/integration/tests/helpers.ts`, `tests/integration/tests/runtime-defaults.ts`, `tests/integration/README.md`, and `tests/integration/QUICK_START.md`
|
||||
5. Add or change local dev-runtime orchestration, managed ownership, browser-runtime proof wiring, frontend/backend coherence diagnostics, canonical developer entry wrappers, deterministic dev auth seeding, dependency manifest floors, frontend build chunking, or dev-runtime helper control surfaces through `scripts/hot-dev.sh`, `scripts/hot-dev-bg.sh`, `scripts/lib/hot-dev-runtime.sh`, `scripts/lib/hot-dev-auth.sh`, `scripts/dev-deploy-agent.sh`, `Makefile`, `package.json`, `package-lock.json`, `frontend-modern/package.json`, `frontend-modern/package-lock.json`, `frontend-modern/vite.config.ts`, `go.mod`, `go.sum`, `scripts/dev-check.sh`, `scripts/toggle-mock.sh`, `scripts/clean-mock-alerts.sh`, `scripts/dev-launchd-setup.sh`, `scripts/dev-launchd-wrapper.sh`, `scripts/run_demo_public_browser_smoke.sh`, `scripts/demo_public_browser_smoke.cjs`, `scripts/com.pulse.hot-dev.plist.template`, `tests/integration/scripts/managed-dev-runtime.mjs`, `tests/integration/playwright.config.ts`, `tests/integration/tests/helpers.ts`, `tests/integration/tests/runtime-defaults.ts`, `tests/integration/README.md`, and `tests/integration/QUICK_START.md`
|
||||
6. Add or change governed release-promotion workflow inputs, operator-facing promotion metadata, the canonical version file, prerelease feedback intake prompts, artifact publication lineage enforcement, release note or changelog packet composition, or stable-promotion rehearsal summaries through `.github/workflows/create-release.yml`, `.github/workflows/helm-pages.yml`, `.github/workflows/publish-docker.yml`, `.github/workflows/publish-helm-chart.yml`, `.github/workflows/promote-floating-tags.yml`, `.github/workflows/release-dry-run.yml`, `.github/workflows/update-demo-server.yml`, `.github/ISSUE_TEMPLATE/v6_rc_feedback.yml`, `docs/RELEASE_NOTES.md`, `docs/releases/`, `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`, `docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md`, `docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md`, `scripts/check-workflow-dispatch-inputs.py`, `scripts/release_control/render_release_body.py`, `scripts/release_control/record_rc_to_ga_rehearsal.py`, `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`, `scripts/release_control/release_promotion_policy_support.py`, `scripts/trigger-release.sh`, and `scripts/trigger-release-dry-run.sh`
|
||||
That release-promotion boundary also owns prerelease note packet lineage:
|
||||
shipped RC notes must remain historically accurate, the top-level
|
||||
|
|
|
|||
|
|
@ -2716,6 +2716,7 @@
|
|||
"scripts/install-docker.sh",
|
||||
"scripts/install.ps1",
|
||||
"scripts/install.sh",
|
||||
"scripts/lib/hot-dev-auth.sh",
|
||||
"scripts/lib/hot-dev-runtime.sh",
|
||||
"scripts/pulse-auto-update.sh",
|
||||
"scripts/release_asset_common.sh",
|
||||
|
|
@ -2970,11 +2971,12 @@
|
|||
"scripts/dev-deploy-agent.sh",
|
||||
"scripts/dev-launchd-setup.sh",
|
||||
"scripts/dev-launchd-wrapper.sh",
|
||||
"scripts/hot-dev-bg.sh",
|
||||
"scripts/hot-dev.sh",
|
||||
"scripts/lib/hot-dev-runtime.sh",
|
||||
"scripts/toggle-mock.sh",
|
||||
"tests/integration/playwright.config.ts",
|
||||
"scripts/hot-dev-bg.sh",
|
||||
"scripts/hot-dev.sh",
|
||||
"scripts/lib/hot-dev-auth.sh",
|
||||
"scripts/lib/hot-dev-runtime.sh",
|
||||
"scripts/toggle-mock.sh",
|
||||
"tests/integration/playwright.config.ts",
|
||||
"tests/integration/QUICK_START.md",
|
||||
"tests/integration/README.md",
|
||||
"tests/integration/scripts/managed-dev-runtime.mjs",
|
||||
|
|
@ -2984,10 +2986,11 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"scripts/release_control/ssh_host_key_policy_test.py",
|
||||
"scripts/tests/test-hot-dev-bg.sh",
|
||||
"scripts/tests/test-hot-dev-runtime.sh",
|
||||
"scripts/tests/test-toggle-mock.sh",
|
||||
"scripts/release_control/ssh_host_key_policy_test.py",
|
||||
"scripts/tests/test-hot-dev-auth.sh",
|
||||
"scripts/tests/test-hot-dev-bg.sh",
|
||||
"scripts/tests/test-hot-dev-runtime.sh",
|
||||
"scripts/tests/test-toggle-mock.sh",
|
||||
"tests/integration/tests/16-dev-runtime-recovery.spec.ts"
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@ start_hot_dev_child() {
|
|||
PULSE_DEV_API_PORT="${PULSE_DEV_API_PORT}" \
|
||||
PULSE_DEV_API_URL="${PULSE_DEV_API_URL}" \
|
||||
PULSE_DEV_WS_URL="${PULSE_DEV_WS_URL}" \
|
||||
HOT_DEV_SKIP_NPM_CLEANUP=true \
|
||||
ROOT_DIR="${ROOT_DIR}" \
|
||||
python3 - <<'PY' &
|
||||
import os
|
||||
|
|
|
|||
|
|
@ -258,6 +258,47 @@ kill_port() {
|
|||
lsof -i :"${port}" 2>/dev/null | awk 'NR>1 {print $2}' | xargs -r kill -9 2>/dev/null || true
|
||||
}
|
||||
|
||||
process_parent_id() {
|
||||
local pid=$1
|
||||
ps -o ppid= -p "${pid}" 2>/dev/null | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
is_current_shell_descendant_of() {
|
||||
local target_pid=$1
|
||||
local current_pid=$$
|
||||
local parent_pid
|
||||
|
||||
[[ -n "${target_pid}" ]] || return 1
|
||||
|
||||
while [[ -n "${current_pid}" && "${current_pid}" != "1" ]]; do
|
||||
parent_pid="$(process_parent_id "${current_pid}")"
|
||||
[[ -n "${parent_pid}" && "${parent_pid}" != "${current_pid}" ]] || break
|
||||
if [[ "${parent_pid}" == "${target_pid}" ]]; then
|
||||
return 0
|
||||
fi
|
||||
current_pid="${parent_pid}"
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
kill_stale_npm_dev_wrappers() {
|
||||
local pid
|
||||
|
||||
if [[ "${HOT_DEV_SKIP_NPM_CLEANUP:-false}" == "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
while IFS= read -r pid; do
|
||||
[[ -n "${pid}" ]] || continue
|
||||
[[ "${pid}" != "$$" ]] || continue
|
||||
if is_current_shell_descendant_of "${pid}"; then
|
||||
continue
|
||||
fi
|
||||
kill "${pid}" 2>/dev/null || true
|
||||
done < <(pgrep -f "npm run dev" 2>/dev/null || true)
|
||||
}
|
||||
|
||||
log_info "Cleaning up existing processes..."
|
||||
|
||||
# OS-Specific Cleanup
|
||||
|
|
@ -271,7 +312,7 @@ fi
|
|||
pkill -f "backend-watch.sh" 2>/dev/null || true
|
||||
# Only kill vite/npm processes that look like ours (simple check)
|
||||
pkill -f "vite" 2>/dev/null || true
|
||||
pkill -f "npm run dev" 2>/dev/null || true
|
||||
kill_stale_npm_dev_wrappers
|
||||
|
||||
pkill -x "pulse" 2>/dev/null || true
|
||||
sleep 1
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ hot_dev_sync_auth_env_file() {
|
|||
printf "PULSE_AUTH_PASS='%s'\n" "$(hot_dev_single_quote "${auth_pass}")"
|
||||
|
||||
if [[ -f "${runtime_env}" ]]; then
|
||||
grep -v -E '^(# Managed by hot-dev\.sh for deterministic dev auth|PULSE_AUTH_USER=|PULSE_AUTH_PASS=)' "${runtime_env}"
|
||||
grep -v -E '^(# Managed by hot-dev\.sh for deterministic dev auth|PULSE_AUTH_USER=|PULSE_AUTH_PASS=)' "${runtime_env}" || true
|
||||
fi
|
||||
} > "${tmp_file}"
|
||||
|
||||
|
|
|
|||
|
|
@ -104,10 +104,39 @@ EOF
|
|||
assert_contains "sync preserves mock settings" "${output}" "PULSE_MOCK_MODE=false"
|
||||
}
|
||||
|
||||
test_sync_auth_env_file_handles_managed_only_env_under_errexit() {
|
||||
local state_dir runtime_env output
|
||||
state_dir="$(make_temp_dir)"
|
||||
runtime_env="${state_dir}/.env"
|
||||
|
||||
cat > "${runtime_env}" <<'EOF'
|
||||
# Managed by hot-dev.sh for deterministic dev auth
|
||||
PULSE_AUTH_USER='admin'
|
||||
PULSE_AUTH_PASS='stale-pass'
|
||||
EOF
|
||||
|
||||
output="$(
|
||||
HOT_DEV_AUTH_LIB="${HOT_DEV_AUTH_LIB}" \
|
||||
RUNTIME_ENV_PATH="${runtime_env}" \
|
||||
bash -lc '
|
||||
set -euo pipefail
|
||||
source "${HOT_DEV_AUTH_LIB}"
|
||||
hot_dev_sync_auth_env_file "${RUNTIME_ENV_PATH}" "admin" "${HOT_DEV_DEFAULT_AUTH_HASH}"
|
||||
printf "survived=yes\n"
|
||||
cat "${RUNTIME_ENV_PATH}"
|
||||
'
|
||||
)"
|
||||
|
||||
assert_contains "managed-only env does not trip errexit" "${output}" "survived=yes"
|
||||
assert_contains "managed-only sync keeps auth user" "${output}" "PULSE_AUTH_USER='admin'"
|
||||
assert_contains "managed-only sync rewrites auth password hash" "${output}" "PULSE_AUTH_PASS='${HOT_DEV_DEFAULT_AUTH_HASH}'"
|
||||
}
|
||||
|
||||
source "${HOT_DEV_AUTH_LIB}"
|
||||
test_default_auth_contract
|
||||
test_custom_auth_banner_contract
|
||||
test_sync_auth_env_file_preserves_non_auth_settings
|
||||
test_sync_auth_env_file_handles_managed_only_env_under_errexit
|
||||
|
||||
if (( failures > 0 )); then
|
||||
echo "FAIL: ${failures} hot-dev auth assertions failed" >&2
|
||||
|
|
|
|||
|
|
@ -720,6 +720,7 @@ test_hot_dev_bg_script_advertises_managed_entrypoint() {
|
|||
assert_contains "hot-dev-bg routes log guidance to managed wrapper" "${output}" "Check logs with: npm run dev:logs"
|
||||
assert_contains "hot-dev-bg routes verify guidance to managed wrapper" "${output}" "Rerun with: npm run dev:verify"
|
||||
assert_contains "hot-dev-bg routes launchd supervision guidance to managed wrapper" "${output}" "Rerun with: npm run dev"
|
||||
assert_contains "hot-dev-bg managed child skips npm wrapper cleanup" "${output}" "HOT_DEV_SKIP_NPM_CLEANUP=true"
|
||||
}
|
||||
|
||||
test_hot_dev_bg_usage_prefers_managed_wrappers() {
|
||||
|
|
|
|||
|
|
@ -127,11 +127,21 @@ test_hot_dev_keeps_backend_launch_errors_in_debug_log() {
|
|||
assert_contains "backend LOG_FILE follows debug log override" "${output}" "LOG_FILE=\"\${BACKEND_DEBUG_LOG}\""
|
||||
}
|
||||
|
||||
test_hot_dev_avoids_self_killing_npm_wrapper() {
|
||||
local output
|
||||
output="$(sed -n '1,330p' "${HOT_DEV}")"
|
||||
|
||||
assert_contains "hot-dev routes npm cleanup through a guarded helper" "${output}" "kill_stale_npm_dev_wrappers"
|
||||
assert_contains "hot-dev supports managed skip for npm cleanup" "${output}" "HOT_DEV_SKIP_NPM_CLEANUP"
|
||||
assert_not_contains "hot-dev no longer broad-kills npm dev wrappers" "${output}" 'pkill -f "npm run dev"'
|
||||
}
|
||||
|
||||
source "${HOT_DEV_RUNTIME_LIB}"
|
||||
test_pulse_process_count_handles_zero_matches_under_pipefail
|
||||
test_pulse_process_count_counts_matching_processes
|
||||
test_hot_dev_uses_resilient_backend_process_count
|
||||
test_hot_dev_keeps_backend_launch_errors_in_debug_log
|
||||
test_hot_dev_avoids_self_killing_npm_wrapper
|
||||
|
||||
if (( failures > 0 )); then
|
||||
echo "FAIL: ${failures} hot-dev runtime assertions failed" >&2
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue