diff --git a/pkg/appview/middleware/registry.go b/pkg/appview/middleware/registry.go index 056e66c..3a4092b 100644 --- a/pkg/appview/middleware/registry.go +++ b/pkg/appview/middleware/registry.go @@ -170,6 +170,15 @@ func (nr *NamespaceResolver) Repository(ctx context.Context, name reference.Name } ctx = context.WithValue(ctx, holdDIDKey, holdDID) + // Auto-reconcile crew membership on first push/pull + // This ensures users can push immediately after docker login without web sign-in + // EnsureCrewMembership is best-effort and logs errors without failing the request + if holdDID != "" && nr.refresher != nil { + fmt.Printf("DEBUG [registry/middleware]: Auto-reconciling crew membership for DID=%s at hold=%s\n", did, holdDID) + client := atproto.NewClient(pdsEndpoint, did, "") + storage.EnsureCrewMembership(ctx, client, nr.refresher, holdDID) + } + // Get service token for hold authentication var serviceToken string if nr.refresher != nil { diff --git a/pkg/appview/storage/proxy_blob_store.go b/pkg/appview/storage/proxy_blob_store.go index a51d8bd..e3a8241 100644 --- a/pkg/appview/storage/proxy_blob_store.go +++ b/pkg/appview/storage/proxy_blob_store.go @@ -87,7 +87,8 @@ func (p *ProxyBlobStore) checkReadAccess(ctx context.Context) error { return fmt.Errorf("authorization check failed: %w", err) } if !allowed { - return distribution.ErrBlobUnknown // Return same error as missing blob for security + // Return 403 Forbidden instead of masquerading as missing blob + return errcode.ErrorCodeDenied.WithMessage("read access denied") } return nil } @@ -106,7 +107,7 @@ func (p *ProxyBlobStore) checkWriteAccess(ctx context.Context) error { } if !allowed { fmt.Printf("[checkWriteAccess] Write access DENIED for userDID=%s to holdDID=%s\n", p.ctx.DID, p.ctx.HoldDID) - return fmt.Errorf("write access denied to hold %s", p.ctx.HoldDID) + return errcode.ErrorCodeDenied.WithMessage(fmt.Sprintf("write access denied to hold %s", p.ctx.HoldDID)) } fmt.Printf("[checkWriteAccess] Write access ALLOWED for userDID=%s to holdDID=%s\n", p.ctx.DID, p.ctx.HoldDID) return nil