Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions apps/cli-go/api/overlay.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@ actions:
- target: $.components.schemas.V1CreateProjectBody.properties.postgres_engine
description: Removes deprecated null-only field that oapi-codegen cannot map
remove: true
- target: $.components.schemas.JitListAccessResponse.properties.items.items.anyOf[0].properties.invite_id
- target: $.components.schemas.JitListAccessResponse_Output.properties.items.items.anyOf[0].properties.invite_id
Comment thread
Coly010 marked this conversation as resolved.

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.

⚪ NIT · maintainability · source: claude

The repaired JIT overlay selectors remain coupled to the concrete JitListAccessResponse_Output schema name, leaving code generation vulnerable to the same failure mode on another upstream rename.

Evidence: apps/cli-go/api/overlay.yaml:41-57 hardcodes JitListAccessResponse_Output in all three selectors, while apps/cli-go/main.go:7-8 regenerates from a live API specification and other structural overlay selectors use schema wildcards.

Suggested fix: Use a sufficiently specific structural wildcard selector, with a test or uniqueness check ensuring it only matches the intended JIT response shape.

description: Replaces null-only project user invite id with nullable UUID for oapi-codegen
update:
type: string
format: uuid
nullable: true
- target: $.components.schemas.JitListAccessResponse.properties.items.items.anyOf[0].properties.expires_at
- target: $.components.schemas.JitListAccessResponse_Output.properties.items.items.anyOf[0].properties.expires_at
description: Replaces null-only project user invite expiry with nullable string for oapi-codegen
update:
type: string
nullable: true
- target: $.components.schemas.JitListAccessResponse.properties.items.items.anyOf[1].properties.user_id
- target: $.components.schemas.JitListAccessResponse_Output.properties.items.items.anyOf[1].properties.user_id
description: Replaces null-only invited user id with nullable UUID for oapi-codegen
update:
type: string
Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/internal/functions/download/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func RunLegacy(ctx context.Context, slug string, projectRef string, fsys afero.F
return nil
}

