Skip to content

Commit 7c98ed8

Browse files
committed
Improve error handling, timeout and remove unused constants
Signed-off-by: Radoslav Dimitrov <[email protected]>
1 parent ff35d12 commit 7c98ed8

File tree

3 files changed

+23
-10
lines changed

3 files changed

+23
-10
lines changed

internal/validators/registries/oci.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"log"
88
"net/http"
99
"strings"
10+
"time"
1011

1112
"github.com/google/go-containerregistry/pkg/authn"
1213
"github.com/google/go-containerregistry/pkg/name"
@@ -75,23 +76,37 @@ func ValidateOCI(ctx context.Context, pkg model.Package, serverName string) erro
7576
return fmt.Errorf("%w: %s", ErrUnsupportedRegistry, registry)
7677
}
7778

79+
// Add explicit timeout to prevent hanging on slow registries
80+
// Use a new context with timeout to avoid modifying the caller's context
81+
timeoutCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
82+
defer cancel()
83+
7884
// Fetch the image using anonymous authentication (public images only)
7985
// The go-containerregistry library handles:
8086
// - OCI auth discovery via WWW-Authenticate headers
8187
// - Token negotiation for different registries
8288
// - Rate limiting and retries
8389
// - Multi-arch manifest resolution
84-
img, err := remote.Image(ref, remote.WithAuth(authn.Anonymous), remote.WithContext(ctx))
90+
img, err := remote.Image(ref, remote.WithAuth(authn.Anonymous), remote.WithContext(timeoutCtx))
8591
if err != nil {
86-
// Check if this is a rate limiting error
92+
// Check if this is a timeout error
93+
if errors.Is(err, context.DeadlineExceeded) {
94+
return fmt.Errorf("OCI image validation timed out after 30 seconds for '%s'. The registry may be slow or unreachable", pkg.Identifier)
95+
}
96+
97+
// Check for specific HTTP status codes
8798
var transportErr *transport.Error
8899
if errors.As(err, &transportErr) {
89-
if transportErr.StatusCode == http.StatusTooManyRequests {
100+
switch transportErr.StatusCode {
101+
case http.StatusTooManyRequests:
102+
// Rate limited - skip validation to avoid blocking publishers
103+
// This is intentional: we prioritize UX over strict validation during high traffic
90104
log.Printf("Skipping OCI validation for %s due to rate limiting", pkg.Identifier)
91105
return nil
92-
}
93-
if transportErr.StatusCode == http.StatusNotFound || transportErr.StatusCode == http.StatusUnauthorized {
94-
return fmt.Errorf("OCI image '%s' not found or not accessible (status: %d)", pkg.Identifier, transportErr.StatusCode)
106+
case http.StatusNotFound:
107+
return fmt.Errorf("OCI image '%s' does not exist in the registry", pkg.Identifier)
108+
case http.StatusUnauthorized, http.StatusForbidden:
109+
return fmt.Errorf("OCI image '%s' is private or requires authentication. Only public images are supported", pkg.Identifier)
95110
}
96111
}
97112
return fmt.Errorf("failed to fetch OCI image: %w", err)

internal/validators/validators_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,10 +1628,10 @@ func TestValidate_RegistryTypesAndUrls(t *testing.T) {
16281628
// Invalid registry types (should fail)
16291629
{"invalid_maven", "io.github.domdomegg/airtable-mcp-server", "maven", model.RegistryURLNPM, "airtable-mcp-server", "1.7.2", "", true},
16301630
{"invalid_cargo", "io.github.domdomegg/time-mcp-pypi", "cargo", model.RegistryURLPyPI, "time-mcp-pypi", "1.0.1", "", true},
1631-
{"invalid_gem", "io.github.domdomegg/airtable-mcp-server", "gem", model.RegistryURLDocker, "domdomegg/airtable-mcp-server", "1.7.2", "", true},
1631+
{"invalid_gem", "io.github.domdomegg/airtable-mcp-server", "gem", "", "domdomegg/airtable-mcp-server", "1.7.2", "", true},
16321632
{"invalid_unknown", "io.github.domdomegg/time-mcp-server", "unknown", model.RegistryURLNuGet, "TimeMcpServer", "1.0.2", "", true},
16331633
{"invalid_blank", "io.github.domdomegg/time-mcp-server", "", model.RegistryURLNuGet, "TimeMcpServer", "1.0.2", "", true},
1634-
{"invalid_docker", "io.github.domdomegg/airtable-mcp-server", "docker", model.RegistryURLDocker, "domdomegg/airtable-mcp-server", "1.7.2", "", true}, // should be oci
1634+
{"invalid_docker", "io.github.domdomegg/airtable-mcp-server", "docker", "", "domdomegg/airtable-mcp-server", "1.7.2", "", true}, // should be oci
16351635
{"invalid_github", "io.github.domdomegg/airtable-mcp-server", "github", model.RegistryURLGitHub, "https://github.com/domdomegg/airtable-mcp-server/releases/download/v1.7.2/airtable-mcp-server.mcpb", "1.7.2", "", true}, // should be mcpb
16361636

16371637
{"invalid_mix_1", "io.github.domdomegg/time-mcp-server", model.RegistryTypeNuGet, model.RegistryURLNPM, "TimeMcpServer", "1.0.2", "", true},

pkg/model/constants.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ const (
1313
const (
1414
RegistryURLNPM = "https://registry.npmjs.org"
1515
RegistryURLPyPI = "https://pypi.org"
16-
RegistryURLDocker = "https://docker.io"
17-
RegistryURLGHCR = "https://ghcr.io"
1816
RegistryURLNuGet = "https://api.nuget.org"
1917
RegistryURLGitHub = "https://github.com"
2018
RegistryURLGitLab = "https://gitlab.com"

0 commit comments

Comments
 (0)