From 12935490d4fb6f46b0ca189020690efcdf8ccc8e Mon Sep 17 00:00:00 2001 From: Evan Jarrett Date: Tue, 14 Oct 2025 21:41:14 -0500 Subject: [PATCH] try and create a crew record for the hold owner --- cmd/hold/main.go | 16 ++++++++++++++++ pkg/hold/pds/crew.go | 25 +++++++++++++++++++------ pkg/hold/pds/server.go | 25 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/cmd/hold/main.go b/cmd/hold/main.go index 19bbe9c..c48609f 100644 --- a/cmd/hold/main.go +++ b/cmd/hold/main.go @@ -48,6 +48,11 @@ func main() { log.Fatalf("Failed to initialize embedded PDS: %v", err) } + // Bootstrap PDS with hold owner as first crew member + if err := holdPDS.Bootstrap(ctx, cfg.Registration.OwnerDID); err != nil { + log.Fatalf("Failed to bootstrap PDS: %v", err) + } + // Create blob store adapter blobStore := pds.NewHoldServiceBlobStore(service, holdDID) @@ -59,6 +64,17 @@ func main() { // Setup HTTP routes mux := http.NewServeMux() + + // Root page + mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + w.Header().Set("Content-Type", "text/plain") + fmt.Fprintf(w, "This is a hold server. More info at https://atcr.io") + return + } + http.NotFound(w, r) + }) + mux.HandleFunc("/health", service.HealthHandler) mux.HandleFunc("/register", service.HandleRegister) mux.HandleFunc("/presigned-url", service.HandlePresignedURL) diff --git a/pkg/hold/pds/crew.go b/pkg/hold/pds/crew.go index b939f17..59e304f 100644 --- a/pkg/hold/pds/crew.go +++ b/pkg/hold/pds/crew.go @@ -33,7 +33,7 @@ const ( CrewCollection = "io.atcr.hold.crew" ) -// AddCrewMember adds a new crew member to the hold +// 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{ Member: memberDID, @@ -42,15 +42,28 @@ func (p *HoldPDS) AddCrewMember(ctx context.Context, memberDID, role string, per AddedAt: time.Now(), } - // Create record in repo - recordCID, rkey, err := p.repo.CreateRecord(ctx, CrewCollection, crewRecord) + // Create record in repo (using memberDID as rkey for easy lookup) + recordCID, _, err := p.repo.CreateRecord(ctx, CrewCollection, crewRecord) if err != nil { return cid.Undef, fmt.Errorf("failed to create crew record: %w", err) } - // TODO: Commit the changes - // For now, just return the CID - _ = rkey // We'll use rkey for GetCrewMember later + // Create signer function from signing key + signer := func(ctx context.Context, did string, data []byte) ([]byte, error) { + return p.signingKey.HashAndSign(data) + } + + // Commit the changes to get new root CID + root, rev, err := p.repo.Commit(ctx, signer) + if err != nil { + return cid.Undef, fmt.Errorf("failed to commit crew record: %w", err) + } + + // Close the delta session with the new root + _, err = p.session.CloseWithRoot(ctx, root, rev) + if err != nil { + return cid.Undef, fmt.Errorf("failed to persist commit: %w", err) + } return recordCID, nil } diff --git a/pkg/hold/pds/server.go b/pkg/hold/pds/server.go index 940c0cf..ba7510b 100644 --- a/pkg/hold/pds/server.go +++ b/pkg/hold/pds/server.go @@ -98,6 +98,31 @@ func (p *HoldPDS) SigningKey() *crypto.PrivateKeyK256 { return p.signingKey } +// 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) + if err == nil { + // Repo already has commits, skip bootstrap + return nil + } + + // Add hold owner as first crew member with admin role + fmt.Printf("🚀 Bootstrapping hold PDS with owner: %s\n", ownerDID) + _, err = p.AddCrewMember(ctx, ownerDID, "admin", []string{"blob:read", "blob:write", "crew:admin"}) + if err != nil { + return fmt.Errorf("failed to add owner as crew member: %w", err) + } + + fmt.Printf("✅ Added %s as hold admin\n", ownerDID) + return nil +} + // Close closes the session and carstore func (p *HoldPDS) Close() error { // TODO: Close session properly