A container registry that uses the AT Protocol for manifest storage and S3 for blob storage. atcr.io
docker container atproto go

fix pull stats tracking

evan.jarrett.net 1f0705a2 347db5c3

verified
Changed files
+16 -6
pkg
appview
hold
oci
+8
pkg/appview/db/migrations/0007_add_artifact_type.yaml
···
··· 1 + description: Add artifact_type column to manifests table for Helm chart support 2 + query: | 3 + -- Add artifact_type column to track manifest types (container-image, helm-chart, unknown) 4 + -- Default to container-image for existing manifests 5 + ALTER TABLE manifests ADD COLUMN artifact_type TEXT NOT NULL DEFAULT 'container-image'; 6 + 7 + -- Add index for filtering by artifact type 8 + CREATE INDEX IF NOT EXISTS idx_manifests_artifact_type ON manifests(artifact_type);
+8 -6
pkg/hold/oci/xrpc.go
··· 254 return 255 } 256 257 - // Verify user DID matches token 258 - if req.UserDID != validatedUser.DID { 259 - RespondError(w, http.StatusForbidden, "user DID mismatch") 260 - return 261 - } 262 - 263 // Default operation to "push" for backward compatibility 264 operation := req.Operation 265 if operation == "" { ··· 269 // Validate operation 270 if operation != "push" && operation != "pull" { 271 RespondError(w, http.StatusBadRequest, fmt.Sprintf("invalid operation: %s (must be 'push' or 'pull')", operation)) 272 return 273 } 274
··· 254 return 255 } 256 257 // Default operation to "push" for backward compatibility 258 operation := req.Operation 259 if operation == "" { ··· 263 // Validate operation 264 if operation != "push" && operation != "pull" { 265 RespondError(w, http.StatusBadRequest, fmt.Sprintf("invalid operation: %s (must be 'push' or 'pull')", operation)) 266 + return 267 + } 268 + 269 + // Verify user DID matches token - only for pushes 270 + // For pulls: userDID is the repo owner (for stats), but the token belongs to the puller 271 + // This allows anyone to pull from a public repo and have stats tracked under the owner 272 + if operation == "push" && req.UserDID != validatedUser.DID { 273 + RespondError(w, http.StatusForbidden, "user DID mismatch") 274 return 275 } 276