Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 65 additions & 6 deletions .github/workflows/deploy-strategy-switch-console.yml
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,69 @@ jobs:
echo "STRATEGY_SWITCH_SYNC_TOKEN or RUNTIME_SETTINGS_GH_TOKEN is required to sync strategy profiles." >&2
exit 2
fi

expected_count="$(python3 - <<'PY'
import json
from pathlib import Path

profiles = json.loads(Path("web/strategy-switch-console/strategy-profiles.example.json").read_text())
if not isinstance(profiles, list):
raise SystemExit("strategy-profiles.example.json must contain a JSON list")
print(len(profiles))
PY
)"
sync_body="$(mktemp)"
live_body="$(mktemp)"
cleanup() { rm -f "$sync_body" "$live_body"; }
trap cleanup EXIT

for attempt in 1 2 3 4 5 6; do
curl --fail --show-error --silent \
--request POST \
--header "Authorization: Bearer ${STRATEGY_SWITCH_SYNC_TOKEN}" \
--header "Content-Type: application/json" \
--header "Cache-Control: no-cache" \
--data '{"source":"github-actions"}' \
--output "$sync_body" \
"${STRATEGY_SWITCH_CONSOLE_URL%/}/api/internal/sync-strategy-profiles"
python3 -m json.tool "$sync_body"

actual_count="$(python3 - "$sync_body" <<'PY'
import json
import sys

payload = json.load(open(sys.argv[1], encoding="utf-8"))
print(payload.get("strategy_profiles_count", ""))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail when the sync endpoint skips KV

If the deployed Worker lacks the STRATEGY_SWITCH_CONFIG binding, syncStrategyProfilesResponse returns HTTP 200 with ok: true, strategy_profiles_sync.skipped: true, and the bundled count (worker.js:1077-1088). Because this script extracts only strategy_profiles_count, it reports Strategy profile KV sync verified even though no KV write occurred and the public endpoint can still pass by serving the bundled fallback.

Useful? React with 👍 / 👎.

PY
)"
if [ "$actual_count" = "$expected_count" ]; then
break
Comment on lines +168 to +169

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify profile content, not just count

When a push changes strategy-profiles.example.json without changing the number of entries, an old Worker during deployment propagation can still return the same strategy_profiles_count, so this exits the retry loop before the newly deployed Worker has written its bundled profiles. In worker.js:1092-1120 the sync writes DEFAULT_STRATEGY_PROFILES but this workflow only observes the count, and the later live check also compares only length, so the job can succeed while KV remains on stale profile metadata.

Useful? React with 👍 / 👎.

fi
if [ "$attempt" = "6" ]; then
echo "Synced strategy profile count ${actual_count:-unknown}; expected $expected_count." >&2
exit 2
fi
echo "Synced strategy profile count ${actual_count:-unknown}; expected $expected_count. Waiting for deployed Worker propagation..." >&2
sleep 5
done

curl --fail --show-error --silent \
--request POST \
--header "Authorization: Bearer ${STRATEGY_SWITCH_SYNC_TOKEN}" \
--header "Content-Type: application/json" \
--data '{"source":"github-actions"}' \
"${STRATEGY_SWITCH_CONSOLE_URL%/}/api/internal/sync-strategy-profiles" \
| python3 -m json.tool
--header "Cache-Control: no-cache" \
--output "$live_body" \
"${STRATEGY_SWITCH_CONSOLE_URL%/}/api/strategy-profiles"
live_count="$(python3 - "$live_body" <<'PY'
import json
import sys

payload = json.load(open(sys.argv[1], encoding="utf-8"))
profiles = payload.get("strategyProfiles")
if not isinstance(profiles, list):
raise SystemExit("/api/strategy-profiles did not return strategyProfiles list")
print(len(profiles))
PY
)"
if [ "$live_count" != "$expected_count" ]; then
echo "Live strategy profile count $live_count; expected $expected_count." >&2
exit 2
Comment on lines +194 to +196

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retry the live KV read before failing

When the sync write succeeds but this immediate public read is served from an edge location with a cached strategy_profiles KV value, Cloudflare KV reads can remain eventually consistent for 60s+, so failing on the first live_count mismatch can mark a valid deploy as failed. The sync POST is retried for propagation, but the live /api/strategy-profiles verification is not, which makes this new release gate flaky after real profile-count changes.

Useful? React with 👍 / 👎.

fi
echo "Strategy profile KV sync verified with $live_count profiles."
3 changes: 3 additions & 0 deletions python/tests/test_runtime_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ def test_strategy_switch_console_deploy_workflow_syncs_bundled_profiles(self):
self.assertIn("environment: runtime-strategy-switch", workflow)
self.assertIn("npx wrangler@4.106.0 deploy --config wrangler.toml", workflow)
self.assertIn("/api/internal/sync-strategy-profiles", workflow)
self.assertIn("expected_count=", workflow)
self.assertIn("Waiting for deployed Worker propagation", workflow)
self.assertIn("Strategy profile KV sync verified", workflow)
self.assertNotIn("continue-on-error: true", workflow)
self.assertIn("STRATEGY_SWITCH_CONSOLE_URL", workflow)
self.assertIn("STRATEGY_SWITCH_SYNC_TOKEN", workflow)
Expand Down
Loading