Skip to content

feat(ci): point iOS PR preview at author's freighter-config sandbox (#859) - #947

Open
piyalbasu wants to merge 4 commits into
mainfrom
feat/859-ios-preview-freighter-config
Open

feat(ci): point iOS PR preview at author's freighter-config sandbox (#859)#947
piyalbasu wants to merge 4 commits into
mainfrom
feat/859-ios-preview-freighter-config

Conversation

@piyalbasu

@piyalbasu piyalbasu commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

TL;DR

Makes the iOS Simulator PR-preview build point at the PR author's own per-engineer sandbox backend instead of shared staging, by looking the author up in the freighter-config map at build time. If the author has no sandbox entry (or the map can't be read), the build falls back to public staging and says so — the preview is never broken, just clearly labeled. The release notes and sticky PR comment now state which backend the preview targets.

Part of the Fullstack PR Preview Flow, Phase 2. Part of #859 (iOS scope). Android has no PR-preview workflow yet, so this PR does not auto-close #859 — Android is tracked as a separate follow-up.

Implementation details (for agents)

What changed — all in .github/workflows/prPreviewIos.yml:

  • New Fetch freighter-config step, placed immediately after checkout and before any PR-controlled code runs (scripts/display-ios-environment, scripts/gh-ios-env, yarn lifecycle hooks). It clones the private stellar/freighter-config repo over SSH using a read-only deploy key (secrets.FREIGHTER_CONFIG_DEPLOY_KEY), writes config.json to $RUNNER_TEMP, and tears the key down in-step (mode-600 tempfile + trap … EXIT). It never fails the build — an unreachable/malformed config just sets config_available=false.
  • New Resolve backend URLs step maps pull_request.user.login → sandbox v1/v2 and writes the six FREIGHTER_BACKEND_V{1,2}_{PROD,STG,DEV}_URL values to $GITHUB_ENV (all three slots set to the same value — mirrors the existing staging trick so runtime network-switching can't escape the target). Those six keys were removed from the job-level env: to avoid a job-env:-vs-$GITHUB_ENV precedence ambiguity; they now live exclusively in this step. EnvFileCreator (lib/env_file_creator.rb) reads them from the process env when it materializes .env.
  • Fallback + labeling: no entry → staging; config unreachable → staging + preview-degraded label. gh label create … || true (create-if-missing), then add/remove so a fixed re-run self-corrects. Added issues: write to the build job solely for creating the label definition (add/remove on the PR is covered by pull-requests: write).
  • Release notes + sticky comment now interpolate BACKEND_DESC/BACKEND_NOTE to state the target (sandbox (piyalbasu) / staging — no sandbox configured / staging — freighter-config unreachable).

Resolve logic:

# release notes + sticky comment.
- name: Resolve backend URLs (sandbox vs staging)
id: resolve_backend
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
CONFIG_AVAILABLE: ${{ steps.fetch_config.outputs.config_available }}
# Phase 1 staging fallbacks (the values previously hardcoded in job env).
STAGING_V1_URL: ${{ vars.FREIGHTER_BACKEND_V1_PROD_URL }}
STAGING_V2_URL: ${{ vars.FREIGHTER_BACKEND_V2_STG_URL }}
run: |
set -euo pipefail
CONFIG_OUT="${RUNNER_TEMP}/freighter-config.json"
V1_URL=""; V2_URL=""; TARGET=""; DESC=""; NOTE=""; DEGRADED="false"
if [ "${CONFIG_AVAILABLE}" = "true" ]; then
V1_URL=$(jq -r --arg u "$PR_AUTHOR" '.engineers[$u].v1 // empty' "$CONFIG_OUT")
V2_URL=$(jq -r --arg u "$PR_AUTHOR" '.engineers[$u].v2 // empty' "$CONFIG_OUT")
if [ -n "$V1_URL" ] && [ -n "$V2_URL" ]; then
TARGET="sandbox"
DESC="sandbox (${PR_AUTHOR})"
NOTE="This preview points at a per-engineer **sandbox** backend — you must have sshuttle connected to reach it (see the \`/preview\` skill)."
else
TARGET="staging"
DESC="staging — no sandbox configured for @${PR_AUTHOR}"
NOTE="This preview points at the public **staging** backend — no VPN needed."
fi
else
TARGET="staging-degraded"; DEGRADED="true"
DESC="staging — freighter-config unreachable (preview degraded)"
NOTE="This preview points at the public **staging** backend — no VPN needed."
fi
if [ "$TARGET" != "sandbox" ]; then
V1_URL="$STAGING_V1_URL"
V2_URL="$STAGING_V2_URL"
fi
if [ -z "$V1_URL" ] || [ -z "$V2_URL" ]; then
echo "::error::Resolved backend URLs are empty (V1='$V1_URL' V2='$V2_URL'). Check repo vars FREIGHTER_BACKEND_V1_PROD_URL / FREIGHTER_BACKEND_V2_STG_URL."
exit 1
fi
# Bake into ALL three PROD/STG/DEV slots so runtime network-switching
# cannot escape the intended backend (mirrors the Phase 1 trick).
{
echo "FREIGHTER_BACKEND_V1_PROD_URL=${V1_URL}"
echo "FREIGHTER_BACKEND_V1_STG_URL=${V1_URL}"
echo "FREIGHTER_BACKEND_V1_DEV_URL=${V1_URL}"
echo "FREIGHTER_BACKEND_V2_PROD_URL=${V2_URL}"
echo "FREIGHTER_BACKEND_V2_STG_URL=${V2_URL}"
echo "FREIGHTER_BACKEND_V2_DEV_URL=${V2_URL}"
echo "BACKEND_TARGET=${TARGET}"
echo "BACKEND_DESC=${DESC}"
echo "BACKEND_NOTE=${NOTE}"
} >> "$GITHUB_ENV"
echo "Backend target: ${TARGET} — ${DESC}"
# preview-degraded label: create-if-missing, then add on degrade /
# remove otherwise so a fixed re-run self-corrects. Label plumbing
# must never fail the build.
gh label create preview-degraded --repo "$GH_REPO" \
--color B60205 \
--description "PR preview fell back to staging because freighter-config was unreachable" \
2>/dev/null || true
if [ "$DEGRADED" = "true" ]; then
gh pr edit "$PR_NUMBER" --repo "$GH_REPO" --add-label preview-degraded || true
else

Security: unchanged posture — pull_request-only + fork-guard, deploy key is read-only + scoped to freighter-config + torn down before PR code runs. Only new outbound is the SSH clone of one private repo. No backend is contacted (CI can't reach sandbox URLs behind the VPN; it only bakes the string).

Verification: YAML validated (yaml.safe_load) pre- and post-prettier; survived the repo pre-commit hook (lint-staged + jest). Full end-to-end verification (author piyalbasu → sandbox URLs baked into .env) requires the two prerequisite PRs below to land first.

Depends on (land in order):

  1. stellar/terraform — registers the read-only deploy key on freighter-config.
  2. stellar/freighter-config — adds config.json with the piyalbasu entry.
  3. This PR.
    (The FREIGHTER_CONFIG_DEPLOY_KEY secret is already set on this repo.)

Follow-ups / out of scope: Android (prPreviewAndroid.yml doesn't exist yet) and the extension prPreview.yml migration off secrets.INDEXER_* — both reuse this same config map + deploy-key pattern.

…859)

Fetch the PR author's per-engineer sandbox URLs from the private
stellar/freighter-config repo (via a read-only deploy key) and bake them
into the iOS Simulator preview build, replacing the hardcoded staging URLs.

- New "Fetch freighter-config" step runs right after checkout, before any
  PR-controlled code, and tears the deploy key down in-step.
- New "Resolve backend URLs" step maps github login -> sandbox v1/v2 and
  writes them to $GITHUB_ENV (all three PROD/STG/DEV slots). The six backend
  URL keys are removed from job env to avoid $GITHUB_ENV precedence ambiguity.
- Fallbacks: no config entry -> staging; freighter-config unreachable ->
  staging + `preview-degraded` label. Both explained in the sticky comment.
- Release notes + sticky comment now state which backend the build targets.
- Adds issues:write for create-if-missing of the preview-degraded label.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 22, 2026 20:49
@github-actions github-actions Bot added the preview-degraded PR preview fell back to staging because freighter-config was unreachable label Jul 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Routes iOS PR previews to each author’s sandbox backend, with staging fallback and backend labeling.

Changes:

  • Fetches and resolves sandbox URLs from freighter-config.
  • Adds degraded-state labeling and fallback routing.
  • Reports the selected backend in releases and PR comments.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/prPreviewIos.yml Outdated
Comment thread .github/workflows/prPreviewIos.yml Outdated
Comment thread .github/workflows/prPreviewIos.yml Outdated
Comment thread .github/workflows/prPreviewIos.yml
Comment thread .github/workflows/prPreviewIos.yml
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

iOS Simulator preview build is ready: https://github.com/stellar/freighter-mobile/releases/tag/untagged-ad7ef61925322c84ba40
Backend: V1 prod + V2 staging — freighter-config unreachable (preview degraded). SDF collaborators only — install instructions in the release description.

Verifies sandbox URL resolution before stellar/freighter-config#1 merges.
REVERT to plain `git clone --depth 1` (reads main) before merging #947.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot removed the preview-degraded PR preview fell back to staging because freighter-config was unreachable label Jul 23, 2026
…tch)

- Revert the temporary --branch feat/seed-config-schema-and-piyalbasu pin;
  the fetch now clones freighter-config's default branch (production behavior).
- Replace StrictHostKeyChecking=accept-new (TOFU, no MITM protection on an
  ephemeral runner) with GitHub's published host keys fetched over
  TLS-authenticated HTTPS (api.github.com/meta) + StrictHostKeyChecking=yes;
  degrade to staging if keys can't be obtained. Parity with stellar/freighter#2917.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the preview-degraded PR preview fell back to staging because freighter-config was unreachable label Jul 27, 2026
- Validate freighter-config/config.json parses (jq empty) before marking it
  available, and make the resolve-step jq tolerant, so a malformed config
  degrades to staging instead of aborting the build under set -e.
- Correct the fallback backend labels: V1 production + V2 staging, not
  "staging" wholesale (matches the routing actually baked in).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

preview-degraded PR preview fell back to staging because freighter-config was unreachable

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[PR Preview] Integrate iOS workflow with freighter-config (sandbox URLs)

2 participants