mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-29 04:06:58 +00:00
cbor_gen crew
This commit is contained in:
+32
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
// CBOR Code Generator
|
||||
//
|
||||
// This generates optimized CBOR marshaling code for ATProto records.
|
||||
//
|
||||
// Usage:
|
||||
// go run gen/main.go
|
||||
//
|
||||
// This creates pkg/hold/pds/cbor_gen.go which should be committed to git.
|
||||
// Only re-run when you modify types in pkg/hold/pds/types.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
|
||||
"atcr.io/pkg/hold/pds"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Generate map-style encoders for CrewRecord
|
||||
if err := cbg.WriteMapEncodersToFile("pkg/hold/pds/cbor_gen.go", "pds",
|
||||
pds.CrewRecord{},
|
||||
); err != nil {
|
||||
fmt.Printf("Failed to generate CBOR encoders: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println("Generated CBOR encoders in pkg/hold/pds/cbor_gen.go")
|
||||
}
|
||||
@@ -11,13 +11,15 @@ require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/ipfs/go-cid v0.4.1
|
||||
github.com/klauspost/compress v1.18.0
|
||||
github.com/mattn/go-sqlite3 v1.14.32
|
||||
github.com/opencontainers/go-digest v1.0.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/whyrusleeping/cbor-gen v0.3.1
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.2
|
||||
golang.org/x/crypto v0.39.0
|
||||
github.com/ipfs/go-cid v0.4.1
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -100,7 +102,6 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e // indirect
|
||||
gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect
|
||||
gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect
|
||||
go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 // indirect
|
||||
@@ -133,7 +134,6 @@ require (
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/time v0.6.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
|
||||
google.golang.org/grpc v1.68.0 // indirect
|
||||
|
||||
@@ -370,8 +370,8 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSD
|
||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0=
|
||||
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ=
|
||||
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e h1:28X54ciEwwUxyHn9yrZfl5ojgF4CBNLWX7LR0rvBkf4=
|
||||
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so=
|
||||
github.com/whyrusleeping/cbor-gen v0.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0=
|
||||
github.com/whyrusleeping/cbor-gen v0.3.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
|
||||
@@ -163,7 +163,7 @@ func (s *HoldService) isCrewMember(did string) (bool, error) {
|
||||
log.Printf("Warning: failed to resolve handle for DID %s: %v", did, err)
|
||||
// Continue checking explicit DIDs even if handle resolution fails
|
||||
handleResolved = true // Mark as attempted (don't retry)
|
||||
handle = "" // Empty handle won't match patterns
|
||||
handle = "" // Empty handle won't match patterns
|
||||
} else {
|
||||
handleResolved = true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
// Code generated by github.com/whyrusleeping/cbor-gen. DO NOT EDIT.
|
||||
|
||||
package pds
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
cid "github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
xerrors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
var _ = xerrors.Errorf
|
||||
var _ = cid.Undef
|
||||
var _ = math.E
|
||||
var _ = sort.Sort
|
||||
|
||||
func (t *CrewRecord) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
|
||||
cw := cbg.NewCborWriter(w)
|
||||
|
||||
if _, err := cw.Write([]byte{165}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Role (string) (string)
|
||||
if len("role") > 8192 {
|
||||
return xerrors.Errorf("Value in field \"role\" was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("role"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string("role")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(t.Role) > 8192 {
|
||||
return xerrors.Errorf("Value in field t.Role was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Role))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string(t.Role)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Type (string) (string)
|
||||
if len("$type") > 8192 {
|
||||
return xerrors.Errorf("Value in field \"$type\" was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("$type"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string("$type")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(t.Type) > 8192 {
|
||||
return xerrors.Errorf("Value in field t.Type was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Type))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string(t.Type)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Member (string) (string)
|
||||
if len("member") > 8192 {
|
||||
return xerrors.Errorf("Value in field \"member\" was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("member"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string("member")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(t.Member) > 8192 {
|
||||
return xerrors.Errorf("Value in field t.Member was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Member))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string(t.Member)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.AddedAt (string) (string)
|
||||
if len("addedAt") > 8192 {
|
||||
return xerrors.Errorf("Value in field \"addedAt\" was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("addedAt"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string("addedAt")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(t.AddedAt) > 8192 {
|
||||
return xerrors.Errorf("Value in field t.AddedAt was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.AddedAt))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string(t.AddedAt)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Permissions ([]string) (slice)
|
||||
if len("permissions") > 8192 {
|
||||
return xerrors.Errorf("Value in field \"permissions\" was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("permissions"))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string("permissions")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(t.Permissions) > 8192 {
|
||||
return xerrors.Errorf("Slice value in field t.Permissions was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Permissions))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.Permissions {
|
||||
if len(v) > 8192 {
|
||||
return xerrors.Errorf("Value in field v was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(v))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := cw.WriteString(string(v)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *CrewRecord) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
*t = CrewRecord{}
|
||||
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}()
|
||||
|
||||
if maj != cbg.MajMap {
|
||||
return fmt.Errorf("cbor input should be of type map")
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("CrewRecord: map struct too large (%d)", extra)
|
||||
}
|
||||
|
||||
n := extra
|
||||
|
||||
nameBuf := make([]byte, 11)
|
||||
for i := uint64(0); i < n; i++ {
|
||||
nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ok {
|
||||
// Field doesn't exist on this type, so ignore it
|
||||
if err := cbg.ScanForLinks(cr, func(cid.Cid) {}); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch string(nameBuf[:nameLen]) {
|
||||
// t.Role (string) (string)
|
||||
case "role":
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringWithMax(cr, 8192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Role = string(sval)
|
||||
}
|
||||
// t.Type (string) (string)
|
||||
case "$type":
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringWithMax(cr, 8192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Type = string(sval)
|
||||
}
|
||||
// t.Member (string) (string)
|
||||
case "member":
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringWithMax(cr, 8192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Member = string(sval)
|
||||
}
|
||||
// t.AddedAt (string) (string)
|
||||
case "addedAt":
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringWithMax(cr, 8192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.AddedAt = string(sval)
|
||||
}
|
||||
// t.Permissions ([]string) (slice)
|
||||
case "permissions":
|
||||
|
||||
maj, extra, err = cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > 8192 {
|
||||
return fmt.Errorf("t.Permissions: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Permissions = make([]string, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
{
|
||||
var maj byte
|
||||
var extra uint64
|
||||
var err error
|
||||
_ = maj
|
||||
_ = extra
|
||||
_ = err
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadStringWithMax(cr, 8192)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Permissions[i] = string(sval)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// Field doesn't exist on this type, so ignore it
|
||||
if err := cbg.ScanForLinks(r, func(cid.Cid) {}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+2
-26
@@ -3,43 +3,19 @@ package pds
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
)
|
||||
|
||||
// CrewRecord represents a crew member in the hold
|
||||
type CrewRecord struct {
|
||||
Member string `json:"member" cborgen:"member"` // DID of the crew member
|
||||
Role string `json:"role" cborgen:"role"` // "admin" or "member"
|
||||
Permissions []string `json:"permissions" cborgen:"permissions"` // e.g., ["blob:read", "blob:write"]
|
||||
AddedAt time.Time `json:"addedAt" cborgen:"addedAt"`
|
||||
}
|
||||
|
||||
// MarshalCBOR implements cbg.CBORMarshaler
|
||||
func (c *CrewRecord) MarshalCBOR(w io.Writer) error {
|
||||
// TODO: Implement proper CBOR marshaling
|
||||
return fmt.Errorf("CBOR marshaling not yet implemented")
|
||||
}
|
||||
|
||||
// UnmarshalCBOR implements cbg.CBORUnmarshaler
|
||||
func (c *CrewRecord) UnmarshalCBOR(r io.Reader) error {
|
||||
// TODO: Implement proper CBOR unmarshaling
|
||||
return fmt.Errorf("CBOR unmarshaling not yet implemented")
|
||||
}
|
||||
|
||||
const (
|
||||
CrewCollection = "io.atcr.hold.crew"
|
||||
)
|
||||
|
||||
// AddCrewMember adds a new crew member to the hold and commits to carstore
|
||||
func (p *HoldPDS) AddCrewMember(ctx context.Context, memberDID, role string, permissions []string) (cid.Cid, error) {
|
||||
crewRecord := &CrewRecord{
|
||||
Type: CrewCollection,
|
||||
Member: memberDID,
|
||||
Role: role,
|
||||
Permissions: permissions,
|
||||
AddedAt: time.Now(),
|
||||
AddedAt: time.Now().Format(time.RFC3339),
|
||||
}
|
||||
|
||||
// Create record in repo (using memberDID as rkey for easy lookup)
|
||||
|
||||
+7
-8
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
// DIDDocument represents a did:web document
|
||||
type DIDDocument struct {
|
||||
Context []string `json:"@context"`
|
||||
ID string `json:"id"`
|
||||
AlsoKnownAs []string `json:"alsoKnownAs,omitempty"`
|
||||
VerificationMethod []VerificationMethod `json:"verificationMethod"`
|
||||
Authentication []string `json:"authentication,omitempty"`
|
||||
AssertionMethod []string `json:"assertionMethod,omitempty"`
|
||||
Service []Service `json:"service,omitempty"`
|
||||
Context []string `json:"@context"`
|
||||
ID string `json:"id"`
|
||||
AlsoKnownAs []string `json:"alsoKnownAs,omitempty"`
|
||||
VerificationMethod []VerificationMethod `json:"verificationMethod"`
|
||||
Authentication []string `json:"authentication,omitempty"`
|
||||
AssertionMethod []string `json:"assertionMethod,omitempty"`
|
||||
Service []Service `json:"service,omitempty"`
|
||||
}
|
||||
|
||||
// VerificationMethod represents a public key in a DID document
|
||||
@@ -83,7 +83,6 @@ func (p *HoldPDS) GenerateDIDDocument(publicURL string) (*DIDDocument, error) {
|
||||
return doc, nil
|
||||
}
|
||||
|
||||
|
||||
// MarshalDIDDocument converts a DID document to JSON using the stored public URL
|
||||
func (p *HoldPDS) MarshalDIDDocument() ([]byte, error) {
|
||||
doc, err := p.GenerateDIDDocument(p.publicURL)
|
||||
|
||||
@@ -101,15 +101,20 @@ func (p *HoldPDS) SigningKey() *crypto.PrivateKeyK256 {
|
||||
// Bootstrap initializes the hold with the owner as the first crew member
|
||||
func (p *HoldPDS) Bootstrap(ctx context.Context, ownerDID string) error {
|
||||
if ownerDID == "" {
|
||||
// No owner specified, skip bootstrap
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if repo already has commits
|
||||
_, err := p.carstore.GetUserRepoHead(ctx, p.uid)
|
||||
head, err := p.carstore.GetUserRepoHead(ctx, p.uid)
|
||||
if err == nil {
|
||||
// Repo already has commits, skip bootstrap
|
||||
return nil
|
||||
// Repo exists - check if we need to re-bootstrap due to key change
|
||||
// If the repo exists but is empty/invalid, we should re-bootstrap
|
||||
if head.String() == "" || head.String() == "b" {
|
||||
fmt.Printf("⚠️ Detected invalid repo state, re-bootstrapping...\n")
|
||||
} else {
|
||||
fmt.Printf("⏭️ Skipping PDS bootstrap: repo already initialized (head: %s)\n", head.String()[:16])
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Add hold owner as first crew member with admin role
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package pds
|
||||
|
||||
// ATProto record types for the hold service
|
||||
|
||||
// CrewRecord represents a crew member in the hold
|
||||
type CrewRecord struct {
|
||||
Type string `cborgen:"$type"`
|
||||
Member string `cborgen:"member"`
|
||||
Role string `cborgen:"role"`
|
||||
Permissions []string `cborgen:"permissions"`
|
||||
AddedAt string `cborgen:"addedAt"` // RFC3339 timestamp
|
||||
}
|
||||
|
||||
const (
|
||||
CrewCollection = "io.atcr.hold.crew"
|
||||
)
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
|
||||
// XRPCHandler handles XRPC requests for the embedded PDS
|
||||
type XRPCHandler struct {
|
||||
pds *HoldPDS
|
||||
publicURL string
|
||||
blobStore BlobStore
|
||||
pds *HoldPDS
|
||||
publicURL string
|
||||
blobStore BlobStore
|
||||
}
|
||||
|
||||
// BlobStore interface wraps the existing hold service storage operations
|
||||
|
||||
Reference in New Issue
Block a user