func getFunctionMetadata(ctx context.Context, projectRef, slug string) (*api.FunctionSlugResponse, error) {
func getFunctionMetadata(ctx context.Context, projectRef, slug string) (*api.FunctionSlugResponseOutput, error) {
resp, err := utils.GetSupabase().V1GetAFunctionWithResponse(ctx, projectRef, slug)
if err != nil {
return nil, errors.Errorf("failed to get function metadata: %w", err)
Expand Down
24 changes: 12 additions & 12 deletions apps/cli-go/internal/functions/download/download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func TestRunLegacyUnbundle(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug).
Reply(http.StatusOK).
JSON(api.FunctionResponse{Id: "1"})
JSON(api.FunctionResponseOutput{Id: "1"})
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug + "/body").
Reply(http.StatusOK)
Expand Down Expand Up @@ -344,7 +344,7 @@ func TestDownloadAllRejectsMaliciousSlug(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions").
Reply(http.StatusOK).
JSON([]api.FunctionResponse{{
JSON([]api.FunctionResponseOutput{{
Id: "poc-id",
Name: "poc",
Slug: maliciousSlug,
Expand Down Expand Up @@ -447,11 +447,11 @@ func TestRunServerSideUnbundle(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get(fmt.Sprintf("/v1/projects/%s/functions/%s", project, slug)).
Reply(http.StatusOK).
JSON(api.FunctionSlugResponse{
JSON(api.FunctionSlugResponseOutput{
Id: "1",
Name: slug,
Slug: slug,
Status: api.FunctionSlugResponseStatus("ACTIVE"),
Status: api.FunctionSlugResponseOutputStatus("ACTIVE"),
Version: 1,
CreatedAt: 0,
UpdatedAt: 0,
Expand Down Expand Up @@ -481,11 +481,11 @@ func TestRunServerSideUnbundle(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get(fmt.Sprintf("/v1/projects/%s/functions/%s", project, slug)).
Reply(http.StatusOK).
JSON(api.FunctionSlugResponse{
JSON(api.FunctionSlugResponseOutput{
Id: "1",
Name: slug,
Slug: slug,
Status: api.FunctionSlugResponseStatus("ACTIVE"),
Status: api.FunctionSlugResponseOutputStatus("ACTIVE"),
Version: 1,
CreatedAt: 0,
UpdatedAt: 0,
Expand Down Expand Up @@ -515,11 +515,11 @@ func TestRunServerSideUnbundle(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get(fmt.Sprintf("/v1/projects/%s/functions/%s", project, slug)).
Reply(http.StatusOK).
JSON(api.FunctionSlugResponse{
JSON(api.FunctionSlugResponseOutput{
Id: "1",
Name: slug,
Slug: slug,
Status: api.FunctionSlugResponseStatus("ACTIVE"),
Status: api.FunctionSlugResponseOutputStatus("ACTIVE"),
Version: 1,
CreatedAt: 0,
UpdatedAt: 0,
Expand Down Expand Up @@ -766,7 +766,7 @@ func TestDownloadFunction(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug).
Reply(http.StatusOK).
JSON(api.FunctionResponse{Id: "1"})
JSON(api.FunctionResponseOutput{Id: "1"})
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug + "/body").
ReplyError(errors.New("network error"))
Expand All @@ -782,7 +782,7 @@ func TestDownloadFunction(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug).
Reply(http.StatusOK).
JSON(api.FunctionResponse{Id: "1"})
JSON(api.FunctionResponseOutput{Id: "1"})
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug + "/body").
Reply(http.StatusServiceUnavailable)
Expand All @@ -800,7 +800,7 @@ func TestDownloadFunction(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug).
Reply(http.StatusOK).
JSON(api.FunctionResponse{Id: "1"})
JSON(api.FunctionResponseOutput{Id: "1"})
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug + "/body").
Reply(http.StatusOK)
Expand All @@ -825,7 +825,7 @@ func TestGetMetadata(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + project + "/functions/" + slug).
Reply(http.StatusOK).
JSON(api.FunctionResponse{Id: "1"})
JSON(api.FunctionResponseOutput{Id: "1"})
// Run test
meta, err := getFunctionMetadata(context.Background(), project, slug)
// Check error
Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/internal/gen/types/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func TestGenLinkedCommand(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + projectId + "/types/typescript").
Reply(200).
JSON(api.TypescriptResponse{Types: ""})
JSON(api.TypescriptResponseOutput{Types: ""})
// Run test
assert.NoError(t, Run(context.Background(), projectId, pgconn.Config{}, LangTypescript, []string{}, true, "", time.Second, fsys))
// Validate api
Expand Down
4 changes: 2 additions & 2 deletions apps/cli-go/internal/telemetry/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func linkedProjectPath() string {
return filepath.Join(utils.TempDir, "linked-project.json")
}

func SaveLinkedProject(project api.V1ProjectWithDatabaseResponse, fsys afero.Fs) error {
func SaveLinkedProject(project api.V1ProjectWithDatabaseResponseOutput, fsys afero.Fs) error {
linked := LinkedProject{
Ref: project.Ref,
Name: project.Name,
Expand Down Expand Up @@ -63,7 +63,7 @@ func HasLinkedProject(fsys afero.Fs) bool {
// auth — this function only handles caching and PostHog group identification.
//
// Best-effort: logs errors to debug output, never returns them.
func CacheProjectAndIdentifyGroups(project api.V1ProjectWithDatabaseResponse, service *Service, fsys afero.Fs) {
func CacheProjectAndIdentifyGroups(project api.V1ProjectWithDatabaseResponseOutput, service *Service, fsys afero.Fs) {
if err := SaveLinkedProject(project, fsys); err != nil {
fmt.Fprintln(utils.GetDebugLogger(), err)
}
Expand Down
4 changes: 2 additions & 2 deletions apps/cli-go/internal/telemetry/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/supabase/cli/pkg/api"
)

var testProject = api.V1ProjectWithDatabaseResponse{
var testProject = api.V1ProjectWithDatabaseResponseOutput{
Ref: "proj_abc",
Name: "My Project",
OrganizationId: "org_123",
Expand Down Expand Up @@ -93,7 +93,7 @@ func TestCacheProjectAndIdentifyGroups(t *testing.T) {
analytics := &fakeAnalytics{enabled: true}
service := newTestService(t, fsys, analytics)

noOrgProject := api.V1ProjectWithDatabaseResponse{
noOrgProject := api.V1ProjectWithDatabaseResponseOutput{
Ref: "proj_abc",
Name: "My Project",
}
Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/internal/telemetry/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ func TestServiceCaptureIncludesLinkedProjectGroups(t *testing.T) {
t.Setenv("SUPABASE_HOME", "/tmp/supabase-home")
fsys := afero.NewMemMapFs()
analytics := &fakeAnalytics{enabled: true}
require.NoError(t, SaveLinkedProject(api.V1ProjectWithDatabaseResponse{
require.NoError(t, SaveLinkedProject(api.V1ProjectWithDatabaseResponseOutput{
Ref: "proj_123",
Name: "My Project",
OrganizationId: "org_123",
Expand Down
6 changes: 3 additions & 3 deletions apps/cli-go/internal/utils/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,16 @@ func toPostgresURL(config pgconn.Config, userinfo *url.Userinfo) string {

var ErrPrimaryNotFound = errors.New("primary database not found")

func GetPoolerConfigPrimary(ctx context.Context, ref string) (api.SupavisorConfigResponse, error) {
var result api.SupavisorConfigResponse
func GetPoolerConfigPrimary(ctx context.Context, ref string) (api.SupavisorConfigResponseOutput, error) {
var result api.SupavisorConfigResponseOutput
resp, err := GetSupabase().V1GetPoolerConfigWithResponse(ctx, ref)
if err != nil {
return result, errors.Errorf("failed to get pooler: %w", err)
} else if resp.JSON200 == nil {
return result, errors.Errorf("unexpected get pooler status %d: %s", resp.StatusCode(), string(resp.Body))
}
for _, config := range *resp.JSON200 {
if config.DatabaseType == api.SupavisorConfigResponseDatabaseTypePRIMARY {
if config.DatabaseType == api.SupavisorConfigResponseOutputDatabaseTypePRIMARY {
return config, nil
}
}
Expand Down
10 changes: 5 additions & 5 deletions apps/cli-go/internal/utils/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ func TestSuggestIPv6Pooler(t *testing.T) {
gock.New(DefaultApiHost).
Get("/v1/projects/" + ref + "/config/database/pooler").
Reply(http.StatusOK).
JSON([]api.SupavisorConfigResponse{{
DatabaseType: api.SupavisorConfigResponseDatabaseTypePRIMARY,
JSON([]api.SupavisorConfigResponseOutput{{
DatabaseType: api.SupavisorConfigResponseOutputDatabaseTypePRIMARY,
ConnectionString: poolerURL,
}})
ok := SuggestIPv6Pooler(context.Background(), "db."+ref+".supabase.co")
Expand All @@ -317,8 +317,8 @@ func TestSuggestIPv6Pooler(t *testing.T) {
gock.New(DefaultApiHost).
Get("/v1/projects/" + ref + "/config/database/pooler").
Reply(http.StatusOK).
JSON([]api.SupavisorConfigResponse{{
DatabaseType: api.SupavisorConfigResponseDatabaseTypePRIMARY,
JSON([]api.SupavisorConfigResponseOutput{{
DatabaseType: api.SupavisorConfigResponseOutputDatabaseTypePRIMARY,
ConnectionString: secretURL,
}})
ok := SuggestIPv6Pooler(context.Background(), "db."+ref+".supabase.co")
Expand All @@ -340,7 +340,7 @@ func TestSuggestIPv6Pooler(t *testing.T) {
gock.New(DefaultApiHost).
Get("/v1/projects/" + ref + "/config/database/pooler").
Reply(http.StatusOK).
JSON([]api.SupavisorConfigResponse{})
JSON([]api.SupavisorConfigResponseOutput{})
assert.False(t, SuggestIPv6Pooler(context.Background(), "db."+ref+".supabase.co"))
assert.Empty(t, CmdSuggestion)
})
Expand Down
6 changes: 3 additions & 3 deletions apps/cli-go/internal/utils/flags/db_url_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ func TestResolvePoolerConfigForFallback(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + ref + "/config/database/pooler").
Reply(http.StatusOK).
JSON([]api.SupavisorConfigResponse{{
DatabaseType: api.SupavisorConfigResponseDatabaseTypePRIMARY,
JSON([]api.SupavisorConfigResponseOutput{{
DatabaseType: api.SupavisorConfigResponseOutputDatabaseTypePRIMARY,
ConnectionString: poolerURL,
}})

Expand All @@ -137,7 +137,7 @@ func TestResolvePoolerConfigForFallback(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + ref + "/config/database/pooler").
Reply(http.StatusOK).
JSON([]api.SupavisorConfigResponse{})
JSON([]api.SupavisorConfigResponseOutput{})

_, err := ResolvePoolerConfigForFallback(context.Background(), ref)

Expand Down
2 changes: 1 addition & 1 deletion apps/cli-go/internal/utils/flags/project_ref_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func TestProjectPrompt(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects").
Reply(http.StatusOK).
JSON([]api.V1ProjectResponse{{
JSON([]api.V1ProjectResponseOutput{{
Id: "test-project",
Name: "My Project",
OrganizationSlug: "test-org",
Expand Down
8 changes: 4 additions & 4 deletions apps/cli-go/internal/utils/tenant/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (a ApiKey) IsEmpty() bool {
return len(a.Anon) == 0 && len(a.ServiceRole) == 0
}

func NewApiKey(resp []api.ApiKeyResponse) ApiKey {
func NewApiKey(resp []api.ApiKeyResponseOutput) ApiKey {
var result ApiKey
for _, key := range resp {
value, err := key.ApiKey.Get()
Expand All @@ -34,10 +34,10 @@ func NewApiKey(resp []api.ApiKeyResponse) ApiKey {
}
if t, err := key.Type.Get(); err == nil {
switch t {
case api.ApiKeyResponseTypePublishable:
case api.ApiKeyResponseOutputTypePublishable:
result.Anon = value
continue
case api.ApiKeyResponseTypeSecret:
case api.ApiKeyResponseOutputTypeSecret:
if isServiceRole(key) {
result.ServiceRole = value
}
Expand All @@ -58,7 +58,7 @@ func NewApiKey(resp []api.ApiKeyResponse) ApiKey {
return result
}

func isServiceRole(key api.ApiKeyResponse) bool {
func isServiceRole(key api.ApiKeyResponseOutput) bool {
if tmpl, err := key.SecretJwtTemplate.Get(); err == nil {
if role, ok := tmpl["role"].(string); ok {
return strings.EqualFold(role, "service_role")
Expand Down
10 changes: 5 additions & 5 deletions apps/cli-go/internal/utils/tenant/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

func TestApiKey(t *testing.T) {
t.Run("creates api key from response", func(t *testing.T) {
resp := []api.ApiKeyResponse{
resp := []api.ApiKeyResponseOutput{
{Name: "anon", ApiKey: nullable.NewNullableWithValue("anon-key")},
{Name: "service_role", ApiKey: nullable.NewNullableWithValue("service-key")},
}
Expand All @@ -28,7 +28,7 @@ func TestApiKey(t *testing.T) {
})

t.Run("handles empty response", func(t *testing.T) {
resp := []api.ApiKeyResponse{
resp := []api.ApiKeyResponseOutput{
{Name: "service_role", ApiKey: nullable.NewNullNullable[string]()},
}

Expand All @@ -40,7 +40,7 @@ func TestApiKey(t *testing.T) {
})

t.Run("handles partial response", func(t *testing.T) {
resp := []api.ApiKeyResponse{
resp := []api.ApiKeyResponseOutput{
{Name: "anon", ApiKey: nullable.NewNullableWithValue("anon-key")},
}

Expand All @@ -62,7 +62,7 @@ func TestGetApiKeys(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + projectRef + "/api-keys").
Reply(http.StatusOK).
JSON([]api.ApiKeyResponse{
JSON([]api.ApiKeyResponseOutput{
{Name: "anon", ApiKey: nullable.NewNullableWithValue("anon-key")},
{Name: "service_role", ApiKey: nullable.NewNullableWithValue("service-key")},
})
Expand Down Expand Up @@ -120,7 +120,7 @@ func TestGetApiKeys(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + projectRef + "/api-keys").
Reply(http.StatusOK).
JSON([]api.ApiKeyResponse{}) // should this error if response has only service_role key?
JSON([]api.ApiKeyResponseOutput{}) // should this error if response has only service_role key?

keys, err := GetApiKeys(context.Background(), projectRef)

Expand Down
4 changes: 2 additions & 2 deletions apps/cli-go/internal/utils/tenant/database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestGetDatabaseVersion(t *testing.T) {
t.Run("retrieves database version successfully", func(t *testing.T) {
// Setup mock api
defer gock.OffAll()
mockPostgres := api.V1ProjectWithDatabaseResponse{}
mockPostgres := api.V1ProjectWithDatabaseResponseOutput{}
mockPostgres.Database.Version = "14.1.0.99"
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + projectRef).
Expand Down Expand Up @@ -58,7 +58,7 @@ func TestGetDatabaseVersion(t *testing.T) {
gock.New(utils.DefaultApiHost).
Get("/v1/projects/" + projectRef).
Reply(http.StatusOK).
JSON(api.V1ProjectWithDatabaseResponse{})
JSON(api.V1ProjectWithDatabaseResponseOutput{})
// Run test
version, err := GetDatabaseVersion(context.Background(), projectRef)
// Check error
Expand Down
Loading
Loading