Monorepo for Tangled tangled.org
2

Configure Feed

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

1package db 2 3import ( 4 "context" 5 "strings" 6 "testing" 7 "time" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 "tangled.org/core/appview/models" 11 "tangled.org/core/orm" 12 spindle "tangled.org/core/spindle/models" 13 "tangled.org/core/workflow" 14) 15 16// seedPipeline inserts a trigger + pipeline row and returns the pipeline. 17func seedPipeline(t *testing.T, d *DB, knot, rkey, repoDid string) models.Pipeline { 18 t.Helper() 19 sha := strings.Repeat("a", 40) 20 ref := "refs/heads/main" 21 newSha := sha 22 oldSha := strings.Repeat("0", 40) 23 trigger := models.Trigger{ 24 Kind: workflow.TriggerKindPush, 25 PushRef: &ref, 26 PushNewSha: &newSha, 27 PushOldSha: &oldSha, 28 } 29 tx, err := d.Begin() 30 if err != nil { 31 t.Fatalf("Begin: %v", err) 32 } 33 triggerID, err := AddTrigger(tx, trigger) 34 if err != nil { 35 tx.Rollback() 36 t.Fatalf("AddTrigger: %v", err) 37 } 38 pipeline := models.Pipeline{ 39 Knot: knot, 40 Rkey: rkey, 41 RepoOwner: syntax.DID("did:plc:owner"), 42 RepoName: "repo", 43 RepoDid: repoDid, 44 TriggerId: int(triggerID), 45 Sha: sha, 46 } 47 if err := AddPipeline(tx, pipeline); err != nil { 48 tx.Rollback() 49 t.Fatalf("AddPipeline: %v", err) 50 } 51 if err := tx.Commit(); err != nil { 52 t.Fatalf("Commit: %v", err) 53 } 54 return pipeline 55} 56 57// seedStatus inserts a pipeline_status row directly. 58func seedStatus(t *testing.T, d *DB, spindleInstance, rkey, pipelineKnot, pipelineRkey, workflow string) { 59 t.Helper() 60 status := models.PipelineStatus{ 61 Spindle: spindleInstance, 62 Rkey: rkey, 63 PipelineKnot: pipelineKnot, 64 PipelineRkey: pipelineRkey, 65 Workflow: workflow, 66 Status: spindle.StatusKindSuccess, 67 Created: time.Now(), 68 } 69 if err := AddPipelineStatus(context.Background(), d, status); err != nil { 70 t.Fatalf("AddPipelineStatus: %v", err) 71 } 72} 73 74// TestGetPipelineStatuses_SpindleValidation verifies that GetPipelineStatuses 75// only returns statuses emitted by the spindle registered for the pipeline's 76// repo, and silently drops statuses from a rogue spindle. 77func TestGetPipelineStatuses_SpindleValidation(t *testing.T) { 78 d := newTestDB(t) 79 80 const ( 81 knot = "knot.example.com" 82 correctSpindle = "spindle.example.com" 83 rogueSpindle = "evil.example.com" 84 repoDid = "did:plc:testrepo" 85 pipelineRkey = "pipeline1" 86 ) 87 88 // seed repo with the correct spindle 89 repo := seedRepo(t, d, "did:plc:owner", knot, "repo", "repo", repoDid) 90 if err := UpdateSpindle(d, repo.RepoDid, &[]string{correctSpindle}[0]); err != nil { 91 t.Fatalf("UpdateSpindle: %v", err) 92 } 93 94 // seed the pipeline for this repo 95 seedPipeline(t, d, knot, pipelineRkey, repoDid) 96 97 // insert one status from the correct spindle, one from a rogue spindle 98 seedStatus(t, d, correctSpindle, "status-valid", knot, pipelineRkey, "build") 99 seedStatus(t, d, rogueSpindle, "status-rogue", knot, pipelineRkey, "build") 100 101 pipelines, err := GetPipelineStatuses(d, 10, orm.FilterEq("p.repo_did", repoDid)) 102 if err != nil { 103 t.Fatalf("GetPipelineStatuses: %v", err) 104 } 105 if len(pipelines) != 1 { 106 t.Fatalf("expected 1 pipeline, got %d", len(pipelines)) 107 } 108 109 statuses := pipelines[0].Statuses["build"].Data 110 if len(statuses) != 1 { 111 t.Fatalf("expected 1 status (from correct spindle), got %d", len(statuses)) 112 } 113 if statuses[0].Spindle != correctSpindle { 114 t.Errorf("expected spindle %q, got %q", correctSpindle, statuses[0].Spindle) 115 } 116}