Skip to content

feat: generate proper wildcard domains#3987

Merged
chronark merged 5 commits intomainfrom
09-17-feat_generate_proper_wildcard_domains
Sep 18, 2025
Merged

feat: generate proper wildcard domains#3987
chronark merged 5 commits intomainfrom
09-17-feat_generate_proper_wildcard_domains

Conversation

@chronark
Copy link
Collaborator

@chronark chronark commented Sep 17, 2025

What does this PR do?

Improves deployment domain generation by implementing a more structured approach to domain naming. This PR:

  • Adds a new buildDomains function that generates consistent domain patterns:
    • <projectslug>-git-<gitsha>-<workspaceslug>.domain
    • <projectslug>-git-<branchname>-<workspaceslug>.domain
    • <projectslug>-<environmentslug>-<workspaceslug>.domain

Example CLI output

Domains
  https://api-git-62a6995-asdasd.unkey.local
  https://api-git-main-asdasd.unkey.local
  https://api-preview-asdasd.unkey.local
  • Sets domain type to wildcard instead of custom

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Deploy a project and verify that the domains are generated correctly with the new pattern
  • Verify that domains are properly assigned to deployments
  • Check that branch names with special characters are properly sluggified

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Summary by CodeRabbit

  • New Features

    • Deploys now auto-generate multiple accessible domains using workspace/project/environment and optional git-SHA and branch-slug variants, based on a configurable default domain.
  • Chores

    • Added default domain configuration for the controller (UNKEY_DEFAULT_DOMAIN).
    • Switched MinIO/S3 image to the legacy repository tag across manifests.
    • Temporarily disabled automatic OpenAPI scraping during deploys.

@changeset-bot
Copy link

changeset-bot bot commented Sep 17, 2025

⚠️ No Changeset found

Latest commit: 9612523

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Sep 17, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Canceled Canceled Sep 18, 2025 11:18am
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
engineering Ignored Ignored Preview Sep 18, 2025 11:18am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

📝 Walkthrough

Walkthrough

Pre-fetches workspace, project, environment, and deployment in the deploy workflow; replaces Git-based hostname logic with a slug-based buildDomains utility and creates wildcard domain entries; disables OpenAPI scraping; adds FindEnvironmentById SQL and generated code; exposes UNKEY_DEFAULT_DOMAIN in the ctrl manifest; updates MinIO image references.

Changes

