@riddledc/riddle-proof 0.7.45 → 0.7.47

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.
package/README.md CHANGED
@@ -224,11 +224,15 @@ success pair across multiple viewports. Repeated sequences also record
224
224
  `sequence_cycle: true` after the first cycle.
225
225
 
226
226
  Set `capture_request_body: true` to include compact request-body evidence on
227
- mock hits. Add `request_body_contains` or `request_body_patterns` when the
228
- request body is part of the contract, such as proving that a save request
229
- references the build ID returned by a prior mocked build response. Body
230
- assertions use the full request body for matching and store only length plus a
231
- compact sample in the proof evidence.
227
+ mock hits. Add `request_body_contains` / `request_body_patterns` or
228
+ `request_body_not_contains` / `request_body_not_patterns` when the request body
229
+ is part of the contract, such as proving that a save request references the
230
+ current build ID returned by a prior mocked build response and not a stale one.
231
+ Body assertions use the full request body for matching and store only length
232
+ plus a compact sample in the proof evidence. For sequenced mocks, the same
233
+ request-body fields may also be placed on individual `responses[]` entries when
234
+ each step has a different request contract, such as a fail-then-success retry
235
+ where the second request must carry newer state.
232
236
 
233
237
  `target.setup_actions` is optional. Use it when the meaningful proof surface
234
238
  appears only after a picker, tab, login stub, storage seed, form fill,
@@ -253,15 +253,7 @@ function normalizeNetworkMock(input, index) {
253
253
  const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
254
254
  const responsesInput = input.responses ?? input.sequence;
255
255
  const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
256
- const requestBodyContains = normalizeStringList(
257
- input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
258
- `target.network_mocks[${index}].request_body_contains`
259
- );
260
- const requestBodyPatterns = normalizeStringList(
261
- input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
262
- `target.network_mocks[${index}].request_body_patterns`
263
- );
264
- validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
256
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
265
257
  const requiredHitCount = numberValue(
266
258
  input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
267
259
  );
@@ -277,9 +269,38 @@ function normalizeNetworkMock(input, index) {
277
269
  repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
278
270
  required_hit_count: requiredHitCount,
279
271
  required: input.required === false ? false : true,
280
- capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length),
272
+ capture_request_body: requestBody.capture_request_body,
273
+ request_body_contains: requestBody.request_body_contains,
274
+ request_body_patterns: requestBody.request_body_patterns,
275
+ request_body_not_contains: requestBody.request_body_not_contains,
276
+ request_body_not_patterns: requestBody.request_body_not_patterns
277
+ };
278
+ }
279
+ function normalizeNetworkMockRequestBodyConstraints(input, label) {
280
+ const requestBodyContains = normalizeStringList(
281
+ input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
282
+ `${label}.request_body_contains`
283
+ );
284
+ const requestBodyPatterns = normalizeStringList(
285
+ input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
286
+ `${label}.request_body_patterns`
287
+ );
288
+ validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
289
+ const requestBodyNotContains = normalizeStringList(
290
+ input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
291
+ `${label}.request_body_not_contains`
292
+ );
293
+ const requestBodyNotPatterns = normalizeStringList(
294
+ input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
295
+ `${label}.request_body_not_patterns`
296
+ );
297
+ validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
298
+ return {
299
+ capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
281
300
  request_body_contains: requestBodyContains,
282
- request_body_patterns: requestBodyPatterns
301
+ request_body_patterns: requestBodyPatterns,
302
+ request_body_not_contains: requestBodyNotContains,
303
+ request_body_not_patterns: requestBodyNotPatterns
283
304
  };
284
305
  }
285
306
  function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
@@ -289,20 +310,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
289
310
  }
290
311
  const body = stringValue(input.body) ?? stringValue(input.body_text) ?? stringValue(input.bodyText) ?? defaults.body;
291
312
  const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
313
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
292
314
  return {
293
315
  label: stringValue(input.label) || stringValue(input.name) || defaults.label,
294
316
  status,
295
317
  content_type: stringValue(input.content_type) || stringValue(input.contentType) || defaults.content_type,
296
318
  headers: stringRecord(input.headers) || defaults.headers,
297
319
  body,
298
- body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
320
+ body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
321
+ capture_request_body: requestBody.capture_request_body,
322
+ request_body_contains: requestBody.request_body_contains,
323
+ request_body_patterns: requestBody.request_body_patterns,
324
+ request_body_not_contains: requestBody.request_body_not_contains,
325
+ request_body_not_patterns: requestBody.request_body_not_patterns
299
326
  };
300
327
  }
