From 2d5039d33c984d4cac17f99cff8d93d92581dbd8 Mon Sep 17 00:00:00 2001 From: Eduardo Cuducos <4732915+cuducos@users.noreply.github.com> Date: Mon, 5 Jan 2026 10:50:38 -0500 Subject: [PATCH] Implements linter for pkg/hold --- .golangci.yml | 11 +++ .tangled/workflows/lint.yaml | 24 +++++++ pkg/hold/pds/xrpc.go | 128 ++++++++++++++++++++++++++++------- 3 files changed, 137 insertions(+), 26 deletions(-) create mode 100644 .tangled/workflows/lint.yaml diff --git a/.golangci.yml b/.golangci.yml index 6a879dd..7df5e82 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,6 +25,17 @@ linters: linters: - errcheck + # TODO: fix issues and remove these paths one by one + - path: pkg/auth + linters: + - errcheck + - path: pkg/appview + linters: + - errcheck + - path: cmd/credential-helper + linters: + - errcheck + formatters: enable: - gofmt diff --git a/.tangled/workflows/lint.yaml b/.tangled/workflows/lint.yaml new file mode 100644 index 0000000..cafefcd --- /dev/null +++ b/.tangled/workflows/lint.yaml @@ -0,0 +1,24 @@ +when: + - event: ["push"] + branch: ["*"] + - event: ["pull_request"] + branch: ["main"] + +engine: kubernetes +image: golang:1.25-trixie +architecture: amd64 + +steps: + - name: Download and Generate + environment: + CGO_ENABLED: 1 + command: | + go mod download + go generate ./... + + - name: Run Linter + environment: + CGO_ENABLED: 1 + command: | + curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.7.2 + golangci-lint run ./... diff --git a/pkg/hold/pds/xrpc.go b/pkg/hold/pds/xrpc.go index 7fd7d4d..8f0c62a 100644 --- a/pkg/hold/pds/xrpc.go +++ b/pkg/hold/pds/xrpc.go @@ -207,7 +207,10 @@ func (h *XRPCHandler) HandleHealth(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleDescribeServer returns server metadata @@ -227,7 +230,10 @@ func (h *XRPCHandler) HandleDescribeServer(w http.ResponseWriter, r *http.Reques } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleResolveHandle resolves a handle to a DID @@ -255,7 +261,10 @@ func (h *XRPCHandler) HandleResolveHandle(w http.ResponseWriter, r *http.Request } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleGetProfile returns aggregated profile information @@ -290,7 +299,10 @@ func (h *XRPCHandler) HandleGetProfile(w http.ResponseWriter, r *http.Request) { response := h.buildProfileResponse(r.Context()) w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleGetProfiles returns aggregated profile information for multiple actors @@ -341,7 +353,10 @@ func (h *XRPCHandler) HandleGetProfiles(w http.ResponseWriter, r *http.Request) } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // buildProfileResponse builds a profile response map (shared by GetProfile and GetProfiles) @@ -435,7 +450,10 @@ func (h *XRPCHandler) HandleDescribeRepo(w http.ResponseWriter, r *http.Request) } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleGetRecord retrieves a record from the repository @@ -479,7 +497,10 @@ func (h *XRPCHandler) HandleGetRecord(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleListRecords lists records in a collection @@ -551,7 +572,10 @@ func (h *XRPCHandler) handleListRecordsIndexed(w http.ResponseWriter, r *http.Re // Empty repo, return empty list response := map[string]any{"records": []any{}} w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } @@ -598,7 +622,10 @@ func (h *XRPCHandler) handleListRecordsIndexed(w http.ResponseWriter, r *http.Re } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // handleListRecordsMST uses the legacy MST-based listing (fallback for tests) @@ -620,7 +647,10 @@ func (h *XRPCHandler) handleListRecordsMST(w http.ResponseWriter, r *http.Reques // Empty repo, return empty list response := map[string]any{"records": []any{}} w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } @@ -729,7 +759,10 @@ func (h *XRPCHandler) handleListRecordsMST(w http.ResponseWriter, r *http.Reques } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleDeleteRecord deletes a record from the repository @@ -799,10 +832,14 @@ func (h *XRPCHandler) HandleDeleteRecord(w http.ResponseWriter, r *http.Request) if !currentCID.Equals(swapRecordCID) { // Swap failed - record CID doesn't match w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(map[string]any{ + response := map[string]any{ "error": "InvalidSwap", "message": "record CID does not match swapRecord", - }) + } + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } } @@ -846,7 +883,10 @@ func (h *XRPCHandler) HandleDeleteRecord(w http.ResponseWriter, r *http.Request) } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleSyncGetRecord returns a single record as a CAR file for sync @@ -900,7 +940,10 @@ func (h *XRPCHandler) HandleSyncGetRecord(w http.ResponseWriter, r *http.Request } // Write the CAR data to the response - w.Write(buf.Bytes()) + if _, err := w.Write(buf.Bytes()); err != nil { + slog.Error("failed to write car to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleGetRepo returns the full repository as a CAR file @@ -1063,7 +1106,10 @@ func (h *XRPCHandler) HandleUploadBlob(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleGetBlob routes blob requests to appropriate handlers based on blob type @@ -1139,7 +1185,10 @@ func (h *XRPCHandler) handleGetOCIBlob(w http.ResponseWriter, r *http.Request, d "url": presignedURL, } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // handleGetATProtoBlob handles standard ATProto blob requests @@ -1193,7 +1242,10 @@ func (h *XRPCHandler) HandleListRepos(w http.ResponseWriter, r *http.Request) { "repos": []any{}, } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } @@ -1205,7 +1257,10 @@ func (h *XRPCHandler) HandleListRepos(w http.ResponseWriter, r *http.Request) { "repos": []any{}, } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } @@ -1223,7 +1278,10 @@ func (h *XRPCHandler) HandleListRepos(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleGetRepoStatus returns the hosting status for a repository @@ -1252,7 +1310,10 @@ func (h *XRPCHandler) HandleGetRepoStatus(w http.ResponseWriter, r *http.Request "active": true, } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } @@ -1264,7 +1325,10 @@ func (h *XRPCHandler) HandleGetRepoStatus(w http.ResponseWriter, r *http.Request } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleDIDDocument returns the DID document @@ -1276,7 +1340,10 @@ func (h *XRPCHandler) HandleDIDDocument(w http.ResponseWriter, r *http.Request) } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(doc) + if err := json.NewEncoder(w).Encode(doc); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // HandleAtprotoDID returns the DID for handle resolution @@ -1375,7 +1442,10 @@ func (h *XRPCHandler) HandleRequestCrew(w http.ResponseWriter, r *http.Request) } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } return } } @@ -1408,7 +1478,10 @@ func (h *XRPCHandler) HandleRequestCrew(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) - json.NewEncoder(w).Encode(response) + if err := json.NewEncoder(w).Encode(response); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } } // GetPresignedURL generates a presigned URL for GET, HEAD, or PUT operations @@ -1546,5 +1619,8 @@ func (h *XRPCHandler) HandleGetQuota(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(stats) + if err := json.NewEncoder(w).Encode(stats); err != nil { + slog.Error("failed to encode json to http response", "error", err, "path", r.URL.Path) + w.WriteHeader(http.StatusInternalServerError) + } }