package ingress import ( "bytes" "context" "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/json" "net/http" "net/http/httptest" "os" "path/filepath" "strconv" "testing" "time" "yovision/bell/contracts" "yovision/bell/internal/event" ) type ingressIDs struct{} func (ingressIDs) NewEventID() (string, error) { return "evt_01J8XQ2K7M3P5R9T0V4W6Y8Z2B", nil } type ingressPrivacy struct{} func (ingressPrivacy) VideoAllowed(context.Context, int64, int64, int64) (bool, error) { return true, nil } type fakeRepository struct { replayResult Result replayFound bool replayErr error processErr error processed int } func (f *fakeRepository) Replay(context.Context, string, string, [sha256.Size]byte, string, string, [sha256.Size]byte) (Result, bool, error) { return f.replayResult, f.replayFound, f.replayErr } func (f *fakeRepository) ProcessEvent(_ context.Context, _, _ string, _ [sha256.Size]byte, producer string, _ [sha256.Size]byte, value event.Event) (Result, error) { f.processed++ if f.processErr != nil { return Result{}, f.processErr } return Result{SchemaVersion: 1, ProducerID: producer, SourceEventID: value.SourceEventID(), EventID: value.ID(), Status: "accepted", HTTPStatus: 201}, nil } func ingressCandidate(t *testing.T) []byte { t.Helper() raw, err := os.ReadFile(filepath.Join("..", "..", "..", "docs", "raw", "contracts", "event-v0.1.example-current.json")) if err != nil { t.Fatal(err) } var object map[string]any if err := json.Unmarshal(raw, &object); err != nil { t.Fatal(err) } delete(object, "id") object["kind"] = "zone_entry" object["severity"] = "medium" object["evidence"] = map[string]any{"snapshot_uris": []any{}, "clip_uri": nil, "clip_range": nil} encoded, err := json.Marshal(object) if err != nil { t.Fatal(err) } return encoded } func newIngressHandler(t *testing.T, repository Repository) (*Handler, []byte) { t.Helper() guard, err := event.NewEvidenceGuard("private-customer") if err != nil { t.Fatal(err) } factory, err := event.NewFactory(contracts.EventV01Schema, ingressIDs{}, ingressPrivacy{}, guard) if err != nil { t.Fatal(err) } secret := make([]byte, 32) if _, err := rand.Read(secret); err != nil { t.Fatal(err) } handler, err := NewHandler(repository, map[string]Key{"brain-a": {ProducerID: "brain-main", Secret: secret}}, factory) if err != nil { t.Fatal(err) } handler.now = func() time.Time { return time.Unix(1_800_000_000, 0).UTC() } return handler, secret } func signedRequest(t *testing.T, secret []byte, producer string, candidate []byte) *http.Request { t.Helper() body, err := json.Marshal(map[string]any{"schema_version": 1, "producer_id": producer, "candidate": json.RawMessage(candidate)}) if err != nil { t.Fatal(err) } request := httptest.NewRequest(http.MethodPost, Path, bytes.NewReader(body)) timestamp := strconv.FormatInt(1_800_000_000, 10) nonce := base64.RawURLEncoding.EncodeToString([]byte("0123456789abcdef")) request.Header.Set(HeaderKeyID, "brain-a") request.Header.Set(HeaderTimestamp, timestamp) request.Header.Set(HeaderNonce, nonce) request.Header.Set(HeaderSignature, base64.RawURLEncoding.EncodeToString(signature(secret, canonicalString(http.MethodPost, Path, timestamp, nonce, body)))) return request } func TestHandlerAcceptsSignedCandidateAndRejectsProducerSpoofing(t *testing.T) { repository := &fakeRepository{} handler, secret := newIngressHandler(t, repository) response := httptest.NewRecorder() handler.ServeHTTP(response, signedRequest(t, secret, "brain-main", ingressCandidate(t))) if response.Code != http.StatusCreated || repository.processed != 1 { t.Fatalf("signed candidate: status=%d body=%s processed=%d", response.Code, response.Body.String(), repository.processed) } var result Result if err := json.Unmarshal(response.Body.Bytes(), &result); err != nil || result.Status != "accepted" || result.EventID == "" { t.Fatalf("invalid accepted response: %+v %v", result, err) } response = httptest.NewRecorder() handler.ServeHTTP(response, signedRequest(t, secret, "brain-spoofed", ingressCandidate(t))) if response.Code != http.StatusUnauthorized || repository.processed != 1 { t.Fatalf("producer spoofing was not rejected: %d %s", response.Code, response.Body.String()) } } func TestHandlerReturnsDurableReplayAndStableConflicts(t *testing.T) { repository := &fakeRepository{replayFound: true, replayResult: Result{ SchemaVersion: 1, ProducerID: "brain-main", SourceEventID: "source-1", EventID: "evt_01J8XQ2K7M3P5R9T0V4W6Y8Z2B", Status: "duplicate", HTTPStatus: 200, }} handler, secret := newIngressHandler(t, repository) response := httptest.NewRecorder() handler.ServeHTTP(response, signedRequest(t, secret, "brain-main", ingressCandidate(t))) if response.Code != http.StatusOK || repository.processed != 0 { t.Fatalf("durable replay did not bypass factory persistence: %d", response.Code) } repository.replayFound = false repository.replayErr = ErrSourceConflict response = httptest.NewRecorder() handler.ServeHTTP(response, signedRequest(t, secret, "brain-main", ingressCandidate(t))) if response.Code != http.StatusConflict { t.Fatalf("source conflict status=%d body=%s", response.Code, response.Body.String()) } } func TestHandlerRejectsInvalidSignatureAndUpstreamPlatformID(t *testing.T) { repository := &fakeRepository{} handler, secret := newIngressHandler(t, repository) request := signedRequest(t, secret, "brain-main", ingressCandidate(t)) request.Header.Set(HeaderSignature, base64.RawURLEncoding.EncodeToString(make([]byte, 32))) response := httptest.NewRecorder() handler.ServeHTTP(response, request) if response.Code != http.StatusUnauthorized { t.Fatalf("invalid signature status=%d", response.Code) } var object map[string]any if err := json.Unmarshal(ingressCandidate(t), &object); err != nil { t.Fatal(err) } object["id"] = "evt_01J8XQ2K7M3P5R9T0V4W6Y8Z2B" withID, _ := json.Marshal(object) response = httptest.NewRecorder() handler.ServeHTTP(response, signedRequest(t, secret, "brain-main", withID)) if response.Code != http.StatusUnprocessableEntity || repository.processed != 0 { t.Fatalf("upstream ID status=%d body=%s", response.Code, response.Body.String()) } }