@openwop/openwop-conformance 1.153.0 → 1.154.0

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 (51) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +9 -0
  3. package/dist/cli.js +7 -2
  4. package/package.json +31 -2
  5. package/schemas/CORPUS-STAMP.json +99 -3
  6. package/src/cli.ts +7 -5
  7. package/src/global-setup.ts +13 -0
  8. package/src/lib/corpus-stamp.ts +125 -0
  9. package/src/lib/capabilities-auth-subject-link.test.ts +0 -103
  10. package/src/lib/fork-availability.test.ts +0 -69
  11. package/src/lib/global-setup.test.ts +0 -76
  12. package/src/lib/grpc-framing.test.ts +0 -96
  13. package/src/lib/oidc-issuer.test.ts +0 -328
  14. package/src/lib/otel-collector-grpc.test.ts +0 -191
  15. package/src/lib/otel-collector.test.ts +0 -303
  16. package/src/lib/otlp-protobuf.test.ts +0 -461
  17. package/src/lib/polling.test.ts +0 -80
  18. package/src/lib/requirement-ids.test.ts +0 -83
  19. package/src/lib/requirement-ledger.test.ts +0 -75
  20. package/src/lib/risk-disposition.test.ts +0 -91
  21. package/src/lib/saml-idp.test.ts +0 -127
  22. package/src/lib/spec-coherence-registry.test.ts +0 -155
  23. package/src/lib/webhook-receiver.test.ts +0 -144
  24. package/src/scenarios/artifact-schema-compile-bounded.test.ts +0 -126
  25. package/src/scenarios/artifact-type-legacy-ids.test.ts +0 -124
  26. package/src/scenarios/capability-example-root-layout.test.ts +0 -272
  27. package/src/scenarios/certification-floor-enforcement.test.ts +0 -204
  28. package/src/scenarios/chain-subchain-unsupported-refused.test.ts +0 -70
  29. package/src/scenarios/compensation-profile.test.ts +0 -340
  30. package/src/scenarios/core-manifest-and-extension-registry.test.ts +0 -250
  31. package/src/scenarios/discovery-canonical-family-no-shadow.test.ts +0 -219
  32. package/src/scenarios/edge-condition-truthy-falsy.test.ts +0 -108
  33. package/src/scenarios/effect-identity-composition.test.ts +0 -129
  34. package/src/scenarios/effect-identity-cross-scope.test.ts +0 -82
  35. package/src/scenarios/error-envelope-canonical-shape.test.ts +0 -64
  36. package/src/scenarios/form-content-packs.test.ts +0 -415
  37. package/src/scenarios/multi-region-effect-vocabulary.test.ts +0 -175
  38. package/src/scenarios/normative-example-extraction.test.ts +0 -242
  39. package/src/scenarios/openapi-asyncapi-sdk-parity.test.ts +0 -309
  40. package/src/scenarios/pack-manifest-extensions.test.ts +0 -203
  41. package/src/scenarios/protocol-version-grammar.test.ts +0 -119
  42. package/src/scenarios/registry-declarative-kinds.test.ts +0 -121
  43. package/src/scenarios/rfc-0147-self-audit.test.ts +0 -104
  44. package/src/scenarios/rfc-lifecycle-coherence.test.ts +0 -215
  45. package/src/scenarios/semantic-digest-v2.test.ts +0 -128
  46. package/src/scenarios/spec-corpus-validity.test.ts +0 -1727
  47. package/src/scenarios/spec-section-citations.test.ts +0 -132
  48. package/src/scenarios/tool-result-trust-monotone.test.ts +0 -168
  49. package/src/scenarios/versioned-composition-profiles.test.ts +0 -201
  50. package/src/scenarios/workflow-chain-internal-flag.test.ts +0 -84
  51. package/src/scenarios/workload-identity-profile.test.ts +0 -184