Cohort / File(s) Summary
Deployment workflow & domains
go/apps/ctrl/services/deployment/deploy_workflow.go, go/apps/ctrl/services/deployment/domains.go
Workflow now pre-fetches workspace/project/environment/deployment via Hydra steps; removed git import/usage; initialization logs added; replaced inlined Git-based domain logic with buildDomains(workspaceSlug, projectSlug, environmentSlug, gitSha, branch, apex) and creates wildcard domain entries; assigns metaldDeployment and logs VM IDs; OpenAPI scraping steps commented out; added sluggify and domain-builder utilities.
DB: environment lookup
go/pkg/db/queries/environment_find_by_id.sql, go/pkg/db/environment_find_by_id.sql_generated.go, go/pkg/db/querier_generated.go
Adds FindEnvironmentById SQL query, sqlc-generated Go file with FindEnvironmentByIdRow and FindEnvironmentById(ctx, db, id) method, and updates Querier interface to include FindEnvironmentById.
Ctrl manifest
go/k8s/manifests/ctrl.yaml
Adds environment variable UNKEY_DEFAULT_DOMAIN="unkey.local" to the ctrl container.
MinIO image updates
deployment/docker-compose.yaml, go/k8s/manifests/s3.yaml
Updates MinIO image references to use bitnamilegacy/minio:2025.7.23 (compose and k8s). No other spec changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Ctrl as ctrl (deploy workflow)
  participant DB as DB / Querier
  participant Metald as metald backend
  participant DNS as Domains store

  rect rgba(230,245,255,0.6)
  note over Ctrl: Initialize deploy workflow (metald_backend, UNKEY_DEFAULT_DOMAIN, is_running_docker)
  end

  User->>Ctrl: Trigger deploy
  Ctrl->>DB: Fetch Workspace by ID
  DB-->>Ctrl: Workspace (slug)
  Ctrl->>DB: Fetch Project by ID
  DB-->>Ctrl: Project (slug)
  Ctrl->>DB: FindEnvironmentById
  DB-->>Ctrl: Environment (slug)
  Ctrl->>DB: Fetch Deployment by ID
  DB-->>Ctrl: Deployment (git SHA, branch)

  rect rgba(240,255,230,0.6)
  note over Ctrl: Build domains via buildDomains(workspaceSlug, projectSlug, environmentSlug, gitSha, branch, defaultDomain)
  end

  Ctrl->>Metald: Create deployment
  Metald-->>Ctrl: Deployment (VM IDs)

  Ctrl->>DNS: Create domain entries (type: wildcard) for each built domain
  DNS-->>Ctrl: OK

  opt OpenAPI scraping
    note right of Ctrl: OpenAPI scraping steps commented out (disabled)
  end

  Ctrl-->>User: Deployment pending/created
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • imeyer
  • mcstepp
  • perkinsjr
  • MichaelUnkey
  • ogzhanolguncu

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description largely follows the repository template: it includes a clear summary, example output, a marked type of change, testing instructions, and a completed checklist. However, it omits the required "Fixes # (issue)" line and does not reference a tracking issue as the template requests. Because the template explicitly asks for an issue reference (or creation of one), this required piece is missing and prevents a full pass. Please add or link an issue to satisfy the repository's template requirement. Create or link a tracking issue and add a "Fixes #" line in the PR description, or explicitly state why no issue is needed; retain the existing testing steps and checklist. After updating the description with the issue reference, re-run the pre-merge checks. Once the issue reference is added the description will meet the template requirements.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat: generate proper wildcard domains" is concise and accurately reflects the primary change in this PR—introducing structured wildcard domain generation. It directly maps to the added buildDomains logic and the switch to wildcard domain type in the deployment workflow. The phrasing is clear and specific enough for a teammate scanning history to understand the main intent without extra detail.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 09-17-feat_generate_proper_wildcard_domains

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 936aebd and 9612523.

📒 Files selected for processing (1)
  • go/apps/ctrl/services/deployment/domains.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • go/apps/ctrl/services/deployment/domains.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Go API Local / Test

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@vercel vercel bot temporarily deployed to Preview – engineering September 17, 2025 20:02 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard September 17, 2025 20:02 Inactive
@chronark chronark marked this pull request as ready for review September 17, 2025 20:03
@github-actions
Copy link
Contributor

github-actions bot commented Sep 17, 2025

Thank you for following the naming conventions for pull request titles! 🙏

@vercel vercel bot temporarily deployed to Preview – dashboard September 17, 2025 20:10 Inactive
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
deployment/docker-compose.yaml (1)

167-176: Switch to bitnamilegacy image is fine; fix console port mapping to match env (3903).

MINIO_CONSOLE_PORT_NUMBER is 3903, but ports map 2903:2903. Console won’t be reachable as configured. Use 3903:3903 to stay consistent with prior learnings and k8s manifests.

Apply:

   s3:
     networks:
       - default
     container_name: s3
-    image: bitnamilegacy/minio:2025.7.23
+    image: bitnamilegacy/minio:2025.7.23
     ports:
       - 3902:3902
-      - 2903:2903
+      - 3903:3903
     environment:
       MINIO_ROOT_USER: minio_root_user
       MINIO_ROOT_PASSWORD: minio_root_password
       MINIO_API_PORT_NUMBER: 3902
       MINIO_CONSOLE_PORT_NUMBER: 3903
go/apps/ctrl/services/deployment/deploy_workflow.go (1)

201-206: Go compile bug: “for i := range 300” is invalid.

This won’t compile. Use a classic counter loop.

Apply:

