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)
}
}