@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/index.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;
|
|
@@ -294687,7 +294687,7 @@ function getIDToken(aud) {
|
|
|
294687
294687
|
|
|
294688
294688
|
// src/index.ts
|
|
294689
294689
|
var import_node_crypto4 = require("node:crypto");
|
|
294690
|
-
var
|
|
294690
|
+
var import_node_fs5 = require("node:fs");
|
|
294691
294691
|
var path9 = __toESM(require("node:path"), 1);
|
|
294692
294692
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
294693
294693
|
|
|
@@ -296241,12 +296241,62 @@ function resolvePostmanEndpointProfile(stack, region = "us") {
|
|
|
296241
296241
|
|
|
296242
296242
|
// src/lib/postman/credential-identity.ts
|
|
296243
296243
|
var sessionPath = "/api/sessions/current";
|
|
296244
|
+
var SESSION_MAX_ATTEMPTS = 3;
|
|
296245
|
+
var SESSION_RETRY_BASE_DELAY_MS = 500;
|
|
296246
|
+
var SESSION_RETRY_MAX_DELAY_MS = 8e3;
|
|
296244
296247
|
var pmakMemo = /* @__PURE__ */ new Map();
|
|
296245
296248
|
var sessionMemo = /* @__PURE__ */ new Map();
|
|
296246
296249
|
var memoizedSessionIdentity;
|
|
296250
|
+
var memoizedSessionFailure;
|
|
296251
|
+
function defaultSessionSleep(ms) {
|
|
296252
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
296253
|
+
}
|
|
296254
|
+
function defaultRandom() {
|
|
296255
|
+
return Math.random();
|
|
296256
|
+
}
|
|
296257
|
+
function parseRetryAfterMs(value) {
|
|
296258
|
+
const trimmed = value?.trim();
|
|
296259
|
+
if (!trimmed) {
|
|
296260
|
+
return void 0;
|
|
296261
|
+
}
|
|
296262
|
+
if (/^\d+$/.test(trimmed)) {
|
|
296263
|
+
return Number(trimmed) * 1e3;
|
|
296264
|
+
}
|
|
296265
|
+
const dateMs = Date.parse(trimmed);
|
|
296266
|
+
if (!Number.isNaN(dateMs)) {
|
|
296267
|
+
return Math.max(0, dateMs - Date.now());
|
|
296268
|
+
}
|
|
296269
|
+
return void 0;
|
|
296270
|
+
}
|
|
296271
|
+
function parseRateLimitResetMs(value) {
|
|
296272
|
+
const trimmed = value?.trim();
|
|
296273
|
+
if (!trimmed || !/^\d+$/.test(trimmed)) {
|
|
296274
|
+
return void 0;
|
|
296275
|
+
}
|
|
296276
|
+
const seconds = Number(trimmed);
|
|
296277
|
+
const nowSeconds = Date.now() / 1e3;
|
|
296278
|
+
if (seconds > nowSeconds) {
|
|
296279
|
+
return Math.max(0, (seconds - nowSeconds) * 1e3);
|
|
296280
|
+
}
|
|
296281
|
+
return seconds * 1e3;
|
|
296282
|
+
}
|
|
296283
|
+
function computeSessionRetryDelayMs(response, attempt, random) {
|
|
296284
|
+
const headers = response?.headers;
|
|
296285
|
+
const signal = parseRetryAfterMs(headers?.get("retry-after") ?? null) ?? parseRateLimitResetMs(
|
|
296286
|
+
headers?.get("ratelimit-reset") ?? headers?.get("x-ratelimit-reset") ?? null
|
|
296287
|
+
);
|
|
296288
|
+
if (signal !== void 0) {
|
|
296289
|
+
return Math.min(Math.max(0, signal), SESSION_RETRY_MAX_DELAY_MS);
|
|
296290
|
+
}
|
|
296291
|
+
const ceiling = Math.min(SESSION_RETRY_MAX_DELAY_MS, SESSION_RETRY_BASE_DELAY_MS * 2 ** (attempt - 1));
|
|
296292
|
+
return Math.round(random() * ceiling);
|
|
296293
|
+
}
|
|
296247
296294
|
function getMemoizedSessionIdentity() {
|
|
296248
296295
|
return memoizedSessionIdentity;
|
|
296249
296296
|
}
|
|
296297
|
+
function getSessionResolutionFailure() {
|
|
296298
|
+
return memoizedSessionFailure;
|
|
296299
|
+
}
|
|
296250
296300
|
function asRecord2(value) {
|
|
296251
296301
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
296252
296302
|
return void 0;
|
|
@@ -296315,46 +296365,90 @@ async function resolveSessionIdentity(opts) {
|
|
|
296315
296365
|
const memoKey = `${baseUrl}::${accessToken}`;
|
|
296316
296366
|
let pending = sessionMemo.get(memoKey);
|
|
296317
296367
|
if (!pending) {
|
|
296318
|
-
pending = probeSessionIdentity(
|
|
296368
|
+
pending = probeSessionIdentity(
|
|
296369
|
+
baseUrl,
|
|
296370
|
+
accessToken,
|
|
296371
|
+
opts.fetchImpl ?? fetch,
|
|
296372
|
+
Math.max(1, opts.maxAttempts ?? SESSION_MAX_ATTEMPTS),
|
|
296373
|
+
opts.sleepImpl ?? defaultSessionSleep,
|
|
296374
|
+
opts.randomImpl ?? defaultRandom
|
|
296375
|
+
);
|
|
296319
296376
|
sessionMemo.set(memoKey, pending);
|
|
296320
296377
|
}
|
|
296321
296378
|
return pending;
|
|
296322
296379
|
}
|
|
296323
|
-
async function
|
|
296380
|
+
async function parseSessionResponse(response) {
|
|
296381
|
+
let payload;
|
|
296324
296382
|
try {
|
|
296325
|
-
|
|
296326
|
-
method: "GET",
|
|
296327
|
-
headers: { "x-access-token": accessToken }
|
|
296328
|
-
});
|
|
296329
|
-
if (!response.ok) {
|
|
296330
|
-
return void 0;
|
|
296331
|
-
}
|
|
296332
|
-
const payload = asRecord2(await response.json());
|
|
296333
|
-
if (!payload) {
|
|
296334
|
-
return void 0;
|
|
296335
|
-
}
|
|
296336
|
-
const root = asRecord2(payload.session) ?? payload;
|
|
296337
|
-
const identity = asRecord2(root.identity);
|
|
296338
|
-
const data = asRecord2(root.data);
|
|
296339
|
-
const user = asRecord2(data?.user);
|
|
296340
|
-
const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
|
|
296341
|
-
const singleRole = coerceText(user?.role);
|
|
296342
|
-
const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
|
|
296343
|
-
const resolved = {
|
|
296344
|
-
source: "iapub/sessions",
|
|
296345
|
-
userId: coerceId(identity?.user) ?? coerceId(user?.id),
|
|
296346
|
-
fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
|
|
296347
|
-
teamId: coerceId(identity?.team),
|
|
296348
|
-
teamName: coerceText(user?.teamName),
|
|
296349
|
-
teamDomain: coerceText(identity?.domain),
|
|
296350
|
-
...roles ? { roles } : {},
|
|
296351
|
-
consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
|
|
296352
|
-
};
|
|
296353
|
-
memoizedSessionIdentity = resolved;
|
|
296354
|
-
return resolved;
|
|
296383
|
+
payload = asRecord2(await response.json());
|
|
296355
296384
|
} catch {
|
|
296356
296385
|
return void 0;
|
|
296357
296386
|
}
|
|
296387
|
+
if (!payload) {
|
|
296388
|
+
return void 0;
|
|
296389
|
+
}
|
|
296390
|
+
const root = asRecord2(payload.session) ?? payload;
|
|
296391
|
+
const identity = asRecord2(root.identity);
|
|
296392
|
+
const data = asRecord2(root.data);
|
|
296393
|
+
const user = asRecord2(data?.user);
|
|
296394
|
+
const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
|
|
296395
|
+
const singleRole = coerceText(user?.role);
|
|
296396
|
+
const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
|
|
296397
|
+
return {
|
|
296398
|
+
source: "iapub/sessions",
|
|
296399
|
+
userId: coerceId(identity?.user) ?? coerceId(user?.id),
|
|
296400
|
+
fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
|
|
296401
|
+
teamId: coerceId(identity?.team),
|
|
296402
|
+
teamName: coerceText(user?.teamName),
|
|
296403
|
+
teamDomain: coerceText(identity?.domain),
|
|
296404
|
+
...roles ? { roles } : {},
|
|
296405
|
+
consumerType: coerceText(root.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
|
|
296406
|
+
};
|
|
296407
|
+
}
|
|
296408
|
+
async function probeSessionIdentity(baseUrl, accessToken, fetchImpl, maxAttempts, sleepImpl, random) {
|
|
296409
|
+
let failure = "unavailable";
|
|
296410
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
296411
|
+
let response;
|
|
296412
|
+
try {
|
|
296413
|
+
response = await fetchImpl(`${baseUrl}${sessionPath}`, {
|
|
296414
|
+
method: "GET",
|
|
296415
|
+
headers: { "x-access-token": accessToken }
|
|
296416
|
+
});
|
|
296417
|
+
} catch {
|
|
296418
|
+
failure = "unavailable";
|
|
296419
|
+
if (attempt < maxAttempts) {
|
|
296420
|
+
await sleepImpl(computeSessionRetryDelayMs(void 0, attempt, random));
|
|
296421
|
+
continue;
|
|
296422
|
+
}
|
|
296423
|
+
break;
|
|
296424
|
+
}
|
|
296425
|
+
if (response.ok) {
|
|
296426
|
+
const resolved = await parseSessionResponse(response);
|
|
296427
|
+
if (resolved) {
|
|
296428
|
+
memoizedSessionIdentity = resolved;
|
|
296429
|
+
memoizedSessionFailure = void 0;
|
|
296430
|
+
return resolved;
|
|
296431
|
+
}
|
|
296432
|
+
failure = "unavailable";
|
|
296433
|
+
break;
|
|
296434
|
+
}
|
|
296435
|
+
if (response.status === 401 || response.status === 403) {
|
|
296436
|
+
failure = "auth";
|
|
296437
|
+
break;
|
|
296438
|
+
}
|
|
296439
|
+
if (response.status === 429 || response.status >= 500) {
|
|
296440
|
+
failure = "unavailable";
|
|
296441
|
+
if (attempt < maxAttempts) {
|
|
296442
|
+
await sleepImpl(computeSessionRetryDelayMs(response, attempt, random));
|
|
296443
|
+
continue;
|
|
296444
|
+
}
|
|
296445
|
+
break;
|
|
296446
|
+
}
|
|
296447
|
+
failure = "unavailable";
|
|
296448
|
+
break;
|
|
296449
|
+
}
|
|
296450
|
+
memoizedSessionFailure = failure;
|
|
296451
|
+
return void 0;
|
|
296358
296452
|
}
|
|
296359
296453
|
function describeTeam(id) {
|
|
296360
296454
|
const label = id?.teamName ?? id?.teamDomain;
|
|
@@ -296445,7 +296539,9 @@ async function runCredentialPreflight(args) {
|
|
|
296445
296539
|
session = await resolveSessionIdentity({
|
|
296446
296540
|
iapubBaseUrl: args.iapubBaseUrl,
|
|
296447
296541
|
accessToken,
|
|
296448
|
-
fetchImpl: args.fetchImpl
|
|
296542
|
+
fetchImpl: args.fetchImpl,
|
|
296543
|
+
...args.sleepImpl ? { sleepImpl: args.sleepImpl } : {},
|
|
296544
|
+
...args.randomImpl ? { randomImpl: args.randomImpl } : {}
|
|
296449
296545
|
});
|
|
296450
296546
|
} catch (error2) {
|
|
296451
296547
|
args.log.warning(
|
|
@@ -296465,11 +296561,20 @@ async function runCredentialPreflight(args) {
|
|
|
296465
296561
|
);
|
|
296466
296562
|
}
|
|
296467
296563
|
} else {
|
|
296564
|
+
const failure = getSessionResolutionFailure();
|
|
296565
|
+
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.";
|
|
296566
|
+
const base = "postman: credential preflight could not resolve the access-token session identity from iapub: " + detail;
|
|
296567
|
+
if (args.mode === "enforce") {
|
|
296568
|
+
throw new Error(
|
|
296569
|
+
mask(
|
|
296570
|
+
`${base} (credential-preflight: enforce requires a resolvable session identity; use credential-preflight: warn to continue with reactive error guidance only.)`
|
|
296571
|
+
)
|
|
296572
|
+
);
|
|
296573
|
+
}
|
|
296468
296574
|
args.log.warning(
|
|
296469
|
-
mask(
|
|
296470
|
-
"postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
|
|
296471
|
-
)
|
|
296575
|
+
mask(`${base} Continuing with reactive error guidance only (credential-preflight: warn).`)
|
|
296472
296576
|
);
|
|
296577
|
+
return;
|
|
296473
296578
|
}
|
|
296474
296579
|
const result = crossCheckIdentities({
|
|
296475
296580
|
pmak,
|
|
@@ -298236,7 +298341,11 @@ function securityCheckFor(schemeName, scheme) {
|
|
|
298236
298341
|
if (scheme?.type === "http") {
|
|
298237
298342
|
const httpScheme = String(scheme.scheme || "").toLowerCase();
|
|
298238
298343
|
if (httpScheme === "basic") return { scheme: schemeName, kind, checkable: true, prefix: "Basic " };
|
|
298239
|
-
if (httpScheme === "bearer")
|
|
298344
|
+
if (httpScheme === "bearer") {
|
|
298345
|
+
const check = { scheme: schemeName, kind, checkable: true, prefix: "Bearer " };
|
|
298346
|
+
if (typeof scheme.bearerFormat === "string" && scheme.bearerFormat) check.bearerFormat = scheme.bearerFormat;
|
|
298347
|
+
return check;
|
|
298348
|
+
}
|
|
298240
298349
|
if (httpScheme) return { scheme: schemeName, kind, checkable: true, prefix: `${httpScheme.charAt(0).toUpperCase()}${httpScheme.slice(1)} ` };
|
|
298241
298350
|
return { scheme: schemeName, kind, checkable: true, in: "header", name: "Authorization" };
|
|
298242
298351
|
}
|
|
@@ -298375,6 +298484,7 @@ function collectParameterChecks(root, pathItem, operation, version2, operationId
|
|
|
298375
298484
|
if (defaultSerialization) warnings.push(`CONTRACT_SCHEMA_NOT_COMPILED: parameter ${location2}:${name} schema on ${operationId} skipped (${packed.unsupported})`);
|
|
298376
298485
|
continue;
|
|
298377
298486
|
}
|
|
298487
|
+
validateParameterExamples(root, param, packed, `${location2}:${name} of ${operationId}`, warnings);
|
|
298378
298488
|
if (location2 === "path") {
|
|
298379
298489
|
const containingSegment = pathTemplate.split("/").find((segment) => segment.includes(`{${name}}`));
|
|
298380
298490
|
if (containingSegment !== void 0 && containingSegment !== `{${name}}`) {
|
|
@@ -298391,12 +298501,32 @@ function collectParameterChecks(root, pathItem, operation, version2, operationId
|
|
|
298391
298501
|
}
|
|
298392
298502
|
const scalarSchema = packedScalarSchema(packed);
|
|
298393
298503
|
if (scalarSchema !== void 0) {
|
|
298394
|
-
|
|
298504
|
+
const decodablePathStyle = location2 === "path" && (style === "label" || style === "matrix") && !explode ? style : void 0;
|
|
298505
|
+
if (!defaultSerialization && !decodablePathStyle) continue;
|
|
298506
|
+
if (!defaultSerialization) warnings.push(...noteWarnings);
|
|
298395
298507
|
const check2 = { in: location2, name, required: param.required === true, schema: scalarSchema };
|
|
298508
|
+
if (decodablePathStyle) check2.pathStyle = decodablePathStyle;
|
|
298396
298509
|
if (location2 === "query" && param.allowEmptyValue === true) check2.allowEmptyValue = true;
|
|
298397
298510
|
checks.push(check2);
|
|
298398
298511
|
continue;
|
|
298399
298512
|
}
|
|
298513
|
+
if (location2 === "query" && style === "deepObject" && explode) {
|
|
298514
|
+
const objectSchema = asRecord5(packed.schema);
|
|
298515
|
+
const properties = objectSchema ? asRecord5(objectSchema.properties) : null;
|
|
298516
|
+
const allScalar = properties !== null && Object.keys(properties).length > 0 && Object.values(properties).every((prop) => {
|
|
298517
|
+
const record = asRecord5(prop);
|
|
298518
|
+
if (!record) return false;
|
|
298519
|
+
const types2 = Array.isArray(record.type) ? record.type : [record.type];
|
|
298520
|
+
return types2.every((entry) => typeof entry === "string" && SCALAR_SCHEMA_TYPES.has(entry));
|
|
298521
|
+
});
|
|
298522
|
+
if (allScalar) {
|
|
298523
|
+
warnings.push(...noteWarnings);
|
|
298524
|
+
const check2 = { in: "query", name, required: param.required === true, schema: packed.schema, decode: "deepObject" };
|
|
298525
|
+
if (param.allowEmptyValue === true) check2.allowEmptyValue = true;
|
|
298526
|
+
checks.push(check2);
|
|
298527
|
+
continue;
|
|
298528
|
+
}
|
|
298529
|
+
}
|
|
298400
298530
|
if (location2 !== "query" && location2 !== "header") continue;
|
|
298401
298531
|
const items = packedArrayItemsSchema(packed);
|
|
298402
298532
|
if (items === void 0) continue;
|
|
@@ -298707,6 +298837,185 @@ function responseHeaders(root, version2, response, context, warnings) {
|
|
|
298707
298837
|
}
|
|
298708
298838
|
return entries;
|
|
298709
298839
|
}
|
|
298840
|
+
var IANA_HTTP_AUTH_SCHEMES = /* @__PURE__ */ new Set([
|
|
298841
|
+
"basic",
|
|
298842
|
+
"bearer",
|
|
298843
|
+
"concealed",
|
|
298844
|
+
"digest",
|
|
298845
|
+
"dpop",
|
|
298846
|
+
"gnap",
|
|
298847
|
+
"hoba",
|
|
298848
|
+
"mutual",
|
|
298849
|
+
"negotiate",
|
|
298850
|
+
"oauth",
|
|
298851
|
+
"privatetoken",
|
|
298852
|
+
"scram-sha-1",
|
|
298853
|
+
"scram-sha-256",
|
|
298854
|
+
"vapid"
|
|
298855
|
+
]);
|
|
298856
|
+
function httpsUrlLint(value, label, schemeName) {
|
|
298857
|
+
if (typeof value !== "string" || !value) return void 0;
|
|
298858
|
+
try {
|
|
298859
|
+
const parsed = new URL(value);
|
|
298860
|
+
if (parsed.protocol !== "https:") return `CONTRACT_SECURITY_SCHEME_URL: security scheme ${schemeName} ${label} ${value} is not an HTTPS URL`;
|
|
298861
|
+
} catch {
|
|
298862
|
+
return `CONTRACT_SECURITY_SCHEME_URL: security scheme ${schemeName} ${label} ${value} is not a valid URL`;
|
|
298863
|
+
}
|
|
298864
|
+
return void 0;
|
|
298865
|
+
}
|
|
298866
|
+
function collectSecurityStaticLints(root, operation) {
|
|
298867
|
+
const securitySchemes = asRecord5(asRecord5(root.components)?.securitySchemes);
|
|
298868
|
+
const requirements = operation.security === void 0 ? asArray3(root.security) : asArray3(operation.security);
|
|
298869
|
+
const warnings = /* @__PURE__ */ new Set();
|
|
298870
|
+
for (const requirement of requirements.map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry))) {
|
|
298871
|
+
for (const [schemeName, requiredScopes] of Object.entries(requirement)) {
|
|
298872
|
+
let scheme;
|
|
298873
|
+
try {
|
|
298874
|
+
scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
|
|
298875
|
+
} catch {
|
|
298876
|
+
scheme = null;
|
|
298877
|
+
}
|
|
298878
|
+
if (!scheme) continue;
|
|
298879
|
+
if (scheme.type === "http") {
|
|
298880
|
+
const httpScheme = String(scheme.scheme || "").toLowerCase();
|
|
298881
|
+
if (httpScheme && !IANA_HTTP_AUTH_SCHEMES.has(httpScheme)) {
|
|
298882
|
+
warnings.add(`CONTRACT_UNKNOWN_HTTP_AUTH_SCHEME: security scheme ${schemeName} uses "${httpScheme}", which is not in the IANA HTTP Authentication Scheme registry`);
|
|
298883
|
+
}
|
|
298884
|
+
}
|
|
298885
|
+
if (scheme.type === "apiKey" && String(scheme.in) === "query") {
|
|
298886
|
+
warnings.add(`CONTRACT_CREDENTIALS_IN_QUERY: security scheme ${schemeName} sends credentials in the query string, which leaks into logs and referrers`);
|
|
298887
|
+
}
|
|
298888
|
+
if (scheme.type === "openIdConnect") {
|
|
298889
|
+
const urlWarning = httpsUrlLint(scheme.openIdConnectUrl, "openIdConnectUrl", schemeName);
|
|
298890
|
+
if (urlWarning) warnings.add(urlWarning);
|
|
298891
|
+
else if (typeof scheme.openIdConnectUrl === "string" && !scheme.openIdConnectUrl.endsWith("/.well-known/openid-configuration")) {
|
|
298892
|
+
warnings.add(`CONTRACT_SECURITY_SCHEME_URL: security scheme ${schemeName} openIdConnectUrl does not end in /.well-known/openid-configuration`);
|
|
298893
|
+
}
|
|
298894
|
+
}
|
|
298895
|
+
if (scheme.type === "oauth2") {
|
|
298896
|
+
const flows = asRecord5(scheme.flows) ?? {};
|
|
298897
|
+
const declaredScopes = /* @__PURE__ */ new Set();
|
|
298898
|
+
for (const [flowName, rawFlow] of Object.entries(flows)) {
|
|
298899
|
+
const flow = asRecord5(rawFlow);
|
|
298900
|
+
if (!flow) continue;
|
|
298901
|
+
for (const scope of Object.keys(asRecord5(flow.scopes) ?? {})) declaredScopes.add(scope);
|
|
298902
|
+
const urlFields = [["refreshUrl", flow.refreshUrl]];
|
|
298903
|
+
if (flowName === "implicit" || flowName === "authorizationCode") urlFields.push(["authorizationUrl", flow.authorizationUrl]);
|
|
298904
|
+
if (flowName === "password" || flowName === "clientCredentials" || flowName === "authorizationCode") urlFields.push(["tokenUrl", flow.tokenUrl]);
|
|
298905
|
+
for (const [label, value] of urlFields) {
|
|
298906
|
+
const urlWarning = httpsUrlLint(value, `${flowName} ${label}`, schemeName);
|
|
298907
|
+
if (urlWarning) warnings.add(urlWarning);
|
|
298908
|
+
}
|
|
298909
|
+
}
|
|
298910
|
+
for (const scope of asArray3(requiredScopes).filter((entry) => typeof entry === "string")) {
|
|
298911
|
+
if (!declaredScopes.has(scope)) {
|
|
298912
|
+
warnings.add(`CONTRACT_OAUTH2_UNDECLARED_SCOPE: operation requires scope "${scope}" of ${schemeName}, which no flow of the scheme declares`);
|
|
298913
|
+
}
|
|
298914
|
+
}
|
|
298915
|
+
}
|
|
298916
|
+
}
|
|
298917
|
+
}
|
|
298918
|
+
return [...warnings];
|
|
298919
|
+
}
|
|
298920
|
+
function collectSecurityResponseLints(root, operation, responses, operationId) {
|
|
298921
|
+
const warnings = [];
|
|
298922
|
+
const requirements = operation.security === void 0 ? asArray3(root.security) : asArray3(operation.security);
|
|
298923
|
+
const requirementRecords = requirements.map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry));
|
|
298924
|
+
const secured = requirementRecords.length > 0 && requirementRecords.every((entry) => Object.keys(entry).length > 0);
|
|
298925
|
+
const statusKeys = new Set(Object.keys(responses));
|
|
298926
|
+
const hasCatchAll = statusKeys.has("default") || statusKeys.has("4XX");
|
|
298927
|
+
if (secured && !statusKeys.has("401") && !hasCatchAll) {
|
|
298928
|
+
warnings.push(`CONTRACT_SECURITY_RESPONSES_INCOMPLETE: ${operationId} requires authentication but documents no 401 (or 4XX/default) response`);
|
|
298929
|
+
}
|
|
298930
|
+
const usesScopes = requirementRecords.some((entry) => Object.values(entry).some((scopes) => Array.isArray(scopes) && scopes.length > 0));
|
|
298931
|
+
if (secured && usesScopes && !statusKeys.has("403") && !hasCatchAll) {
|
|
298932
|
+
warnings.push(`CONTRACT_SECURITY_RESPONSES_INCOMPLETE: ${operationId} requires scopes but documents no 403 (or 4XX/default) response`);
|
|
298933
|
+
}
|
|
298934
|
+
if (requirementRecords.length === 0) {
|
|
298935
|
+
for (const status of ["401", "403"]) {
|
|
298936
|
+
if (statusKeys.has(status)) warnings.push(`CONTRACT_UNSECURED_AUTH_RESPONSES: ${operationId} documents a ${status} response but declares no security requirement`);
|
|
298937
|
+
}
|
|
298938
|
+
}
|
|
298939
|
+
return warnings;
|
|
298940
|
+
}
|
|
298941
|
+
function collectLinkExpressions(root, response, operationId, warnings) {
|
|
298942
|
+
const links = asRecord5(response.links);
|
|
298943
|
+
if (!links) return [];
|
|
298944
|
+
const expressions = [];
|
|
298945
|
+
let unevaluated = false;
|
|
298946
|
+
for (const [linkName, rawLink] of Object.entries(links)) {
|
|
298947
|
+
let link;
|
|
298948
|
+
try {
|
|
298949
|
+
link = resolveInternalRef(root, rawLink);
|
|
298950
|
+
} catch {
|
|
298951
|
+
link = null;
|
|
298952
|
+
}
|
|
298953
|
+
if (!link) {
|
|
298954
|
+
unevaluated = true;
|
|
298955
|
+
continue;
|
|
298956
|
+
}
|
|
298957
|
+
const values = Object.values(asRecord5(link.parameters) ?? {});
|
|
298958
|
+
if (link.requestBody !== void 0) values.push(link.requestBody);
|
|
298959
|
+
if (values.length === 0) unevaluated = true;
|
|
298960
|
+
for (const value of values) {
|
|
298961
|
+
if (typeof value !== "string" || !value.startsWith("$")) continue;
|
|
298962
|
+
const bodyMatch = value.match(/^\$response\.body#(\/.*)$/);
|
|
298963
|
+
if (bodyMatch) {
|
|
298964
|
+
expressions.push({ link: linkName, kind: "body", pointer: bodyMatch[1] });
|
|
298965
|
+
continue;
|
|
298966
|
+
}
|
|
298967
|
+
const headerMatch = value.match(/^\$response\.header\.([!#$%&'*+.^_`|~0-9A-Za-z-]+)$/);
|
|
298968
|
+
if (headerMatch) {
|
|
298969
|
+
expressions.push({ link: linkName, kind: "header", header: headerMatch[1] });
|
|
298970
|
+
continue;
|
|
298971
|
+
}
|
|
298972
|
+
unevaluated = true;
|
|
298973
|
+
}
|
|
298974
|
+
}
|
|
298975
|
+
if (expressions.length === 0) {
|
|
298976
|
+
if (unevaluated) warnings.add(`CONTRACT_LINKS_NOT_VALIDATED: response links are not validated for ${operationId}`);
|
|
298977
|
+
} else if (unevaluated) {
|
|
298978
|
+
warnings.add(`CONTRACT_LINKS_PARTIALLY_VALIDATED: some link expressions for ${operationId} are not runtime-evaluable and are skipped`);
|
|
298979
|
+
}
|
|
298980
|
+
return expressions;
|
|
298981
|
+
}
|
|
298982
|
+
function escapeRegExpLiteral(value) {
|
|
298983
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
298984
|
+
}
|
|
298985
|
+
function serverAdvisoryPatterns(root, pathItem, operation) {
|
|
298986
|
+
const serverLists = [asArray3(operation.servers), asArray3(pathItem.servers), asArray3(root.servers)];
|
|
298987
|
+
const servers = serverLists.find((list) => list.length > 0) ?? [];
|
|
298988
|
+
const patterns = [];
|
|
298989
|
+
for (const rawServer of servers) {
|
|
298990
|
+
const server = asRecord5(rawServer);
|
|
298991
|
+
if (!server) continue;
|
|
298992
|
+
const url = typeof server.url === "string" ? server.url.trim() : "";
|
|
298993
|
+
if (!url || url === "/") continue;
|
|
298994
|
+
const variables = asRecord5(server.variables);
|
|
298995
|
+
const pattern = url.split(/(\{[^}]+\})/).map((part) => {
|
|
298996
|
+
const varMatch = part.match(/^\{([^}]+)\}$/);
|
|
298997
|
+
if (!varMatch) return escapeRegExpLiteral(part);
|
|
298998
|
+
const variable = asRecord5(variables?.[varMatch[1]]);
|
|
298999
|
+
const enumValues = asArray3(variable?.enum).filter((entry) => typeof entry === "string");
|
|
299000
|
+
if (enumValues.length > 0) return `(${enumValues.map(escapeRegExpLiteral).join("|")})`;
|
|
299001
|
+
return "[^/]*";
|
|
299002
|
+
}).join("");
|
|
299003
|
+
patterns.push(`^${pattern}`);
|
|
299004
|
+
}
|
|
299005
|
+
return patterns.length > 0 ? patterns : void 0;
|
|
299006
|
+
}
|
|
299007
|
+
function validateParameterExamples(root, param, packed, context, warnings) {
|
|
299008
|
+
if (packed.schema === void 0 || packed.unsupported) return;
|
|
299009
|
+
const candidates = exampleCandidates(root, param);
|
|
299010
|
+
if (candidates.length === 0) return;
|
|
299011
|
+
const validate3 = compileSchemaValidator(packed.schema);
|
|
299012
|
+
if (!validate3) return;
|
|
299013
|
+
for (const candidate of candidates) {
|
|
299014
|
+
if (!validate3(candidate.value)) {
|
|
299015
|
+
warnings.push(`CONTRACT_EXAMPLE_SCHEMA_MISMATCH: ${candidate.label} for parameter ${context} does not match its schema`);
|
|
299016
|
+
}
|
|
299017
|
+
}
|
|
299018
|
+
}
|
|
298710
299019
|
function buildContractIndex(root) {
|
|
298711
299020
|
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)");
|
|
298712
299021
|
if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
|
|
@@ -298725,6 +299034,9 @@ function buildContractIndex(root) {
|
|
|
298725
299034
|
const operation = resolveInternalRef(root, rawOperation);
|
|
298726
299035
|
if (!operation) continue;
|
|
298727
299036
|
if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path10}`);
|
|
299037
|
+
if (operation.requestBody !== void 0 && ["get", "head", "delete"].includes(lowerMethod)) {
|
|
299038
|
+
warnings.push(`CONTRACT_METHOD_BODY_SEMANTICS: ${lowerMethod.toUpperCase()} ${path10} declares a request body; RFC 9110 defines no request-body semantics for ${lowerMethod.toUpperCase()}`);
|
|
299039
|
+
}
|
|
298728
299040
|
const responses = asRecord5(operation.responses);
|
|
298729
299041
|
if (!responses || Object.keys(responses).length === 0) {
|
|
298730
299042
|
throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path10} must define at least one response`);
|
|
@@ -298734,11 +299046,15 @@ function buildContractIndex(root) {
|
|
|
298734
299046
|
for (const [status, rawResponse] of Object.entries(responses)) {
|
|
298735
299047
|
const response = resolveInternalRef(root, rawResponse);
|
|
298736
299048
|
if (!response) continue;
|
|
298737
|
-
if (
|
|
298738
|
-
responseWarnings.add(`
|
|
299049
|
+
if (status !== "default" && !/^[1-5]XX$/.test(status) && !/^[1-5][0-9][0-9]$/.test(status)) {
|
|
299050
|
+
responseWarnings.add(`CONTRACT_INVALID_STATUS_CODE: ${lowerMethod.toUpperCase()} ${path10} declares response status "${status}" outside RFC 9110's 100-599, 1XX-5XX, or default forms`);
|
|
298739
299051
|
}
|
|
299052
|
+
const linkExpressions = collectLinkExpressions(root, response, `${lowerMethod.toUpperCase()} ${path10}`, responseWarnings);
|
|
298740
299053
|
const responseContext = `${lowerMethod.toUpperCase()} ${path10} status ${status}`;
|
|
298741
299054
|
const content = responseContent(root, version2, response, responseContext, responseWarnings);
|
|
299055
|
+
if ((status === "204" || status === "205" || status === "304") && Object.keys(content).length > 0) {
|
|
299056
|
+
responseWarnings.add(`CONTRACT_BODYLESS_STATUS_WITH_CONTENT: ${lowerMethod.toUpperCase()} ${path10} declares content for status ${status}, which RFC 9110 forbids on the wire`);
|
|
299057
|
+
}
|
|
298742
299058
|
for (const [contentType2, media] of Object.entries(content)) {
|
|
298743
299059
|
const base = contentType2.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
298744
299060
|
const schemaType = asRecord5(media.schema)?.type;
|
|
@@ -298750,7 +299066,8 @@ function buildContractIndex(root) {
|
|
|
298750
299066
|
contractResponses[normalizeResponseKey(status)] = {
|
|
298751
299067
|
content,
|
|
298752
299068
|
hasBody: Object.keys(content).length > 0,
|
|
298753
|
-
headers
|
|
299069
|
+
headers,
|
|
299070
|
+
...linkExpressions.length > 0 ? { links: linkExpressions } : {}
|
|
298754
299071
|
};
|
|
298755
299072
|
}
|
|
298756
299073
|
const candidates = [...new Set([
|
|
@@ -298763,11 +299080,13 @@ function buildContractIndex(root) {
|
|
|
298763
299080
|
opWarnings.push(...collectSecuritySchemeWarnings(root, operation));
|
|
298764
299081
|
const parameterChecks = collectParameterChecks(root, pathItem, operation, version2, operationId, path10, opWarnings);
|
|
298765
299082
|
const checkedKeys = new Set((parameterChecks ?? []).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
298766
|
-
const decodedKeys = new Set((parameterChecks ?? []).filter((check) => check.decode).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
299083
|
+
const decodedKeys = new Set((parameterChecks ?? []).filter((check) => check.decode || check.pathStyle).map((check) => `${check.in}:${check.name.toLowerCase()}`));
|
|
298767
299084
|
opWarnings.push(...collectSerializationWarnings(root, pathItem, operation, decodedKeys));
|
|
298768
299085
|
if (operation.deprecated === true) {
|
|
298769
299086
|
opWarnings.push(`CONTRACT_OPERATION_DEPRECATED: ${lowerMethod.toUpperCase()} ${path10} is marked deprecated in the OpenAPI document`);
|
|
298770
299087
|
}
|
|
299088
|
+
opWarnings.push(...collectSecurityStaticLints(root, operation));
|
|
299089
|
+
opWarnings.push(...collectSecurityResponseLints(root, operation, responses, operationId));
|
|
298771
299090
|
const requiredParameters = collectParameters(root, pathItem, operation);
|
|
298772
299091
|
for (const parameter of requiredParameters.filter((entry) => entry.securityDerived)) {
|
|
298773
299092
|
opWarnings.push(`CONTRACT_SECURITY_NOT_VALIDATED: security parameter ${parameter.in}:${parameter.name} is not statically required in generated requests`);
|
|
@@ -298796,6 +299115,9 @@ function buildContractIndex(root) {
|
|
|
298796
299115
|
parameterChecks,
|
|
298797
299116
|
requestBody: collectRequestBody(root, operation, version2, operationId, opWarnings),
|
|
298798
299117
|
security: collectSecurityRuntimeChecks(root, operation),
|
|
299118
|
+
pathMethods: Object.keys(pathItem).filter((key) => HTTP_METHODS.has(key)).map((key) => key.toUpperCase()),
|
|
299119
|
+
deprecated: operation.deprecated === true || void 0,
|
|
299120
|
+
servers: serverAdvisoryPatterns(root, pathItem, operation),
|
|
298799
299121
|
warnings: opWarnings
|
|
298800
299122
|
});
|
|
298801
299123
|
}
|
|
@@ -298972,7 +299294,7 @@ function buildValidatorAssignments(operation, warnings, skipped) {
|
|
|
298972
299294
|
return lines;
|
|
298973
299295
|
}
|
|
298974
299296
|
function createContractScript(operation, warnings = []) {
|
|
298975
|
-
const contract = { method: operation.method, path: operation.path, responses: operation.responses, security: operation.security, parameters: operation.parameterChecks };
|
|
299297
|
+
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 };
|
|
298976
299298
|
const skipped = [];
|
|
298977
299299
|
const validatorLines = buildValidatorAssignments(operation, warnings, skipped);
|
|
298978
299300
|
return [
|
|
@@ -299083,6 +299405,417 @@ function createContractScript(operation, warnings = []) {
|
|
|
299083
299405
|
' if (!isJsonSubtype(actual.subtype) && media.media.schema && media.media.schema.type !== "string") { return; }',
|
|
299084
299406
|
' if (!validate(value)) pm.expect.fail("OpenAPI schema validation failed for " + contract.method + " " + contract.path + " status " + pm.response.code + ": " + JSON.stringify(validate.errors || []));',
|
|
299085
299407
|
"});",
|
|
299408
|
+
"pm.test('Response satisfies RFC 9110 status-code requirements', function () {",
|
|
299409
|
+
" var code = pm.response.code;",
|
|
299410
|
+
' function respHeader(name) { return pm.response.headers.get(name) || ""; }',
|
|
299411
|
+
" if (code === 401) {",
|
|
299412
|
+
' var challenge = respHeader("WWW-Authenticate");',
|
|
299413
|
+
' if (!challenge) pm.expect.fail("RFC 9110 requires WWW-Authenticate on 401 responses");',
|
|
299414
|
+
' var wantsBearer = (contract.security || []).some(function (alternative) { return alternative.some(function (check) { return check.prefix && check.prefix.toLowerCase().indexOf("bearer") === 0; }); });',
|
|
299415
|
+
' 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);',
|
|
299416
|
+
' 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);',
|
|
299417
|
+
' 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);',
|
|
299418
|
+
" }",
|
|
299419
|
+
" if (code === 401 || code === 403) {",
|
|
299420
|
+
' var authChallenge = respHeader("WWW-Authenticate");',
|
|
299421
|
+
' var bearerError = authChallenge && /\\bbearer\\b/i.test(authChallenge) ? authChallenge.match(/\\berror\\s*=\\s*"?([A-Za-z0-9_]+)"?/i) : null;',
|
|
299422
|
+
' 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]);',
|
|
299423
|
+
" }",
|
|
299424
|
+
" if (code === 405) {",
|
|
299425
|
+
' var allow = respHeader("Allow");',
|
|
299426
|
+
' if (!allow) pm.expect.fail("RFC 9110 requires Allow on 405 responses");',
|
|
299427
|
+
' var allowed = allow.split(",").map(function (entry) { return entry.trim().toUpperCase(); });',
|
|
299428
|
+
' (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); });',
|
|
299429
|
+
" }",
|
|
299430
|
+
' if (code === 304 && responseText().trim().length > 0) pm.expect.fail("RFC 9110 forbids content in a 304 response");',
|
|
299431
|
+
' var retryAfter = respHeader("Retry-After");',
|
|
299432
|
+
" if (retryAfter && (code === 429 || code === 503 || (code >= 300 && code < 400))) {",
|
|
299433
|
+
' 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);',
|
|
299434
|
+
" }",
|
|
299435
|
+
' var location = respHeader("Location");',
|
|
299436
|
+
" if (location && (code === 201 || (code >= 300 && code < 400))) {",
|
|
299437
|
+
' if (/\\s/.test(location.trim()) || location.trim().length === 0) pm.expect.fail("Location must be a valid URI-reference (RFC 9110 / RFC 3986): " + location);',
|
|
299438
|
+
" }",
|
|
299439
|
+
"});",
|
|
299440
|
+
"pm.test('Error and encoding conventions match RFC 9457 / RFC 8259 / RFC 8288', function () {",
|
|
299441
|
+
' var contentTypeRaw = pm.response.headers.get("Content-Type") || "";',
|
|
299442
|
+
" var ct = mediaParts(contentTypeRaw);",
|
|
299443
|
+
' if (ct.type === "application" && ct.subtype === "problem+json") {',
|
|
299444
|
+
" var problem;",
|
|
299445
|
+
' try { problem = pm.response.json(); } catch (error) { pm.expect.fail("application/problem+json body is not valid JSON (RFC 9457): " + error); }',
|
|
299446
|
+
' if (!problem || typeof problem !== "object" || Array.isArray(problem)) pm.expect.fail("problem details must be a JSON object (RFC 9457)");',
|
|
299447
|
+
' ["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]); });',
|
|
299448
|
+
' ["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]); });',
|
|
299449
|
+
" if (problem.status !== undefined) {",
|
|
299450
|
+
' if (typeof problem.status !== "number") pm.expect.fail("RFC 9457 status member must be a number; got " + typeof problem.status);',
|
|
299451
|
+
' 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 + ")");',
|
|
299452
|
+
" }",
|
|
299453
|
+
" }",
|
|
299454
|
+
" if (isJsonSubtype(ct.subtype)) {",
|
|
299455
|
+
' var charsetMatch = contentTypeRaw.match(/charset\\s*=\\s*"?([^";\\s]+)"?/i);',
|
|
299456
|
+
' if (charsetMatch && charsetMatch[1].toLowerCase() !== "utf-8") pm.expect.fail("JSON interchange must be UTF-8 (RFC 8259); got charset=" + charsetMatch[1]);',
|
|
299457
|
+
" }",
|
|
299458
|
+
' var link = pm.response.headers.get("Link");',
|
|
299459
|
+
" if (link) {",
|
|
299460
|
+
" link.split(/,(?=\\s*<)/).forEach(function (value) {",
|
|
299461
|
+
' if (!/^\\s*<[^>]*>/.test(value)) pm.expect.fail("RFC 8288 link-value must start with a <URI-Reference>: " + value);',
|
|
299462
|
+
' if (!/;\\s*rel\\s*=/i.test(value)) pm.expect.fail("RFC 8288 link-value must carry a rel parameter: " + value);',
|
|
299463
|
+
" });",
|
|
299464
|
+
" }",
|
|
299465
|
+
"});",
|
|
299466
|
+
"var rfcAdvisories = [];",
|
|
299467
|
+
"function rfcAdvise(message) { if (rfcAdvisories.indexOf(message) === -1) rfcAdvisories.push(message); }",
|
|
299468
|
+
'function rfcRespHeader(name) { return pm.response.headers.get(name) || ""; }',
|
|
299469
|
+
"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; }",
|
|
299470
|
+
"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)); }",
|
|
299471
|
+
"function rfcIsToken(value) { return /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(String(value)); }",
|
|
299472
|
+
'function rfcIsEntityTag(value) { return /^(W\\/)?"[\\x21\\x23-\\x7e\\x80-\\xff]*"$/.test(String(value).trim()); }',
|
|
299473
|
+
"function rfcIsFieldContent(value) { return /^[\\t \\x21-\\x7e\\x80-\\xff]*$/.test(String(value)); }",
|
|
299474
|
+
'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; }',
|
|
299475
|
+
`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; }`,
|
|
299476
|
+
'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; }',
|
|
299477
|
+
"function rfcSfParse(input, kind) {",
|
|
299478
|
+
" var s = String(input), i = 0;",
|
|
299479
|
+
' function ws() { while (i < s.length && (s.charAt(i) === " " || s.charAt(i) === "\\t")) i += 1; }',
|
|
299480
|
+
" 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); }",
|
|
299481
|
+
" function bareItem() {",
|
|
299482
|
+
" var ch = s.charAt(i);",
|
|
299483
|
+
` 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; }`,
|
|
299484
|
+
' 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; }',
|
|
299485
|
+
' if (ch === "?") { i += 1; if (s.charAt(i) !== "0" && s.charAt(i) !== "1") return null; i += 1; return true; }',
|
|
299486
|
+
' 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; }',
|
|
299487
|
+
' 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; }',
|
|
299488
|
+
" if (/[A-Za-z*]/.test(ch)) { i += 1; while (i < s.length && /[!#$%&'*+.^_`|~:\\/0-9A-Za-z-]/.test(s.charAt(i))) i += 1; return true; }",
|
|
299489
|
+
" return null;",
|
|
299490
|
+
" }",
|
|
299491
|
+
' 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; }',
|
|
299492
|
+
' 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(); }',
|
|
299493
|
+
" ws();",
|
|
299494
|
+
' if (kind === "item") { if (item() === null) return false; ws(); return i === s.length; }',
|
|
299495
|
+
" if (i === s.length) return true;",
|
|
299496
|
+
" while (i < s.length) {",
|
|
299497
|
+
' 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; }',
|
|
299498
|
+
" else if (item() === null) return false;",
|
|
299499
|
+
" ws();",
|
|
299500
|
+
" if (i === s.length) return true;",
|
|
299501
|
+
' if (s.charAt(i) !== ",") return false;',
|
|
299502
|
+
" i += 1; ws();",
|
|
299503
|
+
" if (i === s.length) return false;",
|
|
299504
|
+
" }",
|
|
299505
|
+
" return true;",
|
|
299506
|
+
"}",
|
|
299507
|
+
"pm.test('Response header fields satisfy RFC 9110 field syntax', function () {",
|
|
299508
|
+
" pm.response.headers.each(function (header) {",
|
|
299509
|
+
" if (!header) return;",
|
|
299510
|
+
' if (!rfcIsToken(String(header.key))) pm.expect.fail("Response header name is not a valid RFC 9110 token: " + header.key);',
|
|
299511
|
+
' if (!rfcIsFieldContent(String(header.value))) pm.expect.fail("Response header value contains characters forbidden by RFC 9110 field-content: " + header.key);',
|
|
299512
|
+
" });",
|
|
299513
|
+
' ["content-type", "content-length", "etag", "location", "date", "age", "expires", "last-modified", "retry-after"].forEach(function (name) {',
|
|
299514
|
+
" var values = rfcHeaderAll(name);",
|
|
299515
|
+
' 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)"); }',
|
|
299516
|
+
" });",
|
|
299517
|
+
"});",
|
|
299518
|
+
"pm.test('Response header values satisfy their RFC grammars', function () {",
|
|
299519
|
+
' var date = rfcRespHeader("Date");',
|
|
299520
|
+
' if (date && !rfcIsHttpDate(date)) pm.expect.fail("Date must be an IMF-fixdate (RFC 9110): " + date);',
|
|
299521
|
+
' if (!date) rfcAdvise("RFC 9110: origin servers SHOULD send a Date header");',
|
|
299522
|
+
' var etag = rfcRespHeader("ETag");',
|
|
299523
|
+
' if (etag && !rfcIsEntityTag(etag)) pm.expect.fail("ETag is not a valid entity-tag (RFC 9110): " + etag);',
|
|
299524
|
+
' var lastModified = rfcRespHeader("Last-Modified");',
|
|
299525
|
+
" if (lastModified) {",
|
|
299526
|
+
' if (!rfcIsHttpDate(lastModified)) pm.expect.fail("Last-Modified must be a valid HTTP-date (RFC 9110): " + lastModified);',
|
|
299527
|
+
' 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);',
|
|
299528
|
+
" }",
|
|
299529
|
+
' var vary = rfcRespHeader("Vary");',
|
|
299530
|
+
" if (vary) {",
|
|
299531
|
+
' var varyMembers = vary.split(",").map(function (entry) { return entry.trim(); });',
|
|
299532
|
+
' if (varyMembers.indexOf("*") !== -1 && varyMembers.length > 1) pm.expect.fail("Vary: * must not be combined with other members (RFC 9110): " + vary);',
|
|
299533
|
+
' varyMembers.forEach(function (member) { if (member !== "*" && !rfcIsToken(member)) pm.expect.fail("Vary member is not a field-name token (RFC 9110): " + member); });',
|
|
299534
|
+
" }",
|
|
299535
|
+
' var contentLocation = rfcRespHeader("Content-Location");',
|
|
299536
|
+
' if (contentLocation && (/\\s/.test(contentLocation.trim()) || contentLocation.trim().length === 0)) pm.expect.fail("Content-Location must be a valid URI-reference (RFC 9110): " + contentLocation);',
|
|
299537
|
+
' var acceptRanges = rfcRespHeader("Accept-Ranges");',
|
|
299538
|
+
' if (acceptRanges && !rfcTokenList(acceptRanges)) pm.expect.fail("Accept-Ranges must be a list of range-unit tokens (RFC 9110): " + acceptRanges);',
|
|
299539
|
+
' var contentLanguage = rfcRespHeader("Content-Language");',
|
|
299540
|
+
' 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()); });',
|
|
299541
|
+
' var allow = rfcRespHeader("Allow");',
|
|
299542
|
+
' if (allow && allow.trim() && !rfcTokenList(allow)) pm.expect.fail("Allow must be a comma-separated list of method tokens (RFC 9110): " + allow);',
|
|
299543
|
+
' if (allow && contract.method === "OPTIONS" && pm.response.code >= 200 && pm.response.code < 300) {',
|
|
299544
|
+
' var optionsAllowed = allow.split(",").map(function (entry) { return entry.trim().toUpperCase(); });',
|
|
299545
|
+
' (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); });',
|
|
299546
|
+
" }",
|
|
299547
|
+
' var age = rfcRespHeader("Age");',
|
|
299548
|
+
' if (age && !/^[0-9]+$/.test(age.trim())) pm.expect.fail("Age must be a non-negative integer of delta-seconds (RFC 9111): " + age);',
|
|
299549
|
+
' var expires = rfcRespHeader("Expires");',
|
|
299550
|
+
' if (expires && !rfcIsHttpDate(expires)) rfcAdvise("RFC 9111: Expires is not a valid HTTP-date and will be treated as already expired: " + expires);',
|
|
299551
|
+
' if (rfcHeaderAll("warning").length > 0) rfcAdvise("RFC 9111 obsoleted the Warning header; the server still emits it");',
|
|
299552
|
+
' var cacheControl = rfcRespHeader("Cache-Control");',
|
|
299553
|
+
" if (cacheControl) {",
|
|
299554
|
+
" var seenDirectives = {};",
|
|
299555
|
+
" rfcSplitList(cacheControl).forEach(function (entry) {",
|
|
299556
|
+
" var directive = entry.trim();",
|
|
299557
|
+
' if (!directive) { pm.expect.fail("Cache-Control contains an empty directive (RFC 9111): " + cacheControl); return; }',
|
|
299558
|
+
' var eq = directive.indexOf("=");',
|
|
299559
|
+
" var name = (eq === -1 ? directive : directive.slice(0, eq)).trim().toLowerCase();",
|
|
299560
|
+
" var argument = eq === -1 ? undefined : directive.slice(eq + 1).trim();",
|
|
299561
|
+
' if (!rfcIsToken(name)) pm.expect.fail("Cache-Control directive name is not a token (RFC 9111): " + directive);',
|
|
299562
|
+
" seenDirectives[name] = argument === undefined ? true : argument;",
|
|
299563
|
+
' 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);',
|
|
299564
|
+
" });",
|
|
299565
|
+
' 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);',
|
|
299566
|
+
" }",
|
|
299567
|
+
' var acceptPatch = rfcRespHeader("Accept-Patch");',
|
|
299568
|
+
' 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()); });',
|
|
299569
|
+
' var deprecation = rfcRespHeader("Deprecation");',
|
|
299570
|
+
' if (deprecation && !/^@-?[0-9]+$/.test(deprecation.trim())) pm.expect.fail("Deprecation must be an RFC 9745 Date structured field (@unix-timestamp): " + deprecation);',
|
|
299571
|
+
' var sunset = rfcRespHeader("Sunset");',
|
|
299572
|
+
" if (sunset) {",
|
|
299573
|
+
' if (!rfcIsHttpDate(sunset)) pm.expect.fail("Sunset must be a valid HTTP-date (RFC 8594): " + sunset);',
|
|
299574
|
+
' else if (Date.parse(sunset) < Date.now()) rfcAdvise("RFC 8594: Sunset date is already in the past: " + sunset);',
|
|
299575
|
+
" }",
|
|
299576
|
+
' var preferenceApplied = rfcRespHeader("Preference-Applied");',
|
|
299577
|
+
" if (preferenceApplied) {",
|
|
299578
|
+
' var requestPrefer = requestHeader("Prefer").toLowerCase();',
|
|
299579
|
+
" rfcSplitList(preferenceApplied).forEach(function (entry) {",
|
|
299580
|
+
' var token = entry.split("=")[0].trim().toLowerCase();',
|
|
299581
|
+
' if (token && requestPrefer.indexOf(token) === -1) pm.expect.fail("Preference-Applied echoes a preference the request never sent (RFC 7240): " + entry.trim());',
|
|
299582
|
+
" });",
|
|
299583
|
+
" }",
|
|
299584
|
+
"});",
|
|
299585
|
+
"pm.test('Response satisfies RFC 9110 message framing requirements', function () {",
|
|
299586
|
+
" var code = pm.response.code;",
|
|
299587
|
+
' if ((code === 204 || code < 200) && rfcRespHeader("Content-Length")) pm.expect.fail("RFC 9110 forbids Content-Length on 1xx and 204 responses");',
|
|
299588
|
+
' if ([301, 302, 303, 307, 308].indexOf(code) !== -1 && !rfcRespHeader("Location")) pm.expect.fail("RFC 9110 expects Location on a " + code + " redirect response");',
|
|
299589
|
+
" if (code === 416) {",
|
|
299590
|
+
' var unsatisfiedRange = rfcRespHeader("Content-Range");',
|
|
299591
|
+
' if (!unsatisfiedRange) pm.expect.fail("RFC 9110 requires Content-Range (unsatisfied-range form) on 416 responses");',
|
|
299592
|
+
' 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);',
|
|
299593
|
+
" }",
|
|
299594
|
+
" if (code === 206) {",
|
|
299595
|
+
' var contentRange = rfcRespHeader("Content-Range");',
|
|
299596
|
+
' var responseMedia = mediaParts(rfcRespHeader("Content-Type"));',
|
|
299597
|
+
' var isByteranges = responseMedia.type === "multipart" && responseMedia.subtype === "byteranges";',
|
|
299598
|
+
' if (!contentRange && !isByteranges) pm.expect.fail("RFC 9110 requires Content-Range on a single-part 206 response (or multipart/byteranges for multi-range)");',
|
|
299599
|
+
' if (contentRange && isByteranges) pm.expect.fail("RFC 9110 forbids Content-Range on a multipart/byteranges 206 response");',
|
|
299600
|
+
" if (contentRange) {",
|
|
299601
|
+
" var rangeParts = contentRange.trim().match(/^(\\S+) (?:([0-9]+)-([0-9]+)|\\*)\\/([0-9]+|\\*)$/);",
|
|
299602
|
+
' if (!rangeParts) pm.expect.fail("Content-Range is not a valid RFC 9110 range: " + contentRange);',
|
|
299603
|
+
" else {",
|
|
299604
|
+
' if (rangeParts[1] !== "bytes") rfcAdvise("RFC 9110: 206 Content-Range uses a non-bytes range unit: " + rangeParts[1]);',
|
|
299605
|
+
" if (rangeParts[2] !== undefined) {",
|
|
299606
|
+
' if (Number(rangeParts[2]) > Number(rangeParts[3])) pm.expect.fail("Content-Range first-byte-pos must be <= last-byte-pos (RFC 9110): " + contentRange);',
|
|
299607
|
+
' if (rangeParts[4] !== "*" && Number(rangeParts[3]) >= Number(rangeParts[4])) pm.expect.fail("Content-Range last-byte-pos must be < complete-length (RFC 9110): " + contentRange);',
|
|
299608
|
+
" }",
|
|
299609
|
+
" }",
|
|
299610
|
+
" }",
|
|
299611
|
+
" }",
|
|
299612
|
+
' if (code === 407 && !rfcRespHeader("Proxy-Authenticate")) pm.expect.fail("RFC 9110 requires Proxy-Authenticate on 407 responses");',
|
|
299613
|
+
' if (code === 415 && contract.method === "PATCH" && !rfcRespHeader("Accept-Patch")) rfcAdvise("RFC 5789: a 415 response to PATCH SHOULD carry Accept-Patch");',
|
|
299614
|
+
"});",
|
|
299615
|
+
"pm.test('Response media type is acceptable under the request Accept header', function () {",
|
|
299616
|
+
" if (pm.response.code < 200 || pm.response.code >= 300 || isBodyless()) return;",
|
|
299617
|
+
' var accept = requestHeader("Accept");',
|
|
299618
|
+
' if (!accept || accept.indexOf("{{") !== -1) return;',
|
|
299619
|
+
' var actual = mediaParts(rfcRespHeader("Content-Type"));',
|
|
299620
|
+
" if (!actual.type) return;",
|
|
299621
|
+
" var acceptable = false;",
|
|
299622
|
+
" var jsonSoftened = false;",
|
|
299623
|
+
" rfcSplitList(accept).forEach(function (entry) {",
|
|
299624
|
+
" var range = mediaParts(entry);",
|
|
299625
|
+
' var qMatch = entry.match(/;\\s*q\\s*=\\s*"?([0-9.]+)"?/i);',
|
|
299626
|
+
" if (qMatch && Number(qMatch[1]) <= 0) return;",
|
|
299627
|
+
' if ((range.type === "*" && range.subtype === "*") || (range.type === actual.type && (range.subtype === "*" || range.subtype === actual.subtype))) acceptable = true;',
|
|
299628
|
+
' if (range.type === actual.type && range.subtype === "json" && isJsonSubtype(actual.subtype)) jsonSoftened = true;',
|
|
299629
|
+
" });",
|
|
299630
|
+
' if (!acceptable && jsonSoftened) { rfcAdvise("Content negotiation: response " + actual.raw + " is a +json type while the request only accepted application/json"); return; }',
|
|
299631
|
+
' if (!acceptable) pm.expect.fail("Response Content-Type " + actual.raw + " is not acceptable under the request Accept header (RFC 9110): " + accept);',
|
|
299632
|
+
"});",
|
|
299633
|
+
"pm.test('Response body satisfies its media type RFC conventions', function () {",
|
|
299634
|
+
' var contentTypeValue = rfcRespHeader("Content-Type");',
|
|
299635
|
+
" var media = mediaParts(contentTypeValue);",
|
|
299636
|
+
" var text = responseText();",
|
|
299637
|
+
' if (pm.response.code === 406 && !text.trim()) rfcAdvise("RFC 9110: a 406 response SHOULD include a list of available representations");',
|
|
299638
|
+
" if (!text) return;",
|
|
299639
|
+
" if (isJsonSubtype(media.subtype)) {",
|
|
299640
|
+
' if (text.charCodeAt(0) === 65279) pm.expect.fail("RFC 8259 forbids a byte order mark at the start of JSON text");',
|
|
299641
|
+
' var charsetParam = contentTypeValue.match(/charset\\s*=\\s*"?([^";\\s]+)"?/i);',
|
|
299642
|
+
' if (charsetParam) rfcAdvise("RFC 8259 defines no charset parameter for JSON media types; got charset=" + charsetParam[1]);',
|
|
299643
|
+
" }",
|
|
299644
|
+
' if (media.raw === "application/x-ndjson" || media.raw === "application/jsonl" || media.raw === "application/x-jsonlines") {',
|
|
299645
|
+
' 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); } });',
|
|
299646
|
+
" }",
|
|
299647
|
+
' if (media.raw === "text/event-stream") {',
|
|
299648
|
+
' 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); });',
|
|
299649
|
+
" }",
|
|
299650
|
+
' if (media.type === "multipart") {',
|
|
299651
|
+
' var boundary = contentTypeValue.match(/;\\s*boundary=(?:"([^"]*)"|([^;]*))/i);',
|
|
299652
|
+
' var boundaryValue = boundary ? (boundary[1] !== undefined ? boundary[1] : boundary[2].trim()) : "";',
|
|
299653
|
+
' if (!boundaryValue) pm.expect.fail("multipart responses must carry a boundary parameter (RFC 2046): " + contentTypeValue);',
|
|
299654
|
+
" else {",
|
|
299655
|
+
' if (boundaryValue.length > 70) pm.expect.fail("multipart boundary must be 1-70 characters (RFC 2046): " + boundaryValue);',
|
|
299656
|
+
` 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);`,
|
|
299657
|
+
" }",
|
|
299658
|
+
" }",
|
|
299659
|
+
' if (media.raw === "application/hal+json") {',
|
|
299660
|
+
" var hal; try { hal = JSON.parse(text); } catch (error) { hal = null; }",
|
|
299661
|
+
' if (hal && typeof hal === "object" && !Array.isArray(hal)) {',
|
|
299662
|
+
" var halLinks = hal._links;",
|
|
299663
|
+
' if (halLinks !== undefined && (typeof halLinks !== "object" || Array.isArray(halLinks) || halLinks === null)) pm.expect.fail("HAL _links must be an object of link relations");',
|
|
299664
|
+
' 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"); }); });',
|
|
299665
|
+
" var halEmbedded = hal._embedded;",
|
|
299666
|
+
' if (halEmbedded !== undefined && (typeof halEmbedded !== "object" || Array.isArray(halEmbedded) || halEmbedded === null)) pm.expect.fail("HAL _embedded must be an object of resource names");',
|
|
299667
|
+
" }",
|
|
299668
|
+
" }",
|
|
299669
|
+
' if (media.raw === "application/vnd.api+json") {',
|
|
299670
|
+
" var jsonApi; try { jsonApi = JSON.parse(text); } catch (error) { jsonApi = null; }",
|
|
299671
|
+
' if (jsonApi && typeof jsonApi === "object" && !Array.isArray(jsonApi)) {',
|
|
299672
|
+
' 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");',
|
|
299673
|
+
' if (jsonApi.data !== undefined && jsonApi.errors !== undefined) pm.expect.fail("JSON:API forbids data and errors in the same document");',
|
|
299674
|
+
" }",
|
|
299675
|
+
" }",
|
|
299676
|
+
' if (media.subtype === "problem+xml") {',
|
|
299677
|
+
' if (text.indexOf("urn:ietf:rfc:7807") === -1) rfcAdvise("application/problem+xml body does not reference the urn:ietf:rfc:7807 namespace");',
|
|
299678
|
+
" var xmlStatus = text.match(/<status[^>]*>\\s*([0-9]+)\\s*<\\/status>/);",
|
|
299679
|
+
' 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 + ")");',
|
|
299680
|
+
" }",
|
|
299681
|
+
"});",
|
|
299682
|
+
"pm.test('Structured field response headers parse per RFC 8941', function () {",
|
|
299683
|
+
' [["Cache-Status", "list"], ["Proxy-Status", "list"], ["Priority", "dict"], ["RateLimit", "dict"], ["RateLimit-Policy", "dict"], ["Signature", "dict"], ["Signature-Input", "dict"]].forEach(function (pair) {',
|
|
299684
|
+
' var value = rfcHeaderAll(pair[0]).join(", ");',
|
|
299685
|
+
" if (!value) return;",
|
|
299686
|
+
' if (!rfcSfParse(value, pair[1])) pm.expect.fail(pair[0] + " is not a valid RFC 8941 structured field (" + pair[1] + "): " + value);',
|
|
299687
|
+
" });",
|
|
299688
|
+
"});",
|
|
299689
|
+
"pm.test('Content-Digest and Repr-Digest match the response body (RFC 9530)', function () {",
|
|
299690
|
+
" var cryptoLib = null;",
|
|
299691
|
+
' try { cryptoLib = require("crypto-js"); } catch (error) { cryptoLib = null; }',
|
|
299692
|
+
' ["Content-Digest", "Repr-Digest"].forEach(function (name) {',
|
|
299693
|
+
" var value = rfcRespHeader(name);",
|
|
299694
|
+
" if (!value) return;",
|
|
299695
|
+
' if (!rfcSfParse(value, "dict")) { pm.expect.fail(name + " is not a valid RFC 8941 dictionary (RFC 9530): " + value); return; }',
|
|
299696
|
+
' if (!cryptoLib || rfcRespHeader("Content-Encoding")) return;',
|
|
299697
|
+
' var media = mediaParts(rfcRespHeader("Content-Type"));',
|
|
299698
|
+
' if (media.type !== "text" && !isJsonSubtype(media.subtype) && !/xml$/.test(media.subtype)) return;',
|
|
299699
|
+
" rfcSplitList(value).forEach(function (entry) {",
|
|
299700
|
+
" var match = entry.trim().match(/^(sha-256|sha-512)=:([A-Za-z0-9+\\/=]+):$/);",
|
|
299701
|
+
" if (!match) return;",
|
|
299702
|
+
' var computed = match[1] === "sha-256" ? cryptoLib.SHA256(responseText()) : cryptoLib.SHA512(responseText());',
|
|
299703
|
+
" var encoded = cryptoLib.enc.Base64.stringify(computed);",
|
|
299704
|
+
' 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]);',
|
|
299705
|
+
" });",
|
|
299706
|
+
" });",
|
|
299707
|
+
"});",
|
|
299708
|
+
"pm.test('Request credentials are well-formed per their authentication scheme RFCs', function () {",
|
|
299709
|
+
' var authorization = requestHeader("Authorization");',
|
|
299710
|
+
' if (authorization && authorization.indexOf("{{") === -1) {',
|
|
299711
|
+
" var schemeMatch = authorization.match(/^(\\S+)(?:\\s+([\\s\\S]*))?$/);",
|
|
299712
|
+
' var authScheme = schemeMatch ? schemeMatch[1].toLowerCase() : "";',
|
|
299713
|
+
' var authParams = schemeMatch && schemeMatch[2] !== undefined ? schemeMatch[2].trim() : "";',
|
|
299714
|
+
' if (authScheme === "basic") {',
|
|
299715
|
+
" var decoded = rfcBase64Decode(authParams);",
|
|
299716
|
+
' if (decoded === null) pm.expect.fail("Basic credentials must be base64 (RFC 7617)");',
|
|
299717
|
+
' else if (decoded.indexOf(":") === -1) pm.expect.fail("Basic credentials must decode to user-id:password (RFC 7617)");',
|
|
299718
|
+
" }",
|
|
299719
|
+
' if (authScheme === "bearer" && !/^[A-Za-z0-9\\-._~+\\/]+=*$/.test(authParams)) pm.expect.fail("Bearer token does not match the b64token grammar (RFC 6750)");',
|
|
299720
|
+
' if (authScheme === "digest") {',
|
|
299721
|
+
' 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); });',
|
|
299722
|
+
' var digestResponse = authParams.match(/\\bresponse\\s*=\\s*"?([^",\\s]+)"?/i);',
|
|
299723
|
+
' if (digestResponse && !/^[0-9a-fA-F]+$/.test(digestResponse[1])) pm.expect.fail("Digest response parameter must be hex (RFC 7616): " + digestResponse[1]);',
|
|
299724
|
+
" }",
|
|
299725
|
+
" }",
|
|
299726
|
+
' var wantsJwt = (contract.security || []).some(function (alternative) { return alternative.some(function (check) { return check.prefix === "Bearer " && String(check.bearerFormat || "").toUpperCase() === "JWT"; }); });',
|
|
299727
|
+
' if (wantsJwt && authorization && authorization.indexOf("{{") === -1 && authorization.toLowerCase().indexOf("bearer ") === 0) {',
|
|
299728
|
+
" var jwtToken = authorization.slice(7).trim();",
|
|
299729
|
+
' var jwtSegments = jwtToken.split(".");',
|
|
299730
|
+
' if (jwtSegments.length !== 3) pm.expect.fail("bearerFormat JWT tokens must have three base64url segments (RFC 7519); got " + jwtSegments.length);',
|
|
299731
|
+
' else if (!jwtSegments.every(function (segment) { return /^[A-Za-z0-9_-]+$/.test(segment); })) pm.expect.fail("JWT segments must be base64url (RFC 7515)");',
|
|
299732
|
+
" else {",
|
|
299733
|
+
' var jwtDecode = function (segment) { var padded = segment.replace(/-/g, "+").replace(/_/g, "/"); while (padded.length % 4 !== 0) padded += "="; return rfcBase64Decode(padded); };',
|
|
299734
|
+
" var jwtHeader = null; var jwtPayload = null;",
|
|
299735
|
+
' try { jwtHeader = JSON.parse(jwtDecode(jwtSegments[0])); } catch (error) { pm.expect.fail("JWT header segment does not decode to JSON (RFC 7515)"); }',
|
|
299736
|
+
' try { jwtPayload = JSON.parse(jwtDecode(jwtSegments[1])); } catch (error) { pm.expect.fail("JWT payload segment does not decode to JSON (RFC 7519)"); }',
|
|
299737
|
+
' if (jwtHeader && typeof jwtHeader.alg !== "string") pm.expect.fail("JWT header must carry a string alg member (RFC 7515)");',
|
|
299738
|
+
" if (jwtPayload) {",
|
|
299739
|
+
' ["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)"); });',
|
|
299740
|
+
' if (typeof jwtPayload.exp === "number" && jwtPayload.exp * 1000 < Date.now()) rfcAdvise("RFC 7519: the outgoing JWT exp claim is already in the past");',
|
|
299741
|
+
" }",
|
|
299742
|
+
" }",
|
|
299743
|
+
" }",
|
|
299744
|
+
' if (hasQueryParam("access_token")) rfcAdvise("RFC 6750: bearer tokens SHOULD NOT travel in the query string");',
|
|
299745
|
+
" (contract.security || []).forEach(function (alternative) {",
|
|
299746
|
+
" alternative.forEach(function (check) {",
|
|
299747
|
+
" if (!check.checkable || !check.name) return;",
|
|
299748
|
+
' if (check.in === "query") { if (hasQueryParam(check.name)) rfcAdvise("Security scheme " + check.scheme + " sends credentials in the query string"); return; }',
|
|
299749
|
+
' if (check.in !== "header" || String(check.name).toLowerCase() === "authorization") return;',
|
|
299750
|
+
" var apiKeyValue = requestHeader(check.name);",
|
|
299751
|
+
' if (!apiKeyValue || apiKeyValue.indexOf("{{") !== -1) return;',
|
|
299752
|
+
' if (apiKeyValue !== apiKeyValue.trim()) pm.expect.fail("API key header " + check.name + " carries leading or trailing whitespace");',
|
|
299753
|
+
' if (!rfcIsFieldContent(apiKeyValue)) pm.expect.fail("API key header " + check.name + " contains characters forbidden by RFC 9110 field-content");',
|
|
299754
|
+
" });",
|
|
299755
|
+
" });",
|
|
299756
|
+
"});",
|
|
299757
|
+
"pm.test('Request preconditions, preferences, and patch bodies follow their RFCs', function () {",
|
|
299758
|
+
' ["If-Match", "If-None-Match"].forEach(function (name) {',
|
|
299759
|
+
" var value = requestHeader(name);",
|
|
299760
|
+
' if (!value || value.indexOf("{{") !== -1 || value.trim() === "*") return;',
|
|
299761
|
+
' 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()); });',
|
|
299762
|
+
" });",
|
|
299763
|
+
' var prefer = requestHeader("Prefer");',
|
|
299764
|
+
' if (prefer && prefer.indexOf("{{") === -1) {',
|
|
299765
|
+
' 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()); });',
|
|
299766
|
+
" }",
|
|
299767
|
+
' var requestContentType = mediaBase(requestHeader("Content-Type"));',
|
|
299768
|
+
" var body = pm.request.body;",
|
|
299769
|
+
' var raw = body && body.mode === "raw" && typeof body.raw === "string" ? body.raw : "";',
|
|
299770
|
+
' if (!raw.trim() || raw.indexOf("{{") !== -1 || /"<[^"<>]*>"/.test(raw)) return;',
|
|
299771
|
+
' if (requestContentType === "application/json-patch+json") {',
|
|
299772
|
+
' 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; }',
|
|
299773
|
+
' if (!Array.isArray(patch)) { pm.expect.fail("A JSON Patch document must be an array of operations (RFC 6902)"); return; }',
|
|
299774
|
+
" patch.forEach(function (operation, operationIndex) {",
|
|
299775
|
+
' if (!operation || typeof operation !== "object" || Array.isArray(operation)) { pm.expect.fail("JSON Patch operation " + operationIndex + " must be an object (RFC 6902)"); return; }',
|
|
299776
|
+
' 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);',
|
|
299777
|
+
" var pointerPattern = /^(\\/([^\\/~]|~[01])*)*$/;",
|
|
299778
|
+
' if (typeof operation.path !== "string" || !pointerPattern.test(operation.path)) pm.expect.fail("JSON Patch operation " + operationIndex + " path must be an RFC 6901 JSON Pointer");',
|
|
299779
|
+
' 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)");',
|
|
299780
|
+
' 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)");',
|
|
299781
|
+
" });",
|
|
299782
|
+
" }",
|
|
299783
|
+
' if (requestContentType === "application/merge-patch+json") {',
|
|
299784
|
+
' 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); }',
|
|
299785
|
+
" }",
|
|
299786
|
+
"});",
|
|
299787
|
+
"pm.test('Deprecated operation signals deprecation in the response', function () {",
|
|
299788
|
+
" if (!contract.deprecated) return;",
|
|
299789
|
+
' if (!rfcRespHeader("Deprecation") && !rfcRespHeader("Sunset")) rfcAdvise("RFC 9745: the OpenAPI document deprecates this operation but the response carries neither Deprecation nor Sunset");',
|
|
299790
|
+
"});",
|
|
299791
|
+
"pm.test('OpenAPI link expressions resolve against the response', function () {",
|
|
299792
|
+
" if (!selected || !selected.value.links || selected.value.links.length === 0) return;",
|
|
299793
|
+
" var linkBody = null; var linkBodyParsed = false;",
|
|
299794
|
+
" selected.value.links.forEach(function (expression) {",
|
|
299795
|
+
' if (expression.kind === "header") {',
|
|
299796
|
+
' if (!pm.response.headers.get(expression.header)) pm.expect.fail("OpenAPI link " + expression.link + " references response header " + expression.header + " which is absent");',
|
|
299797
|
+
" return;",
|
|
299798
|
+
" }",
|
|
299799
|
+
" if (!linkBodyParsed) { linkBodyParsed = true; try { linkBody = JSON.parse(responseText()); } catch (error) { linkBody = null; } }",
|
|
299800
|
+
' if (linkBody === null) { pm.expect.fail("OpenAPI link " + expression.link + " references the response body but the body is not JSON"); return; }',
|
|
299801
|
+
" var target = linkBody;",
|
|
299802
|
+
' var tokens = String(expression.pointer).split("/").slice(1).map(function (token) { return token.replace(/~1/g, "/").replace(/~0/g, "~"); });',
|
|
299803
|
+
" for (var t = 0; t < tokens.length; t += 1) {",
|
|
299804
|
+
' if (target !== null && typeof target === "object") target = Array.isArray(target) ? target[Number(tokens[t])] : target[tokens[t]];',
|
|
299805
|
+
" else { target = undefined; break; }",
|
|
299806
|
+
" }",
|
|
299807
|
+
' if (target === undefined) pm.expect.fail("OpenAPI link " + expression.link + " expression $response.body#" + expression.pointer + " does not resolve in the response body");',
|
|
299808
|
+
" });",
|
|
299809
|
+
"});",
|
|
299810
|
+
"pm.test('Request URL conforms to an OpenAPI servers entry', function () {",
|
|
299811
|
+
" if (!contract.servers || contract.servers.length === 0) return;",
|
|
299812
|
+
' var requestUrl = "";',
|
|
299813
|
+
' try { requestUrl = String(pm.request.url.toString()); } catch (ignored) { requestUrl = ""; }',
|
|
299814
|
+
' if (!requestUrl || requestUrl.indexOf("{{") !== -1) return;',
|
|
299815
|
+
' var pathOnly = requestUrl.replace(/^[a-z][a-z0-9+.-]*:\\/\\/[^\\/]+/i, "");',
|
|
299816
|
+
' 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; } });',
|
|
299817
|
+
' if (!matched) rfcAdvise("Request URL does not match any OpenAPI servers entry: " + requestUrl);',
|
|
299818
|
+
"});",
|
|
299086
299819
|
...operation.security ? [
|
|
299087
299820
|
"pm.test('Request carries credentials required by OpenAPI security', function () {",
|
|
299088
299821
|
" function satisfied(check) {",
|
|
@@ -299122,6 +299855,12 @@ function createContractScript(operation, warnings = []) {
|
|
|
299122
299855
|
' if (param.allowEmptyValue && entries.length === 1 && entries[0] === "") return;',
|
|
299123
299856
|
" if (entries.some(isPlaceholder)) return;",
|
|
299124
299857
|
" value = entries.map(function (entry) { return coerceBySchema(decodeComponent(entry), param.items); });",
|
|
299858
|
+
' } else if (param.decode === "deepObject") {',
|
|
299859
|
+
" var deepValue = {}; var deepFound = false; var deepPlaceholder = false;",
|
|
299860
|
+
' 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]]) || {}); });',
|
|
299861
|
+
' if (!deepFound) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
299862
|
+
" if (deepPlaceholder) return;",
|
|
299863
|
+
" value = deepValue;",
|
|
299125
299864
|
" } else if (param.decode) {",
|
|
299126
299865
|
' var joined = param.in === "query" ? queryValue(String(param.name).toLowerCase()) : headerValue(param.name);',
|
|
299127
299866
|
' if (joined === undefined) { if (param.required) pm.expect.fail("Required parameter " + param.in + ":" + param.name + " was not sent for " + contract.method + " " + contract.path); return; }',
|
|
@@ -299138,6 +299877,8 @@ function createContractScript(operation, warnings = []) {
|
|
|
299138
299877
|
' } else if (param.in === "path") {',
|
|
299139
299878
|
" value = pathParamValue(param.name);",
|
|
299140
299879
|
" if (value === undefined) return;",
|
|
299880
|
+
' if (param.pathStyle === "label") { if (String(value).charAt(0) !== ".") return; value = String(value).slice(1); }',
|
|
299881
|
+
' if (param.pathStyle === "matrix") { var matrixPrefix = ";" + param.name + "="; if (String(value).indexOf(matrixPrefix) !== 0) return; value = String(value).slice(matrixPrefix.length); }',
|
|
299141
299882
|
' if (isPlaceholder(value) || value.charAt(0) === ":" || value.charAt(0) === "{") return;',
|
|
299142
299883
|
" value = coerceBySchema(value, param.schema);",
|
|
299143
299884
|
' } else if (param.in === "cookie") {',
|
|
@@ -299189,6 +299930,9 @@ function createContractScript(operation, warnings = []) {
|
|
|
299189
299930
|
' if (pm.response.headers.get("Content-Encoding")) return;',
|
|
299190
299931
|
" var mustBeEmpty = isBodyless() || (selected && Object.keys(selected.value.content || {}).length === 0);",
|
|
299191
299932
|
' 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);',
|
|
299933
|
+
"});",
|
|
299934
|
+
"pm.test('RFC SHOULD-level advisories are documented', function () {",
|
|
299935
|
+
' pm.expect(rfcAdvisories, "SHOULD-level findings (advisory, non-failing): " + rfcAdvisories.join("; ")).to.be.an("array");',
|
|
299192
299936
|
"});"
|
|
299193
299937
|
];
|
|
299194
299938
|
}
|
|
@@ -299258,6 +300002,9 @@ function assertStaticRequestShape(operation, request) {
|
|
|
299258
300002
|
}
|
|
299259
300003
|
}
|
|
299260
300004
|
const warnings = collectStaticBodyWarnings(operation, request, contentType2);
|
|
300005
|
+
if (["GET", "HEAD", "DELETE"].includes(operation.method) && hasRequestBody(request)) {
|
|
300006
|
+
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`);
|
|
300007
|
+
}
|
|
299261
300008
|
if (operation.requestBody && !operation.requestBody.required && operation.requestBody.contentTypes.length > 0 && hasRequestBody(request) && contentType2) {
|
|
299262
300009
|
const actual = contentType2.toLowerCase().split(";")[0]?.trim() ?? "";
|
|
299263
300010
|
const matches = operation.requestBody.contentTypes.some((expected) => mediaTypeMatchesPattern(expected.toLowerCase(), actual));
|
|
@@ -299512,6 +300259,15 @@ function asRecord7(value) {
|
|
|
299512
300259
|
}
|
|
299513
300260
|
return value;
|
|
299514
300261
|
}
|
|
300262
|
+
function adviseWorkspaceFlipForbidden(error2) {
|
|
300263
|
+
if (error2 instanceof HttpError && error2.status === 403) {
|
|
300264
|
+
const body = error2.responseBody || "";
|
|
300265
|
+
if (/addWorkspaceLevelTeamRoles/i.test(body) || /You are not authorized to perform this action/i.test(body)) {
|
|
300266
|
+
return new Error(WORKSPACE_PERSONAL_ONLY_ADVICE, { cause: error2 });
|
|
300267
|
+
}
|
|
300268
|
+
}
|
|
300269
|
+
return error2;
|
|
300270
|
+
}
|
|
299515
300271
|
function extractGitRepoUrl(value) {
|
|
299516
300272
|
if (!value) return null;
|
|
299517
300273
|
if (typeof value === "string") {
|
|
@@ -299817,7 +300573,7 @@ var PostmanGatewayAssetsClient = class _PostmanGatewayAssetsClient {
|
|
|
299817
300573
|
}
|
|
299818
300574
|
} catch (error2) {
|
|
299819
300575
|
await this.deleteWorkspace(workspaceId).catch(() => void 0);
|
|
299820
|
-
throw error2;
|
|
300576
|
+
throw adviseWorkspaceFlipForbidden(error2);
|
|
299821
300577
|
}
|
|
299822
300578
|
return { id: workspaceId };
|
|
299823
300579
|
}
|
|
@@ -301074,7 +301830,7 @@ function resolveActionVersion(explicit) {
|
|
|
301074
301830
|
if (explicit) {
|
|
301075
301831
|
return explicit;
|
|
301076
301832
|
}
|
|
301077
|
-
return "
|
|
301833
|
+
return typeof __ACTION_VERSION__ !== "undefined" && __ACTION_VERSION__ ? __ACTION_VERSION__ : "unknown";
|
|
301078
301834
|
}
|
|
301079
301835
|
function telemetryDisabled(env) {
|
|
301080
301836
|
const flag = String(env.POSTMAN_ACTIONS_TELEMETRY ?? "").trim().toLowerCase();
|
|
@@ -301196,11 +301952,23 @@ function createTelemetryContext(options) {
|
|
|
301196
301952
|
};
|
|
301197
301953
|
}
|
|
301198
301954
|
|
|
301199
|
-
// src/
|
|
301955
|
+
// src/action-version.ts
|
|
301200
301956
|
var import_node_fs3 = require("node:fs");
|
|
301957
|
+
var import_node_path3 = require("node:path");
|
|
301958
|
+
function resolveActionVersion2() {
|
|
301959
|
+
try {
|
|
301960
|
+
const raw = (0, import_node_fs3.readFileSync)((0, import_node_path3.join)(__dirname, "..", "package.json"), "utf8");
|
|
301961
|
+
return JSON.parse(raw).version ?? "unknown";
|
|
301962
|
+
} catch {
|
|
301963
|
+
return "unknown";
|
|
301964
|
+
}
|
|
301965
|
+
}
|
|
301966
|
+
|
|
301967
|
+
// src/lib/spec/openapi-loader.ts
|
|
301968
|
+
var import_node_fs4 = require("node:fs");
|
|
301201
301969
|
var import_promises3 = require("node:fs/promises");
|
|
301202
301970
|
var import_node_url2 = require("node:url");
|
|
301203
|
-
var
|
|
301971
|
+
var import_node_path4 = __toESM(require("node:path"), 1);
|
|
301204
301972
|
|
|
301205
301973
|
// node_modules/@apidevtools/json-schema-ref-parser/dist/lib/util/convert-path-to-posix.js
|
|
301206
301974
|
var win32Sep = "\\";
|
|
@@ -301541,14 +302309,14 @@ function fromFileSystemPath(path10) {
|
|
|
301541
302309
|
const hasProjectUri = upperPath.includes(posixUpper);
|
|
301542
302310
|
const isAbsolutePath = isAbsoluteWin32Path.test(path10) || path10.startsWith("http://") || path10.startsWith("https://") || path10.startsWith("file://");
|
|
301543
302311
|
if (!(hasProjectDir || hasProjectUri || isAbsolutePath) && !projectDir.startsWith("http")) {
|
|
301544
|
-
const
|
|
302312
|
+
const join4 = (a, b) => {
|
|
301545
302313
|
if (a.endsWith("/") || a.endsWith("\\")) {
|
|
301546
302314
|
return a + b;
|
|
301547
302315
|
} else {
|
|
301548
302316
|
return a + "/" + b;
|
|
301549
302317
|
}
|
|
301550
302318
|
};
|
|
301551
|
-
path10 =
|
|
302319
|
+
path10 = join4(projectDir, path10);
|
|
301552
302320
|
}
|
|
301553
302321
|
path10 = convertPathToPosix(path10);
|
|
301554
302322
|
}
|
|
@@ -305663,6 +306431,7 @@ function inventory$Ref($refParent, $refKey, path10, scopeBase, dynamicIdScope, p
|
|
|
305663
306431
|
const file = stripHash(pointer.path);
|
|
305664
306432
|
const hash = getHash(pointer.path);
|
|
305665
306433
|
const external = file !== $refs._root$Ref.path && !$refs._aliases[file];
|
|
306434
|
+
const nestedResource = Boolean($refs._aliases[file]) && pointer.$ref.value !== $refs._root$Ref.value;
|
|
305666
306435
|
const extended = ref_default.isExtended$Ref($ref);
|
|
305667
306436
|
indirections += pointer.indirections;
|
|
305668
306437
|
const existingEntry = findInInventory(inventory, $refParent, $refKey);
|
|
@@ -305696,6 +306465,8 @@ function inventory$Ref($refParent, $refKey, path10, scopeBase, dynamicIdScope, p
|
|
|
305696
306465
|
// Does this $ref extend its resolved value? (i.e. it has extra properties, in addition to "$ref")
|
|
305697
306466
|
external,
|
|
305698
306467
|
// Does this $ref pointer point to a file other than the main JSON Schema file?
|
|
306468
|
+
nestedResource,
|
|
306469
|
+
// Does this $ref resolve to an embedded schema resource with its own $id?
|
|
305699
306470
|
indirections
|
|
305700
306471
|
// The number of indirect references that were traversed to resolve the value
|
|
305701
306472
|
});
|
|
@@ -305731,7 +306502,7 @@ function remap(inventory, options, rootId) {
|
|
|
305731
306502
|
for (const entry of inventory) {
|
|
305732
306503
|
const bundleOpts = options.bundle || {};
|
|
305733
306504
|
if (!entry.external) {
|
|
305734
|
-
if (bundleOpts.optimizeInternalRefs !== false) {
|
|
306505
|
+
if (bundleOpts.optimizeInternalRefs !== false && !entry.nestedResource) {
|
|
305735
306506
|
entry.$ref.$ref = entry.hash;
|
|
305736
306507
|
}
|
|
305737
306508
|
} else if (entry.file === file && entry.hash === hash) {
|
|
@@ -313535,22 +314306,22 @@ async function loadOpenApiContractSpec(specUrl, options = {}) {
|
|
|
313535
314306
|
async function loadOpenApiContractSpecFromPath(specPath, options = {}) {
|
|
313536
314307
|
if (!specPath) throw new Error("CONTRACT_SPEC_READ_FAILED: spec-path must not be empty");
|
|
313537
314308
|
const workspaceRoot = (() => {
|
|
313538
|
-
const root =
|
|
314309
|
+
const root = import_node_path4.default.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
|
|
313539
314310
|
try {
|
|
313540
|
-
return (0,
|
|
314311
|
+
return (0, import_node_fs4.realpathSync)(root);
|
|
313541
314312
|
} catch {
|
|
313542
314313
|
return root;
|
|
313543
314314
|
}
|
|
313544
314315
|
})();
|
|
313545
|
-
const resolved =
|
|
314316
|
+
const resolved = import_node_path4.default.resolve(workspaceRoot, specPath);
|
|
313546
314317
|
let absolutePath;
|
|
313547
314318
|
try {
|
|
313548
|
-
absolutePath = (0,
|
|
314319
|
+
absolutePath = (0, import_node_fs4.realpathSync)(resolved);
|
|
313549
314320
|
} catch (error2) {
|
|
313550
314321
|
throw new Error(`CONTRACT_SPEC_READ_FAILED: Unable to read spec at ${specPath}`, { cause: error2 });
|
|
313551
314322
|
}
|
|
313552
|
-
const rel =
|
|
313553
|
-
if (!rel || rel.startsWith("..") ||
|
|
314323
|
+
const rel = import_node_path4.default.relative(workspaceRoot, absolutePath);
|
|
314324
|
+
if (!rel || rel.startsWith("..") || import_node_path4.default.isAbsolute(rel)) {
|
|
313554
314325
|
throw new Error(`CONTRACT_SPEC_READ_FAILED: spec-path must resolve inside ${workspaceRoot}, got: ${specPath}`);
|
|
313555
314326
|
}
|
|
313556
314327
|
const maxBytes = options.maxBytesPerResource ?? SAFE_FETCH_LIMITS.maxBytesPerResource;
|
|
@@ -313964,6 +314735,17 @@ function buildOperationScript(operation, index, warnings) {
|
|
|
313964
314735
|
' pm.expect(pm.response.code, "GraphQL responses are HTTP 200 even when the data field carries errors").to.be.below(500);',
|
|
313965
314736
|
"});"
|
|
313966
314737
|
);
|
|
314738
|
+
lines.push(
|
|
314739
|
+
"pm.test(" + JSON.stringify("[" + label + "] GraphQL-over-HTTP media type and status are consistent") + ", function () {",
|
|
314740
|
+
' var contentType = ((pm.response.headers && pm.response.headers.get && pm.response.headers.get("Content-Type")) || "").toLowerCase();',
|
|
314741
|
+
' var mediaType = contentType.split(";")[0].trim();',
|
|
314742
|
+
" if (!mediaType) return;",
|
|
314743
|
+
' 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>")); }',
|
|
314744
|
+
" var wellFormed = gqlBody.data !== undefined || Array.isArray(gqlBody.errors);",
|
|
314745
|
+
' 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"); }',
|
|
314746
|
+
' 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); }',
|
|
314747
|
+
"});"
|
|
314748
|
+
);
|
|
313967
314749
|
lines.push(
|
|
313968
314750
|
`pm.test(${JSON.stringify(`[${label}] GraphQL errors are well-formed and not a total failure`)}, function () {`,
|
|
313969
314751
|
" var errors = gqlBody.errors;",
|
|
@@ -315504,6 +316286,8 @@ function createSoapScript(operation, warnings = []) {
|
|
|
315504
316286
|
hasOutput: Boolean(operation.output)
|
|
315505
316287
|
};
|
|
315506
316288
|
const responseRegex = operation.expectedResponseElement ? elementPresenceRegex(operation.expectedResponseElement) : "";
|
|
316289
|
+
const mediaType = operation.soapVersion === "1.2" ? "application/soap+xml" : "text/xml";
|
|
316290
|
+
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);';
|
|
315507
316291
|
const lines = [
|
|
315508
316292
|
`var soap = JSON.parse(${JSON.stringify(JSON.stringify(meta))});`,
|
|
315509
316293
|
'var bodyText = (pm.response.text && pm.response.text()) || "";',
|
|
@@ -315514,9 +316298,11 @@ function createSoapScript(operation, warnings = []) {
|
|
|
315514
316298
|
" pm.response.to.have.status(200);",
|
|
315515
316299
|
"});",
|
|
315516
316300
|
"",
|
|
315517
|
-
|
|
316301
|
+
// SOAP 1.1 responses bind to text/xml (SOAP 1.1 HTTP binding, WS-I Basic
|
|
316302
|
+
// Profile); SOAP 1.2 responses bind to application/soap+xml (RFC 3902).
|
|
316303
|
+
`pm.test('SOAP response Content-Type matches the SOAP ${operation.soapVersion} binding', function () {`,
|
|
315518
316304
|
' var ct = header("Content-Type").toLowerCase();',
|
|
315519
|
-
|
|
316305
|
+
` pm.expect(ct, "SOAP ${operation.soapVersion} responses use ${mediaType} (got: " + (ct || "<missing>") + ")").to.include("${mediaType}");`,
|
|
315520
316306
|
"});",
|
|
315521
316307
|
"",
|
|
315522
316308
|
"pm.test('SOAP Envelope element is present', function () {",
|
|
@@ -315533,6 +316319,13 @@ function createSoapScript(operation, warnings = []) {
|
|
|
315533
316319
|
' var detail = (bodyText.match(/<(?:[A-Za-z_][\\w.-]*:)?(?:faultstring|Reason|Text)[^>]*>([\\s\\S]*?)<\\//) || [])[1] || "";',
|
|
315534
316320
|
' pm.expect.fail("SOAP Fault returned for operation " + soap.name + (detail ? (": " + detail.trim()) : ""));',
|
|
315535
316321
|
" }",
|
|
316322
|
+
"});",
|
|
316323
|
+
"",
|
|
316324
|
+
"pm.test('SOAP Fault and HTTP status are consistent', function () {",
|
|
316325
|
+
' var faulted = matchTag("Fault").test(bodyText);',
|
|
316326
|
+
" var code = pm.response.code;",
|
|
316327
|
+
faultStatusLine,
|
|
316328
|
+
' if (!faulted && code === 500) pm.expect.fail("HTTP 500 from a SOAP endpoint must carry a SOAP Fault in the body");',
|
|
315536
316329
|
"});"
|
|
315537
316330
|
];
|
|
315538
316331
|
if (responseRegex) {
|
|
@@ -316784,6 +317577,7 @@ function normalizeSpecDocument(raw, warn) {
|
|
|
316784
317577
|
async function runBootstrap(inputs, dependencies) {
|
|
316785
317578
|
const telemetry = createTelemetryContext({
|
|
316786
317579
|
action: "postman-bootstrap-action",
|
|
317580
|
+
actionVersion: resolveActionVersion2(),
|
|
316787
317581
|
logger: dependencies.core
|
|
316788
317582
|
});
|
|
316789
317583
|
try {
|
|
@@ -317190,7 +317984,7 @@ async function runBootstrapInner(inputs, dependencies, telemetry) {
|
|
|
317190
317984
|
async () => {
|
|
317191
317985
|
if (inputs.specPath) {
|
|
317192
317986
|
const workspaceRoot = path9.resolve(process.env.GITHUB_WORKSPACE ?? process.cwd());
|
|
317193
|
-
return (0,
|
|
317987
|
+
return (0, import_node_fs5.readFileSync)(path9.resolve(workspaceRoot, inputs.specPath), "utf8");
|
|
317194
317988
|
}
|
|
317195
317989
|
if (dependencies.specFetcher === fetch) {
|
|
317196
317990
|
return safeFetchText(inputs.specUrl, { depth: 0 });
|