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
2 changes: 1 addition & 1 deletion cmd/publisher/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func createServerJSON(
URL: repoURL,
Source: repoSource,
},
Version: version,
Version: version,
Packages: []model.Package{pkg},
}
}
6 changes: 3 additions & 3 deletions cmd/publisher/commands/logout.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func LogoutCommand() error {
}

tokenPath := filepath.Join(homeDir, TokenFileName)

// Check if token file exists
if _, err := os.Stat(tokenPath); os.IsNotExist(err) {
_, _ = fmt.Fprintln(os.Stdout, "Not logged in")
Expand All @@ -30,7 +30,7 @@ func LogoutCommand() error {
".mcpregistry_github_token",
".mcpregistry_registry_token",
}

for _, file := range legacyFiles {
path := filepath.Join(homeDir, file)
if _, err := os.Stat(path); err == nil {
Expand All @@ -40,4 +40,4 @@ func LogoutCommand() error {

_, _ = fmt.Fprintln(os.Stdout, "✓ Successfully logged out")
return nil
}
}
2 changes: 1 addition & 1 deletion cmd/publisher/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,4 @@ func printUsage() {
_, _ = fmt.Fprintln(os.Stdout, " publish Publish server.json to the registry")
_, _ = fmt.Fprintln(os.Stdout)
_, _ = fmt.Fprintln(os.Stdout, "Use 'mcp-publisher <command> --help' for more information about a command.")
}
}
2 changes: 1 addition & 1 deletion deploy/pkg/k8s/ingress.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func SetupIngressController(ctx *pulumi.Context, cluster *providers.ProviderInfo
Values: pulumi.Map{
"controller": pulumi.Map{
"service": pulumi.Map{
"type": serviceType,
"type": serviceType,
"annotations": pulumi.Map{},
},
"config": pulumi.Map{
Expand Down
10 changes: 5 additions & 5 deletions deploy/pkg/providers/gcp/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ type Provider struct{}
// createGCPProvider creates a GCP provider with explicit credentials if configured
func createGCPProvider(ctx *pulumi.Context, name string) (*gcp.Provider, error) {
gcpConf := config.New(ctx, "gcp")

// Get project ID from config
projectID := gcpConf.Get("project")
if projectID == "" {
return nil, fmt.Errorf("GCP project ID not configured. Set gcp:project")
}

// Get region from config or use default
region := gcpConf.Get("region")
if region == "" {
region = "us-central1"
}

// Get credentials from config (base64 encoded service account JSON)
credentials := gcpConf.Get("credentials")
if credentials != "" {
Expand All @@ -45,7 +45,7 @@ func createGCPProvider(ctx *pulumi.Context, name string) (*gcp.Provider, error)
}
credentials = string(decodedCreds)
}

// Create a GCP provider with explicit credentials if provided
if credentials != "" {
return gcp.NewProvider(ctx, name, &gcp.ProviderArgs{
Expand All @@ -54,7 +54,7 @@ func createGCPProvider(ctx *pulumi.Context, name string) (*gcp.Provider, error)
Credentials: pulumi.String(credentials),
})
}

return nil, nil
}

Expand Down
2 changes: 0 additions & 2 deletions internal/api/handlers/v0/auth/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,6 @@ func TestDefaultHTTPKeyFetcher(t *testing.T) {
}
}


func TestHTTPAuthHandler_Permissions(t *testing.T) {
cfg := &config.Config{
JWTPrivateKey: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
Expand Down Expand Up @@ -738,4 +737,3 @@ func TestHTTPvsDNS_PermissionDifferences(t *testing.T) {
})
}
}

4 changes: 2 additions & 2 deletions internal/api/handlers/v0/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg *

// Prevent undeleting servers - once deleted, they stay deleted
if currentServer.Meta.Official != nil &&
currentServer.Meta.Official.Status == model.StatusDeleted &&
newStatus != model.StatusDeleted {
currentServer.Meta.Official.Status == model.StatusDeleted &&
newStatus != model.StatusDeleted {
return nil, huma.Error400BadRequest("Cannot change status of deleted server. Deleted servers cannot be undeleted.")
}

Expand Down
2 changes: 1 addition & 1 deletion internal/api/handlers/v0/edit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -639,4 +639,4 @@ func TestEditServerEndpointEdgeCases(t *testing.T) {
// Helper function
func stringPtr(s string) *string {
return &s
}
}
4 changes: 2 additions & 2 deletions internal/api/handlers/v0/publish.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ func buildPermissionErrorMessage(attemptedResource string, permissions []auth.Pe
permissionStrs = append(permissionStrs, perm.ResourcePattern)
}
}

errorMsg := "You do not have permission to publish this server"
if len(permissionStrs) > 0 {
errorMsg += ". You have permission to publish: " + strings.Join(permissionStrs, ", ")
} else {
errorMsg += ". You do not have any publish permissions"
}
errorMsg += ". Attempting to publish: " + attemptedResource

return errorMsg
}
10 changes: 5 additions & 5 deletions internal/api/handlers/v0/publish_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ func TestPublishIntegration(t *testing.T) {

t.Run("publish fails with invalid token", func(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "io.github.domdomegg/test-server",
Description: "Test server",
Version: "1.0.0",
Name: "io.github.domdomegg/test-server",
Description: "Test server",
Version: "1.0.0",
}

body, err := json.Marshal(publishReq)
Expand All @@ -185,7 +185,7 @@ func TestPublishIntegration(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "io.github.other/test-server",
Description: "A test server",
Version: "1.0.0",
Version: "1.0.0",
Repository: model.Repository{
URL: "https://github.com/example/test-server",
Source: "github",
Expand Down Expand Up @@ -221,7 +221,7 @@ func TestPublishIntegration(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "io.github.domdomegg/airtable-mcp-server",
Description: "A test server with MCPB package",
Version: "1.7.2",
Version: "1.7.2",
Packages: []model.Package{
{
RegistryType: model.RegistryTypeMCPB,
Expand Down
8 changes: 4 additions & 4 deletions internal/api/handlers/v0/publish_registry_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestPublishRegistryValidation(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "com.example/test-server-with-npm",
Description: "A test server with invalid npm package reference",
Version: "1.0.0",
Version: "1.0.0",
Packages: []model.Package{
{
RegistryType: model.RegistryTypeNPM,
Expand Down Expand Up @@ -88,7 +88,7 @@ func TestPublishRegistryValidation(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "com.example/test-server-mcpb-validation",
Description: "A test server with MCPB package and registry validation enabled",
Version: "0.0.36",
Version: "0.0.36",
Packages: []model.Package{
{
RegistryType: model.RegistryTypeMCPB,
Expand Down Expand Up @@ -138,7 +138,7 @@ func TestPublishRegistryValidation(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "com.example/test-server-multiple-packages",
Description: "A test server with multiple packages where second fails",
Version: "1.0.0",
Version: "1.0.0",
Packages: []model.Package{
{
RegistryType: model.RegistryTypeMCPB,
Expand Down Expand Up @@ -189,7 +189,7 @@ func TestPublishRegistryValidation(t *testing.T) {
publishReq := apiv0.ServerJSON{
Name: "com.example/test-server-first-package-fails",
Description: "A test server where first package fails",
Version: "1.0.0",
Version: "1.0.0",
Packages: []model.Package{
{
RegistryType: model.RegistryTypeNPM,
Expand Down
20 changes: 10 additions & 10 deletions internal/api/handlers/v0/publish_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ func TestPublishEndpoint(t *testing.T) {
{
name: "invalid authorization header format",
requestBody: apiv0.ServerJSON{
Name: "io.github.domdomegg/test-server",
Description: "Test server",
Version: "1.0.0",
Name: "io.github.domdomegg/test-server",
Description: "Test server",
Version: "1.0.0",
},
authHeader: "InvalidFormat",
setupRegistryService: func(_ service.RegistryService) {
Expand All @@ -129,7 +129,7 @@ func TestPublishEndpoint(t *testing.T) {
requestBody: apiv0.ServerJSON{
Name: "test-server",
Description: "A test server",
Version: "1.0.0",
Version: "1.0.0",
},
authHeader: "Bearer invalidToken",
setupRegistryService: func(_ service.RegistryService) {
Expand All @@ -143,7 +143,7 @@ func TestPublishEndpoint(t *testing.T) {
requestBody: apiv0.ServerJSON{
Name: "io.github.other/test-server",
Description: "A test server",
Version: "1.0.0",
Version: "1.0.0",
Repository: model.Repository{
URL: "https://github.com/example/test-server",
Source: "github",
Expand All @@ -167,7 +167,7 @@ func TestPublishEndpoint(t *testing.T) {
requestBody: apiv0.ServerJSON{
Name: "example/test-server",
Description: "A test server",
Version: "1.0.0",
Version: "1.0.0",
Repository: model.Repository{
URL: "https://github.com/example/test-server",
Source: "github",
Expand All @@ -185,7 +185,7 @@ func TestPublishEndpoint(t *testing.T) {
existingServer := apiv0.ServerJSON{
Name: "example/test-server",
Description: "Existing test server",
Version: "1.0.0",
Version: "1.0.0",
Repository: model.Repository{
URL: "https://github.com/example/test-server-existing",
Source: "github",
Expand All @@ -202,7 +202,7 @@ func TestPublishEndpoint(t *testing.T) {
requestBody: apiv0.ServerJSON{
Name: "com.example/test-server-mcpb",
Description: "A test server with MCPB package",
Version: "1.0.0",
Version: "1.0.0",
Packages: []model.Package{
{
RegistryType: model.RegistryTypeMCPB,
Expand Down Expand Up @@ -499,7 +499,7 @@ func TestPublishEndpoint_MultipleSlashesEdgeCases(t *testing.T) {
mux.ServeHTTP(rr, req)

// Assertions
assert.Equal(t, tc.expectedStatus, rr.Code,
assert.Equal(t, tc.expectedStatus, rr.Code,
"%s: expected status %d, got %d", tc.description, tc.expectedStatus, rr.Code)

if tc.expectedStatus == http.StatusBadRequest {
Expand All @@ -508,4 +508,4 @@ func TestPublishEndpoint_MultipleSlashesEdgeCases(t *testing.T) {
}
})
}
}
}
1 change: 1 addition & 0 deletions internal/api/handlers/v0/servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type ServerVersionsInput struct {
}

// RegisterServersEndpoints registers all server-related endpoints
//
//nolint:cyclop // Multiple endpoint registrations are inherently complex
func RegisterServersEndpoints(api huma.API, registry service.RegistryService) {
// List servers endpoint
Expand Down
2 changes: 1 addition & 1 deletion internal/api/handlers/v0/servers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -509,4 +509,4 @@ func TestServersEndpointEdgeCases(t *testing.T) {
assert.Contains(t, []model.Status{model.StatusActive, model.StatusDeprecated, model.StatusDeleted}, server.Meta.Official.Status)
}
})
}
}
4 changes: 2 additions & 2 deletions internal/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ func TrailingSlashMiddleware(next http.Handler) http.Handler {
// Create a copy of the URL and remove the trailing slash
newURL := *r.URL
newURL.Path = strings.TrimSuffix(r.URL.Path, "/")

// Use 308 Permanent Redirect to preserve the request method
http.Redirect(w, r, newURL.String(), http.StatusPermanentRedirect)
return
}

next.ServeHTTP(w, r)
})
}
Expand Down
2 changes: 1 addition & 1 deletion internal/auth/blocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ var BlockedNamespaces = []string{
// Add blocked namespaces here, e.g.:
// "io.github.spammer",
// "com.evil-domain",
}
}
16 changes: 8 additions & 8 deletions internal/auth/jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,9 +300,9 @@ func TestJWTManager_BlockedNamespaces(t *testing.T) {
originalBlocked := auth.BlockedNamespaces
auth.BlockedNamespaces = []string{"io.github.spammer"}
defer func() { auth.BlockedNamespaces = originalBlocked }()

jwtManager := auth.NewJWTManager(cfg)

claims := auth.JWTClaims{
AuthMethod: auth.MethodGitHubAT,
AuthMethodSubject: "spammer",
Expand All @@ -325,9 +325,9 @@ func TestJWTManager_BlockedNamespaces(t *testing.T) {
originalBlocked := auth.BlockedNamespaces
auth.BlockedNamespaces = []string{"io.github.spammer"}
defer func() { auth.BlockedNamespaces = originalBlocked }()

jwtManager := auth.NewJWTManager(cfg)

claims := auth.JWTClaims{
AuthMethod: auth.MethodGitHubAT,
AuthMethodSubject: "gooduser",
Expand All @@ -349,9 +349,9 @@ func TestJWTManager_BlockedNamespaces(t *testing.T) {
originalBlocked := auth.BlockedNamespaces
auth.BlockedNamespaces = []string{"io.github.badorg"}
defer func() { auth.BlockedNamespaces = originalBlocked }()

jwtManager := auth.NewJWTManager(cfg)

claims := auth.JWTClaims{
AuthMethod: auth.MethodGitHubAT,
AuthMethodSubject: "user",
Expand All @@ -378,9 +378,9 @@ func TestJWTManager_BlockedNamespaces(t *testing.T) {
originalBlocked := auth.BlockedNamespaces
auth.BlockedNamespaces = []string{"io.github.spammer"}
defer func() { auth.BlockedNamespaces = originalBlocked }()

jwtManager := auth.NewJWTManager(cfg)

claims := auth.JWTClaims{
AuthMethod: auth.MethodNone,
AuthMethodSubject: "admin",
Expand Down
2 changes: 1 addition & 1 deletion internal/auth/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ const (
MethodHTTP Method = "http"
// No authentication - should only be used for local development and testing
MethodNone Method = "none"
)
)
18 changes: 9 additions & 9 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import (
// Config holds the application configuration
// See .env.example for more documentation
type Config struct {
ServerAddress string `env:"SERVER_ADDRESS" envDefault:":8080"`
DatabaseURL string `env:"DATABASE_URL" envDefault:"postgres://localhost:5432/mcp-registry?sslmode=disable"`
SeedFrom string `env:"SEED_FROM" envDefault:""`
Version string `env:"VERSION" envDefault:"dev"`
GithubClientID string `env:"GITHUB_CLIENT_ID" envDefault:""`
GithubClientSecret string `env:"GITHUB_CLIENT_SECRET" envDefault:""`
JWTPrivateKey string `env:"JWT_PRIVATE_KEY" envDefault:""`
EnableAnonymousAuth bool `env:"ENABLE_ANONYMOUS_AUTH" envDefault:"false"`
EnableRegistryValidation bool `env:"ENABLE_REGISTRY_VALIDATION" envDefault:"true"`
ServerAddress string `env:"SERVER_ADDRESS" envDefault:":8080"`
DatabaseURL string `env:"DATABASE_URL" envDefault:"postgres://localhost:5432/mcp-registry?sslmode=disable"`
SeedFrom string `env:"SEED_FROM" envDefault:""`
Version string `env:"VERSION" envDefault:"dev"`
GithubClientID string `env:"GITHUB_CLIENT_ID" envDefault:""`
GithubClientSecret string `env:"GITHUB_CLIENT_SECRET" envDefault:""`
JWTPrivateKey string `env:"JWT_PRIVATE_KEY" envDefault:""`
EnableAnonymousAuth bool `env:"ENABLE_ANONYMOUS_AUTH" envDefault:"false"`
EnableRegistryValidation bool `env:"ENABLE_REGISTRY_VALIDATION" envDefault:"true"`

// OIDC Configuration
OIDCEnabled bool `env:"OIDC_ENABLED" envDefault:"false"`
Expand Down
Loading
Loading