add labels to the manifest annotations

This commit is contained in:
Evan Jarrett
2025-10-07 21:09:33 -05:00
parent de60510097
commit 261f1d6547
2 changed files with 58 additions and 5 deletions
+54 -4
View File
@@ -1,6 +1,7 @@
package atproto
import (
"maps"
"context"
"encoding/json"
"fmt"
@@ -15,18 +16,20 @@ import (
type ManifestStore struct {
client *Client
repository string
holdEndpoint string // Hold service endpoint where blobs are stored (for push)
did string // User's DID for cache key
lastFetchedHoldEndpoint string // Hold endpoint from most recently fetched manifest (for pull)
holdEndpoint string // Hold service endpoint where blobs are stored (for push)
did string // User's DID for cache key
lastFetchedHoldEndpoint string // Hold endpoint from most recently fetched manifest (for pull)
blobStore distribution.BlobStore // Blob store for fetching config during push
}
// NewManifestStore creates a new ATProto-backed manifest store
func NewManifestStore(client *Client, repository string, holdEndpoint string, did string) *ManifestStore {
func NewManifestStore(client *Client, repository string, holdEndpoint string, did string, blobStore distribution.BlobStore) *ManifestStore {
return &ManifestStore{
client: client,
repository: repository,
holdEndpoint: holdEndpoint,
did: did,
blobStore: blobStore,
}
}
@@ -116,6 +119,25 @@ func (s *ManifestStore) Put(ctx context.Context, manifest distribution.Manifest,
manifestRecord.ManifestBlob = blobRef
manifestRecord.HoldEndpoint = s.holdEndpoint
// Extract Dockerfile labels from config blob and add to annotations
if s.blobStore != nil && manifestRecord.Config.Digest != "" {
labels, err := s.extractConfigLabels(ctx, manifestRecord.Config.Digest)
if err != nil {
// Log error but don't fail the push - labels are optional
fmt.Printf("WARNING: Failed to extract config labels: %v\n", err)
} else {
// Initialize annotations map if needed
if manifestRecord.Annotations == nil {
manifestRecord.Annotations = make(map[string]string)
}
// Copy labels to annotations (Dockerfile LABELs → manifest annotations)
maps.Copy(manifestRecord.Annotations, labels)
fmt.Printf("DEBUG: Extracted %d labels from config blob\n", len(labels))
}
}
// Store manifest record in ATProto
rkey := digestToRKey(dgst)
_, err = s.client.PutRecord(ctx, ManifestCollection, rkey, manifestRecord)
@@ -185,3 +207,31 @@ func (m *rawManifest) References() []distribution.Descriptor {
func (m *rawManifest) Payload() (string, []byte, error) {
return m.mediaType, m.payload, nil
}
// extractConfigLabels fetches the image config blob and extracts Dockerfile LABELs
func (s *ManifestStore) extractConfigLabels(ctx context.Context, configDigestStr string) (map[string]string, error) {
// Parse digest string
configDigest, err := digest.Parse(configDigestStr)
if err != nil {
return nil, fmt.Errorf("invalid config digest: %w", err)
}
// Fetch config blob from storage
configData, err := s.blobStore.Get(ctx, configDigest)
if err != nil {
return nil, fmt.Errorf("failed to fetch config blob: %w", err)
}
// Parse config JSON
var configJSON struct {
Config struct {
Labels map[string]string `json:"Labels"`
} `json:"config"`
}
if err := json.Unmarshal(configData, &configJSON); err != nil {
return nil, fmt.Errorf("failed to parse config JSON: %w", err)
}
return configJSON.Config.Labels, nil
}
+4 -1
View File
@@ -42,7 +42,10 @@ func NewRoutingRepository(
func (r *RoutingRepository) Manifests(ctx context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
// Create or return cached manifest store
if r.manifestStore == nil {
r.manifestStore = atproto.NewManifestStore(r.atprotoClient, r.repositoryName, r.storageEndpoint, r.did)
// Ensure blob store is created first (needed for label extraction during push)
blobStore := r.Blobs(ctx)
r.manifestStore = atproto.NewManifestStore(r.atprotoClient, r.repositoryName, r.storageEndpoint, r.did, blobStore)
}
// After any manifest operation, cache the hold endpoint for blob fetches