fix(deploy): stop pinning API_ORIGIN, and probe one origin not the list

Two leftovers from making the browser derive the API origin. The stack env still
injected API_ORIGIN from a repo secret, which pinned the origin again on every
deploy and would have re-broken an https front door with mixed active content.
Drop it from both env_data blocks; the secret stays, now purely as the URL the
verify step probes.

That verify step was also about to break on its own: WEB_ORIGIN is a
comma-separated CORS list now, and `curl "$WEB_ORIGIN/version"` on a list
retries thirty times and fails a deploy whose app is perfectly healthy. Probe
the first entry, so keep the runner-reachable origin first in the secret.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 13:14:04 -07:00
co-authored by Claude Opus 5
parent 3b02c6944f
commit cf40cd22ef
2 changed files with 27 additions and 2 deletions
+14 -1
View File
@@ -281,13 +281,20 @@ jobs:
standalone: true standalone: true
pull: true pull: true
endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID_GALACTUS }} endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID_GALACTUS }}
# NOTE: the block below is parsed as JSON — no comments inside it.
#
# API_ORIGIN is deliberately absent. The browser derives the API origin
# from the page it loaded (apps/web/src/lib/api.ts), so the deployment
# survives the box moving between the tailnet, the office LAN and a
# demo domain. Setting it here would pin it again and re-break an https
# front door with mixed active content. APP_API_ORIGIN_GALACTUS lives
# on only as the URL the verify step probes.
env_data: | env_data: |
{ {
"APP_TAG": "${{ github.event.inputs.tag }}", "APP_TAG": "${{ github.event.inputs.tag }}",
"API_PORT": "3001", "API_PORT": "3001",
"WEB_PORT": "3000", "WEB_PORT": "3000",
"S3_BUCKET": "jorgecuadros-documents", "S3_BUCKET": "jorgecuadros-documents",
"API_ORIGIN": "${{ secrets.APP_API_ORIGIN_GALACTUS }}",
"WEB_ORIGIN": "${{ secrets.APP_WEB_ORIGIN_GALACTUS }}", "WEB_ORIGIN": "${{ secrets.APP_WEB_ORIGIN_GALACTUS }}",
"S3_ENDPOINT": "${{ secrets.APP_S3_ENDPOINT_GALACTUS }}", "S3_ENDPOINT": "${{ secrets.APP_S3_ENDPOINT_GALACTUS }}",
"DATABASE_URL": "${{ secrets.DATABASE_URL_GALACTUS }}", "DATABASE_URL": "${{ secrets.DATABASE_URL_GALACTUS }}",
@@ -322,6 +329,12 @@ jobs:
run: | run: |
set -e set -e
apk add --no-cache curl >/dev/null apk add --no-cache curl >/dev/null
# These secrets are CORS origin LISTS as far as the app is concerned
# (WEB_ORIGIN is comma-separated so one deployment can be reached by
# LAN IP, tailnet name and demo domain at once). A list is not a URL,
# so probe the FIRST entry — keep the runner-reachable origin first.
API_ORIGIN=${API_ORIGIN%%,*}
WEB_ORIGIN=${WEB_ORIGIN%%,*}
fetch_version() { fetch_version() {
for i in $(seq 1 30); do for i in $(seq 1 30); do
if curl -fsS "$1/version" > "$2"; then return 0; fi if curl -fsS "$1/version" > "$2"; then return 0; fi
+13 -1
View File
@@ -253,13 +253,19 @@ jobs:
type: file type: file
pull: true pull: true
endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID }} endpoint: ${{ secrets.PORTAINER_ENDPOINT_ID }}
# NOTE: the block below is parsed as JSON — no comments inside it.
#
# API_ORIGIN is deliberately absent. The browser derives the API origin
# from the page it loaded (apps/web/src/lib/api.ts), so the deployment
# survives the host moving. Setting it here would pin it again and
# re-break an https front door with mixed active content. APP_API_ORIGIN
# lives on only as the URL the verify step probes.
env_data: | env_data: |
{ {
"APP_TAG": "${{ github.event.inputs.tag }}", "APP_TAG": "${{ github.event.inputs.tag }}",
"API_PORT": "3001", "API_PORT": "3001",
"WEB_PORT": "3000", "WEB_PORT": "3000",
"S3_BUCKET": "jorgecuadros-documents", "S3_BUCKET": "jorgecuadros-documents",
"API_ORIGIN": "${{ secrets.APP_API_ORIGIN }}",
"WEB_ORIGIN": "${{ secrets.APP_WEB_ORIGIN }}", "WEB_ORIGIN": "${{ secrets.APP_WEB_ORIGIN }}",
"S3_ENDPOINT": "${{ secrets.APP_S3_ENDPOINT }}", "S3_ENDPOINT": "${{ secrets.APP_S3_ENDPOINT }}",
"DATABASE_URL": "${{ secrets.DATABASE_URL }}", "DATABASE_URL": "${{ secrets.DATABASE_URL }}",
@@ -288,6 +294,12 @@ jobs:
run: | run: |
set -e set -e
apk add --no-cache curl >/dev/null apk add --no-cache curl >/dev/null
# These secrets are CORS origin LISTS as far as the app is concerned
# (WEB_ORIGIN is comma-separated so one deployment can be reached under
# several origins at once). A list is not a URL, so probe the FIRST
# entry — keep the runner-reachable origin first.
API_ORIGIN=${API_ORIGIN%%,*}
WEB_ORIGIN=${WEB_ORIGIN%%,*}
fetch_version() { fetch_version() {
for i in $(seq 1 30); do for i in $(seq 1 30); do
if curl -fsS "$1/version" > "$2"; then return 0; fi if curl -fsS "$1/version" > "$2"; then return 0; fi