fix(helm-lint): Add HTTP/HTTPS URL support for json schema references

Signed-off-by: Isaiah Lewis <isaiah@roof12.com>
pull/31138/head
Isaiah Lewis 3 weeks ago
parent 36e52c828d
commit fa73b6743b
No known key found for this signature in database
GPG Key ID: 37AA12928D9CE030

@ -21,13 +21,53 @@ import (
"errors"
"fmt"
"log/slog"
"net/http"
"strings"
"time"
"github.com/santhosh-tekuri/jsonschema/v6"
"helm.sh/helm/v4/internal/version"
chart "helm.sh/helm/v4/pkg/chart/v2"
)
// HTTPURLLoader implements a loader for HTTP/HTTPS URLs
type HTTPURLLoader http.Client
func (l *HTTPURLLoader) Load(urlStr string) (any, error) {
client := (*http.Client)(l)
req, err := http.NewRequest(http.MethodGet, urlStr, nil)
if err != nil {
return nil, fmt.Errorf("failed to create HTTP request for %s: %w", urlStr, err)
}
req.Header.Set("User-Agent", version.GetUserAgent())
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("HTTP request failed for %s: %w", urlStr, err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("HTTP request to %s returned status %d (%s)", urlStr, resp.StatusCode, http.StatusText(resp.StatusCode))
}
return jsonschema.UnmarshalJSON(resp.Body)
}
// newHTTPURLLoader creates a HTTP URL loader with proxy support.
func newHTTPURLLoader() *HTTPURLLoader {
httpLoader := HTTPURLLoader(http.Client{
Timeout: 15 * time.Second,
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
},
})
return &httpLoader
}
// ValidateAgainstSchema checks that values does not violate the structure laid out in schema
func ValidateAgainstSchema(chrt *chart.Chart, values map[string]interface{}) error {
var sb strings.Builder
@ -71,7 +111,15 @@ func ValidateAgainstSingleSchema(values Values, schemaJSON []byte) (reterr error
}
slog.Debug("unmarshalled JSON schema", "schema", schemaJSON)
// Configure compiler with loaders for different URL schemes
loader := jsonschema.SchemeURLLoader{
"file": jsonschema.FileLoader{},
"http": newHTTPURLLoader(),
"https": newHTTPURLLoader(),
}
compiler := jsonschema.NewCompiler()
compiler.UseLoader(loader)
err = compiler.AddResource("file:///values.schema.json", schema)
if err != nil {
return err

@ -17,7 +17,10 @@ limitations under the License.
package util
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
chart "helm.sh/helm/v4/pkg/chart/v2"
@ -245,3 +248,40 @@ func TestValidateAgainstSchema2020Negative(t *testing.T) {
t.Errorf("Error string :\n`%s`\ndoes not match expected\n`%s`", errString, expectedErrString)
}
}
func TestHTTPURLLoader_Load(t *testing.T) {
// Test successful JSON schema loading
t.Run("successful load", func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"type": "object", "properties": {"name": {"type": "string"}}}`))
}))
defer server.Close()
loader := newHTTPURLLoader()
result, err := loader.Load(server.URL)
if err != nil {
t.Fatalf("Expected no error, got: %v", err)
}
if result == nil {
t.Fatal("Expected result to be non-nil")
}
})
t.Run("HTTP error status", func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusNotFound)
}))
defer server.Close()
loader := newHTTPURLLoader()
_, err := loader.Load(server.URL)
if err == nil {
t.Fatal("Expected error for HTTP 404")
}
if !strings.Contains(err.Error(), "404") {
t.Errorf("Expected error message to contain '404', got: %v", err)
}
})
}

Loading…
Cancel
Save