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

Configure Feed

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

cbor_gen crew

+370 -47
+32
gen/main.go
··· 1 + package main 2 + 3 + // CBOR Code Generator 4 + // 5 + // This generates optimized CBOR marshaling code for ATProto records. 6 + // 7 + // Usage: 8 + // go run gen/main.go 9 + // 10 + // This creates pkg/hold/pds/cbor_gen.go which should be committed to git. 11 + // Only re-run when you modify types in pkg/hold/pds/types.go 12 + 13 + import ( 14 + "fmt" 15 + "os" 16 + 17 + cbg "github.com/whyrusleeping/cbor-gen" 18 + 19 + "atcr.io/pkg/hold/pds" 20 + ) 21 + 22 + func main() { 23 + // Generate map-style encoders for CrewRecord 24 + if err := cbg.WriteMapEncodersToFile("pkg/hold/pds/cbor_gen.go", "pds", 25 + pds.CrewRecord{}, 26 + ); err != nil { 27 + fmt.Printf("Failed to generate CBOR encoders: %v\n", err) 28 + os.Exit(1) 29 + } 30 + 31 + fmt.Println("Generated CBOR encoders in pkg/hold/pds/cbor_gen.go") 32 + }
+3 -3
go.mod
··· 11 11 github.com/google/uuid v1.6.0 12 12 github.com/gorilla/mux v1.8.1 13 13 github.com/gorilla/websocket v1.5.3 14 + github.com/ipfs/go-cid v0.4.1 14 15 github.com/klauspost/compress v1.18.0 15 16 github.com/mattn/go-sqlite3 v1.14.32 16 17 github.com/opencontainers/go-digest v1.0.0 17 18 github.com/spf13/cobra v1.8.0 19 + github.com/whyrusleeping/cbor-gen v0.3.1 18 20 go.yaml.in/yaml/v4 v4.0.0-rc.2 19 21 golang.org/x/crypto v0.39.0 20 - github.com/ipfs/go-cid v0.4.1 22 + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 21 23 ) 22 24 23 25 require ( ··· 100 102 github.com/sirupsen/logrus v1.9.3 // indirect 101 103 github.com/spaolacci/murmur3 v1.1.0 // indirect 102 104 github.com/spf13/pflag v1.0.5 // indirect 103 - github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e // indirect 104 105 gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect 105 106 gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect 106 107 go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 // indirect ··· 133 134 golang.org/x/sys v0.33.0 // indirect 134 135 golang.org/x/text v0.26.0 // indirect 135 136 golang.org/x/time v0.6.0 // indirect 136 - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect 137 137 google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect 138 138 google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect 139 139 google.golang.org/grpc v1.68.0 // indirect
+2 -2
go.sum
··· 370 370 github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= 371 371 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= 372 372 github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= 373 - github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e h1:28X54ciEwwUxyHn9yrZfl5ojgF4CBNLWX7LR0rvBkf4= 374 - github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= 373 + github.com/whyrusleeping/cbor-gen v0.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0= 374 + github.com/whyrusleeping/cbor-gen v0.3.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= 375 375 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 376 376 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 377 377 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+1 -1
pkg/hold/authorization.go
··· 163 163 log.Printf("Warning: failed to resolve handle for DID %s: %v", did, err) 164 164 // Continue checking explicit DIDs even if handle resolution fails 165 165 handleResolved = true // Mark as attempted (don't retry) 166 - handle = "" // Empty handle won't match patterns 166 + handle = "" // Empty handle won't match patterns 167 167 } else { 168 168 handleResolved = true 169 169 }
+295
pkg/hold/pds/cbor_gen.go
··· 1 + // Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT. 2 + 3 + package pds 4 + 5 + import ( 6 + "fmt" 7 + "io" 8 + "math" 9 + "sort" 10 + 11 + cid "github.com/ipfs/go-cid" 12 + cbg "github.com/whyrusleeping/cbor-gen" 13 + xerrors "golang.org/x/xerrors" 14 + ) 15 + 16 + var _ = xerrors.Errorf 17 + var _ = cid.Undef 18 + var _ = math.E 19 + var _ = sort.Sort 20 + 21 + func (t *CrewRecord) MarshalCBOR(w io.Writer) error { 22 + if t == nil { 23 + _, err := w.Write(cbg.CborNull) 24 + return err 25 + } 26 + 27 + cw := cbg.NewCborWriter(w) 28 + 29 + if _, err := cw.Write([]byte{165}); err != nil { 30 + return err 31 + } 32 + 33 + // t.Role (string) (string) 34 + if len("role") > 8192 { 35 + return xerrors.Errorf("Value in field \"role\" was too long") 36 + } 37 + 38 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("role"))); err != nil { 39 + return err 40 + } 41 + if _, err := cw.WriteString(string("role")); err != nil { 42 + return err 43 + } 44 + 45 + if len(t.Role) > 8192 { 46 + return xerrors.Errorf("Value in field t.Role was too long") 47 + } 48 + 49 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Role))); err != nil { 50 + return err 51 + } 52 + if _, err := cw.WriteString(string(t.Role)); err != nil { 53 + return err 54 + } 55 + 56 + // t.Type (string) (string) 57 + if len("$type") > 8192 { 58 + return xerrors.Errorf("Value in field \"$type\" was too long") 59 + } 60 + 61 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil { 62 + return err 63 + } 64 + if _, err := cw.WriteString(string("$type")); err != nil { 65 + return err 66 + } 67 + 68 + if len(t.Type) > 8192 { 69 + return xerrors.Errorf("Value in field t.Type was too long") 70 + } 71 + 72 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Type))); err != nil { 73 + return err 74 + } 75 + if _, err := cw.WriteString(string(t.Type)); err != nil { 76 + return err 77 + } 78 + 79 + // t.Member (string) (string) 80 + if len("member") > 8192 { 81 + return xerrors.Errorf("Value in field \"member\" was too long") 82 + } 83 + 84 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("member"))); err != nil { 85 + return err 86 + } 87 + if _, err := cw.WriteString(string("member")); err != nil { 88 + return err 89 + } 90 + 91 + if len(t.Member) > 8192 { 92 + return xerrors.Errorf("Value in field t.Member was too long") 93 + } 94 + 95 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Member))); err != nil { 96 + return err 97 + } 98 + if _, err := cw.WriteString(string(t.Member)); err != nil { 99 + return err 100 + } 101 + 102 + // t.AddedAt (string) (string) 103 + if len("addedAt") > 8192 { 104 + return xerrors.Errorf("Value in field \"addedAt\" was too long") 105 + } 106 + 107 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("addedAt"))); err != nil { 108 + return err 109 + } 110 + if _, err := cw.WriteString(string("addedAt")); err != nil { 111 + return err 112 + } 113 + 114 + if len(t.AddedAt) > 8192 { 115 + return xerrors.Errorf("Value in field t.AddedAt was too long") 116 + } 117 + 118 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.AddedAt))); err != nil { 119 + return err 120 + } 121 + if _, err := cw.WriteString(string(t.AddedAt)); err != nil { 122 + return err 123 + } 124 + 125 + // t.Permissions ([]string) (slice) 126 + if len("permissions") > 8192 { 127 + return xerrors.Errorf("Value in field \"permissions\" was too long") 128 + } 129 + 130 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("permissions"))); err != nil { 131 + return err 132 + } 133 + if _, err := cw.WriteString(string("permissions")); err != nil { 134 + return err 135 + } 136 + 137 + if len(t.Permissions) > 8192 { 138 + return xerrors.Errorf("Slice value in field t.Permissions was too long") 139 + } 140 + 141 + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Permissions))); err != nil { 142 + return err 143 + } 144 + for _, v := range t.Permissions { 145 + if len(v) > 8192 { 146 + return xerrors.Errorf("Value in field v was too long") 147 + } 148 + 149 + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil { 150 + return err 151 + } 152 + if _, err := cw.WriteString(string(v)); err != nil { 153 + return err 154 + } 155 + 156 + } 157 + return nil 158 + } 159 + 160 + func (t *CrewRecord) UnmarshalCBOR(r io.Reader) (err error) { 161 + *t = CrewRecord{} 162 + 163 + cr := cbg.NewCborReader(r) 164 + 165 + maj, extra, err := cr.ReadHeader() 166 + if err != nil { 167 + return err 168 + } 169 + defer func() { 170 + if err == io.EOF { 171 + err = io.ErrUnexpectedEOF 172 + } 173 + }() 174 + 175 + if maj != cbg.MajMap { 176 + return fmt.Errorf("cbor input should be of type map") 177 + } 178 + 179 + if extra > cbg.MaxLength { 180 + return fmt.Errorf("CrewRecord: map struct too large (%d)", extra) 181 + } 182 + 183 + n := extra 184 + 185 + nameBuf := make([]byte, 11) 186 + for i := uint64(0); i < n; i++ { 187 + nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) 188 + if err != nil { 189 + return err 190 + } 191 + 192 + if !ok { 193 + // Field doesn't exist on this type, so ignore it 194 + if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil { 195 + return err 196 + } 197 + continue 198 + } 199 + 200 + switch string(nameBuf[:nameLen]) { 201 + // t.Role (string) (string) 202 + case "role": 203 + 204 + { 205 + sval, err := cbg.ReadStringWithMax(cr, 8192) 206 + if err != nil { 207 + return err 208 + } 209 + 210 + t.Role = string(sval) 211 + } 212 + // t.Type (string) (string) 213 + case "$type": 214 + 215 + { 216 + sval, err := cbg.ReadStringWithMax(cr, 8192) 217 + if err != nil { 218 + return err 219 + } 220 + 221 + t.Type = string(sval) 222 + } 223 + // t.Member (string) (string) 224 + case "member": 225 + 226 + { 227 + sval, err := cbg.ReadStringWithMax(cr, 8192) 228 + if err != nil { 229 + return err 230 + } 231 + 232 + t.Member = string(sval) 233 + } 234 + // t.AddedAt (string) (string) 235 + case "addedAt": 236 + 237 + { 238 + sval, err := cbg.ReadStringWithMax(cr, 8192) 239 + if err != nil { 240 + return err 241 + } 242 + 243 + t.AddedAt = string(sval) 244 + } 245 + // t.Permissions ([]string) (slice) 246 + case "permissions": 247 + 248 + maj, extra, err = cr.ReadHeader() 249 + if err != nil { 250 + return err 251 + } 252 + 253 + if extra > 8192 { 254 + return fmt.Errorf("t.Permissions: array too large (%d)", extra) 255 + } 256 + 257 + if maj != cbg.MajArray { 258 + return fmt.Errorf("expected cbor array") 259 + } 260 + 261 + if extra > 0 { 262 + t.Permissions = make([]string, extra) 263 + } 264 + 265 + for i := 0; i < int(extra); i++ { 266 + { 267 + var maj byte 268 + var extra uint64 269 + var err error 270 + _ = maj 271 + _ = extra 272 + _ = err 273 + 274 + { 275 + sval, err := cbg.ReadStringWithMax(cr, 8192) 276 + if err != nil { 277 + return err 278 + } 279 + 280 + t.Permissions[i] = string(sval) 281 + } 282 + 283 + } 284 + } 285 + 286 + default: 287 + // Field doesn't exist on this type, so ignore it 288 + if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil { 289 + return err 290 + } 291 + } 292 + } 293 + 294 + return nil 295 + }
+2 -26
pkg/hold/pds/crew.go
··· 3 3 import ( 4 4 "context" 5 5 "fmt" 6 - "io" 7 6 "time" 8 7 9 8 "github.com/ipfs/go-cid" 10 9 ) 11 10 12 - // CrewRecord represents a crew member in the hold 13 - type CrewRecord struct { 14 - Member string `json:"member" cborgen:"member"` // DID of the crew member 15 - Role string `json:"role" cborgen:"role"` // "admin" or "member" 16 - Permissions []string `json:"permissions" cborgen:"permissions"` // e.g., ["blob:read", "blob:write"] 17 - AddedAt time.Time `json:"addedAt" cborgen:"addedAt"` 18 - } 19 - 20 - // MarshalCBOR implements cbg.CBORMarshaler 21 - func (c *CrewRecord) MarshalCBOR(w io.Writer) error { 22 - // TODO: Implement proper CBOR marshaling 23 - return fmt.Errorf("CBOR marshaling not yet implemented") 24 - } 25 - 26 - // UnmarshalCBOR implements cbg.CBORUnmarshaler 27 - func (c *CrewRecord) UnmarshalCBOR(r io.Reader) error { 28 - // TODO: Implement proper CBOR unmarshaling 29 - return fmt.Errorf("CBOR unmarshaling not yet implemented") 30 - } 31 - 32 - const ( 33 - CrewCollection = "io.atcr.hold.crew" 34 - ) 35 - 36 11 // AddCrewMember adds a new crew member to the hold and commits to carstore 37 12 func (p *HoldPDS) AddCrewMember(ctx context.Context, memberDID, role string, permissions []string) (cid.Cid, error) { 38 13 crewRecord := &CrewRecord{ 14 + Type: CrewCollection, 39 15 Member: memberDID, 40 16 Role: role, 41 17 Permissions: permissions, 42 - AddedAt: time.Now(), 18 + AddedAt: time.Now().Format(time.RFC3339), 43 19 } 44 20 45 21 // Create record in repo (using memberDID as rkey for easy lookup)
+7 -8
pkg/hold/pds/did.go
··· 9 9 10 10 // DIDDocument represents a did:web document 11 11 type DIDDocument struct { 12 - Context []string `json:"@context"` 13 - ID string `json:"id"` 14 - AlsoKnownAs []string `json:"alsoKnownAs,omitempty"` 15 - VerificationMethod []VerificationMethod `json:"verificationMethod"` 16 - Authentication []string `json:"authentication,omitempty"` 17 - AssertionMethod []string `json:"assertionMethod,omitempty"` 18 - Service []Service `json:"service,omitempty"` 12 + Context []string `json:"@context"` 13 + ID string `json:"id"` 14 + AlsoKnownAs []string `json:"alsoKnownAs,omitempty"` 15 + VerificationMethod []VerificationMethod `json:"verificationMethod"` 16 + Authentication []string `json:"authentication,omitempty"` 17 + AssertionMethod []string `json:"assertionMethod,omitempty"` 18 + Service []Service `json:"service,omitempty"` 19 19 } 20 20 21 21 // VerificationMethod represents a public key in a DID document ··· 82 82 83 83 return doc, nil 84 84 } 85 - 86 85 87 86 // MarshalDIDDocument converts a DID document to JSON using the stored public URL 88 87 func (p *HoldPDS) MarshalDIDDocument() ([]byte, error) {
+9 -4
pkg/hold/pds/server.go
··· 101 101 // Bootstrap initializes the hold with the owner as the first crew member 102 102 func (p *HoldPDS) Bootstrap(ctx context.Context, ownerDID string) error { 103 103 if ownerDID == "" { 104 - // No owner specified, skip bootstrap 105 104 return nil 106 105 } 107 106 108 107 // Check if repo already has commits 109 - _, err := p.carstore.GetUserRepoHead(ctx, p.uid) 108 + head, err := p.carstore.GetUserRepoHead(ctx, p.uid) 110 109 if err == nil { 111 - // Repo already has commits, skip bootstrap 112 - return nil 110 + // Repo exists - check if we need to re-bootstrap due to key change 111 + // If the repo exists but is empty/invalid, we should re-bootstrap 112 + if head.String() == "" || head.String() == "b" { 113 + fmt.Printf("⚠️ Detected invalid repo state, re-bootstrapping...\n") 114 + } else { 115 + fmt.Printf("⏭️ Skipping PDS bootstrap: repo already initialized (head: %s)\n", head.String()[:16]) 116 + return nil 117 + } 113 118 } 114 119 115 120 // Add hold owner as first crew member with admin role
+16
pkg/hold/pds/types.go
··· 1 + package pds 2 + 3 + // ATProto record types for the hold service 4 + 5 + // CrewRecord represents a crew member in the hold 6 + type CrewRecord struct { 7 + Type string `cborgen:"$type"` 8 + Member string `cborgen:"member"` 9 + Role string `cborgen:"role"` 10 + Permissions []string `cborgen:"permissions"` 11 + AddedAt string `cborgen:"addedAt"` // RFC3339 timestamp 12 + } 13 + 14 + const ( 15 + CrewCollection = "io.atcr.hold.crew" 16 + )
+3 -3
pkg/hold/pds/xrpc.go
··· 11 11 12 12 // XRPCHandler handles XRPC requests for the embedded PDS 13 13 type XRPCHandler struct { 14 - pds *HoldPDS 15 - publicURL string 16 - blobStore BlobStore 14 + pds *HoldPDS 15 + publicURL string 16 + blobStore BlobStore 17 17 } 18 18 19 19 // BlobStore interface wraps the existing hold service storage operations