From 0c4d1cae8f0f159fe356f991858cdaafda307e1c Mon Sep 17 00:00:00 2001 From: Evan Jarrett Date: Fri, 24 Oct 2025 20:27:16 -0500 Subject: [PATCH] fix post schema --- pkg/appview/middleware/registry.go | 6 +++--- pkg/hold/oci/xrpc.go | 1 + pkg/hold/pds/manifest_post.go | 16 ++++++++-------- pkg/hold/pds/manifest_post_test.go | 22 +++++++++++++++------- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/pkg/appview/middleware/registry.go b/pkg/appview/middleware/registry.go index 716ae09..ed936f2 100644 --- a/pkg/appview/middleware/registry.go +++ b/pkg/appview/middleware/registry.go @@ -33,9 +33,9 @@ const holdDIDKey contextKey = "hold.did" // These are set by main.go during startup and copied into NamespaceResolver instances. // After initialization, request handling uses the NamespaceResolver's instance fields. var ( - globalRefresher *oauth.Refresher - globalDatabase storage.DatabaseMetrics - globalAuthorizer auth.HoldAuthorizer + globalRefresher *oauth.Refresher + globalDatabase storage.DatabaseMetrics + globalAuthorizer auth.HoldAuthorizer globalReadmeCache storage.ReadmeCache ) diff --git a/pkg/hold/oci/xrpc.go b/pkg/hold/oci/xrpc.go index daaba9c..ad938e7 100644 --- a/pkg/hold/oci/xrpc.go +++ b/pkg/hold/oci/xrpc.go @@ -291,6 +291,7 @@ func (h *XRPCHandler) HandleNotifyManifest(w http.ResponseWriter, r *http.Reques req.Repository, req.Tag, req.UserHandle, + req.UserDID, manifestDigest, totalSize, ) diff --git a/pkg/hold/pds/manifest_post.go b/pkg/hold/pds/manifest_post.go index 0b54df5..8f3ae55 100644 --- a/pkg/hold/pds/manifest_post.go +++ b/pkg/hold/pds/manifest_post.go @@ -13,7 +13,7 @@ import ( // Includes facets for clickable mentions and links func (p *HoldPDS) CreateManifestPost( ctx context.Context, - repository, tag, userHandle, digest string, + repository, tag, userHandle, userDID, digest string, totalSize int64, ) (string, error) { now := time.Now() @@ -30,7 +30,7 @@ func (p *HoldPDS) CreateManifestPost( text := fmt.Sprintf("@%s just pushed %s\nDigest: %s Size: %s", userHandle, repoWithTag, digestShort, sizeStr) // Create facets for mentions and links - facets := buildFacets(text, userHandle, repoWithTag, appViewURL) + facets := buildFacets(text, userHandle, userDID, repoWithTag, appViewURL) // Create post struct with facets post := &bsky.FeedPost{ @@ -60,19 +60,19 @@ func (p *HoldPDS) CreateManifestPost( return postURI, nil } -// formatDigest truncates digest to first 7 and last 7 chars -// Example: sha256:abc1234567890...fedcba9876543210 -> sha256:abc1234...9876543 +// formatDigest truncates digest to first 10 chars +// Example: sha256:abc1234567890fedcba9876543210 -> sha256:abc1234567... func formatDigest(digest string) string { if !strings.HasPrefix(digest, "sha256:") { return digest // Return as-is if not sha256 } hash := strings.TrimPrefix(digest, "sha256:") - if len(hash) <= 14 { + if len(hash) <= 10 { return digest // Too short to truncate } - return fmt.Sprintf("sha256:%s...%s", hash[:7], hash[len(hash)-7:]) + return fmt.Sprintf("sha256:%s...", hash[:10]) } // formatSize converts bytes to human-readable format @@ -98,7 +98,7 @@ func formatSize(bytes int64) string { // buildFacets creates mention and link facets for rich text // IMPORTANT: Byte offsets must be calculated for UTF-8 encoded text -func buildFacets(text, userHandle, repoWithTag, appViewURL string) []*bsky.RichtextFacet { +func buildFacets(text, userHandle, userDID, repoWithTag, appViewURL string) []*bsky.RichtextFacet { facets := []*bsky.RichtextFacet{} // Find mention: "@alice.bsky.social" @@ -117,7 +117,7 @@ func buildFacets(text, userHandle, repoWithTag, appViewURL string) []*bsky.Richt Features: []*bsky.RichtextFacet_Features_Elem{ { RichtextFacet_Mention: &bsky.RichtextFacet_Mention{ - Did: "", // Will be resolved by Bluesky from handle + Did: userDID, }, }, }, diff --git a/pkg/hold/pds/manifest_post_test.go b/pkg/hold/pds/manifest_post_test.go index 29c6111..5911bb4 100644 --- a/pkg/hold/pds/manifest_post_test.go +++ b/pkg/hold/pds/manifest_post_test.go @@ -16,7 +16,7 @@ func TestFormatDigest(t *testing.T) { { name: "standard sha256 digest", digest: "sha256:abc1234567890fedcba9876543210", - expected: "sha256:abc1234...6543210", // Last 7 chars of hash + expected: "sha256:abc1234567...", // First 10 chars }, { name: "short digest (no truncation)", @@ -31,7 +31,7 @@ func TestFormatDigest(t *testing.T) { { name: "real sha256 digest", digest: "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f", - expected: "sha256:e692418...7fc331f", // Last 7 chars are "7fc331f" + expected: "sha256:e692418e4c...", // First 10 chars }, } @@ -108,6 +108,7 @@ func TestBuildFacets(t *testing.T) { name string text string userHandle string + userDID string repoWithTag string appViewURL string wantFacets int // number of facets expected @@ -116,6 +117,7 @@ func TestBuildFacets(t *testing.T) { name: "standard post with mention and link", text: "@alice.bsky.social just pushed myapp:latest\nDigest: sha256:abc...def Size: 12.2 MB", userHandle: "alice.bsky.social", + userDID: "did:plc:alice123", repoWithTag: "myapp:latest", appViewURL: "https://atcr.io/r/alice.bsky.social/myapp", wantFacets: 2, @@ -124,6 +126,7 @@ func TestBuildFacets(t *testing.T) { name: "no matches found", text: "random text", userHandle: "alice.bsky.social", + userDID: "did:plc:alice123", repoWithTag: "myapp:latest", appViewURL: "https://atcr.io/r/alice.bsky.social/myapp", wantFacets: 0, @@ -132,6 +135,7 @@ func TestBuildFacets(t *testing.T) { name: "only mention found", text: "@alice.bsky.social did something", userHandle: "alice.bsky.social", + userDID: "did:plc:alice123", repoWithTag: "myapp:latest", appViewURL: "https://atcr.io/r/alice.bsky.social/myapp", wantFacets: 1, @@ -140,7 +144,7 @@ func TestBuildFacets(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - facets := buildFacets(tt.text, tt.userHandle, tt.repoWithTag, tt.appViewURL) + facets := buildFacets(tt.text, tt.userHandle, tt.userDID, tt.repoWithTag, tt.appViewURL) if len(facets) != tt.wantFacets { t.Errorf("buildFacets() returned %d facets, want %d", len(facets), tt.wantFacets) @@ -183,10 +187,11 @@ func TestBuildFacets_ByteOffsets(t *testing.T) { // Test that byte offsets are correctly calculated text := "@alice.bsky.social just pushed myapp:latest" userHandle := "alice.bsky.social" + userDID := "did:plc:alice123" repoWithTag := "myapp:latest" appViewURL := "https://atcr.io/r/alice.bsky.social/myapp" - facets := buildFacets(text, userHandle, repoWithTag, appViewURL) + facets := buildFacets(text, userHandle, userDID, repoWithTag, appViewURL) if len(facets) != 2 { t.Fatalf("expected 2 facets, got %d", len(facets)) @@ -235,10 +240,11 @@ func TestBuildFacets_UTF8Handling(t *testing.T) { // Test with Unicode characters to ensure byte offsets work correctly text := "@alice.bsky.social just pushed 🚀myapp:latest" userHandle := "alice.bsky.social" + userDID := "did:plc:alice123" repoWithTag := "🚀myapp:latest" // Note: emoji is multi-byte appViewURL := "https://atcr.io/r/alice.bsky.social/myapp" - facets := buildFacets(text, userHandle, repoWithTag, appViewURL) + facets := buildFacets(text, userHandle, userDID, repoWithTag, appViewURL) if len(facets) != 2 { t.Fatalf("expected 2 facets, got %d", len(facets)) @@ -263,10 +269,11 @@ func TestBuildFacets_NoOverlap(t *testing.T) { // Ensure facets don't overlap text := "@alice.bsky.social just pushed myapp:latest" userHandle := "alice.bsky.social" + userDID := "did:plc:alice123" repoWithTag := "myapp:latest" appViewURL := "https://atcr.io/r/alice.bsky.social/myapp" - facets := buildFacets(text, userHandle, repoWithTag, appViewURL) + facets := buildFacets(text, userHandle, userDID, repoWithTag, appViewURL) if len(facets) != 2 { t.Fatalf("expected 2 facets, got %d", len(facets)) @@ -287,6 +294,7 @@ func TestBuildFacets_RealWorldExample(t *testing.T) { repository := "hsm-secrets-operator" tag := "latest" userHandle := "evan.jarrett.net" + userDID := "did:plc:pddp4xt5lgnv2qsegbzzs4xg" digest := "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f" totalSize := int64(12800000) // ~12.2 MB @@ -297,7 +305,7 @@ func TestBuildFacets_RealWorldExample(t *testing.T) { text := "@" + userHandle + " just pushed " + repoWithTag + "\nDigest: " + digestShort + " Size: " + sizeStr appViewURL := "https://atcr.io/r/" + userHandle + "/" + repository - facets := buildFacets(text, userHandle, repoWithTag, appViewURL) + facets := buildFacets(text, userHandle, userDID, repoWithTag, appViewURL) // Should have 2 facets: mention and link if len(facets) != 2 {