Skip to content

Comments

Lio/cleanup tenants#1732

Merged
lionello merged 8 commits intomainfrom
lio/cleanup-tenants
Dec 23, 2025
Merged

Lio/cleanup tenants#1732
lionello merged 8 commits intomainfrom
lio/cleanup-tenants

Conversation

@lionello
Copy link
Member

@lionello lionello commented Dec 22, 2025

Description

Instead of #1729. Resolving several places where the "name or ID" was used for the subdomain, instead of the "tenant name" from Fabric.

  • need to make sure that Terms-of-service is still signed after login
  • only MCP deploy tool does login; other tools do not

Linked Issues

Checklist

  • I have performed a self-review of my code
  • I have added appropriate tests
  • I have updated the Defang CLI docs and/or README to reflect my changes, if necessary

Summary by CodeRabbit

  • New Features

    • Added DEFANG_WORKSPACE, TZ and XDG_STATE_HOME environment variables.
    • Improved tenant/workspace handling across the CLI and connection flows.
  • Bug Fixes

    • Debug output now goes to the error stream (stderr) for clearer logging.
  • Chores

    • Removed deprecated DEFANG_ORG environment variable.
    • Multiple CLI and client interfaces updated (breaking changes); tests and mocks adjusted accordingly.
    • BYOC provider public surface and DNS behavior simplified.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 22, 2025

Warning

Rate limit exceeded

@lionello has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 14 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between e4d7ba2 and 8c9d238.

📒 Files selected for processing (3)
  • src/cmd/cli/command/commands_test.go
  • src/pkg/cli/client/byoc/aws/byoc.go
  • src/pkg/cli/whoami.go

Walkthrough

Refactors tenant/workspace typing and propagation across CLI, client, and auth layers: replaces DEFANG_ORG with DEFANG_WORKSPACE, introduces TenantLabel and TenantNameOrID flag behavior, changes Connect/ConnectWithTenant and NewGrpcClient signatures, removes tenant-selection helper and context from SetupCommands, and updates login/auth flows to be tenant-aware.

Changes

