@postman-cse/onboarding-bootstrap 2.1.2 → 2.3.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 +15 -1
- package/dist/action.cjs +934 -140
- package/dist/cli.cjs +952 -158
- package/dist/index.cjs +934 -140
- package/package.json +6 -5
package/dist/action.cjs
CHANGED
|
@@ -55569,7 +55569,7 @@ var require_lodash = __commonJS({
|
|
|
55569
55569
|
}
|
|
55570
55570
|
return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped, undefined2, comparator) : [];
|
|
55571
55571
|
});
|
|
55572
|
-
function
|
|
55572
|
+
function join4(array, separator) {
|
|
55573
55573
|
return array == null ? "" : nativeJoin.call(array, separator);
|
|
55574
55574
|
}
|
|
55575
55575
|
function last(array) {
|
|
@@ -57488,7 +57488,7 @@ var require_lodash = __commonJS({
|
|
|
57488
57488
|
lodash.isUndefined = isUndefined;
|
|
57489
57489
|
lodash.isWeakMap = isWeakMap;
|
|
57490
57490
|
lodash.isWeakSet = isWeakSet;
|
|
57491
|
-
lodash.join =
|
|
57491
|
+
lodash.join = join4;
|
|
57492
57492
|
lodash.kebabCase = kebabCase;
|
|
57493
57493
|
lodash.last = last;
|
|
57494
57494
|
lodash.lastIndexOf = lastIndexOf;
|
|
@@ -127435,16 +127435,16 @@ var require_printer = __commonJS({
|
|
|
127435
127435
|
},
|
|
127436
127436
|
// Document
|
|
127437
127437
|
Document: {
|
|
127438
|
-
leave: (node) =>
|
|
127438
|
+
leave: (node) => join4(node.definitions, "\n\n")
|
|
127439
127439
|
},
|
|
127440
127440
|
OperationDefinition: {
|
|
127441
127441
|
leave(node) {
|
|
127442
|
-
const varDefs = hasMultilineItems(node.variableDefinitions) ? wrap("(\n",
|
|
127443
|
-
const prefix = wrap("", node.description, "\n") +
|
|
127442
|
+
const varDefs = hasMultilineItems(node.variableDefinitions) ? wrap("(\n", join4(node.variableDefinitions, "\n"), "\n)") : wrap("(", join4(node.variableDefinitions, ", "), ")");
|
|
127443
|
+
const prefix = wrap("", node.description, "\n") + join4(
|
|
127444
127444
|
[
|
|
127445
127445
|
node.operation,
|
|
127446
|
-
|
|
127447
|
-
|
|
127446
|
+
join4([node.name, varDefs]),
|
|
127447
|
+
join4(node.directives, " ")
|
|
127448
127448
|
],
|
|
127449
127449
|
" "
|
|
127450
127450
|
);
|
|
@@ -127452,7 +127452,7 @@ var require_printer = __commonJS({
|
|
|
127452
127452
|
}
|
|
127453
127453
|
},
|
|
127454
127454
|
VariableDefinition: {
|
|
127455
|
-
leave: ({ variable, type, defaultValue, directives, description }) => wrap("", description, "\n") + variable + ": " + type + wrap(" = ", defaultValue) + wrap(" ",
|
|
127455
|
+
leave: ({ variable, type, defaultValue, directives, description }) => wrap("", description, "\n") + variable + ": " + type + wrap(" = ", defaultValue) + wrap(" ", join4(directives, " "))
|
|
127456
127456
|
},
|
|
127457
127457
|
SelectionSet: {
|
|
127458
127458
|
leave: ({ selections }) => block(selections)
|
|
@@ -127460,11 +127460,11 @@ var require_printer = __commonJS({
|
|
|
127460
127460
|
Field: {
|
|
127461
127461
|
leave({ alias, name, arguments: args, directives, selectionSet }) {
|
|
127462
127462
|
const prefix = wrap("", alias, ": ") + name;
|
|
127463
|
-
let argsLine = prefix + wrap("(",
|
|
127463
|
+
let argsLine = prefix + wrap("(", join4(args, ", "), ")");
|
|
127464
127464
|
if (argsLine.length > MAX_LINE_LENGTH) {
|
|
127465
|
-
argsLine = prefix + wrap("(\n", indent2(
|
|
127465
|
+
argsLine = prefix + wrap("(\n", indent2(join4(args, "\n")), "\n)");
|
|
127466
127466
|
}
|
|
127467
|
-
return
|
|
127467
|
+
return join4([argsLine, join4(directives, " "), selectionSet], " ");
|
|
127468
127468
|
}
|
|
127469
127469
|
},
|
|
127470
127470
|
Argument: {
|
|
@@ -127472,14 +127472,14 @@ var require_printer = __commonJS({
|
|
|
127472
127472
|
},
|
|
127473
127473
|
// Fragments
|
|
127474
127474
|
FragmentSpread: {
|
|
127475
|
-
leave: ({ name, directives }) => "..." + name + wrap(" ",
|
|
127475
|
+
leave: ({ name, directives }) => "..." + name + wrap(" ", join4(directives, " "))
|
|
127476
127476
|
},
|
|
127477
127477
|
InlineFragment: {
|
|
127478
|
-
leave: ({ typeCondition, directives, selectionSet }) =>
|
|
127478
|
+
leave: ({ typeCondition, directives, selectionSet }) => join4(
|
|
127479
127479
|
[
|
|
127480
127480
|
"...",
|
|
127481
127481
|
wrap("on ", typeCondition),
|
|
127482
|
-
|
|
127482
|
+
join4(directives, " "),
|
|
127483
127483
|
selectionSet
|
|
127484
127484
|
],
|
|
127485
127485
|
" "
|
|
@@ -127495,7 +127495,7 @@ var require_printer = __commonJS({
|
|
|
127495
127495
|
description
|
|
127496
127496
|
}) => wrap("", description, "\n") + // Note: fragment variable definitions are experimental and may be changed
|
|
127497
127497
|
// or removed in the future.
|
|
127498
|
-
`fragment ${name}${wrap("(",
|
|
127498
|
+
`fragment ${name}${wrap("(", join4(variableDefinitions, ", "), ")")} on ${typeCondition} ${wrap("", join4(directives, " "), " ")}` + selectionSet
|
|
127499
127499
|
},
|
|
127500
127500
|
// Value
|
|
127501
127501
|
IntValue: {
|
|
@@ -127517,17 +127517,17 @@ var require_printer = __commonJS({
|
|
|
127517
127517
|
leave: ({ value }) => value
|
|
127518
127518
|
},
|
|
127519
127519
|
ListValue: {
|
|
127520
|
-
leave: ({ values }) => "[" +
|
|
127520
|
+
leave: ({ values }) => "[" + join4(values, ", ") + "]"
|
|
127521
127521
|
},
|
|
127522
127522
|
ObjectValue: {
|
|
127523
|
-
leave: ({ fields }) => "{" +
|
|
127523
|
+
leave: ({ fields }) => "{" + join4(fields, ", ") + "}"
|
|
127524
127524
|
},
|
|
127525
127525
|
ObjectField: {
|
|
127526
127526
|
leave: ({ name, value }) => name + ": " + value
|
|
127527
127527
|
},
|
|
127528
127528
|
// Directive
|
|
127529
127529
|
Directive: {
|
|
127530
|
-
leave: ({ name, arguments: args }) => "@" + name + wrap("(",
|
|
127530
|
+
leave: ({ name, arguments: args }) => "@" + name + wrap("(", join4(args, ", "), ")")
|
|
127531
127531
|
},
|
|
127532
127532
|
// Type
|
|
127533
127533
|
NamedType: {
|
|
@@ -127541,61 +127541,61 @@ var require_printer = __commonJS({
|
|
|
127541
127541
|
},
|
|
127542
127542
|
// Type System Definitions
|
|
127543
127543
|
SchemaDefinition: {
|
|
127544
|
-
leave: ({ description, directives, operationTypes }) => wrap("", description, "\n") +
|
|
127544
|
+
leave: ({ description, directives, operationTypes }) => wrap("", description, "\n") + join4(["schema", join4(directives, " "), block(operationTypes)], " ")
|
|
127545
127545
|
},
|
|
127546
127546
|
OperationTypeDefinition: {
|
|
127547
127547
|
leave: ({ operation, type }) => operation + ": " + type
|
|
127548
127548
|
},
|
|
127549
127549
|
ScalarTypeDefinition: {
|
|
127550
|
-
leave: ({ description, name, directives }) => wrap("", description, "\n") +
|
|
127550
|
+
leave: ({ description, name, directives }) => wrap("", description, "\n") + join4(["scalar", name, join4(directives, " ")], " ")
|
|
127551
127551
|
},
|
|
127552
127552
|
ObjectTypeDefinition: {
|
|
127553
|
-
leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") +
|
|
127553
|
+
leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") + join4(
|
|
127554
127554
|
[
|
|
127555
127555
|
"type",
|
|
127556
127556
|
name,
|
|
127557
|
-
wrap("implements ",
|
|
127558
|
-
|
|
127557
|
+
wrap("implements ", join4(interfaces, " & ")),
|
|
127558
|
+
join4(directives, " "),
|
|
127559
127559
|
block(fields)
|
|
127560
127560
|
],
|
|
127561
127561
|
" "
|
|
127562
127562
|
)
|
|
127563
127563
|
},
|
|
127564
127564
|
FieldDefinition: {
|
|
127565
|
-
leave: ({ description, name, arguments: args, type, directives }) => wrap("", description, "\n") + name + (hasMultilineItems(args) ? wrap("(\n", indent2(
|
|
127565
|
+
leave: ({ description, name, arguments: args, type, directives }) => wrap("", description, "\n") + name + (hasMultilineItems(args) ? wrap("(\n", indent2(join4(args, "\n")), "\n)") : wrap("(", join4(args, ", "), ")")) + ": " + type + wrap(" ", join4(directives, " "))
|
|
127566
127566
|
},
|
|
127567
127567
|
InputValueDefinition: {
|
|
127568
|
-
leave: ({ description, name, type, defaultValue, directives }) => wrap("", description, "\n") +
|
|
127569
|
-
[name + ": " + type, wrap("= ", defaultValue),
|
|
127568
|
+
leave: ({ description, name, type, defaultValue, directives }) => wrap("", description, "\n") + join4(
|
|
127569
|
+
[name + ": " + type, wrap("= ", defaultValue), join4(directives, " ")],
|
|
127570
127570
|
" "
|
|
127571
127571
|
)
|
|
127572
127572
|
},
|
|
127573
127573
|
InterfaceTypeDefinition: {
|
|
127574
|
-
leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") +
|
|
127574
|
+
leave: ({ description, name, interfaces, directives, fields }) => wrap("", description, "\n") + join4(
|
|
127575
127575
|
[
|
|
127576
127576
|
"interface",
|
|
127577
127577
|
name,
|
|
127578
|
-
wrap("implements ",
|
|
127579
|
-
|
|
127578
|
+
wrap("implements ", join4(interfaces, " & ")),
|
|
127579
|
+
join4(directives, " "),
|
|
127580
127580
|
block(fields)
|
|
127581
127581
|
],
|
|
127582
127582
|
" "
|
|
127583
127583
|
)
|
|
127584
127584
|
},
|
|
127585
127585
|
UnionTypeDefinition: {
|
|
127586
|
-
leave: ({ description, name, directives, types: types2 }) => wrap("", description, "\n") +
|
|
127587
|
-
["union", name,
|
|
127586
|
+
leave: ({ description, name, directives, types: types2 }) => wrap("", description, "\n") + join4(
|
|
127587
|
+
["union", name, join4(directives, " "), wrap("= ", join4(types2, " | "))],
|
|
127588
127588
|
" "
|
|
127589
127589
|
)
|
|
127590
127590
|
},
|
|
127591
127591
|
EnumTypeDefinition: {
|
|
127592
|
-
leave: ({ description, name, directives, values }) => wrap("", description, "\n") +
|
|
127592
|
+
leave: ({ description, name, directives, values }) => wrap("", description, "\n") + join4(["enum", name, join4(directives, " "), block(values)], " ")
|
|
127593
127593
|
},
|
|
127594
127594
|
EnumValueDefinition: {
|
|
127595
|
-
leave: ({ description, name, directives }) => wrap("", description, "\n") +
|
|
127595
|
+
leave: ({ description, name, directives }) => wrap("", description, "\n") + join4([name, join4(directives, " ")], " ")
|
|
127596
127596
|
},
|
|
127597
127597
|
InputObjectTypeDefinition: {
|
|
127598
|
-
leave: ({ description, name, directives, fields }) => wrap("", description, "\n") +
|
|
127598
|
+
leave: ({ description, name, directives, fields }) => wrap("", description, "\n") + join4(["input", name, join4(directives, " "), block(fields)], " ")
|
|
127599
127599
|
},
|
|
127600
127600
|
DirectiveDefinition: {
|
|
127601
127601
|
leave: ({
|
|
@@ -127605,84 +127605,84 @@ var require_printer = __commonJS({
|
|
|
127605
127605
|
directives,
|
|
127606
127606
|
repeatable,
|
|
127607
127607
|
locations
|
|
127608
|
-
}) => wrap("", description, "\n") + "directive @" + name + (hasMultilineItems(args) ? wrap("(\n", indent2(
|
|
127608
|
+
}) => wrap("", description, "\n") + "directive @" + name + (hasMultilineItems(args) ? wrap("(\n", indent2(join4(args, "\n")), "\n)") : wrap("(", join4(args, ", "), ")")) + wrap(" ", join4(directives, " ")) + (repeatable ? " repeatable" : "") + " on " + join4(locations, " | ")
|
|
127609
127609
|
},
|
|
127610
127610
|
SchemaExtension: {
|
|
127611
|
-
leave: ({ directives, operationTypes }) =>
|
|
127612
|
-
["extend schema",
|
|
127611
|
+
leave: ({ directives, operationTypes }) => join4(
|
|
127612
|
+
["extend schema", join4(directives, " "), block(operationTypes)],
|
|
127613
127613
|
" "
|
|
127614
127614
|
)
|
|
127615
127615
|
},
|
|
127616
127616
|
ScalarTypeExtension: {
|
|
127617
|
-
leave: ({ name, directives }) =>
|
|
127617
|
+
leave: ({ name, directives }) => join4(["extend scalar", name, join4(directives, " ")], " ")
|
|
127618
127618
|
},
|
|
127619
127619
|
ObjectTypeExtension: {
|
|
127620
|
-
leave: ({ name, interfaces, directives, fields }) =>
|
|
127620
|
+
leave: ({ name, interfaces, directives, fields }) => join4(
|
|
127621
127621
|
[
|
|
127622
127622
|
"extend type",
|
|
127623
127623
|
name,
|
|
127624
|
-
wrap("implements ",
|
|
127625
|
-
|
|
127624
|
+
wrap("implements ", join4(interfaces, " & ")),
|
|
127625
|
+
join4(directives, " "),
|
|
127626
127626
|
block(fields)
|
|
127627
127627
|
],
|
|
127628
127628
|
" "
|
|
127629
127629
|
)
|
|
127630
127630
|
},
|
|
127631
127631
|
InterfaceTypeExtension: {
|
|
127632
|
-
leave: ({ name, interfaces, directives, fields }) =>
|
|
127632
|
+
leave: ({ name, interfaces, directives, fields }) => join4(
|
|
127633
127633
|
[
|
|
127634
127634
|
"extend interface",
|
|
127635
127635
|
name,
|
|
127636
|
-
wrap("implements ",
|
|
127637
|
-
|
|
127636
|
+
wrap("implements ", join4(interfaces, " & ")),
|
|
127637
|
+
join4(directives, " "),
|
|
127638
127638
|
block(fields)
|
|
127639
127639
|
],
|
|
127640
127640
|
" "
|
|
127641
127641
|
)
|
|
127642
127642
|
},
|
|
127643
127643
|
UnionTypeExtension: {
|
|
127644
|
-
leave: ({ name, directives, types: types2 }) =>
|
|
127644
|
+
leave: ({ name, directives, types: types2 }) => join4(
|
|
127645
127645
|
[
|
|
127646
127646
|
"extend union",
|
|
127647
127647
|
name,
|
|
127648
|
-
|
|
127649
|
-
wrap("= ",
|
|
127648
|
+
join4(directives, " "),
|
|
127649
|
+
wrap("= ", join4(types2, " | "))
|
|
127650
127650
|
],
|
|
127651
127651
|
" "
|
|
127652
127652
|
)
|
|
127653
127653
|
},
|
|
127654
127654
|
EnumTypeExtension: {
|
|
127655
|
-
leave: ({ name, directives, values }) =>
|
|
127655
|
+
leave: ({ name, directives, values }) => join4(["extend enum", name, join4(directives, " "), block(values)], " ")
|
|
127656
127656
|
},
|
|
127657
127657
|
InputObjectTypeExtension: {
|
|
127658
|
-
leave: ({ name, directives, fields }) =>
|
|
127658
|
+
leave: ({ name, directives, fields }) => join4(["extend input", name, join4(directives, " "), block(fields)], " ")
|
|
127659
127659
|
},
|
|
127660
127660
|
DirectiveExtension: {
|
|
127661
|
-
leave: ({ name, directives }) =>
|
|
127661
|
+
leave: ({ name, directives }) => join4(["extend directive @" + name, join4(directives, " ")], " ")
|
|
127662
127662
|
},
|
|
127663
127663
|
// Schema Coordinates
|
|
127664
127664
|
TypeCoordinate: {
|
|
127665
127665
|
leave: ({ name }) => name
|
|
127666
127666
|
},
|
|
127667
127667
|
MemberCoordinate: {
|
|
127668
|
-
leave: ({ name, memberName }) =>
|
|
127668
|
+
leave: ({ name, memberName }) => join4([name, wrap(".", memberName)])
|
|
127669
127669
|
},
|
|
127670
127670
|
ArgumentCoordinate: {
|
|
127671
|
-
leave: ({ name, fieldName, argumentName }) =>
|
|
127671
|
+
leave: ({ name, fieldName, argumentName }) => join4([name, wrap(".", fieldName), wrap("(", argumentName, ":)")])
|
|
127672
127672
|
},
|
|
127673
127673
|
DirectiveCoordinate: {
|
|
127674
|
-
leave: ({ name }) =>
|
|
127674
|
+
leave: ({ name }) => join4(["@", name])
|
|
127675
127675
|
},
|
|
127676
127676
|
DirectiveArgumentCoordinate: {
|
|
127677
|
-
leave: ({ name, argumentName }) =>
|
|
127677
|
+
leave: ({ name, argumentName }) => join4(["@", name, wrap("(", argumentName, ":)")])
|
|
127678
127678
|
}
|
|
127679
127679
|
};
|
|
127680
|
-
function
|
|
127680
|
+
function join4(maybeArray, separator = "") {
|
|
127681
127681
|
var _maybeArray$filter$jo;
|
|
127682
127682
|
return (_maybeArray$filter$jo = maybeArray === null || maybeArray === void 0 ? void 0 : maybeArray.filter((x) => x).join(separator)) !== null && _maybeArray$filter$jo !== void 0 ? _maybeArray$filter$jo : "";
|
|
127683
127683
|
}
|
|
127684
127684
|
function block(array) {
|
|
127685
|
-
return wrap("{\n", indent2(
|
|
127685
|
+
return wrap("{\n", indent2(join4(array, "\n")), "\n}");
|
|
127686
127686
|
}
|
|
127687
127687
|
function wrap(start, maybeString, end = "") {
|
|
127688
127688
|
return maybeString != null && maybeString !== "" ? start + maybeString + end : "";
|
|
@@ -152316,7 +152316,7 @@ var require_index_cjs = __commonJS({
|
|
|
152316
152316
|
const t = parse10(r);
|
|
152317
152317
|
return "http" === t.protocol || "https" === t.protocol;
|
|
152318
152318
|
}
|
|
152319
|
-
var
|
|
152319
|
+
var join4 = (...r) => {
|
|
152320
152320
|
if (0 === r.length) return ".";
|
|
152321
152321
|
const t = r.map(parse10), e = Object.assign({}, t[0]);
|
|
152322
152322
|
for (let n = 1; n < t.length; n++) {
|
|
@@ -152340,7 +152340,7 @@ var require_index_cjs = __commonJS({
|
|
|
152340
152340
|
function resolve5(...r) {
|
|
152341
152341
|
if (0 === r.length) return ".";
|
|
152342
152342
|
const t = normalizeParsed(parse10(r[r.length - 1]));
|
|
152343
|
-
return t.absolute ? format3(t) :
|
|
152343
|
+
return t.absolute ? format3(t) : join4(...r);
|
|
152344
152344
|
}
|
|
152345
152345
|
var startsWithWindowsDrive = (r) => {
|
|
152346
152346
|
return null !== parse10(r).drive;
|
|
@@ -152354,7 +152354,7 @@ var require_index_cjs = __commonJS({
|
|
|
152354
152354
|
function serializeSrn({ shortcode: r, orgSlug: t, projectSlug: e, uri: n = "" }) {
|
|
152355
152355
|
return [r, t, e, n.replace(/^\//, "")].filter(Boolean).join("/");
|
|
152356
152356
|
}
|
|
152357
|
-
exports2.basename = basename3, exports2.deserializeSrn = deserializeSrn, exports2.dirname = dirname3, exports2.extname = extname2, exports2.format = format3, exports2.isAbsolute = isAbsolute, exports2.isURL = isURL, exports2.join =
|
|
152357
|
+
exports2.basename = basename3, exports2.deserializeSrn = deserializeSrn, exports2.dirname = dirname3, exports2.extname = extname2, exports2.format = format3, exports2.isAbsolute = isAbsolute, exports2.isURL = isURL, exports2.join = join4, exports2.normalize = normalize3, exports2.parse = parse10, exports2.relative = relative2, exports2.resolve = resolve5, exports2.sep = "/", exports2.serializeSrn = serializeSrn, exports2.startsWithWindowsDrive = startsWithWindowsDrive, exports2.stripRoot = stripRoot, exports2.toFSPath = normalize3;
|
|
152358
152358
|
}
|
|
152359
152359
|
});
|
|
152360
152360
|
|
|
@@ -154097,7 +154097,7 @@ var require_stable = __commonJS({
|
|
|
154097
154097
|
return result;
|
|
154098
154098
|
}
|
|
154099
154099
|
function stringifyFullFn(key, parent, stack, replacer, indent2) {
|
|
154100
|
-
var i, res,
|
|
154100
|
+
var i, res, join4;
|
|
154101
154101
|
const originalIndentation = indentation;
|
|
154102
154102
|
var value = parent[key];
|
|
154103
154103
|
if (typeof value === "object" && value !== null && typeof value.toJSON === "function") {
|
|
@@ -154123,12 +154123,12 @@ var require_stable = __commonJS({
|
|
|
154123
154123
|
indentation += indent2;
|
|
154124
154124
|
res += `
|
|
154125
154125
|
${indentation}`;
|
|
154126
|
-
|
|
154126
|
+
join4 = `,
|
|
154127
154127
|
${indentation}`;
|
|
154128
154128
|
for (i = 0; i < value.length - 1; i++) {
|
|
154129
154129
|
const tmp2 = stringifyFullFn(i, value, stack, replacer, indent2);
|
|
154130
154130
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
154131
|
-
res +=
|
|
154131
|
+
res += join4;
|
|
154132
154132
|
}
|
|
154133
154133
|
const tmp = stringifyFullFn(i, value, stack, replacer, indent2);
|
|
154134
154134
|
res += tmp !== void 0 ? tmp : "null";
|
|
@@ -154150,7 +154150,7 @@ ${originalIndentation}`;
|
|
|
154150
154150
|
indentation += indent2;
|
|
154151
154151
|
res += `
|
|
154152
154152
|
${indentation}`;
|
|
154153
|
-
|
|
154153
|
+
join4 = `,
|
|
154154
154154
|
${indentation}`;
|
|
154155
154155
|
var separator = "";
|
|
154156
154156
|
for (i = 0; i < keys.length; i++) {
|
|
@@ -154158,7 +154158,7 @@ ${indentation}`;
|
|
|
154158
154158
|
const tmp = stringifyFullFn(key, value, stack, replacer, indent2);
|
|
154159
154159
|
if (tmp !== void 0) {
|
|
154160
154160
|
res += `${separator}"${strEscape(key)}": ${tmp}`;
|
|
154161
|
-
separator =
|
|
154161
|
+
separator = join4;
|
|
154162
154162
|
}
|
|
154163
154163
|
}
|
|
154164
154164
|
if (separator !== "") {
|
|
@@ -154180,7 +154180,7 @@ ${originalIndentation}`;
|
|
|
154180
154180
|
}
|
|
154181
154181
|
}
|
|
154182
154182
|
function stringifyFullArr(key, value, stack, replacer, indent2) {
|
|
154183
|
-
var i, res,
|
|
154183
|
+
var i, res, join4;
|
|
154184
154184
|
const originalIndentation = indentation;
|
|
154185
154185
|
if (typeof value === "object" && value !== null && typeof value.toJSON === "function") {
|
|
154186
154186
|
value = value.toJSON(key);
|
|
@@ -154204,12 +154204,12 @@ ${originalIndentation}`;
|
|
|
154204
154204
|
indentation += indent2;
|
|
154205
154205
|
res += `
|
|
154206
154206
|
${indentation}`;
|
|
154207
|
-
|
|
154207
|
+
join4 = `,
|
|
154208
154208
|
${indentation}`;
|
|
154209
154209
|
for (i = 0; i < value.length - 1; i++) {
|
|
154210
154210
|
const tmp2 = stringifyFullArr(i, value[i], stack, replacer, indent2);
|
|
154211
154211
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
154212
|
-
res +=
|
|
154212
|
+
res += join4;
|
|
154213
154213
|
}
|
|
154214
154214
|
const tmp = stringifyFullArr(i, value[i], stack, replacer, indent2);
|
|
154215
154215
|
res += tmp !== void 0 ? tmp : "null";
|
|
@@ -154230,7 +154230,7 @@ ${originalIndentation}`;
|
|
|
154230
154230
|
indentation += indent2;
|
|
154231
154231
|
res += `
|
|
154232
154232
|
${indentation}`;
|
|
154233
|
-
|
|
154233
|
+
join4 = `,
|
|
154234
154234
|
${indentation}`;
|
|
154235
154235
|
var separator = "";
|
|
154236
154236
|
for (i = 0; i < replacer.length; i++) {
|
|
@@ -154239,7 +154239,7 @@ ${indentation}`;
|
|
|
154239
154239
|
const tmp = stringifyFullArr(key, value[key], stack, replacer, indent2);
|
|
154240
154240
|
if (tmp !== void 0) {
|
|
154241
154241
|
res += `${separator}"${strEscape(key)}": ${tmp}`;
|
|
154242
|
-
separator =
|
|
154242
|
+
separator = join4;
|
|
154243
154243
|
}
|
|
154244
154244
|
}
|
|
154245
154245
|
}
|
|
@@ -154262,7 +154262,7 @@ ${originalIndentation}`;
|
|
|
154262
154262
|
}
|
|
154263
154263
|
}
|
|
154264
154264
|
function stringifyIndent(key, value, stack, indent2) {
|
|
154265
|
-
var i, res,
|
|
154265
|
+
var i, res, join4;
|
|
154266
154266
|
const originalIndentation = indentation;
|
|
154267
154267
|
switch (typeof value) {
|
|
154268
154268
|
case "object":
|
|
@@ -154292,12 +154292,12 @@ ${originalIndentation}`;
|
|
|
154292
154292
|
indentation += indent2;
|
|
154293
154293
|
res += `
|
|
154294
154294
|
${indentation}`;
|
|
154295
|
-
|
|
154295
|
+
join4 = `,
|
|
154296
154296
|
${indentation}`;
|
|
154297
154297
|
for (i = 0; i < value.length - 1; i++) {
|
|
154298
154298
|
const tmp2 = stringifyIndent(i, value[i], stack, indent2);
|
|
154299
154299
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
154300
|
-
res +=
|
|
154300
|
+
res += join4;
|
|
154301
154301
|
}
|
|
154302
154302
|
const tmp = stringifyIndent(i, value[i], stack, indent2);
|
|
154303
154303
|
res += tmp !== void 0 ? tmp : "null";
|
|
@@ -154319,7 +154319,7 @@ ${originalIndentation}`;
|
|
|
154319
154319
|
indentation += indent2;
|
|
154320
154320
|
res += `
|
|
154321
154321
|
${indentation}`;
|
|
154322
|
-
|
|
154322
|
+
join4 = `,
|
|
154323
154323
|
${indentation}`;
|
|
154324
154324
|
var separator = "";
|
|
154325
154325
|
for (i = 0; i < keys.length; i++) {
|
|
@@ -154327,7 +154327,7 @@ ${indentation}`;
|
|
|
154327
154327
|
const tmp = stringifyIndent(key, value[key], stack, indent2);
|
|
154328
154328
|
if (tmp !== void 0) {
|
|
154329
154329
|
res += `${separator}"${strEscape(key)}": ${tmp}`;
|
|
154330
|
-
separator =
|
|
154330
|
+
separator = join4;
|
|
154331
154331
|
}
|
|
154332
154332
|
}
|
|
154333
154333
|
if (separator !== "") {
|
|
@@ -172660,7 +172660,7 @@ var require_lodash2 = __commonJS({
|
|
|
172660
172660
|
}
|
|
172661
172661
|
return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped, undefined2, comparator) : [];
|
|
172662
172662
|
});
|
|
172663
|
-
function
|
|
172663
|
+
function join4(array, separator) {
|
|
172664
172664
|
return array == null ? "" : nativeJoin.call(array, separator);
|
|
172665
172665
|
}
|
|
172666
172666
|
function last(array) {
|
|
@@ -174584,7 +174584,7 @@ var require_lodash2 = __commonJS({
|
|
|
174584
174584
|
lodash.isUndefined = isUndefined;
|
|
174585
174585
|
lodash.isWeakMap = isWeakMap;
|
|
174586
174586
|
lodash.isWeakSet = isWeakSet;
|
|
174587
|
-
lodash.join =
|
|
174587
|
+
lodash.join = join4;
|
|
174588
174588
|
lodash.kebabCase = kebabCase;
|
|
174589
174589
|
lodash.last = last;
|
|
174590
174590
|
lodash.lastIndexOf = lastIndexOf;
|
|
@@ -179718,7 +179718,7 @@ var require_lodash3 = __commonJS({
|
|
|
179718
179718
|
}
|
|
179719
179719
|
return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped, undefined2, comparator) : [];
|
|
179720
179720
|
});
|
|
179721
|
-
function
|
|
179721
|
+
function join4(array, separator) {
|
|
179722
179722
|
return array == null ? "" : nativeJoin.call(array, separator);
|
|
179723
179723
|
}
|
|
179724
179724
|
function last(array) {
|
|
@@ -181642,7 +181642,7 @@ var require_lodash3 = __commonJS({
|
|
|
181642
181642
|
lodash.isUndefined = isUndefined;
|
|
181643
181643
|
lodash.isWeakMap = isWeakMap;
|
|
181644
181644
|
lodash.isWeakSet = isWeakSet;
|
|
181645
|
-
lodash.join =
|
|
181645
|
+
lodash.join = join4;
|
|
181646
181646
|
lodash.kebabCase = kebabCase;
|
|
181647
181647
|
lodash.last = last;
|
|
181648
181648
|
lodash.lastIndexOf = lastIndexOf;
|
|
@@ -283137,7 +283137,7 @@ var require_lodash5 = __commonJS({
|
|
|
283137
283137
|
}
|
|
283138
283138
|
return mapped.length && mapped[0] === arrays[0] ? baseIntersection(mapped, undefined2, comparator) : [];
|
|
283139
283139
|
});
|
|
283140
|
-
function
|
|
283140
|
+
function join4(array, separator) {
|
|
283141
283141
|
return array == null ? "" : nativeJoin.call(array, separator);
|
|
283142
283142
|
}
|
|
283143
283143
|
function last(array) {
|
|
@@ -285061,7 +285061,7 @@ var require_lodash5 = __commonJS({
|
|
|
285061
285061
|
lodash.isUndefined = isUndefined;
|
|
285062
285062
|
lodash.isWeakMap = isWeakMap;
|
|
285063
285063
|
lodash.isWeakSet = isWeakSet;
|
|
285064
|
-
lodash.join =
|
|
285064
|
+
lodash.join = join4;
|
|
285065
285065
|
lodash.kebabCase = kebabCase;
|
|
285066
285066
|
lodash.last = last;
|
|
285067
285067
|
lodash.lastIndexOf = lastIndexOf;
|
|
@@ -294670,7 +294670,7 @@ function getIDToken(aud) {
|
|
|
294670
294670
|
|
|
294671
294671
|
// src/index.ts
|
|
294672
294672
|
var import_node_crypto4 = require("node:crypto");
|
|
294673
|
-
var
|
|
294673
|
+
var import_node_fs5 = require("node:fs");
|
|
294674
294674
|
var path9 = __toESM(require("node:path"), 1);
|
|
294675
294675
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
294676
294676
|
|
|
@@ -296224,12 +296224,62 @@ function resolvePostmanEndpointProfile(stack, region = "us") {
|
|
|
296224
296224
|
|
|
296225
296225
|
// src/lib/postman/credential-identity.ts
|
|
296226
296226
|
var sessionPath = "/api/sessions/current";
|
|
296227
|
+
var SESSION_MAX_ATTEMPTS = 3;
|
|
296228
|
+
var SESSION_RETRY_BASE_DELAY_MS = 500;
|
|
296229
|
+
var SESSION_RETRY_MAX_DELAY_MS = 8e3;
|
|
296227
296230
|
var pmakMemo = /* @__PURE__ */ new Map();
|
|
296228
296231
|
var sessionMemo = /* @__PURE__ */ new Map();
|
|
296229
296232
|
var memoizedSessionIdentity;
|
|
296233
|
+
var memoizedSessionFailure;
|
|
296234
|
+
function defaultSessionSleep(ms) {
|
|
296235
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
296236
|
+
}
|
|
296237
|
+
function defaultRandom() {
|
|
296238
|
+
return Math.random();
|
|
296239
|
+
}
|
|
296240
|
+
function parseRetryAfterMs(value) {
|
|
296241
|
+
const trimmed = value?.trim();
|
|
296242
|
+
if (!trimmed) {
|
|
296243
|
+
return void 0;
|
|
296244
|
+
}
|
|
296245
|
+
if (/^\d+$/.test(trimmed)) {
|
|
296246
|
+
return Number(trimmed) * 1e3;
|
|
296247
|
+
}
|
|
296248
|
+
const dateMs = Date.parse(trimmed);
|
|
296249
|
+
if (!Number.isNaN(dateMs)) {
|
|
296250
|
+
return Math.max(0, dateMs - Date.now());
|
|
296251
|
+
}
|
|
296252
|
+
return void 0;
|
|
296253
|
+
}
|
|
296254
|
+
function parseRateLimitResetMs(value) {
|
|
296255
|
+
const trimmed = value?.trim();
|
|
296256
|
+
if (!trimmed || !/^\d+$/.test(trimmed)) {
|
|
296257
|
+
return void 0;
|
|
296258
|
+
}
|
|
296259
|
+
const seconds = Number(trimmed);
|
|
296260
|
+
const nowSeconds = Date.now() / 1e3;
|
|
296261
|
+
if (seconds > nowSeconds) {
|
|
296262
|
+
return Math.max(0, (seconds - nowSeconds) * 1e3);
|
|
296263
|
+
}
|
|
296264
|
+
return seconds * 1e3;
|
|
296265
|
+
}
|
|
296266
|
+
function computeSessionRetryDelayMs(response, attempt, random) {
|
|
296267
|
+
const headers = response?.headers;
|
|
296268
|
+
const signal = parseRetryAfterMs(headers?.get("retry-after") ?? null) ?? parseRateLimitResetMs(
|
|
296269
|
+
headers?.get("ratelimit-reset") ?? headers?.get("x-ratelimit-reset") ?? null
|
|
296270
|
+
);
|
|
296271
|
+
if (signal !== void 0) {
|
|
296272
|
+
return Math.min(Math.max(0, signal), SESSION_RETRY_MAX_DELAY_MS);
|
|
296273
|
+
}
|
|
296274
|
+
const ceiling = Math.min(SESSION_RETRY_MAX_DELAY_MS, SESSION_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
|
|
296275
|
+
return Math.round(random() * ceiling);
|
|
296276
|
+
}
|
|
296230
296277
|
function getMemoizedSessionIdentity() {
|
|
296231
296278
|
return memoizedSessionIdentity;
|
|
296232
296279
|
}
|
|
296280
|
+
function getSessionResolutionFailure() {
|
|
296281
|
+
return memoizedSessionFailure;
|
|
296282
|
+
}
|
|
296233
296283
|
function asRecord2(value) {
|
|
296234
296284
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
296235
296285
|
return void 0;
|
|
@@ -296298,46 +296348,90 @@ async function resolveSessionIdentity(opts) {
|
|
|
296298
296348
|
const memoKey = `${baseUrl}::${accessToken}`;
|
|
296299
296349
|
let pending = sessionMemo.get(memoKey);
|
|
296300
296350
|
if (!pending) {
|
|
296301
|
-
pending = probeSessionIdentity(
|
|
296351
|
+
pending = probeSessionIdentity(
|
|
296352
|
+
baseUrl,
|
|
296353
|
+
accessToken,
|
|
296354
|
+
opts.fetchImpl ?? fetch,
|
|
296355
|
+
Math.max(1, opts.maxAttempts ?? SESSION_MAX_ATTEMPTS),
|
|
296356
|
+
opts.sleepImpl ?? defaultSessionSleep,
|
|
296357
|
+
opts.randomImpl ?? defaultRandom
|
|
296358
|
+
);
|
|
296302
296359
|
sessionMemo.set(memoKey, pending);
|
|
296303
296360
|
}
|
|
296304
296361
|
return pending;
|
|
296305
296362
|
}
|
|
296306
|
-
async function
|
|
296363
|
+
async function parseSessionResponse(response) {
|
|
296364
|
+
let payload;
|
|
296307
296365
|
try {
|
|
296308
|
-
|
|
296309
|
-
method: "GET",
|
|
296310
|
-
headers: { "x-access-token": accessToken }
|
|
296311
|
-
});
|
|
296312
|
-
if (!response.ok) {
|
|
296313
|
-
return void 0;
|
|
296314
|
-
}
|
|
296315
|
-
const payload = asRecord2(await response.json());
|
|
296316
|
-
if (!payload) {
|
|
296317
|
-
return void 0;
|
|
296318
|
-
}
|
|
296319
|
-
const root = asRecord2(payload.session) ?? payload;
|
|
296320
|
-
const identity = asRecord2(root.identity);
|
|
296321
|
-
const data = asRecord2(root.data);
|
|
296322
|
-
const user = asRecord2(data?.user);
|
|
296323
|
-
const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
|
|
296324
|
-
const singleRole = coerceText(user?.role);
|
|
296325
|
-
const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
|
|
296326
|
-
const resolved = {
|
|
296327
|
-
source: "iapub/sessions",
|
|
296328
|
-
userId: coerceId(identity?.user) ?? coerceId(user?.id),
|
|
296329
|
-
fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
|
|
296330
|
-
teamId: coerceId(identity?.team),
|
|
296331
|
-
teamName: coerceText(user?.teamName),
|
|
296332
|
-
teamDomain: coerceText(identity?.domain),
|
|
296333
|
-
...roles ? { roles } : {},
|
|
296334
|
-
consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
|
|
296335
|
-
};
|
|
296336
|
-
memoizedSessionIdentity = resolved;
|
|
296337
|
-
return resolved;
|
|
296366
|
+
payload = asRecord2(await response.json());
|
|
296338
296367
|
} catch {
|
|
296339
296368
|
return void 0;
|
|
296340
296369
|
}
|
|
296370
|
+
if (!payload) {
|
|
296371
|
+
return void 0;
|
|
296372
|
+
}
|
|
296373
|
+
const root = asRecord2(payload.session) ?? payload;
|
|
296374
|
+
const identity = asRecord2(root.identity);
|
|
296375
|
+
const data = asRecord2(root.data);
|
|
296376
|
+
const user = asRecord2(data?.user);
|
|
296377
|
+
const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
|
|
296378
|
+
const singleRole = coerceText(user?.role);
|
|
296379
|
+
const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
|
|
296380
|
+
return {
|
|
296381
|
+
source: "iapub/sessions",
|
|
296382
|
+
userId: coerceId(identity?.user) ?? coerceId(user?.id),
|
|
296383
|
+
fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
|
|
296384
|
+
teamId: coerceId(identity?.team),
|
|
296385
|
+
teamName: coerceText(user?.teamName),
|
|
296386
|
+
teamDomain: coerceText(identity?.domain),
|
|
296387
|
+
...roles ? { roles } : {},
|
|
296388
|
+
consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
|
|
296389
|
+
};
|
|
296390
|
+
}
|
|
296391
|
+
async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random) {
|
|
296392
|
+
let failure = "unavailable";
|
|
296393
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
296394
|
+
let response;
|
|
296395
|
+
try {
|
|
296396
|
+
response = await fetchImpl(`${baseUrl}${sessionPath}`, {
|
|
296397
|
+
method: "GET",
|
|
296398
|
+
headers: { "x-access-token": accessToken }
|
|
296399
|
+
});
|
|
296400
|
+
} catch {
|
|
296401
|
+
failure = "unavailable";
|
|
296402
|
+
if (attempt < maxAttempts) {
|
|
296403
|
+
await sleepImpl(computeSessionRetryDelayMs(void 0, attempt, random));
|
|
296404
|
+
continue;
|
|
296405
|
+
}
|
|
296406
|
+
break;
|
|
296407
|
+
}
|
|
296408
|
+
if (response.ok) {
|
|
296409
|
+
const resolved = await parseSessionResponse(response);
|
|
296410
|
+
if (resolved) {
|
|
296411
|
+
memoizedSessionIdentity = resolved;
|
|
296412
|
+
memoizedSessionFailure = void 0;
|
|
296413
|
+
return resolved;
|
|
296414
|
+
}
|
|
296415
|
+
failure = "unavailable";
|
|
296416
|
+
break;
|
|
296417
|
+
}
|
|
296418
|
+
if (response.status === 401 || response.status === 403) {
|
|
296419
|
+
failure = "auth";
|
|
296420
|
+
break;
|
|
296421
|
+
}
|
|
296422
|
+
if (response.status === 429 || response.status >= 500) {
|
|
296423
|
+
failure = "unavailable";
|
|
296424
|
+
if (attempt < maxAttempts) {
|
|
296425
|
+
await sleepImpl(computeSessionRetryDelayMs(response, attempt, random));
|
|
296426
|
+
continue;
|
|
296427
|
+
}
|
|
296428
|
+
break;
|
|
296429
|
+
}
|
|
296430
|
+
failure = "unavailable";
|
|
296431
|
+
break;
|
|
296432
|
+
}
|
|
296433
|
+
memoizedSessionFailure = failure;
|
|
296434
|
+
return void 0;
|
|
296341
296435
|
}
|
|
296342
296436
|
function describeTeam(id) {
|
|
296343
296437
|
const label = id?.teamName ?? id?.teamDomain;
|
|
@@ -296428,7 +296522,9 @@ async function runCredentialPreflight(args) {
|
|
|
296428
296522
|
session = await resolveSessionIdentity({
|
|
296429
296523
|
iapubBaseUrl: args.iapubBaseUrl,
|
|
296430
296524
|
accessToken,
|
|
296431
|
-
fetchImpl: args.fetchImpl
|
|
296525
|
+
fetchImpl: args.fetchImpl,
|
|
296526
|
+
...args.sleepImpl ? { sleepImpl: args.sleepImpl } : {},
|
|
296527
|
+
...args.randomImpl ? { randomImpl: args.randomImpl } : {}
|
|
296432
296528
|
});
|
|
296433
296529
|
} catch (error2) {
|
|
296434
296530
|
args.log.warning(
|
|
@@ -296448,11 +296544,20 @@ async function runCredentialPreflight(args) {
|
|
|
296448
296544
|
);
|
|
296449
296545
|
}
|
|
296450
296546
|
} else {
|
|
296547
|
+
const failure = getSessionResolutionFailure();
|
|
296548
|
+
const detail = failure === "auth" ? "the access token was rejected by iapub (401/403), so it is invalid or expired. Re-mint it with postman-resolve-service-token-action (or POST https://api.getpostman.com/service-account-tokens) and re-run." : "iapub was unreachable after retries (network or 5xx). This is usually transient; re-run the job.";
|
|
296549
|
+
const base = "postman: credential preflight could not resolve the access-token session identity from iapub: " + detail;
|
|
296550
|
+
if (args.mode === "enforce") {
|
|
296551
|
+
throw new Error(
|
|
296552
|
+
mask(
|
|
296553
|
+
`${base} (credential-preflight: enforce requires a resolvable session identity; use credential-preflight: warn to continue with reactive error guidance only.)`
|
|
296554
|
+
)
|
|
296555
|
+
);
|
|
296556
|
+
}
|
|
296451
296557
|
args.log.warning(
|
|
296452
|
-
mask(
|
|
296453
|
-
"postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
|
|
296454
|
-
)
|
|
296558
|
+
mask(`${base} Continuing with reactive error guidance only (credential-preflight: warn).`)
|
|
296455
296559
|
);
|
|
296560
|
+
return;
|
|
296456
296561
|
}
|
|
296457
296562
|
const result = crossCheckIdentities({
|
|
296458
296563
|
pmak,
|
|
@@ -298219,7 +298324,11 @@ function securityCheckFor(schemeName, scheme) {
|
|
|
298219
298324
|
if (scheme?.type === "http") {
|
|
298220
298325
|
const httpScheme = String(scheme.scheme || "").toLowerCase();
|
|
298221
298326
|
if (httpScheme === "basic") return { scheme: schemeName, kind, checkable: true, prefix: "Basic " };
|
|
298222
|
-
if (httpScheme === "bearer")
|
|
298327
|
+
if (httpScheme === "bearer") {
|
|
298328
|
+
const check = { scheme: schemeName, kind, checkable: true, prefix: "Bearer " };
|
|
298329
|
+
if (typeof scheme.bearerFormat === "string" && scheme.bearerFormat) check.bearerFormat = scheme.bearerFormat;
|
|
298330
|
+
return check;
|
|
298331
|
+
}
|
|
298223
298332
|
if (httpScheme) return { scheme: schemeName, kind, checkable: true, prefix: `${httpScheme.charAt(0).toUpperCase()}${httpScheme.slice(1)} ` };
|
|
298224
298333
|
return { scheme: schemeName, kind, checkable: true, in: "header", name: "Authorization" };
|
|
298225
298334
|
}
|
|
@@ -298358,6 +298467,7 @@ function collectParameterChecks(root, pathItem, operation, version2, operationId
|
|
|
298358
298467
|
if (defaultSerialization) warnings.push(`CONTRACT_SCHEMA_NOT_COMPILED: parameter ${location2}:${name} schema on ${operationId} skipped (${packed.unsupported})`);
|
|
298359
298468
|
continue;
|
|
298360
298469
|
}
|
|
298470
|
+
validateParameterExamples(root, param, packed, `${location2}:${name} of ${operationId}`, warnings);
|
|
298361
298471
|
if (location2 === "path") {
|
|
298362
298472
|
const containingSegment = pathTemplate.split("/").find((segment) => segment.includes(`{${name}}`));
|
|
298363
298473
|
if (containingSegment !== void 0 && containingSegment !== `{${name}}`) {
|
|
@@ -298374,12 +298484,32 @@ function collectParameterChecks(root, pathItem, operation, version2, operationId
|
|
|
298374
298484
|
}
|
|
298375
298485
|
const scalarSchema = packedScalarSchema(packed);
|
|
298376
298486
|
if (scalarSchema !== void 0) {
|
|
298377
|
-
|
|
298487
|
+
const decodablePathStyle = location2 === "path" && (style === "label" || style === "matrix") && !explode ? style : void 0;
|
|
298488
|
+
if (!defaultSerialization && !decodablePathStyle) continue;
|
|
298489
|
+
if (!defaultSerialization) warnings.push(...noteWarnings);
|
|
298378
298490
|
const check2 = { in: location2, name, required: param.required === true, schema: scalarSchema };
|
|
298491
|
+
if (decodablePathStyle) check2.pathStyle = decodablePathStyle;
|
|
298379
298492
|
if (location2 === "query" && param.allowEmptyValue === true) check2.allowEmptyValue = true;
|
|
298380
298493
|
checks.push(check2);
|
|
298381
298494
|
continue;
|
|
298382
298495
|
}
|
|
298496
|
+
if (location2 === "query" && style === "deepObject" && explode) {
|
|
298497
|
+
const objectSchema = asRecord5(packed.schema);
|
|
298498
|
+
const properties = objectSchema ? asRecord5(objectSchema.properties) : null;
|
|
298499
|
+
const allScalar = properties !== null && Object.keys(properties).length > 0 && Object.values(properties).every((prop) => {
|
|
298500
|
+
const record = asRecord5(prop);
|
|
298501
|
+
if (!record) return false;
|
|
298502
|
+
const types2 = Array.isArray(record.type) ? record.type : [record.type];
|
|
298503
|
+
return types2.every((entry) => typeof entry === "string" && SCALAR_SCHEMA_TYPES.has(entry));
|
|
298504
|
+
});
|
|
298505
|
+
if (allScalar) {
|
|
298506
|
+
warnings.push(...noteWarnings);
|
|
298507
|
+
const check2 = { in: "query", name, required: param.required === true, schema: packed.schema, decode: "deepObject" };
|
|
298508
|
+
if (param.allowEmptyValue === true) check2.allowEmptyValue = true;
|
|
298509
|
+
checks.push(check2);
|
|
298510
|
+
continue;
|
|
298511
|
+
}
|
|
298512
|
+
}
|
|
298383
298513
|
if (location2 !== "query" && location2 !== "header") continue;
|
|
298384
298514
|
const items = packedArrayItemsSchema(packed);
|
|
298385
298515
|
if (items === void 0) continue;
|
|
@@ -298690,6 +298820,185 @@ function responseHeaders(root, version2, response, context, warnings) {
|
|
|
298690
298820
|
}
|
|
298691
298821
|
return entries;
|
|
298692
298822
|
}
|
|
298823
|
+
var IANA_HTTP_AUTH_SCHEMES = /* @__PURE__ */ new Set([
|
|
298824
|
+
"basic",
|
|
298825
|
+
"bearer",
|
|
298826
|
+
"concealed",
|
|
298827
|
+
"digest",
|
|
298828
|
+
"dpop",
|
|
298829
|
+
"gnap",
|
|
298830
|
+
"hoba",
|
|
298831
|
+
"mutual",
|
|
298832
|
+
"negotiate",
|
|
298833
|
+
"oauth",
|
|
298834
|
+
"privatetoken",
|
|
298835
|
+
"scram-sha-1",
|
|
298836
|
+
"scram-sha-256",
|
|
298837
|
+
"vapid"
|
|
298838
|
+
]);
|
|
298839
|
+
function httpsUrlLint(value, label, schemeName) {
|
|
298840
|
+
if (typeof value !== "string" || !value) return void 0;
|
|
298841
|
+
try {
|
|
298842
|
+
const parsed = new URL(value);
|
|
298843
|
+
if (parsed.protocol !== "https:") return `CONTRACT_SECURITY_SCHEME_URL: security scheme ${schemeName} ${label} ${value} is not an HTTPS URL`;
|
|
298844
|
+
} catch {
|
|
298845
|
+
return `CONTRACT_SECURITY_SCHEME_URL: security scheme ${schemeName} ${label} ${value} is not a valid URL`;
|
|
298846
|
+
}
|
|
298847
|
+
return void 0;
|
|
298848
|
+
}
|
|
298849
|
+
function collectSecurityStaticLints(root, operation) {
|
|
298850
|
+
const securitySchemes = asRecord5(asRecord5(root.components)?.securitySchemes);
|
|
298851
|
+
const requirements = operation.security === void 0 ? asArray3(root.security) : asArray3(operation.security);
|
|
298852
|
+
const warnings = /* @__PURE__ */ new Set();
|
|
298853
|
+
for (const requirement of requirements.map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry))) {
|
|
298854
|
+
for (const [schemeName, requiredScopes] of Object.entries(requirement)) {
|
|
298855
|
+
let scheme;
|
|
298856
|
+
try {
|
|
298857
|
+
scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
|
|
298858
|
+
} catch {
|
|
298859
|
+
scheme = null;
|
|
298860
|
+
}
|
|
298861
|
+
if (!scheme) continue;
|
|
298862
|
+
if (scheme.type === "http") {
|
|
298863
|
+
const httpScheme = String(scheme.scheme || "").toLowerCase();
|
|
298864
|
+
if (httpScheme && !IANA_HTTP_AUTH_SCHEMES.has(httpScheme)) {
|
|
298865
|
+
warnings.add(`CONTRACT_UNKNOWN_HTTP_AUTH_SCHEME: security scheme ${schemeName} uses "${httpScheme}", which is not in the IANA HTTP Authentication Scheme registry`);
|
|
298866
|
+
}
|
|
298867
|
+
}
|
|
298868
|
+
if (scheme.type === "apiKey" && String(scheme.in) === "query") {
|
|
298869
|
+
warnings.add(`CONTRACT_CREDENTIALS_IN_QUERY: security scheme ${schemeName} sends credentials in the query string, which leaks into logs and referrers`);
|
|
298870
|
+
}
|
|
298871
|
+
if (scheme.type === "openIdConnect") {
|
|
298872
|
+
const urlWarning = httpsUrlLint(scheme.openIdConnectUrl, "openIdConnectUrl", schemeName);
|
|
298873
|
+
if (urlWarning) warnings.add(urlWarning);
|
|
298874
|
+
else if (typeof scheme.openIdConnectUrl === "string" && !scheme.openIdConnectUrl.endsWith("/.well-known/openid-configuration")) {
|
|
298875
|
+
warnings.add(`CONTRACT_SECURITY_SCHEME_URL: security scheme ${schemeName} openIdConnectUrl does not end in /.well-known/openid-configuration`);
|
|
298876
|
+
}
|
|
298877
|
+
}
|
|
298878
|
+
if (scheme.type === "oauth2") {
|
|
298879
|
+
const flows = asRecord5(scheme.flows) ?? {};
|
|
298880
|
+
const declaredScopes = /* @__PURE__ */ new Set();
|
|
298881
|
+
for (const [flowName, rawFlow] of Object.entries(flows)) {
|
|
298882
|
+
const flow = asRecord5(rawFlow);
|
|
298883
|
+
if (!flow) continue;
|
|
298884
|
+
for (const scope of Object.keys(asRecord5(flow.scopes) ?? {})) declaredScopes.add(scope);
|
|
298885
|
+
const urlFields = [["refreshUrl", flow.refreshUrl]];
|
|
298886
|
+
if (flowName === "implicit" || flowName === "authorizationCode") urlFields.push(["authorizationUrl", flow.authorizationUrl]);
|
|
298887
|
+
if (flowName === "password" || flowName === "clientCredentials" || flowName === "authorizationCode") urlFields.push(["tokenUrl", flow.tokenUrl]);
|
|
298888
|
+
for (const [label, value] of urlFields) {
|
|
298889
|
+
const urlWarning = httpsUrlLint(value, `${flowName} ${label}`, schemeName);
|
|
298890
|
+
if (urlWarning) warnings.add(urlWarning);
|
|
298891
|
+
}
|
|
298892
|
+
}
|
|
298893
|
+
for (const scope of asArray3(requiredScopes).filter((entry) => typeof entry === "string")) {
|
|
298894
|
+
if (!declaredScopes.has(scope)) {
|
|
298895
|
+
warnings.add(`CONTRACT_OAUTH2_UNDECLARED_SCOPE: operation requires scope "${scope}" of ${schemeName}, which no flow of the scheme declares`);
|
|
298896
|
+
}
|
|
298897
|
+
}
|
|
298898
|
+
}
|
|
298899
|
+
}
|
|
298900
|
+
}
|
|
298901
|
+
return [...warnings];
|
|
298902
|
+
}
|
|
298903
|
+
function collectSecurityResponseLints(root, operation, responses, operationId) {
|
|
298904
|
+
const warnings = [];
|
|
298905
|
+
const requirements = operation.security === void 0 ? asArray3(root.security) : asArray3(operation.security);
|
|
298906
|
+
const requirementRecords = requirements.map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry));
|
|
298907
|
+
const secured = requirementRecords.length > 0 && requirementRecords.every((entry) => Object.keys(entry).length > 0);
|
|
298908
|
+
const statusKeys = new Set(Object.keys(responses));
|
|
298909
|
+
const hasCatchAll = statusKeys.has("default") || statusKeys.has("4XX");
|
|
298910
|
+
if (secured && !statusKeys.has("401") && !hasCatchAll) {
|
|
298911
|
+
warnings.push(`CONTRACT_SECURITY_RESPONSES_INCOMPLETE: ${operationId} requires authentication but documents no 401 (or 4XX/default) response`);
|
|
298912
|
+
}
|
|
298913
|
+
const usesScopes = requirementRecords.some((entry) => Object.values(entry).some((scopes) => Array.isArray(scopes) && scopes.length > 0));
|
|
298914
|
+
if (secured && usesScopes && !statusKeys.has("403") && !hasCatchAll) {
|
|
298915
|
+
warnings.push(`CONTRACT_SECURITY_RESPONSES_INCOMPLETE: ${operationId} requires scopes but documents no 403 (or 4XX/default) response`);
|
|
298916
|
+
}
|
|
298917
|
+
if (requirementRecords.length === 0) {
|
|
298918
|
+
for (const status of ["401", "403"]) {
|
|
298919
|
+
if (statusKeys.has(status)) warnings.push(`CONTRACT_UNSECURED_AUTH_RESPONSES: ${operationId} documents a ${status} response but declares no security requirement`);
|
|
298920
|
+
}
|
|
298921
|
+
}
|
|
298922
|
+
return warnings;
|
|
298923
|
+
}
|
|
298924
|
+
function collectLinkExpressions(root, response, operationId, warnings) {
|
|
298925
|
+
const links = asRecord5(response.links);
|
|
298926
|
+
if (!links) return [];
|
|
298927
|
+
const expressions = [];
|
|
298928
|
+
let unevaluated = false;
|
|
298929
|
+
for (const [linkName, rawLink] of Object.entries(links)) {
|
|
298930
|
+
let link;
|
|
298931
|
+
try {
|
|
298932
|
+
link = resolveInternalRef(root, rawLink);
|
|
298933
|
+
} catch {
|
|
298934
|
+
link = null;
|
|
298935
|
+
}
|
|
298936
|
+
if (!link) {
|
|
298937
|
+
unevaluated = true;
|
|
298938
|
+
continue;
|
|
298939
|
+
}
|
|
298940
|
+
const values = Object.values(asRecord5(link.parameters) ?? {});
|
|
298941
|
+
if (link.requestBody !== void 0) values.push(link.requestBody);
|
|
298942
|
+
if (values.length === 0) unevaluated = true;
|
|
298943
|
+
for (const value of values) {
|
|
298944
|
+
if (typeof value !== "string" || !value.startsWith("$")) continue;
|
|
298945
|
+
const bodyMatch = value.match(/^\$response\.body#(\/.*)$/);
|
|
298946
|
+
if (bodyMatch) {
|
|
298947
|
+
expressions.push({ link: linkName, kind: "body", pointer: bodyMatch[1] });
|
|
298948
|
+
continue;
|
|
298949
|
+
}
|
|
298950
|
+
const headerMatch = value.match(/^\$response\.header\.([!#$%&'*+.^_`|~0-9A-Za-z-]+)$/);
|
|
298951
|
+
if (headerMatch) {
|
|
298952
|
+
expressions.push({ link: linkName, kind: "header", header: headerMatch[1] });
|
|
298953
|
+
continue;
|
|
298954
|
+
}
|
|
298955
|
+
unevaluated = true;
|
|
298956
|
+
}
|
|
298957
|
+
}
|
|
298958
|
+
if (expressions.length === 0) {
|
|
298959
|
+
if (unevaluated) warnings.add(`CONTRACT_LINKS_NOT_VALIDATED: response links are not validated for ${operationId}`);
|
|
298960
|
+
} else if (unevaluated) {
|
|
298961
|
+
warnings.add(`CONTRACT_LINKS_PARTIALLY_VALIDATED: some link expressions for ${operationId} are not runtime-evaluable and are skipped`);
|
|
298962
|
+
}
|
|
298963
|
+
return expressions;
|
|
298964
|
+
}
|
|
298965
|
+
function escapeRegExpLiteral(value) {
|
|
298966
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
298967
|
+
}
|
|
298968
|
+
function serverAdvisoryPatterns(root, pathItem, operation) {
|
|
298969
|
+
const serverLists = [asArray3(operation.servers), asArray3(pathItem.servers), asArray3(root.servers)];
|
|
298970
|
+
const servers = serverLists.find((list) => list.length > 0) ?? [];
|
|
298971
|
+
const patterns = [];
|
|
298972
|
+
for (const rawServer of servers) {
|
|
298973
|
+
const server = asRecord5(rawServer);
|
|
298974
|
+
if (!server) continue;
|
|
298975
|
+
const url = typeof server.url === "string" ? server.url.trim() : "";
|
|
298976
|
+
if (!url || url === "/") continue;
|
|
298977
|
+
const variables = asRecord5(server.variables);
|
|
298978
|
+
const pattern = url.split(/(\{[^}]+\})/).map((part) => {
|
|
298979
|
+
const varMatch = part.match(/^\{([^}]+)\}$/);
|
|
298980
|
+
if (!varMatch) return escapeRegExpLiteral(part);
|
|
298981
|
+
const variable = asRecord5(variables?.[varMatch[1]]);
|
|
298982
|
+
const enumValues = asArray3(variable?.enum).filter((entry) => typeof entry === "string");
|
|
298983
|
+
if (enumValues.length > 0) return `(${enumValues.map(escapeRegExpLiteral).join("|")})`;
|
|
298984
|
+
return "[^/]*";
|
|
298985
|
+
}).join("");
|
|
298986
|
+
patterns.push(`^${pattern}`);
|
|
298987
|
+
}
|
|
298988
|
+
return patterns.length > 0 ? patterns : void 0;
|
|
298989
|
+
}
|
|
298990
|
+
function validateParameterExamples(root, param, packed, context, warnings) {
|
|
298991
|
+
if (packed.schema === void 0 || packed.unsupported) return;
|
|
298992
|
+
const candidates = exampleCandidates(root, param);
|
|
298993
|
+
if (candidates.length === 0) return;
|
|
298994
|
+
const validate3 = compileSchemaValidator(packed.schema);
|
|
298995
|
+
if (!validate3) return;
|
|
298996
|
+
for (const candidate of candidates) {
|
|
298997
|
+
if (!validate3(candidate.value)) {
|
|
298998
|
+
warnings.push(`CONTRACT_EXAMPLE_SCHEMA_MISMATCH: ${candidate.label} for parameter ${context} does not match its schema`);
|
|
298999
|
+
}
|
|
299000
|
+
}
|
|
299001
|
+
}
|
|
298693
299002
|
function buildContractIndex(root) {
|
|
298694
299003
|
if (root.swagger === "2.0") throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (found swagger 2.0)");
|
|
298695
299004
|
if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
|
|
@@ -298708,6 +299017,9 @@ function buildContractIndex(root) {
|
|
|
298708
299017
|
const operation = resolveInternalRef(root, rawOperation);
|
|
298709
299018
|
if (!operation) continue;
|
|
298710
299019
|
if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path10}`);
|
|
299020
|
+
if (operation.requestBody !== void 0 && ["get", "head", "delete"].includes(lowerMethod)) {
|
|
299021
|
+
warnings.push(`CONTRACT_METHOD_BODY_SEMANTICS: ${lowerMethod.toUpperCase()} ${path10} declares a request body; RFC 9110 defines no request-body semantics for ${lowerMethod.toUpperCase()}`);
|
|
299022
|
+
}
|
|
298711
299023
|
const responses = asRecord5(operation.responses);
|
|
298712
299024
|
if (!responses || Object.keys(responses).length === 0) {
|
|
298713
299025
|
throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path10} must define at least one response`);
|
|
@@ -298717,11 +299029,15 @@ function buildContractIndex(root) {
|
|
|
298717
299029
|
for (const [status, rawResponse] of Object.entries(responses)) {
|
|
298718
299030
|
const response = resolveInternalRef(root, rawResponse);
|
|
298719
299031
|
if (!response) continue;
|
|
298720
|
-
if (
|
|
298721
|
-
responseWarnings.add(`
|
|
299032
|
+
if (status !== "default" && !/^[1-5]XX$/.test(status) && !/^[1-5][0-9][0-9]$/.test(status)) {
|
|
299033
|
+
responseWarnings.add(`CONTRACT_INVALID_STATUS_CODE: ${lowerMethod.toUpperCase()} ${path10} declares response status "${status}" outside RFC 9110's 100-599, 1XX-5XX, or default forms`);
|
|
298722
299034
|
}
|
|
299035
|
+
const linkExpressions = collectLinkExpressions(root, response, `${lowerMethod.toUpperCase()} ${path10}`, responseWarnings);
|
|
298723
299036
|
const responseContext = `${lowerMethod.toUpperCase()} ${path10} status ${status}`;
|
|
298724
299037
|
const content = responseContent(root, version2, response, responseContext, responseWarnings);
|
|
299038
|
+
if ((status === "204" || status === "205" || status === "304") && Object.keys(content).length > 0) {
|
|
299039
|
+
responseWarnings.add(`CONTRACT_BODYLESS_STATUS_WITH_CONTENT: ${lowerMethod.toUpperCase()} ${path10} declares content for status ${status}, which RFC 9110 forbids on the wire`);
|
|
299040
|
+
}
|
|
298725
299041
|
for (const [contentType2, media] of Object.entries(content)) {
|
|
298726
299042
|
const base = contentType2.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
298727
299043
|
const schemaType = asRecord5(media.schema)?.type;
|
|
@@ -298733,7 +299049,8 @@ function buildContractIndex(root) {
|
|
|
298733
299049
|
contractResponses[normalizeResponseKey(status)] = {
|
|
298734
299050
|
content,
|
|
298735
299051
|
hasBody: Object.keys(content).length > 0,
|
|
298736
|
-
headers
|
|
299052
|
+
headers,
|
|
299053
|
+
...linkExpressions.length > 0 ? { links: linkExpressions } : {}
|
|
298737
299054
|
};
|
|
298738
299055
|
}
|
|
298739
299056
|
const candidates = [...new Set([
|
|
@@ -298746,11 +299063,13 @@ function buildContractIndex(root) {
|
|
|
298746
299063
|
opWarnings.push(...collectSecuritySchemeWarnings(root, operation));
|
|
298747
299064
|
const parameterChecks = collectParameterChecks(root, pathItem, operation, version2, operationId, path10, opWarnings);
|
|
298748
299065
|
const checkedKeys = new Set((parameterChecks ?? []).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
298749
|
-
const decodedKeys = new Set((parameterChecks ?? []).filter((check) => check.decode).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
299066
|
+
const decodedKeys = new Set((parameterChecks ?? []).filter((check) => check.decode || check.pathStyle).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
298750
299067
|
opWarnings.push(...collectSerializationWarnings(root, pathItem, operation, decodedKeys));
|
|
298751
299068
|
if (operation.deprecated === true) {
|
|
298752
299069
|
opWarnings.push(`CONTRACT_OPERATION_DEPRECATED: ${lowerMethod.toUpperCase()} ${path10} is marked deprecated in the OpenAPI document`);
|
|
298753
299070
|
}
|
|
299071
|
+
opWarnings.push(...collectSecurityStaticLints(root, operation));
|
|
299072
|
+
opWarnings.push(...collectSecurityResponseLints(root, operation, responses, operationId));
|
|
298754
299073
|
const requiredParameters = collectParameters(root, pathItem, operation);
|
|
298755
299074
|
for (const parameter of requiredParameters.filter((entry) => entry.securityDerived)) {
|
|
298756
299075
|
opWarnings.push(`CONTRACT_SECURITY_NOT_VALIDATED: security parameter ${parameter.in}:${parameter.name} is not statically required in generated requests`);
|
|
@@ -298779,6 +299098,9 @@ function buildContractIndex(root) {
|
|
|
298779
299098
|
parameterChecks,
|
|
298780
299099
|
requestBody: collectRequestBody(root, operation, version2, operationId, opWarnings),
|
|
298781
299100
|
security: collectSecurityRuntimeChecks(root, operation),
|
|
299101
|
+
pathMethods: Object.keys(pathItem).filter((key) => HTTP_METHODS.has(key)).map((key) => key.toUpperCase()),
|
|
299102
|
+
deprecated: operation.deprecated === true || void 0,
|
|
299103
|
+
servers: serverAdvisoryPatterns(root, pathItem, operation),
|
|
298782
299104
|
warnings: opWarnings
|
|
298783
299105
|
});
|
|
298784
299106
|
}
|
|
@@ -298955,7 +299277,7 @@ function buildValidatorAssignments(operation, warnings, skipped) {
|
|
|
298955
299277
|
return lines;
|
|
298956
299278
|
}
|
|
298957
299279
|
function createContractScript(operation, warnings = []) {
|
|
298958
|
-
const contract = { method: operation.method, path: operation.path, responses: operation.responses, security: operation.security, parameters: operation.parameterChecks };
|
|
299280
|
+
const contract = { method: operation.method, path: operation.path, responses: operation.responses, security: operation.security, parameters: operation.parameterChecks, pathMethods: operation.pathMethods, deprecated: operation.deprecated, servers: operation.servers };
|
|
298959
299281
|
const skipped = [];
|
|
298960
299282
|
const validatorLines = buildValidatorAssignments(operation, warnings, skipped);
|
|
298961
299283
|
return [
|
|
@@ -299066,6 +299388,417 @@ function createContractScript(operation, warnings = []) {
|
|
|
299066
299388
|
' if (!isJsonSubtype(actual.subtype) && media.media.schema && media.media.schema.type !== "string") { return; }',
|
|
299067
299389
|
' if (!validate(value)) pm.expect.fail("OpenAPI schema validation failed for " + contract.method + " " + contract.path + " status " + pm.response.code + ": " + JSON.stringify(validate.errors || []));',
|
|
299068
299390
|
"});",
|
|
299391
|
+
"pm.test('Response satisfies RFC 9110 status-code requirements', function () {",
|
|
299392
|
+
" var code = pm.response.code;",
|
|
299393
|
+
' function respHeader(name) { return pm.response.headers.get(name) || ""; }',
|
|
299394
|
+
" if (code === 401) {",
|
|
299395
|
+
' var challenge = respHeader("WWW-Authenticate");',
|
|
299396
|
+
' if (!challenge) pm.expect.fail("RFC 9110 requires WWW-Authenticate on 401 responses");',
|
|
299397
|
+
' var wantsBearer = (contract.security || []).some(function (alternative) { return alternative.some(function (check) { return check.prefix && check.prefix.toLowerCase().indexOf("bearer") === 0; }); });',
|
|
299398
|
+
' if (wantsBearer && challenge && challenge.toLowerCase().indexOf("bearer") === -1) pm.expect.fail("RFC 6750 expects a Bearer challenge on 401 for bearer-secured operations; got: " + challenge);',
|
|
299399
|
+
' if (challenge && /\\bbasic\\b/i.test(challenge) && !/realm\\s*=/i.test(challenge)) pm.expect.fail("RFC 7617 requires a realm parameter on Basic challenges: " + challenge);',
|
|
299400
|
+
' if (challenge && /\\bdigest\\b/i.test(challenge) && (!/realm\\s*=/i.test(challenge) || !/nonce\\s*=/i.test(challenge))) pm.expect.fail("RFC 7616 requires realm and nonce on Digest challenges: " + challenge);',
|
|
299401
|
+
" }",
|
|
299402
|
+
" if (code === 401 || code === 403) {",
|
|
299403
|
+
' var authChallenge = respHeader("WWW-Authenticate");',
|
|
299404
|
+
' var bearerError = authChallenge && /\\bbearer\\b/i.test(authChallenge) ? authChallenge.match(/\\berror\\s*=\\s*"?([A-Za-z0-9_]+)"?/i) : null;',
|
|
299405
|
+
' if (bearerError && ["invalid_request", "invalid_token", "insufficient_scope"].indexOf(bearerError[1]) === -1) pm.expect.fail("RFC 6750 Bearer error code must be invalid_request, invalid_token, or insufficient_scope; got " + bearerError[1]);',
|
|
299406
|
+
" }",
|
|
299407
|
+
" if (code === 405) {",
|
|
299408
|
+
' var allow = respHeader("Allow");',
|
|
299409
|
+
' if (!allow) pm.expect.fail("RFC 9110 requires Allow on 405 responses");',
|
|
299410
|
+
' var allowed = allow.split(",").map(function (entry) { return entry.trim().toUpperCase(); });',
|
|
299411
|
+
' (contract.pathMethods || []).forEach(function (method) { if (allowed.indexOf(method) === -1) pm.expect.fail("Allow on 405 must list every method the OpenAPI path declares (RFC 9110); missing " + method + " in: " + allow); });',
|
|
299412
|
+
" }",
|
|
299413
|
+
' if (code === 304 && responseText().trim().length > 0) pm.expect.fail("RFC 9110 forbids content in a 304 response");',
|
|
299414
|
+
' var retryAfter = respHeader("Retry-After");',
|
|
299415
|
+
" if (retryAfter && (code === 429 || code === 503 || (code >= 300 && code < 400))) {",
|
|
299416
|
+
' if (!/^\\d+$/.test(retryAfter.trim()) && isNaN(Date.parse(retryAfter))) pm.expect.fail("Retry-After must be delay-seconds or an HTTP-date (RFC 9110): " + retryAfter);',
|
|
299417
|
+
" }",
|
|
299418
|
+
' var location = respHeader("Location");',
|
|
299419
|
+
" if (location && (code === 201 || (code >= 300 && code < 400))) {",
|
|
299420
|
+
' if (/\\s/.test(location.trim()) || location.trim().length === 0) pm.expect.fail("Location must be a valid URI-reference (RFC 9110 / RFC 3986): " + location);',
|
|
299421
|
+
" }",
|
|
299422
|
+
"});",
|
|
299423
|
+
"pm.test('Error and encoding conventions match RFC 9457 / RFC 8259 / RFC 8288', function () {",
|
|
299424
|
+
' var contentTypeRaw = pm.response.headers.get("Content-Type") || "";',
|
|
299425
|
+
" var ct = mediaParts(contentTypeRaw);",
|
|
299426
|
+
' if (ct.type === "application" && ct.subtype === "problem+json") {',
|
|
299427
|
+
" var problem;",
|
|
299428
|
+
' try { problem = pm.response.json(); } catch (error) { pm.expect.fail("application/problem+json body is not valid JSON (RFC 9457): " + error); }',
|
|
299429
|
+
' if (!problem || typeof problem !== "object" || Array.isArray(problem)) pm.expect.fail("problem details must be a JSON object (RFC 9457)");',
|
|
299430
|
+
' ["type", "title", "detail", "instance"].forEach(function (member) { if (problem[member] !== undefined && typeof problem[member] !== "string") pm.expect.fail("RFC 9457 " + member + " member must be a string; got " + typeof problem[member]); });',
|
|
299431
|
+
' ["type", "instance"].forEach(function (member) { if (typeof problem[member] === "string" && /\\s/.test(problem[member].trim())) pm.expect.fail("RFC 9457 " + member + " member must be a URI-reference (RFC 3986): " + problem[member]); });',
|
|
299432
|
+
" if (problem.status !== undefined) {",
|
|
299433
|
+
' if (typeof problem.status !== "number") pm.expect.fail("RFC 9457 status member must be a number; got " + typeof problem.status);',
|
|
299434
|
+
' else if (problem.status !== pm.response.code) pm.expect.fail("RFC 9457 status member (" + problem.status + ") must match the HTTP status code (" + pm.response.code + ")");',
|
|
299435
|
+
" }",
|
|
299436
|
+
" }",
|
|
299437
|
+
" if (isJsonSubtype(ct.subtype)) {",
|
|
299438
|
+
' var charsetMatch = contentTypeRaw.match(/charset\\s*=\\s*"?([^";\\s]+)"?/i);',
|
|
299439
|
+
' if (charsetMatch && charsetMatch[1].toLowerCase() !== "utf-8") pm.expect.fail("JSON interchange must be UTF-8 (RFC 8259); got charset=" + charsetMatch[1]);',
|
|
299440
|
+
" }",
|
|
299441
|
+
' var link = pm.response.headers.get("Link");',
|
|
299442
|
+
" if (link) {",
|
|
299443
|
+
" link.split(/,(?=\\s*<)/).forEach(function (value) {",
|
|
299444
|
+
' if (!/^\\s*<[^>]*>/.test(value)) pm.expect.fail("RFC 8288 link-value must start with a <URI-Reference>: " + value);',
|
|
299445
|
+
' if (!/;\\s*rel\\s*=/i.test(value)) pm.expect.fail("RFC 8288 link-value must carry a rel parameter: " + value);',
|
|
299446
|
+
" });",
|
|
299447
|
+
" }",
|
|
299448
|
+
"});",
|
|
299449
|
+
"var rfcAdvisories = [];",
|
|
299450
|
+
"function rfcAdvise(message) { if (rfcAdvisories.indexOf(message) === -1) rfcAdvisories.push(message); }",
|
|
299451
|
+
'function rfcRespHeader(name) { return pm.response.headers.get(name) || ""; }',
|
|
299452
|
+
"function rfcHeaderAll(name) { var out = []; pm.response.headers.each(function (header) { if (header && String(header.key).toLowerCase() === String(name).toLowerCase()) out.push(String(header.value)); }); return out; }",
|
|
299453
|
+
"function rfcIsHttpDate(value) { return /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), [0-3][0-9] (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] GMT$/.test(String(value).trim()) && !isNaN(Date.parse(value)); }",
|
|
299454
|
+
"function rfcIsToken(value) { return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(String(value)); }",
|
|
299455
|
+
'function rfcIsEntityTag(value) { return /^(W\\/)?"[\\x21\\x23-\\x7e\\x80-\\xff]*"$/.test(String(value).trim()); }',
|
|
299456
|
+
"function rfcIsFieldContent(value) { return /^[\\t \\x21-\\x7e\\x80-\\xff]*$/.test(String(value)); }",
|
|
299457
|
+
'function rfcTokenList(value) { var parts = String(value).split(","); for (var i = 0; i < parts.length; i += 1) { if (!rfcIsToken(parts[i].trim())) return false; } return true; }',
|
|
299458
|
+
`function rfcSplitList(value) { var out = []; var current = ""; var inQuote = false; for (var i = 0; i < value.length; i += 1) { var ch = value.charAt(i); if (ch === "\\\\" && inQuote) { current += ch + (value.charAt(i + 1) || ""); i += 1; continue; } if (ch === '"') inQuote = !inQuote; if (ch === "," && !inQuote) { out.push(current); current = ""; continue; } current += ch; } out.push(current); return out; }`,
|
|
299459
|
+
'function rfcBase64Decode(value) { var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var clean = String(value).replace(/=+$/, ""); if (clean.length === 0 || /[^A-Za-z0-9+\\/]/.test(clean)) return null; var bits = 0, buffer = 0, out = ""; for (var i = 0; i < clean.length; i += 1) { buffer = (buffer << 6) | alphabet.indexOf(clean.charAt(i)); bits += 6; if (bits >= 8) { bits -= 8; out += String.fromCharCode((buffer >> bits) & 255); } } return out; }',
|
|
299460
|
+
"function rfcSfParse(input, kind) {",
|
|
299461
|
+
" var s = String(input), i = 0;",
|
|
299462
|
+
' function ws() { while (i < s.length && (s.charAt(i) === " " || s.charAt(i) === "\\t")) i += 1; }',
|
|
299463
|
+
" function key() { if (!/[a-z*]/.test(s.charAt(i))) return null; var start = i; i += 1; while (i < s.length && /[a-z0-9_.*-]/.test(s.charAt(i))) i += 1; return s.slice(start, i); }",
|
|
299464
|
+
" function bareItem() {",
|
|
299465
|
+
" var ch = s.charAt(i);",
|
|
299466
|
+
` if (ch === '"') { i += 1; while (i < s.length) { var c = s.charAt(i); if (c === "\\\\") { if (!/["\\\\]/.test(s.charAt(i + 1))) return null; i += 2; continue; } if (c === '"') { i += 1; return true; } if (c < " " || c > "~") return null; i += 1; } return null; }`,
|
|
299467
|
+
' if (ch === ":") { i += 1; var start = i; while (i < s.length && s.charAt(i) !== ":") i += 1; if (s.charAt(i) !== ":") return null; var body = s.slice(start, i); i += 1; return /^[A-Za-z0-9+\\/=]*$/.test(body) ? true : null; }',
|
|
299468
|
+
' if (ch === "?") { i += 1; if (s.charAt(i) !== "0" && s.charAt(i) !== "1") return null; i += 1; return true; }',
|
|
299469
|
+
' if (ch === "@") { i += 1; if (s.charAt(i) === "-") i += 1; if (!/[0-9]/.test(s.charAt(i))) return null; while (i < s.length && /[0-9]/.test(s.charAt(i))) i += 1; return true; }',
|
|
299470
|
+
' if (/[-0-9]/.test(ch)) { if (ch === "-") i += 1; if (!/[0-9]/.test(s.charAt(i))) return null; while (i < s.length && /[0-9]/.test(s.charAt(i))) i += 1; if (s.charAt(i) === ".") { i += 1; if (!/[0-9]/.test(s.charAt(i))) return null; while (i < s.length && /[0-9]/.test(s.charAt(i))) i += 1; } return true; }',
|
|
299471
|
+
" if (/[A-Za-z*]/.test(ch)) { i += 1; while (i < s.length && /[!#$%&'*+.^_`|~:\\/0-9A-Za-z-]/.test(s.charAt(i))) i += 1; return true; }",
|
|
299472
|
+
" return null;",
|
|
299473
|
+
" }",
|
|
299474
|
+
' function params() { while (s.charAt(i) === ";") { i += 1; ws(); if (key() === null) return null; if (s.charAt(i) === "=") { i += 1; if (bareItem() === null) return null; } } return true; }',
|
|
299475
|
+
' function item() { if (s.charAt(i) === "(") { i += 1; ws(); while (s.charAt(i) !== ")") { if (i >= s.length) return null; if (bareItem() === null || params() === null) return null; ws(); } i += 1; return params(); } if (bareItem() === null) return null; return params(); }',
|
|
299476
|
+
" ws();",
|
|
299477
|
+
' if (kind === "item") { if (item() === null) return false; ws(); return i === s.length; }',
|
|
299478
|
+
" if (i === s.length) return true;",
|
|
299479
|
+
" while (i < s.length) {",
|
|
299480
|
+
' if (kind === "dict") { if (key() === null) return false; if (s.charAt(i) === "=") { i += 1; if (item() === null) return false; } else if (params() === null) return false; }',
|
|
299481
|
+
" else if (item() === null) return false;",
|
|
299482
|
+
" ws();",
|
|
299483
|
+
" if (i === s.length) return true;",
|
|
299484
|
+
' if (s.charAt(i) !== ",") return false;',
|
|
299485
|
+
" i += 1; ws();",
|
|
299486
|
+
" if (i === s.length) return false;",
|
|
299487
|
+
" }",
|
|
299488
|
+
" return true;",
|
|
299489
|
+
"}",
|
|
299490
|
+
"pm.test('Response header fields satisfy RFC 9110 field syntax', function () {",
|
|
299491
|
+
" pm.response.headers.each(function (header) {",
|
|
299492
|
+
" if (!header) return;",
|
|
299493
|
+
' if (!rfcIsToken(String(header.key))) pm.expect.fail("Response header name is not a valid RFC 9110 token: " + header.key);',
|
|
299494
|
+
' if (!rfcIsFieldContent(String(header.value))) pm.expect.fail("Response header value contains characters forbidden by RFC 9110 field-content: " + header.key);',
|
|
299495
|
+
" });",
|
|
299496
|
+
' ["content-type", "content-length", "etag", "location", "date", "age", "expires", "last-modified", "retry-after"].forEach(function (name) {',
|
|
299497
|
+
" var values = rfcHeaderAll(name);",
|
|
299498
|
+
' for (var i = 1; i < values.length; i += 1) { if (values[i] !== values[0]) pm.expect.fail("Singleton response header " + name + " appears " + values.length + " times with differing values (RFC 9110)"); }',
|
|
299499
|
+
" });",
|
|
299500
|
+
"});",
|
|
299501
|
+
"pm.test('Response header values satisfy their RFC grammars', function () {",
|
|
299502
|
+
' var date = rfcRespHeader("Date");',
|
|
299503
|
+
' if (date && !rfcIsHttpDate(date)) pm.expect.fail("Date must be an IMF-fixdate (RFC 9110): " + date);',
|
|
299504
|
+
' if (!date) rfcAdvise("RFC 9110: origin servers SHOULD send a Date header");',
|
|
299505
|
+
' var etag = rfcRespHeader("ETag");',
|
|
299506
|
+
' if (etag && !rfcIsEntityTag(etag)) pm.expect.fail("ETag is not a valid entity-tag (RFC 9110): " + etag);',
|
|
299507
|
+
' var lastModified = rfcRespHeader("Last-Modified");',
|
|
299508
|
+
" if (lastModified) {",
|
|
299509
|
+
' if (!rfcIsHttpDate(lastModified)) pm.expect.fail("Last-Modified must be a valid HTTP-date (RFC 9110): " + lastModified);',
|
|
299510
|
+
' else if (date && rfcIsHttpDate(date) && Date.parse(lastModified) > Date.parse(date)) pm.expect.fail("Last-Modified must not be later than Date (RFC 9110): " + lastModified + " > " + date);',
|
|
299511
|
+
" }",
|
|
299512
|
+
' var vary = rfcRespHeader("Vary");',
|
|
299513
|
+
" if (vary) {",
|
|
299514
|
+
' var varyMembers = vary.split(",").map(function (entry) { return entry.trim(); });',
|
|
299515
|
+
' if (varyMembers.indexOf("*") !== -1 && varyMembers.length > 1) pm.expect.fail("Vary: * must not be combined with other members (RFC 9110): " + vary);',
|
|
299516
|
+
' varyMembers.forEach(function (member) { if (member !== "*" && !rfcIsToken(member)) pm.expect.fail("Vary member is not a field-name token (RFC 9110): " + member); });',
|
|
299517
|
+
" }",
|
|
299518
|
+
' var contentLocation = rfcRespHeader("Content-Location");',
|
|
299519
|
+
' if (contentLocation && (/\\s/.test(contentLocation.trim()) || contentLocation.trim().length === 0)) pm.expect.fail("Content-Location must be a valid URI-reference (RFC 9110): " + contentLocation);',
|
|
299520
|
+
' var acceptRanges = rfcRespHeader("Accept-Ranges");',
|
|
299521
|
+
' if (acceptRanges && !rfcTokenList(acceptRanges)) pm.expect.fail("Accept-Ranges must be a list of range-unit tokens (RFC 9110): " + acceptRanges);',
|
|
299522
|
+
' var contentLanguage = rfcRespHeader("Content-Language");',
|
|
299523
|
+
' if (contentLanguage) contentLanguage.split(",").forEach(function (tag) { if (!/^[A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})*$/.test(tag.trim())) pm.expect.fail("Content-Language carries a malformed BCP 47 language-tag (RFC 5646): " + tag.trim()); });',
|
|
299524
|
+
' var allow = rfcRespHeader("Allow");',
|
|
299525
|
+
' if (allow && allow.trim() && !rfcTokenList(allow)) pm.expect.fail("Allow must be a comma-separated list of method tokens (RFC 9110): " + allow);',
|
|
299526
|
+
' if (allow && contract.method === "OPTIONS" && pm.response.code >= 200 && pm.response.code < 300) {',
|
|
299527
|
+
' var optionsAllowed = allow.split(",").map(function (entry) { return entry.trim().toUpperCase(); });',
|
|
299528
|
+
' (contract.pathMethods || []).forEach(function (method) { if (optionsAllowed.indexOf(method) === -1) pm.expect.fail("Allow on an OPTIONS response must list every method the OpenAPI path declares (RFC 9110); missing " + method + " in: " + allow); });',
|
|
299529
|
+
" }",
|
|
299530
|
+
' var age = rfcRespHeader("Age");',
|
|
299531
|
+
' if (age && !/^[0-9]+$/.test(age.trim())) pm.expect.fail("Age must be a non-negative integer of delta-seconds (RFC 9111): " + age);',
|
|
299532
|
+
' var expires = rfcRespHeader("Expires");',
|
|
299533
|
+
' if (expires && !rfcIsHttpDate(expires)) rfcAdvise("RFC 9111: Expires is not a valid HTTP-date and will be treated as already expired: " + expires);',
|
|
299534
|
+
' if (rfcHeaderAll("warning").length > 0) rfcAdvise("RFC 9111 obsoleted the Warning header; the server still emits it");',
|
|
299535
|
+
' var cacheControl = rfcRespHeader("Cache-Control");',
|
|
299536
|
+
" if (cacheControl) {",
|
|
299537
|
+
" var seenDirectives = {};",
|
|
299538
|
+
" rfcSplitList(cacheControl).forEach(function (entry) {",
|
|
299539
|
+
" var directive = entry.trim();",
|
|
299540
|
+
' if (!directive) { pm.expect.fail("Cache-Control contains an empty directive (RFC 9111): " + cacheControl); return; }',
|
|
299541
|
+
' var eq = directive.indexOf("=");',
|
|
299542
|
+
" var name = (eq === -1 ? directive : directive.slice(0, eq)).trim().toLowerCase();",
|
|
299543
|
+
" var argument = eq === -1 ? undefined : directive.slice(eq + 1).trim();",
|
|
299544
|
+
' if (!rfcIsToken(name)) pm.expect.fail("Cache-Control directive name is not a token (RFC 9111): " + directive);',
|
|
299545
|
+
" seenDirectives[name] = argument === undefined ? true : argument;",
|
|
299546
|
+
' if (["max-age", "s-maxage", "stale-while-revalidate", "stale-if-error"].indexOf(name) !== -1 && (argument === undefined || !/^"?[0-9]+"?$/.test(argument))) pm.expect.fail("Cache-Control " + name + " requires a delta-seconds argument (RFC 9111): " + directive);',
|
|
299547
|
+
" });",
|
|
299548
|
+
' if (seenDirectives["no-store"] && seenDirectives["max-age"] !== undefined) pm.expect.fail("Cache-Control combines no-store with max-age; the directives contradict (RFC 9111): " + cacheControl);',
|
|
299549
|
+
" }",
|
|
299550
|
+
' var acceptPatch = rfcRespHeader("Accept-Patch");',
|
|
299551
|
+
' if (acceptPatch) acceptPatch.split(",").forEach(function (entry) { var parts = mediaParts(entry); if (!parts.type || !parts.subtype) pm.expect.fail("Accept-Patch must be a list of media types (RFC 5789): " + entry.trim()); });',
|
|
299552
|
+
' var deprecation = rfcRespHeader("Deprecation");',
|
|
299553
|
+
' if (deprecation && !/^@-?[0-9]+$/.test(deprecation.trim())) pm.expect.fail("Deprecation must be an RFC 9745 Date structured field (@unix-timestamp): " + deprecation);',
|
|
299554
|
+
' var sunset = rfcRespHeader("Sunset");',
|
|
299555
|
+
" if (sunset) {",
|
|
299556
|
+
' if (!rfcIsHttpDate(sunset)) pm.expect.fail("Sunset must be a valid HTTP-date (RFC 8594): " + sunset);',
|
|
299557
|
+
' else if (Date.parse(sunset) < Date.now()) rfcAdvise("RFC 8594: Sunset date is already in the past: " + sunset);',
|
|
299558
|
+
" }",
|
|
299559
|
+
' var preferenceApplied = rfcRespHeader("Preference-Applied");',
|
|
299560
|
+
" if (preferenceApplied) {",
|
|
299561
|
+
' var requestPrefer = requestHeader("Prefer").toLowerCase();',
|
|
299562
|
+
" rfcSplitList(preferenceApplied).forEach(function (entry) {",
|
|
299563
|
+
' var token = entry.split("=")[0].trim().toLowerCase();',
|
|
299564
|
+
' if (token && requestPrefer.indexOf(token) === -1) pm.expect.fail("Preference-Applied echoes a preference the request never sent (RFC 7240): " + entry.trim());',
|
|
299565
|
+
" });",
|
|
299566
|
+
" }",
|
|
299567
|
+
"});",
|
|
299568
|
+
"pm.test('Response satisfies RFC 9110 message framing requirements', function () {",
|
|
299569
|
+
" var code = pm.response.code;",
|
|
299570
|
+
' if ((code === 204 || code < 200) && rfcRespHeader("Content-Length")) pm.expect.fail("RFC 9110 forbids Content-Length on 1xx and 204 responses");',
|
|
299571
|
+
' if ([301, 302, 303, 307, 308].indexOf(code) !== -1 && !rfcRespHeader("Location")) pm.expect.fail("RFC 9110 expects Location on a " + code + " redirect response");',
|
|
299572
|
+
" if (code === 416) {",
|
|
299573
|
+
' var unsatisfiedRange = rfcRespHeader("Content-Range");',
|
|
299574
|
+
' if (!unsatisfiedRange) pm.expect.fail("RFC 9110 requires Content-Range (unsatisfied-range form) on 416 responses");',
|
|
299575
|
+
' else if (!/^\\S+ \\*\\/[0-9]+$/.test(unsatisfiedRange.trim())) pm.expect.fail("Content-Range on 416 must use the unsatisfied-range form <unit> */<complete-length> (RFC 9110): " + unsatisfiedRange);',
|
|
299576
|
+
" }",
|
|
299577
|
+
" if (code === 206) {",
|
|
299578
|
+
' var contentRange = rfcRespHeader("Content-Range");',
|
|
299579
|
+
' var responseMedia = mediaParts(rfcRespHeader("Content-Type"));',
|
|
299580
|
+
' var isByteranges = responseMedia.type === "multipart" && responseMedia.subtype === "byteranges";',
|
|
299581
|
+
' if (!contentRange && !isByteranges) pm.expect.fail("RFC 9110 requires Content-Range on a single-part 206 response (or multipart/byteranges for multi-range)");',
|
|
299582
|
+
' if (contentRange && isByteranges) pm.expect.fail("RFC 9110 forbids Content-Range on a multipart/byteranges 206 response");',
|
|
299583
|
+
" if (contentRange) {",
|
|
299584
|
+
" var rangeParts = contentRange.trim().match(/^(\\S+) (?:([0-9]+)-([0-9]+)|\\*)\\/([0-9]+|\\*)$/);",
|
|
299585
|
+
' if (!rangeParts) pm.expect.fail("Content-Range is not a valid RFC 9110 range: " + contentRange);',
|
|
299586
|
+
" else {",
|
|
299587
|
+
' if (rangeParts[1] !== "bytes") rfcAdvise("RFC 9110: 206 Content-Range uses a non-bytes range unit: " + rangeParts[1]);',
|
|
299588
|
+
" if (rangeParts[2] !== undefined) {",
|
|
299589
|
+
' if (Number(rangeParts[2]) > Number(rangeParts[3])) pm.expect.fail("Content-Range first-byte-pos must be <= last-byte-pos (RFC 9110): " + contentRange);',
|
|
299590
|
+
' if (rangeParts[4] !== "*" && Number(rangeParts[3]) >= Number(rangeParts[4])) pm.expect.fail("Content-Range last-byte-pos must be < complete-length (RFC 9110): " + contentRange);',
|
|
299591
|
+
" }",
|
|
299592
|
+
" }",
|
|
299593
|
+
" }",
|
|
299594
|
+
" }",
|
|
299595
|
+
' if (code === 407 && !rfcRespHeader("Proxy-Authenticate")) pm.expect.fail("RFC 9110 requires Proxy-Authenticate on 407 responses");',
|
|
299596
|
+
' if (code === 415 && contract.method === "PATCH" && !rfcRespHeader("Accept-Patch")) rfcAdvise("RFC 5789: a 415 response to PATCH SHOULD carry Accept-Patch");',
|
|
299597
|
+
"});",
|
|
299598
|
+
"pm.test('Response media type is acceptable under the request Accept header', function () {",
|
|
299599
|
+
" if (pm.response.code < 200 || pm.response.code >= 300 || isBodyless()) return;",
|
|
299600
|
+
' var accept = requestHeader("Accept");',
|
|
299601
|
+
' if (!accept || accept.indexOf("{{") !== -1) return;',
|
|
299602
|
+
' var actual = mediaParts(rfcRespHeader("Content-Type"));',
|
|
299603
|
+
" if (!actual.type) return;",
|
|
299604
|
+
" var acceptable = false;",
|
|
299605
|
+
" var jsonSoftened = false;",
|
|
299606
|
+
" rfcSplitList(accept).forEach(function (entry) {",
|
|
299607
|
+
" var range = mediaParts(entry);",
|
|
299608
|
+
' var qMatch = entry.match(/;\\s*q\\s*=\\s*"?([0-9.]+)"?/i);',
|
|
299609
|
+
" if (qMatch && Number(qMatch[1]) <= 0) return;",
|
|
299610
|
+
' if ((range.type === "*" && range.subtype === "*") || (range.type === actual.type && (range.subtype === "*" || range.subtype === actual.subtype))) acceptable = true;',
|
|
299611
|
+
' if (range.type === actual.type && range.subtype === "json" && isJsonSubtype(actual.subtype)) jsonSoftened = true;',
|
|
299612
|
+
" });",
|
|
299613
|
+
' if (!acceptable && jsonSoftened) { rfcAdvise("Content negotiation: response " + actual.raw + " is a +json type while the request only accepted application/json"); return; }',
|
|
299614
|
+
' if (!acceptable) pm.expect.fail("Response Content-Type " + actual.raw + " is not acceptable under the request Accept header (RFC 9110): " + accept);',
|
|
299615
|
+
"});",
|
|
299616
|
+
"pm.test('Response body satisfies its media type RFC conventions', function () {",
|
|
299617
|
+
' var contentTypeValue = rfcRespHeader("Content-Type");',
|
|
299618
|
+
" var media = mediaParts(contentTypeValue);",
|
|
299619
|
+
" var text = responseText();",
|
|
299620
|
+
' if (pm.response.code === 406 && !text.trim()) rfcAdvise("RFC 9110: a 406 response SHOULD include a list of available representations");',
|
|
299621
|
+
" if (!text) return;",
|
|
299622
|
+
" if (isJsonSubtype(media.subtype)) {",
|
|
299623
|
+
' if (text.charCodeAt(0) === 65279) pm.expect.fail("RFC 8259 forbids a byte order mark at the start of JSON text");',
|
|
299624
|
+
' var charsetParam = contentTypeValue.match(/charset\\s*=\\s*"?([^";\\s]+)"?/i);',
|
|
299625
|
+
' if (charsetParam) rfcAdvise("RFC 8259 defines no charset parameter for JSON media types; got charset=" + charsetParam[1]);',
|
|
299626
|
+
" }",
|
|
299627
|
+
' if (media.raw === "application/x-ndjson" || media.raw === "application/jsonl" || media.raw === "application/x-jsonlines") {',
|
|
299628
|
+
' text.split(/\\r?\\n/).forEach(function (line, lineNumber) { if (!line.trim()) return; try { JSON.parse(line); } catch (error) { pm.expect.fail("NDJSON line " + (lineNumber + 1) + " is not valid JSON: " + error); } });',
|
|
299629
|
+
" }",
|
|
299630
|
+
' if (media.raw === "text/event-stream") {',
|
|
299631
|
+
' text.split(/\\r?\\n/).forEach(function (line) { if (!line || line.charAt(0) === ":") return; var field = line.split(":")[0]; if (["data", "event", "id", "retry"].indexOf(field) === -1) pm.expect.fail("SSE line does not start with a known field or comment: " + line); if (field === "retry" && !/^retry:\\s*[0-9]+\\s*$/.test(line)) pm.expect.fail("SSE retry field must be an integer: " + line); });',
|
|
299632
|
+
" }",
|
|
299633
|
+
' if (media.type === "multipart") {',
|
|
299634
|
+
' var boundary = contentTypeValue.match(/;\\s*boundary=(?:"([^"]*)"|([^;]*))/i);',
|
|
299635
|
+
' var boundaryValue = boundary ? (boundary[1] !== undefined ? boundary[1] : boundary[2].trim()) : "";',
|
|
299636
|
+
' if (!boundaryValue) pm.expect.fail("multipart responses must carry a boundary parameter (RFC 2046): " + contentTypeValue);',
|
|
299637
|
+
" else {",
|
|
299638
|
+
' if (boundaryValue.length > 70) pm.expect.fail("multipart boundary must be 1-70 characters (RFC 2046): " + boundaryValue);',
|
|
299639
|
+
` if (!/^[0-9A-Za-z'()+_,\\-.\\/:=? ]*[0-9A-Za-z'()+_,\\-.\\/:=?]$/.test(boundaryValue)) pm.expect.fail("multipart boundary contains characters outside RFC 2046 bchars or ends with a space: " + boundaryValue);`,
|
|
299640
|
+
" }",
|
|
299641
|
+
" }",
|
|
299642
|
+
' if (media.raw === "application/hal+json") {',
|
|
299643
|
+
" var hal; try { hal = JSON.parse(text); } catch (error) { hal = null; }",
|
|
299644
|
+
' if (hal && typeof hal === "object" && !Array.isArray(hal)) {',
|
|
299645
|
+
" var halLinks = hal._links;",
|
|
299646
|
+
' if (halLinks !== undefined && (typeof halLinks !== "object" || Array.isArray(halLinks) || halLinks === null)) pm.expect.fail("HAL _links must be an object of link relations");',
|
|
299647
|
+
' if (halLinks) Object.keys(halLinks).forEach(function (rel) { var linkValue = halLinks[rel]; (Array.isArray(linkValue) ? linkValue : [linkValue]).forEach(function (linkObject) { if (!linkObject || typeof linkObject !== "object" || typeof linkObject.href !== "string") pm.expect.fail("HAL link relation " + rel + " must be a Link Object (or array of them) with a string href"); }); });',
|
|
299648
|
+
" var halEmbedded = hal._embedded;",
|
|
299649
|
+
' if (halEmbedded !== undefined && (typeof halEmbedded !== "object" || Array.isArray(halEmbedded) || halEmbedded === null)) pm.expect.fail("HAL _embedded must be an object of resource names");',
|
|
299650
|
+
" }",
|
|
299651
|
+
" }",
|
|
299652
|
+
' if (media.raw === "application/vnd.api+json") {',
|
|
299653
|
+
" var jsonApi; try { jsonApi = JSON.parse(text); } catch (error) { jsonApi = null; }",
|
|
299654
|
+
' if (jsonApi && typeof jsonApi === "object" && !Array.isArray(jsonApi)) {',
|
|
299655
|
+
' if (jsonApi.data === undefined && jsonApi.errors === undefined && jsonApi.meta === undefined) pm.expect.fail("JSON:API documents must contain at least one of data, errors, meta");',
|
|
299656
|
+
' if (jsonApi.data !== undefined && jsonApi.errors !== undefined) pm.expect.fail("JSON:API forbids data and errors in the same document");',
|
|
299657
|
+
" }",
|
|
299658
|
+
" }",
|
|
299659
|
+
' if (media.subtype === "problem+xml") {',
|
|
299660
|
+
' if (text.indexOf("urn:ietf:rfc:7807") === -1) rfcAdvise("application/problem+xml body does not reference the urn:ietf:rfc:7807 namespace");',
|
|
299661
|
+
" var xmlStatus = text.match(/<status[^>]*>\\s*([0-9]+)\\s*<\\/status>/);",
|
|
299662
|
+
' if (xmlStatus && Number(xmlStatus[1]) !== pm.response.code) pm.expect.fail("RFC 9457 status member (" + xmlStatus[1] + ") must match the HTTP status code (" + pm.response.code + ")");',
|
|
299663
|
+
" }",
|
|
299664
|
+
"});",
|
|
299665
|
+
"pm.test('Structured field response headers parse per RFC 8941', function () {",
|
|
299666
|
+
' [["Cache-Status", "list"], ["Proxy-Status", "list"], ["Priority", "dict"], ["RateLimit", "dict"], ["RateLimit-Policy", "dict"], ["Signature", "dict"], ["Signature-Input", "dict"]].forEach(function (pair) {',
|
|
299667
|
+
' var value = rfcHeaderAll(pair[0]).join(", ");',
|
|
299668
|
+
" if (!value) return;",
|
|
299669
|
+
' if (!rfcSfParse(value, pair[1])) pm.expect.fail(pair[0] + " is not a valid RFC 8941 structured field (" + pair[1] + "): " + value);',
|
|
299670
|
+
" });",
|
|
299671
|
+
"});",
|
|
299672
|
+
"pm.test('Content-Digest and Repr-Digest match the response body (RFC 9530)', function () {",
|
|
299673
|
+
" var cryptoLib = null;",
|
|
299674
|
+
' try { cryptoLib = require("crypto-js"); } catch (error) { cryptoLib = null; }',
|
|
299675
|
+
' ["Content-Digest", "Repr-Digest"].forEach(function (name) {',
|
|
299676
|
+
" var value = rfcRespHeader(name);",
|
|
299677
|
+
" if (!value) return;",
|
|
299678
|
+
' if (!rfcSfParse(value, "dict")) { pm.expect.fail(name + " is not a valid RFC 8941 dictionary (RFC 9530): " + value); return; }',
|
|
299679
|
+
' if (!cryptoLib || rfcRespHeader("Content-Encoding")) return;',
|
|
299680
|
+
' var media = mediaParts(rfcRespHeader("Content-Type"));',
|
|
299681
|
+
' if (media.type !== "text" && !isJsonSubtype(media.subtype) && !/xml$/.test(media.subtype)) return;',
|
|
299682
|
+
" rfcSplitList(value).forEach(function (entry) {",
|
|
299683
|
+
" var match = entry.trim().match(/^(sha-256|sha-512)=:([A-Za-z0-9+\\/=]+):$/);",
|
|
299684
|
+
" if (!match) return;",
|
|
299685
|
+
' var computed = match[1] === "sha-256" ? cryptoLib.SHA256(responseText()) : cryptoLib.SHA512(responseText());',
|
|
299686
|
+
" var encoded = cryptoLib.enc.Base64.stringify(computed);",
|
|
299687
|
+
' if (encoded !== match[2]) pm.expect.fail(name + " " + match[1] + " does not match the response body (RFC 9530): computed " + encoded + " but header carries " + match[2]);',
|
|
299688
|
+
" });",
|
|
299689
|
+
" });",
|
|
299690
|
+
"});",
|
|
299691
|
+
"pm.test('Request credentials are well-formed per their authentication scheme RFCs', function () {",
|
|
299692
|
+
' var authorization = requestHeader("Authorization");',
|
|
299693
|
+
' if (authorization && authorization.indexOf("{{") === -1) {',
|
|
299694
|
+
" var schemeMatch = authorization.match(/^(\\S+)(?:\\s+([\\s\\S]*))?$/);",
|
|
299695
|
+
' var authScheme = schemeMatch ? schemeMatch[1].toLowerCase() : "";',
|
|
299696
|
+
' var authParams = schemeMatch && schemeMatch[2] !== undefined ? schemeMatch[2].trim() : "";',
|
|
299697
|
+
' if (authScheme === "basic") {',
|
|
299698
|
+
" var decoded = rfcBase64Decode(authParams);",
|
|
299699
|
+
' if (decoded === null) pm.expect.fail("Basic credentials must be base64 (RFC 7617)");',
|
|
299700
|
+
' else if (decoded.indexOf(":") === -1) pm.expect.fail("Basic credentials must decode to user-id:password (RFC 7617)");',
|
|
299701
|
+
" }",
|
|
299702
|
+
' if (authScheme === "bearer" && !/^[A-Za-z0-9\\-._~+\\/]+=*$/.test(authParams)) pm.expect.fail("Bearer token does not match the b64token grammar (RFC 6750)");',
|
|
299703
|
+
' if (authScheme === "digest") {',
|
|
299704
|
+
' rfcSplitList(authParams).forEach(function (entry) { var param = entry.trim(); if (param && !/^[!#$%&\'*+.^_`|~0-9A-Za-z-]+\\s*=\\s*("([^"\\\\]|\\\\.)*"|[!#$%&\'*+.^_`|~0-9A-Za-z-]+)$/.test(param)) pm.expect.fail("Digest auth-param is malformed (RFC 7616): " + param); });',
|
|
299705
|
+
' var digestResponse = authParams.match(/\\bresponse\\s*=\\s*"?([^",\\s]+)"?/i);',
|
|
299706
|
+
' if (digestResponse && !/^[0-9a-fA-F]+$/.test(digestResponse[1])) pm.expect.fail("Digest response parameter must be hex (RFC 7616): " + digestResponse[1]);',
|
|
299707
|
+
" }",
|
|
299708
|
+
" }",
|
|
299709
|
+
' var wantsJwt = (contract.security || []).some(function (alternative) { return alternative.some(function (check) { return check.prefix === "Bearer " && String(check.bearerFormat || "").toUpperCase() === "JWT"; }); });',
|
|
299710
|
+
' if (wantsJwt && authorization && authorization.indexOf("{{") === -1 && authorization.toLowerCase().indexOf("bearer ") === 0) {',
|
|
299711
|
+
" var jwtToken = authorization.slice(7).trim();",
|
|
299712
|
+
' var jwtSegments = jwtToken.split(".");',
|
|
299713
|
+
' if (jwtSegments.length !== 3) pm.expect.fail("bearerFormat JWT tokens must have three base64url segments (RFC 7519); got " + jwtSegments.length);',
|
|
299714
|
+
' else if (!jwtSegments.every(function (segment) { return /^[A-Za-z0-9_-]+$/.test(segment); })) pm.expect.fail("JWT segments must be base64url (RFC 7515)");',
|
|
299715
|
+
" else {",
|
|
299716
|
+
' var jwtDecode = function (segment) { var padded = segment.replace(/-/g, "+").replace(/_/g, "/"); while (padded.length % 4 !== 0) padded += "="; return rfcBase64Decode(padded); };',
|
|
299717
|
+
" var jwtHeader = null; var jwtPayload = null;",
|
|
299718
|
+
' try { jwtHeader = JSON.parse(jwtDecode(jwtSegments[0])); } catch (error) { pm.expect.fail("JWT header segment does not decode to JSON (RFC 7515)"); }',
|
|
299719
|
+
' try { jwtPayload = JSON.parse(jwtDecode(jwtSegments[1])); } catch (error) { pm.expect.fail("JWT payload segment does not decode to JSON (RFC 7519)"); }',
|
|
299720
|
+
' if (jwtHeader && typeof jwtHeader.alg !== "string") pm.expect.fail("JWT header must carry a string alg member (RFC 7515)");',
|
|
299721
|
+
" if (jwtPayload) {",
|
|
299722
|
+
' ["exp", "nbf", "iat"].forEach(function (claim) { if (jwtPayload[claim] !== undefined && typeof jwtPayload[claim] !== "number") pm.expect.fail("JWT " + claim + " claim must be numeric (RFC 7519)"); });',
|
|
299723
|
+
' if (typeof jwtPayload.exp === "number" && jwtPayload.exp * 1000 < Date.now()) rfcAdvise("RFC 7519: the outgoing JWT exp claim is already in the past");',
|
|
299724
|
+
" }",
|
|
299725
|
+
" }",
|
|
299726
|
+
" }",
|
|
299727
|
+
' if (hasQueryParam("access_token")) rfcAdvise("RFC 6750: bearer tokens SHOULD NOT travel in the query string");',
|
|
299728
|
+
" (contract.security || []).forEach(function (alternative) {",
|
|
299729
|
+
" alternative.forEach(function (check) {",
|
|
299730
|
+
" if (!check.checkable || !check.name) return;",
|
|
299731
|
+
' if (check.in === "query") { if (hasQueryParam(check.name)) rfcAdvise("Security scheme " + check.scheme + " sends credentials in the query string"); return; }',
|
|
299732
|
+
' if (check.in !== "header" || String(check.name).toLowerCase() === "authorization") return;',
|
|
299733
|
+
" var apiKeyValue = requestHeader(check.name);",
|
|
299734
|
+
' if (!apiKeyValue || apiKeyValue.indexOf("{{") !== -1) return;',
|
|
299735
|
+
' if (apiKeyValue !== apiKeyValue.trim()) pm.expect.fail("API key header " + check.name + " carries leading or trailing whitespace");',
|
|
299736
|
+
' if (!rfcIsFieldContent(apiKeyValue)) pm.expect.fail("API key header " + check.name + " contains characters forbidden by RFC 9110 field-content");',
|
|
299737
|
+
" });",
|
|
299738
|
+
" });",
|
|
299739
|
+
"});",
|
|
299740
|
+
"pm.test('Request preconditions, preferences, and patch bodies follow their RFCs', function () {",
|
|
299741
|
+
' ["If-Match", "If-None-Match"].forEach(function (name) {',
|
|
299742
|
+
" var value = requestHeader(name);",
|
|
299743
|
+
' if (!value || value.indexOf("{{") !== -1 || value.trim() === "*") return;',
|
|
299744
|
+
' rfcSplitList(value).forEach(function (entry) { if (entry.trim() && !rfcIsEntityTag(entry.trim())) pm.expect.fail(name + " must be * or a list of entity-tags (RFC 9110): " + entry.trim()); });',
|
|
299745
|
+
" });",
|
|
299746
|
+
' var prefer = requestHeader("Prefer");',
|
|
299747
|
+
' if (prefer && prefer.indexOf("{{") === -1) {',
|
|
299748
|
+
' rfcSplitList(prefer).forEach(function (entry) { var token = entry.split("=")[0].split(";")[0].trim(); if (token && !rfcIsToken(token)) pm.expect.fail("Prefer preference name must be a token (RFC 7240): " + entry.trim()); });',
|
|
299749
|
+
" }",
|
|
299750
|
+
' var requestContentType = mediaBase(requestHeader("Content-Type"));',
|
|
299751
|
+
" var body = pm.request.body;",
|
|
299752
|
+
' var raw = body && body.mode === "raw" && typeof body.raw === "string" ? body.raw : "";',
|
|
299753
|
+
' if (!raw.trim() || raw.indexOf("{{") !== -1 || /"<[^"<>]*>"/.test(raw)) return;',
|
|
299754
|
+
' if (requestContentType === "application/json-patch+json") {',
|
|
299755
|
+
' var patch; try { patch = JSON.parse(raw); } catch (error) { if (/<[A-Za-z][A-Za-z0-9_ -]*>/.test(raw)) return; pm.expect.fail("application/json-patch+json request body is not valid JSON (RFC 6902): " + error); return; }',
|
|
299756
|
+
' if (!Array.isArray(patch)) { pm.expect.fail("A JSON Patch document must be an array of operations (RFC 6902)"); return; }',
|
|
299757
|
+
" patch.forEach(function (operation, operationIndex) {",
|
|
299758
|
+
' if (!operation || typeof operation !== "object" || Array.isArray(operation)) { pm.expect.fail("JSON Patch operation " + operationIndex + " must be an object (RFC 6902)"); return; }',
|
|
299759
|
+
' if (["add", "remove", "replace", "move", "copy", "test"].indexOf(operation.op) === -1) pm.expect.fail("JSON Patch operation " + operationIndex + " has an invalid op (RFC 6902): " + operation.op);',
|
|
299760
|
+
" var pointerPattern = /^(\\/([^\\/~]|~[01])*)*$/;",
|
|
299761
|
+
' if (typeof operation.path !== "string" || !pointerPattern.test(operation.path)) pm.expect.fail("JSON Patch operation " + operationIndex + " path must be an RFC 6901 JSON Pointer");',
|
|
299762
|
+
' if (["add", "replace", "test"].indexOf(operation.op) !== -1 && operation.value === undefined) pm.expect.fail("JSON Patch " + operation.op + " operation " + operationIndex + " requires a value member (RFC 6902)");',
|
|
299763
|
+
' if (["move", "copy"].indexOf(operation.op) !== -1 && (typeof operation.from !== "string" || !pointerPattern.test(operation.from))) pm.expect.fail("JSON Patch " + operation.op + " operation " + operationIndex + " requires an RFC 6901 from pointer (RFC 6902)");',
|
|
299764
|
+
" });",
|
|
299765
|
+
" }",
|
|
299766
|
+
' if (requestContentType === "application/merge-patch+json") {',
|
|
299767
|
+
' try { JSON.parse(raw); } catch (error) { if (/<[A-Za-z][A-Za-z0-9_ -]*>/.test(raw)) return; pm.expect.fail("application/merge-patch+json request body must be valid JSON (RFC 7386): " + error); }',
|
|
299768
|
+
" }",
|
|
299769
|
+
"});",
|
|
299770
|
+
"pm.test('Deprecated operation signals deprecation in the response', function () {",
|
|
299771
|
+
" if (!contract.deprecated) return;",
|
|
299772
|
+
' if (!rfcRespHeader("Deprecation") && !rfcRespHeader("Sunset")) rfcAdvise("RFC 9745: the OpenAPI document deprecates this operation but the response carries neither Deprecation nor Sunset");',
|
|
299773
|
+
"});",
|
|
299774
|
+
"pm.test('OpenAPI link expressions resolve against the response', function () {",
|
|
299775
|
+
" if (!selected || !selected.value.links || selected.value.links.length === 0) return;",
|
|
299776
|
+
" var linkBody = null; var linkBodyParsed = false;",
|
|
299777
|
+
" selected.value.links.forEach(function (expression) {",
|
|
299778
|
+
' if (expression.kind === "header") {',
|
|
299779
|
+
' if (!pm.response.headers.get(expression.header)) pm.expect.fail("OpenAPI link " + expression.link + " references response header " + expression.header + " which is absent");',
|
|
299780
|
+
" return;",
|
|
299781
|
+
" }",
|
|
299782
|
+
" if (!linkBodyParsed) { linkBodyParsed = true; try { linkBody = JSON.parse(responseText()); } catch (error) { linkBody = null; } }",
|
|
299783
|
+
' if (linkBody === null) { pm.expect.fail("OpenAPI link " + expression.link + " references the response body but the body is not JSON"); return; }',
|
|
299784
|
+
" var target = linkBody;",
|
|
299785
|
+
' var tokens = String(expression.pointer).split("/").slice(1).map(function (token) { return token.replace(/~1/g, "/").replace(/~0/g, "~"); });',
|
|
299786
|
+
" for (var t = 0; t < tokens.length; t += 1) {",
|
|
299787
|
+
' if (target !== null && typeof target === "object") target = Array.isArray(target) ? target[Number(tokens[t])] : target[tokens[t]];',
|
|
299788
|
+
" else { target = undefined; break; }",
|
|
299789
|
+
" }",
|
|
299790
|
+
' if (target === undefined) pm.expect.fail("OpenAPI link " + expression.link + " expression $response.body#" + expression.pointer + " does not resolve in the response body");',
|
|
299791
|
+
" });",
|
|
299792
|
+
"});",
|
|
299793
|
+
"pm.test('Request URL conforms to an OpenAPI servers entry', function () {",
|
|
299794
|
+
" if (!contract.servers || contract.servers.length === 0) return;",
|
|
299795
|
+
' var requestUrl = "";',
|
|
299796
|
+
' try { requestUrl = String(pm.request.url.toString()); } catch (ignored) { requestUrl = ""; }',
|
|
299797
|
+
' if (!requestUrl || requestUrl.indexOf("{{") !== -1) return;',
|
|
299798
|
+
' var pathOnly = requestUrl.replace(/^[a-z][a-z0-9+.-]*:\\/\\/[^\\/]+/i, "");',
|
|
299799
|
+
' var matched = contract.servers.some(function (pattern) { try { var serverPattern = new RegExp(pattern, "i"); return serverPattern.test(requestUrl) || serverPattern.test(pathOnly); } catch (ignored) { return true; } });',
|
|
299800
|
+
' if (!matched) rfcAdvise("Request URL does not match any OpenAPI servers entry: " + requestUrl);',
|
|
299801
|
+
"});",
|
|
299069
299802
|
...operation.security ? [
|
|
299070
299803
|
"pm.test('Request carries credentials required by OpenAPI security', function () {",
|
|
299071
299804
|
" function satisfied(check) {",
|
|
@@ -299105,6 +299838,12 @@ function createContractScript(operation, warnings = []) {
|
|
|
299105
299838
|
' if (param.allowEmptyValue && entries.length === 1 && entries[0] === "") return;',
|
|
299106
299839
|
" if (entries.some(isPlaceholder)) return;",
|
|
299107
299840
|
" value = entries.map(function (entry) { return coerceBySchema(decodeComponent(entry), param.items); });",
|
|
299841
|
+
' } else if (param.decode === "deepObject") {',
|
|
299842
|
+
" var deepValue = {}; var deepFound = false; var deepPlaceholder = false;",
|
|
299843
|
+
' pm.request.url.query.each(function (queryParam) { if (!queryParam || queryParam.disabled === true) return; var deepMatch = String(queryParam.key).match(/^([^\\[]+)\\[([^\\]]+)\\]$/); if (!deepMatch || deepMatch[1].toLowerCase() !== String(param.name).toLowerCase()) return; deepFound = true; var deepRaw = queryParam.value === null || queryParam.value === undefined ? "" : String(queryParam.value); if (isPlaceholder(deepRaw)) { deepPlaceholder = true; return; } deepValue[deepMatch[2]] = coerceBySchema(decodeComponent(deepRaw), (param.schema && param.schema.properties && param.schema.properties[deepMatch[2]]) || {}); });',
|
|
299844
|
+
' if (!deepFound) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
299845
|
+
" if (deepPlaceholder) return;",
|
|
299846
|
+
" value = deepValue;",
|
|
299108
299847
|
" } else if (param.decode) {",
|
|
299109
299848
|
' var joined = param.in === "query" ? queryValue(String(param.name).toLowerCase()) : headerValue(param.name);',
|
|
299110
299849
|
' if (joined === undefined) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
@@ -299121,6 +299860,8 @@ function createContractScript(operation, warnings = []) {
|
|
|
299121
299860
|
' } else if (param.in === "path") {',
|
|
299122
299861
|
" value = pathParamValue(param.name);",
|
|
299123
299862
|
" if (value === undefined) return;",
|
|
299863
|
+
' if (param.pathStyle === "label") { if (String(value).charAt(0) !== ".") return; value = String(value).slice(1); }',
|
|
299864
|
+
' if (param.pathStyle === "matrix") { var matrixPrefix = ";" + param.name + "="; if (String(value).indexOf(matrixPrefix) !== 0) return; value = String(value).slice(matrixPrefix.length); }',
|
|
299124
299865
|
' if (isPlaceholder(value) || value.charAt(0) === ":" || value.charAt(0) === "{") return;',
|
|
299125
299866
|
" value = coerceBySchema(value, param.schema);",
|
|
299126
299867
|
' } else if (param.in === "cookie") {',
|
|
@@ -299172,6 +299913,9 @@ function createContractScript(operation, warnings = []) {
|
|
|
299172
299913
|
' if (pm.response.headers.get("Content-Encoding")) return;',
|
|
299173
299914
|
" var mustBeEmpty = isBodyless() || (selected && Object.keys(selected.value.content || {}).length === 0);",
|
|
299174
299915
|
' if (mustBeEmpty && Number(String(raw).trim()) !== 0) pm.expect.fail("OpenAPI defines no response body for " + contract.method + " " + contract.path + " status " + pm.response.code + " but Content-Length was " + raw);',
|
|
299916
|
+
"});",
|
|
299917
|
+
"pm.test('RFC SHOULD-level advisories are documented', function () {",
|
|
299918
|
+
' pm.expect(rfcAdvisories, "SHOULD-level findings (advisory, non-failing): " + rfcAdvisories.join("; ")).to.be.an("array");',
|
|
299175
299919
|
"});"
|
|
299176
299920
|
];
|
|
299177
299921
|
}
|
|
@@ -299241,6 +299985,9 @@ function assertStaticRequestShape(operation, request) {
|
|
|
299241
299985
|
}
|
|
299242
299986
|
}
|
|
299243
299987
|
const warnings = collectStaticBodyWarnings(operation, request, contentType2);
|
|
299988
|
+
if (["GET", "HEAD", "DELETE"].includes(operation.method) && hasRequestBody(request)) {
|
|
299989
|
+
warnings.push(`CONTRACT_METHOD_BODY_SEMANTICS: ${operation.id} sends a request body with ${operation.method}; RFC 9110 defines no request-body semantics for this method`);
|
|
299990
|
+
}
|
|
299244
299991
|
if (operation.requestBody && !operation.requestBody.required && operation.requestBody.contentTypes.length > 0 && hasRequestBody(request) && contentType2) {
|
|
299245
299992
|
const actual = contentType2.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
299246
299993
|
const matches = operation.requestBody.contentTypes.some((expected) => mediaTypeMatchesPattern(expected.toLowerCase(), actual));
|
|
@@ -299495,6 +300242,15 @@ function asRecord7(value) {
|
|
|
299495
300242
|
}
|
|
299496
300243
|
return value;
|
|
299497
300244
|
}
|
|
300245
|
+
function adviseWorkspaceFlipForbidden(error2) {
|
|
300246
|
+
if (error2 instanceof HttpError && error2.status === 403) {
|
|
300247
|
+
const body = error2.responseBody || "";
|
|
300248
|
+
if (/addWorkspaceLevelTeamRoles/i.test(body) || /You are not authorized to perform this action/i.test(body)) {
|
|
300249
|
+
return new Error(WORKSPACE_PERSONAL_ONLY_ADVICE, { cause: error2 });
|
|
300250
|
+
}
|
|
300251
|
+
}
|
|
300252
|
+
return error2;
|
|
300253
|
+
}
|
|
299498
300254
|
function extractGitRepoUrl(value) {
|
|
299499
300255
|
if (!value) return null;
|
|
299500
300256
|
if (typeof value === "string") {
|
|
@@ -299800,7 +300556,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
299800
300556
|
}
|
|
299801
300557
|
} catch (error2) {
|
|
299802
300558
|
await this.deleteWorkspace(workspaceId).catch(() => void 0);
|
|
299803
|
-
throw error2;
|
|
300559
|
+
throw adviseWorkspaceFlipForbidden(error2);
|
|
299804
300560
|
}
|
|
299805
300561
|
return { id: workspaceId };
|
|
299806
300562
|
}
|
|
@@ -301057,7 +301813,7 @@ function resolveActionVersion(explicit) {
|
|
|
301057
301813
|
if (explicit) {
|
|
301058
301814
|
return explicit;
|
|
301059
301815
|
}
|
|
301060
|
-
return "
|
|
301816
|
+
return typeof __ACTION_VERSION__ !== "undefined" && __ACTION_VERSION__ ? __ACTION_VERSION__ : "unknown";
|
|
301061
301817
|
}
|
|
301062
301818
|
function telemetryDisabled(env) {
|
|
301063
301819
|
const flag = String(env.POSTMAN_ACTIONS_TELEMETRY ?? "").trim().toLowerCase();
|
|
@@ -301179,11 +301935,23 @@ function createTelemetryContext(options) {
|
|
|
301179
301935
|
};
|
|
301180
301936
|
}
|
|
301181
301937
|
|
|
301182
|
-
// src/
|
|
301938
|
+
// src/action-version.ts
|
|
301183
301939
|
var import_node_fs3 = require("node:fs");
|
|
301940
|
+
var import_node_path3 = require("node:path");
|
|
301941
|
+
function resolveActionVersion2() {
|
|
301942
|
+
try {
|
|
301943
|
+
const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(__dirname, "..", "package.json"), "utf8");
|
|
301944
|
+
return JSON.parse(raw).version ?? "unknown";
|
|
301945
|
+
} catch {
|
|
301946
|
+
return "unknown";
|
|
301947
|
+
}
|
|
301948
|
+
}
|
|
301949
|
+
|
|
301950
|
+
// src/lib/spec/openapi-loader.ts
|
|
301951
|
+
var import_node_fs4 = require("node:fs");
|
|
301184
301952
|
var import_promises3 = require("node:fs/promises");
|
|
301185
301953
|
var import_node_url2 = require("node:url");
|
|
301186
|
-
var
|
|
301954
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
301187
301955
|
|
|
301188
301956
|
// node_modules/@apidevtools/json-schema-ref-parser/dist/lib/util/convert-path-to-posix.js
|
|
301189
301957
|
var win32Sep = "\\";
|
|
@@ -301524,14 +302292,14 @@ function fromFileSystemPath(path10) {
|
|
|
301524
302292
|
const hasProjectUri = upperPath.includes(posixUpper);
|
|
301525
302293
|
const isAbsolutePath = isAbsoluteWin32Path.test(path10) || path10.startsWith("http://") || path10.startsWith("https://") || path10.startsWith("file://");
|
|
301526
302294
|
if (!(hasProjectDir || hasProjectUri || isAbsolutePath) && !projectDir.startsWith("http")) {
|
|
301527
|
-
const
|
|
302295
|
+
const join4 = (a, b) => {
|
|
301528
302296
|
if (a.endsWith("/") || a.endsWith("\\")) {
|
|
301529
302297
|
return a + b;
|
|
301530
302298
|
} else {
|
|
301531
302299
|
return a + "/" + b;
|
|
301532
302300
|
}
|
|
301533
302301
|
};
|
|
301534
|
-
path10 =
|
|
302302
|
+
path10 = join4(projectDir, path10);
|
|
301535
302303
|
}
|
|
301536
302304
|
path10 = convertPathToPosix(path10);
|
|
301537
302305
|
}
|
|
@@ -305646,6 +306414,7 @@ function inventory$Ref($refParent, $refKey, path10, scopeBase, dynamicIdScope, p
|
|
|
305646
306414
|
const file = stripHash(pointer.path);
|
|
305647
306415
|
const hash = getHash(pointer.path);
|
|
305648
306416
|
const external = file !== $refs._root$Ref.path && !$refs._aliases[file];
|
|
306417
|
+
const nestedResource = Boolean($refs._aliases[file]) && pointer.$ref.value !== $refs._root$Ref.value;
|
|
305649
306418
|
const extended = ref_default.isExtended$Ref($ref);
|
|
305650
306419
|
indirections += pointer.indirections;
|
|
305651
306420
|
const existingEntry = findInInventory(inventory, $refParent, $refKey);
|
|
@@ -305679,6 +306448,8 @@ function inventory$Ref($refParent, $refKey, path10, scopeBase, dynamicIdScope, p
|
|
|
305679
306448
|
// Does this $ref extend its resolved value? (i.e. it has extra properties, in addition to "$ref")
|
|
305680
306449
|
external,
|
|
305681
306450
|
// Does this $ref pointer point to a file other than the main JSON Schema file?
|
|
306451
|
+
nestedResource,
|
|
306452
|
+
// Does this $ref resolve to an embedded schema resource with its own $id?
|
|
305682
306453
|
indirections
|
|
305683
306454
|
// The number of indirect references that were traversed to resolve the value
|
|
305684
306455
|
});
|
|
@@ -305714,7 +306485,7 @@ function remap(inventory, options, rootId) {
|
|
|
305714
306485
|
for (const entry of inventory) {
|
|
305715
306486
|
const bundleOpts = options.bundle || {};
|
|
305716
306487
|
if (!entry.external) {
|
|
305717
|
-
if (bundleOpts.optimizeInternalRefs !== false) {
|
|
306488
|
+
if (bundleOpts.optimizeInternalRefs !== false && !entry.nestedResource) {
|
|
305718
306489
|
entry.$ref.$ref = entry.hash;
|
|
305719
306490
|
}
|
|
305720
306491
|
} else if (entry.file === file && entry.hash === hash) {
|
|
@@ -313518,22 +314289,22 @@ async function loadOpenApiContractSpec(specUrl, options = {}) {
|
|
|
313518
314289
|
async function loadOpenApiContractSpecFromPath(specPath, options = {}) {
|
|
313519
314290
|
if (!specPath) throw new Error("CONTRACT_SPEC_READ_FAILED: spec-path must not be empty");
|
|
313520
314291
|
const workspaceRoot = (() => {
|
|
313521
|
-
const root =
|
|
314292
|
+
const root = import_node_path4.default.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
|
|
313522
314293
|
try {
|
|
313523
|
-
return (0,
|
|
314294
|
+
return (0, import_node_fs4.realpathSync)(root);
|
|
313524
314295
|
} catch {
|
|
313525
314296
|
return root;
|
|
313526
314297
|
}
|
|
313527
314298
|
})();
|
|
313528
|
-
const resolved =
|
|
314299
|
+
const resolved = import_node_path4.default.resolve(workspaceRoot, specPath);
|
|
313529
314300
|
let absolutePath;
|
|
313530
314301
|
try {
|
|
313531
|
-
absolutePath = (0,
|
|
314302
|
+
absolutePath = (0, import_node_fs4.realpathSync)(resolved);
|
|
313532
314303
|
} catch (error2) {
|
|
313533
314304
|
throw new Error(`CONTRACT_SPEC_READ_FAILED: Unable to read spec at ${specPath}`, { cause: error2 });
|
|
313534
314305
|
}
|
|
313535
|
-
const rel =
|
|
313536
|
-
if (!rel || rel.startsWith("..") ||
|
|
314306
|
+
const rel = import_node_path4.default.relative(workspaceRoot, absolutePath);
|
|
314307
|
+
if (!rel || rel.startsWith("..") || import_node_path4.default.isAbsolute(rel)) {
|
|
313537
314308
|
throw new Error(`CONTRACT_SPEC_READ_FAILED: spec-path must resolve inside ${workspaceRoot}, got: ${specPath}`);
|
|
313538
314309
|
}
|
|
313539
314310
|
const maxBytes = options.maxBytesPerResource ?? SAFE_FETCH_LIMITS.maxBytesPerResource;
|
|
@@ -313947,6 +314718,17 @@ function buildOperationScript(operation, index, warnings) {
|
|
|
313947
314718
|
' pm.expect(pm.response.code, "GraphQL responses are HTTP 200 even when the data field carries errors").to.be.below(500);',
|
|
313948
314719
|
"});"
|
|
313949
314720
|
);
|
|
314721
|
+
lines.push(
|
|
314722
|
+
"pm.test(" + JSON.stringify("[" + label + "] GraphQL-over-HTTP media type and status are consistent") + ", function () {",
|
|
314723
|
+
' var contentType = ((pm.response.headers && pm.response.headers.get && pm.response.headers.get("Content-Type")) || "").toLowerCase();',
|
|
314724
|
+
' var mediaType = contentType.split(";")[0].trim();',
|
|
314725
|
+
" if (!mediaType) return;",
|
|
314726
|
+
' if (mediaType !== "application/graphql-response+json" && mediaType !== "application/json") { pm.expect.fail("GraphQL-over-HTTP responses use application/graphql-response+json or application/json; got: " + (mediaType || "<missing>")); }',
|
|
314727
|
+
" var wellFormed = gqlBody.data !== undefined || Array.isArray(gqlBody.errors);",
|
|
314728
|
+
' if (mediaType === "application/graphql-response+json" && pm.response.code >= 200 && pm.response.code < 300 && !wellFormed) { pm.expect.fail("application/graphql-response+json forbids a 2xx status when the body is not a well-formed GraphQL response"); }',
|
|
314729
|
+
' if (mediaType === "application/json" && gqlBody.data !== undefined && gqlBody.data !== null && pm.response.code !== 200) { pm.expect.fail("a GraphQL response carrying data over application/json must be HTTP 200; got " + pm.response.code); }',
|
|
314730
|
+
"});"
|
|
314731
|
+
);
|
|
313950
314732
|
lines.push(
|
|
313951
314733
|
`pm.test(${JSON.stringify(`[${label}] GraphQL errors are well-formed and not a total failure`)}, function () {`,
|
|
313952
314734
|
" var errors = gqlBody.errors;",
|
|
@@ -315487,6 +316269,8 @@ function createSoapScript(operation, warnings = []) {
|
|
|
315487
316269
|
hasOutput: Boolean(operation.output)
|
|
315488
316270
|
};
|
|
315489
316271
|
const responseRegex = operation.expectedResponseElement ? elementPresenceRegex(operation.expectedResponseElement) : "";
|
|
316272
|
+
const mediaType = operation.soapVersion === "1.2" ? "application/soap+xml" : "text/xml";
|
|
316273
|
+
const faultStatusLine = operation.soapVersion === "1.2" ? ' if (faulted && code !== 500 && code !== 400) pm.expect.fail("SOAP 1.2 Faults ride HTTP 500, or 400 for env:Sender faults (SOAP 1.2 Part 2 HTTP binding); got HTTP " + code);' : ' if (faulted && code !== 500) pm.expect.fail("SOAP 1.1 Faults must ride HTTP 500 (WS-I Basic Profile R1126); got HTTP " + code);';
|
|
315490
316274
|
const lines = [
|
|
315491
316275
|
`var soap = JSON.parse(${JSON.stringify(JSON.stringify(meta))});`,
|
|
315492
316276
|
'var bodyText = (pm.response.text && pm.response.text()) || "";',
|
|
@@ -315497,9 +316281,11 @@ function createSoapScript(operation, warnings = []) {
|
|
|
315497
316281
|
" pm.response.to.have.status(200);",
|
|
315498
316282
|
"});",
|
|
315499
316283
|
"",
|
|
315500
|
-
|
|
316284
|
+
// SOAP 1.1 responses bind to text/xml (SOAP 1.1 HTTP binding, WS-I Basic
|
|
316285
|
+
// Profile); SOAP 1.2 responses bind to application/soap+xml (RFC 3902).
|
|
316286
|
+
`pm.test('SOAP response Content-Type matches the SOAP ${operation.soapVersion} binding', function () {`,
|
|
315501
316287
|
' var ct = header("Content-Type").toLowerCase();',
|
|
315502
|
-
|
|
316288
|
+
` pm.expect(ct, "SOAP ${operation.soapVersion} responses use ${mediaType} (got: " + (ct || "<missing>") + ")").to.include("${mediaType}");`,
|
|
315503
316289
|
"});",
|
|
315504
316290
|
"",
|
|
315505
316291
|
"pm.test('SOAP Envelope element is present', function () {",
|
|
@@ -315516,6 +316302,13 @@ function createSoapScript(operation, warnings = []) {
|
|
|
315516
316302
|
' var detail = (bodyText.match(/<(?:[A-Za-z_][\\w.-]*:)?(?:faultstring|Reason|Text)[^>]*>([\\s\\S]*?)<\\//) || [])[1] || "";',
|
|
315517
316303
|
' pm.expect.fail("SOAP Fault returned for operation " + soap.name + (detail ? (": " + detail.trim()) : ""));',
|
|
315518
316304
|
" }",
|
|
316305
|
+
"});",
|
|
316306
|
+
"",
|
|
316307
|
+
"pm.test('SOAP Fault and HTTP status are consistent', function () {",
|
|
316308
|
+
' var faulted = matchTag("Fault").test(bodyText);',
|
|
316309
|
+
" var code = pm.response.code;",
|
|
316310
|
+
faultStatusLine,
|
|
316311
|
+
' if (!faulted && code === 500) pm.expect.fail("HTTP 500 from a SOAP endpoint must carry a SOAP Fault in the body");',
|
|
315519
316312
|
"});"
|
|
315520
316313
|
];
|
|
315521
316314
|
if (responseRegex) {
|
|
@@ -316767,6 +317560,7 @@ function normalizeSpecDocument(raw, warn) {
|
|
|
316767
317560
|
async function runBootstrap(inputs, dependencies) {
|
|
316768
317561
|
const telemetry = createTelemetryContext({
|
|
316769
317562
|
action: "postman-bootstrap-action",
|
|
317563
|
+
actionVersion: resolveActionVersion2(),
|
|
316770
317564
|
logger: dependencies.core
|
|
316771
317565
|
});
|
|
316772
317566
|
try {
|
|
@@ -317173,7 +317967,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
317173
317967
|
async () => {
|
|
317174
317968
|
if (inputs.specPath) {
|
|
317175
317969
|
const workspaceRoot = path9.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
|
|
317176
|
-
return (0,
|
|
317970
|
+
return (0, import_node_fs5.readFileSync)(path9.resolve(workspaceRoot, inputs.specPath), "utf8");
|
|
317177
317971
|
}
|
|
317178
317972
|
if (dependencies.specFetcher === fetch) {
|
|
317179
317973
|
return safeFetchText(inputs.specUrl, { depth: 0 });
|