@superblocksteam/telemetry 2.0.93 → 2.0.94-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +59 -44
  2. package/dist/browser/index.d.ts +2 -2
  3. package/dist/browser/resilient-exporter.d.ts.map +1 -1
  4. package/dist/browser/resilient-exporter.js.map +1 -1
  5. package/dist/common/contracts/tier2-traces.d.ts +62 -50
  6. package/dist/common/contracts/tier2-traces.d.ts.map +1 -1
  7. package/dist/common/contracts/tier2-traces.js +484 -138
  8. package/dist/common/contracts/tier2-traces.js.map +1 -1
  9. package/dist/common/guardrails.d.ts +2 -2
  10. package/dist/common/guardrails.d.ts.map +1 -1
  11. package/dist/common/guardrails.js +7 -7
  12. package/dist/common/guardrails.js.map +1 -1
  13. package/dist/common/log-sanitizer.d.ts +88 -0
  14. package/dist/common/log-sanitizer.d.ts.map +1 -1
  15. package/dist/common/log-sanitizer.js +304 -6
  16. package/dist/common/log-sanitizer.js.map +1 -1
  17. package/dist/common/resource.d.ts +4 -1
  18. package/dist/common/resource.d.ts.map +1 -1
  19. package/dist/common/resource.js +4 -2
  20. package/dist/common/resource.js.map +1 -1
  21. package/dist/common/trace-sanitizer.d.ts +82 -0
  22. package/dist/common/trace-sanitizer.d.ts.map +1 -0
  23. package/dist/common/trace-sanitizer.js +230 -0
  24. package/dist/common/trace-sanitizer.js.map +1 -0
  25. package/dist/index.d.ts +2 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +16 -8
  28. package/dist/index.js.map +1 -1
  29. package/dist/lint/forbidden-attributes.d.ts +2 -2
  30. package/dist/lint/forbidden-attributes.d.ts.map +1 -1
  31. package/dist/lint/forbidden-attributes.js +41 -40
  32. package/dist/lint/forbidden-attributes.js.map +1 -1
  33. package/dist/lint/index.d.ts +1 -1
  34. package/dist/llmobs/index.d.ts +2 -2
  35. package/dist/llmobs/tier1-exporter.d.ts +2 -2
  36. package/dist/llmobs/tier1-exporter.d.ts.map +1 -1
  37. package/dist/llmobs/tier1-exporter.js +17 -14
  38. package/dist/llmobs/tier1-exporter.js.map +1 -1
  39. package/dist/llmobs/tier2-summarizer.d.ts.map +1 -1
  40. package/dist/llmobs/tier2-summarizer.js +10 -4
  41. package/dist/llmobs/tier2-summarizer.js.map +1 -1
  42. package/dist/node/exporters/resilient-exporter.d.ts +14 -0
  43. package/dist/node/exporters/resilient-exporter.d.ts.map +1 -1
  44. package/dist/node/exporters/resilient-exporter.js +8 -1
  45. package/dist/node/exporters/resilient-exporter.js.map +1 -1
  46. package/dist/node/index.d.ts +2 -1
  47. package/dist/node/index.d.ts.map +1 -1
  48. package/dist/node/index.js +7 -2
  49. package/dist/node/index.js.map +1 -1
  50. package/dist/node/init.d.ts.map +1 -1
  51. package/dist/node/init.js +61 -12
  52. package/dist/node/init.js.map +1 -1
  53. package/dist/node/log-processor.d.ts +41 -6
  54. package/dist/node/log-processor.d.ts.map +1 -1
  55. package/dist/node/log-processor.js +152 -61
  56. package/dist/node/log-processor.js.map +1 -1
  57. package/dist/node/metrics-client.d.ts.map +1 -1
  58. package/dist/node/metrics-client.js.map +1 -1
  59. package/dist/node/safe-logger.d.ts +55 -0
  60. package/dist/node/safe-logger.d.ts.map +1 -0
  61. package/dist/node/safe-logger.js +158 -0
  62. package/dist/node/safe-logger.js.map +1 -0
  63. package/dist/node/sanitizing-processor.d.ts +56 -0
  64. package/dist/node/sanitizing-processor.d.ts.map +1 -0
  65. package/dist/node/sanitizing-processor.js +124 -0
  66. package/dist/node/sanitizing-processor.js.map +1 -0
  67. package/dist/node/traced-socket.d.ts +47 -3
  68. package/dist/node/traced-socket.d.ts.map +1 -1
  69. package/dist/node/traced-socket.js +96 -19
  70. package/dist/node/traced-socket.js.map +1 -1
  71. package/dist/testing/in-memory-exporter.d.ts +3 -3
  72. package/dist/testing/in-memory-exporter.d.ts.map +1 -1
  73. package/dist/testing/in-memory-exporter.js +3 -1
  74. package/dist/testing/in-memory-exporter.js.map +1 -1
  75. package/dist/testing/index.d.ts +2 -2
  76. package/dist/types/index.d.ts +28 -1
  77. package/dist/types/index.d.ts.map +1 -1
  78. package/dist-esm/browser/index.d.ts +2 -2
  79. package/dist-esm/browser/index.js +2 -2
  80. package/dist-esm/browser/resilient-exporter.d.ts.map +1 -1
  81. package/dist-esm/browser/resilient-exporter.js.map +1 -1
  82. package/dist-esm/common/contracts/tier2-traces.d.ts +62 -50
  83. package/dist-esm/common/contracts/tier2-traces.d.ts.map +1 -1
  84. package/dist-esm/common/contracts/tier2-traces.js +480 -137
  85. package/dist-esm/common/contracts/tier2-traces.js.map +1 -1
  86. package/dist-esm/common/guardrails.d.ts +2 -2
  87. package/dist-esm/common/guardrails.d.ts.map +1 -1
  88. package/dist-esm/common/guardrails.js +9 -9
  89. package/dist-esm/common/guardrails.js.map +1 -1
  90. package/dist-esm/common/log-sanitizer.d.ts +88 -0
  91. package/dist-esm/common/log-sanitizer.d.ts.map +1 -1
  92. package/dist-esm/common/log-sanitizer.js +294 -5
  93. package/dist-esm/common/log-sanitizer.js.map +1 -1
  94. package/dist-esm/common/resource.d.ts +4 -1
  95. package/dist-esm/common/resource.d.ts.map +1 -1
  96. package/dist-esm/common/resource.js +3 -1
  97. package/dist-esm/common/resource.js.map +1 -1
  98. package/dist-esm/common/trace-sanitizer.d.ts +82 -0
  99. package/dist-esm/common/trace-sanitizer.d.ts.map +1 -0
  100. package/dist-esm/common/trace-sanitizer.js +226 -0
  101. package/dist-esm/common/trace-sanitizer.js.map +1 -0
  102. package/dist-esm/index.d.ts +2 -1
  103. package/dist-esm/index.d.ts.map +1 -1
  104. package/dist-esm/index.js +2 -1
  105. package/dist-esm/index.js.map +1 -1
  106. package/dist-esm/lint/forbidden-attributes.d.ts +2 -2
  107. package/dist-esm/lint/forbidden-attributes.d.ts.map +1 -1
  108. package/dist-esm/lint/forbidden-attributes.js +43 -42
  109. package/dist-esm/lint/forbidden-attributes.js.map +1 -1
  110. package/dist-esm/lint/index.d.ts +1 -1
  111. package/dist-esm/lint/index.js +1 -1
  112. package/dist-esm/llmobs/index.d.ts +2 -2
  113. package/dist-esm/llmobs/index.js +2 -2
  114. package/dist-esm/llmobs/tier1-exporter.d.ts +2 -2
  115. package/dist-esm/llmobs/tier1-exporter.d.ts.map +1 -1
  116. package/dist-esm/llmobs/tier1-exporter.js +18 -15
  117. package/dist-esm/llmobs/tier1-exporter.js.map +1 -1
  118. package/dist-esm/llmobs/tier2-summarizer.d.ts.map +1 -1
  119. package/dist-esm/llmobs/tier2-summarizer.js +10 -4
  120. package/dist-esm/llmobs/tier2-summarizer.js.map +1 -1
  121. package/dist-esm/node/exporters/resilient-exporter.d.ts +14 -0
  122. package/dist-esm/node/exporters/resilient-exporter.d.ts.map +1 -1
  123. package/dist-esm/node/exporters/resilient-exporter.js +8 -1
  124. package/dist-esm/node/exporters/resilient-exporter.js.map +1 -1
  125. package/dist-esm/node/index.d.ts +2 -1
  126. package/dist-esm/node/index.d.ts.map +1 -1
  127. package/dist-esm/node/index.js +2 -1
  128. package/dist-esm/node/index.js.map +1 -1
  129. package/dist-esm/node/init.d.ts.map +1 -1
  130. package/dist-esm/node/init.js +61 -12
  131. package/dist-esm/node/init.js.map +1 -1
  132. package/dist-esm/node/log-processor.d.ts +41 -6
  133. package/dist-esm/node/log-processor.d.ts.map +1 -1
  134. package/dist-esm/node/log-processor.js +151 -62
  135. package/dist-esm/node/log-processor.js.map +1 -1
  136. package/dist-esm/node/metrics-client.d.ts.map +1 -1
  137. package/dist-esm/node/metrics-client.js.map +1 -1
  138. package/dist-esm/node/safe-logger.d.ts +55 -0
  139. package/dist-esm/node/safe-logger.d.ts.map +1 -0
  140. package/dist-esm/node/safe-logger.js +154 -0
  141. package/dist-esm/node/safe-logger.js.map +1 -0
  142. package/dist-esm/node/sanitizing-processor.d.ts +56 -0
  143. package/dist-esm/node/sanitizing-processor.d.ts.map +1 -0
  144. package/dist-esm/node/sanitizing-processor.js +120 -0
  145. package/dist-esm/node/sanitizing-processor.js.map +1 -0
  146. package/dist-esm/node/traced-socket.d.ts +47 -3
  147. package/dist-esm/node/traced-socket.d.ts.map +1 -1
  148. package/dist-esm/node/traced-socket.js +96 -19
  149. package/dist-esm/node/traced-socket.js.map +1 -1
  150. package/dist-esm/testing/in-memory-exporter.d.ts +3 -3
  151. package/dist-esm/testing/in-memory-exporter.d.ts.map +1 -1
  152. package/dist-esm/testing/in-memory-exporter.js +4 -2
  153. package/dist-esm/testing/in-memory-exporter.js.map +1 -1
  154. package/dist-esm/testing/index.d.ts +2 -2
  155. package/dist-esm/testing/index.js +2 -2
  156. package/dist-esm/types/index.d.ts +28 -1
  157. package/dist-esm/types/index.d.ts.map +1 -1
  158. package/dist-esm/types/index.js +1 -1
  159. package/package.json +17 -18
