@riddledc/riddle-proof 0.7.99 → 0.7.101
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/dist/{chunk-W5PBTTMJ.js → chunk-7FQU5UH7.js} +78 -3
- package/dist/cli.cjs +78 -3
- package/dist/cli.js +1 -1
- package/dist/index.cjs +78 -3
- package/dist/index.js +1 -1
- package/dist/profile.cjs +78 -3
- package/dist/profile.d.cts +2 -0
- package/dist/profile.d.ts +2 -0
- package/dist/profile.js +1 -1
- package/package.json +1 -1
|
@@ -807,6 +807,15 @@ function normalizeCheck(input, index) {
|
|
|
807
807
|
input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
|
|
808
808
|
`checks[${index}] body_contains`
|
|
809
809
|
) : void 0;
|
|
810
|
+
const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
|
|
811
|
+
input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
812
|
+
`checks[${index}] body_not_contains`
|
|
813
|
+
) : void 0;
|
|
814
|
+
const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
|
|
815
|
+
input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
816
|
+
`checks[${index}] body_not_patterns`
|
|
817
|
+
) : void 0;
|
|
818
|
+
if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
|
|
810
819
|
if (isLinkStatusCheck) {
|
|
811
820
|
if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
|
|
812
821
|
throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
|
|
@@ -830,6 +839,8 @@ function normalizeCheck(input, index) {
|
|
|
830
839
|
body: isHttpStatusCheck ? stringValue(input.body) : void 0,
|
|
831
840
|
body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
|
|
832
841
|
body_contains: bodyContains,
|
|
842
|
+
body_not_contains: bodyNotContains,
|
|
843
|
+
body_not_patterns: bodyNotPatterns,
|
|
833
844
|
expected_texts: expectedTexts,
|
|
834
845
|
link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
|
|
835
846
|
source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
|
|
@@ -1007,6 +1018,18 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
1007
1018
|
const observed = isRecord(result.body_contains) ? result.body_contains : {};
|
|
1008
1019
|
return expected.filter((text) => observed[text] !== true);
|
|
1009
1020
|
}
|
|
1021
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
1022
|
+
const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
|
|
1023
|
+
if (!forbidden.length) return [];
|
|
1024
|
+
const observed = isRecord(result.body_not_contains) ? result.body_not_contains : {};
|
|
1025
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
1026
|
+
}
|
|
1027
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
1028
|
+
const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
|
|
1029
|
+
if (!forbidden.length) return [];
|
|
1030
|
+
const observed = isRecord(result.body_not_patterns) ? result.body_not_patterns : {};
|
|
1031
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
1032
|
+
}
|
|
1010
1033
|
function linkStatusResultOk(result, check) {
|
|
1011
1034
|
const status = numberValue(result.status);
|
|
1012
1035
|
if (!httpStatusIsAllowed(status, check)) return false;
|
|
@@ -1022,6 +1045,8 @@ function linkStatusResultOk(result, check) {
|
|
|
1022
1045
|
if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
|
|
1023
1046
|
}
|
|
1024
1047
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
1048
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
1049
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
1025
1050
|
return true;
|
|
1026
1051
|
}
|
|
1027
1052
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
@@ -1044,6 +1069,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
1044
1069
|
}
|
|
1045
1070
|
const failures = [];
|
|
1046
1071
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
1072
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
1073
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
1047
1074
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
1048
1075
|
failures.push({
|
|
1049
1076
|
code: "http_status_failed",
|
|
@@ -1058,6 +1085,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
1058
1085
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
1059
1086
|
body_contains: check.body_contains ?? null,
|
|
1060
1087
|
body_contains_missing: bodyContainsMissing,
|
|
1088
|
+
body_not_contains: check.body_not_contains ?? null,
|
|
1089
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
1090
|
+
body_not_patterns: check.body_not_patterns ?? null,
|
|
1091
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
1061
1092
|
body_sample: stringValue(statusEvidence.body_sample) ?? null
|
|
1062
1093
|
});
|
|
1063
1094
|
}
|
|
@@ -1075,6 +1106,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
1075
1106
|
bytes: linkStatusObservedBytes(statusEvidence) ?? null,
|
|
1076
1107
|
body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
|
|
1077
1108
|
body_contains_missing: bodyContainsMissing,
|
|
1109
|
+
body_not_contains: isRecord(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
|
|
1110
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
1111
|
+
body_not_patterns: isRecord(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
|
|
1112
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
1078
1113
|
body_sample: stringValue(statusEvidence.body_sample) ?? null,
|
|
1079
1114
|
failures
|
|
1080
1115
|
};
|
|
@@ -1686,6 +1721,8 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
1686
1721
|
min_bytes: check.min_bytes ?? null,
|
|
1687
1722
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
1688
1723
|
body_contains: check.body_contains ?? [],
|
|
1724
|
+
body_not_contains: check.body_not_contains ?? [],
|
|
1725
|
+
body_not_patterns: check.body_not_patterns ?? [],
|
|
1689
1726
|
viewports: summaries.map((summary) => toJsonValue(summary)),
|
|
1690
1727
|
failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue(summary.viewport) ?? null, failure })) : [])
|
|
1691
1728
|
},
|
|
@@ -2362,6 +2399,22 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
2362
2399
|
: {};
|
|
2363
2400
|
return expected.filter((text) => observed[text] !== true);
|
|
2364
2401
|
}
|
|
2402
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
2403
|
+
const forbidden = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
2404
|
+
if (!forbidden.length) return [];
|
|
2405
|
+
const observed = result && typeof result.body_not_contains === "object" && !Array.isArray(result.body_not_contains)
|
|
2406
|
+
? result.body_not_contains
|
|
2407
|
+
: {};
|
|
2408
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
2409
|
+
}
|
|
2410
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
2411
|
+
const forbidden = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
2412
|
+
if (!forbidden.length) return [];
|
|
2413
|
+
const observed = result && typeof result.body_not_patterns === "object" && !Array.isArray(result.body_not_patterns)
|
|
2414
|
+
? result.body_not_patterns
|
|
2415
|
+
: {};
|
|
2416
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
2417
|
+
}
|
|
2365
2418
|
function linkStatusResultOk(result, check) {
|
|
2366
2419
|
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
2367
2420
|
if (!httpStatusIsAllowed(result.status, check)) return false;
|
|
@@ -2377,6 +2430,8 @@ function linkStatusResultOk(result, check) {
|
|
|
2377
2430
|
if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
|
|
2378
2431
|
}
|
|
2379
2432
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
2433
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
2434
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
2380
2435
|
return true;
|
|
2381
2436
|
}
|
|
2382
2437
|
function summarizeHttpStatusEvidence(viewport, check) {
|
|
@@ -2395,6 +2450,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
2395
2450
|
}
|
|
2396
2451
|
const failures = [];
|
|
2397
2452
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
2453
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
2454
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
2398
2455
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
2399
2456
|
failures.push({
|
|
2400
2457
|
code: "http_status_failed",
|
|
@@ -2409,6 +2466,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
2409
2466
|
allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
|
|
2410
2467
|
body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
|
|
2411
2468
|
body_contains_missing: bodyContainsMissing,
|
|
2469
|
+
body_not_contains: Array.isArray(check.body_not_contains) ? check.body_not_contains : null,
|
|
2470
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
2471
|
+
body_not_patterns: Array.isArray(check.body_not_patterns) ? check.body_not_patterns : null,
|
|
2472
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
2412
2473
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
2413
2474
|
});
|
|
2414
2475
|
}
|
|
@@ -2428,6 +2489,14 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
2428
2489
|
? statusEvidence.body_contains
|
|
2429
2490
|
: null,
|
|
2430
2491
|
body_contains_missing: bodyContainsMissing,
|
|
2492
|
+
body_not_contains: statusEvidence.body_not_contains && typeof statusEvidence.body_not_contains === "object" && !Array.isArray(statusEvidence.body_not_contains)
|
|
2493
|
+
? statusEvidence.body_not_contains
|
|
2494
|
+
: null,
|
|
2495
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
2496
|
+
body_not_patterns: statusEvidence.body_not_patterns && typeof statusEvidence.body_not_patterns === "object" && !Array.isArray(statusEvidence.body_not_patterns)
|
|
2497
|
+
? statusEvidence.body_not_patterns
|
|
2498
|
+
: null,
|
|
2499
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
2431
2500
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
2432
2501
|
failures,
|
|
2433
2502
|
};
|
|
@@ -4423,6 +4492,8 @@ async function collectHttpStatus(check) {
|
|
|
4423
4492
|
body = check.body;
|
|
4424
4493
|
}
|
|
4425
4494
|
const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
|
|
4495
|
+
const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
4496
|
+
const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
4426
4497
|
const options = {
|
|
4427
4498
|
method,
|
|
4428
4499
|
redirect: "follow",
|
|
@@ -4448,15 +4519,17 @@ async function collectHttpStatus(check) {
|
|
|
4448
4519
|
Object.assign(result, linkProbeResponseFields(response, method));
|
|
4449
4520
|
result.url = url;
|
|
4450
4521
|
result.status_text = response.statusText || "";
|
|
4451
|
-
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
|
|
4522
|
+
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
|
|
4452
4523
|
if (shouldReadBody) {
|
|
4453
4524
|
try {
|
|
4454
4525
|
const buffer = await response.arrayBuffer();
|
|
4455
4526
|
result.bytes = buffer.byteLength;
|
|
4456
|
-
if (bodyContains.length) {
|
|
4527
|
+
if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
|
|
4457
4528
|
const text = new TextDecoder().decode(buffer);
|
|
4458
4529
|
result.body_sample = text.slice(0, 1000);
|
|
4459
|
-
result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
4530
|
+
if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
4531
|
+
if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
|
|
4532
|
+
if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
|
|
4460
4533
|
}
|
|
4461
4534
|
} catch (error) {
|
|
4462
4535
|
result.error = String(error && error.message ? error.message : error).slice(0, 500);
|
|
@@ -4467,6 +4540,8 @@ async function collectHttpStatus(check) {
|
|
|
4467
4540
|
&& (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
|
|
4468
4541
|
&& (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
|
|
4469
4542
|
&& (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
|
|
4543
|
+
&& (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
|
|
4544
|
+
&& (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
|
|
4470
4545
|
&& !result.error;
|
|
4471
4546
|
return result;
|
|
4472
4547
|
} catch (error) {
|
package/dist/cli.cjs
CHANGED
|
@@ -7700,6 +7700,15 @@ function normalizeCheck(input, index) {
|
|
|
7700
7700
|
input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
|
|
7701
7701
|
`checks[${index}] body_contains`
|
|
7702
7702
|
) : void 0;
|
|
7703
|
+
const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
|
|
7704
|
+
input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
7705
|
+
`checks[${index}] body_not_contains`
|
|
7706
|
+
) : void 0;
|
|
7707
|
+
const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
|
|
7708
|
+
input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
7709
|
+
`checks[${index}] body_not_patterns`
|
|
7710
|
+
) : void 0;
|
|
7711
|
+
if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
|
|
7703
7712
|
if (isLinkStatusCheck) {
|
|
7704
7713
|
if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
|
|
7705
7714
|
throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
|
|
@@ -7723,6 +7732,8 @@ function normalizeCheck(input, index) {
|
|
|
7723
7732
|
body: isHttpStatusCheck ? stringValue2(input.body) : void 0,
|
|
7724
7733
|
body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
|
|
7725
7734
|
body_contains: bodyContains,
|
|
7735
|
+
body_not_contains: bodyNotContains,
|
|
7736
|
+
body_not_patterns: bodyNotPatterns,
|
|
7726
7737
|
expected_texts: expectedTexts,
|
|
7727
7738
|
link_selector: stringValue2(input.link_selector) || stringValue2(input.linkSelector),
|
|
7728
7739
|
source_selector: stringValue2(input.source_selector) || stringValue2(input.sourceSelector),
|
|
@@ -7900,6 +7911,18 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
7900
7911
|
const observed = isRecord(result.body_contains) ? result.body_contains : {};
|
|
7901
7912
|
return expected.filter((text) => observed[text] !== true);
|
|
7902
7913
|
}
|
|
7914
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
7915
|
+
const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
|
|
7916
|
+
if (!forbidden.length) return [];
|
|
7917
|
+
const observed = isRecord(result.body_not_contains) ? result.body_not_contains : {};
|
|
7918
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
7919
|
+
}
|
|
7920
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
7921
|
+
const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
|
|
7922
|
+
if (!forbidden.length) return [];
|
|
7923
|
+
const observed = isRecord(result.body_not_patterns) ? result.body_not_patterns : {};
|
|
7924
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
7925
|
+
}
|
|
7903
7926
|
function linkStatusResultOk(result, check) {
|
|
7904
7927
|
const status = numberValue(result.status);
|
|
7905
7928
|
if (!httpStatusIsAllowed(status, check)) return false;
|
|
@@ -7915,6 +7938,8 @@ function linkStatusResultOk(result, check) {
|
|
|
7915
7938
|
if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
|
|
7916
7939
|
}
|
|
7917
7940
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
7941
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
7942
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
7918
7943
|
return true;
|
|
7919
7944
|
}
|
|
7920
7945
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
@@ -7937,6 +7962,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
7937
7962
|
}
|
|
7938
7963
|
const failures = [];
|
|
7939
7964
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
7965
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
7966
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
7940
7967
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
7941
7968
|
failures.push({
|
|
7942
7969
|
code: "http_status_failed",
|
|
@@ -7951,6 +7978,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
7951
7978
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
7952
7979
|
body_contains: check.body_contains ?? null,
|
|
7953
7980
|
body_contains_missing: bodyContainsMissing,
|
|
7981
|
+
body_not_contains: check.body_not_contains ?? null,
|
|
7982
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
7983
|
+
body_not_patterns: check.body_not_patterns ?? null,
|
|
7984
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
7954
7985
|
body_sample: stringValue2(statusEvidence.body_sample) ?? null
|
|
7955
7986
|
});
|
|
7956
7987
|
}
|
|
@@ -7968,6 +7999,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
7968
7999
|
bytes: linkStatusObservedBytes(statusEvidence) ?? null,
|
|
7969
8000
|
body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
|
|
7970
8001
|
body_contains_missing: bodyContainsMissing,
|
|
8002
|
+
body_not_contains: isRecord(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
|
|
8003
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
8004
|
+
body_not_patterns: isRecord(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
|
|
8005
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
7971
8006
|
body_sample: stringValue2(statusEvidence.body_sample) ?? null,
|
|
7972
8007
|
failures
|
|
7973
8008
|
};
|
|
@@ -8579,6 +8614,8 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
8579
8614
|
min_bytes: check.min_bytes ?? null,
|
|
8580
8615
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
8581
8616
|
body_contains: check.body_contains ?? [],
|
|
8617
|
+
body_not_contains: check.body_not_contains ?? [],
|
|
8618
|
+
body_not_patterns: check.body_not_patterns ?? [],
|
|
8582
8619
|
viewports: summaries.map((summary) => toJsonValue(summary)),
|
|
8583
8620
|
failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue2(summary.viewport) ?? null, failure })) : [])
|
|
8584
8621
|
},
|
|
@@ -9239,6 +9276,22 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
9239
9276
|
: {};
|
|
9240
9277
|
return expected.filter((text) => observed[text] !== true);
|
|
9241
9278
|
}
|
|
9279
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
9280
|
+
const forbidden = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
9281
|
+
if (!forbidden.length) return [];
|
|
9282
|
+
const observed = result && typeof result.body_not_contains === "object" && !Array.isArray(result.body_not_contains)
|
|
9283
|
+
? result.body_not_contains
|
|
9284
|
+
: {};
|
|
9285
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
9286
|
+
}
|
|
9287
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
9288
|
+
const forbidden = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
9289
|
+
if (!forbidden.length) return [];
|
|
9290
|
+
const observed = result && typeof result.body_not_patterns === "object" && !Array.isArray(result.body_not_patterns)
|
|
9291
|
+
? result.body_not_patterns
|
|
9292
|
+
: {};
|
|
9293
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
9294
|
+
}
|
|
9242
9295
|
function linkStatusResultOk(result, check) {
|
|
9243
9296
|
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
9244
9297
|
if (!httpStatusIsAllowed(result.status, check)) return false;
|
|
@@ -9254,6 +9307,8 @@ function linkStatusResultOk(result, check) {
|
|
|
9254
9307
|
if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
|
|
9255
9308
|
}
|
|
9256
9309
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
9310
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
9311
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
9257
9312
|
return true;
|
|
9258
9313
|
}
|
|
9259
9314
|
function summarizeHttpStatusEvidence(viewport, check) {
|
|
@@ -9272,6 +9327,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
9272
9327
|
}
|
|
9273
9328
|
const failures = [];
|
|
9274
9329
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
9330
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
9331
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
9275
9332
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
9276
9333
|
failures.push({
|
|
9277
9334
|
code: "http_status_failed",
|
|
@@ -9286,6 +9343,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
9286
9343
|
allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
|
|
9287
9344
|
body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
|
|
9288
9345
|
body_contains_missing: bodyContainsMissing,
|
|
9346
|
+
body_not_contains: Array.isArray(check.body_not_contains) ? check.body_not_contains : null,
|
|
9347
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
9348
|
+
body_not_patterns: Array.isArray(check.body_not_patterns) ? check.body_not_patterns : null,
|
|
9349
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
9289
9350
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
9290
9351
|
});
|
|
9291
9352
|
}
|
|
@@ -9305,6 +9366,14 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
9305
9366
|
? statusEvidence.body_contains
|
|
9306
9367
|
: null,
|
|
9307
9368
|
body_contains_missing: bodyContainsMissing,
|
|
9369
|
+
body_not_contains: statusEvidence.body_not_contains && typeof statusEvidence.body_not_contains === "object" && !Array.isArray(statusEvidence.body_not_contains)
|
|
9370
|
+
? statusEvidence.body_not_contains
|
|
9371
|
+
: null,
|
|
9372
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
9373
|
+
body_not_patterns: statusEvidence.body_not_patterns && typeof statusEvidence.body_not_patterns === "object" && !Array.isArray(statusEvidence.body_not_patterns)
|
|
9374
|
+
? statusEvidence.body_not_patterns
|
|
9375
|
+
: null,
|
|
9376
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
9308
9377
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
9309
9378
|
failures,
|
|
9310
9379
|
};
|
|
@@ -11300,6 +11369,8 @@ async function collectHttpStatus(check) {
|
|
|
11300
11369
|
body = check.body;
|
|
11301
11370
|
}
|
|
11302
11371
|
const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
|
|
11372
|
+
const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
11373
|
+
const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
11303
11374
|
const options = {
|
|
11304
11375
|
method,
|
|
11305
11376
|
redirect: "follow",
|
|
@@ -11325,15 +11396,17 @@ async function collectHttpStatus(check) {
|
|
|
11325
11396
|
Object.assign(result, linkProbeResponseFields(response, method));
|
|
11326
11397
|
result.url = url;
|
|
11327
11398
|
result.status_text = response.statusText || "";
|
|
11328
|
-
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
|
|
11399
|
+
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
|
|
11329
11400
|
if (shouldReadBody) {
|
|
11330
11401
|
try {
|
|
11331
11402
|
const buffer = await response.arrayBuffer();
|
|
11332
11403
|
result.bytes = buffer.byteLength;
|
|
11333
|
-
if (bodyContains.length) {
|
|
11404
|
+
if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
|
|
11334
11405
|
const text = new TextDecoder().decode(buffer);
|
|
11335
11406
|
result.body_sample = text.slice(0, 1000);
|
|
11336
|
-
result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
11407
|
+
if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
11408
|
+
if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
|
|
11409
|
+
if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
|
|
11337
11410
|
}
|
|
11338
11411
|
} catch (error) {
|
|
11339
11412
|
result.error = String(error && error.message ? error.message : error).slice(0, 500);
|
|
@@ -11344,6 +11417,8 @@ async function collectHttpStatus(check) {
|
|
|
11344
11417
|
&& (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
|
|
11345
11418
|
&& (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
|
|
11346
11419
|
&& (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
|
|
11420
|
+
&& (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
|
|
11421
|
+
&& (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
|
|
11347
11422
|
&& !result.error;
|
|
11348
11423
|
return result;
|
|
11349
11424
|
} catch (error) {
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -9536,6 +9536,15 @@ function normalizeCheck(input, index) {
|
|
|
9536
9536
|
input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
|
|
9537
9537
|
`checks[${index}] body_contains`
|
|
9538
9538
|
) : void 0;
|
|
9539
|
+
const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
|
|
9540
|
+
input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
9541
|
+
`checks[${index}] body_not_contains`
|
|
9542
|
+
) : void 0;
|
|
9543
|
+
const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
|
|
9544
|
+
input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
9545
|
+
`checks[${index}] body_not_patterns`
|
|
9546
|
+
) : void 0;
|
|
9547
|
+
if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
|
|
9539
9548
|
if (isLinkStatusCheck) {
|
|
9540
9549
|
if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
|
|
9541
9550
|
throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
|
|
@@ -9559,6 +9568,8 @@ function normalizeCheck(input, index) {
|
|
|
9559
9568
|
body: isHttpStatusCheck ? stringValue5(input.body) : void 0,
|
|
9560
9569
|
body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
|
|
9561
9570
|
body_contains: bodyContains,
|
|
9571
|
+
body_not_contains: bodyNotContains,
|
|
9572
|
+
body_not_patterns: bodyNotPatterns,
|
|
9562
9573
|
expected_texts: expectedTexts,
|
|
9563
9574
|
link_selector: stringValue5(input.link_selector) || stringValue5(input.linkSelector),
|
|
9564
9575
|
source_selector: stringValue5(input.source_selector) || stringValue5(input.sourceSelector),
|
|
@@ -9736,6 +9747,18 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
9736
9747
|
const observed = isRecord2(result.body_contains) ? result.body_contains : {};
|
|
9737
9748
|
return expected.filter((text) => observed[text] !== true);
|
|
9738
9749
|
}
|
|
9750
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
9751
|
+
const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
|
|
9752
|
+
if (!forbidden.length) return [];
|
|
9753
|
+
const observed = isRecord2(result.body_not_contains) ? result.body_not_contains : {};
|
|
9754
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
9755
|
+
}
|
|
9756
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
9757
|
+
const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
|
|
9758
|
+
if (!forbidden.length) return [];
|
|
9759
|
+
const observed = isRecord2(result.body_not_patterns) ? result.body_not_patterns : {};
|
|
9760
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
9761
|
+
}
|
|
9739
9762
|
function linkStatusResultOk(result, check) {
|
|
9740
9763
|
const status = numberValue3(result.status);
|
|
9741
9764
|
if (!httpStatusIsAllowed(status, check)) return false;
|
|
@@ -9751,6 +9774,8 @@ function linkStatusResultOk(result, check) {
|
|
|
9751
9774
|
if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
|
|
9752
9775
|
}
|
|
9753
9776
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
9777
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
9778
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
9754
9779
|
return true;
|
|
9755
9780
|
}
|
|
9756
9781
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
@@ -9773,6 +9798,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
9773
9798
|
}
|
|
9774
9799
|
const failures = [];
|
|
9775
9800
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
9801
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
9802
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
9776
9803
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
9777
9804
|
failures.push({
|
|
9778
9805
|
code: "http_status_failed",
|
|
@@ -9787,6 +9814,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
9787
9814
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
9788
9815
|
body_contains: check.body_contains ?? null,
|
|
9789
9816
|
body_contains_missing: bodyContainsMissing,
|
|
9817
|
+
body_not_contains: check.body_not_contains ?? null,
|
|
9818
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
9819
|
+
body_not_patterns: check.body_not_patterns ?? null,
|
|
9820
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
9790
9821
|
body_sample: stringValue5(statusEvidence.body_sample) ?? null
|
|
9791
9822
|
});
|
|
9792
9823
|
}
|
|
@@ -9804,6 +9835,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
9804
9835
|
bytes: linkStatusObservedBytes(statusEvidence) ?? null,
|
|
9805
9836
|
body_contains: isRecord2(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
|
|
9806
9837
|
body_contains_missing: bodyContainsMissing,
|
|
9838
|
+
body_not_contains: isRecord2(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
|
|
9839
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
9840
|
+
body_not_patterns: isRecord2(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
|
|
9841
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
9807
9842
|
body_sample: stringValue5(statusEvidence.body_sample) ?? null,
|
|
9808
9843
|
failures
|
|
9809
9844
|
};
|
|
@@ -10415,6 +10450,8 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
10415
10450
|
min_bytes: check.min_bytes ?? null,
|
|
10416
10451
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
10417
10452
|
body_contains: check.body_contains ?? [],
|
|
10453
|
+
body_not_contains: check.body_not_contains ?? [],
|
|
10454
|
+
body_not_patterns: check.body_not_patterns ?? [],
|
|
10418
10455
|
viewports: summaries.map((summary) => toJsonValue(summary)),
|
|
10419
10456
|
failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue5(summary.viewport) ?? null, failure })) : [])
|
|
10420
10457
|
},
|
|
@@ -11091,6 +11128,22 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
11091
11128
|
: {};
|
|
11092
11129
|
return expected.filter((text) => observed[text] !== true);
|
|
11093
11130
|
}
|
|
11131
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
11132
|
+
const forbidden = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
11133
|
+
if (!forbidden.length) return [];
|
|
11134
|
+
const observed = result && typeof result.body_not_contains === "object" && !Array.isArray(result.body_not_contains)
|
|
11135
|
+
? result.body_not_contains
|
|
11136
|
+
: {};
|
|
11137
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
11138
|
+
}
|
|
11139
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
11140
|
+
const forbidden = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
11141
|
+
if (!forbidden.length) return [];
|
|
11142
|
+
const observed = result && typeof result.body_not_patterns === "object" && !Array.isArray(result.body_not_patterns)
|
|
11143
|
+
? result.body_not_patterns
|
|
11144
|
+
: {};
|
|
11145
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
11146
|
+
}
|
|
11094
11147
|
function linkStatusResultOk(result, check) {
|
|
11095
11148
|
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
11096
11149
|
if (!httpStatusIsAllowed(result.status, check)) return false;
|
|
@@ -11106,6 +11159,8 @@ function linkStatusResultOk(result, check) {
|
|
|
11106
11159
|
if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
|
|
11107
11160
|
}
|
|
11108
11161
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
11162
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
11163
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
11109
11164
|
return true;
|
|
11110
11165
|
}
|
|
11111
11166
|
function summarizeHttpStatusEvidence(viewport, check) {
|
|
@@ -11124,6 +11179,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
11124
11179
|
}
|
|
11125
11180
|
const failures = [];
|
|
11126
11181
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
11182
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
11183
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
11127
11184
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
11128
11185
|
failures.push({
|
|
11129
11186
|
code: "http_status_failed",
|
|
@@ -11138,6 +11195,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
11138
11195
|
allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
|
|
11139
11196
|
body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
|
|
11140
11197
|
body_contains_missing: bodyContainsMissing,
|
|
11198
|
+
body_not_contains: Array.isArray(check.body_not_contains) ? check.body_not_contains : null,
|
|
11199
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
11200
|
+
body_not_patterns: Array.isArray(check.body_not_patterns) ? check.body_not_patterns : null,
|
|
11201
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
11141
11202
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
11142
11203
|
});
|
|
11143
11204
|
}
|
|
@@ -11157,6 +11218,14 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
11157
11218
|
? statusEvidence.body_contains
|
|
11158
11219
|
: null,
|
|
11159
11220
|
body_contains_missing: bodyContainsMissing,
|
|
11221
|
+
body_not_contains: statusEvidence.body_not_contains && typeof statusEvidence.body_not_contains === "object" && !Array.isArray(statusEvidence.body_not_contains)
|
|
11222
|
+
? statusEvidence.body_not_contains
|
|
11223
|
+
: null,
|
|
11224
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
11225
|
+
body_not_patterns: statusEvidence.body_not_patterns && typeof statusEvidence.body_not_patterns === "object" && !Array.isArray(statusEvidence.body_not_patterns)
|
|
11226
|
+
? statusEvidence.body_not_patterns
|
|
11227
|
+
: null,
|
|
11228
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
11160
11229
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
11161
11230
|
failures,
|
|
11162
11231
|
};
|
|
@@ -13152,6 +13221,8 @@ async function collectHttpStatus(check) {
|
|
|
13152
13221
|
body = check.body;
|
|
13153
13222
|
}
|
|
13154
13223
|
const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
|
|
13224
|
+
const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
13225
|
+
const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
13155
13226
|
const options = {
|
|
13156
13227
|
method,
|
|
13157
13228
|
redirect: "follow",
|
|
@@ -13177,15 +13248,17 @@ async function collectHttpStatus(check) {
|
|
|
13177
13248
|
Object.assign(result, linkProbeResponseFields(response, method));
|
|
13178
13249
|
result.url = url;
|
|
13179
13250
|
result.status_text = response.statusText || "";
|
|
13180
|
-
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
|
|
13251
|
+
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
|
|
13181
13252
|
if (shouldReadBody) {
|
|
13182
13253
|
try {
|
|
13183
13254
|
const buffer = await response.arrayBuffer();
|
|
13184
13255
|
result.bytes = buffer.byteLength;
|
|
13185
|
-
if (bodyContains.length) {
|
|
13256
|
+
if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
|
|
13186
13257
|
const text = new TextDecoder().decode(buffer);
|
|
13187
13258
|
result.body_sample = text.slice(0, 1000);
|
|
13188
|
-
result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
13259
|
+
if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
13260
|
+
if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
|
|
13261
|
+
if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
|
|
13189
13262
|
}
|
|
13190
13263
|
} catch (error) {
|
|
13191
13264
|
result.error = String(error && error.message ? error.message : error).slice(0, 500);
|
|
@@ -13196,6 +13269,8 @@ async function collectHttpStatus(check) {
|
|
|
13196
13269
|
&& (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
|
|
13197
13270
|
&& (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
|
|
13198
13271
|
&& (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
|
|
13272
|
+
&& (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
|
|
13273
|
+
&& (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
|
|
13199
13274
|
&& !result.error;
|
|
13200
13275
|
return result;
|
|
13201
13276
|
} catch (error) {
|
package/dist/index.js
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
resolveRiddleProofProfileTimeoutSec,
|
|
59
59
|
slugifyRiddleProofProfileName,
|
|
60
60
|
summarizeRiddleProofProfileResult
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-7FQU5UH7.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -850,6 +850,15 @@ function normalizeCheck(input, index) {
|
|
|
850
850
|
input.body_contains ?? input.bodyContains ?? input.expected_body_contains ?? input.expectedBodyContains ?? input.response_body_contains ?? input.responseBodyContains ?? input.body_includes ?? input.bodyIncludes,
|
|
851
851
|
`checks[${index}] body_contains`
|
|
852
852
|
) : void 0;
|
|
853
|
+
const bodyNotContains = isHttpStatusCheck ? normalizeStringList(
|
|
854
|
+
input.body_not_contains ?? input.bodyNotContains ?? input.expected_body_not_contains ?? input.expectedBodyNotContains ?? input.response_body_not_contains ?? input.responseBodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
855
|
+
`checks[${index}] body_not_contains`
|
|
856
|
+
) : void 0;
|
|
857
|
+
const bodyNotPatterns = isHttpStatusCheck ? normalizeStringList(
|
|
858
|
+
input.body_not_patterns ?? input.bodyNotPatterns ?? input.expected_body_not_patterns ?? input.expectedBodyNotPatterns ?? input.response_body_not_patterns ?? input.responseBodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
859
|
+
`checks[${index}] body_not_patterns`
|
|
860
|
+
) : void 0;
|
|
861
|
+
if (bodyNotPatterns?.length) validateRegexPatterns(bodyNotPatterns, `checks[${index}] body_not_patterns`);
|
|
853
862
|
if (isLinkStatusCheck) {
|
|
854
863
|
if (minCount !== void 0 && (!Number.isInteger(minCount) || minCount < 0)) {
|
|
855
864
|
throw new Error(`checks[${index}] ${type} min_count must be a non-negative integer.`);
|
|
@@ -873,6 +882,8 @@ function normalizeCheck(input, index) {
|
|
|
873
882
|
body: isHttpStatusCheck ? stringValue(input.body) : void 0,
|
|
874
883
|
body_json: isHttpStatusCheck && hasBodyJson ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : void 0,
|
|
875
884
|
body_contains: bodyContains,
|
|
885
|
+
body_not_contains: bodyNotContains,
|
|
886
|
+
body_not_patterns: bodyNotPatterns,
|
|
876
887
|
expected_texts: expectedTexts,
|
|
877
888
|
link_selector: stringValue(input.link_selector) || stringValue(input.linkSelector),
|
|
878
889
|
source_selector: stringValue(input.source_selector) || stringValue(input.sourceSelector),
|
|
@@ -1050,6 +1061,18 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
1050
1061
|
const observed = isRecord(result.body_contains) ? result.body_contains : {};
|
|
1051
1062
|
return expected.filter((text) => observed[text] !== true);
|
|
1052
1063
|
}
|
|
1064
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
1065
|
+
const forbidden = check.body_not_contains?.filter(Boolean) ?? [];
|
|
1066
|
+
if (!forbidden.length) return [];
|
|
1067
|
+
const observed = isRecord(result.body_not_contains) ? result.body_not_contains : {};
|
|
1068
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
1069
|
+
}
|
|
1070
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
1071
|
+
const forbidden = check.body_not_patterns?.filter(Boolean) ?? [];
|
|
1072
|
+
if (!forbidden.length) return [];
|
|
1073
|
+
const observed = isRecord(result.body_not_patterns) ? result.body_not_patterns : {};
|
|
1074
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
1075
|
+
}
|
|
1053
1076
|
function linkStatusResultOk(result, check) {
|
|
1054
1077
|
const status = numberValue(result.status);
|
|
1055
1078
|
if (!httpStatusIsAllowed(status, check)) return false;
|
|
@@ -1065,6 +1088,8 @@ function linkStatusResultOk(result, check) {
|
|
|
1065
1088
|
if (observedBytes === void 0 || observedBytes < check.min_bytes) return false;
|
|
1066
1089
|
}
|
|
1067
1090
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
1091
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
1092
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
1068
1093
|
return true;
|
|
1069
1094
|
}
|
|
1070
1095
|
function httpStatusEvidenceForCheck(viewport, check) {
|
|
@@ -1087,6 +1112,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
1087
1112
|
}
|
|
1088
1113
|
const failures = [];
|
|
1089
1114
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
1115
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
1116
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
1090
1117
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
1091
1118
|
failures.push({
|
|
1092
1119
|
code: "http_status_failed",
|
|
@@ -1101,6 +1128,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
1101
1128
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
1102
1129
|
body_contains: check.body_contains ?? null,
|
|
1103
1130
|
body_contains_missing: bodyContainsMissing,
|
|
1131
|
+
body_not_contains: check.body_not_contains ?? null,
|
|
1132
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
1133
|
+
body_not_patterns: check.body_not_patterns ?? null,
|
|
1134
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
1104
1135
|
body_sample: stringValue(statusEvidence.body_sample) ?? null
|
|
1105
1136
|
});
|
|
1106
1137
|
}
|
|
@@ -1118,6 +1149,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
1118
1149
|
bytes: linkStatusObservedBytes(statusEvidence) ?? null,
|
|
1119
1150
|
body_contains: isRecord(statusEvidence.body_contains) ? toJsonValue(statusEvidence.body_contains) : null,
|
|
1120
1151
|
body_contains_missing: bodyContainsMissing,
|
|
1152
|
+
body_not_contains: isRecord(statusEvidence.body_not_contains) ? toJsonValue(statusEvidence.body_not_contains) : null,
|
|
1153
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
1154
|
+
body_not_patterns: isRecord(statusEvidence.body_not_patterns) ? toJsonValue(statusEvidence.body_not_patterns) : null,
|
|
1155
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
1121
1156
|
body_sample: stringValue(statusEvidence.body_sample) ?? null,
|
|
1122
1157
|
failures
|
|
1123
1158
|
};
|
|
@@ -1729,6 +1764,8 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
1729
1764
|
min_bytes: check.min_bytes ?? null,
|
|
1730
1765
|
allowed_content_types: check.allowed_content_types ?? null,
|
|
1731
1766
|
body_contains: check.body_contains ?? [],
|
|
1767
|
+
body_not_contains: check.body_not_contains ?? [],
|
|
1768
|
+
body_not_patterns: check.body_not_patterns ?? [],
|
|
1732
1769
|
viewports: summaries.map((summary) => toJsonValue(summary)),
|
|
1733
1770
|
failures: failed.flatMap((summary) => Array.isArray(summary.failures) ? summary.failures.map((failure) => toJsonValue({ viewport: stringValue(summary.viewport) ?? null, failure })) : [])
|
|
1734
1771
|
},
|
|
@@ -2405,6 +2442,22 @@ function httpStatusBodyContainsFailures(result, check) {
|
|
|
2405
2442
|
: {};
|
|
2406
2443
|
return expected.filter((text) => observed[text] !== true);
|
|
2407
2444
|
}
|
|
2445
|
+
function httpStatusBodyNotContainsFailures(result, check) {
|
|
2446
|
+
const forbidden = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
2447
|
+
if (!forbidden.length) return [];
|
|
2448
|
+
const observed = result && typeof result.body_not_contains === "object" && !Array.isArray(result.body_not_contains)
|
|
2449
|
+
? result.body_not_contains
|
|
2450
|
+
: {};
|
|
2451
|
+
return forbidden.filter((text) => observed[text] !== false);
|
|
2452
|
+
}
|
|
2453
|
+
function httpStatusBodyNotPatternFailures(result, check) {
|
|
2454
|
+
const forbidden = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
2455
|
+
if (!forbidden.length) return [];
|
|
2456
|
+
const observed = result && typeof result.body_not_patterns === "object" && !Array.isArray(result.body_not_patterns)
|
|
2457
|
+
? result.body_not_patterns
|
|
2458
|
+
: {};
|
|
2459
|
+
return forbidden.filter((pattern) => observed[pattern] !== false);
|
|
2460
|
+
}
|
|
2408
2461
|
function linkStatusResultOk(result, check) {
|
|
2409
2462
|
if (!result || typeof result !== "object" || Array.isArray(result)) return false;
|
|
2410
2463
|
if (!httpStatusIsAllowed(result.status, check)) return false;
|
|
@@ -2420,6 +2473,8 @@ function linkStatusResultOk(result, check) {
|
|
|
2420
2473
|
if (observedBytes === undefined || observedBytes < check.min_bytes) return false;
|
|
2421
2474
|
}
|
|
2422
2475
|
if (httpStatusBodyContainsFailures(result, check).length) return false;
|
|
2476
|
+
if (httpStatusBodyNotContainsFailures(result, check).length) return false;
|
|
2477
|
+
if (httpStatusBodyNotPatternFailures(result, check).length) return false;
|
|
2423
2478
|
return true;
|
|
2424
2479
|
}
|
|
2425
2480
|
function summarizeHttpStatusEvidence(viewport, check) {
|
|
@@ -2438,6 +2493,8 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
2438
2493
|
}
|
|
2439
2494
|
const failures = [];
|
|
2440
2495
|
const bodyContainsMissing = httpStatusBodyContainsFailures(statusEvidence, check);
|
|
2496
|
+
const bodyNotContainsFound = httpStatusBodyNotContainsFailures(statusEvidence, check);
|
|
2497
|
+
const bodyNotPatternsFound = httpStatusBodyNotPatternFailures(statusEvidence, check);
|
|
2441
2498
|
if (!linkStatusResultOk(statusEvidence, check)) {
|
|
2442
2499
|
failures.push({
|
|
2443
2500
|
code: "http_status_failed",
|
|
@@ -2452,6 +2509,10 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
2452
2509
|
allowed_content_types: Array.isArray(check.allowed_content_types) ? check.allowed_content_types : null,
|
|
2453
2510
|
body_contains: Array.isArray(check.body_contains) ? check.body_contains : null,
|
|
2454
2511
|
body_contains_missing: bodyContainsMissing,
|
|
2512
|
+
body_not_contains: Array.isArray(check.body_not_contains) ? check.body_not_contains : null,
|
|
2513
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
2514
|
+
body_not_patterns: Array.isArray(check.body_not_patterns) ? check.body_not_patterns : null,
|
|
2515
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
2455
2516
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
2456
2517
|
});
|
|
2457
2518
|
}
|
|
@@ -2471,6 +2532,14 @@ function summarizeHttpStatusEvidence(viewport, check) {
|
|
|
2471
2532
|
? statusEvidence.body_contains
|
|
2472
2533
|
: null,
|
|
2473
2534
|
body_contains_missing: bodyContainsMissing,
|
|
2535
|
+
body_not_contains: statusEvidence.body_not_contains && typeof statusEvidence.body_not_contains === "object" && !Array.isArray(statusEvidence.body_not_contains)
|
|
2536
|
+
? statusEvidence.body_not_contains
|
|
2537
|
+
: null,
|
|
2538
|
+
body_not_contains_found: bodyNotContainsFound,
|
|
2539
|
+
body_not_patterns: statusEvidence.body_not_patterns && typeof statusEvidence.body_not_patterns === "object" && !Array.isArray(statusEvidence.body_not_patterns)
|
|
2540
|
+
? statusEvidence.body_not_patterns
|
|
2541
|
+
: null,
|
|
2542
|
+
body_not_patterns_found: bodyNotPatternsFound,
|
|
2474
2543
|
body_sample: typeof statusEvidence.body_sample === "string" ? statusEvidence.body_sample : null,
|
|
2475
2544
|
failures,
|
|
2476
2545
|
};
|
|
@@ -4466,6 +4535,8 @@ async function collectHttpStatus(check) {
|
|
|
4466
4535
|
body = check.body;
|
|
4467
4536
|
}
|
|
4468
4537
|
const bodyContains = Array.isArray(check.body_contains) ? check.body_contains.filter(Boolean) : [];
|
|
4538
|
+
const bodyNotContains = Array.isArray(check.body_not_contains) ? check.body_not_contains.filter(Boolean) : [];
|
|
4539
|
+
const bodyNotPatterns = Array.isArray(check.body_not_patterns) ? check.body_not_patterns.filter(Boolean) : [];
|
|
4469
4540
|
const options = {
|
|
4470
4541
|
method,
|
|
4471
4542
|
redirect: "follow",
|
|
@@ -4491,15 +4562,17 @@ async function collectHttpStatus(check) {
|
|
|
4491
4562
|
Object.assign(result, linkProbeResponseFields(response, method));
|
|
4492
4563
|
result.url = url;
|
|
4493
4564
|
result.status_text = response.statusText || "";
|
|
4494
|
-
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0;
|
|
4565
|
+
const shouldReadBody = check.require_nonzero_bytes === true || (typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || bodyContains.length > 0 || bodyNotContains.length > 0 || bodyNotPatterns.length > 0;
|
|
4495
4566
|
if (shouldReadBody) {
|
|
4496
4567
|
try {
|
|
4497
4568
|
const buffer = await response.arrayBuffer();
|
|
4498
4569
|
result.bytes = buffer.byteLength;
|
|
4499
|
-
if (bodyContains.length) {
|
|
4570
|
+
if (bodyContains.length || bodyNotContains.length || bodyNotPatterns.length) {
|
|
4500
4571
|
const text = new TextDecoder().decode(buffer);
|
|
4501
4572
|
result.body_sample = text.slice(0, 1000);
|
|
4502
|
-
result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
4573
|
+
if (bodyContains.length) result.body_contains = Object.fromEntries(bodyContains.map((expected) => [expected, text.includes(expected)]));
|
|
4574
|
+
if (bodyNotContains.length) result.body_not_contains = Object.fromEntries(bodyNotContains.map((forbidden) => [forbidden, text.includes(forbidden)]));
|
|
4575
|
+
if (bodyNotPatterns.length) result.body_not_patterns = Object.fromEntries(bodyNotPatterns.map((pattern) => [pattern, new RegExp(pattern).test(text)]));
|
|
4503
4576
|
}
|
|
4504
4577
|
} catch (error) {
|
|
4505
4578
|
result.error = String(error && error.message ? error.message : error).slice(0, 500);
|
|
@@ -4510,6 +4583,8 @@ async function collectHttpStatus(check) {
|
|
|
4510
4583
|
&& (check.require_nonzero_bytes !== true || ((linkProbeObservedBytes(result) || 0) > 0))
|
|
4511
4584
|
&& (!(typeof check.min_bytes === "number" && Number.isFinite(check.min_bytes)) || ((linkProbeObservedBytes(result) || 0) >= check.min_bytes))
|
|
4512
4585
|
&& (!bodyContains.length || bodyContains.every((expected) => result.body_contains && result.body_contains[expected] === true))
|
|
4586
|
+
&& (!bodyNotContains.length || bodyNotContains.every((forbidden) => result.body_not_contains && result.body_not_contains[forbidden] === false))
|
|
4587
|
+
&& (!bodyNotPatterns.length || bodyNotPatterns.every((pattern) => result.body_not_patterns && result.body_not_patterns[pattern] === false))
|
|
4513
4588
|
&& !result.error;
|
|
4514
4589
|
return result;
|
|
4515
4590
|
} catch (error) {
|
package/dist/profile.d.cts
CHANGED
|
@@ -120,6 +120,8 @@ interface RiddleProofProfileCheck {
|
|
|
120
120
|
body?: string;
|
|
121
121
|
body_json?: JsonValue;
|
|
122
122
|
body_contains?: string[];
|
|
123
|
+
body_not_contains?: string[];
|
|
124
|
+
body_not_patterns?: string[];
|
|
123
125
|
expected_texts?: string[];
|
|
124
126
|
link_selector?: string;
|
|
125
127
|
source_selector?: string;
|
package/dist/profile.d.ts
CHANGED
|
@@ -120,6 +120,8 @@ interface RiddleProofProfileCheck {
|
|
|
120
120
|
body?: string;
|
|
121
121
|
body_json?: JsonValue;
|
|
122
122
|
body_contains?: string[];
|
|
123
|
+
body_not_contains?: string[];
|
|
124
|
+
body_not_patterns?: string[];
|
|
123
125
|
expected_texts?: string[];
|
|
124
126
|
link_selector?: string;
|
|
125
127
|
source_selector?: string;
|
package/dist/profile.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
resolveRiddleProofProfileTimeoutSec,
|
|
20
20
|
slugifyRiddleProofProfileName,
|
|
21
21
|
summarizeRiddleProofProfileResult
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-7FQU5UH7.js";
|
|
23
23
|
export {
|
|
24
24
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
25
25
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|