@postman-cse/onboarding-bootstrap 0.12.0 → 0.13.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 +1 -1
- package/action.yml +4 -0
- package/dist/cli.cjs +184 -93
- package/dist/index.cjs +182 -92
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -222,7 +222,7 @@ Install globally:
|
|
|
222
222
|
npm install -g @postman-cse/onboarding-bootstrap
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
The CLI package supports Node.js
|
|
225
|
+
The CLI package supports Node.js 24+ to match the GitHub Action runtime.
|
|
226
226
|
|
|
227
227
|
Basic usage:
|
|
228
228
|
|
package/action.yml
CHANGED
|
@@ -86,6 +86,10 @@ inputs:
|
|
|
86
86
|
description: Determines how requests are named in generated collections (Fallback or URL)
|
|
87
87
|
required: false
|
|
88
88
|
default: Fallback
|
|
89
|
+
postman-stack:
|
|
90
|
+
description: Postman stack profile
|
|
91
|
+
required: false
|
|
92
|
+
default: prod
|
|
89
93
|
outputs:
|
|
90
94
|
workspace-id:
|
|
91
95
|
description: Postman workspace ID
|
package/dist/cli.cjs
CHANGED
|
@@ -46951,6 +46951,12 @@ var openAlphaActionContract = {
|
|
|
46951
46951
|
required: false,
|
|
46952
46952
|
default: "Fallback",
|
|
46953
46953
|
allowedValues: ["Fallback", "URL"]
|
|
46954
|
+
},
|
|
46955
|
+
"postman-stack": {
|
|
46956
|
+
description: "Postman stack profile.",
|
|
46957
|
+
required: false,
|
|
46958
|
+
default: "prod",
|
|
46959
|
+
allowedValues: ["prod", "beta"]
|
|
46954
46960
|
}
|
|
46955
46961
|
},
|
|
46956
46962
|
outputs: {
|
|
@@ -47141,6 +47147,32 @@ var HttpError = class _HttpError extends Error {
|
|
|
47141
47147
|
}
|
|
47142
47148
|
};
|
|
47143
47149
|
|
|
47150
|
+
// src/lib/postman/base-urls.ts
|
|
47151
|
+
var POSTMAN_ENDPOINT_PROFILES = {
|
|
47152
|
+
prod: {
|
|
47153
|
+
apiBaseUrl: "https://api.getpostman.com",
|
|
47154
|
+
bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
|
|
47155
|
+
cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
|
|
47156
|
+
gatewayBaseUrl: "https://gateway.postman.com"
|
|
47157
|
+
},
|
|
47158
|
+
beta: {
|
|
47159
|
+
apiBaseUrl: "https://api.getpostman-beta.com",
|
|
47160
|
+
bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
|
|
47161
|
+
cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
|
|
47162
|
+
gatewayBaseUrl: "https://gateway.postman-beta.com"
|
|
47163
|
+
}
|
|
47164
|
+
};
|
|
47165
|
+
function parsePostmanStack(value) {
|
|
47166
|
+
const normalized = String(value || "prod").trim().toLowerCase();
|
|
47167
|
+
if (normalized === "prod" || normalized === "beta") {
|
|
47168
|
+
return normalized;
|
|
47169
|
+
}
|
|
47170
|
+
throw new Error(`Unsupported postman-stack "${value}". Supported values: prod, beta`);
|
|
47171
|
+
}
|
|
47172
|
+
function resolvePostmanEndpointProfile(stack) {
|
|
47173
|
+
return POSTMAN_ENDPOINT_PROFILES[stack];
|
|
47174
|
+
}
|
|
47175
|
+
|
|
47144
47176
|
// src/lib/retry.ts
|
|
47145
47177
|
function sleep(delayMs) {
|
|
47146
47178
|
return new Promise((resolve3) => {
|
|
@@ -47195,6 +47227,15 @@ function asRecord(value) {
|
|
|
47195
47227
|
}
|
|
47196
47228
|
return value;
|
|
47197
47229
|
}
|
|
47230
|
+
function extractWorkspacesPage(data) {
|
|
47231
|
+
const workspaces = Array.isArray(data?.workspaces) ? data.workspaces : [];
|
|
47232
|
+
const meta = asRecord(data?.meta);
|
|
47233
|
+
const pagination = asRecord(data?.pagination);
|
|
47234
|
+
const nextCursor = String(
|
|
47235
|
+
data?.nextCursor ?? data?.next_cursor ?? meta?.nextCursor ?? meta?.next_cursor ?? pagination?.nextCursor ?? pagination?.next_cursor ?? ""
|
|
47236
|
+
).trim() || void 0;
|
|
47237
|
+
return { nextCursor, workspaces };
|
|
47238
|
+
}
|
|
47198
47239
|
function normalizeGitRepoUrl(url) {
|
|
47199
47240
|
const raw = String(url || "").trim();
|
|
47200
47241
|
if (!raw) return "";
|
|
@@ -47243,20 +47284,27 @@ function extractGitRepoUrl(value) {
|
|
|
47243
47284
|
var PostmanAssetsClient = class {
|
|
47244
47285
|
apiKey;
|
|
47245
47286
|
baseUrl;
|
|
47287
|
+
bifrostBaseUrl;
|
|
47246
47288
|
fetchImpl;
|
|
47247
47289
|
secretMasker;
|
|
47248
47290
|
constructor(options) {
|
|
47249
47291
|
this.apiKey = String(options.apiKey || "").trim();
|
|
47250
|
-
this.baseUrl = String(options.baseUrl ||
|
|
47292
|
+
this.baseUrl = String(options.baseUrl || POSTMAN_ENDPOINT_PROFILES.prod.apiBaseUrl).replace(
|
|
47251
47293
|
/\/+$/,
|
|
47252
47294
|
""
|
|
47253
47295
|
);
|
|
47296
|
+
this.bifrostBaseUrl = String(
|
|
47297
|
+
options.bifrostBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl
|
|
47298
|
+
).replace(/\/+$/, "");
|
|
47254
47299
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
47255
47300
|
this.secretMasker = options.secretMasker ?? createSecretMasker([this.apiKey]);
|
|
47256
47301
|
}
|
|
47257
47302
|
getBaseUrl() {
|
|
47258
47303
|
return this.baseUrl;
|
|
47259
47304
|
}
|
|
47305
|
+
getBifrostBaseUrl() {
|
|
47306
|
+
return this.bifrostBaseUrl;
|
|
47307
|
+
}
|
|
47260
47308
|
async getMe() {
|
|
47261
47309
|
return this.request("/me", { method: "GET" });
|
|
47262
47310
|
}
|
|
@@ -47357,20 +47405,33 @@ var PostmanAssetsClient = class {
|
|
|
47357
47405
|
});
|
|
47358
47406
|
}
|
|
47359
47407
|
async listWorkspaces() {
|
|
47360
|
-
const
|
|
47361
|
-
const
|
|
47362
|
-
|
|
47408
|
+
const allWorkspaces = [];
|
|
47409
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
47410
|
+
let nextCursor;
|
|
47411
|
+
do {
|
|
47412
|
+
const query = nextCursor ? `?cursor=${encodeURIComponent(nextCursor)}` : "";
|
|
47413
|
+
const data = await this.request(`/workspaces${query}`);
|
|
47414
|
+
const page = extractWorkspacesPage(data);
|
|
47415
|
+
allWorkspaces.push(...page.workspaces);
|
|
47416
|
+
if (!page.nextCursor || seenCursors.has(page.nextCursor)) {
|
|
47417
|
+
nextCursor = void 0;
|
|
47418
|
+
} else {
|
|
47419
|
+
seenCursors.add(page.nextCursor);
|
|
47420
|
+
nextCursor = page.nextCursor;
|
|
47421
|
+
}
|
|
47422
|
+
} while (nextCursor);
|
|
47423
|
+
return allWorkspaces.map((entry) => asRecord(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
|
|
47363
47424
|
id: String(workspace.id),
|
|
47364
47425
|
name: String(workspace.name),
|
|
47365
47426
|
type: String(workspace.type ?? "team")
|
|
47366
|
-
}))
|
|
47427
|
+
}));
|
|
47367
47428
|
}
|
|
47368
47429
|
async findWorkspacesByName(name) {
|
|
47369
47430
|
const workspaces = await this.listWorkspaces();
|
|
47370
47431
|
return workspaces.filter((w) => w.name === name).sort((a, b) => a.id.localeCompare(b.id)).map((w) => ({ id: w.id, name: w.name }));
|
|
47371
47432
|
}
|
|
47372
47433
|
async getWorkspaceGitRepoUrl(workspaceId, teamId, accessToken) {
|
|
47373
|
-
const url =
|
|
47434
|
+
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
47374
47435
|
const headers = {
|
|
47375
47436
|
"x-access-token": accessToken,
|
|
47376
47437
|
"Content-Type": "application/json"
|
|
@@ -47389,8 +47450,12 @@ var PostmanAssetsClient = class {
|
|
|
47389
47450
|
});
|
|
47390
47451
|
if (response.status === 404) return null;
|
|
47391
47452
|
if (!response.ok) {
|
|
47392
|
-
|
|
47393
|
-
|
|
47453
|
+
throw await HttpError.fromResponse(response, {
|
|
47454
|
+
method: "POST",
|
|
47455
|
+
requestHeaders: headers,
|
|
47456
|
+
secretValues: [this.apiKey, accessToken],
|
|
47457
|
+
url
|
|
47458
|
+
});
|
|
47394
47459
|
}
|
|
47395
47460
|
const body = await response.text();
|
|
47396
47461
|
if (!body.trim()) return null;
|
|
@@ -47790,26 +47855,32 @@ var PostmanAssetsClient = class {
|
|
|
47790
47855
|
// src/lib/postman/internal-integration-adapter.ts
|
|
47791
47856
|
var BifrostInternalIntegrationAdapter = class {
|
|
47792
47857
|
accessToken;
|
|
47858
|
+
bifrostBaseUrl;
|
|
47793
47859
|
fetchImpl;
|
|
47860
|
+
gatewayBaseUrl;
|
|
47861
|
+
orgMode;
|
|
47794
47862
|
secretMasker;
|
|
47795
47863
|
teamId;
|
|
47796
|
-
workerBaseUrl;
|
|
47797
47864
|
constructor(options) {
|
|
47798
47865
|
this.accessToken = String(options.accessToken || "").trim();
|
|
47866
|
+
this.bifrostBaseUrl = String(
|
|
47867
|
+
options.bifrostBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl
|
|
47868
|
+
).replace(/\/+$/, "");
|
|
47799
47869
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
47870
|
+
this.gatewayBaseUrl = String(
|
|
47871
|
+
options.gatewayBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.gatewayBaseUrl
|
|
47872
|
+
).replace(/\/+$/, "");
|
|
47873
|
+
this.orgMode = options.orgMode ?? false;
|
|
47800
47874
|
this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
|
|
47801
47875
|
this.teamId = String(options.teamId || "").trim();
|
|
47802
|
-
this.workerBaseUrl = String(
|
|
47803
|
-
options.workerBaseUrl || "https://catalog-admin.postman-account2009.workers.dev"
|
|
47804
|
-
).replace(/\/+$/, "");
|
|
47805
47876
|
}
|
|
47806
47877
|
async proxyRequest(service, method, requestPath2, body) {
|
|
47807
|
-
const url =
|
|
47878
|
+
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
47808
47879
|
const headers = {
|
|
47809
47880
|
"Content-Type": "application/json",
|
|
47810
47881
|
"x-access-token": this.accessToken
|
|
47811
47882
|
};
|
|
47812
|
-
if (this.teamId) {
|
|
47883
|
+
if (this.teamId && this.orgMode) {
|
|
47813
47884
|
headers["x-entity-team-id"] = this.teamId;
|
|
47814
47885
|
}
|
|
47815
47886
|
return this.fetchImpl(url, {
|
|
@@ -47834,14 +47905,12 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47834
47905
|
if (!groupName) {
|
|
47835
47906
|
return;
|
|
47836
47907
|
}
|
|
47837
|
-
const
|
|
47838
|
-
|
|
47839
|
-
{
|
|
47840
|
-
|
|
47841
|
-
"x-access-token": this.accessToken
|
|
47842
|
-
}
|
|
47908
|
+
const listUrl = `${this.gatewayBaseUrl}/configure/workspace-groups`;
|
|
47909
|
+
const listResponse = await this.fetchImpl(listUrl, {
|
|
47910
|
+
headers: {
|
|
47911
|
+
"x-access-token": this.accessToken
|
|
47843
47912
|
}
|
|
47844
|
-
);
|
|
47913
|
+
});
|
|
47845
47914
|
if (!listResponse.ok) {
|
|
47846
47915
|
throw await HttpError.fromResponse(listResponse, {
|
|
47847
47916
|
method: "GET",
|
|
@@ -47849,7 +47918,7 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47849
47918
|
"x-access-token": this.accessToken
|
|
47850
47919
|
},
|
|
47851
47920
|
secretValues: [this.accessToken],
|
|
47852
|
-
url:
|
|
47921
|
+
url: listUrl
|
|
47853
47922
|
});
|
|
47854
47923
|
}
|
|
47855
47924
|
const groups = await listResponse.json();
|
|
@@ -47857,19 +47926,17 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47857
47926
|
if (!group?.id) {
|
|
47858
47927
|
return;
|
|
47859
47928
|
}
|
|
47860
|
-
const
|
|
47861
|
-
|
|
47862
|
-
|
|
47863
|
-
|
|
47864
|
-
|
|
47865
|
-
|
|
47866
|
-
|
|
47867
|
-
|
|
47868
|
-
|
|
47869
|
-
|
|
47870
|
-
|
|
47871
|
-
}
|
|
47872
|
-
);
|
|
47929
|
+
const patchUrl = `${this.gatewayBaseUrl}/configure/workspace-groups/${group.id}`;
|
|
47930
|
+
const patchResponse = await this.fetchImpl(patchUrl, {
|
|
47931
|
+
method: "PATCH",
|
|
47932
|
+
headers: {
|
|
47933
|
+
"Content-Type": "application/json",
|
|
47934
|
+
"x-access-token": this.accessToken
|
|
47935
|
+
},
|
|
47936
|
+
body: JSON.stringify({
|
|
47937
|
+
workspaces: [workspaceId]
|
|
47938
|
+
})
|
|
47939
|
+
});
|
|
47873
47940
|
if (!patchResponse.ok) {
|
|
47874
47941
|
throw await HttpError.fromResponse(patchResponse, {
|
|
47875
47942
|
method: "PATCH",
|
|
@@ -47878,40 +47945,7 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47878
47945
|
"x-access-token": this.accessToken
|
|
47879
47946
|
},
|
|
47880
47947
|
secretValues: [this.accessToken],
|
|
47881
|
-
url:
|
|
47882
|
-
});
|
|
47883
|
-
}
|
|
47884
|
-
}
|
|
47885
|
-
async associateSystemEnvironments(workspaceId, associations) {
|
|
47886
|
-
if (associations.length === 0) {
|
|
47887
|
-
return;
|
|
47888
|
-
}
|
|
47889
|
-
const response = await this.fetchImpl(
|
|
47890
|
-
`${this.workerBaseUrl}/api/internal/system-envs/associate`,
|
|
47891
|
-
{
|
|
47892
|
-
method: "POST",
|
|
47893
|
-
headers: {
|
|
47894
|
-
Authorization: `Bearer ${this.accessToken}`,
|
|
47895
|
-
"Content-Type": "application/json"
|
|
47896
|
-
},
|
|
47897
|
-
body: JSON.stringify({
|
|
47898
|
-
workspace_id: workspaceId,
|
|
47899
|
-
associations: associations.map((entry) => ({
|
|
47900
|
-
env_uid: entry.envUid,
|
|
47901
|
-
system_env_id: entry.systemEnvId
|
|
47902
|
-
}))
|
|
47903
|
-
})
|
|
47904
|
-
}
|
|
47905
|
-
);
|
|
47906
|
-
if (!response.ok) {
|
|
47907
|
-
throw await HttpError.fromResponse(response, {
|
|
47908
|
-
method: "POST",
|
|
47909
|
-
requestHeaders: {
|
|
47910
|
-
Authorization: `Bearer ${this.accessToken}`,
|
|
47911
|
-
"Content-Type": "application/json"
|
|
47912
|
-
},
|
|
47913
|
-
secretValues: [this.accessToken],
|
|
47914
|
-
url: `${this.workerBaseUrl}/api/internal/system-envs/associate`
|
|
47948
|
+
url: patchUrl
|
|
47915
47949
|
});
|
|
47916
47950
|
}
|
|
47917
47951
|
}
|
|
@@ -47951,10 +47985,10 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47951
47985
|
requestHeaders: {
|
|
47952
47986
|
"Content-Type": "application/json",
|
|
47953
47987
|
"x-access-token": this.accessToken,
|
|
47954
|
-
...this.teamId ? { "x-entity-team-id": this.teamId } : {}
|
|
47988
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
47955
47989
|
},
|
|
47956
47990
|
secretValues: [this.accessToken],
|
|
47957
|
-
url:
|
|
47991
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
47958
47992
|
});
|
|
47959
47993
|
}
|
|
47960
47994
|
async linkCollectionsToSpecification(specificationId, collections) {
|
|
@@ -47978,10 +48012,10 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47978
48012
|
requestHeaders: {
|
|
47979
48013
|
"Content-Type": "application/json",
|
|
47980
48014
|
"x-access-token": this.accessToken,
|
|
47981
|
-
...this.teamId ? { "x-entity-team-id": this.teamId } : {}
|
|
48015
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
47982
48016
|
},
|
|
47983
48017
|
secretValues: [this.accessToken],
|
|
47984
|
-
url:
|
|
48018
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
47985
48019
|
});
|
|
47986
48020
|
}
|
|
47987
48021
|
async syncCollection(specificationId, collectionId) {
|
|
@@ -47998,10 +48032,10 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47998
48032
|
requestHeaders: {
|
|
47999
48033
|
"Content-Type": "application/json",
|
|
48000
48034
|
"x-access-token": this.accessToken,
|
|
48001
|
-
...this.teamId ? { "x-entity-team-id": this.teamId } : {}
|
|
48035
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
48002
48036
|
},
|
|
48003
48037
|
secretValues: [this.accessToken],
|
|
48004
|
-
url:
|
|
48038
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
48005
48039
|
});
|
|
48006
48040
|
}
|
|
48007
48041
|
async getWorkspaceGitRepoUrl(workspaceId) {
|
|
@@ -48422,10 +48456,18 @@ async function resolveCanonicalWorkspaceSelection(args) {
|
|
|
48422
48456
|
args.warn?.(`Workspace duplicate check failed; falling back to repo workspace ${args.repoWorkspaceId}: ${error}`);
|
|
48423
48457
|
}
|
|
48424
48458
|
if (matchingWorkspaces.length > 0) {
|
|
48425
|
-
|
|
48459
|
+
const lookupResults = await Promise.allSettled(matchingWorkspaces.map(async (workspace) => ({
|
|
48426
48460
|
...workspace,
|
|
48427
48461
|
linkedRepoUrl: await args.postman.getWorkspaceGitRepoUrl(workspace.id, args.teamId, args.accessToken)
|
|
48428
48462
|
})));
|
|
48463
|
+
matchingWorkspaces = lookupResults.map((result, index) => {
|
|
48464
|
+
if (result.status === "fulfilled") {
|
|
48465
|
+
return result.value;
|
|
48466
|
+
}
|
|
48467
|
+
const workspace = matchingWorkspaces[index];
|
|
48468
|
+
args.warn?.(`Workspace Git repo lookup failed for ${workspace?.id ?? "unknown workspace"}; ignoring linked-repo metadata for that candidate: ${result.reason}`);
|
|
48469
|
+
return workspace ? { ...workspace, linkedRepoUrl: null } : void 0;
|
|
48470
|
+
}).filter((workspace) => Boolean(workspace));
|
|
48429
48471
|
}
|
|
48430
48472
|
return chooseCanonicalWorkspace({
|
|
48431
48473
|
repoWorkspaceId: args.repoWorkspaceId,
|
|
@@ -61754,6 +61796,8 @@ function resolveInputs(env = process.env) {
|
|
|
61754
61796
|
throw new Error(`spec-url must be a valid HTTPS URL, got: ${sanitizeUrlForLog(specUrl)}`, { cause: error });
|
|
61755
61797
|
}
|
|
61756
61798
|
}
|
|
61799
|
+
const postmanStack = parsePostmanStack(getInput("postman-stack", env));
|
|
61800
|
+
const endpointProfile = resolvePostmanEndpointProfile(postmanStack);
|
|
61757
61801
|
return {
|
|
61758
61802
|
projectName: getInput("project-name", env) ?? env.GITHUB_REPOSITORY?.split("/").pop() ?? env.CI_PROJECT_NAME ?? "",
|
|
61759
61803
|
workspaceId: getInput("workspace-id", env),
|
|
@@ -61781,6 +61825,11 @@ function resolveInputs(env = process.env) {
|
|
|
61781
61825
|
folderStrategy: parseEnumInput("folder-strategy", getInput("folder-strategy", env), "Paths"),
|
|
61782
61826
|
nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput("nested-folder-hierarchy", env), false),
|
|
61783
61827
|
requestNameSource: parseEnumInput("request-name-source", getInput("request-name-source", env), "Fallback"),
|
|
61828
|
+
postmanStack,
|
|
61829
|
+
postmanApiBase: endpointProfile.apiBaseUrl,
|
|
61830
|
+
postmanBifrostBase: endpointProfile.bifrostBaseUrl,
|
|
61831
|
+
postmanGatewayBase: endpointProfile.gatewayBaseUrl,
|
|
61832
|
+
postmanCliInstallUrl: endpointProfile.cliInstallUrl,
|
|
61784
61833
|
githubRefName: env.GITHUB_REF_NAME,
|
|
61785
61834
|
githubHeadRef: env.GITHUB_HEAD_REF,
|
|
61786
61835
|
githubRef: env.GITHUB_REF,
|
|
@@ -61847,7 +61896,8 @@ function readActionInputs(actionCore) {
|
|
|
61847
61896
|
INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? openAlphaActionContract.inputs["folder-strategy"].default,
|
|
61848
61897
|
INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? openAlphaActionContract.inputs["nested-folder-hierarchy"].default,
|
|
61849
61898
|
INPUT_REQUEST_NAME_SOURCE: optionalInput(actionCore, "request-name-source") ?? openAlphaActionContract.inputs["request-name-source"].default,
|
|
61850
|
-
INPUT_OPENAPI_VERSION: optionalInput(actionCore, "openapi-version") ?? ""
|
|
61899
|
+
INPUT_OPENAPI_VERSION: optionalInput(actionCore, "openapi-version") ?? "",
|
|
61900
|
+
INPUT_POSTMAN_STACK: optionalInput(actionCore, "postman-stack") ?? openAlphaActionContract.inputs["postman-stack"].default
|
|
61851
61901
|
});
|
|
61852
61902
|
return inputs;
|
|
61853
61903
|
}
|
|
@@ -61857,13 +61907,29 @@ function createWorkspaceName(inputs) {
|
|
|
61857
61907
|
async function runGroup(actionCore, name, fn) {
|
|
61858
61908
|
return actionCore.group(name, fn);
|
|
61859
61909
|
}
|
|
61860
|
-
|
|
61910
|
+
function validateHttpsInstallUrl(url) {
|
|
61911
|
+
const safeUrlPattern = /^https:\/\/[A-Za-z0-9.-]+\/[A-Za-z0-9._~/?=&%-]+$/;
|
|
61912
|
+
if (!safeUrlPattern.test(url)) {
|
|
61913
|
+
throw new Error(
|
|
61914
|
+
`postman-cli-install-url must be an https URL with safe characters; got: ${url}`
|
|
61915
|
+
);
|
|
61916
|
+
}
|
|
61917
|
+
return url;
|
|
61918
|
+
}
|
|
61919
|
+
async function ensurePostmanCli(dependencies, postmanApiKey, installUrl = "https://dl-cli.pstmn.io/install/unix.sh") {
|
|
61920
|
+
const validatedUrl = validateHttpsInstallUrl(installUrl);
|
|
61861
61921
|
const existing = await dependencies.io.which("postman", false).catch(() => "");
|
|
61862
61922
|
if (!existing) {
|
|
61863
|
-
await dependencies.exec.exec(
|
|
61864
|
-
"
|
|
61865
|
-
'curl -
|
|
61866
|
-
|
|
61923
|
+
await dependencies.exec.exec(
|
|
61924
|
+
"sh",
|
|
61925
|
+
["-c", 'curl -fsSL "$POSTMAN_CLI_INSTALL_URL" | sh'],
|
|
61926
|
+
{
|
|
61927
|
+
env: {
|
|
61928
|
+
...process.env,
|
|
61929
|
+
POSTMAN_CLI_INSTALL_URL: validatedUrl
|
|
61930
|
+
}
|
|
61931
|
+
}
|
|
61932
|
+
);
|
|
61867
61933
|
}
|
|
61868
61934
|
await dependencies.exec.exec("postman", ["login", "--with-api-key", postmanApiKey]);
|
|
61869
61935
|
}
|
|
@@ -62081,7 +62147,7 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
62081
62147
|
const workspaceName = createWorkspaceName(inputs);
|
|
62082
62148
|
const aboutText = `Auto-provisioned by Postman CS open-alpha for ${inputs.projectName}`;
|
|
62083
62149
|
await runGroup(dependencies.core, "Install Postman CLI", async () => {
|
|
62084
|
-
await ensurePostmanCli(dependencies, inputs.postmanApiKey);
|
|
62150
|
+
await ensurePostmanCli(dependencies, inputs.postmanApiKey, inputs.postmanCliInstallUrl);
|
|
62085
62151
|
});
|
|
62086
62152
|
const resourcesState = readResourcesState();
|
|
62087
62153
|
let specId = inputs.specId;
|
|
@@ -62197,13 +62263,17 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
62197
62263
|
"GET /teams returned multiple teams but none include organizationId. Org-mode detection may be degraded due to an upstream API change. If workspace creation fails, set workspace-team-id explicitly."
|
|
62198
62264
|
);
|
|
62199
62265
|
}
|
|
62200
|
-
const
|
|
62201
|
-
const meTeamId = parseInt(teamId, 10);
|
|
62202
|
-
const isOrgMode = teams.length > 1 && orgIds.size === 1 && orgIds.has(meTeamId);
|
|
62266
|
+
const isOrgMode = teams.some((t) => t.organizationId != null);
|
|
62203
62267
|
if (isOrgMode) {
|
|
62204
|
-
|
|
62205
|
-
|
|
62206
|
-
|
|
62268
|
+
if (teams.length === 1) {
|
|
62269
|
+
workspaceTeamId = teams[0].id;
|
|
62270
|
+
dependencies.core.info(
|
|
62271
|
+
`Org-mode account detected. Using sub-team ${teams[0].id} (${teams[0].name}) for workspace creation.`
|
|
62272
|
+
);
|
|
62273
|
+
} else {
|
|
62274
|
+
const teamList = teams.map((t) => ` ${t.id} ${t.name}`).join("\n");
|
|
62275
|
+
throw new Error(
|
|
62276
|
+
`Org-mode account detected. Workspace creation requires a specific sub-team ID.
|
|
62207
62277
|
|
|
62208
62278
|
Available sub-teams:
|
|
62209
62279
|
${teamList}
|
|
@@ -62215,7 +62285,8 @@ Or for reuse across runs, create a repository variable and reference it:
|
|
|
62215
62285
|
workspace-team-id: \${{ vars.POSTMAN_WORKSPACE_TEAM_ID }}
|
|
62216
62286
|
|
|
62217
62287
|
For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID=<id>.`
|
|
62218
|
-
|
|
62288
|
+
);
|
|
62289
|
+
}
|
|
62219
62290
|
} else if (teams.length > 1) {
|
|
62220
62291
|
dependencies.core.warning(
|
|
62221
62292
|
`API key has access to ${teams.length} teams but org-mode could not be confirmed. Proceeding without teamId. If workspace creation fails, set workspace-team-id explicitly.`
|
|
@@ -62840,12 +62911,26 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
|
|
|
62840
62911
|
}
|
|
62841
62912
|
async function runAction(actionCore = core2, actionExec = exec, actionIo = io) {
|
|
62842
62913
|
const inputs = readActionInputs(actionCore);
|
|
62914
|
+
let orgMode = false;
|
|
62915
|
+
if (inputs.postmanAccessToken && inputs.teamId) {
|
|
62916
|
+
try {
|
|
62917
|
+
const tempPostman = new PostmanAssetsClient({
|
|
62918
|
+
apiKey: inputs.postmanApiKey,
|
|
62919
|
+
baseUrl: inputs.postmanApiBase,
|
|
62920
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
62921
|
+
secretMasker: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken])
|
|
62922
|
+
});
|
|
62923
|
+
const teams = await tempPostman.getTeams();
|
|
62924
|
+
orgMode = teams.some((t) => t.organizationId != null);
|
|
62925
|
+
} catch {
|
|
62926
|
+
}
|
|
62927
|
+
}
|
|
62843
62928
|
const dependencies = createBootstrapDependencies(inputs, {
|
|
62844
62929
|
core: actionCore,
|
|
62845
62930
|
exec: actionExec,
|
|
62846
62931
|
io: actionIo,
|
|
62847
62932
|
specFetcher: fetch
|
|
62848
|
-
});
|
|
62933
|
+
}, orgMode);
|
|
62849
62934
|
if (inputs.domain && !dependencies.internalIntegration) {
|
|
62850
62935
|
actionCore.warning(
|
|
62851
62936
|
"Skipping governance assignment because postman-access-token is not configured"
|
|
@@ -62853,18 +62938,23 @@ async function runAction(actionCore = core2, actionExec = exec, actionIo = io) {
|
|
|
62853
62938
|
}
|
|
62854
62939
|
return runBootstrap(inputs, dependencies);
|
|
62855
62940
|
}
|
|
62856
|
-
function createBootstrapDependencies(inputs, factories) {
|
|
62941
|
+
function createBootstrapDependencies(inputs, factories, orgMode = false) {
|
|
62857
62942
|
const secretMasker = createSecretMasker([
|
|
62858
62943
|
inputs.postmanApiKey,
|
|
62859
62944
|
inputs.postmanAccessToken
|
|
62860
62945
|
]);
|
|
62861
62946
|
const postman = new PostmanAssetsClient({
|
|
62862
62947
|
apiKey: inputs.postmanApiKey,
|
|
62948
|
+
baseUrl: inputs.postmanApiBase,
|
|
62949
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
62863
62950
|
secretMasker
|
|
62864
62951
|
});
|
|
62865
62952
|
const internalIntegration = inputs.postmanAccessToken ? createInternalIntegrationAdapter({
|
|
62866
62953
|
accessToken: inputs.postmanAccessToken,
|
|
62867
62954
|
backend: inputs.integrationBackend,
|
|
62955
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
62956
|
+
gatewayBaseUrl: inputs.postmanGatewayBase,
|
|
62957
|
+
orgMode,
|
|
62868
62958
|
secretMasker,
|
|
62869
62959
|
teamId: inputs.teamId || ""
|
|
62870
62960
|
}) : void 0;
|
|
@@ -62948,7 +63038,8 @@ var cliInputNames = [
|
|
|
62948
63038
|
"request-name-source",
|
|
62949
63039
|
"workspace-team-id",
|
|
62950
63040
|
"repo-url",
|
|
62951
|
-
"openapi-version"
|
|
63041
|
+
"openapi-version",
|
|
63042
|
+
"postman-stack"
|
|
62952
63043
|
];
|
|
62953
63044
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
62954
63045
|
function toCommandLabel(commandLine, args, secretMasker) {
|
package/dist/index.cjs
CHANGED
|
@@ -46945,6 +46945,12 @@ var openAlphaActionContract = {
|
|
|
46945
46945
|
required: false,
|
|
46946
46946
|
default: "Fallback",
|
|
46947
46947
|
allowedValues: ["Fallback", "URL"]
|
|
46948
|
+
},
|
|
46949
|
+
"postman-stack": {
|
|
46950
|
+
description: "Postman stack profile.",
|
|
46951
|
+
required: false,
|
|
46952
|
+
default: "prod",
|
|
46953
|
+
allowedValues: ["prod", "beta"]
|
|
46948
46954
|
}
|
|
46949
46955
|
},
|
|
46950
46956
|
outputs: {
|
|
@@ -47135,6 +47141,32 @@ var HttpError = class _HttpError extends Error {
|
|
|
47135
47141
|
}
|
|
47136
47142
|
};
|
|
47137
47143
|
|
|
47144
|
+
// src/lib/postman/base-urls.ts
|
|
47145
|
+
var POSTMAN_ENDPOINT_PROFILES = {
|
|
47146
|
+
prod: {
|
|
47147
|
+
apiBaseUrl: "https://api.getpostman.com",
|
|
47148
|
+
bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
|
|
47149
|
+
cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
|
|
47150
|
+
gatewayBaseUrl: "https://gateway.postman.com"
|
|
47151
|
+
},
|
|
47152
|
+
beta: {
|
|
47153
|
+
apiBaseUrl: "https://api.getpostman-beta.com",
|
|
47154
|
+
bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
|
|
47155
|
+
cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
|
|
47156
|
+
gatewayBaseUrl: "https://gateway.postman-beta.com"
|
|
47157
|
+
}
|
|
47158
|
+
};
|
|
47159
|
+
function parsePostmanStack(value) {
|
|
47160
|
+
const normalized = String(value || "prod").trim().toLowerCase();
|
|
47161
|
+
if (normalized === "prod" || normalized === "beta") {
|
|
47162
|
+
return normalized;
|
|
47163
|
+
}
|
|
47164
|
+
throw new Error(`Unsupported postman-stack "${value}". Supported values: prod, beta`);
|
|
47165
|
+
}
|
|
47166
|
+
function resolvePostmanEndpointProfile(stack) {
|
|
47167
|
+
return POSTMAN_ENDPOINT_PROFILES[stack];
|
|
47168
|
+
}
|
|
47169
|
+
|
|
47138
47170
|
// src/lib/retry.ts
|
|
47139
47171
|
function sleep(delayMs) {
|
|
47140
47172
|
return new Promise((resolve3) => {
|
|
@@ -47189,6 +47221,15 @@ function asRecord(value) {
|
|
|
47189
47221
|
}
|
|
47190
47222
|
return value;
|
|
47191
47223
|
}
|
|
47224
|
+
function extractWorkspacesPage(data) {
|
|
47225
|
+
const workspaces = Array.isArray(data?.workspaces) ? data.workspaces : [];
|
|
47226
|
+
const meta = asRecord(data?.meta);
|
|
47227
|
+
const pagination = asRecord(data?.pagination);
|
|
47228
|
+
const nextCursor = String(
|
|
47229
|
+
data?.nextCursor ?? data?.next_cursor ?? meta?.nextCursor ?? meta?.next_cursor ?? pagination?.nextCursor ?? pagination?.next_cursor ?? ""
|
|
47230
|
+
).trim() || void 0;
|
|
47231
|
+
return { nextCursor, workspaces };
|
|
47232
|
+
}
|
|
47192
47233
|
function normalizeGitRepoUrl(url) {
|
|
47193
47234
|
const raw = String(url || "").trim();
|
|
47194
47235
|
if (!raw) return "";
|
|
@@ -47237,20 +47278,27 @@ function extractGitRepoUrl(value) {
|
|
|
47237
47278
|
var PostmanAssetsClient = class {
|
|
47238
47279
|
apiKey;
|
|
47239
47280
|
baseUrl;
|
|
47281
|
+
bifrostBaseUrl;
|
|
47240
47282
|
fetchImpl;
|
|
47241
47283
|
secretMasker;
|
|
47242
47284
|
constructor(options) {
|
|
47243
47285
|
this.apiKey = String(options.apiKey || "").trim();
|
|
47244
|
-
this.baseUrl = String(options.baseUrl ||
|
|
47286
|
+
this.baseUrl = String(options.baseUrl || POSTMAN_ENDPOINT_PROFILES.prod.apiBaseUrl).replace(
|
|
47245
47287
|
/\/+$/,
|
|
47246
47288
|
""
|
|
47247
47289
|
);
|
|
47290
|
+
this.bifrostBaseUrl = String(
|
|
47291
|
+
options.bifrostBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl
|
|
47292
|
+
).replace(/\/+$/, "");
|
|
47248
47293
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
47249
47294
|
this.secretMasker = options.secretMasker ?? createSecretMasker([this.apiKey]);
|
|
47250
47295
|
}
|
|
47251
47296
|
getBaseUrl() {
|
|
47252
47297
|
return this.baseUrl;
|
|
47253
47298
|
}
|
|
47299
|
+
getBifrostBaseUrl() {
|
|
47300
|
+
return this.bifrostBaseUrl;
|
|
47301
|
+
}
|
|
47254
47302
|
async getMe() {
|
|
47255
47303
|
return this.request("/me", { method: "GET" });
|
|
47256
47304
|
}
|
|
@@ -47351,20 +47399,33 @@ var PostmanAssetsClient = class {
|
|
|
47351
47399
|
});
|
|
47352
47400
|
}
|
|
47353
47401
|
async listWorkspaces() {
|
|
47354
|
-
const
|
|
47355
|
-
const
|
|
47356
|
-
|
|
47402
|
+
const allWorkspaces = [];
|
|
47403
|
+
const seenCursors = /* @__PURE__ */ new Set();
|
|
47404
|
+
let nextCursor;
|
|
47405
|
+
do {
|
|
47406
|
+
const query = nextCursor ? `?cursor=${encodeURIComponent(nextCursor)}` : "";
|
|
47407
|
+
const data = await this.request(`/workspaces${query}`);
|
|
47408
|
+
const page = extractWorkspacesPage(data);
|
|
47409
|
+
allWorkspaces.push(...page.workspaces);
|
|
47410
|
+
if (!page.nextCursor || seenCursors.has(page.nextCursor)) {
|
|
47411
|
+
nextCursor = void 0;
|
|
47412
|
+
} else {
|
|
47413
|
+
seenCursors.add(page.nextCursor);
|
|
47414
|
+
nextCursor = page.nextCursor;
|
|
47415
|
+
}
|
|
47416
|
+
} while (nextCursor);
|
|
47417
|
+
return allWorkspaces.map((entry) => asRecord(entry)).filter((workspace) => Boolean(workspace?.id && workspace?.name)).map((workspace) => ({
|
|
47357
47418
|
id: String(workspace.id),
|
|
47358
47419
|
name: String(workspace.name),
|
|
47359
47420
|
type: String(workspace.type ?? "team")
|
|
47360
|
-
}))
|
|
47421
|
+
}));
|
|
47361
47422
|
}
|
|
47362
47423
|
async findWorkspacesByName(name) {
|
|
47363
47424
|
const workspaces = await this.listWorkspaces();
|
|
47364
47425
|
return workspaces.filter((w) => w.name === name).sort((a, b) => a.id.localeCompare(b.id)).map((w) => ({ id: w.id, name: w.name }));
|
|
47365
47426
|
}
|
|
47366
47427
|
async getWorkspaceGitRepoUrl(workspaceId, teamId, accessToken) {
|
|
47367
|
-
const url =
|
|
47428
|
+
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
47368
47429
|
const headers = {
|
|
47369
47430
|
"x-access-token": accessToken,
|
|
47370
47431
|
"Content-Type": "application/json"
|
|
@@ -47383,8 +47444,12 @@ var PostmanAssetsClient = class {
|
|
|
47383
47444
|
});
|
|
47384
47445
|
if (response.status === 404) return null;
|
|
47385
47446
|
if (!response.ok) {
|
|
47386
|
-
|
|
47387
|
-
|
|
47447
|
+
throw await HttpError.fromResponse(response, {
|
|
47448
|
+
method: "POST",
|
|
47449
|
+
requestHeaders: headers,
|
|
47450
|
+
secretValues: [this.apiKey, accessToken],
|
|
47451
|
+
url
|
|
47452
|
+
});
|
|
47388
47453
|
}
|
|
47389
47454
|
const body = await response.text();
|
|
47390
47455
|
if (!body.trim()) return null;
|
|
@@ -47784,26 +47849,32 @@ var PostmanAssetsClient = class {
|
|
|
47784
47849
|
// src/lib/postman/internal-integration-adapter.ts
|
|
47785
47850
|
var BifrostInternalIntegrationAdapter = class {
|
|
47786
47851
|
accessToken;
|
|
47852
|
+
bifrostBaseUrl;
|
|
47787
47853
|
fetchImpl;
|
|
47854
|
+
gatewayBaseUrl;
|
|
47855
|
+
orgMode;
|
|
47788
47856
|
secretMasker;
|
|
47789
47857
|
teamId;
|
|
47790
|
-
workerBaseUrl;
|
|
47791
47858
|
constructor(options) {
|
|
47792
47859
|
this.accessToken = String(options.accessToken || "").trim();
|
|
47860
|
+
this.bifrostBaseUrl = String(
|
|
47861
|
+
options.bifrostBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.bifrostBaseUrl
|
|
47862
|
+
).replace(/\/+$/, "");
|
|
47793
47863
|
this.fetchImpl = options.fetchImpl ?? fetch;
|
|
47864
|
+
this.gatewayBaseUrl = String(
|
|
47865
|
+
options.gatewayBaseUrl || POSTMAN_ENDPOINT_PROFILES.prod.gatewayBaseUrl
|
|
47866
|
+
).replace(/\/+$/, "");
|
|
47867
|
+
this.orgMode = options.orgMode ?? false;
|
|
47794
47868
|
this.secretMasker = options.secretMasker ?? createSecretMasker([this.accessToken]);
|
|
47795
47869
|
this.teamId = String(options.teamId || "").trim();
|
|
47796
|
-
this.workerBaseUrl = String(
|
|
47797
|
-
options.workerBaseUrl || "https://catalog-admin.postman-account2009.workers.dev"
|
|
47798
|
-
).replace(/\/+$/, "");
|
|
47799
47870
|
}
|
|
47800
47871
|
async proxyRequest(service, method, requestPath2, body) {
|
|
47801
|
-
const url =
|
|
47872
|
+
const url = `${this.bifrostBaseUrl}/ws/proxy`;
|
|
47802
47873
|
const headers = {
|
|
47803
47874
|
"Content-Type": "application/json",
|
|
47804
47875
|
"x-access-token": this.accessToken
|
|
47805
47876
|
};
|
|
47806
|
-
if (this.teamId) {
|
|
47877
|
+
if (this.teamId && this.orgMode) {
|
|
47807
47878
|
headers["x-entity-team-id"] = this.teamId;
|
|
47808
47879
|
}
|
|
47809
47880
|
return this.fetchImpl(url, {
|
|
@@ -47828,14 +47899,12 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47828
47899
|
if (!groupName) {
|
|
47829
47900
|
return;
|
|
47830
47901
|
}
|
|
47831
|
-
const
|
|
47832
|
-
|
|
47833
|
-
{
|
|
47834
|
-
|
|
47835
|
-
"x-access-token": this.accessToken
|
|
47836
|
-
}
|
|
47902
|
+
const listUrl = `${this.gatewayBaseUrl}/configure/workspace-groups`;
|
|
47903
|
+
const listResponse = await this.fetchImpl(listUrl, {
|
|
47904
|
+
headers: {
|
|
47905
|
+
"x-access-token": this.accessToken
|
|
47837
47906
|
}
|
|
47838
|
-
);
|
|
47907
|
+
});
|
|
47839
47908
|
if (!listResponse.ok) {
|
|
47840
47909
|
throw await HttpError.fromResponse(listResponse, {
|
|
47841
47910
|
method: "GET",
|
|
@@ -47843,7 +47912,7 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47843
47912
|
"x-access-token": this.accessToken
|
|
47844
47913
|
},
|
|
47845
47914
|
secretValues: [this.accessToken],
|
|
47846
|
-
url:
|
|
47915
|
+
url: listUrl
|
|
47847
47916
|
});
|
|
47848
47917
|
}
|
|
47849
47918
|
const groups = await listResponse.json();
|
|
@@ -47851,19 +47920,17 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47851
47920
|
if (!group?.id) {
|
|
47852
47921
|
return;
|
|
47853
47922
|
}
|
|
47854
|
-
const
|
|
47855
|
-
|
|
47856
|
-
|
|
47857
|
-
|
|
47858
|
-
|
|
47859
|
-
|
|
47860
|
-
|
|
47861
|
-
|
|
47862
|
-
|
|
47863
|
-
|
|
47864
|
-
|
|
47865
|
-
}
|
|
47866
|
-
);
|
|
47923
|
+
const patchUrl = `${this.gatewayBaseUrl}/configure/workspace-groups/${group.id}`;
|
|
47924
|
+
const patchResponse = await this.fetchImpl(patchUrl, {
|
|
47925
|
+
method: "PATCH",
|
|
47926
|
+
headers: {
|
|
47927
|
+
"Content-Type": "application/json",
|
|
47928
|
+
"x-access-token": this.accessToken
|
|
47929
|
+
},
|
|
47930
|
+
body: JSON.stringify({
|
|
47931
|
+
workspaces: [workspaceId]
|
|
47932
|
+
})
|
|
47933
|
+
});
|
|
47867
47934
|
if (!patchResponse.ok) {
|
|
47868
47935
|
throw await HttpError.fromResponse(patchResponse, {
|
|
47869
47936
|
method: "PATCH",
|
|
@@ -47872,40 +47939,7 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47872
47939
|
"x-access-token": this.accessToken
|
|
47873
47940
|
},
|
|
47874
47941
|
secretValues: [this.accessToken],
|
|
47875
|
-
url:
|
|
47876
|
-
});
|
|
47877
|
-
}
|
|
47878
|
-
}
|
|
47879
|
-
async associateSystemEnvironments(workspaceId, associations) {
|
|
47880
|
-
if (associations.length === 0) {
|
|
47881
|
-
return;
|
|
47882
|
-
}
|
|
47883
|
-
const response = await this.fetchImpl(
|
|
47884
|
-
`${this.workerBaseUrl}/api/internal/system-envs/associate`,
|
|
47885
|
-
{
|
|
47886
|
-
method: "POST",
|
|
47887
|
-
headers: {
|
|
47888
|
-
Authorization: `Bearer ${this.accessToken}`,
|
|
47889
|
-
"Content-Type": "application/json"
|
|
47890
|
-
},
|
|
47891
|
-
body: JSON.stringify({
|
|
47892
|
-
workspace_id: workspaceId,
|
|
47893
|
-
associations: associations.map((entry) => ({
|
|
47894
|
-
env_uid: entry.envUid,
|
|
47895
|
-
system_env_id: entry.systemEnvId
|
|
47896
|
-
}))
|
|
47897
|
-
})
|
|
47898
|
-
}
|
|
47899
|
-
);
|
|
47900
|
-
if (!response.ok) {
|
|
47901
|
-
throw await HttpError.fromResponse(response, {
|
|
47902
|
-
method: "POST",
|
|
47903
|
-
requestHeaders: {
|
|
47904
|
-
Authorization: `Bearer ${this.accessToken}`,
|
|
47905
|
-
"Content-Type": "application/json"
|
|
47906
|
-
},
|
|
47907
|
-
secretValues: [this.accessToken],
|
|
47908
|
-
url: `${this.workerBaseUrl}/api/internal/system-envs/associate`
|
|
47942
|
+
url: patchUrl
|
|
47909
47943
|
});
|
|
47910
47944
|
}
|
|
47911
47945
|
}
|
|
@@ -47945,10 +47979,10 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47945
47979
|
requestHeaders: {
|
|
47946
47980
|
"Content-Type": "application/json",
|
|
47947
47981
|
"x-access-token": this.accessToken,
|
|
47948
|
-
...this.teamId ? { "x-entity-team-id": this.teamId } : {}
|
|
47982
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
47949
47983
|
},
|
|
47950
47984
|
secretValues: [this.accessToken],
|
|
47951
|
-
url:
|
|
47985
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
47952
47986
|
});
|
|
47953
47987
|
}
|
|
47954
47988
|
async linkCollectionsToSpecification(specificationId, collections) {
|
|
@@ -47972,10 +48006,10 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47972
48006
|
requestHeaders: {
|
|
47973
48007
|
"Content-Type": "application/json",
|
|
47974
48008
|
"x-access-token": this.accessToken,
|
|
47975
|
-
...this.teamId ? { "x-entity-team-id": this.teamId } : {}
|
|
48009
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
47976
48010
|
},
|
|
47977
48011
|
secretValues: [this.accessToken],
|
|
47978
|
-
url:
|
|
48012
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
47979
48013
|
});
|
|
47980
48014
|
}
|
|
47981
48015
|
async syncCollection(specificationId, collectionId) {
|
|
@@ -47992,10 +48026,10 @@ var BifrostInternalIntegrationAdapter = class {
|
|
|
47992
48026
|
requestHeaders: {
|
|
47993
48027
|
"Content-Type": "application/json",
|
|
47994
48028
|
"x-access-token": this.accessToken,
|
|
47995
|
-
...this.teamId ? { "x-entity-team-id": this.teamId } : {}
|
|
48029
|
+
...this.teamId && this.orgMode ? { "x-entity-team-id": this.teamId } : {}
|
|
47996
48030
|
},
|
|
47997
48031
|
secretValues: [this.accessToken],
|
|
47998
|
-
url:
|
|
48032
|
+
url: `${this.bifrostBaseUrl}/ws/proxy`
|
|
47999
48033
|
});
|
|
48000
48034
|
}
|
|
48001
48035
|
async getWorkspaceGitRepoUrl(workspaceId) {
|
|
@@ -48416,10 +48450,18 @@ async function resolveCanonicalWorkspaceSelection(args) {
|
|
|
48416
48450
|
args.warn?.(`Workspace duplicate check failed; falling back to repo workspace ${args.repoWorkspaceId}: ${error}`);
|
|
48417
48451
|
}
|
|
48418
48452
|
if (matchingWorkspaces.length > 0) {
|
|
48419
|
-
|
|
48453
|
+
const lookupResults = await Promise.allSettled(matchingWorkspaces.map(async (workspace) => ({
|
|
48420
48454
|
...workspace,
|
|
48421
48455
|
linkedRepoUrl: await args.postman.getWorkspaceGitRepoUrl(workspace.id, args.teamId, args.accessToken)
|
|
48422
48456
|
})));
|
|
48457
|
+
matchingWorkspaces = lookupResults.map((result, index) => {
|
|
48458
|
+
if (result.status === "fulfilled") {
|
|
48459
|
+
return result.value;
|
|
48460
|
+
}
|
|
48461
|
+
const workspace = matchingWorkspaces[index];
|
|
48462
|
+
args.warn?.(`Workspace Git repo lookup failed for ${workspace?.id ?? "unknown workspace"}; ignoring linked-repo metadata for that candidate: ${result.reason}`);
|
|
48463
|
+
return workspace ? { ...workspace, linkedRepoUrl: null } : void 0;
|
|
48464
|
+
}).filter((workspace) => Boolean(workspace));
|
|
48423
48465
|
}
|
|
48424
48466
|
return chooseCanonicalWorkspace({
|
|
48425
48467
|
repoWorkspaceId: args.repoWorkspaceId,
|
|
@@ -61748,6 +61790,8 @@ function resolveInputs(env = process.env) {
|
|
|
61748
61790
|
throw new Error(`spec-url must be a valid HTTPS URL, got: ${sanitizeUrlForLog(specUrl)}`, { cause: error });
|
|
61749
61791
|
}
|
|
61750
61792
|
}
|
|
61793
|
+
const postmanStack = parsePostmanStack(getInput("postman-stack", env));
|
|
61794
|
+
const endpointProfile = resolvePostmanEndpointProfile(postmanStack);
|
|
61751
61795
|
return {
|
|
61752
61796
|
projectName: getInput("project-name", env) ?? env.GITHUB_REPOSITORY?.split("/").pop() ?? env.CI_PROJECT_NAME ?? "",
|
|
61753
61797
|
workspaceId: getInput("workspace-id", env),
|
|
@@ -61775,6 +61819,11 @@ function resolveInputs(env = process.env) {
|
|
|
61775
61819
|
folderStrategy: parseEnumInput("folder-strategy", getInput("folder-strategy", env), "Paths"),
|
|
61776
61820
|
nestedFolderHierarchy: parseBooleanInput("nested-folder-hierarchy", getInput("nested-folder-hierarchy", env), false),
|
|
61777
61821
|
requestNameSource: parseEnumInput("request-name-source", getInput("request-name-source", env), "Fallback"),
|
|
61822
|
+
postmanStack,
|
|
61823
|
+
postmanApiBase: endpointProfile.apiBaseUrl,
|
|
61824
|
+
postmanBifrostBase: endpointProfile.bifrostBaseUrl,
|
|
61825
|
+
postmanGatewayBase: endpointProfile.gatewayBaseUrl,
|
|
61826
|
+
postmanCliInstallUrl: endpointProfile.cliInstallUrl,
|
|
61778
61827
|
githubRefName: env.GITHUB_REF_NAME,
|
|
61779
61828
|
githubHeadRef: env.GITHUB_HEAD_REF,
|
|
61780
61829
|
githubRef: env.GITHUB_REF,
|
|
@@ -61841,7 +61890,8 @@ function readActionInputs(actionCore) {
|
|
|
61841
61890
|
INPUT_FOLDER_STRATEGY: optionalInput(actionCore, "folder-strategy") ?? openAlphaActionContract.inputs["folder-strategy"].default,
|
|
61842
61891
|
INPUT_NESTED_FOLDER_HIERARCHY: optionalInput(actionCore, "nested-folder-hierarchy") ?? openAlphaActionContract.inputs["nested-folder-hierarchy"].default,
|
|
61843
61892
|
INPUT_REQUEST_NAME_SOURCE: optionalInput(actionCore, "request-name-source") ?? openAlphaActionContract.inputs["request-name-source"].default,
|
|
61844
|
-
INPUT_OPENAPI_VERSION: optionalInput(actionCore, "openapi-version") ?? ""
|
|
61893
|
+
INPUT_OPENAPI_VERSION: optionalInput(actionCore, "openapi-version") ?? "",
|
|
61894
|
+
INPUT_POSTMAN_STACK: optionalInput(actionCore, "postman-stack") ?? openAlphaActionContract.inputs["postman-stack"].default
|
|
61845
61895
|
});
|
|
61846
61896
|
return inputs;
|
|
61847
61897
|
}
|
|
@@ -61851,13 +61901,29 @@ function createWorkspaceName(inputs) {
|
|
|
61851
61901
|
async function runGroup(actionCore, name, fn) {
|
|
61852
61902
|
return actionCore.group(name, fn);
|
|
61853
61903
|
}
|
|
61854
|
-
|
|
61904
|
+
function validateHttpsInstallUrl(url) {
|
|
61905
|
+
const safeUrlPattern = /^https:\/\/[A-Za-z0-9.-]+\/[A-Za-z0-9._~/?=&%-]+$/;
|
|
61906
|
+
if (!safeUrlPattern.test(url)) {
|
|
61907
|
+
throw new Error(
|
|
61908
|
+
`postman-cli-install-url must be an https URL with safe characters; got: ${url}`
|
|
61909
|
+
);
|
|
61910
|
+
}
|
|
61911
|
+
return url;
|
|
61912
|
+
}
|
|
61913
|
+
async function ensurePostmanCli(dependencies, postmanApiKey, installUrl = "https://dl-cli.pstmn.io/install/unix.sh") {
|
|
61914
|
+
const validatedUrl = validateHttpsInstallUrl(installUrl);
|
|
61855
61915
|
const existing = await dependencies.io.which("postman", false).catch(() => "");
|
|
61856
61916
|
if (!existing) {
|
|
61857
|
-
await dependencies.exec.exec(
|
|
61858
|
-
"
|
|
61859
|
-
'curl -
|
|
61860
|
-
|
|
61917
|
+
await dependencies.exec.exec(
|
|
61918
|
+
"sh",
|
|
61919
|
+
["-c", 'curl -fsSL "$POSTMAN_CLI_INSTALL_URL" | sh'],
|
|
61920
|
+
{
|
|
61921
|
+
env: {
|
|
61922
|
+
...process.env,
|
|
61923
|
+
POSTMAN_CLI_INSTALL_URL: validatedUrl
|
|
61924
|
+
}
|
|
61925
|
+
}
|
|
61926
|
+
);
|
|
61861
61927
|
}
|
|
61862
61928
|
await dependencies.exec.exec("postman", ["login", "--with-api-key", postmanApiKey]);
|
|
61863
61929
|
}
|
|
@@ -62075,7 +62141,7 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
62075
62141
|
const workspaceName = createWorkspaceName(inputs);
|
|
62076
62142
|
const aboutText = `Auto-provisioned by Postman CS open-alpha for ${inputs.projectName}`;
|
|
62077
62143
|
await runGroup(dependencies.core, "Install Postman CLI", async () => {
|
|
62078
|
-
await ensurePostmanCli(dependencies, inputs.postmanApiKey);
|
|
62144
|
+
await ensurePostmanCli(dependencies, inputs.postmanApiKey, inputs.postmanCliInstallUrl);
|
|
62079
62145
|
});
|
|
62080
62146
|
const resourcesState = readResourcesState();
|
|
62081
62147
|
let specId = inputs.specId;
|
|
@@ -62191,13 +62257,17 @@ async function runBootstrap(inputs, dependencies) {
|
|
|
62191
62257
|
"GET /teams returned multiple teams but none include organizationId. Org-mode detection may be degraded due to an upstream API change. If workspace creation fails, set workspace-team-id explicitly."
|
|
62192
62258
|
);
|
|
62193
62259
|
}
|
|
62194
|
-
const
|
|
62195
|
-
const meTeamId = parseInt(teamId, 10);
|
|
62196
|
-
const isOrgMode = teams.length > 1 && orgIds.size === 1 && orgIds.has(meTeamId);
|
|
62260
|
+
const isOrgMode = teams.some((t) => t.organizationId != null);
|
|
62197
62261
|
if (isOrgMode) {
|
|
62198
|
-
|
|
62199
|
-
|
|
62200
|
-
|
|
62262
|
+
if (teams.length === 1) {
|
|
62263
|
+
workspaceTeamId = teams[0].id;
|
|
62264
|
+
dependencies.core.info(
|
|
62265
|
+
`Org-mode account detected. Using sub-team ${teams[0].id} (${teams[0].name}) for workspace creation.`
|
|
62266
|
+
);
|
|
62267
|
+
} else {
|
|
62268
|
+
const teamList = teams.map((t) => ` ${t.id} ${t.name}`).join("\n");
|
|
62269
|
+
throw new Error(
|
|
62270
|
+
`Org-mode account detected. Workspace creation requires a specific sub-team ID.
|
|
62201
62271
|
|
|
62202
62272
|
Available sub-teams:
|
|
62203
62273
|
${teamList}
|
|
@@ -62209,7 +62279,8 @@ Or for reuse across runs, create a repository variable and reference it:
|
|
|
62209
62279
|
workspace-team-id: \${{ vars.POSTMAN_WORKSPACE_TEAM_ID }}
|
|
62210
62280
|
|
|
62211
62281
|
For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID=<id>.`
|
|
62212
|
-
|
|
62282
|
+
);
|
|
62283
|
+
}
|
|
62213
62284
|
} else if (teams.length > 1) {
|
|
62214
62285
|
dependencies.core.warning(
|
|
62215
62286
|
`API key has access to ${teams.length} teams but org-mode could not be confirmed. Proceeding without teamId. If workspace creation fails, set workspace-team-id explicitly.`
|
|
@@ -62834,12 +62905,26 @@ For CLI usage, pass --workspace-team-id <id> or export POSTMAN_WORKSPACE_TEAM_ID
|
|
|
62834
62905
|
}
|
|
62835
62906
|
async function runAction(actionCore = core2, actionExec = exec, actionIo = io) {
|
|
62836
62907
|
const inputs = readActionInputs(actionCore);
|
|
62908
|
+
let orgMode = false;
|
|
62909
|
+
if (inputs.postmanAccessToken && inputs.teamId) {
|
|
62910
|
+
try {
|
|
62911
|
+
const tempPostman = new PostmanAssetsClient({
|
|
62912
|
+
apiKey: inputs.postmanApiKey,
|
|
62913
|
+
baseUrl: inputs.postmanApiBase,
|
|
62914
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
62915
|
+
secretMasker: createSecretMasker([inputs.postmanApiKey, inputs.postmanAccessToken])
|
|
62916
|
+
});
|
|
62917
|
+
const teams = await tempPostman.getTeams();
|
|
62918
|
+
orgMode = teams.some((t) => t.organizationId != null);
|
|
62919
|
+
} catch {
|
|
62920
|
+
}
|
|
62921
|
+
}
|
|
62837
62922
|
const dependencies = createBootstrapDependencies(inputs, {
|
|
62838
62923
|
core: actionCore,
|
|
62839
62924
|
exec: actionExec,
|
|
62840
62925
|
io: actionIo,
|
|
62841
62926
|
specFetcher: fetch
|
|
62842
|
-
});
|
|
62927
|
+
}, orgMode);
|
|
62843
62928
|
if (inputs.domain && !dependencies.internalIntegration) {
|
|
62844
62929
|
actionCore.warning(
|
|
62845
62930
|
"Skipping governance assignment because postman-access-token is not configured"
|
|
@@ -62847,18 +62932,23 @@ async function runAction(actionCore = core2, actionExec = exec, actionIo = io) {
|
|
|
62847
62932
|
}
|
|
62848
62933
|
return runBootstrap(inputs, dependencies);
|
|
62849
62934
|
}
|
|
62850
|
-
function createBootstrapDependencies(inputs, factories) {
|
|
62935
|
+
function createBootstrapDependencies(inputs, factories, orgMode = false) {
|
|
62851
62936
|
const secretMasker = createSecretMasker([
|
|
62852
62937
|
inputs.postmanApiKey,
|
|
62853
62938
|
inputs.postmanAccessToken
|
|
62854
62939
|
]);
|
|
62855
62940
|
const postman = new PostmanAssetsClient({
|
|
62856
62941
|
apiKey: inputs.postmanApiKey,
|
|
62942
|
+
baseUrl: inputs.postmanApiBase,
|
|
62943
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
62857
62944
|
secretMasker
|
|
62858
62945
|
});
|
|
62859
62946
|
const internalIntegration = inputs.postmanAccessToken ? createInternalIntegrationAdapter({
|
|
62860
62947
|
accessToken: inputs.postmanAccessToken,
|
|
62861
62948
|
backend: inputs.integrationBackend,
|
|
62949
|
+
bifrostBaseUrl: inputs.postmanBifrostBase,
|
|
62950
|
+
gatewayBaseUrl: inputs.postmanGatewayBase,
|
|
62951
|
+
orgMode,
|
|
62862
62952
|
secretMasker,
|
|
62863
62953
|
teamId: inputs.teamId || ""
|
|
62864
62954
|
}) : void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postman-cse/onboarding-bootstrap",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Public open-alpha Postman bootstrap GitHub Action.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"LICENSE"
|
|
15
15
|
],
|
|
16
16
|
"engines": {
|
|
17
|
-
"node": ">=
|
|
17
|
+
"node": ">=24"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "npm run typecheck && rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=
|
|
20
|
+
"build": "npm run typecheck && rm -rf dist && esbuild src/index.ts --bundle --platform=node --target=node24 --format=cjs --outfile=dist/index.cjs && esbuild src/cli.ts --bundle --platform=node --target=node24 --format=cjs --outfile=dist/cli.cjs",
|
|
21
21
|
"check:dist": "npm run build && git diff --exit-code -- dist",
|
|
22
22
|
"lint": "eslint .",
|
|
23
23
|
"lint:fix": "eslint . --fix",
|