A container registry that uses the AT Protocol for manifest storage and S3 for blob storage.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

try new permission sets

+74 -36
+27
lexicons/io/atcr/authFullApp.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "io.atcr.authFullApp", 4 + "defs": { 5 + "main": { 6 + "type": "permission-set", 7 + "title": "AT Container Registry", 8 + "title:langs": {}, 9 + "detail": "Push and pull container images to the ATProto Container Registry. Includes creating and managing image manifests, tags, and repository settings.", 10 + "detail:langs": {}, 11 + "permissions": [ 12 + { 13 + "type": "permission", 14 + "resource": "repo", 15 + "action": ["create", "update", "delete"], 16 + "collection": ["io.atcr.manifest", "io.atcr.tag", "io.atcr.sailor.star", "io.atcr.sailor.profile", "io.atcr.repo.page"] 17 + }, 18 + { 19 + "type": "permission", 20 + "resource": "rpc", 21 + "lxm": ["com.atproto.repo.getRecord"], 22 + "aud": "*" 23 + } 24 + ] 25 + } 26 + } 27 + }
+4 -2
lexicons/io/atcr/hold/captain.json
··· 34 34 }, 35 35 "region": { 36 36 "type": "string", 37 - "description": "S3 region where blobs are stored" 37 + "description": "S3 region where blobs are stored", 38 + "maxLength": 64 38 39 }, 39 40 "provider": { 40 41 "type": "string", 41 - "description": "Deployment provider (e.g., fly.io, aws, etc.)" 42 + "description": "Deployment provider (e.g., fly.io, aws, etc.)", 43 + "maxLength": 64 42 44 } 43 45 } 44 46 }
+4 -2
lexicons/io/atcr/hold/crew.json
··· 18 18 "role": { 19 19 "type": "string", 20 20 "description": "Member's role in the hold", 21 - "knownValues": ["owner", "admin", "write", "read"] 21 + "knownValues": ["owner", "admin", "write", "read"], 22 + "maxLength": 32 22 23 }, 23 24 "permissions": { 24 25 "type": "array", 25 26 "description": "Specific permissions granted to this member", 26 27 "items": { 27 - "type": "string" 28 + "type": "string", 29 + "maxLength": 64 28 30 } 29 31 }, 30 32 "addedAt": {
+6 -3
lexicons/io/atcr/hold/layer.json
··· 12 12 "properties": { 13 13 "digest": { 14 14 "type": "string", 15 - "description": "Layer digest (e.g., sha256:abc123...)" 15 + "description": "Layer digest (e.g., sha256:abc123...)", 16 + "maxLength": 128 16 17 }, 17 18 "size": { 18 19 "type": "integer", ··· 20 21 }, 21 22 "mediaType": { 22 23 "type": "string", 23 - "description": "Media type (e.g., application/vnd.oci.image.layer.v1.tar+gzip)" 24 + "description": "Media type (e.g., application/vnd.oci.image.layer.v1.tar+gzip)", 25 + "maxLength": 128 24 26 }, 25 27 "repository": { 26 28 "type": "string", 27 - "description": "Repository this layer belongs to" 29 + "description": "Repository this layer belongs to", 30 + "maxLength": 255 28 31 }, 29 32 "userDid": { 30 33 "type": "string",
+22 -11
lexicons/io/atcr/manifest.json
··· 17 17 }, 18 18 "digest": { 19 19 "type": "string", 20 - "description": "Content digest (e.g., 'sha256:abc123...')" 20 + "description": "Content digest (e.g., 'sha256:abc123...')", 21 + "maxLength": 128 21 22 }, 22 23 "holdDid": { 23 24 "type": "string", ··· 37 38 "application/vnd.docker.distribution.manifest.v2+json", 38 39 "application/vnd.oci.image.index.v1+json", 39 40 "application/vnd.docker.distribution.manifest.list.v2+json" 40 - ] 41 + ], 42 + "maxLength": 128 41 43 }, 42 44 "schemaVersion": { 43 45 "type": "integer", ··· 92 94 "properties": { 93 95 "mediaType": { 94 96 "type": "string", 95 - "description": "MIME type of the blob" 97 + "description": "MIME type of the blob", 98 + "maxLength": 128 96 99 }, 97 100 "size": { 98 101 "type": "integer", ··· 100 103 }, 101 104 "digest": { 102 105 "type": "string", 103 - "description": "Content digest (e.g., 'sha256:...')" 106 + "description": "Content digest (e.g., 'sha256:...')", 107 + "maxLength": 128 104 108 }, 105 109 "urls": { 106 110 "type": "array", ··· 123 127 "properties": { 124 128 "mediaType": { 125 129 "type": "string", 126 - "description": "Media type of the referenced manifest" 130 + "description": "Media type of the referenced manifest", 131 + "maxLength": 128 127 132 }, 128 133 "size": { 129 134 "type": "integer", ··· 131 136 }, 132 137 "digest": { 133 138 "type": "string", 134 - "description": "Content digest (e.g., 'sha256:...')" 139 + "description": "Content digest (e.g., 'sha256:...')", 140 + "maxLength": 128 135 141 }, 136 142 "platform": { 137 143 "type": "ref", ··· 151 157 "properties": { 152 158 "architecture": { 153 159 "type": "string", 154 - "description": "CPU architecture (e.g., 'amd64', 'arm64', 'arm')" 160 + "description": "CPU architecture (e.g., 'amd64', 'arm64', 'arm')", 161 + "maxLength": 32 155 162 }, 156 163 "os": { 157 164 "type": "string", 158 - "description": "Operating system (e.g., 'linux', 'windows', 'darwin')" 165 + "description": "Operating system (e.g., 'linux', 'windows', 'darwin')", 166 + "maxLength": 32 159 167 }, 160 168 "osVersion": { 161 169 "type": "string", 162 - "description": "Optional OS version" 170 + "description": "Optional OS version", 171 + "maxLength": 64 163 172 }, 164 173 "osFeatures": { 165 174 "type": "array", 166 175 "items": { 167 - "type": "string" 176 + "type": "string", 177 + "maxLength": 64 168 178 }, 169 179 "description": "Optional OS features" 170 180 }, 171 181 "variant": { 172 182 "type": "string", 173 - "description": "Optional CPU variant (e.g., 'v7' for ARM)" 183 + "description": "Optional CPU variant (e.g., 'v7' for ARM)", 184 + "maxLength": 32 174 185 } 175 186 } 176 187 }
+2 -1
lexicons/io/atcr/tag.json
··· 27 27 }, 28 28 "manifestDigest": { 29 29 "type": "string", 30 - "description": "DEPRECATED: Digest of the manifest (e.g., 'sha256:...'). Kept for backward compatibility with old records. New records should use 'manifest' field instead." 30 + "description": "DEPRECATED: Digest of the manifest (e.g., 'sha256:...'). Kept for backward compatibility with old records. New records should use 'manifest' field instead.", 31 + "maxLength": 128 31 32 }, 32 33 "createdAt": { 33 34 "type": "string",
+9 -17
pkg/auth/oauth/client.go
··· 72 72 return baseURL + "/auth/oauth/callback" 73 73 } 74 74 75 - // GetDefaultScopes returns the default OAuth scopes for ATCR registry operations 76 - // testMode determines whether to use transition:generic (test) or rpc scopes (production) 75 + // GetDefaultScopes returns the default OAuth scopes for ATCR registry operations. 76 + // Uses io.atcr.permissions#registry permission-set to bundle repo and rpc scopes. 77 + // Blob scopes are listed explicitly (not supported in Lexicon permission-sets). 77 78 func GetDefaultScopes(did string) []string { 78 - scopes := []string{ 79 + return []string{ 79 80 "atproto", 80 - // Used for service token validation on holds 81 - "rpc:com.atproto.repo.getRecord?aud=*", 81 + // Permission-set bundles repo and rpc scopes 82 + // See lexicons/io/atcr/authFullApp.json for definition 83 + "io.atcr.authFullApp", 84 + // Blob scopes (not supported in Lexicon permission-sets) 82 85 // Image manifest types (single-arch) 83 86 "blob:application/vnd.oci.image.manifest.v1+json", 84 87 "blob:application/vnd.docker.distribution.manifest.v2+json", ··· 87 90 "blob:application/vnd.docker.distribution.manifest.list.v2+json", 88 91 // OCI artifact manifests (for cosign signatures, SBOMs, attestations) 89 92 "blob:application/vnd.cncf.oras.artifact.manifest.v1+json", 90 - // image avatars 93 + // Image avatars 91 94 "blob:image/*", 92 95 } 93 - 94 - // Add repo scopes 95 - scopes = append(scopes, 96 - fmt.Sprintf("repo:%s", atproto.ManifestCollection), 97 - fmt.Sprintf("repo:%s", atproto.TagCollection), 98 - fmt.Sprintf("repo:%s", atproto.StarCollection), 99 - fmt.Sprintf("repo:%s", atproto.SailorProfileCollection), 100 - fmt.Sprintf("repo:%s", atproto.RepoPageCollection), 101 - ) 102 - 103 - return scopes 104 96 } 105 97 106 98 // ScopesMatch checks if two scope lists are equivalent (order-independent)