@postman-cse/onboarding-bootstrap 0.14.1 → 0.15.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/action.yml +4 -0
- package/dist/action.cjs +452 -84
- package/dist/cli.cjs +127 -13
- package/dist/index.cjs +452 -84
- package/package.json +1 -1
package/dist/action.cjs
CHANGED
|
@@ -46776,6 +46776,12 @@ var customerPreviewActionContract = {
|
|
|
46776
46776
|
description: "Postman access token used for governance and workspace mutations.",
|
|
46777
46777
|
required: false
|
|
46778
46778
|
},
|
|
46779
|
+
"credential-preflight": {
|
|
46780
|
+
description: "Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created; off skips the identity probes entirely (the reactive error guidance still applies). Promotion of the default to enforce is planned once the live e2e legs prove both directions.",
|
|
46781
|
+
required: false,
|
|
46782
|
+
default: "warn",
|
|
46783
|
+
allowedValues: ["enforce", "warn", "off"]
|
|
46784
|
+
},
|
|
46779
46785
|
"integration-backend": {
|
|
46780
46786
|
description: "Integration backend for downstream workspace connectivity.",
|
|
46781
46787
|
required: false,
|
|
@@ -47799,13 +47805,15 @@ var POSTMAN_ENDPOINT_PROFILES = {
|
|
|
47799
47805
|
apiBaseUrl: "https://api.getpostman.com",
|
|
47800
47806
|
bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
|
|
47801
47807
|
cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
|
|
47802
|
-
gatewayBaseUrl: "https://gateway.postman.com"
|
|
47808
|
+
gatewayBaseUrl: "https://gateway.postman.com",
|
|
47809
|
+
iapubBaseUrl: "https://iapub.postman.co"
|
|
47803
47810
|
},
|
|
47804
47811
|
beta: {
|
|
47805
47812
|
apiBaseUrl: "https://api.getpostman-beta.com",
|
|
47806
47813
|
bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
|
|
47807
47814
|
cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
|
|
47808
|
-
gatewayBaseUrl: "https://gateway.postman-beta.com"
|
|
47815
|
+
gatewayBaseUrl: "https://gateway.postman-beta.com",
|
|
47816
|
+
iapubBaseUrl: "https://iapub.postman.co"
|
|
47809
47817
|
}
|
|
47810
47818
|
};
|
|
47811
47819
|
function parsePostmanStack(value) {
|
|
@@ -47819,6 +47827,311 @@ function resolvePostmanEndpointProfile(stack) {
|
|
|
47819
47827
|
return POSTMAN_ENDPOINT_PROFILES[stack];
|
|
47820
47828
|
}
|
|
47821
47829
|
|
|
47830
|
+
// src/lib/postman/credential-identity.ts
|
|
47831
|
+
var sessionPath = "/api/sessions/current";
|
|
47832
|
+
var pmakMemo = /* @__PURE__ */ new Map();
|
|
47833
|
+
var sessionMemo = /* @__PURE__ */ new Map();
|
|
47834
|
+
var memoizedSessionIdentity;
|
|
47835
|
+
function getMemoizedSessionIdentity() {
|
|
47836
|
+
return memoizedSessionIdentity;
|
|
47837
|
+
}
|
|
47838
|
+
function asRecord(value) {
|
|
47839
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
47840
|
+
return void 0;
|
|
47841
|
+
}
|
|
47842
|
+
return value;
|
|
47843
|
+
}
|
|
47844
|
+
function coerceId(raw) {
|
|
47845
|
+
return raw ? String(raw) : void 0;
|
|
47846
|
+
}
|
|
47847
|
+
function coerceText(raw) {
|
|
47848
|
+
if (typeof raw !== "string") {
|
|
47849
|
+
return void 0;
|
|
47850
|
+
}
|
|
47851
|
+
const trimmed = raw.trim();
|
|
47852
|
+
return trimmed ? trimmed : void 0;
|
|
47853
|
+
}
|
|
47854
|
+
function normalizeBaseUrl(raw) {
|
|
47855
|
+
return String(raw || "").replace(/\/+$/, "");
|
|
47856
|
+
}
|
|
47857
|
+
async function resolvePmakIdentity(opts) {
|
|
47858
|
+
const apiKey = String(opts.apiKey || "").trim();
|
|
47859
|
+
if (!apiKey) {
|
|
47860
|
+
return void 0;
|
|
47861
|
+
}
|
|
47862
|
+
const baseUrl = normalizeBaseUrl(opts.apiBaseUrl);
|
|
47863
|
+
const memoKey = `${baseUrl}::${apiKey}`;
|
|
47864
|
+
let pending = pmakMemo.get(memoKey);
|
|
47865
|
+
if (!pending) {
|
|
47866
|
+
pending = probePmakIdentity(baseUrl, apiKey, opts.fetchImpl ?? fetch);
|
|
47867
|
+
pmakMemo.set(memoKey, pending);
|
|
47868
|
+
}
|
|
47869
|
+
return pending;
|
|
47870
|
+
}
|
|
47871
|
+
async function probePmakIdentity(baseUrl, apiKey, fetchImpl) {
|
|
47872
|
+
try {
|
|
47873
|
+
const response = await fetchImpl(`${baseUrl}/me`, {
|
|
47874
|
+
method: "GET",
|
|
47875
|
+
headers: { "X-Api-Key": apiKey }
|
|
47876
|
+
});
|
|
47877
|
+
if (!response.ok) {
|
|
47878
|
+
return void 0;
|
|
47879
|
+
}
|
|
47880
|
+
const payload = asRecord(await response.json());
|
|
47881
|
+
const user = asRecord(payload?.user);
|
|
47882
|
+
if (!user) {
|
|
47883
|
+
return void 0;
|
|
47884
|
+
}
|
|
47885
|
+
return {
|
|
47886
|
+
source: "pmak/me",
|
|
47887
|
+
userId: coerceId(user.id),
|
|
47888
|
+
fullName: coerceText(user.fullName) ?? coerceText(user.username),
|
|
47889
|
+
teamId: coerceId(user.teamId),
|
|
47890
|
+
teamName: coerceText(user.teamName),
|
|
47891
|
+
teamDomain: coerceText(user.teamDomain)
|
|
47892
|
+
};
|
|
47893
|
+
} catch {
|
|
47894
|
+
return void 0;
|
|
47895
|
+
}
|
|
47896
|
+
}
|
|
47897
|
+
async function resolveSessionIdentity(opts) {
|
|
47898
|
+
const accessToken = String(opts.accessToken || "").trim();
|
|
47899
|
+
if (!accessToken) {
|
|
47900
|
+
return void 0;
|
|
47901
|
+
}
|
|
47902
|
+
const baseUrl = normalizeBaseUrl(opts.iapubBaseUrl);
|
|
47903
|
+
const memoKey = `${baseUrl}::${accessToken}`;
|
|
47904
|
+
let pending = sessionMemo.get(memoKey);
|
|
47905
|
+
if (!pending) {
|
|
47906
|
+
pending = probeSessionIdentity(baseUrl, accessToken, opts.fetchImpl ?? fetch);
|
|
47907
|
+
sessionMemo.set(memoKey, pending);
|
|
47908
|
+
}
|
|
47909
|
+
return pending;
|
|
47910
|
+
}
|
|
47911
|
+
async function probeSessionIdentity(baseUrl, accessToken, fetchImpl) {
|
|
47912
|
+
try {
|
|
47913
|
+
const response = await fetchImpl(`${baseUrl}${sessionPath}`, {
|
|
47914
|
+
method: "GET",
|
|
47915
|
+
headers: { "x-access-token": accessToken }
|
|
47916
|
+
});
|
|
47917
|
+
if (!response.ok) {
|
|
47918
|
+
return void 0;
|
|
47919
|
+
}
|
|
47920
|
+
const payload = asRecord(await response.json());
|
|
47921
|
+
if (!payload) {
|
|
47922
|
+
return void 0;
|
|
47923
|
+
}
|
|
47924
|
+
const identity = asRecord(payload.identity);
|
|
47925
|
+
const data = asRecord(payload.data);
|
|
47926
|
+
const user = asRecord(data?.user);
|
|
47927
|
+
const roleEntries = Array.isArray(user?.roles) ? user.roles.map((entry) => coerceText(entry) ?? coerceId(entry)).filter((entry) => Boolean(entry)) : [];
|
|
47928
|
+
const singleRole = coerceText(user?.role);
|
|
47929
|
+
const roles = roleEntries.length > 0 ? roleEntries : singleRole ? [singleRole] : void 0;
|
|
47930
|
+
const resolved = {
|
|
47931
|
+
source: "iapub/sessions",
|
|
47932
|
+
userId: coerceId(user?.id),
|
|
47933
|
+
fullName: coerceText(user?.fullName) ?? coerceText(user?.name) ?? coerceText(user?.username),
|
|
47934
|
+
teamId: coerceId(identity?.team),
|
|
47935
|
+
teamDomain: coerceText(identity?.domain),
|
|
47936
|
+
...roles ? { roles } : {},
|
|
47937
|
+
consumerType: coerceText(payload.consumerType) ?? coerceText(data?.consumerType) ?? coerceText(user?.consumerType)
|
|
47938
|
+
};
|
|
47939
|
+
memoizedSessionIdentity = resolved;
|
|
47940
|
+
return resolved;
|
|
47941
|
+
} catch {
|
|
47942
|
+
return void 0;
|
|
47943
|
+
}
|
|
47944
|
+
}
|
|
47945
|
+
function describeTeam(id) {
|
|
47946
|
+
const label = id?.teamName ?? id?.teamDomain;
|
|
47947
|
+
return `team ${id?.teamId ?? "unresolved"}${label ? ` (${label})` : ""}`;
|
|
47948
|
+
}
|
|
47949
|
+
function formatIdentityLine(id, mask) {
|
|
47950
|
+
const teamPart = id.teamId ? describeTeam(id) : "team unresolved";
|
|
47951
|
+
const domainPart = id.teamDomain ? `, domain ${id.teamDomain}` : "";
|
|
47952
|
+
if (id.source === "pmak/me") {
|
|
47953
|
+
const userPart = id.userId ? `user ${id.userId}${id.fullName ? ` (${id.fullName})` : ""}, ` : "";
|
|
47954
|
+
return mask(`postman: PMAK identity - ${userPart}${teamPart}${domainPart}`);
|
|
47955
|
+
}
|
|
47956
|
+
return mask(
|
|
47957
|
+
`postman: access-token session identity - ${teamPart}${domainPart} [source: iapub/sessions]`
|
|
47958
|
+
);
|
|
47959
|
+
}
|
|
47960
|
+
function crossCheckIdentities(args) {
|
|
47961
|
+
if (args.mode === "off") {
|
|
47962
|
+
return { ok: true, level: "ok", message: "" };
|
|
47963
|
+
}
|
|
47964
|
+
const pmakTeamId = args.pmak?.teamId;
|
|
47965
|
+
const sessionTeamId = args.session?.teamId;
|
|
47966
|
+
if (pmakTeamId && sessionTeamId && pmakTeamId !== sessionTeamId) {
|
|
47967
|
+
const level = args.mode === "enforce" ? "fail" : "note";
|
|
47968
|
+
const lead = level === "fail" ? "credential preflight FAILED" : "credential preflight note";
|
|
47969
|
+
const fix = level === "fail" ? "Use one credential pair from a single parent org: re-mint the access token from the same parent org as postman-api-key (postman-resolve-service-token-action, or POST https://api.getpostman.com/service-account-tokens with that team's PMAK), or set postman-api-key to the matching parent org." : "Use one credential pair from a single parent org. Set credential-preflight: enforce to fail the run on this condition.";
|
|
47970
|
+
return {
|
|
47971
|
+
ok: false,
|
|
47972
|
+
level,
|
|
47973
|
+
message: args.mask(
|
|
47974
|
+
`postman: ${lead} - PMAK belongs to ${describeTeam(args.pmak)} but the access token's session belongs to a different parent org, ${describeTeam(args.session)}. Assets would be created against one team while Bifrost linking and governance act under the other, producing duplicate-link 400s and workspaces not visible to the other credential. ` + fix
|
|
47975
|
+
)
|
|
47976
|
+
};
|
|
47977
|
+
}
|
|
47978
|
+
if (pmakTeamId && sessionTeamId) {
|
|
47979
|
+
const scope = args.workspaceTeamId || args.explicitTeamId ? "parent org team" : "team";
|
|
47980
|
+
const label = args.pmak?.teamName ?? args.pmak?.teamDomain ?? args.session?.teamName ?? args.session?.teamDomain;
|
|
47981
|
+
return {
|
|
47982
|
+
ok: true,
|
|
47983
|
+
level: "ok",
|
|
47984
|
+
message: args.mask(
|
|
47985
|
+
`postman: credential preflight OK - PMAK and access token both resolve to ${scope} ${pmakTeamId}${label ? ` (${label})` : ""}`
|
|
47986
|
+
)
|
|
47987
|
+
};
|
|
47988
|
+
}
|
|
47989
|
+
const missing = [
|
|
47990
|
+
!pmakTeamId ? "PMAK identity" : void 0,
|
|
47991
|
+
!sessionTeamId ? "access-token session identity" : void 0
|
|
47992
|
+
].filter(Boolean).join(" and ");
|
|
47993
|
+
return {
|
|
47994
|
+
ok: false,
|
|
47995
|
+
level: "note",
|
|
47996
|
+
message: args.mask(
|
|
47997
|
+
`postman: credential preflight note - cross-check skipped because the ${missing} did not resolve a team id; continuing with reactive error guidance only`
|
|
47998
|
+
)
|
|
47999
|
+
};
|
|
48000
|
+
}
|
|
48001
|
+
async function runCredentialPreflight(args) {
|
|
48002
|
+
if (args.mode === "off") {
|
|
48003
|
+
return;
|
|
48004
|
+
}
|
|
48005
|
+
const mask = args.mask;
|
|
48006
|
+
const apiKey = String(args.postmanApiKey || "").trim();
|
|
48007
|
+
const accessToken = String(args.postmanAccessToken || "").trim();
|
|
48008
|
+
let pmak;
|
|
48009
|
+
if (apiKey) {
|
|
48010
|
+
try {
|
|
48011
|
+
pmak = await resolvePmakIdentity({
|
|
48012
|
+
apiBaseUrl: args.apiBaseUrl,
|
|
48013
|
+
apiKey,
|
|
48014
|
+
fetchImpl: args.fetchImpl
|
|
48015
|
+
});
|
|
48016
|
+
} catch (error2) {
|
|
48017
|
+
args.log.warning(
|
|
48018
|
+
mask(
|
|
48019
|
+
`postman: credential preflight could not resolve PMAK identity: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
48020
|
+
)
|
|
48021
|
+
);
|
|
48022
|
+
}
|
|
48023
|
+
if (pmak) {
|
|
48024
|
+
args.log.info(formatIdentityLine(pmak, mask));
|
|
48025
|
+
} else {
|
|
48026
|
+
args.log.warning(
|
|
48027
|
+
mask("postman: credential preflight could not resolve PMAK identity from GET /me; continuing")
|
|
48028
|
+
);
|
|
48029
|
+
}
|
|
48030
|
+
}
|
|
48031
|
+
if (!accessToken) {
|
|
48032
|
+
args.log.info(mask("postman: Bifrost diagnostics limited: no access token"));
|
|
48033
|
+
return;
|
|
48034
|
+
}
|
|
48035
|
+
let session;
|
|
48036
|
+
try {
|
|
48037
|
+
session = await resolveSessionIdentity({
|
|
48038
|
+
iapubBaseUrl: args.iapubBaseUrl,
|
|
48039
|
+
accessToken,
|
|
48040
|
+
fetchImpl: args.fetchImpl
|
|
48041
|
+
});
|
|
48042
|
+
} catch (error2) {
|
|
48043
|
+
args.log.warning(
|
|
48044
|
+
mask(
|
|
48045
|
+
`postman: credential preflight could not resolve access-token session identity: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
48046
|
+
)
|
|
48047
|
+
);
|
|
48048
|
+
}
|
|
48049
|
+
if (session) {
|
|
48050
|
+
args.log.info(formatIdentityLine(session, mask));
|
|
48051
|
+
} else {
|
|
48052
|
+
args.log.warning(
|
|
48053
|
+
mask(
|
|
48054
|
+
"postman: credential preflight could not resolve the access-token session identity from iapub; continuing with reactive error guidance only"
|
|
48055
|
+
)
|
|
48056
|
+
);
|
|
48057
|
+
}
|
|
48058
|
+
const result = crossCheckIdentities({
|
|
48059
|
+
pmak,
|
|
48060
|
+
session,
|
|
48061
|
+
workspaceTeamId: args.workspaceTeamId,
|
|
48062
|
+
explicitTeamId: args.explicitTeamId,
|
|
48063
|
+
mode: args.mode,
|
|
48064
|
+
mask
|
|
48065
|
+
});
|
|
48066
|
+
if (!result.message) {
|
|
48067
|
+
return;
|
|
48068
|
+
}
|
|
48069
|
+
if (result.level === "fail") {
|
|
48070
|
+
throw new Error(result.message);
|
|
48071
|
+
}
|
|
48072
|
+
if (result.level === "note") {
|
|
48073
|
+
args.log.warning(result.message);
|
|
48074
|
+
return;
|
|
48075
|
+
}
|
|
48076
|
+
args.log.info(result.message);
|
|
48077
|
+
}
|
|
48078
|
+
|
|
48079
|
+
// src/lib/postman/error-advice.ts
|
|
48080
|
+
var WORKSPACE_PERSONAL_ONLY_ADVICE = "Workspace creation failed: This may be an Org-mode account that requires a workspace-team-id input. The Postman API does not allow creating team workspaces at the organization level. Use the workspace-team-id input to specify which sub-team should own this workspace.";
|
|
48081
|
+
function workspaceTeamIdUnauthorizedAdvice(targetTeamId) {
|
|
48082
|
+
return `The workspace-team-id input (${targetTeamId}) was rejected as unauthorized by the Postman API. In org-mode accounts it must be the numeric id of a sub-team this API key can access; GET https://api.getpostman.com/teams lists the available sub-teams. Fix the workspace-team-id value and re-run.`;
|
|
48083
|
+
}
|
|
48084
|
+
function adviseFromWorkspaceCreateError(err, targetTeamId) {
|
|
48085
|
+
if (err.message.includes("Only personal workspaces")) {
|
|
48086
|
+
return new Error(WORKSPACE_PERSONAL_ONLY_ADVICE, { cause: err });
|
|
48087
|
+
}
|
|
48088
|
+
if (targetTeamId != null && err.message.includes("You are not authorized to perform this action")) {
|
|
48089
|
+
return new Error(workspaceTeamIdUnauthorizedAdvice(targetTeamId), { cause: err });
|
|
48090
|
+
}
|
|
48091
|
+
return void 0;
|
|
48092
|
+
}
|
|
48093
|
+
function expiryAdvice(code) {
|
|
48094
|
+
return `postman: Bifrost rejected the access token (${code}). Service-account access tokens expire after about 1 to 1.5 hours; this run likely outlived its token. Re-mint a fresh token (postman-resolve-service-token-action, or POST https://api.getpostman.com/service-account-tokens) and re-run. If it was just minted, confirm postman-access-token is the token for the same parent org as postman-api-key.`;
|
|
48095
|
+
}
|
|
48096
|
+
function forbiddenAdvice(ctx) {
|
|
48097
|
+
const sessionDetail = ctx.sessionTeamId ? ` while the access token is valid (it resolved to team ${ctx.sessionTeamId}${ctx.sessionRoles && ctx.sessionRoles.length > 0 ? `, roles [${ctx.sessionRoles.join(", ")}]` : ""}${ctx.sessionConsumerType ? `, consumerType ${ctx.sessionConsumerType}` : ""} at preflight)` : "";
|
|
48098
|
+
const scopedTeamId = ctx.workspaceTeamId || ctx.explicitTeamId;
|
|
48099
|
+
const teamClause = scopedTeamId ? `, or workspace-team-id ${scopedTeamId} names a sub-team it cannot act in` : ", or the workspace-team-id / POSTMAN_TEAM_ID in use names a sub-team it cannot act in";
|
|
48100
|
+
return `postman: Bifrost refused ${ctx.operation || "this operation"} with 403${sessionDetail}. The token's identity lacks permission for this endpoint${teamClause}. Verify the token's role and that workspace-team-id / POSTMAN_TEAM_ID matches a sub-team from GET https://api.getpostman.com/teams.`;
|
|
48101
|
+
}
|
|
48102
|
+
function buildAdvice(status, body, ctx) {
|
|
48103
|
+
if (body.includes("UNAUTHENTICATED")) {
|
|
48104
|
+
return expiryAdvice("UNAUTHENTICATED");
|
|
48105
|
+
}
|
|
48106
|
+
if (body.includes("authenticationError")) {
|
|
48107
|
+
return expiryAdvice("authenticationError");
|
|
48108
|
+
}
|
|
48109
|
+
if (body.includes("Only personal workspaces")) {
|
|
48110
|
+
return WORKSPACE_PERSONAL_ONLY_ADVICE;
|
|
48111
|
+
}
|
|
48112
|
+
if (body.includes("projectAlreadyConnected")) {
|
|
48113
|
+
return `postman: ${ctx.operation || "this operation"} reports projectAlreadyConnected with no workspace id in the error body. The repository is already linked to a workspace this credential cannot see, usually one created by a different credential pair or sub-team. Delete the stale link or its workspace, then re-run with one credential pair from a single parent org.`;
|
|
48114
|
+
}
|
|
48115
|
+
if (body.includes("invalidParamError") && body.includes("already exists")) {
|
|
48116
|
+
return `postman: ${ctx.operation || "this operation"} hit a duplicate resource error (invalidParamError: already exists). A matching resource already exists, possibly under another credential pair or sub-team where this credential cannot see it. Identify which workspace holds the existing resource and re-run with one credential pair from a single parent org.`;
|
|
48117
|
+
}
|
|
48118
|
+
if (body.includes("Team feature is not available for your organization")) {
|
|
48119
|
+
return `postman: ${ctx.operation || "this operation"} failed because the team feature is not available for this organization. The credential belongs to an account whose plan lacks team features; use credentials from the intended team and confirm the plan supports this operation.`;
|
|
48120
|
+
}
|
|
48121
|
+
if (body.includes("You are not authorized to perform this action") || status === 403 && ctx.hasAccessToken) {
|
|
48122
|
+
return forbiddenAdvice(ctx);
|
|
48123
|
+
}
|
|
48124
|
+
return void 0;
|
|
48125
|
+
}
|
|
48126
|
+
function adviseFromHttpError(err, ctx) {
|
|
48127
|
+
const body = err.responseBody || err.message || "";
|
|
48128
|
+
const advice = buildAdvice(err.status, body, ctx);
|
|
48129
|
+
if (!advice) {
|
|
48130
|
+
return void 0;
|
|
48131
|
+
}
|
|
48132
|
+
return new Error(ctx.mask(advice), { cause: err });
|
|
48133
|
+
}
|
|
48134
|
+
|
|
47822
48135
|
// src/lib/retry.ts
|
|
47823
48136
|
function sleep(delayMs) {
|
|
47824
48137
|
return new Promise((resolve4) => {
|
|
@@ -47867,7 +48180,7 @@ async function retry(operation, options = {}) {
|
|
|
47867
48180
|
}
|
|
47868
48181
|
|
|
47869
48182
|
// src/lib/postman/postman-assets-client.ts
|
|
47870
|
-
function
|
|
48183
|
+
function asRecord2(value) {
|
|
47871
48184
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
47872
48185
|
return null;
|
|
47873
48186
|
}
|
|
@@ -47875,8 +48188,8 @@ function asRecord(value) {
|
|
|
47875
48188
|
}
|
|
47876
48189
|
function extractWorkspacesPage(data) {
|
|
47877
48190
|
const workspaces = Array.isArray(data?.workspaces) ? data.workspaces : [];
|
|
47878
|
-
const meta =
|
|
47879
|
-
const pagination =
|
|
48191
|
+
const meta = asRecord2(data?.meta);
|
|
48192
|
+
const pagination = asRecord2(data?.pagination);
|
|
47880
48193
|
const nextCursor = String(
|
|
47881
48194
|
data?.nextCursor ?? data?.next_cursor ?? meta?.nextCursor ?? meta?.next_cursor ?? pagination?.nextCursor ?? pagination?.next_cursor ?? ""
|
|
47882
48195
|
).trim() || void 0;
|
|
@@ -47968,7 +48281,7 @@ var PostmanAssetsClient = class {
|
|
|
47968
48281
|
async getTeams() {
|
|
47969
48282
|
const data = await this.request("/teams");
|
|
47970
48283
|
const teams = data?.data ?? [];
|
|
47971
|
-
return Array.isArray(teams) ? teams.map((entry) =>
|
|
48284
|
+
return Array.isArray(teams) ? teams.map((entry) => asRecord2(entry)).filter((team) => Boolean(team?.id && team?.name)).map((team) => ({
|
|
47972
48285
|
id: Number(team.id),
|
|
47973
48286
|
name: String(team.name),
|
|
47974
48287
|
handle: String(team.handle || ""),
|
|
@@ -48020,28 +48333,28 @@ var PostmanAssetsClient = class {
|
|
|
48020
48333
|
body: JSON.stringify(payload)
|
|
48021
48334
|
});
|
|
48022
48335
|
} catch (err) {
|
|
48023
|
-
if (err instanceof Error
|
|
48024
|
-
|
|
48025
|
-
|
|
48026
|
-
|
|
48027
|
-
|
|
48336
|
+
if (err instanceof Error) {
|
|
48337
|
+
const advised = adviseFromWorkspaceCreateError(err, targetTeamId);
|
|
48338
|
+
if (advised) {
|
|
48339
|
+
throw advised;
|
|
48340
|
+
}
|
|
48028
48341
|
}
|
|
48029
48342
|
throw err;
|
|
48030
48343
|
}
|
|
48031
|
-
const createdWorkspace =
|
|
48344
|
+
const createdWorkspace = asRecord2(created?.workspace);
|
|
48032
48345
|
const workspaceId = String(createdWorkspace?.id || "").trim();
|
|
48033
48346
|
if (!workspaceId) {
|
|
48034
48347
|
throw new Error("Workspace create did not return an id");
|
|
48035
48348
|
}
|
|
48036
48349
|
const workspace = await this.request(`/workspaces/${workspaceId}`);
|
|
48037
|
-
let visibility =
|
|
48350
|
+
let visibility = asRecord2(workspace?.workspace)?.visibility;
|
|
48038
48351
|
if (visibility !== "team") {
|
|
48039
48352
|
await this.request(`/workspaces/${workspaceId}`, {
|
|
48040
48353
|
method: "PUT",
|
|
48041
48354
|
body: JSON.stringify(payload)
|
|
48042
48355
|
});
|
|
48043
48356
|
const reread = await this.request(`/workspaces/${workspaceId}`);
|
|
48044
|
-
visibility =
|
|
48357
|
+
visibility = asRecord2(reread?.workspace)?.visibility;
|
|
48045
48358
|
}
|
|
48046
48359
|
if (typeof visibility === "string" && visibility !== "team") {
|
|
48047
48360
|
let cleanedUp = false;
|
|
@@ -48070,7 +48383,7 @@ var PostmanAssetsClient = class {
|
|
|
48070
48383
|
async getWorkspaceVisibility(workspaceId) {
|
|
48071
48384
|
try {
|
|
48072
48385
|
const workspace = await this.request(`/workspaces/${workspaceId}`);
|
|
48073
|
-
const visibility =
|
|
48386
|
+
const visibility = asRecord2(workspace?.workspace)?.visibility;
|
|
48074
48387
|
return typeof visibility === "string" ? visibility : null;
|
|
48075
48388
|
} catch {
|
|
48076
48389
|
return null;
|
|
@@ -48092,7 +48405,7 @@ var PostmanAssetsClient = class {
|
|
|
48092
48405
|
nextCursor = page.nextCursor;
|
|
48093
48406
|
}
|
|
48094
48407
|
} while (nextCursor);
|
|
48095
|
-
return allWorkspaces.map((entry) =>
|
|
48408
|
+
return allWorkspaces.map((entry) => asRecord2(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
|
|
48096
48409
|
id: String(workspace.id),
|
|
48097
48410
|
name: String(workspace.name),
|
|
48098
48411
|
type: String(workspace.type ?? "team")
|
|
@@ -48140,7 +48453,7 @@ var PostmanAssetsClient = class {
|
|
|
48140
48453
|
async inviteRequesterToWorkspace(workspaceId, email) {
|
|
48141
48454
|
const users = await this.request("/users");
|
|
48142
48455
|
const userList = Array.isArray(users?.data) ? users.data : [];
|
|
48143
|
-
const user = userList.map((entry) =>
|
|
48456
|
+
const user = userList.map((entry) => asRecord2(entry)).find((entry) => entry?.email === email);
|
|
48144
48457
|
if (!user?.id) {
|
|
48145
48458
|
return;
|
|
48146
48459
|
}
|
|
@@ -48228,12 +48541,12 @@ var PostmanAssetsClient = class {
|
|
|
48228
48541
|
}
|
|
48229
48542
|
};
|
|
48230
48543
|
const extractUid = (data) => {
|
|
48231
|
-
const root =
|
|
48232
|
-
const details =
|
|
48544
|
+
const root = asRecord2(data);
|
|
48545
|
+
const details = asRecord2(root?.details);
|
|
48233
48546
|
const resources = Array.isArray(details?.resources) ? details.resources : [];
|
|
48234
|
-
const firstResource =
|
|
48235
|
-
const collection =
|
|
48236
|
-
const resource =
|
|
48547
|
+
const firstResource = asRecord2(resources[0]);
|
|
48548
|
+
const collection = asRecord2(root?.collection);
|
|
48549
|
+
const resource = asRecord2(root?.resource);
|
|
48237
48550
|
return String(
|
|
48238
48551
|
firstResource?.id ?? collection?.id ?? collection?.uid ?? resource?.uid ?? resource?.id ?? ""
|
|
48239
48552
|
).trim() || void 0;
|
|
@@ -48267,9 +48580,9 @@ var PostmanAssetsClient = class {
|
|
|
48267
48580
|
if (directUid) {
|
|
48268
48581
|
return directUid;
|
|
48269
48582
|
}
|
|
48270
|
-
let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(
|
|
48583
|
+
let taskUrl = String(generationResponse?.url ?? "") || String(generationResponse?.task_url ?? "") || String(generationResponse?.taskUrl ?? "") || String(asRecord2(generationResponse?.links)?.task ?? "");
|
|
48271
48584
|
if (!taskUrl) {
|
|
48272
|
-
const task =
|
|
48585
|
+
const task = asRecord2(generationResponse?.task);
|
|
48273
48586
|
const taskId = generationResponse?.taskId || task?.id || generationResponse?.id;
|
|
48274
48587
|
if (!taskId) {
|
|
48275
48588
|
throw new Error(
|
|
@@ -48283,8 +48596,8 @@ var PostmanAssetsClient = class {
|
|
|
48283
48596
|
setTimeout(resolve4, 2e3);
|
|
48284
48597
|
});
|
|
48285
48598
|
const task = await this.request(taskUrl);
|
|
48286
|
-
const taskRecord =
|
|
48287
|
-
const taskNested =
|
|
48599
|
+
const taskRecord = asRecord2(task);
|
|
48600
|
+
const taskNested = asRecord2(taskRecord?.task);
|
|
48288
48601
|
const status = String(taskRecord?.status || taskNested?.status || "").toLowerCase();
|
|
48289
48602
|
if (status === "completed") {
|
|
48290
48603
|
const taskUid = extractUid(task);
|
|
@@ -48315,7 +48628,7 @@ var PostmanAssetsClient = class {
|
|
|
48315
48628
|
}
|
|
48316
48629
|
async injectTests(collectionUid, type2) {
|
|
48317
48630
|
const collectionResponse = await this.request(`/collections/${collectionUid}`);
|
|
48318
|
-
const collection =
|
|
48631
|
+
const collection = asRecord2(collectionResponse?.collection);
|
|
48319
48632
|
if (!collection) {
|
|
48320
48633
|
throw new Error(`Failed to fetch collection ${collectionUid}`);
|
|
48321
48634
|
}
|
|
@@ -48401,7 +48714,7 @@ var PostmanAssetsClient = class {
|
|
|
48401
48714
|
});
|
|
48402
48715
|
}
|
|
48403
48716
|
if (Array.isArray(itemNode.item)) {
|
|
48404
|
-
itemNode.item.map((entry) =>
|
|
48717
|
+
itemNode.item.map((entry) => asRecord2(entry)).filter((entry) => Boolean(entry)).forEach(injectScripts);
|
|
48405
48718
|
}
|
|
48406
48719
|
};
|
|
48407
48720
|
if (Array.isArray(collection.item)) {
|
|
@@ -48429,7 +48742,7 @@ var PostmanAssetsClient = class {
|
|
|
48429
48742
|
}
|
|
48430
48743
|
})
|
|
48431
48744
|
});
|
|
48432
|
-
const environment =
|
|
48745
|
+
const environment = asRecord2(response?.environment);
|
|
48433
48746
|
const uid = String(environment?.uid || "").trim();
|
|
48434
48747
|
if (!uid) {
|
|
48435
48748
|
throw new Error("Environment create did not return a UID");
|
|
@@ -48462,7 +48775,7 @@ var PostmanAssetsClient = class {
|
|
|
48462
48775
|
}
|
|
48463
48776
|
})
|
|
48464
48777
|
});
|
|
48465
|
-
const monitor =
|
|
48778
|
+
const monitor = asRecord2(response?.monitor);
|
|
48466
48779
|
const uid = String(monitor?.uid || "").trim();
|
|
48467
48780
|
if (!uid) {
|
|
48468
48781
|
throw new Error("Monitor create did not return a UID");
|
|
@@ -48481,8 +48794,8 @@ var PostmanAssetsClient = class {
|
|
|
48481
48794
|
}
|
|
48482
48795
|
})
|
|
48483
48796
|
});
|
|
48484
|
-
const mock =
|
|
48485
|
-
const mockConfig =
|
|
48797
|
+
const mock = asRecord2(response?.mock);
|
|
48798
|
+
const mockConfig = asRecord2(mock?.config);
|
|
48486
48799
|
const uid = String(mock?.uid || "").trim();
|
|
48487
48800
|
if (!uid) {
|
|
48488
48801
|
throw new Error("Mock create did not return a UID");
|
|
@@ -48553,6 +48866,18 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48553
48866
|
this.teamId = String(teamId || "").trim();
|
|
48554
48867
|
this.orgMode = orgMode;
|
|
48555
48868
|
}
|
|
48869
|
+
adviceContext(operation) {
|
|
48870
|
+
const session = getMemoizedSessionIdentity();
|
|
48871
|
+
return {
|
|
48872
|
+
operation,
|
|
48873
|
+
hasAccessToken: Boolean(this.accessToken),
|
|
48874
|
+
sessionTeamId: session?.teamId,
|
|
48875
|
+
sessionRoles: session?.roles,
|
|
48876
|
+
sessionConsumerType: session?.consumerType,
|
|
48877
|
+
explicitTeamId: this.teamId || void 0,
|
|
48878
|
+
mask: this.secretMasker
|
|
48879
|
+
};
|
|
48880
|
+
}
|
|
48556
48881
|
async proxyRequest(service, method, requestPath2, body, options = {}) {
|
|
48557
48882
|
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
48558
48883
|
const headers = {
|
|
@@ -48619,7 +48944,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48619
48944
|
{ appVersion, query: { tag: "governance" } }
|
|
48620
48945
|
);
|
|
48621
48946
|
if (!listResponse.ok) {
|
|
48622
|
-
|
|
48947
|
+
const httpErr = await HttpError.fromResponse(listResponse, {
|
|
48623
48948
|
method: "GET",
|
|
48624
48949
|
requestHeaders: {
|
|
48625
48950
|
"Content-Type": "application/json",
|
|
@@ -48630,6 +48955,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48630
48955
|
secretValues: [this.accessToken],
|
|
48631
48956
|
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
48632
48957
|
});
|
|
48958
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
|
|
48959
|
+
throw advised ?? httpErr;
|
|
48633
48960
|
}
|
|
48634
48961
|
const groups = await listResponse.json();
|
|
48635
48962
|
const group2 = (groups.workspaceGroups ?? groups.data)?.find(
|
|
@@ -48655,7 +48982,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48655
48982
|
{ appVersion }
|
|
48656
48983
|
);
|
|
48657
48984
|
if (!patchResponse.ok) {
|
|
48658
|
-
|
|
48985
|
+
const httpErr = await HttpError.fromResponse(patchResponse, {
|
|
48659
48986
|
method: "PATCH",
|
|
48660
48987
|
requestHeaders: {
|
|
48661
48988
|
"Content-Type": "application/json",
|
|
@@ -48666,6 +48993,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48666
48993
|
secretValues: [this.accessToken],
|
|
48667
48994
|
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
48668
48995
|
});
|
|
48996
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("governance assignment"));
|
|
48997
|
+
throw advised ?? httpErr;
|
|
48669
48998
|
}
|
|
48670
48999
|
}
|
|
48671
49000
|
async connectWorkspaceToRepository(workspaceId, repoUrl) {
|
|
@@ -48699,7 +49028,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48699
49028
|
);
|
|
48700
49029
|
}
|
|
48701
49030
|
}
|
|
48702
|
-
|
|
49031
|
+
const httpErr = await HttpError.fromResponse(response, {
|
|
48703
49032
|
method: "POST",
|
|
48704
49033
|
requestHeaders: {
|
|
48705
49034
|
"Content-Type": "application/json",
|
|
@@ -48709,6 +49038,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48709
49038
|
secretValues: [this.accessToken],
|
|
48710
49039
|
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
48711
49040
|
});
|
|
49041
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("workspace repository linking"));
|
|
49042
|
+
throw advised ?? httpErr;
|
|
48712
49043
|
}
|
|
48713
49044
|
async linkCollectionsToSpecification(specificationId, collections) {
|
|
48714
49045
|
if (collections.length === 0) {
|
|
@@ -48726,7 +49057,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48726
49057
|
if (response.ok) {
|
|
48727
49058
|
return;
|
|
48728
49059
|
}
|
|
48729
|
-
|
|
49060
|
+
const httpErr = await HttpError.fromResponse(response, {
|
|
48730
49061
|
method: "POST",
|
|
48731
49062
|
requestHeaders: {
|
|
48732
49063
|
"Content-Type": "application/json",
|
|
@@ -48736,6 +49067,11 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48736
49067
|
secretValues: [this.accessToken],
|
|
48737
49068
|
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
48738
49069
|
});
|
|
49070
|
+
const advised = adviseFromHttpError(
|
|
49071
|
+
httpErr,
|
|
49072
|
+
this.adviceContext("collection-to-specification linking")
|
|
49073
|
+
);
|
|
49074
|
+
throw advised ?? httpErr;
|
|
48739
49075
|
}
|
|
48740
49076
|
async syncCollection(specificationId, collectionId) {
|
|
48741
49077
|
const response = await this.proxyRequest(
|
|
@@ -48746,7 +49082,7 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48746
49082
|
if (response.ok) {
|
|
48747
49083
|
return;
|
|
48748
49084
|
}
|
|
48749
|
-
|
|
49085
|
+
const httpErr = await HttpError.fromResponse(response, {
|
|
48750
49086
|
method: "POST",
|
|
48751
49087
|
requestHeaders: {
|
|
48752
49088
|
"Content-Type": "application/json",
|
|
@@ -48756,6 +49092,8 @@ var BifrostInternalIntegrationAdapter = class _BifrostInternalIntegrationAdapter
|
|
|
48756
49092
|
secretValues: [this.accessToken],
|
|
48757
49093
|
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
48758
49094
|
});
|
|
49095
|
+
const advised = adviseFromHttpError(httpErr, this.adviceContext("collection sync"));
|
|
49096
|
+
throw advised ?? httpErr;
|
|
48759
49097
|
}
|
|
48760
49098
|
async getWorkspaceGitRepoUrl(workspaceId) {
|
|
48761
49099
|
const response = await this.proxyRequest(
|
|
@@ -49329,7 +49667,7 @@ var STRIP_KEYS = /* @__PURE__ */ new Set([
|
|
|
49329
49667
|
"discriminator",
|
|
49330
49668
|
"format"
|
|
49331
49669
|
]);
|
|
49332
|
-
function
|
|
49670
|
+
function asRecord3(value) {
|
|
49333
49671
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
49334
49672
|
return value;
|
|
49335
49673
|
}
|
|
@@ -49341,7 +49679,7 @@ function decodePointerSegment(segment) {
|
|
|
49341
49679
|
}
|
|
49342
49680
|
function resolvePointer(root, ref) {
|
|
49343
49681
|
if (!ref.startsWith("#/")) return void 0;
|
|
49344
|
-
return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) =>
|
|
49682
|
+
return ref.slice(2).split("/").map(decodePointerSegment).reduce((node, segment) => asRecord3(node)?.[segment], root);
|
|
49345
49683
|
}
|
|
49346
49684
|
function unsupported(message) {
|
|
49347
49685
|
return { unsupported: message };
|
|
@@ -49351,7 +49689,7 @@ function mergeRequiredWithoutWriteOnly(required, writeOnlyProperties) {
|
|
|
49351
49689
|
return values.length > 0 ? values : void 0;
|
|
49352
49690
|
}
|
|
49353
49691
|
function hasUnsupported(child2) {
|
|
49354
|
-
return
|
|
49692
|
+
return asRecord3(child2)?.unsupported;
|
|
49355
49693
|
}
|
|
49356
49694
|
function rootDialect(root, version, schemaRecord) {
|
|
49357
49695
|
if (version === "3.0") return DRAFT_07_SCHEMA_URI;
|
|
@@ -49371,7 +49709,7 @@ function normalizeSchema(root, schema2, options) {
|
|
|
49371
49709
|
const bad = normalized2.map(hasUnsupported).find(Boolean);
|
|
49372
49710
|
return bad ? unsupported(bad) : normalized2;
|
|
49373
49711
|
}
|
|
49374
|
-
const record =
|
|
49712
|
+
const record = asRecord3(schema2);
|
|
49375
49713
|
if (!record) return schema2;
|
|
49376
49714
|
const ref = typeof record.$ref === "string" ? record.$ref : "";
|
|
49377
49715
|
if (ref) {
|
|
@@ -49406,10 +49744,10 @@ function normalizeSchema(root, schema2, options) {
|
|
|
49406
49744
|
const nullable = sourceSchema.nullable === true && options.version === "3.0";
|
|
49407
49745
|
delete sourceSchema.nullable;
|
|
49408
49746
|
const writeOnlyProperties = /* @__PURE__ */ new Set();
|
|
49409
|
-
const rawProperties =
|
|
49747
|
+
const rawProperties = asRecord3(sourceSchema.properties);
|
|
49410
49748
|
if (rawProperties) {
|
|
49411
49749
|
for (const [propertyName, propertySchema] of Object.entries(rawProperties)) {
|
|
49412
|
-
if (
|
|
49750
|
+
if (asRecord3(propertySchema)?.writeOnly === true) writeOnlyProperties.add(propertyName);
|
|
49413
49751
|
}
|
|
49414
49752
|
}
|
|
49415
49753
|
const normalized = {};
|
|
@@ -49441,7 +49779,7 @@ function normalizeSchema(root, schema2, options) {
|
|
|
49441
49779
|
return unsupported("Tuple array items are unsupported in OpenAPI 3.0");
|
|
49442
49780
|
}
|
|
49443
49781
|
if (key === "properties") {
|
|
49444
|
-
const properties =
|
|
49782
|
+
const properties = asRecord3(value);
|
|
49445
49783
|
if (!properties) continue;
|
|
49446
49784
|
const nextProperties = {};
|
|
49447
49785
|
for (const [propertyName, propertySchema] of Object.entries(properties)) {
|
|
@@ -49484,7 +49822,7 @@ function normalizeSchema(root, schema2, options) {
|
|
|
49484
49822
|
}
|
|
49485
49823
|
function packSchema(root, schema2, version) {
|
|
49486
49824
|
try {
|
|
49487
|
-
const dialect = rootDialect(root, version,
|
|
49825
|
+
const dialect = rootDialect(root, version, asRecord3(schema2) ?? void 0);
|
|
49488
49826
|
const normalized = normalizeSchema(root, schema2, { version, rootSchema: true, dialect });
|
|
49489
49827
|
const message = hasUnsupported(normalized);
|
|
49490
49828
|
return message ? unsupported(message) : { schema: normalized };
|
|
@@ -49495,7 +49833,7 @@ function packSchema(root, schema2, version) {
|
|
|
49495
49833
|
|
|
49496
49834
|
// src/lib/spec/contract-index.ts
|
|
49497
49835
|
var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "put", "post", "delete", "options", "head", "patch", "trace"]);
|
|
49498
|
-
function
|
|
49836
|
+
function asRecord4(value) {
|
|
49499
49837
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
49500
49838
|
return value;
|
|
49501
49839
|
}
|
|
@@ -49512,12 +49850,12 @@ function detectOpenApiVersion(root) {
|
|
|
49512
49850
|
return match[1] === "1" ? "3.1" : "3.0";
|
|
49513
49851
|
}
|
|
49514
49852
|
function resolveInternalRef(root, value) {
|
|
49515
|
-
const record =
|
|
49853
|
+
const record = asRecord4(value);
|
|
49516
49854
|
if (!record) return null;
|
|
49517
49855
|
const ref = typeof record.$ref === "string" ? record.$ref : "";
|
|
49518
49856
|
if (!ref) return record;
|
|
49519
49857
|
if (!ref.startsWith("#/")) throw new Error(`CONTRACT_UNRESOLVED_REF: External ref remained after bundling: ${ref}`);
|
|
49520
|
-
const resolved =
|
|
49858
|
+
const resolved = asRecord4(resolvePointer(root, ref));
|
|
49521
49859
|
if (!resolved) throw new Error(`CONTRACT_UNRESOLVED_REF: Unresolved OpenAPI $ref: ${ref}`);
|
|
49522
49860
|
return resolved;
|
|
49523
49861
|
}
|
|
@@ -49537,11 +49875,11 @@ function normalizePath(path8) {
|
|
|
49537
49875
|
return trimmed.split("/").map((segment, index) => index === 0 ? "" : safeDecodeSegment(segment)).join("/") || "/";
|
|
49538
49876
|
}
|
|
49539
49877
|
function pathItemServers(pathItem) {
|
|
49540
|
-
return asArray2(pathItem.servers).map((entry) =>
|
|
49878
|
+
return asArray2(pathItem.servers).map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
|
|
49541
49879
|
}
|
|
49542
49880
|
function operationServers(root, pathItem, operation) {
|
|
49543
49881
|
const rawServers = asArray2(operation.servers).length > 0 ? asArray2(operation.servers) : pathItemServers(pathItem).length > 0 ? asArray2(pathItem.servers) : asArray2(root.servers);
|
|
49544
|
-
const values = rawServers.map((entry) =>
|
|
49882
|
+
const values = rawServers.map((entry) => asRecord4(entry)).map((entry) => typeof entry?.url === "string" ? entry.url : "").filter(Boolean);
|
|
49545
49883
|
return values.length > 0 ? values : [""];
|
|
49546
49884
|
}
|
|
49547
49885
|
function serverPathPrefix(url) {
|
|
@@ -49562,10 +49900,10 @@ function normalizeResponseKey(status) {
|
|
|
49562
49900
|
return /^[1-5]xx$/i.test(raw) ? raw.toUpperCase() : raw;
|
|
49563
49901
|
}
|
|
49564
49902
|
function collectSecurityApiKeys(root, operation) {
|
|
49565
|
-
const securitySchemes =
|
|
49903
|
+
const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
|
|
49566
49904
|
const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
|
|
49567
49905
|
const names = /* @__PURE__ */ new Set();
|
|
49568
|
-
for (const requirement of requirements.map((entry) =>
|
|
49906
|
+
for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
|
|
49569
49907
|
for (const schemeName of Object.keys(requirement)) {
|
|
49570
49908
|
const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
|
|
49571
49909
|
if (scheme?.type === "apiKey" && typeof scheme.name === "string" && ["query", "header"].includes(String(scheme.in))) {
|
|
@@ -49583,10 +49921,10 @@ function securitySchemeKind(scheme) {
|
|
|
49583
49921
|
return type2;
|
|
49584
49922
|
}
|
|
49585
49923
|
function collectSecuritySchemeWarnings(root, operation) {
|
|
49586
|
-
const securitySchemes =
|
|
49924
|
+
const securitySchemes = asRecord4(asRecord4(root.components)?.securitySchemes);
|
|
49587
49925
|
const requirements = operation.security === void 0 ? asArray2(root.security) : asArray2(operation.security);
|
|
49588
49926
|
const warnings = /* @__PURE__ */ new Set();
|
|
49589
|
-
for (const requirement of requirements.map((entry) =>
|
|
49927
|
+
for (const requirement of requirements.map((entry) => asRecord4(entry)).filter(Boolean)) {
|
|
49590
49928
|
for (const schemeName of Object.keys(requirement)) {
|
|
49591
49929
|
const scheme = resolveInternalRef(root, securitySchemes?.[schemeName]);
|
|
49592
49930
|
warnings.add(
|
|
@@ -49622,24 +49960,24 @@ function collectParameters(root, pathItem, operation) {
|
|
|
49622
49960
|
function collectRequestBody(root, operation) {
|
|
49623
49961
|
const body = resolveInternalRef(root, operation.requestBody);
|
|
49624
49962
|
if (!body || body.required !== true) return void 0;
|
|
49625
|
-
const content =
|
|
49963
|
+
const content = asRecord4(body.content);
|
|
49626
49964
|
return {
|
|
49627
49965
|
required: true,
|
|
49628
49966
|
contentTypes: content ? Object.keys(content) : []
|
|
49629
49967
|
};
|
|
49630
49968
|
}
|
|
49631
49969
|
function responseContent(root, version, response) {
|
|
49632
|
-
const content =
|
|
49970
|
+
const content = asRecord4(response.content);
|
|
49633
49971
|
if (!content) return {};
|
|
49634
49972
|
const media = {};
|
|
49635
49973
|
for (const [contentType, mediaObject] of Object.entries(content)) {
|
|
49636
|
-
const schema2 =
|
|
49974
|
+
const schema2 = asRecord4(mediaObject)?.schema;
|
|
49637
49975
|
media[contentType] = schema2 === void 0 ? {} : packSchema(root, schema2, version);
|
|
49638
49976
|
}
|
|
49639
49977
|
return media;
|
|
49640
49978
|
}
|
|
49641
49979
|
function responseHeaders(root, version, response) {
|
|
49642
|
-
const headers =
|
|
49980
|
+
const headers = asRecord4(response.headers);
|
|
49643
49981
|
if (!headers) return [];
|
|
49644
49982
|
return Object.entries(headers).map(([name, rawHeader]) => {
|
|
49645
49983
|
const header = resolveInternalRef(root, rawHeader);
|
|
@@ -49654,10 +49992,10 @@ function buildContractIndex(root) {
|
|
|
49654
49992
|
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)");
|
|
49655
49993
|
if (!("openapi" in root)) throw new Error("CONTRACT_UNSUPPORTED_OPENAPI_VERSION: Dynamic contract tests require OpenAPI 3.0 or 3.1 (missing openapi)");
|
|
49656
49994
|
const version = detectOpenApiVersion(root);
|
|
49657
|
-
const paths =
|
|
49995
|
+
const paths = asRecord4(root.paths);
|
|
49658
49996
|
const operations = [];
|
|
49659
49997
|
const warnings = [];
|
|
49660
|
-
if (
|
|
49998
|
+
if (asRecord4(root.webhooks)) warnings.push("CONTRACT_WEBHOOKS_NOT_VALIDATED: OpenAPI webhooks are not validated by dynamic contract tests");
|
|
49661
49999
|
if (paths) {
|
|
49662
50000
|
for (const [path8, rawPathItem] of Object.entries(paths)) {
|
|
49663
50001
|
const pathItem = resolveInternalRef(root, rawPathItem);
|
|
@@ -49668,7 +50006,7 @@ function buildContractIndex(root) {
|
|
|
49668
50006
|
const operation = resolveInternalRef(root, rawOperation);
|
|
49669
50007
|
if (!operation) continue;
|
|
49670
50008
|
if (operation.callbacks) warnings.push(`CONTRACT_CALLBACKS_NOT_VALIDATED: callbacks are not validated for ${lowerMethod.toUpperCase()} ${path8}`);
|
|
49671
|
-
const responses =
|
|
50009
|
+
const responses = asRecord4(operation.responses);
|
|
49672
50010
|
if (!responses || Object.keys(responses).length === 0) {
|
|
49673
50011
|
throw new Error(`CONTRACT_OPERATION_NO_RESPONSES: ${lowerMethod.toUpperCase()} ${path8} must define at least one response`);
|
|
49674
50012
|
}
|
|
@@ -49758,7 +50096,7 @@ var CONTRACT_SIZE_LIMITS = {
|
|
|
49758
50096
|
maxTestScriptBytes: 9e5,
|
|
49759
50097
|
maxCollectionUpdateBytes: 4e6
|
|
49760
50098
|
};
|
|
49761
|
-
function
|
|
50099
|
+
function asRecord5(value) {
|
|
49762
50100
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
49763
50101
|
return value;
|
|
49764
50102
|
}
|
|
@@ -49767,7 +50105,7 @@ function asArray3(value) {
|
|
|
49767
50105
|
}
|
|
49768
50106
|
function stringifyPathSegment(segment) {
|
|
49769
50107
|
if (typeof segment === "string") return segment;
|
|
49770
|
-
const record =
|
|
50108
|
+
const record = asRecord5(segment);
|
|
49771
50109
|
if (!record) return String(segment ?? "");
|
|
49772
50110
|
for (const key of ["value", "key", "name"]) {
|
|
49773
50111
|
if (typeof record[key] === "string" && record[key]) return String(record[key]);
|
|
@@ -49785,10 +50123,10 @@ function pathFromRaw(raw) {
|
|
|
49785
50123
|
}
|
|
49786
50124
|
}
|
|
49787
50125
|
function requestPath(request) {
|
|
49788
|
-
const record =
|
|
50126
|
+
const record = asRecord5(request);
|
|
49789
50127
|
const url = record?.url ?? request;
|
|
49790
50128
|
if (typeof url === "string") return pathFromRaw(url);
|
|
49791
|
-
const urlRecord =
|
|
50129
|
+
const urlRecord = asRecord5(url);
|
|
49792
50130
|
if (!urlRecord) return "/";
|
|
49793
50131
|
if (Array.isArray(urlRecord.path)) return normalizePath(`/${urlRecord.path.map(stringifyPathSegment).filter(Boolean).join("/")}`);
|
|
49794
50132
|
if (typeof urlRecord.path === "string") return normalizePath(urlRecord.path);
|
|
@@ -49820,7 +50158,7 @@ function matchCandidate(candidate, request) {
|
|
|
49820
50158
|
return { matched: true, staticCount, templateCount };
|
|
49821
50159
|
}
|
|
49822
50160
|
function matchOperation(index, request) {
|
|
49823
|
-
const record =
|
|
50161
|
+
const record = asRecord5(request);
|
|
49824
50162
|
const method = String(record?.method || "").toUpperCase();
|
|
49825
50163
|
const path8 = requestPath(request);
|
|
49826
50164
|
const candidates = index.operations.filter((operation) => operation.method === method).flatMap((operation) => operation.candidates.map((candidate) => ({ operation, score: matchCandidate(candidate, path8), serverFull: candidate !== normalizePath(operation.path) }))).filter((entry) => entry.score.matched).map((entry) => ({ operation: entry.operation, score: [entry.score.staticCount, entry.serverFull ? 2 : 1, -entry.score.templateCount] })).sort((a, b) => {
|
|
@@ -49971,17 +50309,17 @@ function createSecretsResolverItem() {
|
|
|
49971
50309
|
}
|
|
49972
50310
|
function isResolverItem(item) {
|
|
49973
50311
|
if (item.name !== "00 - Resolve Secrets") return false;
|
|
49974
|
-
const request =
|
|
50312
|
+
const request = asRecord5(item.request);
|
|
49975
50313
|
if (String(request?.method || "").toUpperCase() !== "POST") return false;
|
|
49976
|
-
const headers = asArray3(request?.header).map((entry) =>
|
|
50314
|
+
const headers = asArray3(request?.header).map((entry) => asRecord5(entry));
|
|
49977
50315
|
const target = headers.find((entry) => entry?.key === "X-Amz-Target");
|
|
49978
50316
|
return String(target?.value || "") === "secretsmanager.GetSecretValue" && !requestPath(request).includes("secretsmanager");
|
|
49979
50317
|
}
|
|
49980
50318
|
function requestQueryNames(request) {
|
|
49981
|
-
const url =
|
|
50319
|
+
const url = asRecord5(request.url);
|
|
49982
50320
|
const names = /* @__PURE__ */ new Set();
|
|
49983
50321
|
if (Array.isArray(url?.query)) {
|
|
49984
|
-
for (const entry of url.query.map((item) =>
|
|
50322
|
+
for (const entry of url.query.map((item) => asRecord5(item)).filter(Boolean)) {
|
|
49985
50323
|
if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
|
|
49986
50324
|
}
|
|
49987
50325
|
}
|
|
@@ -49996,17 +50334,17 @@ function requestQueryNames(request) {
|
|
|
49996
50334
|
}
|
|
49997
50335
|
function requestHeaderNames(request) {
|
|
49998
50336
|
const names = /* @__PURE__ */ new Set();
|
|
49999
|
-
for (const entry of asArray3(request.header).map((item) =>
|
|
50337
|
+
for (const entry of asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean)) {
|
|
50000
50338
|
if (entry.disabled !== true && typeof entry.key === "string") names.add(entry.key.toLowerCase());
|
|
50001
50339
|
}
|
|
50002
50340
|
return names;
|
|
50003
50341
|
}
|
|
50004
50342
|
function requestHeaderValue(request, name) {
|
|
50005
|
-
const match = asArray3(request.header).map((item) =>
|
|
50343
|
+
const match = asArray3(request.header).map((item) => asRecord5(item)).filter(Boolean).find((entry) => String(entry.key || "").toLowerCase() === name.toLowerCase() && entry.disabled !== true);
|
|
50006
50344
|
return typeof match?.value === "string" ? match.value : void 0;
|
|
50007
50345
|
}
|
|
50008
50346
|
function hasRequestBody(request) {
|
|
50009
|
-
const body =
|
|
50347
|
+
const body = asRecord5(request.body);
|
|
50010
50348
|
if (!body) return false;
|
|
50011
50349
|
if (typeof body.raw === "string" && body.raw.trim()) return true;
|
|
50012
50350
|
return ["urlencoded", "formdata", "graphql"].some((key) => Array.isArray(body[key]) ? body[key].length > 0 : Boolean(body[key]));
|
|
@@ -50057,21 +50395,21 @@ function validateScript(script) {
|
|
|
50057
50395
|
return void 0;
|
|
50058
50396
|
}
|
|
50059
50397
|
function scriptExecLines(script) {
|
|
50060
|
-
const record =
|
|
50398
|
+
const record = asRecord5(script);
|
|
50061
50399
|
if (!record) return [];
|
|
50062
50400
|
if (Array.isArray(record.exec)) return record.exec.map((line) => String(line));
|
|
50063
50401
|
if (typeof record.exec === "string") return [record.exec];
|
|
50064
50402
|
return [];
|
|
50065
50403
|
}
|
|
50066
50404
|
function scanExecutableScripts(node, warnings) {
|
|
50067
|
-
for (const event of asArray3(node.event).map((entry) =>
|
|
50405
|
+
for (const event of asArray3(node.event).map((entry) => asRecord5(entry)).filter(Boolean)) {
|
|
50068
50406
|
const lines = scriptExecLines(event.script);
|
|
50069
50407
|
if (lines.length === 0) continue;
|
|
50070
50408
|
const warning2 = validateScript(lines);
|
|
50071
50409
|
if (warning2) warnings.push(warning2);
|
|
50072
50410
|
}
|
|
50073
50411
|
for (const child2 of asArray3(node.item)) {
|
|
50074
|
-
const childRecord =
|
|
50412
|
+
const childRecord = asRecord5(child2);
|
|
50075
50413
|
if (childRecord) scanExecutableScripts(childRecord, warnings);
|
|
50076
50414
|
}
|
|
50077
50415
|
}
|
|
@@ -50081,7 +50419,7 @@ function instrumentContractCollection(collection, index) {
|
|
|
50081
50419
|
const inject = (item) => {
|
|
50082
50420
|
if (isResolverItem(item)) return;
|
|
50083
50421
|
if (item.request) {
|
|
50084
|
-
const request =
|
|
50422
|
+
const request = asRecord5(item.request) ?? {};
|
|
50085
50423
|
const result = matchOperation(index, request);
|
|
50086
50424
|
let script;
|
|
50087
50425
|
if (result.operation) {
|
|
@@ -50095,15 +50433,15 @@ function instrumentContractCollection(collection, index) {
|
|
|
50095
50433
|
} else {
|
|
50096
50434
|
script = createMappingFailureScript(`No OpenAPI operation matched request ${result.method} ${result.path}`);
|
|
50097
50435
|
}
|
|
50098
|
-
const events2 = asArray3(item.event).filter((entry) =>
|
|
50436
|
+
const events2 = asArray3(item.event).filter((entry) => asRecord5(entry)?.listen !== "test");
|
|
50099
50437
|
item.event = [...events2, { listen: "test", script: { type: "text/javascript", exec: script } }];
|
|
50100
50438
|
}
|
|
50101
50439
|
for (const child2 of asArray3(item.item)) {
|
|
50102
|
-
const childRecord =
|
|
50440
|
+
const childRecord = asRecord5(child2);
|
|
50103
50441
|
if (childRecord) inject(childRecord);
|
|
50104
50442
|
}
|
|
50105
50443
|
};
|
|
50106
|
-
const items = asArray3(collection.item).map((entry) =>
|
|
50444
|
+
const items = asArray3(collection.item).map((entry) => asRecord5(entry)).filter((entry) => Boolean(entry)).filter((entry) => !isResolverItem(entry));
|
|
50107
50445
|
collection.item = items;
|
|
50108
50446
|
for (const item of items) inject(item);
|
|
50109
50447
|
const missing = index.operations.filter((operation) => !covered.has(operation.id));
|
|
@@ -62467,7 +62805,7 @@ function compileErrors(result) {
|
|
|
62467
62805
|
|
|
62468
62806
|
// src/lib/spec/openapi-loader.ts
|
|
62469
62807
|
var import_yaml2 = __toESM(require_dist(), 1);
|
|
62470
|
-
function
|
|
62808
|
+
function asRecord6(value) {
|
|
62471
62809
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
62472
62810
|
return value;
|
|
62473
62811
|
}
|
|
@@ -62482,7 +62820,7 @@ function parseOpenApiDocument(content) {
|
|
|
62482
62820
|
throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content is not valid JSON or YAML");
|
|
62483
62821
|
}
|
|
62484
62822
|
}
|
|
62485
|
-
const doc =
|
|
62823
|
+
const doc = asRecord6(parsed);
|
|
62486
62824
|
if (!doc) throw new Error("CONTRACT_SPEC_PARSE_FAILED: Spec content must be a JSON or YAML object");
|
|
62487
62825
|
return doc;
|
|
62488
62826
|
}
|
|
@@ -62510,7 +62848,7 @@ function collectExternalRefs(node, baseUrl, refs) {
|
|
|
62510
62848
|
node.forEach((entry) => collectExternalRefs(entry, baseUrl, refs));
|
|
62511
62849
|
return;
|
|
62512
62850
|
}
|
|
62513
|
-
const record =
|
|
62851
|
+
const record = asRecord6(node);
|
|
62514
62852
|
if (!record) return;
|
|
62515
62853
|
const ref = typeof record.$ref === "string" ? record.$ref : "";
|
|
62516
62854
|
if (ref && !ref.startsWith("#")) {
|
|
@@ -62848,6 +63186,11 @@ function resolveInputs(env = process.env) {
|
|
|
62848
63186
|
governanceMappingJson: parseGovernanceMappingJson(getInput2("governance-mapping-json", env)),
|
|
62849
63187
|
postmanApiKey: getInput2("postman-api-key", env) ?? "",
|
|
62850
63188
|
postmanAccessToken: getInput2("postman-access-token", env),
|
|
63189
|
+
credentialPreflight: parseEnumInput(
|
|
63190
|
+
"credential-preflight",
|
|
63191
|
+
getInput2("credential-preflight", env),
|
|
63192
|
+
customerPreviewActionContract.inputs["credential-preflight"].default ?? "warn"
|
|
63193
|
+
),
|
|
62851
63194
|
integrationBackend,
|
|
62852
63195
|
folderStrategy: parseEnumInput("folder-strategy", getInput2("folder-strategy", env), "Paths"),
|
|
62853
63196
|
nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput2("nested-folder-hierarchy", env), false),
|
|
@@ -62857,6 +63200,7 @@ function resolveInputs(env = process.env) {
|
|
|
62857
63200
|
postmanBifrostBase: endpointProfile.bifrostBaseUrl,
|
|
62858
63201
|
postmanGatewayBase: endpointProfile.gatewayBaseUrl,
|
|
62859
63202
|
postmanCliInstallUrl: endpointProfile.cliInstallUrl,
|
|
63203
|
+
postmanIapubBase: endpointProfile.iapubBaseUrl,
|
|
62860
63204
|
githubRefName: env.GITHUB_REF_NAME,
|
|
62861
63205
|
githubHeadRef: env.GITHUB_HEAD_REF,
|
|
62862
63206
|
githubRef: env.GITHUB_REF,
|
|
@@ -62945,6 +63289,7 @@ function readActionInputs(actionCore) {
|
|
|
62945
63289
|
INPUT_GOVERNANCE_MAPPING_JSON: optionalInput(actionCore, "governance-mapping-json") ?? customerPreviewActionContract.inputs["governance-mapping-json"].default,
|
|
62946
63290
|
INPUT_POSTMAN_API_KEY: postmanApiKey,
|
|
62947
63291
|
INPUT_POSTMAN_ACCESS_TOKEN: postmanAccessToken,
|
|
63292
|
+
INPUT_CREDENTIAL_PREFLIGHT: optionalInput(actionCore, "credential-preflight") ?? customerPreviewActionContract.inputs["credential-preflight"].default,
|
|
62948
63293
|
INPUT_INTEGRATION_BACKEND: optionalInput(actionCore, "integration-backend") ?? customerPreviewActionContract.inputs["integration-backend"].default,
|
|
62949
63294
|
INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? customerPreviewActionContract.inputs["folder-strategy"].default,
|
|
62950
63295
|
INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? customerPreviewActionContract.inputs["nested-folder-hierarchy"].default,
|
|
@@ -63456,8 +63801,20 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
|
|
|
63456
63801
|
governanceGroupName
|
|
63457
63802
|
);
|
|
63458
63803
|
} catch (error2) {
|
|
63804
|
+
const session = getMemoizedSessionIdentity();
|
|
63805
|
+
const advised = error2 instanceof HttpError ? adviseFromHttpError(error2, {
|
|
63806
|
+
operation: "governance assignment",
|
|
63807
|
+
hasAccessToken: Boolean(inputs.postmanAccessToken),
|
|
63808
|
+
sessionTeamId: session?.teamId,
|
|
63809
|
+
sessionRoles: session?.roles,
|
|
63810
|
+
sessionConsumerType: session?.consumerType,
|
|
63811
|
+
workspaceTeamId: inputs.workspaceTeamId,
|
|
63812
|
+
explicitTeamId: inputs.teamId || void 0,
|
|
63813
|
+
mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken])
|
|
63814
|
+
}) : void 0;
|
|
63815
|
+
const reported = advised ?? error2;
|
|
63459
63816
|
dependencies.core.warning(
|
|
63460
|
-
`Failed to assign governance group: ${
|
|
63817
|
+
`Failed to assign governance group: ${reported instanceof Error ? reported.message : String(reported)}`
|
|
63461
63818
|
);
|
|
63462
63819
|
}
|
|
63463
63820
|
}
|
|
@@ -64044,6 +64401,17 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
|
|
|
64044
64401
|
}
|
|
64045
64402
|
async function runAction(actionCore = core_exports, actionExec = exec_exports, actionIo = io_exports) {
|
|
64046
64403
|
const inputs = readActionInputs(actionCore);
|
|
64404
|
+
await runCredentialPreflight({
|
|
64405
|
+
apiBaseUrl: inputs.postmanApiBase,
|
|
64406
|
+
iapubBaseUrl: inputs.postmanIapubBase,
|
|
64407
|
+
postmanApiKey: inputs.postmanApiKey,
|
|
64408
|
+
postmanAccessToken: inputs.postmanAccessToken,
|
|
64409
|
+
workspaceTeamId: inputs.workspaceTeamId,
|
|
64410
|
+
explicitTeamId: inputs.teamId || void 0,
|
|
64411
|
+
mode: inputs.credentialPreflight,
|
|
64412
|
+
mask: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken]),
|
|
64413
|
+
log: actionCore
|
|
64414
|
+
});
|
|
64047
64415
|
let orgMode = false;
|
|
64048
64416
|
if (inputs.postmanAccessToken && inputs.teamId) {
|
|
64049
64417
|
try {
|