package console import ( "context" "net/http" "net/url" "testing" "github.com/carlosframework/platform/internal/objstore" ) func TestRevivalPollingWithoutCallbackKeys(t *testing.T) { fx, _, member, _ := storeArmed(t, "revival-poll-only") grantStore(t, fx, member) requestScanning(t, fx, member, false) scanner := objstore.NewMemScanner() fx.srv.cfg.StoreScanner = scanner fx.srv.cfg.CallbackSigner = nil fx.srv.cfg.SecretsPub = "" enableDeploymentScanning(t, fx) if status, out := postJSON(t, scanURL(fx, "titogo")+"/grant", map[string]any{}, member); status != http.StatusOK { t.Fatalf("grant without callback or sealing keys = %d %v", status, out) } rec := storedRecord(t, fx, "titogo") if rec.Scanning.WebhookGen != 0 || rec.Scanning.WebhookKeyID != "" { t.Fatalf("polling-only grant created callback state: %+v", rec.Scanning) } if _, exists := appVars(t, fx, "titogo")[objstore.DefaultEnvPrefix+"_SCAN_CALLBACK_SECRET"]; exists { t.Fatal("polling-only grant delivered a callback secret") } token := appToken(t, fx, "poll-only") key := " uploads/report.pdf " bucket := rec.Provisioned.Bucket seedObject(scanner, bucket, key, "infected-upload") scanner.ScanAs(key, objstore.VerdictInfected) other := "uploads/report.pdf" version := seedObject(scanner, bucket, other, "clean-other-upload") scanner.Put(bucket, other, version, objstore.VerdictClean) if status, out := postJSON(t, enqueueURL(fx, "titogo"), map[string]any{"key": key}, token); status != http.StatusAccepted { t.Fatalf("enqueue = %d %v", status, out) } if status, out := getStatus(t, fx, token, "key="+url.QueryEscape(key)); status != http.StatusOK || out["state"] != "pending" { t.Fatalf("before drain = %d %v, want pending for the exact key", status, out) } if err := fx.srv.scanDrainTick(context.Background()); err != nil { t.Fatal(err) } if status, out := getStatus(t, fx, token, "key="+url.QueryEscape(key)); status != http.StatusOK || out["state"] != "infected" { t.Fatalf("after drain = %d %v, want infected for the exact key", status, out) } if scanner.Scans(key) != 1 || scanner.Scans(other) != 0 { t.Fatalf("wrong objects scanned: requested=%d other=%d", scanner.Scans(key), scanner.Scans(other)) } if n := queueLen(t, fx, fx.sqid, "titogo"); n != 0 { t.Fatalf("queue after drain = %d", n) } if status, out := postJSON(t, enqueueURL(fx, "titogo"), map[string]any{"key": key, "callback_path": "/hooks/scan"}, token); status != http.StatusServiceUnavailable || out["reason"] != "callbacks_not_configured" { t.Fatalf("callback without signer = %d %v", status, out) } }