-
Notifications
You must be signed in to change notification settings - Fork 8
feat(redirect): migrate f3-redirect into the monorepo as apps/redirect #311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
pstaylor-patrick
wants to merge
4
commits into
dev
Choose a base branch
from
feat/redirect-app
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
a848edc
feat(redirect): migrate f3-redirect into the monorepo as apps/redirect
pstaylor-patrick 48a1327
fix(redirect): declare web env vars in turbo.json + lazy DB client
pstaylor-patrick 53e56a2
fix(redirect): address CodeRabbit review findings
pstaylor-patrick 4fa7f62
fix(redirect): surface PUT publish failures like POST
pstaylor-patrick File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| name: Deploy Redirect Server | ||
|
|
||
| # Redirect tier (Go `redirectd`): build the image, push to Artifact Registry, | ||
| # and roll the GCE VM so it pulls and runs the new image on boot. | ||
| # | ||
| # Deploy model: this app has a SINGLE production environment. Pushing to `dev` | ||
| # (the monorepo's integration/default branch) IS the prod deploy — there is no | ||
| # separate staging for redirect. Path-filtered so only changes that affect the | ||
| # redirect binary/container trigger a roll (not web-only or docs changes). | ||
| # | ||
| # ⚠️ SANDBOX (v1): targets Patrick's PERSONAL, self-funded GCP project | ||
| # `f3-redirects`. Long-term this pivots to an F3 Nation org-owned/funded project | ||
| # (provisioned by Tackle); the WIF provider, deployer SA, and project below are | ||
| # personal-sandbox identifiers that change at that cutover. | ||
| # | ||
| # Auth is keyless via Workload Identity Federation — no long-lived SA keys. | ||
|
|
||
| on: | ||
| push: | ||
| branches: [dev] | ||
| paths: | ||
| - "apps/redirect/server/**" | ||
| - "apps/redirect/shared/**" | ||
| - ".github/workflows/deploy-redirect-server.yml" | ||
| workflow_dispatch: | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| concurrency: | ||
| group: deploy-redirect-server | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
|
|
||
| env: | ||
| PROJECT: f3-redirects | ||
| REGION: us-central1 | ||
| ZONE: us-central1-a | ||
| REPO: redirect | ||
| INSTANCE: redirect-vm | ||
| WIF_PROVIDER: projects/355149658273/locations/global/workloadIdentityPools/github-pool/providers/github | ||
| DEPLOYER_SA: redirect-deployer@f3-redirects.iam.gserviceaccount.com | ||
|
|
||
| jobs: | ||
| deploy: | ||
| runs-on: ubuntu-latest | ||
| # Production deploys come only from dev. workflow_dispatch can target any | ||
| # ref, so guard the job to block a manual deploy of unmerged code to prod. | ||
| if: github.ref == 'refs/heads/dev' | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - id: auth | ||
| uses: google-github-actions/auth@v2 | ||
| with: | ||
| workload_identity_provider: ${{ env.WIF_PROVIDER }} | ||
| service_account: ${{ env.DEPLOYER_SA }} | ||
|
|
||
| - uses: google-github-actions/setup-gcloud@v2 | ||
|
pstaylor-patrick marked this conversation as resolved.
|
||
|
|
||
| - name: Configure Docker for Artifact Registry | ||
| run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev --quiet | ||
|
|
||
| - name: Build & push image | ||
| run: | | ||
| IMAGE="${REGION}-docker.pkg.dev/${PROJECT}/${REPO}/redirectd" | ||
| # --provenance=false: emit a plain single-arch manifest. The buildx | ||
| # default OCI index (with an attestation manifest) is not reliably | ||
| # pullable by the Container-Optimized OS docker on the VM. | ||
| docker build --provenance=false --sbom=false \ | ||
| --file apps/redirect/server/Dockerfile \ | ||
| -t "${IMAGE}:${GITHUB_SHA}" -t "${IMAGE}:latest" \ | ||
| apps/redirect/server | ||
| docker push "${IMAGE}:${GITHUB_SHA}" | ||
| docker push "${IMAGE}:latest" | ||
|
|
||
| - name: Roll the VM (re-runs startup script, pulls :latest) | ||
| run: | | ||
| gcloud compute instances reset "${INSTANCE}" --zone "${ZONE}" --project "${PROJECT}" | ||
| echo "Reset ${INSTANCE}; it will pull the new image on boot." | ||
|
pstaylor-patrick marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| name: Deploy Redirect Web | ||
|
|
||
| # Self-serve admin web (Next.js, `f3-redirect-web`): build the turbo-pruned | ||
| # container and deploy to Cloud Run. The Go redirect tier reverse-proxies the | ||
| # admin hostname to this service. | ||
| # | ||
| # Deploy model: SINGLE production environment. Pushing to `dev` (the monorepo's | ||
| # integration/default branch) IS the prod deploy — no separate staging for | ||
| # redirect. Path-filtered to web changes. | ||
| # | ||
| # ⚠️ SANDBOX (v1): targets Patrick's PERSONAL, self-funded GCP project | ||
| # `f3-redirects`. Long-term pivots to an F3 Nation org-owned/funded project | ||
| # (provisioned by Tackle), and the interim Cloud SQL database is replaced by an | ||
| # app-specific schema + service principal in the F3PROD data warehouse (the | ||
| # Codex/PaxVault pattern). Neon Postgres is off the table. | ||
| # | ||
| # Keyless auth via Workload Identity Federation. | ||
|
|
||
| on: | ||
| push: | ||
| branches: [dev] | ||
| paths: | ||
| - "apps/redirect/web/**" | ||
| - ".github/workflows/deploy-redirect-web.yml" | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: deploy-redirect-web | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
|
|
||
| env: | ||
| PROJECT: f3-redirects | ||
| REGION: us-central1 | ||
| AR_REPO: redirect | ||
| # NOTE: the Artifact Registry image and the Cloud Run service are both named | ||
| # `f3redirect-web` (no hyphen) — matching the existing deployed resources so | ||
| # this workflow updates them in place. (The pnpm package is `f3-redirect-web`; | ||
| # the turbo --filter below uses that package name.) | ||
| IMAGE_NAME: f3redirect-web | ||
| SERVICE_NAME: f3redirect-web | ||
| WIF_PROVIDER: projects/355149658273/locations/global/workloadIdentityPools/github-pool/providers/github | ||
| DEPLOYER_SA: redirect-deployer@f3-redirects.iam.gserviceaccount.com | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| # Production deploys come only from dev. workflow_dispatch can target any | ||
| # ref, so guard the entry job (deploy needs: build) to block a manual | ||
| # deploy of unmerged code to prod. | ||
| if: github.ref == 'refs/heads/dev' | ||
| outputs: | ||
| image: ${{ steps.meta.outputs.image }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: google-github-actions/auth@v2 | ||
| with: | ||
| workload_identity_provider: ${{ env.WIF_PROVIDER }} | ||
| service_account: ${{ env.DEPLOYER_SA }} | ||
|
|
||
| - uses: google-github-actions/setup-gcloud@v2 | ||
|
pstaylor-patrick marked this conversation as resolved.
|
||
|
|
||
| - name: Authorize Docker to Artifact Registry | ||
| run: gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev --quiet | ||
|
|
||
| - name: Resolve image reference (immutable by commit SHA) | ||
| id: meta | ||
| run: | | ||
| IMAGE="${REGION}-docker.pkg.dev/${PROJECT}/${AR_REPO}/${IMAGE_NAME}:${GITHUB_SHA}" | ||
| echo "image=${IMAGE}" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Build and push Docker image | ||
| run: | | ||
| docker build \ | ||
| --file apps/redirect/web/Dockerfile \ | ||
| --tag "${{ steps.meta.outputs.image }}" \ | ||
| . | ||
|
pstaylor-patrick marked this conversation as resolved.
|
||
| docker push "${{ steps.meta.outputs.image }}" | ||
|
|
||
| deploy: | ||
| needs: build | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| steps: | ||
| - uses: google-github-actions/auth@v2 | ||
| with: | ||
| workload_identity_provider: ${{ env.WIF_PROVIDER }} | ||
| service_account: ${{ env.DEPLOYER_SA }} | ||
|
|
||
| - name: Deploy to Cloud Run | ||
| uses: google-github-actions/deploy-cloudrun@v2 | ||
| with: | ||
| service: ${{ env.SERVICE_NAME }} | ||
| image: ${{ needs.build.outputs.image }} | ||
| region: ${{ env.REGION }} | ||
| project_id: ${{ env.PROJECT }} | ||
| # Env vars (DATABASE_URL, BETTER_AUTH_SECRET, GCS bucket, etc.) are | ||
| # set on the Cloud Run service out-of-band, not in this workflow. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| name: redirect Terraform Drift | ||
|
|
||
| # Enforces the zero-drift rule for the f3-redirects GCP project: the committed | ||
| # Terraform under apps/redirect/infra/terraform is the source of truth. This | ||
| # workflow runs `terraform plan` and fails if live infrastructure has drifted | ||
| # from the code — daily (catch console drift) and on every PR that touches the | ||
| # Terraform (catch drift before merge). | ||
| # | ||
| # Auth is keyless via the f3-redirects project's own Workload Identity pool | ||
| # (github-pool/github), whose attribute condition was widened in ci.tf to allow | ||
| # this repo (F3-Nation/f3-nation). It impersonates the read-only | ||
| # github-actions-ci@f3-redirects service account. | ||
| # | ||
| # NOTE: f3-redirects is currently Patrick's personal v1 sandbox. When the | ||
| # redirect app pivots to an F3 Nation org-owned project, update the project id, | ||
| # WIF provider, service account, and the TF_VAR_* values below. | ||
|
|
||
| on: | ||
| schedule: | ||
| - cron: "17 13 * * *" # daily ~7-8am Central (offset from region-pages' :00) | ||
| pull_request: | ||
| paths: | ||
| - "apps/redirect/infra/terraform/**" | ||
| - ".github/workflows/redirect-terraform-drift.yml" | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: redirect-tf-drift | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: | ||
| contents: read | ||
| id-token: write | ||
| pull-requests: write | ||
|
|
||
| jobs: | ||
| drift: | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: apps/redirect/infra/terraform | ||
| env: | ||
| # Non-secret values that must match the live VM startup-script metadata so | ||
| # `plan` reports no spurious drift. project has no variable default | ||
| # (removed to prevent unparameterized applies from targeting a live | ||
| # environment), so it is supplied explicitly here. image_tag, region, | ||
| # zone, machine_type, config_object, and cert_prefix defaults match live. | ||
| TF_VAR_project: "f3-redirects" | ||
| TF_VAR_acme_email: "patrick@pstaylor.net" | ||
| TF_VAR_admin_host: "admin.f3regions.com" | ||
| TF_VAR_admin_upstream: "https://f3redirect-web-355149658273.us-central1.run.app" | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Authenticate to GCP (Workload Identity Federation) | ||
| uses: google-github-actions/auth@v2 | ||
| with: | ||
| workload_identity_provider: "projects/355149658273/locations/global/workloadIdentityPools/github-pool/providers/github" | ||
| service_account: "github-actions-ci@f3-redirects.iam.gserviceaccount.com" | ||
|
|
||
| - name: Set up Cloud SDK | ||
| uses: google-github-actions/setup-gcloud@v2 | ||
|
|
||
| - name: Set up Terraform | ||
| uses: hashicorp/setup-terraform@v3 | ||
| with: | ||
| terraform_version: "1.15.3" | ||
|
|
||
| - name: Terraform init | ||
| run: terraform init -input=false | ||
|
|
||
| - name: Terraform plan (detect drift) | ||
| id: plan | ||
| run: | | ||
| set +e | ||
| terraform plan -input=false -lock=false -no-color -detailed-exitcode | ||
| code=$? | ||
| set -e | ||
| echo "exitcode=$code" >> "$GITHUB_OUTPUT" | ||
| # 0 = in sync, 2 = drift detected, 1 = error | ||
| if [ "$code" = "1" ]; then | ||
| echo "::error::terraform plan failed." | ||
| exit 1 | ||
| elif [ "$code" = "2" ]; then | ||
| echo "::error::Drift detected — f3-redirects infrastructure no longer matches Terraform. Reconcile by applying the committed config or importing the change." | ||
| exit 2 | ||
| else | ||
| echo "No drift — f3-redirects matches Terraform." | ||
| fi | ||
|
|
||
| - name: Comment drift result on PR | ||
| # On fork PRs GitHub forces GITHUB_TOKEN to read-only, so createComment | ||
| # would 403 and fail the job. Only comment for same-repo PRs. | ||
| if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && always() | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const code = '${{ steps.plan.outputs.exitcode }}'; | ||
| const body = code === '0' | ||
| ? '✅ **redirect Terraform drift check:** in sync — live infrastructure matches the committed config.' | ||
| : code === '2' | ||
| ? '⚠️ **redirect Terraform drift check:** drift detected — `terraform plan` shows changes. Reconcile before merge (apply the committed config or import the out-of-band change).' | ||
| : '❌ **redirect Terraform drift check:** `terraform plan` errored. See the job logs.'; | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.issue.number, | ||
| body, | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| node-linker=hoisted |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.