@@ -1,177 +1,520 @@
1
1
  /**
2
- * Tier 2 Traces Contract
2
+ * Tier 2 Traces Contract (v0.2.0)
3
3
  *
4
- * This file defines the Tier 2 telemetry contract:
5
- * - Forbidden attributes (removed by Collector)
6
- * - Hashed attributes (pseudonymized by Collector)
7
- * - Dropped attributes (removed by Collector)
8
- * - Forbidden value patterns (for lint-time detection)
4
+ * Single source of truth for Tier 2 sanitized trace telemetry.
5
+ * Mirrors: engineering/projects/o11y-refactor/contracts/tier2-traces.v0.2.0.json
9
6
  *
10
- * ENFORCEMENT: The OTEL Collector handles runtime enforcement.
11
- * These definitions are used for:
12
- * - ESLint rules (static analysis at CI time)
13
- * - Development warnings (guardrails.ts)
7
+ * Used by:
8
+ * - trace-sanitizer (SDK: which spans/attributes to export)
9
+ * - lint/forbidden-attributes (ESLint)
10
+ * - guardrails (dev-time warnings)
14
11
  * - Collector config generation
15
12
  *
16
- * See: obs/otel-collector/config-tiered.yaml
17
- * Source of truth: engineering/projects/o11y-refactor/contracts/tier2-traces.v0.3.0.json
13
+ * "request handler *" is a local extension for Express instrumentation (not in JSON).
18
14
  */
