← 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
M internal/cli/root.goA internal/cli/root_test.go
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 →