- for i := range 300 {
+ for i := 0; i < 300; i++ {
🧹 Nitpick comments (7)
deployment/docker-compose.yaml (1)

167-167: Confirm “bitnamilegacy/minio” choice and pin by digest.

If “legacy” is intentional, pin to a digest to avoid supply‑chain drift and keep docker-compose and k8s images aligned exactly.

go/k8s/manifests/s3.yaml (1)

34-34: Confirm move to bitnamilegacy and consider digest pin.

The image change is consistent with docker-compose. Please confirm the move is intentional and pin to an image digest for reproducibility.

go/apps/ctrl/services/deployment/domains.go (2)

45-70: Slugging rules: preserve separators and normalize more safely.

Current sluggify drops characters like “/_.+” entirely, which can collapse distinct branch names. Prefer replacing non-alphanumerics with “-”, deduping “-”, and trimming both ends. Also consider capping to keep label <=63 in the caller.

Apply:

- var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9\s]`)
- var multipleSpacesRegex = regexp.MustCompile(`\s+`)
+ var nonAlphanumericRegex = regexp.MustCompile(`[^a-zA-Z0-9]+`)
+ var multipleHyphensRegex = regexp.MustCompile(`-+`)
@@
- // Remove all non-alphanumeric characters except spaces
- s = nonAlphanumericRegex.ReplaceAllString(s, "")
-
- // Replace multiple spaces with single space
- s = multipleSpacesRegex.ReplaceAllString(s, " ")
-
- // Replace spaces with hyphens
- s = strings.ReplaceAll(s, " ", "-")
+ // Replace any run of non-alphanumerics with a hyphen
+ s = nonAlphanumericRegex.ReplaceAllString(s, "-")
+ // Collapse multiple hyphens
+ s = multipleHyphensRegex.ReplaceAllString(s, "-")
+ // Trim hyphens
+ s = strings.Trim(s, "-")

16-16: Optional: normalize apex.

Consider trimming scheme/trailing dot to avoid accidental inputs like “https://unkey.local.”.

go/apps/ctrl/services/deployment/deploy_workflow.go (3)

97-120: Use read-only handle for reads (if available).

These steps only read; prefer w.db.RO() to leverage replicas and avoid write pool contention (you already use RO on partitionDB).

If RO exists:

- return db.Query.FindWorkspaceByID(stepCtx, w.db.RW(), req.WorkspaceID)
+ return db.Query.FindWorkspaceByID(stepCtx, w.db.RO(), req.WorkspaceID)

Repeat for project, environment, deployment.


277-284: LGTM: centralizing domain generation. Also guard empty defaultDomain.

If defaultDomain is empty, you’ll generate invalid FQDNs. Validate at workflow init and fail fast or set a sane default.

Apply (constructor):

  return &DeployWorkflow{
     db:                cfg.DB,
     partitionDB:       cfg.PartitionDB,
     logger:            cfg.Logger,
     deploymentBackend: deploymentBackend,
-    defaultDomain:     cfg.DefaultDomain,
+    defaultDomain:     cfg.DefaultDomain,
  }

And before use:

+ if w.defaultDomain == "" {
+   return fmt.Errorf("UNKEY_DEFAULT_DOMAIN is required")
+ }

321-331: Comment/code mismatch on “local” skipping.

isLocalHostname treats defaultDomain (e.g., unkey.local) as NOT local, so these domains get configs (desired). Update the comment to avoid confusion.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfe590b and 6865baa.

📒 Files selected for processing (8)
  • deployment/docker-compose.yaml (1 hunks)
  • go/apps/ctrl/services/deployment/deploy_workflow.go (6 hunks)
  • go/apps/ctrl/services/deployment/domains.go (1 hunks)
  • go/k8s/manifests/ctrl.yaml (1 hunks)
  • go/k8s/manifests/s3.yaml (1 hunks)
  • go/pkg/db/environment_find_by_id.sql_generated.go (1 hunks)
  • go/pkg/db/querier_generated.go (1 hunks)
  • go/pkg/db/queries/environment_find_by_id.sql (1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-08-08T14:55:11.981Z
Learnt from: imeyer
PR: unkeyed/unkey#3755
File: deployment/docker-compose.yaml:179-184
Timestamp: 2025-08-08T14:55:11.981Z
Learning: In deployment/docker-compose.yaml (development only), MinIO is configured with API on 3902 and console on 3903; ports should map 3902:3902 and 3903:3903 to match MINIO_API_PORT_NUMBER and MINIO_CONSOLE_PORT_NUMBER.

Applied to files:

  • go/k8s/manifests/s3.yaml
  • deployment/docker-compose.yaml
📚 Learning: 2025-07-15T14:59:30.212Z
Learnt from: chronark
PR: unkeyed/unkey#3560
File: go/deploy/metald/internal/database/repository.go:0-0
Timestamp: 2025-07-15T14:59:30.212Z
Learning: go/deploy/metald cannot currently import helpers from go/pkg/db because it is not yet part of the main Go module; avoid suggesting such imports until the modules are unified.

Applied to files:

  • go/apps/ctrl/services/deployment/deploy_workflow.go
📚 Learning: 2025-09-01T01:57:42.227Z
Learnt from: imeyer
PR: unkeyed/unkey#3899
File: go/proto/metald/v1/metald.proto:5-9
Timestamp: 2025-09-01T01:57:42.227Z
Learning: In the unkeyed/unkey repository, buf is configured to properly resolve metald proto imports like "metald/v1/vm.proto" without needing the full "go/proto/" prefix. The buf lint command `buf lint --path proto/metald` passes successfully with these relative import paths.

Applied to files:

  • go/apps/ctrl/services/deployment/deploy_workflow.go
🧬 Code graph analysis (3)
go/pkg/db/querier_generated.go (1)
go/pkg/db/environment_find_by_id.sql_generated.go (1)
  • FindEnvironmentByIdRow (19-25)
go/pkg/db/environment_find_by_id.sql_generated.go (1)
go/pkg/db/types/null_string.go (1)
  • NullString (10-10)
go/apps/ctrl/services/deployment/deploy_workflow.go (6)
go/pkg/otel/logging/interface.go (1)
  • Logger (11-116)
go/pkg/hydra/step.go (2)
  • Step (67-276)
  • StepVoid (302-310)
go/pkg/db/models_generated.go (2)
  • Workspace (770-788)
  • DomainsTypeWildcard (243-243)
go/pkg/db/project_find_by_id.sql_generated.go (1)
  • FindProjectByIdRow (28-38)
go/pkg/db/environment_find_by_id.sql_generated.go (1)
  • FindEnvironmentByIdRow (19-25)
go/pkg/db/deployment_find_by_id.sql_generated.go (1)
  • FindDeploymentByIdRow (36-53)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
🔇 Additional comments (8)
go/k8s/manifests/ctrl.yaml (1)

74-75: LGTM: default apex wired into ctrl.

Matches the new domain-generation flow; also set in docker-compose. No further action.

go/pkg/db/querier_generated.go (1)

192-197: LGTM: Querier extended with FindEnvironmentById.

Signature and docs align with the generated implementation and call sites.

go/pkg/db/queries/environment_find_by_id.sql (1)

1-4: LGTM: minimal query for environment lookups.

Fields match generated row type and usage.

go/pkg/db/environment_find_by_id.sql_generated.go (3)

13-17: LGTM: generated SQL constant matches query.


19-25: LGTM: row type matches selected columns.


32-43: LGTM: method scans in correct order.

go/apps/ctrl/services/deployment/deploy_workflow.go (2)

43-47: LGTM: startup log context helpful.


287-305: Confirm BulkQuery.InsertDomains performs upsert semantics.

Branch/env domains must move between deployments. Ensure the bulk path mirrors InsertDomain’s ON DUPLICATE KEY UPDATE behavior.

If not, switch to per‑row InsertDomain or add upsert logic to the bulk query.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu left a comment

Choose a reason for hiding this comment

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

Other than my slug comment and Flo's I think it looks great.

@vercel vercel bot temporarily deployed to Preview – dashboard September 18, 2025 11:18 Inactive
@chronark chronark merged commit 0c71d0e into main Sep 18, 2025
17 of 18 checks passed
@chronark chronark deleted the 09-17-feat_generate_proper_wildcard_domains branch September 18, 2025 11:23
@coderabbitai coderabbitai bot mentioned this pull request Sep 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants