AkurAI Build
Menu

popagent

public

Latest change 12fd35a15b70e604f88afd349057da20f7495bca - Protect native trace reads by Ólafur Búi Ólafsson

import { describe, expect, test } from "bun:test";
import { SensitiveDataFilter } from "@mastra/observability";
import { createTraceId } from "./agent-execution";
import { OBSERVABILITY_SENSITIVE_FIELDS } from "./observability";
import { observabilityFilters, parseObservabilityQuery, publicSpanPayload } from "./observability-store";

const NOW = new Date("2026-08-14T12:00:00.000Z");

describe("observability contracts", () => {
  test("creates valid unique trace IDs", () => {
    const first = createTraceId();
    const second = createTraceId();
    expect(first).toMatch(/^[a-f0-9]{32}$/);
    expect(second).toMatch(/^[a-f0-9]{32}$/);
    expect(first).not.toBe(second);
  });

  test("bounds query time and pagination", () => {
    expect(parseObservabilityQuery("http://localhost/api/observability/traces", NOW)).toEqual({
      from: new Date("2026-08-13T12:00:00.000Z"),
      to: NOW,
      page: 0,
      perPage: 25,
    });
    expect(() => parseObservabilityQuery("http://localhost/api?from=2026-01-01&to=2026-08-01", NOW)).toThrow("cannot exceed 30 days");
    expect(() => parseObservabilityQuery("http://localhost/api?page=-1", NOW)).toThrow("Invalid observability pagination");
    expect(() => parseObservabilityQuery("http://localhost/api?perPage=101", NOW)).toThrow("Invalid observability pagination");
  });

  test("does not hide Mastra spans that omit service name", () => {
    expect(observabilityFilters({ startedAt: { start: NOW, end: NOW } })).toEqual({
      startedAt: { start: NOW, end: NOW },
    });
  });

  test("never returns model or tool payload bodies from trace reads", () => {
    expect(publicSpanPayload({ prompt: "private prompt" })).toBeNull();
    expect(publicSpanPayload({ value: "private tool result" })).toBeNull();
  });

  test("redacts secret tool values before export", () => {
    const marker = "plaintext-secret-marker";
    const filter = new SensitiveDataFilter({ sensitiveFields: OBSERVABILITY_SENSITIVE_FIELDS });
    const span = filter.process({
      traceId: createTraceId(),
      spanId: createTraceId().slice(0, 16),
      type: "tool_call",
      name: "recall-secret",
      input: { name: "service", value: marker },
      output: JSON.stringify({ name: "service", value: marker }),
      attributes: {},
      metadata: {},
    } as never);
    expect(JSON.stringify(span)).not.toContain(marker);
    expect(JSON.stringify(span)).toContain("[REDACTED]");
  });
});