@rogatio/cli 5.8.2 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/editor/index.js +681 -739
- package/dist/node/index.js +229 -264
- package/package.json +1 -1
package/dist/node/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// packages/cli/src/index.ts
|
|
4
4
|
import { realpathSync } from "node:fs";
|
|
5
|
-
import { basename as
|
|
5
|
+
import { basename as basename3, dirname as dirname8, resolve as resolve8 } from "node:path";
|
|
6
6
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
7
7
|
|
|
8
8
|
// packages/runtime/dist/node/index.js
|
|
@@ -99,6 +99,7 @@ var LIMITS = Object.freeze({
|
|
|
99
99
|
maxMockDelayMs: 3e4,
|
|
100
100
|
maxMockFilePathLength: 2048,
|
|
101
101
|
maxResponseBodyReplacements: 64,
|
|
102
|
+
maxResponseBodyBytes: 4 * 1024 * 1024,
|
|
102
103
|
maxResponseBodyPatternLength: 2048,
|
|
103
104
|
maxResponseBodyReplacementLength: 4096,
|
|
104
105
|
maxRequestBodyBytes: 4 * 1024 * 1024,
|
|
@@ -266,7 +267,6 @@ var projectSchemaDefinition = {
|
|
|
266
267
|
"redirect",
|
|
267
268
|
"query",
|
|
268
269
|
"header",
|
|
269
|
-
"mock",
|
|
270
270
|
"response-body",
|
|
271
271
|
"request-body"
|
|
272
272
|
]
|
|
@@ -291,9 +291,9 @@ var projectSchemaDefinition = {
|
|
|
291
291
|
type: "string",
|
|
292
292
|
maxLength: LIMITS.maxHeaderValueLength
|
|
293
293
|
},
|
|
294
|
-
mock: { $ref: "#/$defs/mockAction" },
|
|
295
294
|
responseBody: { $ref: "#/$defs/responseBodyAction" },
|
|
296
|
-
requestBody: { $ref: "#/$defs/requestBodyAction" }
|
|
295
|
+
requestBody: { $ref: "#/$defs/requestBodyAction" },
|
|
296
|
+
redactSensitiveInLogs: { type: "boolean" }
|
|
297
297
|
},
|
|
298
298
|
allOf: [
|
|
299
299
|
{
|
|
@@ -326,16 +326,6 @@ var projectSchemaDefinition = {
|
|
|
326
326
|
required: ["headerDirection", "headerOperation", "headerName"]
|
|
327
327
|
}
|
|
328
328
|
},
|
|
329
|
-
{
|
|
330
|
-
if: {
|
|
331
|
-
required: ["type"],
|
|
332
|
-
properties: { type: { const: "mock" } }
|
|
333
|
-
},
|
|
334
|
-
// biome-ignore lint/suspicious/noThenProperty: AJV conditional schema keyword
|
|
335
|
-
then: {
|
|
336
|
-
required: ["mock"]
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
329
|
{
|
|
340
330
|
if: {
|
|
341
331
|
required: ["type"],
|
|
@@ -391,19 +381,51 @@ var projectSchemaDefinition = {
|
|
|
391
381
|
queryParam: {
|
|
392
382
|
type: "object",
|
|
393
383
|
additionalProperties: false,
|
|
394
|
-
required: ["name"
|
|
384
|
+
required: ["name"],
|
|
395
385
|
properties: {
|
|
396
386
|
name: {
|
|
397
387
|
type: "string",
|
|
398
388
|
minLength: 1,
|
|
399
389
|
maxLength: LIMITS.maxQueryNameLength
|
|
400
390
|
},
|
|
391
|
+
operation: {
|
|
392
|
+
enum: ["set", "remove"]
|
|
393
|
+
},
|
|
401
394
|
value: {
|
|
402
395
|
type: "string",
|
|
403
396
|
minLength: 1,
|
|
404
397
|
maxLength: LIMITS.maxQueryValueLength
|
|
405
398
|
}
|
|
406
|
-
}
|
|
399
|
+
},
|
|
400
|
+
allOf: [
|
|
401
|
+
{
|
|
402
|
+
if: {
|
|
403
|
+
anyOf: [
|
|
404
|
+
{ not: { required: ["operation"] } },
|
|
405
|
+
{
|
|
406
|
+
properties: { operation: { const: "set" } },
|
|
407
|
+
required: ["operation"]
|
|
408
|
+
}
|
|
409
|
+
]
|
|
410
|
+
},
|
|
411
|
+
// biome-ignore lint/suspicious/noThenProperty: AJV conditional schema keyword
|
|
412
|
+
then: {
|
|
413
|
+
required: ["value"]
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
if: {
|
|
418
|
+
properties: { operation: { const: "remove" } },
|
|
419
|
+
required: ["operation"]
|
|
420
|
+
},
|
|
421
|
+
// biome-ignore lint/suspicious/noThenProperty: AJV conditional schema keyword
|
|
422
|
+
then: {
|
|
423
|
+
properties: {
|
|
424
|
+
value: false
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
]
|
|
407
429
|
},
|
|
408
430
|
queryAction: {
|
|
409
431
|
type: "object",
|
|
@@ -419,71 +441,50 @@ var projectSchemaDefinition = {
|
|
|
419
441
|
}
|
|
420
442
|
}
|
|
421
443
|
},
|
|
422
|
-
|
|
444
|
+
responseBodyReplacement: {
|
|
423
445
|
type: "object",
|
|
424
446
|
additionalProperties: false,
|
|
425
|
-
required: ["
|
|
447
|
+
required: ["pattern", "replacement"],
|
|
426
448
|
properties: {
|
|
427
|
-
|
|
449
|
+
pattern: {
|
|
428
450
|
type: "string",
|
|
429
451
|
minLength: 1,
|
|
430
|
-
maxLength: LIMITS.
|
|
452
|
+
maxLength: LIMITS.maxResponseBodyPatternLength,
|
|
453
|
+
format: "rogatio-url-regex"
|
|
431
454
|
},
|
|
432
|
-
|
|
455
|
+
replacement: {
|
|
433
456
|
type: "string",
|
|
434
|
-
maxLength: LIMITS.
|
|
457
|
+
maxLength: LIMITS.maxResponseBodyReplacementLength
|
|
435
458
|
}
|
|
436
459
|
}
|
|
437
460
|
},
|
|
438
|
-
|
|
461
|
+
responseBodyReplaceAction: {
|
|
439
462
|
type: "object",
|
|
440
463
|
additionalProperties: false,
|
|
441
|
-
required: ["
|
|
464
|
+
required: ["mode", "body"],
|
|
442
465
|
properties: {
|
|
443
|
-
|
|
444
|
-
type: "integer",
|
|
445
|
-
minimum: LIMITS.minMockStatus,
|
|
446
|
-
maximum: LIMITS.maxMockStatus
|
|
447
|
-
},
|
|
448
|
-
headers: {
|
|
449
|
-
type: "array",
|
|
450
|
-
maxItems: LIMITS.maxMockHeadersPerRule,
|
|
451
|
-
items: { $ref: "#/$defs/mockHeader" }
|
|
452
|
-
},
|
|
453
|
-
delayMs: {
|
|
454
|
-
type: "integer",
|
|
455
|
-
minimum: 0,
|
|
456
|
-
maximum: LIMITS.maxMockDelayMs
|
|
457
|
-
},
|
|
466
|
+
mode: { const: "replace" },
|
|
458
467
|
body: {
|
|
459
468
|
type: "string",
|
|
460
|
-
maxLength: LIMITS.
|
|
461
|
-
},
|
|
462
|
-
file: {
|
|
463
|
-
type: "string",
|
|
464
|
-
minLength: 1,
|
|
465
|
-
maxLength: LIMITS.maxMockFilePathLength
|
|
469
|
+
maxLength: LIMITS.maxResponseBodyBytes
|
|
466
470
|
}
|
|
467
471
|
}
|
|
468
472
|
},
|
|
469
|
-
|
|
473
|
+
responseBodyRegexAction: {
|
|
470
474
|
type: "object",
|
|
471
475
|
additionalProperties: false,
|
|
472
|
-
required: ["
|
|
476
|
+
required: ["mode", "replacements"],
|
|
473
477
|
properties: {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
replacement: {
|
|
481
|
-
type: "string",
|
|
482
|
-
maxLength: LIMITS.maxResponseBodyReplacementLength
|
|
478
|
+
mode: { const: "regex" },
|
|
479
|
+
replacements: {
|
|
480
|
+
type: "array",
|
|
481
|
+
minItems: 1,
|
|
482
|
+
maxItems: LIMITS.maxResponseBodyReplacements,
|
|
483
|
+
items: { $ref: "#/$defs/responseBodyReplacement" }
|
|
483
484
|
}
|
|
484
485
|
}
|
|
485
486
|
},
|
|
486
|
-
|
|
487
|
+
responseBodyUntaggedRegexAction: {
|
|
487
488
|
type: "object",
|
|
488
489
|
additionalProperties: false,
|
|
489
490
|
required: ["replacements"],
|
|
@@ -496,6 +497,13 @@ var projectSchemaDefinition = {
|
|
|
496
497
|
}
|
|
497
498
|
}
|
|
498
499
|
},
|
|
500
|
+
responseBodyAction: {
|
|
501
|
+
oneOf: [
|
|
502
|
+
{ $ref: "#/$defs/responseBodyReplaceAction" },
|
|
503
|
+
{ $ref: "#/$defs/responseBodyRegexAction" },
|
|
504
|
+
{ $ref: "#/$defs/responseBodyUntaggedRegexAction" }
|
|
505
|
+
]
|
|
506
|
+
},
|
|
499
507
|
requestBodyReplaceAction: {
|
|
500
508
|
type: "object",
|
|
501
509
|
additionalProperties: false,
|
|
@@ -547,6 +555,21 @@ var projectSchemaDefinition = {
|
|
|
547
555
|
}
|
|
548
556
|
};
|
|
549
557
|
var projectSchema = projectSchemaDefinition;
|
|
558
|
+
function hasLoneSurrogate(value) {
|
|
559
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
560
|
+
const code = value.charCodeAt(i);
|
|
561
|
+
if (code >= 55296 && code <= 56319) {
|
|
562
|
+
if (i + 1 >= value.length) return true;
|
|
563
|
+
const next = value.charCodeAt(i + 1);
|
|
564
|
+
if (next < 56320 || next > 57343) return true;
|
|
565
|
+
} else if (code >= 56320 && code <= 57343) {
|
|
566
|
+
if (i === 0) return true;
|
|
567
|
+
const prev = value.charCodeAt(i - 1);
|
|
568
|
+
if (prev < 55296 || prev > 56319) return true;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
550
573
|
var ajv = new Ajv2020({
|
|
551
574
|
allErrors: true,
|
|
552
575
|
coerceTypes: false,
|
|
@@ -678,22 +701,6 @@ function semanticIssues(project) {
|
|
|
678
701
|
ids.set(group.id, `${groupPath}/id`);
|
|
679
702
|
}
|
|
680
703
|
for (let ruleIndex = 0; ruleIndex < group.rules.length; ruleIndex += 1) {
|
|
681
|
-
let hasLoneSurrogate2 = function(value) {
|
|
682
|
-
for (let i = 0; i < value.length; i += 1) {
|
|
683
|
-
const code = value.charCodeAt(i);
|
|
684
|
-
if (code >= 55296 && code <= 56319) {
|
|
685
|
-
if (i + 1 >= value.length) return true;
|
|
686
|
-
const next = value.charCodeAt(i + 1);
|
|
687
|
-
if (next < 56320 || next > 57343) return true;
|
|
688
|
-
} else if (code >= 56320 && code <= 57343) {
|
|
689
|
-
if (i === 0) return true;
|
|
690
|
-
const prev = value.charCodeAt(i - 1);
|
|
691
|
-
if (prev < 55296 || prev > 56319) return true;
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
return false;
|
|
695
|
-
};
|
|
696
|
-
var hasLoneSurrogate = hasLoneSurrogate2;
|
|
697
704
|
const rule = group.rules[ruleIndex];
|
|
698
705
|
ruleCount += 1;
|
|
699
706
|
const rulePath = `${groupPath}/rules/${ruleIndex}`;
|
|
@@ -708,17 +715,16 @@ function semanticIssues(project) {
|
|
|
708
715
|
} else {
|
|
709
716
|
ids.set(rule.id, `${rulePath}/id`);
|
|
710
717
|
}
|
|
711
|
-
if (rule.type !== void 0 && rule.type !== "redirect" && rule.type !== "query" && rule.type !== "header" && rule.type !== "
|
|
718
|
+
if (rule.type !== void 0 && rule.type !== "redirect" && rule.type !== "query" && rule.type !== "header" && rule.type !== "response-body" && rule.type !== "request-body") {
|
|
712
719
|
issues.push({
|
|
713
720
|
instancePath: `${rulePath}/type`,
|
|
714
721
|
keyword: "enum",
|
|
715
|
-
message: 'must be "redirect", "query", "header", "
|
|
722
|
+
message: 'must be "redirect", "query", "header", "response-body", or "request-body"',
|
|
716
723
|
params: {
|
|
717
724
|
allowedValues: [
|
|
718
725
|
"redirect",
|
|
719
726
|
"query",
|
|
720
727
|
"header",
|
|
721
|
-
"mock",
|
|
722
728
|
"response-body",
|
|
723
729
|
"request-body"
|
|
724
730
|
]
|
|
@@ -782,6 +788,24 @@ function semanticIssues(project) {
|
|
|
782
788
|
} else {
|
|
783
789
|
seenNames.add(paramName);
|
|
784
790
|
}
|
|
791
|
+
const operation = param.operation ?? "set";
|
|
792
|
+
if (operation === "set") {
|
|
793
|
+
if (typeof param.value !== "string" || param.value.length === 0 || param.value.length > LIMITS.maxQueryValueLength) {
|
|
794
|
+
issues.push({
|
|
795
|
+
instancePath: `${rulePath}/action/params/${p}/value`,
|
|
796
|
+
keyword: "queryParamValue",
|
|
797
|
+
message: "query param value is required for set",
|
|
798
|
+
params: {}
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
} else if (param.value !== void 0) {
|
|
802
|
+
issues.push({
|
|
803
|
+
instancePath: `${rulePath}/action/params/${p}/value`,
|
|
804
|
+
keyword: "queryParamValue",
|
|
805
|
+
message: "query param value must be omitted for remove",
|
|
806
|
+
params: {}
|
|
807
|
+
});
|
|
808
|
+
}
|
|
785
809
|
}
|
|
786
810
|
}
|
|
787
811
|
if (rule.type === "header" && rule.headerName !== void 0) {
|
|
@@ -801,25 +825,64 @@ function semanticIssues(project) {
|
|
|
801
825
|
if (rule.type === "response-body") {
|
|
802
826
|
const action2 = rule.responseBody;
|
|
803
827
|
const actionPath = `${rulePath}/responseBody`;
|
|
804
|
-
if (!action2
|
|
828
|
+
if (!action2) {
|
|
805
829
|
issues.push({
|
|
806
|
-
instancePath:
|
|
807
|
-
keyword: "response-body-
|
|
808
|
-
message: "A response-body rule must define
|
|
830
|
+
instancePath: actionPath,
|
|
831
|
+
keyword: "response-body-action",
|
|
832
|
+
message: "A response-body rule must define a responseBody action.",
|
|
809
833
|
params: {}
|
|
810
834
|
});
|
|
811
|
-
} else {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
835
|
+
} else if ("mode" in action2 && action2.mode === "replace") {
|
|
836
|
+
if (typeof action2.body !== "string") {
|
|
837
|
+
issues.push({
|
|
838
|
+
instancePath: `${actionPath}/body`,
|
|
839
|
+
keyword: "response-body-replace-body",
|
|
840
|
+
message: "Replace mode requires a body string.",
|
|
841
|
+
params: {}
|
|
842
|
+
});
|
|
843
|
+
} else if (action2.body.length > LIMITS.maxResponseBodyBytes) {
|
|
844
|
+
issues.push({
|
|
845
|
+
instancePath: `${actionPath}/body`,
|
|
846
|
+
keyword: "response-body-replace-body",
|
|
847
|
+
message: `Replace body exceeds the maximum size of ${LIMITS.maxResponseBodyBytes} bytes.`,
|
|
848
|
+
params: { limit: LIMITS.maxResponseBodyBytes }
|
|
849
|
+
});
|
|
850
|
+
} else if (hasLoneSurrogate(action2.body)) {
|
|
851
|
+
issues.push({
|
|
852
|
+
instancePath: `${actionPath}/body`,
|
|
853
|
+
keyword: "response-body-lone-surrogate",
|
|
854
|
+
message: "Replace body must not contain lone UTF-16 surrogates.",
|
|
855
|
+
params: {}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
} else if ("replacements" in action2 && Array.isArray(action2.replacements)) {
|
|
859
|
+
if (action2.replacements.length === 0) {
|
|
860
|
+
issues.push({
|
|
861
|
+
instancePath: `${actionPath}/replacements`,
|
|
862
|
+
keyword: "response-body-replacements",
|
|
863
|
+
message: "A response-body rule must define at least one replacement.",
|
|
864
|
+
params: {}
|
|
865
|
+
});
|
|
866
|
+
} else {
|
|
867
|
+
for (let index = 0; index < action2.replacements.length; index += 1) {
|
|
868
|
+
const replacement = action2.replacements[index];
|
|
869
|
+
if (compileUrlRegex(replacement.pattern) === null) {
|
|
870
|
+
issues.push({
|
|
871
|
+
instancePath: `${actionPath}/replacements/${index}/pattern`,
|
|
872
|
+
keyword: "response-body-pattern",
|
|
873
|
+
message: "Response-body replacement patterns must be valid regular expressions.",
|
|
874
|
+
params: {}
|
|
875
|
+
});
|
|
876
|
+
}
|
|
821
877
|
}
|
|
822
878
|
}
|
|
879
|
+
} else {
|
|
880
|
+
issues.push({
|
|
881
|
+
instancePath: actionPath,
|
|
882
|
+
keyword: "response-body-mode",
|
|
883
|
+
message: "responseBody must be replace mode, regex mode, or untagged replacements.",
|
|
884
|
+
params: {}
|
|
885
|
+
});
|
|
823
886
|
}
|
|
824
887
|
}
|
|
825
888
|
if (rule.type === "request-body") {
|
|
@@ -857,7 +920,7 @@ function semanticIssues(project) {
|
|
|
857
920
|
message: `Replace body exceeds the maximum size of ${LIMITS.maxRequestBodyBytes} bytes.`,
|
|
858
921
|
params: { limit: LIMITS.maxRequestBodyBytes }
|
|
859
922
|
});
|
|
860
|
-
} else if (
|
|
923
|
+
} else if (hasLoneSurrogate(action2.body)) {
|
|
861
924
|
issues.push({
|
|
862
925
|
instancePath: `${actionPath}/body`,
|
|
863
926
|
keyword: "request-body-lone-surrogate",
|
|
@@ -896,14 +959,14 @@ function semanticIssues(project) {
|
|
|
896
959
|
message: `Regex replacement exceeds the maximum length of ${LIMITS.maxRequestBodyReplacementLength} characters.`,
|
|
897
960
|
params: { limit: LIMITS.maxRequestBodyReplacementLength }
|
|
898
961
|
});
|
|
899
|
-
} else if (
|
|
962
|
+
} else if (hasLoneSurrogate(action2.pattern)) {
|
|
900
963
|
issues.push({
|
|
901
964
|
instancePath: `${actionPath}/pattern`,
|
|
902
965
|
keyword: "request-body-lone-surrogate",
|
|
903
966
|
message: "Regex pattern must not contain lone UTF-16 surrogates.",
|
|
904
967
|
params: {}
|
|
905
968
|
});
|
|
906
|
-
} else if (
|
|
969
|
+
} else if (hasLoneSurrogate(action2.replacement)) {
|
|
907
970
|
issues.push({
|
|
908
971
|
instancePath: `${actionPath}/replacement`,
|
|
909
972
|
keyword: "request-body-lone-surrogate",
|
|
@@ -931,42 +994,6 @@ function semanticIssues(project) {
|
|
|
931
994
|
});
|
|
932
995
|
}
|
|
933
996
|
}
|
|
934
|
-
if (rule.type === "mock") {
|
|
935
|
-
const mock = rule.mock;
|
|
936
|
-
const mockPath = `${rulePath}/mock`;
|
|
937
|
-
const bodySet = mock?.body !== void 0;
|
|
938
|
-
const fileSet = mock?.file !== void 0;
|
|
939
|
-
if (bodySet === fileSet) {
|
|
940
|
-
issues.push({
|
|
941
|
-
instancePath: mockPath,
|
|
942
|
-
keyword: "mock-body-source",
|
|
943
|
-
message: "A mock rule must set exactly one of body or file.",
|
|
944
|
-
params: {}
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
if (mock?.headers !== void 0) {
|
|
948
|
-
for (let h = 0; h < mock.headers.length; h += 1) {
|
|
949
|
-
const header = mock.headers[h];
|
|
950
|
-
if (header === void 0) continue;
|
|
951
|
-
if (hasControl(header.name) || header.name.includes(":")) {
|
|
952
|
-
issues.push({
|
|
953
|
-
instancePath: `${mockPath}/headers/${h}/name`,
|
|
954
|
-
keyword: "mock-header-name",
|
|
955
|
-
message: "Mock header names must not contain control characters or ':'.",
|
|
956
|
-
params: {}
|
|
957
|
-
});
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
if (mock?.file !== void 0 && hasControl(mock.file)) {
|
|
962
|
-
issues.push({
|
|
963
|
-
instancePath: `${mockPath}/file`,
|
|
964
|
-
keyword: "mock-file-path",
|
|
965
|
-
message: "Mock file paths must not contain control characters.",
|
|
966
|
-
params: {}
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
997
|
}
|
|
971
998
|
}
|
|
972
999
|
if (project.requestBodyPolicy !== void 0) {
|
|
@@ -1376,6 +1403,9 @@ function canonicalResourceTypes(resourceTypes) {
|
|
|
1376
1403
|
}
|
|
1377
1404
|
return ordered;
|
|
1378
1405
|
}
|
|
1406
|
+
function resolveRedactSensitiveInLogs(rule) {
|
|
1407
|
+
return rule.redactSensitiveInLogs === true;
|
|
1408
|
+
}
|
|
1379
1409
|
function compileMatcher(group, rule, groupIndex, ruleIndex) {
|
|
1380
1410
|
const matcher = {
|
|
1381
1411
|
urlRegex: { source: rule.urlRegex, flags: "" },
|
|
@@ -1393,11 +1423,14 @@ function compileOperations(project) {
|
|
|
1393
1423
|
for (let ruleIndex = 0; ruleIndex < group.rules.length; ruleIndex += 1) {
|
|
1394
1424
|
const rule = group.rules[ruleIndex];
|
|
1395
1425
|
const matcher = compileMatcher(group, rule, groupIndex, ruleIndex);
|
|
1426
|
+
const redactSensitiveInLogs = resolveRedactSensitiveInLogs(rule);
|
|
1396
1427
|
if (rule.type === "redirect") {
|
|
1397
1428
|
const operation = {
|
|
1398
1429
|
kind: "redirect",
|
|
1399
1430
|
groupId: group.id,
|
|
1400
1431
|
ruleId: rule.id,
|
|
1432
|
+
name: rule.name,
|
|
1433
|
+
redactSensitiveInLogs,
|
|
1401
1434
|
matcher,
|
|
1402
1435
|
redirect: { destination: rule.redirect?.destination ?? "" }
|
|
1403
1436
|
};
|
|
@@ -1408,6 +1441,8 @@ function compileOperations(project) {
|
|
|
1408
1441
|
kind: "query",
|
|
1409
1442
|
groupId: group.id,
|
|
1410
1443
|
ruleId: rule.id,
|
|
1444
|
+
name: rule.name,
|
|
1445
|
+
redactSensitiveInLogs,
|
|
1411
1446
|
matcher,
|
|
1412
1447
|
action
|
|
1413
1448
|
};
|
|
@@ -1417,6 +1452,8 @@ function compileOperations(project) {
|
|
|
1417
1452
|
kind: "header",
|
|
1418
1453
|
groupId: group.id,
|
|
1419
1454
|
ruleId: rule.id,
|
|
1455
|
+
name: rule.name,
|
|
1456
|
+
redactSensitiveInLogs,
|
|
1420
1457
|
matcher,
|
|
1421
1458
|
header: {
|
|
1422
1459
|
direction: rule.headerDirection ?? "request",
|
|
@@ -1426,20 +1463,13 @@ function compileOperations(project) {
|
|
|
1426
1463
|
}
|
|
1427
1464
|
};
|
|
1428
1465
|
operations.push(operation);
|
|
1429
|
-
} else if (rule.type === "mock") {
|
|
1430
|
-
const operation = {
|
|
1431
|
-
kind: "mock",
|
|
1432
|
-
groupId: group.id,
|
|
1433
|
-
ruleId: rule.id,
|
|
1434
|
-
matcher,
|
|
1435
|
-
mock: rule.mock ?? { status: 200, body: "" }
|
|
1436
|
-
};
|
|
1437
|
-
operations.push(operation);
|
|
1438
1466
|
} else if (rule.type === "response-body") {
|
|
1439
1467
|
const operation = {
|
|
1440
1468
|
kind: "response-body",
|
|
1441
1469
|
groupId: group.id,
|
|
1442
1470
|
ruleId: rule.id,
|
|
1471
|
+
name: rule.name,
|
|
1472
|
+
redactSensitiveInLogs,
|
|
1443
1473
|
matcher,
|
|
1444
1474
|
responseBody: rule.responseBody ?? { replacements: [] }
|
|
1445
1475
|
};
|
|
@@ -1449,6 +1479,8 @@ function compileOperations(project) {
|
|
|
1449
1479
|
kind: "request-body",
|
|
1450
1480
|
groupId: group.id,
|
|
1451
1481
|
ruleId: rule.id,
|
|
1482
|
+
name: rule.name,
|
|
1483
|
+
redactSensitiveInLogs,
|
|
1452
1484
|
matcher,
|
|
1453
1485
|
requestBody: rule.requestBody ?? { mode: "replace", body: "" }
|
|
1454
1486
|
};
|
|
@@ -1458,6 +1490,8 @@ function compileOperations(project) {
|
|
|
1458
1490
|
kind: "matcher",
|
|
1459
1491
|
groupId: group.id,
|
|
1460
1492
|
ruleId: rule.id,
|
|
1493
|
+
name: rule.name,
|
|
1494
|
+
redactSensitiveInLogs,
|
|
1461
1495
|
matcher
|
|
1462
1496
|
};
|
|
1463
1497
|
operations.push(operation);
|
|
@@ -21209,15 +21243,21 @@ function freezeMatcher(operation) {
|
|
|
21209
21243
|
kind: "matcher",
|
|
21210
21244
|
groupId: operation.groupId,
|
|
21211
21245
|
ruleId: operation.ruleId,
|
|
21246
|
+
name: operation.name,
|
|
21247
|
+
redactSensitiveInLogs: operation.redactSensitiveInLogs,
|
|
21212
21248
|
matcher
|
|
21213
21249
|
});
|
|
21214
21250
|
}
|
|
21251
|
+
function resolveMatcherName(ruleId, value) {
|
|
21252
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
21253
|
+
return ruleId;
|
|
21254
|
+
}
|
|
21215
21255
|
function normalizeMatcher(value) {
|
|
21216
21256
|
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
21217
21257
|
return null;
|
|
21218
21258
|
const requiredKeys = ["kind", "groupId", "ruleId", "matcher"];
|
|
21219
21259
|
if (!requiredKeys.every((key) => hasOwn(value, key)) || Object.keys(value).some(
|
|
21220
|
-
(key) => key !== "kind" && key !== "groupId" && key !== "ruleId" && key !== "matcher" && key !== "action"
|
|
21260
|
+
(key) => key !== "kind" && key !== "groupId" && key !== "ruleId" && key !== "name" && key !== "matcher" && key !== "action" && key !== "redactSensitiveInLogs"
|
|
21221
21261
|
))
|
|
21222
21262
|
return null;
|
|
21223
21263
|
const record = value;
|
|
@@ -21272,10 +21312,16 @@ function normalizeMatcher(value) {
|
|
|
21272
21312
|
if (!validMethod2(matcher.method)) return null;
|
|
21273
21313
|
method = matcher.method;
|
|
21274
21314
|
}
|
|
21315
|
+
const redactValue = record.redactSensitiveInLogs;
|
|
21316
|
+
if (redactValue !== void 0 && typeof redactValue !== "boolean")
|
|
21317
|
+
return null;
|
|
21318
|
+
const redactSensitiveInLogs = redactValue === true;
|
|
21275
21319
|
return freezeMatcher({
|
|
21276
21320
|
kind: "matcher",
|
|
21277
21321
|
groupId: record.groupId,
|
|
21278
21322
|
ruleId: record.ruleId,
|
|
21323
|
+
name: resolveMatcherName(record.ruleId, record.name),
|
|
21324
|
+
redactSensitiveInLogs,
|
|
21279
21325
|
matcher: {
|
|
21280
21326
|
urlRegex: { source: regex.source, flags: "" },
|
|
21281
21327
|
origins,
|
|
@@ -21561,28 +21607,13 @@ function createNativeRuntimeController(options) {
|
|
|
21561
21607
|
};
|
|
21562
21608
|
}
|
|
21563
21609
|
const matcherOps = [];
|
|
21564
|
-
const mockConfigs = [];
|
|
21565
21610
|
for (const op of compileResult.operations) {
|
|
21566
|
-
if (op.kind === "mock") {
|
|
21567
|
-
const mock = op.mock;
|
|
21568
|
-
let file;
|
|
21569
|
-
if (mock.file !== void 0) {
|
|
21570
|
-
file = mock.file;
|
|
21571
|
-
}
|
|
21572
|
-
mockConfigs.push({
|
|
21573
|
-
ruleId: op.ruleId,
|
|
21574
|
-
status: mock.status,
|
|
21575
|
-
...mock.headers !== void 0 ? { headers: mock.headers } : {},
|
|
21576
|
-
...mock.delayMs !== void 0 ? { delayMs: mock.delayMs } : {},
|
|
21577
|
-
...mock.body !== void 0 ? { body: mock.body } : {},
|
|
21578
|
-
...file !== void 0 ? { file } : {}
|
|
21579
|
-
});
|
|
21580
|
-
}
|
|
21581
21611
|
if ("matcher" in op) {
|
|
21582
21612
|
matcherOps.push({
|
|
21583
21613
|
kind: "matcher",
|
|
21584
21614
|
groupId: op.groupId,
|
|
21585
21615
|
ruleId: op.ruleId,
|
|
21616
|
+
redactSensitiveInLogs: op.redactSensitiveInLogs,
|
|
21586
21617
|
matcher: op.matcher
|
|
21587
21618
|
});
|
|
21588
21619
|
}
|
|
@@ -21591,14 +21622,11 @@ function createNativeRuntimeController(options) {
|
|
|
21591
21622
|
version: 1,
|
|
21592
21623
|
limits: RUNTIME_LIMITS,
|
|
21593
21624
|
matchers: matcherOps,
|
|
21594
|
-
grants: []
|
|
21595
|
-
...mockConfigs.length > 0 ? { mocks: mockConfigs } : {}
|
|
21625
|
+
grants: []
|
|
21596
21626
|
};
|
|
21597
21627
|
console.error(
|
|
21598
21628
|
"[rogatio-host] normalizeRuntimePreset input: matchers=",
|
|
21599
21629
|
matcherOps.length,
|
|
21600
|
-
"mocks=",
|
|
21601
|
-
mockConfigs.length,
|
|
21602
21630
|
"grants=0"
|
|
21603
21631
|
);
|
|
21604
21632
|
const normalized = normalizeRuntimePreset(presetInput);
|
|
@@ -22878,7 +22906,7 @@ Start/Stop controls, not the CLI. Run 'rogatio runtime install --extension-id
|
|
|
22878
22906
|
|
|
22879
22907
|
Options:
|
|
22880
22908
|
--extension-id Extension ID for native messaging manifest (required for install)
|
|
22881
|
-
--root <dir> Root for confined file
|
|
22909
|
+
--root <dir> Root for confined runtime file access (default: project directory)
|
|
22882
22910
|
--help, -h Show this help
|
|
22883
22911
|
|
|
22884
22912
|
Exit codes:
|
|
@@ -23506,36 +23534,6 @@ function dryRunProject(operations, cases, options) {
|
|
|
23506
23534
|
};
|
|
23507
23535
|
}
|
|
23508
23536
|
|
|
23509
|
-
// packages/cli/src/utils/mock-preview.ts
|
|
23510
|
-
import { basename as basename2 } from "node:path";
|
|
23511
|
-
function createMockPreviewAction(operations) {
|
|
23512
|
-
const mockByRuleId = /* @__PURE__ */ new Map();
|
|
23513
|
-
for (const operation of operations) {
|
|
23514
|
-
if (operation.kind === "mock") {
|
|
23515
|
-
mockByRuleId.set(operation.ruleId, operation);
|
|
23516
|
-
}
|
|
23517
|
-
}
|
|
23518
|
-
return (operation, _url, _testCase) => {
|
|
23519
|
-
const mock = mockByRuleId.get(operation.ruleId);
|
|
23520
|
-
if (mock === void 0) return null;
|
|
23521
|
-
if (mock.mock.body !== void 0) {
|
|
23522
|
-
return {
|
|
23523
|
-
kind: "mock",
|
|
23524
|
-
summary: `Mock ${mock.mock.status} (inline body, ${Buffer.byteLength(
|
|
23525
|
-
mock.mock.body,
|
|
23526
|
-
"utf8"
|
|
23527
|
-
)} bytes)`
|
|
23528
|
-
};
|
|
23529
|
-
}
|
|
23530
|
-
return {
|
|
23531
|
-
kind: "mock",
|
|
23532
|
-
summary: `Mock ${mock.mock.status} (file snapshot: ${basename2(
|
|
23533
|
-
mock.mock.file ?? ""
|
|
23534
|
-
)})`
|
|
23535
|
-
};
|
|
23536
|
-
};
|
|
23537
|
-
}
|
|
23538
|
-
|
|
23539
23537
|
// packages/cli/src/server/routes.ts
|
|
23540
23538
|
function generateCsrfToken() {
|
|
23541
23539
|
return randomBytes3(16).toString("hex");
|
|
@@ -23606,12 +23604,16 @@ function bodyErrorResponse(error) {
|
|
|
23606
23604
|
};
|
|
23607
23605
|
}
|
|
23608
23606
|
function toMatcherOperations(operations) {
|
|
23609
|
-
return operations.map(
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
|
|
23614
|
-
|
|
23607
|
+
return operations.map(
|
|
23608
|
+
({ groupId, ruleId, name, matcher, redactSensitiveInLogs }) => ({
|
|
23609
|
+
kind: "matcher",
|
|
23610
|
+
groupId,
|
|
23611
|
+
ruleId,
|
|
23612
|
+
name,
|
|
23613
|
+
matcher,
|
|
23614
|
+
redactSensitiveInLogs
|
|
23615
|
+
})
|
|
23616
|
+
);
|
|
23615
23617
|
}
|
|
23616
23618
|
function isRecord(value) {
|
|
23617
23619
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -23909,10 +23911,7 @@ function createRoutes(context) {
|
|
|
23909
23911
|
const result = dryRunProject(
|
|
23910
23912
|
toMatcherOperations(compileResult.operations),
|
|
23911
23913
|
body.cases,
|
|
23912
|
-
{
|
|
23913
|
-
...body.options ?? {},
|
|
23914
|
-
previewAction: createMockPreviewAction(compileResult.operations)
|
|
23915
|
-
}
|
|
23914
|
+
body.options ?? {}
|
|
23916
23915
|
);
|
|
23917
23916
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
23918
23917
|
res.end(JSON.stringify(result));
|
|
@@ -24143,7 +24142,7 @@ import {
|
|
|
24143
24142
|
unlink as unlink2,
|
|
24144
24143
|
writeFile as writeFile3
|
|
24145
24144
|
} from "node:fs/promises";
|
|
24146
|
-
import { basename as
|
|
24145
|
+
import { basename as basename2, dirname as dirname6, join as join5 } from "node:path";
|
|
24147
24146
|
var ProjectStorageError = class extends Error {
|
|
24148
24147
|
code;
|
|
24149
24148
|
id;
|
|
@@ -24241,7 +24240,7 @@ async function isDirectoryPath(id2) {
|
|
|
24241
24240
|
}
|
|
24242
24241
|
}
|
|
24243
24242
|
async function writeDocument(id2, data) {
|
|
24244
|
-
const tempName = `.${
|
|
24243
|
+
const tempName = `.${basename2(dirname6(id2))}.${randomBytes4(8).toString("hex")}.tmp`;
|
|
24245
24244
|
const tempPath = join5(dirname6(id2), tempName);
|
|
24246
24245
|
try {
|
|
24247
24246
|
if (await isDirectoryPath(id2)) {
|
|
@@ -24629,7 +24628,7 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
24629
24628
|
{ "imports": { "@rogatio/editor": "/vendor/editor.js" } }
|
|
24630
24629
|
</script>
|
|
24631
24630
|
<script type="module">
|
|
24632
|
-
import { createEditor
|
|
24631
|
+
import { createEditor } from '@rogatio/editor';
|
|
24633
24632
|
|
|
24634
24633
|
const root = document.getElementById('editor-root');
|
|
24635
24634
|
const apiBase = '${apiBase}';
|
|
@@ -24678,8 +24677,8 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
24678
24677
|
|
|
24679
24678
|
const project = await fetchProject();
|
|
24680
24679
|
|
|
24681
|
-
const editor = createEditor(
|
|
24682
|
-
|
|
24680
|
+
const editor = createEditor({
|
|
24681
|
+
root,
|
|
24683
24682
|
initialProject: project,
|
|
24684
24683
|
validate: async (value) => {
|
|
24685
24684
|
const result = await validateProject(value);
|
|
@@ -24720,49 +24719,18 @@ function generateEditorHtml(apiBase, csrfToken, filePath, aiConfigured) {
|
|
|
24720
24719
|
|
|
24721
24720
|
// packages/cli/src/commands/runtime.ts
|
|
24722
24721
|
import { chmod, mkdir as mkdir4, rm as rm2, writeFile as writeFile4 } from "node:fs/promises";
|
|
24723
|
-
import { dirname as dirname7,
|
|
24722
|
+
import { dirname as dirname7, join as join6, resolve as resolve5 } from "node:path";
|
|
24724
24723
|
function toMatcherOperations2(operations) {
|
|
24725
|
-
return operations.map(
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
24729
|
-
|
|
24730
|
-
|
|
24731
|
-
|
|
24732
|
-
|
|
24733
|
-
|
|
24734
|
-
|
|
24735
|
-
const rel = relative(root, absolute);
|
|
24736
|
-
if (rel.startsWith("..") || isAbsolute(rel)) return null;
|
|
24737
|
-
const logical = rel.split(sep2).join("/");
|
|
24738
|
-
return logical.length === 0 ? null : logical;
|
|
24739
|
-
}
|
|
24740
|
-
function buildMockConfigs(operations, root) {
|
|
24741
|
-
const configs = [];
|
|
24742
|
-
for (const operation of operations) {
|
|
24743
|
-
if (operation.kind !== "mock") continue;
|
|
24744
|
-
const mock = operation.mock;
|
|
24745
|
-
let file;
|
|
24746
|
-
if (mock.file !== void 0) {
|
|
24747
|
-
const resolved = resolveMockFile(root, mock.file);
|
|
24748
|
-
if (resolved === null) {
|
|
24749
|
-
return {
|
|
24750
|
-
ok: false,
|
|
24751
|
-
message: `Mock rule "${operation.ruleId}" file "${mock.file}" resolves outside the configured root (${root}).`
|
|
24752
|
-
};
|
|
24753
|
-
}
|
|
24754
|
-
file = resolved;
|
|
24755
|
-
}
|
|
24756
|
-
configs.push({
|
|
24757
|
-
ruleId: operation.ruleId,
|
|
24758
|
-
status: mock.status,
|
|
24759
|
-
...mock.headers !== void 0 ? { headers: mock.headers } : {},
|
|
24760
|
-
...mock.delayMs !== void 0 ? { delayMs: mock.delayMs } : {},
|
|
24761
|
-
...mock.body !== void 0 ? { body: mock.body } : {},
|
|
24762
|
-
...file !== void 0 ? { file } : {}
|
|
24763
|
-
});
|
|
24764
|
-
}
|
|
24765
|
-
return { ok: true, value: configs };
|
|
24724
|
+
return operations.map(
|
|
24725
|
+
({ groupId, ruleId, name, matcher, redactSensitiveInLogs }) => ({
|
|
24726
|
+
kind: "matcher",
|
|
24727
|
+
groupId,
|
|
24728
|
+
ruleId,
|
|
24729
|
+
name,
|
|
24730
|
+
matcher,
|
|
24731
|
+
redactSensitiveInLogs
|
|
24732
|
+
})
|
|
24733
|
+
);
|
|
24766
24734
|
}
|
|
24767
24735
|
function generateHostWrapper(rogatioCommand, logPath) {
|
|
24768
24736
|
const parts = rogatioCommand.split(" ");
|
|
@@ -25016,17 +24984,11 @@ async function runtimeHostCommand(args, options = {}) {
|
|
|
25016
24984
|
return 1;
|
|
25017
24985
|
}
|
|
25018
24986
|
const rootDir = root ?? (inputPath === "-" ? process.cwd() : dirname7(filePath));
|
|
25019
|
-
const mocksResult = buildMockConfigs(compileResult.operations, rootDir);
|
|
25020
|
-
if (!mocksResult.ok) {
|
|
25021
|
-
console.error(`Error: ${mocksResult.message}`);
|
|
25022
|
-
return 1;
|
|
25023
|
-
}
|
|
25024
24987
|
const normalized = normalizeRuntimePreset({
|
|
25025
24988
|
version: 1,
|
|
25026
24989
|
limits: RUNTIME_LIMITS,
|
|
25027
24990
|
matchers: toMatcherOperations2(compileResult.operations),
|
|
25028
|
-
grants: []
|
|
25029
|
-
...mocksResult.value.length > 0 ? { mocks: mocksResult.value } : {}
|
|
24991
|
+
grants: []
|
|
25030
24992
|
});
|
|
25031
24993
|
if (!normalized.ok) {
|
|
25032
24994
|
console.error("Error: Failed to build runtime preset");
|
|
@@ -25070,12 +25032,16 @@ function usageError(message) {
|
|
|
25070
25032
|
`;
|
|
25071
25033
|
}
|
|
25072
25034
|
function toMatcherOperations3(operations) {
|
|
25073
|
-
return operations.map(
|
|
25074
|
-
|
|
25075
|
-
|
|
25076
|
-
|
|
25077
|
-
|
|
25078
|
-
|
|
25035
|
+
return operations.map(
|
|
25036
|
+
({ groupId, ruleId, name, matcher, redactSensitiveInLogs }) => ({
|
|
25037
|
+
kind: "matcher",
|
|
25038
|
+
groupId,
|
|
25039
|
+
ruleId,
|
|
25040
|
+
name,
|
|
25041
|
+
matcher,
|
|
25042
|
+
redactSensitiveInLogs
|
|
25043
|
+
})
|
|
25044
|
+
);
|
|
25079
25045
|
}
|
|
25080
25046
|
function isUrl(value) {
|
|
25081
25047
|
return parseTestUrl(value).ok;
|
|
@@ -25130,10 +25096,9 @@ function addDefaults(cases, defaultMethod, defaultResourceType) {
|
|
|
25130
25096
|
(raw) => applyDefaults(raw, defaultMethod, defaultResourceType)
|
|
25131
25097
|
);
|
|
25132
25098
|
}
|
|
25133
|
-
function resultOptions(maxCases
|
|
25099
|
+
function resultOptions(maxCases) {
|
|
25134
25100
|
const options = {};
|
|
25135
25101
|
if (maxCases !== void 0) options.maxCases = maxCases;
|
|
25136
|
-
options.previewAction = createMockPreviewAction(operations);
|
|
25137
25102
|
return options;
|
|
25138
25103
|
}
|
|
25139
25104
|
function diagnosticsFromSchema(projectData) {
|
|
@@ -25330,7 +25295,7 @@ async function testCommandImpl(args, stdinInput, captureOutput, options = {}) {
|
|
|
25330
25295
|
const dryRunResult = dryRunProject(
|
|
25331
25296
|
toMatcherOperations3(compileResult.operations),
|
|
25332
25297
|
testCases,
|
|
25333
|
-
resultOptions(maxCases
|
|
25298
|
+
resultOptions(maxCases)
|
|
25334
25299
|
);
|
|
25335
25300
|
if (jsonMode) {
|
|
25336
25301
|
const output = jsonOutput(dryRunResult);
|
|
@@ -25600,7 +25565,7 @@ Run 'rogatio <command> --help' for command-specific help.`);
|
|
|
25600
25565
|
return 0;
|
|
25601
25566
|
}
|
|
25602
25567
|
if (process.argv[1] !== void 0 && realpathSync.native(fileURLToPath2(import.meta.url)) === realpathSync.native(resolve8(process.argv[1]))) {
|
|
25603
|
-
if (
|
|
25568
|
+
if (basename3(process.argv[1]) === "runtime-host") {
|
|
25604
25569
|
runRuntimeHostEntry().catch((err) => {
|
|
25605
25570
|
console.error(err);
|
|
25606
25571
|
process.exit(1);
|