package spindle import ( "context" "crypto/rand" "crypto/rsa" "io" "net/http" "net/http/httptest" "testing" "time" "github.com/golang-jwt/jwt/v5" "tangled.org/core/spindle/db" "tangled.org/core/spindle/models" "tangled.org/core/spindle/nixcache" ) func TestNixCacheGranterIsForTheTargetRepo(t *testing.T) { if (&Spindle{}).nixCacheGranter(&db.JobRow{}, true) != nil { t.Fatal("granter without an issuer") } key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { t.Fatal(err) } attic := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, `{"public_key":"k:AAAA="}`) })) t.Cleanup(attic.Close) s := &Spindle{nixCache: &nixcache.Issuer{Client: nixcache.Client{BaseURL: attic.URL}, Key: key}} job := &db.JobRow{RepoDid: "did:plc:z72i7hdynmk6r22z27h6tvur"} run := models.WorkflowId{PipelineId: "3m2abc", Name: "build"} trusted, err := s.nixCacheGranter(job, true)(context.Background(), run, time.Hour) if err != nil { t.Fatal(err) } untrusted, err := s.nixCacheGranter(job, false)(context.Background(), run, time.Hour) if err != nil { t.Fatal(err) } if trusted.Cache != "plc-z72i7hdynmk6r22z27h6tvur" || untrusted.Cache != trusted.Cache { t.Errorf("caches = %q and %q, want the target repo's", trusted.Cache, untrusted.Cache) } if trusted.PushToken == "" || untrusted.PushToken != "" { t.Errorf("push tokens: trusted %q, untrusted %q", trusted.PushToken, untrusted.PushToken) } var claims jwt.RegisteredClaims if _, err := jwt.ParseWithClaims(trusted.PullToken, &claims, func(*jwt.Token) (any, error) { return &key.PublicKey, nil }); err != nil { t.Fatal(err) } if claims.Subject != "3m2abc/build" { t.Errorf("token sub = %q, want the run's workflow id", claims.Subject) } if left := time.Until(claims.ExpiresAt.Time); left < time.Hour || left > time.Hour+nixCacheTokenGrace { t.Errorf("token expires in %s, want the budget plus a small grace", left) } }