15
+ import { DeploymentTypeEnum } from "@superblocksteam/shared";
16
+ export function getAttributeName(attr) {
17
+ return typeof attr === "string" ? attr : attr.name;
18
+ }
19
19
  /**
20
- * Attributes that are FORBIDDEN in Tier 2 telemetry.
21
- * These contain sensitive data that should never leave the customer's environment.
22
- * The Collector strips these entirely (not hashed, not present in Tier 2).
20
+ * Span patterns from tier2-traces.v0.2.0.json.
21
+ * Suffix wildcard only: "HTTP POST *" matches "HTTP POST /api/..." or "POST /api/...".
23
22
  */
24
- export const TIER2_FORBIDDEN_ATTRIBUTES = new Set([
25
- // LLM/AI content
26
- 'llmobs.input',
27
- 'llmobs.output',
28
- 'prompt',
29
- 'code',
30
- 'tool_input',
31
- 'tool_output',
32
- // File content
33
- 'file_path',
34
- 'file_content',
35
- // Database content
36
- 'db.statement',
37
- 'db.query_text',
38
- 'db.query.text',
39
- // HTTP bodies and URLs
40
- 'http.request.body',
41
- 'http.response.body',
42
- 'url.full',
43
- 'url.query',
44
- 'http.url',
45
- 'http.target',
46
- // Resource identifiers (names are customer-specific)
47
- 'api-id',
48
- 'api_id',
49
- 'api-name',
50
- 'api_name',
51
- 'resource-id',
52
- 'resource_id',
53
- 'resource-name',
54
- 'resource_name',
55
- 'integration-id',
56
- 'integration_id',
57
- 'widget-type',
58
- 'branch',
59
- 'commit-id',
60
- 'commit_id',
61
- 'profile-id',
62
- 'profile_id',
63
- // Stack traces
64
- 'error.stack',
65
- 'exception.stacktrace',
66
- // Auth/secrets
67
- 'auth_token',
68
- 'api_key',
69
- 'authorization',
70
- 'cookie',
71
- 'x-api-key',
72
- ]);
23
+ export const TIER_2_TRACE_CONTRACT = [
24
+ {
25
+ name: "HTTP GET *",
26
+ allowedAttributes: [
27
+ "http.method",
28
+ { name: "http.route", maxCardinality: 150 },
29
+ "http.status_code",
30
+ "http.response_content_length",
31
+ { name: "http.flavor", allowedValues: ["1.0", "1.1", "2.0", "3.0"] },
32
+ ],
33
+ },
34
+ {
35
+ name: "HTTP POST *",
36
+ allowedAttributes: [
37
+ "http.method",
38
+ { name: "http.route", maxCardinality: 150 },
39
+ "http.status_code",
40
+ "http.response_content_length",
41
+ "http.request_content_length",
42
+ { name: "http.flavor", allowedValues: ["1.0", "1.1", "2.0", "3.0"] },
43
+ ],
44
+ },
45
+ {
46
+ name: "HTTP PUT *",
47
+ allowedAttributes: [
48
+ "http.method",
49
+ { name: "http.route", maxCardinality: 150 },
50
+ "http.status_code",
51
+ "http.response_content_length",
52
+ "http.request_content_length",
53
+ ],
54
+ },
55
+ {
56
+ name: "HTTP DELETE *",
57
+ allowedAttributes: [
58
+ "http.method",
59
+ { name: "http.route", maxCardinality: 150 },
60
+ "http.status_code",
61
+ "http.response_content_length",
62
+ ],
63
+ },
64
+ {
65
+ name: "HTTP PATCH *",
66
+ allowedAttributes: [
67
+ "http.method",
68
+ { name: "http.route", maxCardinality: 150 },
69
+ "http.status_code",
70
+ "http.response_content_length",
71
+ "http.request_content_length",
72
+ ],
73
+ },
74
+ {
75
+ name: "request handler *",
76
+ allowedAttributes: [
77
+ "http.method",
78
+ { name: "http.route", maxCardinality: 150 },
79
+ "http.status_code",
80
+ "http.response_content_length",
81
+ "http.request_content_length",
82
+ { name: "http.flavor", allowedValues: ["1.0", "1.1", "2.0", "3.0"] },
83
+ "express.route",
84
+ ],
85
+ },
86
+ {
87
+ name: "WS SERVER *",
88
+ allowedAttributes: [
89
+ { name: "messaging.system", allowedValues: ["ws", "websocket"] },
90
+ { name: "messaging.destination_kind", allowedValues: ["websocket"] },
91
+ { name: "ws.handler", maxCardinality: 80 },
92
+ ],
93
+ },
94
+ {
95
+ name: "WS CLIENT *",
96
+ allowedAttributes: [
97
+ { name: "messaging.system", allowedValues: ["ws", "websocket"] },
98
+ ],
99
+ },
100
+ {
101
+ name: "WS HANDLER *",
102
+ allowedAttributes: [
103
+ { name: "messaging.system", allowedValues: ["ws", "websocket"] },
104
+ { name: "messaging.destination_kind", allowedValues: ["websocket"] },
105
+ ],
106
+ },
107
+ {
108
+ name: "api.execute",
109
+ alwaysSample: true,
110
+ allowedAttributes: [
111
+ { name: "view-mode", allowedValues: ["edit", "deployed", "preview"] },
112
+ {
113
+ name: "api.status",
114
+ allowedValues: ["success", "error", "timeout", "cancelled"],
115
+ },
116
+ { name: "api.type", allowedValues: ["api", "workflow", "scheduled_job"] },
117
+ { name: "api.step_count", type: "number" },
118
+ { name: "api.duration_ms", type: "number" },
119
+ { name: "remote", allowedValues: ["true", "false"] },
120
+ "otel.status_code",
121
+ "otel.status_description",
122
+ ],
123
+ },
124
+ {
125
+ name: "api.step",
126
+ allowedAttributes: [
127
+ { name: "step.type", maxCardinality: 50 },
128
+ { name: "step.status", allowedValues: ["success", "error"] },
129
+ { name: "step.duration_ms", type: "number" },
130
+ { name: "step.retry_count", type: "number" },
131
+ "otel.status_code",
132
+ ],
133
+ },
134
+ {
135
+ name: "api.block.*",
136
+ allowedAttributes: [
137
+ { name: "block.type", maxCardinality: 30 },
138
+ { name: "block.status", allowedValues: ["success", "error"] },
139
+ ],
140
+ },
141
+ {
142
+ name: "plugin.*",
143
+ allowedAttributes: [
144
+ { name: "plugin.name", maxCardinality: 80 },
145
+ {
146
+ name: "plugin.event",
147
+ allowedValues: ["execute", "test", "metadata", "pre_delete"],
148
+ },
149
+ { name: "plugin.result", allowedValues: ["succeeded", "failed"] },
150
+ { name: "plugin.duration_ms", type: "number" },
151
+ "otel.status_code",
152
+ ],
153
+ },
154
+ {
155
+ name: "db.*",
156
+ allowedAttributes: [
157
+ {
158
+ name: "db.system",
159
+ allowedValues: [
160
+ "postgresql",
161
+ "mysql",
162
+ "mssql",
163
+ "mongodb",
164
+ "redis",
165
+ "snowflake",
166
+ "bigquery",
167
+ "databricks",
168
+ "dynamodb",
169
+ "sqlite",
170
+ ],
171
+ },
172
+ {
173
+ name: "db.operation",
174
+ allowedValues: ["select", "insert", "update", "delete", "other"],
175
+ },
176
+ { name: "db.name", maxCardinality: 50 },
177
+ "otel.status_code",
178
+ ],
179
+ },
180
+ {
181
+ name: "llm.request",
182
+ allowedAttributes: [
183
+ {
184
+ name: "gen_ai.operation.name",
185
+ allowedValues: [
186
+ "chat",
187
+ "text_completion",
188
+ "embeddings",
189
+ "execute_tool",
190
+ "invoke_agent",
191
+ "generate_content",
192
+ ],
193
+ },
194
+ {
195
+ name: "gen_ai.system",
196
+ allowedValues: [
197
+ "openai",
198
+ "anthropic",
199
+ "aws.bedrock",
200
+ "azure.ai.openai",
201
+ "azure.ai.inference",
202
+ "gcp.gemini",
203
+ "gcp.vertex_ai",
204
+ "cohere",
205
+ "mistral_ai",
206
+ "deepseek",
207
+ "groq",
208
+ ],
209
+ },
210
+ {
211
+ name: "gen_ai.provider.name",
212
+ allowedValues: [
213
+ "openai",
214
+ "anthropic",
215
+ "aws.bedrock",
216
+ "azure.ai.openai",
217
+ "azure.ai.inference",
218
+ "gcp.gemini",
219
+ "gcp.vertex_ai",
220
+ "cohere",
221
+ "mistral_ai",
222
+ "deepseek",
223
+ "groq",
224
+ ],
225
+ },
226
+ { name: "gen_ai.request.model", maxCardinality: 50 },
227
+ { name: "gen_ai.response.model", maxCardinality: 50 },
228
+ "llm.provider",
229
+ "llm.model",
230
+ "llm.status",
231
+ {
232
+ name: "llm.error_category",
233
+ allowedValues: [
234
+ "none",
235
+ "rate_limit",
236
+ "context_length",
237
+ "content_filter",
238
+ "quota",
239
+ "network",
240
+ "timeout",
241
+ "auth_error",
242
+ "api_error",
243
+ "validation_error",
244
+ "aborted",
245
+ "unknown",
246
+ ],
247
+ },
248
+ "llm.duration_ms",
249
+ "gen_ai.usage.input_tokens",
250
+ "gen_ai.usage.output_tokens",
251
+ "llm.input_tokens",
252
+ "llm.output_tokens",
253
+ "llm.total_tokens",
254
+ "llm.reasoning_tokens",
255
+ "llm.cached_tokens",
256
+ "llm.cost_usd",
257
+ { name: "gen_ai.client.time_to_first_token", type: "number" },
258
+ { name: "llm.time_to_first_token_ms", type: "number" },
259
+ "gen_ai.response.finish_reasons",
260
+ "llm.finish_reason",
261
+ "otel.status_code",
262
+ ],
263
+ },
264
+ {
265
+ name: "llm.tool_call",
266
+ allowedAttributes: [
267
+ { name: "tool.name", maxCardinality: 50 },
268
+ { name: "tool.status", allowedValues: ["success", "error"] },
269
+ {
270
+ name: "tool.error_category",
271
+ allowedValues: [
272
+ "none",
273
+ "timeout",
274
+ "execution_error",
275
+ "validation_error",
276
+ "permission_denied",
277
+ "not_found",
278
+ "unknown",
279
+ ],
280
+ },
281
+ { name: "tool.duration_ms", type: "number" },
282
+ "otel.status_code",
283
+ ],
284
+ },
285
+ {
286
+ name: "ai.streamText",
287
+ allowedAttributes: [
288
+ "llm.provider",
289
+ "llm.model",
290
+ "llm.total_tokens",
291
+ "llm.step_count",
292
+ ],
293
+ },
294
+ {
295
+ name: "ai.streamText.step",
296
+ allowedAttributes: [
297
+ { name: "step.number", type: "number" },
298
+ {
299
+ name: "step.type",
300
+ allowedValues: ["text", "tool_call", "thinking", "reasoning"],
301
+ },
302
+ ],
303
+ },
304
+ {
305
+ name: "clark.session",
306
+ allowedAttributes: [
307
+ "session.duration_ms",
308
+ "session.step_count",
309
+ "session.llm_call_count",
310
+ "session.tool_call_count",
311
+ "session.total_tokens",
312
+ {
313
+ name: "session.outcome",
314
+ allowedValues: ["success", "error", "aborted"],
315
+ },
316
+ ],
317
+ },
318
+ {
319
+ name: "clark.debug_loop",
320
+ allowedAttributes: [
321
+ { name: "loop.iteration", type: "number" },
322
+ {
323
+ name: "loop.reason",
324
+ allowedValues: ["error_recovery", "validation_failure", "retry"],
325
+ },
326
+ { name: "loop.duration_ms", type: "number" },
327
+ ],
328
+ },
329
+ {
330
+ name: "grpc.*",
331
+ allowedAttributes: [
332
+ { name: "rpc.system", allowedValues: ["grpc"] },
333
+ { name: "rpc.service", maxCardinality: 50 },
334
+ { name: "rpc.method", maxCardinality: 100 },
335
+ { name: "rpc.grpc.status_code", type: "number" },
336
+ ],
337
+ },
338
+ {
339
+ name: "kafka.*",
340
+ allowedAttributes: [
341
+ { name: "messaging.system", allowedValues: ["kafka"] },
342
+ { name: "messaging.destination", maxCardinality: 50 },
343
+ {
344
+ name: "messaging.operation",
345
+ allowedValues: ["publish", "receive", "process"],
346
+ },
347
+ ],
348
+ },
349
+ {
350
+ name: "redis.*",
351
+ allowedAttributes: [
352
+ { name: "db.system", allowedValues: ["redis"] },
353
+ { name: "db.operation", maxCardinality: 30 },
354
+ ],
355
+ },
356
+ {
357
+ name: "fetch",
358
+ allowedAttributes: [
359
+ "http.method",
360
+ "http.status_code",
361
+ { name: "http.host", maxCardinality: 200 },
362
+ ],
363
+ },
364
+ {
365
+ name: "schedule.*",
366
+ allowedAttributes: [
367
+ {
368
+ name: "schedule.type",
369
+ allowedValues: ["cron", "interval", "one_time"],
370
+ },
371
+ {
372
+ name: "schedule.status",
373
+ allowedValues: ["success", "error", "skipped"],
374
+ },
375
+ ],
376
+ },
377
+ ];
73
378
  /**
74
- * Attributes that should be HASHED (pseudonymized) in Tier 2 telemetry.
75
- * The Collector replaces these with SHA256 hashes for privacy.
76
- * Hashes enable aggregate analysis without exposing plaintext identifiers.
77
- *
78
- * Mapping:
79
- * user-email, user.email, etc. → user.hash
80
- * organization-id, organization_id → organization.hash
81
- * application-id, application_id → application.hash
82
- * session.id → session.hash
83
- * enduser.id → enduser.pseudo.id
379
+ * Cloud trace contract: match-all span name ("*") so no spans are dropped by name.
380
+ * Attribute allowlist is not used when attributeAllowlistPassthrough is true.
84
381
  */