301
328
  function normalizeNetworkMockResponses(value, mockIndex, defaults) {
302
329
  if (value === void 0) return void 0;
303
330
  if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
304
331
  if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
305
- const responseDefaults = { ...defaults, label: void 0 };
332
+ const responseDefaults = {
333
+ label: void 0,
334
+ status: defaults.status,
335
+ content_type: defaults.content_type,
336
+ headers: defaults.headers,
337
+ body: defaults.body,
338
+ body_json: defaults.body_json
339
+ };
306
340
  return value.map((response, responseIndex) => {
307
341
  if (!isRecord(response)) {
308
342
  throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
@@ -1045,6 +1079,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
1045
1079
  if (event.request_body_matches === false) {
1046
1080
  failed.push({
1047
1081
  label: event.label ?? null,
1082
+ response_label: event.response_label ?? null,
1083
+ hit_index: event.hit_index ?? null,
1084
+ response_index: event.response_index ?? null,
1048
1085
  url: event.url ?? null,
1049
1086
  method: event.method ?? null,
1050
1087
  reason: "request_body_mismatch",
@@ -1428,6 +1465,9 @@ function assessProfile(profile, evidence) {
1428
1465
  if (event && event.request_body_matches === false) {
1429
1466
  failed.push({
1430
1467
  label: event.label || null,
1468
+ response_label: event.response_label || null,
1469
+ hit_index: event.hit_index ?? null,
1470
+ response_index: event.response_index ?? null,
1431
1471
  url: event.url || null,
1432
1472
  method: event.method || null,
1433
1473
  reason: "request_body_mismatch",
@@ -1892,18 +1932,21 @@ function compactNetworkMockRequestBody(value) {
1892
1932
  function networkMockStringList(value) {
1893
1933
  return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
1894
1934
  }
1895
- function networkMockShouldCaptureRequestBody(mock) {
1896
- return mock && (
1897
- mock.capture_request_body === true
1898
- || networkMockStringList(mock.request_body_contains).length > 0
1899
- || networkMockStringList(mock.request_body_patterns).length > 0
1900
- );
1935
+ function networkMockShouldCaptureRequestBody(...sources) {
1936
+ return sources.some((source) => source && (
1937
+ source.capture_request_body === true
1938
+ || networkMockStringList(source.request_body_contains).length > 0
1939
+ || networkMockStringList(source.request_body_patterns).length > 0
1940
+ || networkMockStringList(source.request_body_not_contains).length > 0
1941
+ || networkMockStringList(source.request_body_not_patterns).length > 0
1942
+ ));
1901
1943
  }
1902
- function networkMockRequestBodyFailures(body, mock) {
1944
+ function networkMockRequestBodyFailuresForSource(body, source) {
1903
1945
  const failures = [];
1946
+ if (!source) return failures;
1904
1947
  const rawBody = String(body || "");
1905
1948
  const compactBody = compactNetworkMockRequestBody(rawBody);
1906
- for (const expected of networkMockStringList(mock.request_body_contains)) {
1949
+ for (const expected of networkMockStringList(source.request_body_contains)) {
1907
1950
  if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
1908
1951
  failures.push({
1909
1952
  type: "request_body_missing_text",
@@ -1911,7 +1954,7 @@ function networkMockRequestBodyFailures(body, mock) {
1911
1954
  });
1912
1955
  }
1913
1956
  }
1914
- for (const pattern of networkMockStringList(mock.request_body_patterns)) {
1957
+ for (const pattern of networkMockStringList(source.request_body_patterns)) {
1915
1958
  try {
1916
1959
  const regex = new RegExp(pattern);
1917
1960
  if (!regex.test(rawBody) && !regex.test(compactBody)) {
@@ -1928,8 +1971,36 @@ function networkMockRequestBodyFailures(body, mock) {
1928
1971
  });
1929
1972
  }
1930
1973
  }
1974
+ for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
1975
+ if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
1976
+ failures.push({
1977
+ type: "request_body_forbidden_text",
1978
+ text: String(forbidden).slice(0, 200),
1979
+ });
1980
+ }
1981
+ }
1982
+ for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
1983
+ try {
1984
+ const regex = new RegExp(pattern);
1985
+ if (regex.test(rawBody) || regex.test(compactBody)) {
1986
+ failures.push({
1987
+ type: "request_body_forbidden_pattern_matched",
1988
+ pattern: String(pattern).slice(0, 200),
1989
+ });
1990
+ }
1991
+ } catch (error) {
1992
+ failures.push({
1993
+ type: "request_body_invalid_pattern",
1994
+ pattern: String(pattern).slice(0, 200),
1995
+ error: String(error && error.message ? error.message : error).slice(0, 500),
1996
+ });
1997
+ }
1998
+ }
1931
1999
  return failures;
1932
2000
  }
2001
+ function networkMockRequestBodyFailures(body, ...sources) {
2002
+ return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
2003
+ }
1933
2004
  async function setupLocatorVisible(locator, index) {
1934
2005
  return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
1935
2006
  }
@@ -1958,9 +2029,10 @@ async function registerNetworkMocks(mocks) {
1958
2029
  body = JSON.stringify(response.body_json);
1959
2030
  contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
1960
2031
  }
1961
- const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock);
2032
+ const responseBodyContract = responseIndex === null ? null : response;
2033
+ const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
1962
2034
  const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
1963
- const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
2035
+ const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
1964
2036
  const status = response.status || mock.status || 200;
1965
2037
  const event = {
1966
2038
  ok: true,
package/dist/cli.cjs CHANGED
@@ -7126,15 +7126,7 @@ function normalizeNetworkMock(input, index) {
7126
7126
  const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
7127
7127
  const responsesInput = input.responses ?? input.sequence;
7128
7128
  const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
7129
- const requestBodyContains = normalizeStringList(
7130
- input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
7131
- `target.network_mocks[${index}].request_body_contains`
7132
- );
7133
- const requestBodyPatterns = normalizeStringList(
7134
- input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
7135
- `target.network_mocks[${index}].request_body_patterns`
7136
- );
7137
- validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
7129
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
7138
7130
  const requiredHitCount = numberValue(
7139
7131
  input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
7140
7132
  );
@@ -7150,9 +7142,38 @@ function normalizeNetworkMock(input, index) {
7150
7142
  repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
7151
7143
  required_hit_count: requiredHitCount,
7152
7144
  required: input.required === false ? false : true,
7153
- capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length),
7145
+ capture_request_body: requestBody.capture_request_body,
7146
+ request_body_contains: requestBody.request_body_contains,
7147
+ request_body_patterns: requestBody.request_body_patterns,
7148
+ request_body_not_contains: requestBody.request_body_not_contains,
7149
+ request_body_not_patterns: requestBody.request_body_not_patterns
7150
+ };
7151
+ }
7152
+ function normalizeNetworkMockRequestBodyConstraints(input, label) {
7153
+ const requestBodyContains = normalizeStringList(
7154
+ input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
7155
+ `${label}.request_body_contains`
7156
+ );
7157
+ const requestBodyPatterns = normalizeStringList(
7158
+ input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
7159
+ `${label}.request_body_patterns`
7160
+ );
7161
+ validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
7162
+ const requestBodyNotContains = normalizeStringList(
7163
+ input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
7164
+ `${label}.request_body_not_contains`
7165
+ );
7166
+ const requestBodyNotPatterns = normalizeStringList(
7167
+ input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
7168
+ `${label}.request_body_not_patterns`
7169
+ );
7170
+ validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
7171
+ return {
7172
+ capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
7154
7173
  request_body_contains: requestBodyContains,
7155
- request_body_patterns: requestBodyPatterns
7174
+ request_body_patterns: requestBodyPatterns,
7175
+ request_body_not_contains: requestBodyNotContains,
7176
+ request_body_not_patterns: requestBodyNotPatterns
7156
7177
  };
7157
7178
  }
7158
7179
  function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
@@ -7162,20 +7183,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
7162
7183
  }
7163
7184
  const body = stringValue2(input.body) ?? stringValue2(input.body_text) ?? stringValue2(input.bodyText) ?? defaults.body;
7164
7185
  const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
7186
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
7165
7187
  return {
7166
7188
  label: stringValue2(input.label) || stringValue2(input.name) || defaults.label,
7167
7189
  status,
7168
7190
  content_type: stringValue2(input.content_type) || stringValue2(input.contentType) || defaults.content_type,
7169
7191
  headers: stringRecord(input.headers) || defaults.headers,
7170
7192
  body,
7171
- body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
7193
+ body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
7194
+ capture_request_body: requestBody.capture_request_body,
7195
+ request_body_contains: requestBody.request_body_contains,
7196
+ request_body_patterns: requestBody.request_body_patterns,
7197
+ request_body_not_contains: requestBody.request_body_not_contains,
7198
+ request_body_not_patterns: requestBody.request_body_not_patterns
7172
7199
  };
7173
7200
  }
7174
7201
  function normalizeNetworkMockResponses(value, mockIndex, defaults) {
7175
7202
  if (value === void 0) return void 0;
7176
7203
  if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
7177
7204
  if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
7178
- const responseDefaults = { ...defaults, label: void 0 };
7205
+ const responseDefaults = {
7206
+ label: void 0,
7207
+ status: defaults.status,
7208
+ content_type: defaults.content_type,
7209
+ headers: defaults.headers,
7210
+ body: defaults.body,
7211
+ body_json: defaults.body_json
7212
+ };
7179
7213
  return value.map((response, responseIndex) => {
7180
7214
  if (!isRecord(response)) {
7181
7215
  throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
@@ -7918,6 +7952,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
7918
7952
  if (event.request_body_matches === false) {
7919
7953
  failed.push({
7920
7954
  label: event.label ?? null,
7955
+ response_label: event.response_label ?? null,
7956
+ hit_index: event.hit_index ?? null,
7957
+ response_index: event.response_index ?? null,
7921
7958
  url: event.url ?? null,
7922
7959
  method: event.method ?? null,
7923
7960
  reason: "request_body_mismatch",
@@ -8285,6 +8322,9 @@ function assessProfile(profile, evidence) {
8285
8322
  if (event && event.request_body_matches === false) {
8286
8323
  failed.push({
8287
8324
  label: event.label || null,
8325
+ response_label: event.response_label || null,
8326
+ hit_index: event.hit_index ?? null,
8327
+ response_index: event.response_index ?? null,
8288
8328
  url: event.url || null,
8289
8329
  method: event.method || null,
8290
8330
  reason: "request_body_mismatch",
@@ -8749,18 +8789,21 @@ function compactNetworkMockRequestBody(value) {
8749
8789
  function networkMockStringList(value) {
8750
8790
  return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
8751
8791
  }
8752
- function networkMockShouldCaptureRequestBody(mock) {
8753
- return mock && (
8754
- mock.capture_request_body === true
8755
- || networkMockStringList(mock.request_body_contains).length > 0
8756
- || networkMockStringList(mock.request_body_patterns).length > 0
8757
- );
8792
+ function networkMockShouldCaptureRequestBody(...sources) {
8793
+ return sources.some((source) => source && (
8794
+ source.capture_request_body === true
8795
+ || networkMockStringList(source.request_body_contains).length > 0
8796
+ || networkMockStringList(source.request_body_patterns).length > 0
8797
+ || networkMockStringList(source.request_body_not_contains).length > 0
8798
+ || networkMockStringList(source.request_body_not_patterns).length > 0
8799
+ ));
8758
8800
  }
8759
- function networkMockRequestBodyFailures(body, mock) {
8801
+ function networkMockRequestBodyFailuresForSource(body, source) {
8760
8802
  const failures = [];
8803
+ if (!source) return failures;
8761
8804
  const rawBody = String(body || "");
8762
8805
  const compactBody = compactNetworkMockRequestBody(rawBody);
8763
- for (const expected of networkMockStringList(mock.request_body_contains)) {
8806
+ for (const expected of networkMockStringList(source.request_body_contains)) {
8764
8807
  if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
8765
8808
  failures.push({
8766
8809
  type: "request_body_missing_text",
@@ -8768,7 +8811,7 @@ function networkMockRequestBodyFailures(body, mock) {
8768
8811
  });
8769
8812
  }
8770
8813
  }
8771
- for (const pattern of networkMockStringList(mock.request_body_patterns)) {
8814
+ for (const pattern of networkMockStringList(source.request_body_patterns)) {
8772
8815
  try {
8773
8816
  const regex = new RegExp(pattern);
8774
8817
  if (!regex.test(rawBody) && !regex.test(compactBody)) {
@@ -8785,8 +8828,36 @@ function networkMockRequestBodyFailures(body, mock) {
8785
8828
  });
8786
8829
  }
8787
8830
  }
8831
+ for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
8832
+ if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
8833
+ failures.push({
8834
+ type: "request_body_forbidden_text",
8835
+ text: String(forbidden).slice(0, 200),
8836
+ });
8837
+ }
8838
+ }
8839
+ for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
8840
+ try {
8841
+ const regex = new RegExp(pattern);
8842
+ if (regex.test(rawBody) || regex.test(compactBody)) {
8843
+ failures.push({
8844
+ type: "request_body_forbidden_pattern_matched",
8845
+ pattern: String(pattern).slice(0, 200),
8846
+ });
8847
+ }
8848
+ } catch (error) {
8849
+ failures.push({
8850
+ type: "request_body_invalid_pattern",
8851
+ pattern: String(pattern).slice(0, 200),
8852
+ error: String(error && error.message ? error.message : error).slice(0, 500),
8853
+ });
8854
+ }
8855
+ }
8788
8856
  return failures;
8789
8857
  }
8858
+ function networkMockRequestBodyFailures(body, ...sources) {
8859
+ return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
8860
+ }
8790
8861
  async function setupLocatorVisible(locator, index) {
8791
8862
  return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
8792
8863
  }
@@ -8815,9 +8886,10 @@ async function registerNetworkMocks(mocks) {
8815
8886
  body = JSON.stringify(response.body_json);
8816
8887
  contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
8817
8888
  }
8818
- const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock);
8889
+ const responseBodyContract = responseIndex === null ? null : response;
8890
+ const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
8819
8891
  const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
8820
- const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
8892
+ const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
8821
8893
  const status = response.status || mock.status || 200;
8822
8894
  const event = {
8823
8895
  ok: true,
package/dist/cli.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  profileStatusExitCode,
11
11
  resolveRiddleProofProfileTargetUrl,
12
12
  resolveRiddleProofProfileTimeoutSec
13
- } from "./chunk-IJGMTTVP.js";
13
+ } from "./chunk-NJDY7HYE.js";
14
14
  import {
15
15
  createRiddleApiClient,
16
16
  parseRiddleViewport
package/dist/index.cjs CHANGED
@@ -8967,15 +8967,7 @@ function normalizeNetworkMock(input, index) {
8967
8967
  const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
8968
8968
  const responsesInput = input.responses ?? input.sequence;
8969
8969
  const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
8970
- const requestBodyContains = normalizeStringList(
8971
- input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
8972
- `target.network_mocks[${index}].request_body_contains`
8973
- );
8974
- const requestBodyPatterns = normalizeStringList(
8975
- input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
8976
- `target.network_mocks[${index}].request_body_patterns`
8977
- );
8978
- validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
8970
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
8979
8971
  const requiredHitCount = numberValue3(
8980
8972
  input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
8981
8973
  );
@@ -8991,9 +8983,38 @@ function normalizeNetworkMock(input, index) {
8991
8983
  repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
8992
8984
  required_hit_count: requiredHitCount,
8993
8985
  required: input.required === false ? false : true,
8994
- capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length),
8986
+ capture_request_body: requestBody.capture_request_body,
8987
+ request_body_contains: requestBody.request_body_contains,
8988
+ request_body_patterns: requestBody.request_body_patterns,
8989
+ request_body_not_contains: requestBody.request_body_not_contains,
8990
+ request_body_not_patterns: requestBody.request_body_not_patterns
8991
+ };
8992
+ }
8993
+ function normalizeNetworkMockRequestBodyConstraints(input, label) {
8994
+ const requestBodyContains = normalizeStringList(
8995
+ input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
8996
+ `${label}.request_body_contains`
8997
+ );
8998
+ const requestBodyPatterns = normalizeStringList(
8999
+ input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
9000
+ `${label}.request_body_patterns`
9001
+ );
9002
+ validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
9003
+ const requestBodyNotContains = normalizeStringList(
9004
+ input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
9005
+ `${label}.request_body_not_contains`
9006
+ );
9007
+ const requestBodyNotPatterns = normalizeStringList(
9008
+ input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
9009
+ `${label}.request_body_not_patterns`
9010
+ );
9011
+ validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
9012
+ return {
9013
+ capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
8995
9014
  request_body_contains: requestBodyContains,
8996
- request_body_patterns: requestBodyPatterns
9015
+ request_body_patterns: requestBodyPatterns,
9016
+ request_body_not_contains: requestBodyNotContains,
9017
+ request_body_not_patterns: requestBodyNotPatterns
8997
9018
  };
8998
9019
  }
8999
9020
  function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
@@ -9003,20 +9024,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
9003
9024
  }
9004
9025
  const body = stringValue5(input.body) ?? stringValue5(input.body_text) ?? stringValue5(input.bodyText) ?? defaults.body;
9005
9026
  const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
9027
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
9006
9028
  return {
9007
9029
  label: stringValue5(input.label) || stringValue5(input.name) || defaults.label,
9008
9030
  status,
9009
9031
  content_type: stringValue5(input.content_type) || stringValue5(input.contentType) || defaults.content_type,
9010
9032
  headers: stringRecord(input.headers) || defaults.headers,
9011
9033
  body,
9012
- body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
9034
+ body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
9035
+ capture_request_body: requestBody.capture_request_body,
9036
+ request_body_contains: requestBody.request_body_contains,
9037
+ request_body_patterns: requestBody.request_body_patterns,
9038
+ request_body_not_contains: requestBody.request_body_not_contains,
9039
+ request_body_not_patterns: requestBody.request_body_not_patterns
9013
9040
  };
9014
9041
  }
9015
9042
  function normalizeNetworkMockResponses(value, mockIndex, defaults) {
9016
9043
  if (value === void 0) return void 0;
9017
9044
  if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
9018
9045
  if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
9019
- const responseDefaults = { ...defaults, label: void 0 };
9046
+ const responseDefaults = {
9047
+ label: void 0,
9048
+ status: defaults.status,
9049
+ content_type: defaults.content_type,
9050
+ headers: defaults.headers,
9051
+ body: defaults.body,
9052
+ body_json: defaults.body_json
9053
+ };
9020
9054
  return value.map((response, responseIndex) => {
9021
9055
  if (!isRecord2(response)) {
9022
9056
  throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
@@ -9759,6 +9793,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
9759
9793
  if (event.request_body_matches === false) {
9760
9794
  failed.push({
9761
9795
  label: event.label ?? null,
9796
+ response_label: event.response_label ?? null,
9797
+ hit_index: event.hit_index ?? null,
9798
+ response_index: event.response_index ?? null,
9762
9799
  url: event.url ?? null,
9763
9800
  method: event.method ?? null,
9764
9801
  reason: "request_body_mismatch",
@@ -10142,6 +10179,9 @@ function assessProfile(profile, evidence) {
10142
10179
  if (event && event.request_body_matches === false) {
10143
10180
  failed.push({
10144
10181
  label: event.label || null,
10182
+ response_label: event.response_label || null,
10183
+ hit_index: event.hit_index ?? null,
10184
+ response_index: event.response_index ?? null,
10145
10185
  url: event.url || null,
10146
10186
  method: event.method || null,
10147
10187
  reason: "request_body_mismatch",
@@ -10606,18 +10646,21 @@ function compactNetworkMockRequestBody(value) {
10606
10646
  function networkMockStringList(value) {
10607
10647
  return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
10608
10648
  }
10609
- function networkMockShouldCaptureRequestBody(mock) {
10610
- return mock && (
10611
- mock.capture_request_body === true
10612
- || networkMockStringList(mock.request_body_contains).length > 0
10613
- || networkMockStringList(mock.request_body_patterns).length > 0
10614
- );
10649
+ function networkMockShouldCaptureRequestBody(...sources) {
10650
+ return sources.some((source) => source && (
10651
+ source.capture_request_body === true
10652
+ || networkMockStringList(source.request_body_contains).length > 0
10653
+ || networkMockStringList(source.request_body_patterns).length > 0
10654
+ || networkMockStringList(source.request_body_not_contains).length > 0
10655
+ || networkMockStringList(source.request_body_not_patterns).length > 0
10656
+ ));
10615
10657
  }
10616
- function networkMockRequestBodyFailures(body, mock) {
10658
+ function networkMockRequestBodyFailuresForSource(body, source) {
10617
10659
  const failures = [];
10660
+ if (!source) return failures;
10618
10661
  const rawBody = String(body || "");
10619
10662
  const compactBody = compactNetworkMockRequestBody(rawBody);
10620
- for (const expected of networkMockStringList(mock.request_body_contains)) {
10663
+ for (const expected of networkMockStringList(source.request_body_contains)) {
10621
10664
  if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
10622
10665
  failures.push({
10623
10666
  type: "request_body_missing_text",
@@ -10625,7 +10668,7 @@ function networkMockRequestBodyFailures(body, mock) {
10625
10668
  });
10626
10669
  }
10627
10670
  }
10628
- for (const pattern of networkMockStringList(mock.request_body_patterns)) {
10671
+ for (const pattern of networkMockStringList(source.request_body_patterns)) {
10629
10672
  try {
10630
10673
  const regex = new RegExp(pattern);
10631
10674
  if (!regex.test(rawBody) && !regex.test(compactBody)) {
@@ -10642,8 +10685,36 @@ function networkMockRequestBodyFailures(body, mock) {
10642
10685
  });
10643
10686
  }
10644
10687
  }
10688
+ for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
10689
+ if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
10690
+ failures.push({
10691
+ type: "request_body_forbidden_text",
10692
+ text: String(forbidden).slice(0, 200),
10693
+ });
10694
+ }
10695
+ }
10696
+ for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
10697
+ try {
10698
+ const regex = new RegExp(pattern);
10699
+ if (regex.test(rawBody) || regex.test(compactBody)) {
10700
+ failures.push({
10701
+ type: "request_body_forbidden_pattern_matched",
10702
+ pattern: String(pattern).slice(0, 200),
10703
+ });
10704
+ }
10705
+ } catch (error) {
10706
+ failures.push({
10707
+ type: "request_body_invalid_pattern",
10708
+ pattern: String(pattern).slice(0, 200),
10709
+ error: String(error && error.message ? error.message : error).slice(0, 500),
10710
+ });
10711
+ }
10712
+ }
10645
10713
  return failures;
10646
10714
  }
10715
+ function networkMockRequestBodyFailures(body, ...sources) {
10716
+ return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
10717
+ }
10647
10718
  async function setupLocatorVisible(locator, index) {
10648
10719
  return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
10649
10720
  }
@@ -10672,9 +10743,10 @@ async function registerNetworkMocks(mocks) {
10672
10743
  body = JSON.stringify(response.body_json);
10673
10744
  contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
10674
10745
  }
10675
- const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock);
10746
+ const responseBodyContract = responseIndex === null ? null : response;
10747
+ const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
10676
10748
  const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
10677
- const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
10749
+ const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
10678
10750
  const status = response.status || mock.status || 200;
10679
10751
  const event = {
10680
10752
  ok: true,
package/dist/index.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  resolveRiddleProofProfileTimeoutSec,
59
59
  slugifyRiddleProofProfileName,
60
60
  summarizeRiddleProofProfileResult
61
- } from "./chunk-IJGMTTVP.js";
61
+ } from "./chunk-NJDY7HYE.js";
62
62
  import {
63
63
  DEFAULT_RIDDLE_API_BASE_URL,
64
64
  DEFAULT_RIDDLE_API_KEY_FILE,
package/dist/profile.cjs CHANGED
@@ -296,15 +296,7 @@ function normalizeNetworkMock(input, index) {
296
296
  const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
297
297
  const responsesInput = input.responses ?? input.sequence;
298
298
  const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
299
- const requestBodyContains = normalizeStringList(
300
- input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
301
- `target.network_mocks[${index}].request_body_contains`
302
- );
303
- const requestBodyPatterns = normalizeStringList(
304
- input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
305
- `target.network_mocks[${index}].request_body_patterns`
306
- );
307
- validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
299
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
308
300
  const requiredHitCount = numberValue(
309
301
  input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
310
302
  );
@@ -320,9 +312,38 @@ function normalizeNetworkMock(input, index) {
320
312
  repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
321
313
  required_hit_count: requiredHitCount,
322
314
  required: input.required === false ? false : true,
323
- capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length),
315
+ capture_request_body: requestBody.capture_request_body,
316
+ request_body_contains: requestBody.request_body_contains,
317
+ request_body_patterns: requestBody.request_body_patterns,
318
+ request_body_not_contains: requestBody.request_body_not_contains,
319
+ request_body_not_patterns: requestBody.request_body_not_patterns
320
+ };
321
+ }
322
+ function normalizeNetworkMockRequestBodyConstraints(input, label) {
323
+ const requestBodyContains = normalizeStringList(
324
+ input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
325
+ `${label}.request_body_contains`
326
+ );
327
+ const requestBodyPatterns = normalizeStringList(
328
+ input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
329
+ `${label}.request_body_patterns`
330
+ );
331
+ validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
332
+ const requestBodyNotContains = normalizeStringList(
333
+ input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
334
+ `${label}.request_body_not_contains`
335
+ );
336
+ const requestBodyNotPatterns = normalizeStringList(
337
+ input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
338
+ `${label}.request_body_not_patterns`
339
+ );
340
+ validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
341
+ return {
342
+ capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
324
343
  request_body_contains: requestBodyContains,
325
- request_body_patterns: requestBodyPatterns
344
+ request_body_patterns: requestBodyPatterns,
345
+ request_body_not_contains: requestBodyNotContains,
346
+ request_body_not_patterns: requestBodyNotPatterns
326
347
  };
327
348
  }
328
349
  function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
@@ -332,20 +353,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
332
353
  }
333
354
  const body = stringValue(input.body) ?? stringValue(input.body_text) ?? stringValue(input.bodyText) ?? defaults.body;
334
355
  const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
356
+ const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
335
357
  return {
336
358
  label: stringValue(input.label) || stringValue(input.name) || defaults.label,
337
359
  status,
338
360
  content_type: stringValue(input.content_type) || stringValue(input.contentType) || defaults.content_type,
339
361
  headers: stringRecord(input.headers) || defaults.headers,
340
362
  body,
341
- body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
363
+ body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
364
+ capture_request_body: requestBody.capture_request_body,
365
+ request_body_contains: requestBody.request_body_contains,
366
+ request_body_patterns: requestBody.request_body_patterns,
367
+ request_body_not_contains: requestBody.request_body_not_contains,
368
+ request_body_not_patterns: requestBody.request_body_not_patterns
342
369
  };
343
370
  }
344
371
  function normalizeNetworkMockResponses(value, mockIndex, defaults) {
345
372
  if (value === void 0) return void 0;
346
373
  if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
347
374
  if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
348
- const responseDefaults = { ...defaults, label: void 0 };
375
+ const responseDefaults = {
376
+ label: void 0,
377
+ status: defaults.status,
378
+ content_type: defaults.content_type,
379
+ headers: defaults.headers,
380
+ body: defaults.body,
381
+ body_json: defaults.body_json
382
+ };
349
383
  return value.map((response, responseIndex) => {
350
384
  if (!isRecord(response)) {
351
385
  throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
@@ -1088,6 +1122,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
1088
1122
  if (event.request_body_matches === false) {
1089
1123
  failed.push({
1090
1124
  label: event.label ?? null,
1125
+ response_label: event.response_label ?? null,
1126
+ hit_index: event.hit_index ?? null,
1127
+ response_index: event.response_index ?? null,
1091
1128
  url: event.url ?? null,
1092
1129
  method: event.method ?? null,
1093
1130
  reason: "request_body_mismatch",
@@ -1471,6 +1508,9 @@ function assessProfile(profile, evidence) {
1471
1508
  if (event && event.request_body_matches === false) {
1472
1509
  failed.push({
1473
1510
  label: event.label || null,
1511
+ response_label: event.response_label || null,
1512
+ hit_index: event.hit_index ?? null,
1513
+ response_index: event.response_index ?? null,
1474
1514
  url: event.url || null,
1475
1515
  method: event.method || null,
1476
1516
  reason: "request_body_mismatch",
@@ -1935,18 +1975,21 @@ function compactNetworkMockRequestBody(value) {
1935
1975
  function networkMockStringList(value) {
1936
1976
  return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
1937
1977
  }
1938
- function networkMockShouldCaptureRequestBody(mock) {
1939
- return mock && (
1940
- mock.capture_request_body === true
1941
- || networkMockStringList(mock.request_body_contains).length > 0
1942
- || networkMockStringList(mock.request_body_patterns).length > 0
1943
- );
1978
+ function networkMockShouldCaptureRequestBody(...sources) {
1979
+ return sources.some((source) => source && (
1980
+ source.capture_request_body === true
1981
+ || networkMockStringList(source.request_body_contains).length > 0
1982
+ || networkMockStringList(source.request_body_patterns).length > 0
1983
+ || networkMockStringList(source.request_body_not_contains).length > 0
1984
+ || networkMockStringList(source.request_body_not_patterns).length > 0
1985
+ ));
1944
1986
  }
1945
- function networkMockRequestBodyFailures(body, mock) {
1987
+ function networkMockRequestBodyFailuresForSource(body, source) {
1946
1988
  const failures = [];
1989
+ if (!source) return failures;
1947
1990
  const rawBody = String(body || "");
1948
1991
  const compactBody = compactNetworkMockRequestBody(rawBody);
1949
- for (const expected of networkMockStringList(mock.request_body_contains)) {
1992
+ for (const expected of networkMockStringList(source.request_body_contains)) {
1950
1993
  if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
1951
1994
  failures.push({
1952
1995
  type: "request_body_missing_text",
@@ -1954,7 +1997,7 @@ function networkMockRequestBodyFailures(body, mock) {
1954
1997
  });
1955
1998
  }
1956
1999
  }
1957
- for (const pattern of networkMockStringList(mock.request_body_patterns)) {
2000
+ for (const pattern of networkMockStringList(source.request_body_patterns)) {
1958
2001
  try {
1959
2002
  const regex = new RegExp(pattern);
1960
2003
  if (!regex.test(rawBody) && !regex.test(compactBody)) {
@@ -1971,8 +2014,36 @@ function networkMockRequestBodyFailures(body, mock) {
1971
2014
  });
1972
2015
  }
1973
2016
  }
2017
+ for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
2018
+ if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
2019
+ failures.push({
2020
+ type: "request_body_forbidden_text",
2021
+ text: String(forbidden).slice(0, 200),
2022
+ });
2023
+ }
2024
+ }
2025
+ for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
2026
+ try {
2027
+ const regex = new RegExp(pattern);
2028
+ if (regex.test(rawBody) || regex.test(compactBody)) {
2029
+ failures.push({
2030
+ type: "request_body_forbidden_pattern_matched",
2031
+ pattern: String(pattern).slice(0, 200),
2032
+ });
2033
+ }
2034
+ } catch (error) {
2035
+ failures.push({
2036
+ type: "request_body_invalid_pattern",
2037
+ pattern: String(pattern).slice(0, 200),
2038
+ error: String(error && error.message ? error.message : error).slice(0, 500),
2039
+ });
2040
+ }
2041
+ }
1974
2042
  return failures;
1975
2043
  }
2044
+ function networkMockRequestBodyFailures(body, ...sources) {
2045
+ return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
2046
+ }
1976
2047
  async function setupLocatorVisible(locator, index) {
1977
2048
  return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
1978
2049
  }
@@ -2001,9 +2072,10 @@ async function registerNetworkMocks(mocks) {
2001
2072
  body = JSON.stringify(response.body_json);
2002
2073
  contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
2003
2074
  }
2004
- const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock);
2075
+ const responseBodyContract = responseIndex === null ? null : response;
2076
+ const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
2005
2077
  const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
2006
- const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
2078
+ const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
2007
2079
  const status = response.status || mock.status || 200;
2008
2080
  const event = {
2009
2081
  ok: true,
@@ -41,6 +41,11 @@ interface RiddleProofProfileNetworkMockResponse {
41
41
  headers?: Record<string, string>;
42
42
  body?: string;
43
43
  body_json?: JsonValue;
44
+ capture_request_body?: boolean;
45
+ request_body_contains?: string[];
46
+ request_body_patterns?: string[];
47
+ request_body_not_contains?: string[];
48
+ request_body_not_patterns?: string[];
44
49
  }
45
50
  interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockResponse {
46
51
  label: string;
@@ -53,6 +58,8 @@ interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockRes
53
58
  capture_request_body?: boolean;
54
59
  request_body_contains?: string[];
55
60
  request_body_patterns?: string[];
61
+ request_body_not_contains?: string[];
62
+ request_body_not_patterns?: string[];
56
63
  }
57
64
  interface RiddleProofProfileRouteInventoryRoute {
58
65
  name?: string;
package/dist/profile.d.ts CHANGED
@@ -41,6 +41,11 @@ interface RiddleProofProfileNetworkMockResponse {
41
41
  headers?: Record<string, string>;
42
42
  body?: string;
43
43
  body_json?: JsonValue;
44
+ capture_request_body?: boolean;
45
+ request_body_contains?: string[];
46
+ request_body_patterns?: string[];
47
+ request_body_not_contains?: string[];
48
+ request_body_not_patterns?: string[];
44
49
  }
45
50
  interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockResponse {
46
51
  label: string;
@@ -53,6 +58,8 @@ interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockRes
53
58
  capture_request_body?: boolean;
54
59
  request_body_contains?: string[];
55
60
  request_body_patterns?: string[];
61
+ request_body_not_contains?: string[];
62
+ request_body_not_patterns?: string[];
56
63
  }
57
64
  interface RiddleProofProfileRouteInventoryRoute {
58
65
  name?: string;
package/dist/profile.js CHANGED
@@ -19,7 +19,7 @@ import {
19
19
  resolveRiddleProofProfileTimeoutSec,
20
20
  slugifyRiddleProofProfileName,
21
21
  summarizeRiddleProofProfileResult
22
- } from "./chunk-IJGMTTVP.js";
22
+ } from "./chunk-NJDY7HYE.js";
23
23
  export {
24
24
  RIDDLE_PROOF_PROFILE_CHECK_TYPES,
25
25
  RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
295
+ action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
385
+ action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
662
+ action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
292
292
  blocking?: boolean;
293
293
  details?: Record<string, unknown>;
294
294
  ok: boolean;
295
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
295
+ action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
296
296
  state_path: string;
297
297
  stage: any;
298
298
  summary: string;
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
382
382
  continueWithStage?: WorkflowStage | null;
383
383
  blocking?: boolean;
384
384
  details?: Record<string, unknown>;
385
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
385
+ action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
386
386
  state_path: string;
387
387
  stage: any;
388
388
  checkpoint: string;
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
659
659
  error?: undefined;
660
660
  } | {
661
661
  ok: boolean;
662
- action: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
662
+ action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
663
663
  state_path: string;
664
664
  stage: any;
665
665
  summary: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riddledc/riddle-proof",
3
- "version": "0.7.45",
3
+ "version": "0.7.47",
4
4
  "description": "Reusable Riddle Proof contracts and helpers for evidence-backed agent changes.",
5
5
  "license": "MIT",
6
6
  "author": "RiddleDC",