Cohort / File(s) Summary
Docs
README.md, pkgs/npm/README.md, src/README.md
Replace DEFANG_ORG with DEFANG_WORKSPACE; add TZ and XDG_STATE_HOME to npm README; minor formatting tweaks.
Tenant types & flags
src/pkg/types/tenant.go
Add TenantLabel type; add Type() and Set() on TenantNameOrID for flag parsing.
CLI core & commands
src/cmd/cli/command/commands.go, src/cmd/cli/command/commands_test.go, src/cmd/cli/command/globals.go, src/cmd/cli/command/globals_test.go, src/cmd/cli/command/workspace.go, src/cmd/cli/main.go, src/cmd/gendocs/main.go
Remove getTenantSelection() indirection; change SetupCommands(ctx, ...)SetupCommands(...); GlobalConfig.Tenant now types.TenantNameOrID; flag binding changed to use Var; call sites use global.Tenant directly.
Connection & client plumbing
src/pkg/cli/connect.go, src/pkg/cli/connect_test.go, src/pkg/cli/grpc.go, src/pkg/cli/client/client.go, src/pkg/cli/client/mock.go, src/pkg/cli/client/playground.go
Replace Connect API: new Connect(cluster, requestedTenant) and ConnectWithTenant(ctx, addr, requestedTenant); NewGrpcClient signature changed; GrpcClient tenant fields reworked (requestedTenant + Tenant label); rename GetController→GetFabricClient and SetClient→SetFabricClient; update call sites to use Fabric client.
BYOC providers & base
src/pkg/cli/client/byoc/baseclient.go, src/pkg/cli/client/byoc/*
Constructors now accept types.TenantLabel; move/add ServicePublicDNS to base client; provider-specific ServicePublicDNS removed; ENV mapping uses TenantLabel.
Authentication & login flow
src/pkg/auth/interceptor.go, src/pkg/login/login.go, src/pkg/login/agree_tos.go, src/pkg/login/login_test.go
NewAuthInterceptor uses types.TenantNameOrID; remove FabricClient parameter from AuthService.login and InteractiveLogin/InteractiveLoginMCP; login/reconnect flows now use tenant-aware ConnectWithTenant and update trackers.
Agent tools / interfaces
src/pkg/agent/tools/interfaces.go, src/pkg/agent/tools/default_tool_cli.go, src/pkg/agent/tools/deploy.go, src/pkg/agent/tools/*_test.go
Remove fabric *client.GrpcClient param from InteractiveLoginMCP in interface and implementations; add post-login reconnect using Connect; update tests/mocks.
CLI tests
src/pkg/cli/*_test.go
Update many tests to call Connect(url, types.TenantUnset) or ConnectWithTenant(..., types.TenantUnset); import types; adjust expectations for requested vs. server-validated tenant.
Misc / small
src/pkg/term/colorizer.go, src/pkg/term/colorizer_test.go, src/pkg/clouds/aws/route53_test.go, pkgs/npm/README.md
Debug output now goes to stderr; tests adjusted to assert stderr; replace GetDelegationSet calls in tests with GetDelegationSetByZone; small doc changes.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User as CLI User
    participant CLI as Commands
    participant Auth as Auth Service
    participant Conn as Connect Manager
    participant Client as GrpcClient
    participant Server as Defang Server

    Note over User,CLI: User runs a command that may require auth
    User->>CLI: invoke command
    CLI->>CLI: ensure global.Tenant set

    alt Not authenticated
        CLI->>Auth: InteractiveLogin(cluster)
        Auth->>Auth: OAuth/device flow → token
        Auth-->>CLI: token
        CLI->>Conn: ConnectWithTenant(ctx, cluster, global.Tenant)
    else Authenticated or direct connect
        CLI->>Conn: ConnectWithTenant(ctx, cluster, global.Tenant)
    end

    Conn->>Client: NewGrpcClient(host, token, requestedTenant)
    Client->>Server: WhoAmI (Tenant header = requestedTenant if set)
    Server-->>Client: server-validated tenant
    Client->>Conn: update Client.Tenant = server tenant
    Conn-->>CLI: return validated client
    CLI->>Client: Execute gRPC request
    Client->>Server: gRPC call
    Server-->>Client: response
    Client-->>CLI: result
    CLI-->>User: output
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • jordanstephens
  • KevyVo

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title "Lio/cleanup tenants" is vague and uses a branch prefix (Lio/) that provides minimal context about the actual changes. Revise to a more descriptive title like "Use TenantLabel for subdomains and clean up tenant resolution" or "Refactor tenant handling to use Fabric-provided tenant name" to clearly convey the main changes.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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.

@lionello lionello requested a review from raphaeltm December 22, 2025 13:37
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: 1

Caution

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

⚠️ Outside diff range comments (1)
src/pkg/cli/client/byoc/gcp/byoc.go (1)

362-364: Fix DEFANG_ORG to use b.TenantName for consistency across providers

GCP hardcodes DEFANG_ORG to "defang" while AWS and DO both use string(b.TenantName). This inconsistency may cause unexpected behavior when tenant-specific logic is required. The TODO comment in GCP byoc.go (line 362) acknowledges this needs clarification.

🧹 Nitpick comments (3)
src/pkg/cli/client/byoc/baseclient.go (1)

301-306: Consider adding validation for empty projectName.

The method does not validate projectName. If it's empty, the result would be malformed (e.g., name..tenant.defang.app). Other methods in this file use pkg.Ensure(projectName != "", ...) for validation.

🔎 Proposed validation
 func (b ByocBaseClient) ServicePublicDNS(name string, projectName string) string {
+	pkg.Ensure(projectName != "", "ProjectName not set")
 	if b.PulumiStack != "" && b.PulumiStack != "beta" {
 		projectName = projectName + "-" + b.PulumiStack
 	}
 	return dns.SafeLabel(name) + "." + dns.SafeLabel(projectName) + "." + dns.SafeLabel(string(b.TenantName)) + ".defang.app"
 }
src/pkg/login/login.go (2)

57-59: Consider removing or documenting commented-out code.

These lines are commented out without explanation. If they're being removed as part of the refactor (since the new login page shows ToS), either remove them entirely or add a comment explaining why they're preserved.

🔎 Suggested cleanup
-	// tenant := cli.TenantFromToken(token) // show the tenant implied by the freshly issued token
-	// host := client.NormalizeHost(cluster)
-	// term.Info("Successfully logged in to", host, "("+tenant.String()+" tenant)")
-

74-76: Consider removing commented-out ToS code.

The comment on line 73 explains this is no longer needed. Consider removing the dead code entirely.

🔎 Suggested cleanup
 	// The new login page shows the ToS so a successful login implies the user agreed
-	// if err := NonInteractiveAgreeToS(ctx, fabric); err != nil {
-	// 	term.Debug("unable to agree to terms:", err) // not fatal
-	// }
 	return nil
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44ec70f and ce2d73c.

📒 Files selected for processing (39)
  • README.md
  • pkgs/npm/README.md
  • src/README.md
  • src/cmd/cli/command/commands.go
  • src/cmd/cli/command/commands_test.go
  • src/cmd/cli/command/globals.go
  • src/cmd/cli/command/globals_test.go
  • src/cmd/cli/command/workspace.go
  • src/cmd/cli/main.go
  • src/cmd/gendocs/main.go
  • src/pkg/agent/tools/default_tool_cli.go
  • src/pkg/agent/tools/deploy.go
  • src/pkg/agent/tools/deploy_test.go
  • src/pkg/agent/tools/interfaces.go
  • src/pkg/agent/tools/services_test.go
  • src/pkg/auth/interceptor.go
  • src/pkg/cli/activeDeployments_test.go
  • src/pkg/cli/client/byoc/aws/byoc.go
  • src/pkg/cli/client/byoc/aws/byoc_test.go
  • src/pkg/cli/client/byoc/baseclient.go
  • src/pkg/cli/client/byoc/do/byoc.go
  • src/pkg/cli/client/byoc/gcp/byoc.go
  • src/pkg/cli/client/client.go
  • src/pkg/cli/client/grpc.go
  • src/pkg/cli/client/mock.go
  • src/pkg/cli/client/playground.go
  • src/pkg/cli/configList_test.go
  • src/pkg/cli/connect.go
  • src/pkg/cli/connect_test.go
  • src/pkg/cli/deploymentsList_test.go
  • src/pkg/cli/destroy_test.go
  • src/pkg/cli/getServices_test.go
  • src/pkg/clouds/aws/route53_test.go
  • src/pkg/login/agree_tos.go
  • src/pkg/login/login.go
  • src/pkg/login/login_test.go
  • src/pkg/term/colorizer.go
  • src/pkg/term/colorizer_test.go
  • src/pkg/types/tenant.go
🧰 Additional context used
🧬 Code graph analysis (33)
src/pkg/agent/tools/services_test.go (1)
src/pkg/login/login.go (1)
  • InteractiveLoginMCP (47-49)
src/pkg/cli/client/client.go (1)
src/pkg/types/tenant.go (1)
  • TenantName (4-4)
src/cmd/gendocs/main.go (1)
src/cmd/cli/command/commands.go (1)
  • SetupCommands (145-371)
src/cmd/cli/command/globals.go (1)
src/pkg/types/tenant.go (2)
  • TenantNameOrID (8-8)
  • TenantNameOrID (31-33)
src/pkg/clouds/aws/route53_test.go (1)
src/pkg/clouds/aws/route53.go (1)
  • GetDelegationSetByZone (54-63)
src/pkg/cli/client/byoc/do/byoc.go (3)
src/pkg/cli/client/byoc/aws/byoc.go (1)
  • NewByocProvider (126-133)
src/pkg/cli/client/byoc/gcp/byoc.go (1)
  • NewByocProvider (105-111)
src/pkg/types/tenant.go (1)
  • TenantName (4-4)
src/pkg/cli/client/mock.go (1)
src/protos/io/defang/v1/defangv1connect/fabric.connect.go (1)
  • FabricControllerClient (163-217)
src/pkg/agent/tools/deploy.go (4)
src/pkg/login/login.go (1)
  • InteractiveLoginMCP (47-49)
src/pkg/agent/common/common.go (1)
  • MCPDevelopmentClient (12-12)
src/pkg/auth/auth.go (1)
  • ErrNoBrowser (18-21)
src/pkg/cli/connect.go (1)
  • Connect (15-21)
src/pkg/agent/tools/default_tool_cli.go (3)
src/pkg/cli/connect.go (1)
  • ConnectWithTenant (23-34)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/login/login.go (1)
  • InteractiveLoginMCP (47-49)
src/pkg/cli/client/byoc/baseclient.go (3)
src/pkg/types/tenant.go (1)
  • TenantName (4-4)
src/pkg/utils.go (1)
  • Getenv (48-53)
src/pkg/dns/utils.go (1)
  • SafeLabel (5-7)
src/pkg/login/login_test.go (2)
src/pkg/login/login.go (2)
  • LoginFlow (20-20)
  • InteractiveLogin (43-45)
src/pkg/auth/auth.go (1)
  • LoginFlow (33-33)
src/pkg/cli/activeDeployments_test.go (2)
src/pkg/cli/connect.go (1)
  • Connect (15-21)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/login/agree_tos.go (2)
src/pkg/cli/client/client.go (1)
  • FabricClient (17-44)
src/pkg/cli/client/state.go (1)
  • TermsAccepted (63-65)
src/pkg/agent/tools/interfaces.go (1)
src/pkg/login/login.go (1)
  • InteractiveLoginMCP (47-49)
src/pkg/cli/client/byoc/aws/byoc.go (3)
src/pkg/cli/client/byoc/do/byoc.go (1)
  • NewByocProvider (65-79)
src/pkg/cli/client/byoc/gcp/byoc.go (1)
  • NewByocProvider (105-111)
src/pkg/types/tenant.go (1)
  • TenantName (4-4)
src/cmd/cli/command/commands_test.go (1)
src/cmd/cli/command/commands.go (1)
  • SetupCommands (145-371)
src/pkg/cli/client/byoc/gcp/byoc.go (3)
src/pkg/cli/client/byoc/aws/byoc.go (1)
  • NewByocProvider (126-133)
src/pkg/cli/client/byoc/do/byoc.go (1)
  • NewByocProvider (65-79)
src/pkg/types/tenant.go (1)
  • TenantName (4-4)
src/pkg/cli/configList_test.go (2)
src/pkg/cli/connect.go (1)
  • Connect (15-21)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/agent/tools/deploy_test.go (1)
src/pkg/login/login.go (1)
  • InteractiveLoginMCP (47-49)
src/pkg/login/login.go (4)
src/pkg/auth/auth.go (3)
  • LoginFlow (33-33)
  • CliFlow (36-36)
  • McpFlow (37-37)
src/pkg/dryrun/dryrun.go (2)
  • DoDryRun (6-6)
  • ErrDryRun (8-8)
src/pkg/cli/connect.go (1)
  • ConnectWithTenant (23-34)
src/pkg/track/track.go (1)
  • Tracker (23-25)
src/pkg/cli/getServices_test.go (2)
src/pkg/cli/connect.go (1)
  • Connect (15-21)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/cli/destroy_test.go (2)
src/pkg/cli/connect.go (1)
  • Connect (15-21)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/cli/client/grpc.go (2)
src/pkg/types/tenant.go (3)
  • TenantNameOrID (8-8)
  • TenantNameOrID (31-33)
  • TenantName (4-4)
src/pkg/auth/interceptor.go (1)
  • NewAuthInterceptor (18-21)
src/pkg/term/colorizer_test.go (1)
src/pkg/term/colorizer.go (1)
  • Errorf (322-324)
src/pkg/cli/connect_test.go (2)
src/pkg/cli/connect.go (2)
  • ConnectWithTenant (23-34)
  • Connect (15-21)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/auth/interceptor.go (2)
src/pkg/types/tenant.go (2)
  • TenantNameOrID (8-8)
  • TenantNameOrID (31-33)
src/pkg/http/client.go (1)
  • Header (13-13)
src/pkg/cli/client/byoc/aws/byoc_test.go (1)
src/pkg/types/tenant.go (1)
  • TenantName (4-4)
src/pkg/cli/client/playground.go (3)
src/pkg/cli/client/provider.go (2)
  • ServerStream (36-41)
  • BootstrapCommandRequest (20-23)
src/pkg/cli/tail.go (1)
  • Tail (118-153)
src/pkg/cli/bootstrap.go (1)
  • BootstrapCommand (16-39)
src/cmd/cli/command/commands.go (4)
src/pkg/cli/connect.go (2)
  • Connect (15-21)
  • ConnectWithTenant (23-34)
src/pkg/login/login.go (1)
  • InteractiveLogin (43-45)
src/pkg/cli/whoami.go (1)
  • Whoami (25-59)
src/pkg/cli/token.go (1)
  • Token (16-54)
src/cmd/cli/main.go (1)
src/cmd/cli/command/commands.go (1)
  • SetupCommands (145-371)
src/cmd/cli/command/globals_test.go (1)
src/pkg/types/tenant.go (2)
  • TenantNameOrID (8-8)
  • TenantNameOrID (31-33)
src/pkg/cli/deploymentsList_test.go (2)
src/pkg/cli/connect.go (1)
  • Connect (15-21)
src/pkg/types/tenant.go (1)
  • TenantUnset (12-12)
src/pkg/cli/connect.go (3)
src/pkg/types/tenant.go (3)
  • TenantNameOrID (8-8)
  • TenantNameOrID (31-33)
  • TenantName (4-4)
src/pkg/cli/client/cluster.go (2)
  • NormalizeHost (18-26)
  • GetExistingToken (44-69)
src/pkg/term/colorizer.go (2)
  • Debugf (298-300)
  • Debug (294-296)
⏰ 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: Analyze (go)
  • GitHub Check: go-test
🔇 Additional comments (65)
src/pkg/term/colorizer_test.go (1)

96-124: LGTM! Improved test coverage for stderr routing.

The variable renaming (expectedexpectedOut, gotgotOut) and the addition of stderr validation (expectedErr, gotErr) improve test clarity and ensure that debug output is correctly routed to stderr. This change aligns with the commit message about routing debug output to stderr so it doesn't affect JSON output.

src/pkg/clouds/aws/route53_test.go (1)

15-16: Test is marked as broken and skipped.

The test is currently skipped, which prevents it from catching issues introduced by the refactoring. While the skip acknowledges known problems, the underlying issue (see comments on lines 39 and 61) should be resolved to restore test coverage for delegation set operations.

src/pkg/term/colorizer.go (1)

201-201: LGTM! Debug output correctly routed to stderr.

This change ensures debug messages don't interfere with structured output (e.g., JSON) written to stdout, which is a standard CLI best practice.

Also applies to: 208-208

pkgs/npm/README.md (1)

51-51: Consistent with root README—same backward compatibility concern applies.

The DEFANG_WORKSPACE rename here mirrors the change in the root README.md. Ensure backward compatibility handling for DEFANG_ORG applies consistently across all documentation.

src/pkg/agent/tools/services_test.go (1)

93-95: LGTM! Mock signature correctly updated.

The mock's InteractiveLoginMCP signature now matches the updated interface, removing the fabric client parameter as part of the broader refactor to centralize client handling.

src/README.md (1)

51-51: Documentation consistent across READMEs.

The DEFANG_WORKSPACE update is consistent with the root and npm README files. The same backward compatibility verification applies here.

src/pkg/login/login_test.go (2)

49-51: Mock signature correctly updated to match the refactored API.

The mock login method no longer requires the fabric client parameter, aligning with the simplified authentication flow.


71-71: Test call sites correctly updated.

The InteractiveLogin calls now pass only the fabric string, consistent with the updated function signature. Token storage validation logic remains intact.

Also applies to: 87-87

src/cmd/gendocs/main.go (1)

21-21: LGTM! Consistent with the updated SetupCommands API.

The removal of the context parameter aligns with the simplified SetupCommands signature. For documentation generation, context is not required.

README.md (1)

181-181: No action required—backward compatibility is already implemented.

The DEFANG_ORGDEFANG_WORKSPACE rename maintains backward compatibility through a fallback mechanism that recognizes DEFANG_ORG when DEFANG_WORKSPACE is not set, and displays a deprecation warning to users.

src/cmd/cli/command/workspace.go (1)

25-25: The direct access to global.Tenant is safe and properly initialized.

The flag is registered via Cobra's Var() method which handles custom type parsing, and Cobra marks required flags and validates relationships in PreRunE. The global.Tenant field is initialized through Cobra's PersistentFlags system in commands.go and synchronized with environment variables (DEFANG_WORKSPACE or DEFANG_ORG) via syncFlagsWithEnv() before command execution. No validation or fallback logic from a getTenantSelection() function needs to be preserved, as that function does not exist in the current codebase.

src/pkg/cli/client/byoc/aws/byoc_test.go (1)

31-31: LGTM: Type change aligns with refactoring objectives.

The field type change from types.TenantNameOrID to types.TenantName correctly reflects the stricter type semantics introduced in this PR, distinguishing tenant names (DNS labels) from tenant IDs.

src/pkg/cli/getServices_test.go (1)

71-71: LGTM: Connect call updated to match new signature.

The change correctly uses types.TenantUnset to indicate that no specific tenant/workspace is being selected for this test connection.

src/cmd/cli/main.go (1)

35-35: LGTM: API surface change correctly applied.

The removal of the ctx parameter from SetupCommands is appropriate—command setup doesn't require cancellation support, while command execution (line 36) still receives the context.

src/pkg/cli/client/mock.go (1)

114-116: LGTM: Method rename improves API clarity.

Renaming from GetController() to GetFabricClient() better describes what the method returns and aligns with interface changes elsewhere in the codebase.

src/pkg/agent/tools/interfaces.go (1)

24-24: LGTM: Simplified authentication interface.

Removing the fabric *client.GrpcClient parameter simplifies the authentication flow. Callers now reconnect after successful login to obtain a fresh client with the new token, as seen in deploy.go.

src/cmd/cli/command/globals.go (2)

82-82: LGTM: Type-safe tenant handling.

The change from string to types.TenantNameOrID provides better type safety and enables Cobra flag integration via the Type() and Set() methods defined on the type.


204-211: LGTM: Environment variable handling correctly updated.

The updated logic properly maintains backward compatibility with the deprecated DEFANG_ORG environment variable while prioritizing DEFANG_WORKSPACE.

src/pkg/types/tenant.go (2)

3-4: LGTM: New TenantName type for DNS labels.

The introduction of TenantName as a distinct type from TenantNameOrID provides clearer semantics for components that specifically work with tenant DNS labels rather than arbitrary identifiers.


30-39: LGTM: Cobra flag integration correctly implemented.

The Type() and Set() methods properly implement the pflag.Value interface, enabling TenantNameOrID to be used directly with Cobra flag parsing. The Set() method performs no validation, which appears intentional since validation likely occurs at usage sites.

src/pkg/agent/tools/deploy.go (1)

36-50: LGTM: Post-login reconnection correctly implemented.

The updated flow properly handles authentication:

  1. Attempt initial connection
  2. On failure, perform interactive login (line 36)
  3. Reconnect with the fresh token (lines 45-49)
  4. Propagate any reconnection errors

This pattern correctly adapts to the simplified authentication interface where InteractiveLoginMCP no longer receives or modifies a client instance.

src/pkg/cli/destroy_test.go (1)

10-10: LGTM!

The test correctly adapts to the new Connect signature by adding the types import and passing types.TenantUnset as the tenant parameter. This aligns with the refactored API where tenant handling is now explicit.

Also applies to: 57-57

src/pkg/agent/tools/deploy_test.go (1)

59-62: LGTM!

The mock signature correctly aligns with the refactored InteractiveLoginMCP interface that removes the fabric parameter. This matches the actual implementation in src/pkg/login/login.go which now handles fabric connection internally.

src/pkg/cli/client/client.go (2)

31-31: Return type change for GetTenantName: TenantNameOrIDTenantName

This is a meaningful semantic change—TenantName represents a resolved tenant name (output), while TenantNameOrID is for input that may be unset. This improves type safety at the interface boundary.


27-27: Interface method rename: GetControllerGetFabricClient

The rename improves clarity. All implementations of the FabricClient interface have been updated: GrpcClient in grpc.go and MockFabricClient in mock.go both implement the new GetFabricClient() method with no remaining references to the old method name.

src/pkg/agent/tools/default_tool_cli.go (2)

48-51: Connect method updated to use tenant-aware connection

The change to ConnectWithTenant with types.TenantUnset is appropriate, and the TODO comment documents the known limitation for MCP workspace support.


116-117: Simplified InteractiveLoginMCP delegation

The method now correctly delegates to login.InteractiveLoginMCP which handles the fabric connection internally. This aligns with the broader refactor removing the fabric threading through function signatures.

src/pkg/cli/configList_test.go (1)

11-11: LGTM!

The test correctly adapts to the new Connect signature, consistent with other test updates in this PR.

Also applies to: 51-51

src/pkg/cli/deploymentsList_test.go (1)

11-11: LGTM!

The test correctly adapts to the new Connect signature with the explicit tenant parameter, consistent with the tenant refactoring across the codebase.

Also applies to: 61-61

src/pkg/cli/activeDeployments_test.go (1)

10-10: LGTM!

The test correctly adapts to the updated Connect signature by importing the types package and using types.TenantUnset for the tenant parameter. This is appropriate for tests that don't require tenant-specific behavior.

Also applies to: 51-51

src/pkg/cli/client/byoc/gcp/byoc.go (1)

105-111: LGTM!

The constructor signature update to use types.TenantName is consistent with the other BYOC providers (AWS and DO) as shown in the relevant code snippets.

src/pkg/auth/interceptor.go (2)

13-21: LGTM!

The interceptor now properly uses the types.TenantNameOrID type with its IsSet() method for conditional header setting. This provides type safety and clearer intent compared to raw string comparison.


27-29: Consistent tenant header handling in both unary and streaming paths.

Both WrapUnary and WrapStreamingClient use the same pattern for conditionally setting the tenant header, ensuring consistent behavior across request types.

Also applies to: 39-41

src/cmd/cli/command/commands_test.go (2)

86-88: LGTM!

The init() function correctly adapts to the updated SetupCommands signature that no longer requires a context parameter.


267-268: LGTM!

The test correctly uses the renamed SetFabricClient method, which provides a more explicit API for setting the mock fabric controller client.

src/pkg/cli/client/byoc/aws/byoc.go (2)

126-133: LGTM!

The constructor signature update to use types.TenantName is consistent with the other BYOC providers. The initialization pattern remains clean and correct.


480-480: Good documentation of backward compatibility constraint.

The inline comment explaining that DEFANG_ORG is kept for CD backward compatibility is helpful. The explicit string(b.TenantName) conversion is required since TenantName is a defined type.

src/pkg/cli/client/byoc/do/byoc.go (3)

31-31: Import addition is appropriate.

The logs package import supports the logs.LogType usage in the file (e.g., line 425).


65-79: LGTM!

The constructor signature update to use types.TenantName is consistent with the AWS and GCP BYOC providers.


659-659: Consistent with AWS provider.

The DEFANG_ORG environment variable correctly uses string(b.TenantName), matching the AWS provider's approach.

src/cmd/cli/command/globals_test.go (2)

14-14: LGTM! Type-safe tenant handling in tests.

The test updates correctly reflect the migration from string to types.TenantNameOrID for the Tenant field. The use of flags.Var() is appropriate since TenantNameOrID implements the pflag.Value interface (with Set, String, and Type methods as shown in the relevant snippets).

Also applies to: 255-255, 374-374, 395-395, 444-444


406-412: Verify intended deprecation of DEFANG_TENANT environment variable.

The test case "tenant env ignored" shows that DEFANG_TENANT alone now returns an empty tenant, effectively deprecating this env var. Ensure this breaking change is documented and users are informed to migrate to DEFANG_WORKSPACE.

src/pkg/cli/client/playground.go (2)

25-96: LGTM! Consistent migration to FabricClient interface.

All method implementations correctly migrate from the old controller interface to GetFabricClient(), maintaining the same request wrapping pattern with connect.NewRequest(req). The changes are uniform and preserve the original behavior.


140-146: LGTM!

The explicit string() conversion for TenantName is correct and cleaner than a method call.

src/pkg/login/agree_tos.go (1)

18-65: LGTM! Clean parameter rename for clarity.

The parameter rename from c to fabric improves code readability by making the interface type explicit. All internal call sites are correctly updated, and the control flow remains unchanged.

src/pkg/cli/client/byoc/baseclient.go (1)

55-72: LGTM! Stronger typing for tenant handling.

The migration from string to types.TenantName for the TenantName field provides better type safety. The constructor correctly accepts types.TenantName directly, requiring callers to resolve TenantNameOrID to TenantName before instantiation.

src/pkg/cli/connect_test.go (2)

20-168: LGTM! Comprehensive test coverage for tenant-aware connections.

The tests thoroughly verify the new ConnectWithTenant flow including:

  • Network error scenarios with types.TenantUnset
  • Proper distinction between GetRequestedTenant() (client-requested) and GetTenantName() (server-returned)
  • Explicit tenant header propagation
  • Legacy cluster prefix handling

The test structure clearly validates both the request and response sides of tenant handling.


171-181: LGTM!

The mock correctly captures the tenant header from incoming requests for test verification and returns configurable tenant responses.

src/pkg/cli/connect.go (3)

14-21: LGTM! Simplified Connect function.

The new Connect function cleanly builds a GrpcClient with the requested tenant. The removal of the error return simplifies the API since client construction itself doesn't fail—validation happens later in ConnectWithTenant.


23-34: LGTM! Tenant validation via WhoAmI.

The function correctly validates the tenant by calling WhoAmI and updates grpcClient.Tenant with the server-validated tenant name on success. Returning the client even on error allows callers to use it for limited operations (e.g., login).


36-50: LGTM!

The NewProvider function correctly uses fabricClient.GetTenantName() to pass the validated tenant to BYOC providers.

src/cmd/cli/command/commands.go (7)

145-145: LGTM! Simplified SetupCommands signature.

Removing the ctx parameter makes sense since command setup doesn't require a context—execution-time context is available via cmd.Context().


171-171: LGTM!

The --workspace flag correctly binds to global.Tenant of type TenantNameOrID.


403-404: Temporary tracker for pre-auth tracking.

Good pattern: creating a temporary tracker using cli.Connect before authentication allows tracking of the login flow itself. The tracker is updated at line 453 after successful connection.


445-453: LGTM! Connection and tracker flow.

The flow correctly establishes the authenticated connection via ConnectWithTenant, allows the login flow to continue on CodeUnauthenticated, and updates the global tracker with the real client after successful authentication.


509-509: LGTM!

The simplified InteractiveLogin call aligns with the updated signature in login.go.


554-554: LGTM!

Direct use of global.Tenant is cleaner than the removed getTenantSelection() helper.


1154-1154: LGTM!

Consistent use of global.Tenant for the token command.

src/pkg/login/login.go (4)

22-24: LGTM! Simplified AuthService interface.

Removing the FabricClient parameter from login is appropriate since token acquisition via OAuth doesn't require an existing client connection.


28-39: LGTM!

The implementation correctly performs the OAuth code flow and exchanges the code for a token without needing an existing fabric client.


61-63: LGTM! Dry-run guard.

The dry-run check is correctly placed after token acquisition but before any file system operations, ensuring dry runs don't modify state.


127-137: LGTM! Re-authentication flow with tenant preservation.

The flow correctly:

  1. Calls the simplified InteractiveLogin
  2. Reconnects using GetRequestedTenant() to preserve the tenant context
  3. Updates the global tracker with the new fabric client
src/pkg/cli/client/grpc.go (3)

19-25: LGTM! Clean tenant field separation.

Good design: requestedTenant (what was requested by the user) is distinct from Tenant (validated by server). The requestedTenant is private while Tenant is public, allowing external code to read the validated tenant.


27-50: LGTM! Constructor initializes requestedTenant only.

The constructor correctly:

  1. Passes requestedTenant to the auth interceptor for header inclusion
  2. Stores requestedTenant in the client
  3. Leaves Tenant unset—it's populated later by ConnectWithTenant after server validation

59-73: LGTM! Clean accessor methods.

The accessor methods provide clear semantics:

  • GetRequestedTenant(): returns the originally requested tenant (name or ID)
  • GetTenantName(): returns the server-validated tenant name
  • GetFabricClient() / SetFabricClient(): for internal client access

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: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce2d73c and 955443d.

📒 Files selected for processing (9)
  • src/pkg/cli/client/byoc/aws/byoc.go
  • src/pkg/cli/client/byoc/aws/byoc_test.go
  • src/pkg/cli/client/byoc/baseclient.go
  • src/pkg/cli/client/byoc/do/byoc.go
  • src/pkg/cli/client/byoc/gcp/byoc.go
  • src/pkg/cli/client/client.go
  • src/pkg/cli/client/grpc.go
  • src/pkg/cli/connect.go
  • src/pkg/types/tenant.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/pkg/cli/client/byoc/aws/byoc_test.go
🧰 Additional context used
🧬 Code graph analysis (6)
src/pkg/cli/client/client.go (2)
src/protos/io/defang/v1/defangv1connect/fabric.connect.go (1)
  • FabricControllerClient (163-217)
src/pkg/types/tenant.go (1)
  • TenantLabel (4-4)
src/pkg/cli/client/byoc/aws/byoc.go (3)
src/pkg/cli/client/byoc/do/byoc.go (1)
  • NewByocProvider (65-79)
src/pkg/cli/client/byoc/gcp/byoc.go (1)
  • NewByocProvider (105-111)
src/pkg/types/tenant.go (1)
  • TenantLabel (4-4)
src/pkg/cli/client/byoc/gcp/byoc.go (3)
src/pkg/cli/client/byoc/aws/byoc.go (1)
  • NewByocProvider (126-133)
src/pkg/cli/client/byoc/do/byoc.go (1)
  • NewByocProvider (65-79)
src/pkg/types/tenant.go (1)
  • TenantLabel (4-4)
src/pkg/cli/client/byoc/baseclient.go (3)
src/pkg/types/tenant.go (1)
  • TenantLabel (4-4)
src/pkg/utils.go (1)
  • Getenv (48-53)
src/pkg/dns/utils.go (1)
  • SafeLabel (5-7)
src/pkg/cli/client/byoc/do/byoc.go (3)
src/pkg/cli/client/byoc/aws/byoc.go (1)
  • NewByocProvider (126-133)
src/pkg/cli/client/byoc/gcp/byoc.go (1)
  • NewByocProvider (105-111)
src/pkg/types/tenant.go (1)
  • TenantLabel (4-4)
src/pkg/cli/client/grpc.go (2)
src/pkg/types/tenant.go (3)
  • TenantNameOrID (8-8)
  • TenantNameOrID (31-33)
  • TenantLabel (4-4)
src/pkg/auth/interceptor.go (1)
  • NewAuthInterceptor (18-21)
⏰ 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: Analyze (go)
  • GitHub Check: go-test
🔇 Additional comments (15)
src/pkg/types/tenant.go (2)

3-4: LGTM! Clear type definition for tenant DNS labels.

The new TenantLabel type provides type safety and clearly indicates its purpose as a DNS label representation.


30-39: LGTM! Standard Cobra flag implementation.

The Type() and Set() methods correctly implement the pflag.Value interface for Cobra flag parsing. The Set() method accepts any string without validation, which provides flexibility for accepting various tenant identifier formats.

src/pkg/cli/client/grpc.go (3)

27-49: LGTM! Constructor correctly initializes with requested tenant.

The refactored constructor cleanly accepts and stores the requestedTenant, passing it to the authentication interceptor. This aligns with the new tenant resolution flow where the requested tenant is sent to the server.


59-73: LGTM! Method renames improve API clarity.

The renamed methods (GetFabricClient, SetFabricClient) are more descriptive, and the new GetRequestedTenant() method provides appropriate access to the user-supplied tenant identifier. The distinction between requested tenant (input) and resolved tenant (output from WhoAmI) is clear.


23-24: The Tenant field is uninitialized in the constructor and only populated after a successful WhoAmI call in ConnectWithTenant. This is intentional—the codebase has an explicit test validating that GetTenantName() returns an empty value when Connect() is used without ConnectWithTenant(). All production usages of GetTenantName() occur after ConnectWithTenant succeeds or have the Tenant field explicitly set, so the empty state is handled correctly by existing code.

src/pkg/cli/client/client.go (1)

27-31: LGTM! Interface updates align with implementation.

The method renames and return type changes are consistent with the implementation in grpc.go. Based on learnings, the TenantLabel name was chosen to clarify that this represents the tenant's DNS label, addressing previous confusion about "TenantName" usage.

src/pkg/cli/client/byoc/aws/byoc.go (2)

126-133: LGTM! Constructor updated to accept TenantLabel.

The constructor signature correctly uses types.TenantLabel. Minor note: the parameter name tenantName might be slightly misleading since it's now a TenantLabel, but this is consistent across all BYOC providers and doesn't cause functional issues.


480-480: LGTM! Environment variable correctly uses TenantLabel.

The conversion from TenantLabel to string is explicit, and the comment clearly explains the backward compatibility reason for keeping the DEFANG_ORG variable name. This is consistent with the refactoring goals.

src/pkg/cli/client/byoc/gcp/byoc.go (1)

105-111: LGTM! Constructor signature consistent with other BYOC providers.

The constructor correctly accepts types.TenantLabel and passes it to the base client, matching the pattern used in AWS and DO providers.

src/pkg/cli/client/byoc/do/byoc.go (2)

65-79: LGTM! Constructor consistent with BYOC provider pattern.

The constructor correctly accepts types.TenantLabel and passes it to the base client, following the same pattern as the AWS provider.


659-659: LGTM! Environment variable correctly uses TenantLabel.

The DEFANG_ORG environment variable correctly uses string(b.TenantLabel), consistent with the AWS provider implementation.

src/pkg/cli/client/byoc/baseclient.go (2)

55-72: LGTM! Base client correctly updated to use TenantLabel.

The field rename from TenantName to TenantLabel and the type change to types.TenantLabel are consistent with the overall refactoring. The constructor properly accepts and assigns the new type.


301-306: LGTM! New ServicePublicDNS method constructs correct DNS names.

The method correctly builds a public DNS name using SafeLabel for DNS compatibility. The special handling for the "beta" stack maintains backward compatibility, and the use of TenantLabel aligns with the refactoring goals.

src/pkg/cli/connect.go (2)

14-21: LGTM! Simplified Connect function with explicit tenant parameter.

The refactored Connect function removes implicit tenant derivation from tokens and requires callers to explicitly provide the requestedTenant. This makes the tenant source clear and simplifies the connection logic. The debug logging aids troubleshooting.


23-34: Verify error handling when WhoAmI fails.

The function returns the client even when WhoAmI fails (intentional graceful degradation). However, grpcClient.Tenant remains empty in error cases. While callers suppress only CodeUnauthenticated errors and immediately return other errors, and the happy path (GetVersions) doesn't require Tenant, downstream code lacks explicit guards before using GetTenantName(). Consider adding a code comment explaining why this design is safe, or add validation in callers that use the client after error suppression.

@lionello lionello mentioned this pull request Dec 23, 2025
@lionello lionello merged commit 97c423c into main Dec 23, 2025
6 checks passed
@lionello lionello deleted the lio/cleanup-tenants branch December 23, 2025 06:13
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