diff --git a/cmd/help/openapi-normalize/main.go b/cmd/help/openapi-normalize/main.go index c69c8b0a1b..d0e48acbc3 100644 --- a/cmd/help/openapi-normalize/main.go +++ b/cmd/help/openapi-normalize/main.go @@ -13,7 +13,7 @@ import ( "strings" "unicode" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) var requiredFields = map[string][]string{ diff --git a/cmd/help/openapi-normalize/main_test.go b/cmd/help/openapi-normalize/main_test.go index e0fa408a71..1d59efb188 100644 --- a/cmd/help/openapi-normalize/main_test.go +++ b/cmd/help/openapi-normalize/main_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) func TestNormalizeJSONAndYAMLDeterministically(t *testing.T) { diff --git a/cmd/thv-operator/app/warning_handler_test.go b/cmd/thv-operator/app/warning_handler_test.go index 81fade16e5..b76be2b256 100644 --- a/cmd/thv-operator/app/warning_handler_test.go +++ b/cmd/thv-operator/app/warning_handler_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "k8s.io/client-go/rest" crtlog "sigs.k8s.io/controller-runtime/pkg/log" ) diff --git a/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig.go b/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig.go index f5d4d6d8b8..69eb1f3ee7 100644 --- a/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig.go +++ b/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig.go @@ -8,7 +8,7 @@ import ( stderrors "errors" "fmt" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/log" @@ -98,7 +98,7 @@ func (r *VirtualMCPServerReconciler) ensureVmcpConfigConfigMap( } // Marshal the serializable Config to YAML for storage in ConfigMap. - // Note: gopkg.in/yaml.v3 produces deterministic output by sorting map keys alphabetically. + // Note: go.yaml.in/yaml/v3 produces deterministic output by sorting map keys alphabetically. // This ensures stable checksums for triggering pod rollouts only when content actually changes. vmcpConfigYAML, err := yaml.Marshal(config) if err != nil { diff --git a/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go b/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go index e086925d65..b2ea075793 100644 --- a/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go +++ b/cmd/thv-operator/controllers/virtualmcpserver_vmcpconfig_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" diff --git a/cmd/thv/app/llm_test.go b/cmd/thv/app/llm_test.go index b9cbf34bba..b2eab72d69 100644 --- a/cmd/thv/app/llm_test.go +++ b/cmd/thv/app/llm_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/client" "github.com/stacklok/toolhive/pkg/config" diff --git a/go.mod b/go.mod index f3d1fa0f35..d982221745 100644 --- a/go.mod +++ b/go.mod @@ -88,6 +88,7 @@ require ( go.starlark.net v0.0.0-20260908191801-89a6a09411d5 go.uber.org/mock v0.6.0 go.uber.org/zap v1.28.0 + go.yaml.in/yaml/v3 v3.0.5 golang.ngrok.com/ngrok/v2 v2.2.1 golang.org/x/crypto v0.58.0 golang.org/x/exp/jsonrpc2 v0.0.0-20261014143641-f0251eb4aa3e @@ -326,7 +327,6 @@ require ( go.uber.org/atomic v1.12.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect - go.yaml.in/yaml/v3 v3.0.5 // indirect golang.ngrok.com/muxado/v2 v2.0.1 // indirect golang.org/x/exp v0.0.0-20261014143641-f0251eb4aa3e // indirect golang.org/x/exp/event v0.0.0-20261009195045-ca0d7ba23607 // indirect diff --git a/pkg/api/v1/registry_factory_test.go b/pkg/api/v1/registry_factory_test.go index dc40a181d9..1ae8d7a0e2 100644 --- a/pkg/api/v1/registry_factory_test.go +++ b/pkg/api/v1/registry_factory_test.go @@ -15,7 +15,7 @@ import ( "github.com/go-chi/chi/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/config" "github.com/stacklok/toolhive/pkg/registry" diff --git a/pkg/authserver/config_test.go b/pkg/authserver/config_test.go index 426397e7b8..2ed0167302 100644 --- a/pkg/authserver/config_test.go +++ b/pkg/authserver/config_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" servercrypto "github.com/stacklok/toolhive/pkg/authserver/server/crypto" "github.com/stacklok/toolhive/pkg/authserver/server/keys" diff --git a/pkg/authserver/inbound_grants_test.go b/pkg/authserver/inbound_grants_test.go index f1dd8fb8ae..82d8e1a6fa 100644 --- a/pkg/authserver/inbound_grants_test.go +++ b/pkg/authserver/inbound_grants_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/authserver/server/tokenexchange" ) diff --git a/pkg/authserver/runner/embeddedauthserver_test.go b/pkg/authserver/runner/embeddedauthserver_test.go index b7f13961b0..19f039d1c4 100644 --- a/pkg/authserver/runner/embeddedauthserver_test.go +++ b/pkg/authserver/runner/embeddedauthserver_test.go @@ -30,7 +30,7 @@ import ( "github.com/ory/fosite" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/authserver" servercrypto "github.com/stacklok/toolhive/pkg/authserver/server/crypto" diff --git a/pkg/client/config.go b/pkg/client/config.go index 38f761a9e5..0442ad0fde 100644 --- a/pkg/client/config.go +++ b/pkg/client/config.go @@ -18,7 +18,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/tailscale/hujson" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/llmgateway" "github.com/stacklok/toolhive/pkg/transport/types" diff --git a/pkg/client/config_editor.go b/pkg/client/config_editor.go index 66058b5014..6a4a1cc8fd 100644 --- a/pkg/client/config_editor.go +++ b/pkg/client/config_editor.go @@ -44,7 +44,7 @@ import ( "github.com/pelletier/go-toml/v2" "github.com/tailscale/hujson" "github.com/tidwall/gjson" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/fileutils" ) diff --git a/pkg/client/config_editor_test.go b/pkg/client/config_editor_test.go index bcd816d4c7..5df9ebde45 100644 --- a/pkg/client/config_editor_test.go +++ b/pkg/client/config_editor_test.go @@ -15,7 +15,7 @@ import ( "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/tidwall/gjson" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) func TestUpsertMCPServer(t *testing.T) { diff --git a/pkg/config/config.go b/pkg/config/config.go index 7151912793..48b3a434e1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -15,7 +15,7 @@ import ( "time" "github.com/adrg/xdg" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive-core/env" "github.com/stacklok/toolhive/pkg/container/templates" diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 67f92e2012..8f91229060 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive-core/env/mocks" "github.com/stacklok/toolhive/pkg/secrets" diff --git a/pkg/config/interface_test.go b/pkg/config/interface_test.go index 5a6b5e20b0..a11add5bf6 100644 --- a/pkg/config/interface_test.go +++ b/pkg/config/interface_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) func TestNewDefaultProvider(t *testing.T) { diff --git a/pkg/json/any.go b/pkg/json/any.go index da21aa6496..3ad2916bc6 100644 --- a/pkg/json/any.go +++ b/pkg/json/any.go @@ -11,7 +11,7 @@ import ( stdjson "encoding/json" "fmt" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // Data stores JSON-compatible data of type T. It supports both JSON and YAML diff --git a/pkg/llm/manage_test.go b/pkg/llm/manage_test.go index 4acc2068b7..a8401b9db2 100644 --- a/pkg/llm/manage_test.go +++ b/pkg/llm/manage_test.go @@ -15,7 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/secrets" secretsmocks "github.com/stacklok/toolhive/pkg/secrets/mocks" diff --git a/pkg/registry/api/client.go b/pkg/registry/api/client.go index 910f2a5e11..9eb02baf0c 100644 --- a/pkg/registry/api/client.go +++ b/pkg/registry/api/client.go @@ -14,7 +14,7 @@ import ( "net/url" v0 "github.com/modelcontextprotocol/registry/pkg/api/v0" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/registry/auth" "github.com/stacklok/toolhive/pkg/versions" diff --git a/pkg/registry/api/client_test.go b/pkg/registry/api/client_test.go new file mode 100644 index 0000000000..108a235253 --- /dev/null +++ b/pkg/registry/api/client_test.go @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. +// SPDX-License-Identifier: Apache-2.0 + +package api + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestClient_ValidateEndpoint(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + body string + wantErr bool + }{ + { + name: "valid registry spec", + body: "info:\n version: 1.0.0\n description: See https://github.com/modelcontextprotocol/registry\n", + }, + { + name: "wrong version", + body: "info:\n version: 2.0.0\n description: See https://github.com/modelcontextprotocol/registry\n", + wantErr: true, + }, + { + name: "missing info section", + body: "openapi: 3.0.0\n", + wantErr: true, + }, + { + // Mapping-valued key combined with a merge key panicked gopkg.in/yaml.v3. + name: "merge key with mapping-valued key", + body: "? {a: b}\n: c\n<<: {name: x}\n", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + require.Equal(t, "/openapi.yaml", r.URL.Path) + _, _ = w.Write([]byte(tt.body)) + })) + t.Cleanup(server.Close) + + client, err := NewClient(server.URL, true, nil) + require.NoError(t, err) + + err = client.ValidateEndpoint(t.Context()) + if tt.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + }) + } +} diff --git a/pkg/registry/factory_test.go b/pkg/registry/factory_test.go index fbbe665cf2..dd9b9ed754 100644 --- a/pkg/registry/factory_test.go +++ b/pkg/registry/factory_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/config" ) diff --git a/pkg/runner/config_test.go b/pkg/runner/config_test.go index c06987574a..34fc8312cd 100644 --- a/pkg/runner/config_test.go +++ b/pkg/runner/config_test.go @@ -18,7 +18,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive-core/permissions" regtypes "github.com/stacklok/toolhive-core/registry/types" diff --git a/pkg/runner/middleware_test.go b/pkg/runner/middleware_test.go index 9c4ea128c7..27991a6902 100644 --- a/pkg/runner/middleware_test.go +++ b/pkg/runner/middleware_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1beta1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1beta1" diff --git a/pkg/runner/session_tls_test.go b/pkg/runner/session_tls_test.go index a9495ab0b5..7db40c3eac 100644 --- a/pkg/runner/session_tls_test.go +++ b/pkg/runner/session_tls_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" v1beta1 "github.com/stacklok/toolhive/cmd/thv-operator/api/v1beta1" diff --git a/pkg/skills/lockfile/lockfile.go b/pkg/skills/lockfile/lockfile.go index d404d327fc..f95232796b 100644 --- a/pkg/skills/lockfile/lockfile.go +++ b/pkg/skills/lockfile/lockfile.go @@ -28,7 +28,7 @@ import ( "slices" "strings" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/fileutils" "github.com/stacklok/toolhive/pkg/skills" diff --git a/pkg/transport/tunnel/ngrok/tunnel_provider.go b/pkg/transport/tunnel/ngrok/tunnel_provider.go index c22fcf3329..60818eab97 100644 --- a/pkg/transport/tunnel/ngrok/tunnel_provider.go +++ b/pkg/transport/tunnel/ngrok/tunnel_provider.go @@ -12,8 +12,8 @@ import ( "path/filepath" "strings" + "go.yaml.in/yaml/v3" "golang.ngrok.com/ngrok/v2" - "gopkg.in/yaml.v3" ) // TunnelProvider implements the TunnelProvider interface for ngrok. diff --git a/pkg/vmcp/cli/auth_server_config_test.go b/pkg/vmcp/cli/auth_server_config_test.go index 885635a1b0..4562669c32 100644 --- a/pkg/vmcp/cli/auth_server_config_test.go +++ b/pkg/vmcp/cli/auth_server_config_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" authserverconfig "github.com/stacklok/toolhive/pkg/authserver" ) diff --git a/pkg/vmcp/cli/init.go b/pkg/vmcp/cli/init.go index c7bee6417b..10bb94a33d 100644 --- a/pkg/vmcp/cli/init.go +++ b/pkg/vmcp/cli/init.go @@ -14,7 +14,7 @@ import ( "strings" "text/template" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" groupval "github.com/stacklok/toolhive-core/validation/group" "github.com/stacklok/toolhive/pkg/fileutils" @@ -131,7 +131,7 @@ func Init(ctx context.Context, cfg InitConfig) error { } // yamlScalar marshals a string to a properly quoted/escaped YAML scalar value -// using gopkg.in/yaml.v3, ensuring characters like '#' or ':' in names and +// using go.yaml.in/yaml/v3, ensuring characters like '#' or ':' in names and // URLs do not corrupt the rendered YAML. func yamlScalar(v string) (string, error) { b, err := yaml.Marshal(v) diff --git a/pkg/vmcp/cli/serve.go b/pkg/vmcp/cli/serve.go index 4c86836f83..0807e86771 100644 --- a/pkg/vmcp/cli/serve.go +++ b/pkg/vmcp/cli/serve.go @@ -18,7 +18,7 @@ import ( "time" "go.opentelemetry.io/otel/trace" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "k8s.io/client-go/rest" "github.com/stacklok/toolhive-core/env" diff --git a/pkg/vmcp/cli/serve_test.go b/pkg/vmcp/cli/serve_test.go index f28704878a..f042d34c66 100644 --- a/pkg/vmcp/cli/serve_test.go +++ b/pkg/vmcp/cli/serve_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" authserverconfig "github.com/stacklok/toolhive/pkg/authserver" authserverrunner "github.com/stacklok/toolhive/pkg/authserver/runner" diff --git a/pkg/vmcp/config/crd_cli_roundtrip_test.go b/pkg/vmcp/config/crd_cli_roundtrip_test.go index 30d12c9a81..b374ccfe53 100644 --- a/pkg/vmcp/config/crd_cli_roundtrip_test.go +++ b/pkg/vmcp/config/crd_cli_roundtrip_test.go @@ -9,7 +9,7 @@ import ( "testing" "go.uber.org/mock/gomock" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive-core/env/mocks" thvjson "github.com/stacklok/toolhive/pkg/json" diff --git a/pkg/vmcp/config/session_tls_test.go b/pkg/vmcp/config/session_tls_test.go index b5fe3f8a08..1b182b1493 100644 --- a/pkg/vmcp/config/session_tls_test.go +++ b/pkg/vmcp/config/session_tls_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/redisconfig" "github.com/stacklok/toolhive/pkg/vmcp" diff --git a/pkg/vmcp/config/yaml_loader.go b/pkg/vmcp/config/yaml_loader.go index dc6a6d9bb6..9bd9e59a75 100644 --- a/pkg/vmcp/config/yaml_loader.go +++ b/pkg/vmcp/config/yaml_loader.go @@ -9,7 +9,7 @@ import ( "os" "time" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive-core/env" authtypes "github.com/stacklok/toolhive/pkg/vmcp/auth/types" diff --git a/pkg/webhook/config.go b/pkg/webhook/config.go index 88c08faec9..8ba6cec617 100644 --- a/pkg/webhook/config.go +++ b/pkg/webhook/config.go @@ -11,7 +11,7 @@ import ( "path/filepath" "strings" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" ) // FileConfig is the top-level structure for a webhook configuration file. diff --git a/test/e2e/api_secrets_test.go b/test/e2e/api_secrets_test.go index 8f1fb10993..4be396ba5f 100644 --- a/test/e2e/api_secrets_test.go +++ b/test/e2e/api_secrets_test.go @@ -12,7 +12,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/test/e2e" ) diff --git a/test/e2e/cli_llm_setup_test.go b/test/e2e/cli_llm_setup_test.go index fb2d2c23de..2b0d266552 100644 --- a/test/e2e/cli_llm_setup_test.go +++ b/test/e2e/cli_llm_setup_test.go @@ -15,7 +15,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive/pkg/llm" "github.com/stacklok/toolhive/test/e2e" diff --git a/test/e2e/vmcp_cli_features_test.go b/test/e2e/vmcp_cli_features_test.go index 41dff597fb..8bc13989b2 100644 --- a/test/e2e/vmcp_cli_features_test.go +++ b/test/e2e/vmcp_cli_features_test.go @@ -18,7 +18,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "gopkg.in/yaml.v3" + "go.yaml.in/yaml/v3" "github.com/stacklok/toolhive-core/mcpcompat/mcp" thvjson "github.com/stacklok/toolhive/pkg/json"