[object Object]

← back to Cli Printing Press

fix(catalog): update stale spec URLs + add download content-validity check (#282)

4a77f46c3dc9965d68e2ae4bbcc3b2002a1a1f9a · 2026-04-25 13:53:57 -0700 · hnshah

Files touched

Diff

commit 4a77f46c3dc9965d68e2ae4bbcc3b2002a1a1f9a
Author: hnshah <hnshah@gmail.com>
Date:   Sat Apr 25 13:53:57 2026 -0700

    fix(catalog): update stale spec URLs + add download content-validity check (#282)
---
 internal/cli/root.go      | 19 +++++++++++++
 internal/cli/root_test.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/internal/cli/root.go b/internal/cli/root.go
index 6a69e3c6..980900e7 100644
--- a/internal/cli/root.go
+++ b/internal/cli/root.go
@@ -9,6 +9,7 @@ import (
 	"net/http"
 	"os"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strings"
 	"time"
@@ -814,6 +815,17 @@ func fetchOrCacheSpec(specURL string, refresh bool, skipCache bool) ([]byte, err
 		return nil, fmt.Errorf("reading response body: %w", err)
 	}
 
+	// Content-validity check: reject responses that look like error pages
+	// instead of feeding them to the parser (which emits confusing errors).
+	if len(data) < 256 {
+		trimmed := strings.TrimSpace(string(data))
+		if strings.HasPrefix(trimmed, "<") ||
+			regexp.MustCompile(`^\d{3}:\s`).MatchString(trimmed) {
+			return nil, fmt.Errorf("spec_url %s returned a small response that does not look like an OpenAPI spec (%d bytes): %q",
+				specURL, len(data), trunc50(trimmed))
+		}
+	}
+
 	if !skipCache {
 		if err := os.MkdirAll(cacheDir, 0o755); err != nil {
 			return nil, fmt.Errorf("creating cache directory: %w", err)
@@ -826,6 +838,13 @@ func fetchOrCacheSpec(specURL string, refresh bool, skipCache bool) ([]byte, err
 	return data, nil
 }
 
+func trunc50(s string) string {
+	if len(s) > 50 {
+		return s[:50] + "..."
+	}
+	return s
+}
+
 func newVersionCmd() *cobra.Command {
 	var asJSON bool
 
diff --git a/internal/cli/root_test.go b/internal/cli/root_test.go
new file mode 100644
index 00000000..fb700dbd
--- /dev/null
+++ b/internal/cli/root_test.go
@@ -0,0 +1,72 @@
+package cli
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"testing"
+)
+
+func TestFetchOrCacheSpec_ContentValidityCheck(t *testing.T) {
+	tests := []struct {
+		name       string
+		body       string
+		statusCode int
+		wantErr    string
+	}{
+		{
+			name:       "small HTML error page",
+			body:       "<html><body>404 Not Found</body></html>",
+			statusCode: 200,
+			wantErr:    "does not look like an OpenAPI spec",
+		},
+		{
+			name:       "small status-text error",
+			body:       "404: Not Found",
+			statusCode: 200,
+			wantErr:    "does not look like an OpenAPI spec",
+		},
+		{
+			name:       "valid large spec passes",
+			body:       "{\"openapi\":\"3.0.0\",\"info\":{\"title\":\"Test\",\"version\":\"1.0\"},\"paths\":{}}" + string(make([]byte, 300)),
+			statusCode: 200,
+			wantErr:    "",
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				w.WriteHeader(tc.statusCode)
+				w.Write([]byte(tc.body))
+			}))
+			defer srv.Close()
+
+			_, err := fetchOrCacheSpec(srv.URL, true, true)
+			if tc.wantErr == "" {
+				if err != nil {
+					t.Fatalf("expected no error, got: %v", err)
+				}
+			} else {
+				if err == nil {
+					t.Fatalf("expected error containing %q, got nil", tc.wantErr)
+				}
+				if !contains(err.Error(), tc.wantErr) {
+					t.Fatalf("expected error containing %q, got: %v", tc.wantErr, err)
+				}
+			}
+		})
+	}
+}
+
+func contains(s, sub string) bool {
+	return len(s) >= len(sub) && (s == sub || len(sub) == 0 || searchString(s, sub))
+}
+
+func searchString(s, sub string) bool {
+	for i := 0; i <= len(s)-len(sub); i++ {
+		if s[i:i+len(sub)] == sub {
+			return true
+		}
+	}
+	return false
+}

← 6ed197c4 fix(cli): make firstCommandExample helper promotion-aware (#  ·  back to Cli Printing Press  ·  fix(cli): gate publishing on transcendence features (#293) ac74e7d2 →