85
- export const TIER2_HASHED_ATTRIBUTES = new Set([
86
- // User identity (hashed to user.hash)
87
- 'user-email',
88
- 'user.email',
89
- 'user_email',
90
- 'user.id',
91
- 'enduser.email',
92
- // Organization identity (hashed to organization.hash)
93
- 'organization-id',
94
- 'organization_id',
95
- // Application identity (hashed to application.hash)
96
- 'application-id',
97
- 'application_id',
98
- // Session/enduser identity
99
- 'session.id',
100
- 'enduser.id',
101
- ]);
382
+ export const CLOUD_TRACE_CONTRACT = [
383
+ { name: "*", allowedAttributes: [] },
384
+ ];
102
385
  /**
103
- * Attributes that should be DROPPED entirely in Tier 2.
104
- * These are correlation IDs that don't provide operational value.
386
+ * Returns the trace contract (span definitions) for the given deployment type.
387
+ * Cloud: match-all so no traces are dropped by span name.
388
+ * Cloud-prem: Tier 2 contract (named spans only).
105
389
  */
106
- export const TIER2_DROPPED_ATTRIBUTES = new Set([
107
- 'correlation-id',
108
- 'correlation_id',
109
- 'request-id',
110
- 'request_id',
111
- 'trace-id',
112
- 'execution_id',
113
- 'binding_keys',
114
- ]);
390
+ export function getTraceContract(deploymentType) {
391
+ switch (deploymentType) {
392
+ case DeploymentTypeEnum.CLOUD:
393
+ return CLOUD_TRACE_CONTRACT;
394
+ case DeploymentTypeEnum.CLOUD_PREM:
395
+ default:
396
+ return TIER_2_TRACE_CONTRACT;
397
+ }
398
+ }
399
+ // ---------------------------------------------------------------------------
400
+ // Forbidden / hashed / dropped attribute names (v0.2.0 JSON)
401
+ // ---------------------------------------------------------------------------
402
+ /** Forbidden in Tier 2 (forbiddenAttributes in contract). Collector strips these entirely. */
403
+ export const FORBIDDEN_TIER_2_SPAN_ATTRIBUTES = [
404
+ "llmobs.input",
405
+ "llmobs.output",
406
+ "prompt",
407
+ "code",
408
+ "tool_input",
409
+ "tool_output",
410
+ "file_path",
411
+ "file_content",
412
+ "db.statement",
413
+ "db.query_text",
414
+ "db.query.text",
415
+ "http.request.body",
416
+ "http.response.body",
417
+ "url.full",
418
+ "url.query",
419
+ "http.url",
420
+ "http.target",
421
+ "user-email",
422
+ "user.email",
423
+ "user_email",
424
+ "enduser.email",
425
+ "api-name",
426
+ "api_name",
427
+ "resource-name",
428
+ "resource_name",
429
+ "widget-type",
430
+ "branch",
431
+ "error.stack",
432
+ "exception.stacktrace",
433
+ "auth_token",
434
+ "api_key",
435
+ "authorization",
436
+ "cookie",
437
+ "x-api-key",
438
+ ];
439
+ /** Hashed (keyed HMAC) for Tier 2 (hashedAttributes in contract). */
440
+ export const HASHED_TIER_2_SPAN_ATTRIBUTES = [];
441
+ /** Dropped — high cardinality, no hash value (droppedAttributes in contract). */
442
+ export const DROPPED_HIGH_CARDINALITY_ATTRIBUTES = ["binding_keys"];
443
+ // ---------------------------------------------------------------------------
444
+ // Set views (for lint, guardrails: fast .has() lookup)
445
+ // ---------------------------------------------------------------------------
446
+ export const TIER2_FORBIDDEN_ATTRIBUTES = new Set(FORBIDDEN_TIER_2_SPAN_ATTRIBUTES);
447
+ export const TIER2_HASHED_ATTRIBUTES = new Set(HASHED_TIER_2_SPAN_ATTRIBUTES);
448
+ export const TIER2_DROPPED_ATTRIBUTES = new Set(DROPPED_HIGH_CARDINALITY_ATTRIBUTES);
449
+ // ---------------------------------------------------------------------------
450
+ // Per-deployment attribute sets (for trace-sanitizer)
451
+ // ---------------------------------------------------------------------------
452
+ /** Empty set used for cloud (relaxed policy: no drop, no hash, no forbidden). */
453
+ const EMPTY_ATTRIBUTE_SET = new Set();
115
454
  /**
116
- * Spans that should ALWAYS be sampled (never dropped by rate limiting).
455
+ * Returns the Tier 2 trace attribute sets and contract options for the given deployment type.
456
+ * Cloud: relaxed policy (no attributes dropped/hashed), match-all span names, pass-through attributes.
457
+ * Cloud-prem: full Tier 2 contract (forbidden/dropped/hashed), named spans only, pass-through attributes.
117
458
  */