@@ -1,303 +0,0 @@
1
- /**
2
- * End-to-end unit tests for the OTel collector's HTTP receiver.
3
- *
4
- * Boots the collector on an ephemeral port, posts synthesized OTLP
5
- * payloads (both JSON and protobuf), and asserts the collector
6
- * correctly captures them. Closes the gap the senior code-review pass
7
- * flagged as MEDIUM-3 — the protobuf decoder has 18 unit tests, but
8
- * those don't exercise the collector's HTTP receive wiring
9
- * (content-type routing, body-size guard, error responses).
10
- *
11
- * Server-free (binds to 127.0.0.1 on an ephemeral port; no host required).
12
- *
13
- * @see conformance/src/lib/otel-collector.ts
14
- * @see conformance/src/lib/otlp-protobuf.ts
15
- */
16
-
17
- import { afterAll, beforeAll, describe, it, expect } from 'vitest';
18
- import { OtelCollector } from './otel-collector.js';
19
-
20
- // ─── Minimal in-test OTLP/protobuf encoder ─────────────────────────────────
21
- // Hand-rolled so the e2e test doesn't depend on the decoder's own test file
22
- // re-exporting its writer. ~50 LOC; only encodes the wire-format subset this
23
- // file actually emits.
24
-
25
- const WIRE_I64 = 1;
26
- const WIRE_LEN = 2;
27
-
28
- function encVarint(out: number[], v: number | bigint): void {
29
- let x = typeof v === 'bigint' ? v : BigInt(v);
30
- while (x >= 0x80n) {
31
- out.push(Number(x & 0x7fn) | 0x80);
32
- x >>= 7n;
33
- }
34
- out.push(Number(x & 0x7fn));
35
- }
36
-
37
- function encTag(out: number[], field: number, wire: number): void {
38
- encVarint(out, (field << 3) | wire);
39
- }
40
-
41
- function encString(out: number[], field: number, s: string): void {
42
- const bytes = new TextEncoder().encode(s);
43
- encTag(out, field, WIRE_LEN);
44
- encVarint(out, bytes.length);
45
- for (const b of bytes) out.push(b);
46
- }
47
-
48
- function encBytesHex(out: number[], field: number, hex: string): void {
49
- const len = hex.length / 2;
50
- encTag(out, field, WIRE_LEN);
51
- encVarint(out, len);
52
- for (let i = 0; i < len; i++) {
53
- out.push(Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16));
54
- }
55
- }
56
-
57
- function encFixed64(out: number[], field: number, v: bigint): void {
58
- encTag(out, field, WIRE_I64);
59
- const buf = new ArrayBuffer(8);
60
- new DataView(buf).setBigUint64(0, v, true);
61
- for (let i = 0; i < 8; i++) out.push(new Uint8Array(buf)[i]);
62
- }
63
-
64
- function encMessage(out: number[], field: number, body: number[]): void {
65
- encTag(out, field, WIRE_LEN);
66
- encVarint(out, body.length);
67
- for (const b of body) out.push(b);
68
- }
69
-
70
- function buildMinimalProtobufExportTrace(spanName: string, traceIdHex: string, runIdAttr: string): Uint8Array {
71
- // KeyValue { key: "openwop.run_id", value: { stringValue: runIdAttr } }
72
- const anyValue: number[] = [];
73
- encString(anyValue, 1, runIdAttr);
74
- const kv: number[] = [];
75
- encString(kv, 1, 'openwop.run_id');
76
- encMessage(kv, 2, anyValue);
77
-
78
- // Span { trace_id, span_id, name, start, end, attributes }
79
- const span: number[] = [];
80
- encBytesHex(span, 1, traceIdHex);
81
- encBytesHex(span, 2, '0123456789abcdef');
82
- encString(span, 5, spanName);
83
- encFixed64(span, 7, 1700000000000000000n);
84
- encFixed64(span, 8, 1700000000100000000n);
85
- encMessage(span, 9, kv);
86
-
87
- // ScopeSpans { spans: [span] }
88
- const scopeSpans: number[] = [];
89
- encMessage(scopeSpans, 2, span);
90
-
91
- // ResourceSpans { scope_spans: [scopeSpans] }
92
- const resourceSpans: number[] = [];
93
- encMessage(resourceSpans, 2, scopeSpans);
94
-
95
- // ExportTraceServiceRequest { resource_spans: [resourceSpans] }
96
- const req: number[] = [];
97
- encMessage(req, 1, resourceSpans);
98
-
99
- return new Uint8Array(req);
100
- }
101
-
102
- // ─── Test fixture ──────────────────────────────────────────────────────────
103
-
104
- let collector: OtelCollector;
105
- let endpoint: string;
106
-
107
- beforeAll(async () => {
108
- collector = new OtelCollector();
109
- await collector.start(0);
110
- endpoint = collector.endpoint();
111
- });
112
-
113
- afterAll(async () => {
114
- await collector.stop();
115
- });
116
-
117
- // ─── Tests ─────────────────────────────────────────────────────────────────
118
-
119
- describe('OtelCollector: HTTP receiver wiring', () => {
120
- it('accepts OTLP/HTTP-protobuf POST on /v1/traces and captures spans', async () => {
121
- collector.reset();
122
- const body = buildMinimalProtobufExportTrace(
123
- 'openwop.run',
124
- '0123456789abcdef0123456789abcdef',
125
- 'run-pb-e2e',
126
- );
127
-
128
- const res = await fetch(`${endpoint}/v1/traces`, {
129
- method: 'POST',
130
- headers: { 'Content-Type': 'application/x-protobuf' },
131
- body,
132
- });
133
-
134
- expect(res.status).toBe(200);
135
-
136
- const captured = collector.spansWithAttribute('openwop.run_id', 'run-pb-e2e');
137
- expect(captured.length).toBe(1);
138
- expect(captured[0].name).toBe('openwop.run');
139
- expect(captured[0].traceId).toBe('0123456789abcdef0123456789abcdef');
140
- });
141
-
142
- it('accepts OTLP/HTTP-JSON POST on /v1/traces and captures spans', async () => {
143
- collector.reset();
144
- const payload = {
145
- resourceSpans: [
146
- {
147
- resource: { attributes: [] },
148
- scopeSpans: [
149
- {
150
- spans: [
151
- {
152
- traceId: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
153
- spanId: 'bbbbbbbbbbbbbbbb',
154
- name: 'openwop.run',
155
- startTimeUnixNano: '1700000000000000000',
156
- endTimeUnixNano: '1700000000050000000',
157
- attributes: [
158
- { key: 'openwop.run_id', value: { stringValue: 'run-json-e2e' } },
159
- ],
160
- },
161
- ],
162
- },
163
- ],
164
- },
165
- ],
166
- };
167
-
168
- const res = await fetch(`${endpoint}/v1/traces`, {
169
- method: 'POST',
170
- headers: { 'Content-Type': 'application/json' },
171
- body: JSON.stringify(payload),
172
- });
173
-
174
- expect(res.status).toBe(200);
175
-
176
- const captured = collector.spansWithAttribute('openwop.run_id', 'run-json-e2e');
177
- expect(captured.length).toBe(1);
178
- expect(captured[0].name).toBe('openwop.run');
179
- });
180
-
181
- // Note: the collector also accepts "no Content-Type" as JSON for
182
- // back-compat with non-spec OTLP clients. fetch() can't reproduce
183
- // that case — Node automatically sets Content-Type when given a body
184
- // — so the empty-content-type path is exercised only via direct
185
- // node:http use (out of scope for this e2e suite).
186
-
187
- it('returns 415 for an unsupported Content-Type', async () => {
188
- collector.reset();
189
- const res = await fetch(`${endpoint}/v1/traces`, {
190
- method: 'POST',
191
- headers: { 'Content-Type': 'text/csv' },
192
- body: 'a,b,c\n1,2,3',
193
- });
194
-
195
- expect(res.status).toBe(415);
196
- const body = (await res.json()) as { error?: string; message?: string };
197
- expect(body.error).toBe('unsupported_media_type');
198
- expect(body.message).toContain('text/csv');
199
- expect(collector.spans().length).toBe(0);
200
- });
201
-
202
- it('returns 400 for malformed JSON', async () => {
203
- collector.reset();
204
- const res = await fetch(`${endpoint}/v1/traces`, {
205
- method: 'POST',
206
- headers: { 'Content-Type': 'application/json' },
207
- body: '{ this is not valid json',
208
- });
209
-
210
- expect(res.status).toBe(400);
211
- const body = (await res.json()) as { error?: string };
212
- expect(body.error).toBe('invalid_json');
213
- });
214
-
215
- it('returns 400 for malformed protobuf', async () => {
216
- collector.reset();
217
- // Garbage bytes — first byte is a tag for field 0 (invalid) which the
218
- // decoder skips, but the second byte is mid-varint with continuation
219
- // bit set and no follow-up → readVarint throws on unexpected EOF.
220
- const res = await fetch(`${endpoint}/v1/traces`, {
221
- method: 'POST',
222
- headers: { 'Content-Type': 'application/x-protobuf' },
223
- body: new Uint8Array([0x0a, 0xff]),
224
- });
225
-
226
- expect(res.status).toBe(400);
227
- const body = (await res.json()) as { error?: string };
228
- expect(body.error).toBe('invalid_protobuf');
229
- });
230
-
231
- it('returns 405 for non-POST methods', async () => {
232
- collector.reset();
233
- const res = await fetch(`${endpoint}/v1/traces`, { method: 'GET' });
234
- expect(res.status).toBe(405);
235
- });
236
-
237
- it('returns 413 when body exceeds 16 MiB cap', async () => {
238
- collector.reset();
239
- // 16 MiB + 1 byte. Use a fresh ArrayBuffer to avoid TypedArray-cap issues.
240
- const oversize = new Uint8Array(16 * 1024 * 1024 + 1);
241
- oversize.fill(0x00);
242
-
243
- const res = await fetch(`${endpoint}/v1/traces`, {
244
- method: 'POST',
245
- headers: { 'Content-Type': 'application/x-protobuf' },
246
- body: oversize,
247
- });
248
-
249
- expect(res.status).toBe(413);
250
- const body = (await res.json()) as { error?: string };
251
- expect(body.error).toBe('payload_too_large');
252
- }, 30_000); // larger timeout — uploading 16 MiB to localhost still costs a few hundred ms
253
-
254
- it('routes /v1/metrics to the metrics ingest path (JSON)', async () => {
255
- collector.reset();
256
- const payload = {
257
- resourceMetrics: [
258
- {
259
- scopeMetrics: [
260
- {
261
- metrics: [
262
- {
263
- name: 'openwop.queue.depth',
264
- unit: 'count',
265
- gauge: {
266
- dataPoints: [
267
- {
268
- asDouble: 3,
269
- attributes: [],
270
- },
271
- ],
272
- },
273
- },
274
- ],
275
- },
276
- ],
277
- },
278
- ],
279
- };
280
- const res = await fetch(`${endpoint}/v1/metrics`, {
281
- method: 'POST',
282
- headers: { 'Content-Type': 'application/json' },
283
- body: JSON.stringify(payload),
284
- });
285
- expect(res.status).toBe(200);
286
- const m = collector.metricByName('openwop.queue.depth');
287
- expect(m).toBeDefined();
288
- expect(m?.kind).toBe('gauge');
289
- expect(m?.dataPoint.value).toBe(3);
290
- });
291
-
292
- it('200-OKs unknown paths without ingesting (forward-compat for /v1/logs)', async () => {
293
- collector.reset();
294
- const res = await fetch(`${endpoint}/v1/logs`, {
295
- method: 'POST',
296
- headers: { 'Content-Type': 'application/json' },
297
- body: '{}',
298
- });
299
- expect(res.status).toBe(200);
300
- expect(collector.spans().length).toBe(0);
301
- expect(collector.metrics().length).toBe(0);
302
- });
303
- });