more linting fixes

This commit is contained in:
Evan Jarrett
2025-10-24 01:05:19 -05:00
parent dd79b8a0ee
commit 9eb69e2ea7
26 changed files with 110 additions and 23 deletions
+26
View File
@@ -0,0 +1,26 @@
# golangci-lint configuration for ATCR
# See: https://golangci-lint.run/usage/configuration/
version: "2"
linters:
settings:
staticcheck:
checks:
- "all"
- "-SA1019" # Ignore deprecated package warnings for github.com/ipfs/go-ipfs-blockstore
# Cannot upgrade to github.com/ipfs/boxo/blockstore due to opentelemetry
# dependency conflicts with distribution/distribution
errcheck:
exclude-functions:
- (github.com/distribution/distribution/v3/registry/storage/driver.FileWriter).Cancel
- (github.com/distribution/distribution/v3.BlobWriter).Cancel
- (*database/sql.Tx).Rollback
- (*database/sql.Rows).Close
- (*net/http.Server).Shutdown
exclusions:
presets:
- std-error-handling
formatters:
enable:
- gofmt
- goimports
+5
View File
@@ -1,3 +1,8 @@
// Package appview implements the ATCR AppView component, which serves as the main
// OCI Distribution API server. It resolves identities (handle/DID to PDS endpoint),
// routes manifests to user's PDS, routes blobs to hold services, validates OAuth tokens,
// and issues registry JWTs. This package provides environment-based configuration,
// middleware registration, and HTTP server setup for the AppView service.
package appview
import (
+4
View File
@@ -1,3 +1,7 @@
// Package db provides the database layer for the AppView web UI, including
// SQLite schema initialization, migrations, and query functions for OAuth
// sessions, device flows, repository metadata, stars, pull counts, and
// user profiles.
package db
import (
+3
View File
@@ -1,3 +1,6 @@
// Package handlers provides HTTP handlers for the AppView web UI, including
// home page, repository browsing, search, user authentication, settings,
// device management, and API endpoints for the web interface.
package handlers
import (
+3
View File
@@ -1,3 +1,6 @@
// Package holdhealth provides health checking for hold service endpoints.
// It periodically checks hold availability and caches health status with
// configurable TTL to avoid excessive health check requests.
package holdhealth
import (
+3
View File
@@ -131,6 +131,7 @@ func TestGetStatus_CacheHit(t *testing.T) {
status := checker.GetStatus(context.Background(), endpoint)
if status == nil {
t.Fatal("GetStatus returned nil")
return
}
if !status.Reachable {
@@ -155,6 +156,7 @@ func TestGetStatus_CacheMiss(t *testing.T) {
status := checker.GetStatus(context.Background(), server.URL)
if status == nil {
t.Fatal("GetStatus returned nil")
return
}
if !status.Reachable {
@@ -191,6 +193,7 @@ func TestSetStatus(t *testing.T) {
status := checker.GetCachedStatus(endpoint)
if status == nil {
t.Fatal("Status not found in cache")
return
}
if !status.Reachable {
+3
View File
@@ -1,3 +1,6 @@
// Package jetstream provides an ATProto Jetstream consumer for real-time updates.
// It connects to the Bluesky Jetstream WebSocket, processes repository events,
// indexes manifests and tags, and populates the AppView database for the web UI.
package jetstream
import (
+4
View File
@@ -1,3 +1,7 @@
// Package licenses provides SPDX license validation and parsing for container
// image annotations. It embeds the official SPDX license list and provides
// functions to look up license identifiers, validate them, and parse
// multi-license strings with fuzzy matching support.
package licenses
//go:generate curl -fsSL -o spdx-licenses.json https://spdx.org/licenses/licenses.json
+4
View File
@@ -1,3 +1,7 @@
// Package middleware provides HTTP middleware for AppView, including
// authentication (session-based for web UI, token-based for registry),
// identity resolution (handle/DID to PDS endpoint), and hold discovery
// for routing blobs to storage endpoints.
package middleware
import (
+4
View File
@@ -1,3 +1,7 @@
// Package readme provides README fetching, rendering, and caching functionality
// for container repositories. It fetches markdown content from URLs, renders it
// to sanitized HTML using GitHub-flavored markdown, and caches the results in
// a database with configurable TTL.
package readme
import (
+1 -1
View File
@@ -451,7 +451,7 @@ func (p *ProxyBlobStore) getPartUploadInfo(ctx context.Context, digest, uploadID
return nil, err
}
url := fmt.Sprintf("%s%s", p.holdURL, atproto.HoldGetPartUploadUrl)
url := fmt.Sprintf("%s%s", p.holdURL, atproto.HoldGetPartUploadURL)
req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewReader(body))
if err != nil {
return nil, err
+1 -1
View File
@@ -551,7 +551,7 @@ func TestMultipartEndpoints_CorrectURLs(t *testing.T) {
_, err := store.getPartUploadInfo(context.Background(), "sha256:test", "upload-123", 1)
return err
},
expectedPath: atproto.HoldGetPartUploadUrl,
expectedPath: atproto.HoldGetPartUploadURL,
},
{
name: "completeMultipartUpload",
@@ -1,3 +1,7 @@
// Package storage implements the storage routing layer for AppView.
// It routes manifests to ATProto PDS (as io.atcr.manifest records) and
// blobs to hold services via XRPC, with hold DID caching for efficient pulls.
// All storage operations are proxied - AppView stores nothing locally.
package storage
import (
+3 -3
View File
@@ -1,4 +1,4 @@
// Package xrpc provides constants for XRPC endpoint paths used throughout ATCR.
// Package atproto provides constants for XRPC endpoint paths used throughout ATCR.
//
// This package serves as a single source of truth for all XRPC endpoint URLs,
// preventing typos and making refactoring easier. All endpoint paths follow the
@@ -15,11 +15,11 @@ const (
// Response: {"uploadId": "..."}
HoldInitiateUpload = "/xrpc/io.atcr.hold.initiateUpload"
// HoldGetPartUploadUrl gets a presigned URL or endpoint info for uploading a specific part.
// HoldGetPartUploadURL gets a presigned URL or endpoint info for uploading a specific part.
// Method: POST
// Request: {"uploadId": "...", "partNumber": 1}
// Response: {"url": "...", "method": "PUT", "headers": {...}}
HoldGetPartUploadUrl = "/xrpc/io.atcr.hold.getPartUploadUrl"
HoldGetPartUploadURL = "/xrpc/io.atcr.hold.getPartUploadUrl"
// HoldUploadPart handles direct buffered part uploads (alternative to presigned URLs).
// Method: PUT
+1 -1
View File
@@ -9,7 +9,7 @@ import (
"time"
)
// Profile record key is always "self" per lexicon
// ProfileRKey is always "self" per lexicon
const ProfileRKey = "self"
// Global map to track in-flight profile migrations (DID -> true)
+4
View File
@@ -1,3 +1,7 @@
// Package oauth provides OAuth client and flow implementation for ATCR.
// It wraps indigo's OAuth library with ATCR-specific configuration,
// including default scopes, client metadata, token refreshing, and
// interactive browser-based authentication flows.
package oauth
import (
+5 -1
View File
@@ -1,7 +1,9 @@
// Package auth provides authentication and authorization for ATCR, including
// ATProto session validation, hold authorization (captain/crew membership),
// scope parsing, and token caching for OAuth and service tokens.
package auth
import (
"atcr.io/pkg/atproto"
"bytes"
"context"
"crypto/sha256"
@@ -13,6 +15,8 @@ import (
"sync"
"time"
"atcr.io/pkg/atproto"
"github.com/bluesky-social/indigo/atproto/identity"
"github.com/bluesky-social/indigo/atproto/syntax"
)
+4
View File
@@ -1,3 +1,7 @@
// Package token provides service token caching and management for AppView.
// Service tokens are JWTs issued by a user's PDS to authorize AppView to
// act on their behalf when communicating with hold services. Tokens are
// cached with automatic expiry parsing and 10-second safety margins.
package token
import (
+5
View File
@@ -1,3 +1,8 @@
// Package hold implements the ATCR hold service, which provides BYOS
// (Bring Your Own Storage) functionality. It includes an embedded PDS for
// storing captain and crew records, generates presigned URLs for blob storage,
// and handles authorization based on crew membership. Configuration is loaded
// entirely from environment variables.
package hold
import (
+3
View File
@@ -1,3 +1,6 @@
// Package oci provides HTTP helpers for OCI registry endpoints in the hold service.
// It includes utilities for JSON encoding/decoding of request/response bodies
// and standardized error responses for XRPC endpoints.
package oci
import (
+1 -1
View File
@@ -26,7 +26,7 @@ const (
Buffered
)
// CompletedPart represents an uploaded part with its ETag
// PartInfo represents an uploaded part with its ETag
type PartInfo struct {
PartNumber int `json:"part_number"`
ETag string `json:"etag"`
+3 -3
View File
@@ -44,7 +44,7 @@ func (h *XRPCHandler) RegisterHandlers(r chi.Router) {
r.Use(h.requireBlobWriteAccess)
r.Post(atproto.HoldInitiateUpload, h.HandleInitiateUpload)
r.Post(atproto.HoldGetPartUploadUrl, h.HandleGetPartUploadUrl)
r.Post(atproto.HoldGetPartUploadURL, h.HandleGetPartUploadURL)
r.Put(atproto.HoldUploadPart, h.HandleUploadPart)
r.Post(atproto.HoldCompleteUpload, h.HandleCompleteUpload)
r.Post(atproto.HoldAbortUpload, h.HandleAbortUpload)
@@ -80,9 +80,9 @@ func (h *XRPCHandler) HandleInitiateUpload(w http.ResponseWriter, r *http.Reques
})
}
// HandleGetPartUploadUrl returns a presigned URL or endpoint info for uploading a part
// HandleGetPartUploadURL returns a presigned URL or endpoint info for uploading a part
// Replaces the old "action: part" pattern
func (h *XRPCHandler) HandleGetPartUploadUrl(w http.ResponseWriter, r *http.Request) {
func (h *XRPCHandler) HandleGetPartUploadURL(w http.ResponseWriter, r *http.Request) {
var req struct {
UploadID string `json:"uploadId"`
PartNumber int `json:"partNumber"`
+6 -6
View File
@@ -218,14 +218,14 @@ func TestHandleGetPartUploadUrl_Buffered(t *testing.T) {
uploadID := initResp["uploadId"].(string)
// Now get part upload URL
req := makeJSONRequest("POST", atproto.HoldGetPartUploadUrl, map[string]any{
req := makeJSONRequest("POST", atproto.HoldGetPartUploadURL, map[string]any{
"uploadId": uploadID,
"partNumber": 1,
})
addMockAuth(req)
w := httptest.NewRecorder()
handler.HandleGetPartUploadUrl(w, req)
handler.HandleGetPartUploadURL(w, req)
if w.Code != http.StatusOK {
t.Errorf("Expected status 200, got %d: %s", w.Code, w.Body.String())
@@ -246,14 +246,14 @@ func TestHandleGetPartUploadUrl_Buffered(t *testing.T) {
func TestHandleGetPartUploadUrl_InvalidSession(t *testing.T) {
handler, _ := setupTestOCIHandler(t)
req := makeJSONRequest("POST", atproto.HoldGetPartUploadUrl, map[string]any{
req := makeJSONRequest("POST", atproto.HoldGetPartUploadURL, map[string]any{
"uploadId": "invalid-upload-id",
"partNumber": 1,
})
addMockAuth(req)
w := httptest.NewRecorder()
handler.HandleGetPartUploadUrl(w, req)
handler.HandleGetPartUploadURL(w, req)
if w.Code != http.StatusInternalServerError {
t.Errorf("Expected status 500, got %d", w.Code)
@@ -274,11 +274,11 @@ func TestHandleGetPartUploadUrl_MissingParams(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := makeJSONRequest("POST", atproto.HoldGetPartUploadUrl, tt.body)
req := makeJSONRequest("POST", atproto.HoldGetPartUploadURL, tt.body)
addMockAuth(req)
w := httptest.NewRecorder()
handler.HandleGetPartUploadUrl(w, req)
handler.HandleGetPartUploadURL(w, req)
if w.Code != http.StatusBadRequest {
t.Errorf("Expected status 400, got %d", w.Code)
+1 -1
View File
@@ -1250,7 +1250,7 @@ func (rm *RepoManager) TakeDownRepo(ctx context.Context, uid models.Uid) error {
return rm.cs.WipeUserData(ctx, uid)
}
// technically identical to TakeDownRepo, for now
// ResetRepo is technically identical to TakeDownRepo, for now
func (rm *RepoManager) ResetRepo(ctx context.Context, uid models.Uid) error {
unlock := rm.lockUser(ctx, uid)
defer unlock()
+1 -1
View File
@@ -1223,7 +1223,7 @@ func (h *XRPCHandler) HandleRequestCrew(w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(response)
}
// getPresignedURL generates a presigned URL for GET, HEAD, or PUT operations
// GetPresignedURL generates a presigned URL for GET, HEAD, or PUT operations
// Distinguishes between ATProto blobs (per-DID) and OCI blobs (content-addressed)
func (h *XRPCHandler) GetPresignedURL(ctx context.Context, operation string, digest string, did string) (string, error) {
var path string
+8 -4
View File
@@ -1,13 +1,17 @@
// Package s3 provides S3 client initialization and presigned URL generation
// for hold services. It supports S3, Storj, and Minio storage backends,
// with fallback to buffered proxy mode when presigned URLs are unavailable.
package s3
import (
"fmt"
"log"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
"log"
"strings"
)
type S3Service struct {
@@ -16,7 +20,7 @@ type S3Service struct {
PathPrefix string // S3 path prefix (if any)
}
// initializes the S3 client for presigned URL generation
// NewS3Service initializes the S3 client for presigned URL generation
// Returns nil error if S3 client is successfully initialized
// Returns error if storage is not S3 or if initialization fails (service will fall back to proxy mode)
func NewS3Service(params map[string]any, disablePresigned bool, storageType string) (*S3Service, error) {
@@ -85,7 +89,7 @@ func NewS3Service(params map[string]any, disablePresigned bool, storageType stri
}, nil
}
// blobPath converts a digest (e.g., "sha256:abc123...") or temp path to a storage path
// BlobPath converts a digest (e.g., "sha256:abc123...") or temp path to a storage path
// Distribution stores blobs as: /docker/registry/v2/blobs/{algorithm}/{xx}/{hash}/data
// where xx is the first 2 characters of the hash for directory sharding
// NOTE: Path must start with / for filesystem driver