118
- export const ALWAYS_SAMPLE_SPANS = new Set([
119
- 'api.execute',
120
- ]);
459
+ export function getTraceSanitizerAttributeSets(deploymentType) {
460
+ const spanDefinitions = getTraceContract(deploymentType);
461
+ const attributeAllowlistPassthrough = true;
462
+ switch (deploymentType) {
463
+ case DeploymentTypeEnum.CLOUD:
464
+ return {
465
+ forbiddenAttributes: EMPTY_ATTRIBUTE_SET,
466
+ droppedAttributes: EMPTY_ATTRIBUTE_SET,
467
+ hashedAttributes: EMPTY_ATTRIBUTE_SET,
468
+ spanDefinitions,
469
+ attributeAllowlistPassthrough,
470
+ };
471
+ case DeploymentTypeEnum.CLOUD_PREM:
472
+ default:
473
+ return {
474
+ forbiddenAttributes: TIER2_FORBIDDEN_ATTRIBUTES,
475
+ droppedAttributes: TIER2_DROPPED_ATTRIBUTES,
476
+ hashedAttributes: TIER2_HASHED_ATTRIBUTES,
477
+ spanDefinitions,
478
+ attributeAllowlistPassthrough,
479
+ };
480
+ }
481
+ }
482
+ // ---------------------------------------------------------------------------
483
+ // Always-sample and value patterns (v0.2.0 samplingPolicy + lint-time)
484
+ // ---------------------------------------------------------------------------
485
+ /** Spans that should ALWAYS be sampled (samplingPolicy.alwaysSampleSpans in contract). */
486
+ export const ALWAYS_SAMPLE_SPANS = new Set(["api.execute"]);
121
487
  /**
122
- * Patterns that indicate forbidden content in attribute values.
123
- * Used for secondary filtering when attribute names aren't explicit.
124
- *
125
- * IMPORTANT: Patterns should NOT use ^ and $ anchors so they match
126
- * secrets embedded anywhere in a string (e.g., in query params, headers).
488
+ * Patterns that indicate forbidden content in attribute values (e.g. secrets in strings).
489
+ * No ^/$ anchors so they match secrets embedded anywhere.
490
+ * It's not used by TraceSanitizer, only in guardrails.
127
491
  */
