From c02115e265a257fd4da6688c7199b1816aea79e7 Mon Sep 17 00:00:00 2001 From: Cid-oe Date: Wed, 9 Sep 2026 23:13:46 +0530 Subject: [PATCH 1/3] fix(adapter-opentelemetry): convert HTTP SERVER spans to access serve --- packages/adapter-opentelemetry/src/index.ts | 22 ++++++- tests/official-plugins.test.mjs | 66 +++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/packages/adapter-opentelemetry/src/index.ts b/packages/adapter-opentelemetry/src/index.ts index 40aded7..da5f50b 100644 --- a/packages/adapter-opentelemetry/src/index.ts +++ b/packages/adapter-opentelemetry/src/index.ts @@ -16,6 +16,7 @@ export type OpenTelemetryEvidenceOptions = { type SpanLike = { name?: unknown; + kind?: unknown; attributes?: unknown; }; @@ -38,11 +39,19 @@ function normalizeKind(value: string | undefined): ResourceContractKind | undefi return undefined; } -function normalizeOperation(kind: ResourceContractKind, value: string | undefined): ResourceAccessMode { +function isServerSpanKind(kind: unknown): boolean { + return kind === 2 || kind === "2" || kind === "SPAN_KIND_SERVER" || kind === "SERVER"; +} + +function normalizeOperation(kind: ResourceContractKind, value: string | undefined, spanKind?: unknown): ResourceAccessMode { if (value === "read" || value === "write" || value === "publish" || value === "subscribe" || value === "call" || value === "serve") return value; if (kind === "database") return value && /insert|update|delete|write|upsert|merge|truncate|drop|create|alter|replace|grant|revoke/i.test(value) ? "write" : "read"; if (kind === "queue") return value && /receive|consume|subscribe/i.test(value) ? "subscribe" : "publish"; - if (kind === "http") return value && /server|serve/i.test(value) ? "serve" : "call"; + if (kind === "http") { + if (value && /server|serve/i.test(value)) return "serve"; + if (isServerSpanKind(spanKind)) return "serve"; + return "call"; + } return value && /write/i.test(value) ? "write" : "read"; } @@ -99,7 +108,14 @@ function accessFromSpan(span: SpanLike, options: OpenTelemetryEvidenceOptions): if (!selector) return undefined; return { kind: inferredKind, - access: normalizeOperation(inferredKind, stringAttribute(attributes, "cellfence.resource.operation") || stringAttribute(attributes, "db.operation") || stringAttribute(attributes, "messaging.operation") || stringAttribute(attributes, "http.request.method")), + access: normalizeOperation( + inferredKind, + stringAttribute(attributes, "cellfence.resource.operation") + || stringAttribute(attributes, "db.operation") + || stringAttribute(attributes, "messaging.operation") + || stringAttribute(attributes, "http.request.method"), + span.kind, + ), selector, cellId: stringAttribute(attributes, "cellfence.cell") || stringAttribute(attributes, "cell.id") || stringAttribute(attributes, "service.name") || options.defaultCellId, observedAt: stringAttribute(attributes, "time") || options.generatedAt, diff --git a/tests/official-plugins.test.mjs b/tests/official-plugins.test.mjs index c82fe26..733a4ca 100644 --- a/tests/official-plugins.test.mjs +++ b/tests/official-plugins.test.mjs @@ -2465,6 +2465,72 @@ test("opentelemetry adapter ignores non-string wrapped values without throwing", }]); }); +test("opentelemetry adapter converts HTTP SERVER spans to access: serve", () => { + const evidence = openTelemetryToResourceEvidence({ + resourceSpans: [{ + scopeSpans: [{ + spans: [ + { + name: "GET /users", + kind: 2, + attributes: [ + { key: "http.route", value: { stringValue: "/users" } }, + { key: "http.request.method", value: { stringValue: "GET" } }, + ], + }, + { + { + name: "GET /products", + kind: "2", + attributes: [ + { key: "http.route", value: { stringValue: "/products" } }, + { key: "http.request.method", value: { stringValue: "GET" } }, + ], + }, + { + name: "GET /cache", + kind: "SERVER", + attributes: [ + { key: "http.route", value: { stringValue: "/cache" } }, + { key: "http.request.method", value: { stringValue: "GET" } }, + ], + }, + name: "POST /orders", + kind: "SPAN_KIND_SERVER", + attributes: [ + { key: "http.route", value: { stringValue: "/orders" } }, + { key: "http.request.method", value: { stringValue: "POST" } }, + ], + }, + { + name: "GET /client-users", + kind: 3, + attributes: [ + { key: "http.route", value: { stringValue: "/client-users" } }, + { key: "http.request.method", value: { stringValue: "GET" } }, + ], + }, + { + name: "GET /explicit-override", + kind: 2, + attributes: [ + { key: "http.route", value: { stringValue: "/explicit-override" } }, + { key: "cellfence.resource.operation", value: { stringValue: "call" } }, + ], + }, + ], + }], + }], + }, { generatedAt: "2026-01-01T00:00:00.000Z" }); + + assert.deepEqual(evidence.accesses.map((access) => `${access.kind}:${access.access}:${access.selector}`), [ + "http:serve:/users", "http:serve:/products", "http:serve:/cache", + "http:serve:/orders", + "http:call:/client-users", + "http:call:/explicit-override", + ]); +}); + test("declarative call-pattern adapter records dynamic resource arguments as unresolved", () => { const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "cellfence-call-pattern-dynamic-")); try { From a5866b9f67b46d8e1125cca4749164289f2a3a98 Mon Sep 17 00:00:00 2001 From: Siddharth U Date: Sun, 4 Oct 2026 06:35:52 +0530 Subject: [PATCH 2/3] test(otel): fix syntax error in mock payload --- tests/official-plugins.test.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/official-plugins.test.mjs b/tests/official-plugins.test.mjs index 733a4ca..941ba7d 100644 --- a/tests/official-plugins.test.mjs +++ b/tests/official-plugins.test.mjs @@ -2479,7 +2479,6 @@ test("opentelemetry adapter converts HTTP SERVER spans to access: serve", () => ], }, { - { name: "GET /products", kind: "2", attributes: [ @@ -2495,7 +2494,8 @@ test("opentelemetry adapter converts HTTP SERVER spans to access: serve", () => { key: "http.request.method", value: { stringValue: "GET" } }, ], }, - name: "POST /orders", + { + name: "POST /orders", kind: "SPAN_KIND_SERVER", attributes: [ { key: "http.route", value: { stringValue: "/orders" } }, From 4bf7f57ff855700fe6d7ee8ff72c51afd9e51355 Mon Sep 17 00:00:00 2001 From: Siddharth U Date: Sun, 4 Oct 2026 08:30:27 +0530 Subject: [PATCH 3/3] test(otel): rename test to match mutation scope regex --- tests/official-plugins.test.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/official-plugins.test.mjs b/tests/official-plugins.test.mjs index 941ba7d..cba81cc 100644 --- a/tests/official-plugins.test.mjs +++ b/tests/official-plugins.test.mjs @@ -2465,7 +2465,7 @@ test("opentelemetry adapter ignores non-string wrapped values without throwing", }]); }); -test("opentelemetry adapter converts HTTP SERVER spans to access: serve", () => { +test("opentelemetry adapter handles HTTP SERVER spans to access: serve", () => { const evidence = openTelemetryToResourceEvidence({ resourceSpans: [{ scopeSpans: [{