128
492
  export const FORBIDDEN_VALUE_PATTERNS = [
129
- // JWT tokens (anywhere in string)
130
- // Header (eyJ...) and payload (eyJ...) must be base64url encoded JSON
131
- // Signature can be any length (even short for test tokens)
132
493
  /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+/,
133
- // API keys (sk-/pk- prefix patterns with word boundaries)
134
494
  /\b(sk|pk)-[a-zA-Z0-9]{32,}\b/,
135
- // Bearer tokens (anywhere in string)
136
495
  /Bearer\s+[A-Za-z0-9._-]{20,}/,
137
- // PEM blocks (anywhere in string)
138
496
  /-----BEGIN\s+(RSA\s+)?(PRIVATE|PUBLIC)\s+KEY-----/,
139
- // AWS access key IDs
140
497
  /\bAKIA[A-Z0-9]{16}\b/,
141
- // GitHub tokens
142
498
  /\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{36,}\b/,
143
- // Generic API key patterns (key=value or key:value with long alphanumeric)
144
499
  /\b(api[_-]?key|apikey|secret[_-]?key|access[_-]?token)[=:]\s*[A-Za-z0-9_-]{20,}\b/i,
145
500
  ];
146
- /**
147
- * Check if an attribute name is forbidden in Tier 2.
148
- */
501
+ // ---------------------------------------------------------------------------
502
+ // Helpers (for lint, guardrails)
503
+ // ---------------------------------------------------------------------------
149
504
  export function isForbiddenAttribute(name) {
150
505
  return TIER2_FORBIDDEN_ATTRIBUTES.has(name);
151
506
  }
152
- /**
153
- * Check if an attribute should be hashed in Tier 2.
154
- */
155
507
  export function isHashedAttribute(name) {
156
508
  return TIER2_HASHED_ATTRIBUTES.has(name);
157
509
  }
158
- /**
159
- * Check if an attribute should be dropped in Tier 2.
160
- */
161
510
  export function isDroppedAttribute(name) {
162
511
  return TIER2_DROPPED_ATTRIBUTES.has(name);
163
512
  }
164
- /**
165
- * Check if a value contains forbidden patterns (like tokens, keys).
166
- */
167
513
  export function containsForbiddenPattern(value) {
168
- if (typeof value !== 'string')
514
+ if (typeof value !== "string")
169
515
  return false;
170
- return FORBIDDEN_VALUE_PATTERNS.some(pattern => pattern.test(value));
516
+ return FORBIDDEN_VALUE_PATTERNS.some((pattern) => pattern.test(value));
171
517
  }
172
- /**
173
- * Check if a span should always be sampled.
174
- */
175
518
  export function shouldAlwaysSample(spanName) {
176
519
  return ALWAYS_SAMPLE_SPANS.has(spanName);
177
520
  }