@postman-cse/onboarding-repo-sync 2.1.19 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -134765,6 +134765,17 @@ var postmanRepoSyncActionContract = {
134765
134765
  description: "Existing mock server URL. When set, the action validates and reuses this mock instead of creating a new one.",
134766
134766
  required: false
134767
134767
  },
134768
+ "mock-visibility": {
134769
+ description: "Required mock access policy. Public is anonymous; private requires a runtime x-api-key supplied by the caller and is never persisted by repo-sync.",
134770
+ required: false,
134771
+ default: "public",
134772
+ allowedValues: ["public", "private"]
134773
+ },
134774
+ "mock-environment-enabled": {
134775
+ description: "Create or update a dedicated manual-validation environment whose baseUrl is the validated mock URL. This environment is excluded from runtime CI selection and never contains a mock credential.",
134776
+ required: false,
134777
+ default: "false"
134778
+ },
134768
134779
  "monitor-cron": {
134769
134780
  description: "Cron expression for monitor scheduling (e.g. '0 */6 * * *'). When empty, the monitor is created disabled and triggered to run once per workflow invocation (and once on every subsequent run).",
134770
134781
  required: false,
@@ -134958,6 +134969,18 @@ var postmanRepoSyncActionContract = {
134958
134969
  "mock-url": {
134959
134970
  description: "Created or reused mock server URL."
134960
134971
  },
134972
+ "mock-visibility": {
134973
+ description: "Authoritatively observed mock visibility: public or private."
134974
+ },
134975
+ "mock-auth-required": {
134976
+ description: "Whether the collection runner must supply postmanPrivateMockApiKey at runtime."
134977
+ },
134978
+ "mock-environment-uid": {
134979
+ description: "Dedicated manual-validation environment UID when mock-environment-enabled succeeds."
134980
+ },
134981
+ "mock-environment-status": {
134982
+ description: "Whether the optional manual-validation mock environment succeeded, was skipped, or failed."
134983
+ },
134961
134984
  "monitor-id": {
134962
134985
  description: "Created or reused smoke monitor ID."
134963
134986
  },
@@ -135052,19 +135075,30 @@ var MockContractError = class extends Error {
135052
135075
  this.name = "MockContractError";
135053
135076
  }
135054
135077
  };
135055
- function requirePublicMock(mock) {
135056
- if (mock.visibility === "private") {
135078
+ function requireMockVisibility(mock, requested) {
135079
+ if (mock.visibility === "unknown") {
135057
135080
  throw new MockContractError(
135058
- `MOCK_NOT_PUBLIC: Mock ${mock.uid} is private. Make it public in Postman or remove/rename it so repo-sync can create the canonical public mock.`
135081
+ `MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is callable.`
135059
135082
  );
135060
135083
  }
135061
- if (mock.visibility !== "public") {
135084
+ if (mock.visibility !== requested) {
135085
+ const code = requested === "public" ? "MOCK_NOT_PUBLIC" : "MOCK_NOT_PRIVATE";
135062
135086
  throw new MockContractError(
135063
- `MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is publicly callable.`
135087
+ `${code}: Mock ${mock.uid} is ${mock.visibility}, but mock-visibility requires ${requested}. Change the mock visibility in Postman or set mock-visibility to ${mock.visibility}.`
135064
135088
  );
135065
135089
  }
135066
135090
  return mock;
135067
135091
  }
135092
+ var PRIVATE_MOCK_AUTH_MARKER = "postman-enterprise-automation: private-mock-auth";
135093
+ var PRIVATE_MOCK_AUTH_VARIABLE = "postmanPrivateMockApiKey";
135094
+ var PRIVATE_MOCK_AUTH_SCRIPT = [
135095
+ `// ${PRIVATE_MOCK_AUTH_MARKER}`,
135096
+ `var privateMockApiKey = pm.variables.get('${PRIVATE_MOCK_AUTH_VARIABLE}');`,
135097
+ "var privateMockHost = String(pm.request.url && pm.request.url.getHost ? pm.request.url.getHost() : '');",
135098
+ "if (privateMockApiKey && /(^|\\.)mock\\.pstmn\\.io$/i.test(privateMockHost)) {",
135099
+ " pm.request.headers.upsert({ key: 'x-api-key', value: privateMockApiKey });",
135100
+ "}"
135101
+ ].join("\n");
135068
135102
  var MAX_CREATE_FLIGHTS = 256;
135069
135103
  var createFlights = /* @__PURE__ */ new Map();
135070
135104
  var PostmanGatewayAssetsClient = class {
@@ -135572,22 +135606,22 @@ var PostmanGatewayAssetsClient = class {
135572
135606
  return data?.collection ?? null;
135573
135607
  }
135574
135608
  // --- mocks (service: mock) ---
135575
- async createMock(workspaceId, name, collectionUid, environmentUid) {
135609
+ async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "public") {
135576
135610
  const ws = workspaceId || this.workspaceId;
135577
135611
  const mockName = String(name ?? "").trim();
135578
135612
  const collection = String(collectionUid ?? "").trim();
135579
135613
  const environment = String(environmentUid ?? "").trim();
135580
- const flightKey = `mock:${ws}:${collection}:${environment}:${mockName}`;
135614
+ const flightKey = `mock:${ws}:${collection}:${environment}:${requestedVisibility}:${mockName}`;
135581
135615
  return this.singleFlight(flightKey, flightKey, "mock", async () => {
135582
135616
  const existing = await this.findMockByCollection(collection, environment, mockName);
135583
135617
  if (existing) {
135584
- const reusable = requirePublicMock(existing);
135585
- return { uid: reusable.uid, url: reusable.mockUrl };
135618
+ const reusable = requireMockVisibility(existing, requestedVisibility);
135619
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
135586
135620
  }
135587
135621
  const body = {
135588
135622
  name: mockName,
135589
135623
  collection,
135590
- private: false,
135624
+ private: requestedVisibility === "private",
135591
135625
  ...environment ? { environment } : {}
135592
135626
  };
135593
135627
  const send2 = (fallback) => this.gateway.requestJson(
@@ -135605,12 +135639,14 @@ var PostmanGatewayAssetsClient = class {
135605
135639
  );
135606
135640
  const parseMock = (response) => {
135607
135641
  const record = this.dataOf(response);
135608
- const created = requirePublicMock(
135609
- this.decodeMockRecord(record, "Mock create")
135642
+ const created = requireMockVisibility(
135643
+ this.decodeMockRecord(record, "Mock create"),
135644
+ requestedVisibility
135610
135645
  );
135611
135646
  return {
135612
135647
  uid: created.uid,
135613
- url: created.mockUrl
135648
+ url: created.mockUrl,
135649
+ visibility: requestedVisibility
135614
135650
  };
135615
135651
  };
135616
135652
  try {
@@ -135621,8 +135657,8 @@ var PostmanGatewayAssetsClient = class {
135621
135657
  error
135622
135658
  );
135623
135659
  if (adopted) {
135624
- const reusable = requirePublicMock(adopted);
135625
- return { uid: reusable.uid, url: reusable.mockUrl };
135660
+ const reusable = requireMockVisibility(adopted, requestedVisibility);
135661
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
135626
135662
  }
135627
135663
  if (adopted === void 0) {
135628
135664
  const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
@@ -135632,6 +135668,51 @@ var PostmanGatewayAssetsClient = class {
135632
135668
  }
135633
135669
  });
135634
135670
  }
135671
+ /**
135672
+ * Add a secret-free runtime hook to every HTTP request in a collection. The
135673
+ * PMAK value is supplied only by the runner as a transient variable; this
135674
+ * method persists the variable name and header wiring, never the credential.
135675
+ */
135676
+ async configurePrivateMockRuntimeAuth(collectionUid) {
135677
+ const cid = String(collectionUid ?? "").trim();
135678
+ if (!cid) return 0;
135679
+ const listed = await this.gateway.requestJson({
135680
+ service: "collection",
135681
+ method: "get",
135682
+ path: `/v3/collections/${cid}/items/`
135683
+ });
135684
+ const items = Array.isArray(listed?.data) ? listed.data : [];
135685
+ let patched = 0;
135686
+ for (const listedItem of items) {
135687
+ if (String(listedItem.$kind ?? "") !== "http-request") continue;
135688
+ const itemId = String(listedItem.id ?? "").trim();
135689
+ if (!itemId) continue;
135690
+ const response = await this.gateway.requestJson({
135691
+ service: "collection",
135692
+ method: "get",
135693
+ path: `/v3/collections/${cid}/items/${itemId}`,
135694
+ headers: { "X-Entity-Type": "http-request" }
135695
+ });
135696
+ const item = this.asRecord(response?.data) ?? listedItem;
135697
+ const scripts = Array.isArray(item.scripts) ? item.scripts.filter((entry) => Boolean(this.asRecord(entry))) : [];
135698
+ const before = scripts.find((script) => String(script.type ?? "") === "beforeRequest");
135699
+ if (String(before?.code ?? "").includes(PRIVATE_MOCK_AUTH_MARKER)) continue;
135700
+ const code = [String(before?.code ?? "").trim(), PRIVATE_MOCK_AUTH_SCRIPT].filter(Boolean).join("\n");
135701
+ const nextScripts = [
135702
+ ...scripts.filter((script) => String(script.type ?? "") !== "beforeRequest"),
135703
+ { type: "beforeRequest", code, language: "text/javascript" }
135704
+ ];
135705
+ await this.gateway.requestJson({
135706
+ service: "collection",
135707
+ method: "patch",
135708
+ path: `/v3/collections/${cid}/items/${itemId}`,
135709
+ headers: { "X-Entity-Type": "http-request" },
135710
+ body: [{ op: "add", path: "/scripts", value: nextScripts }]
135711
+ });
135712
+ patched += 1;
135713
+ }
135714
+ return patched;
135715
+ }
135635
135716
  async listMocks() {
135636
135717
  const response = await this.gateway.requestJson({
135637
135718
  service: "mock",
@@ -136594,7 +136675,7 @@ function normalizeMockUrl(value, source) {
136594
136675
  url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
136595
136676
  return url.toString();
136596
136677
  }
136597
- function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
136678
+ function resolveExplicitMock(mocks, explicitUrl, collectionUid, environmentUid, requestedVisibility) {
136598
136679
  const normalized = normalizeMockUrl(explicitUrl, "mock-url");
136599
136680
  const matches = mocks.filter(
136600
136681
  (mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
@@ -136620,7 +136701,7 @@ function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmen
136620
136701
  `EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
136621
136702
  );
136622
136703
  }
136623
- return requirePublicMock(match);
136704
+ return requireMockVisibility(match, requestedVisibility);
136624
136705
  }
136625
136706
  function shouldRetryMockCreate(error) {
136626
136707
  if (error instanceof MockContractError) return false;
@@ -136729,6 +136810,15 @@ function parseCredentialPreflight(value) {
136729
136810
  `Unsupported credential-preflight "${normalized}". Supported values: ${allowed.join(", ")}`
136730
136811
  );
136731
136812
  }
136813
+ function parseMockVisibility(value) {
136814
+ const definition = postmanRepoSyncActionContract.inputs["mock-visibility"];
136815
+ const allowed = definition.allowedValues ?? [];
136816
+ const normalized = String(value || "").trim() || (definition.default ?? "public");
136817
+ if (allowed.includes(normalized)) return normalized;
136818
+ throw new Error(
136819
+ `Unsupported mock-visibility "${normalized}". Supported values: ${allowed.join(", ")}`
136820
+ );
136821
+ }
136732
136822
  function parseBranchStrategy(value) {
136733
136823
  const definition = postmanRepoSyncActionContract.inputs["branch-strategy"];
136734
136824
  const allowed = definition.allowedValues ?? [];
@@ -136835,6 +136925,8 @@ function resolveInputs(env = process.env) {
136835
136925
  orgMode: parseBooleanInput(getInput("org-mode", env), false),
136836
136926
  monitorId: getInput("monitor-id", env),
136837
136927
  mockUrl: getInput("mock-url", env),
136928
+ mockVisibility: parseMockVisibility(getInput("mock-visibility", env)),
136929
+ mockEnvironmentEnabled: parseBooleanInput(getInput("mock-environment-enabled", env), false),
136838
136930
  monitorCron: getInput("monitor-cron", env),
136839
136931
  sslClientCert: getInput("ssl-client-cert", env),
136840
136932
  sslClientKey: getInput("ssl-client-key", env),
@@ -137061,6 +137153,10 @@ function createOutputs(inputs) {
137061
137153
  "environment-sync-status": "skipped",
137062
137154
  "environment-uids-json": JSON.stringify(inputs.environmentUids),
137063
137155
  "mock-url": "",
137156
+ "mock-visibility": "",
137157
+ "mock-auth-required": "false",
137158
+ "mock-environment-uid": "",
137159
+ "mock-environment-status": "skipped",
137064
137160
  "monitor-id": "",
137065
137161
  "repo-sync-summary-json": "{}",
137066
137162
  "commit-sha": "",
@@ -137189,6 +137285,52 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
137189
137285
  }
137190
137286
  return envUids;
137191
137287
  }
137288
+ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, mockUrl) {
137289
+ if (!inputs.mockEnvironmentEnabled || !inputs.workspaceId || !mockUrl) {
137290
+ return "";
137291
+ }
137292
+ const displayName = `${assetProjectName} - Mock`;
137293
+ const values = buildEnvironmentValues("mock", mockUrl);
137294
+ const mask = resolveRepoSyncMasker(dependencies);
137295
+ try {
137296
+ const discovered = await dependencies.postman.findEnvironmentByName(
137297
+ inputs.workspaceId,
137298
+ displayName
137299
+ );
137300
+ if (discovered?.uid) {
137301
+ try {
137302
+ const existing = await dependencies.postman.getEnvironment(discovered.uid);
137303
+ const currentValues = existing.data?.values ?? existing.values ?? [];
137304
+ if (currentValues.some((value) => value.key === "baseUrl" && value.value === mockUrl)) {
137305
+ dependencies.core.info(`Mock environment already points to ${mockUrl}: ${discovered.uid}`);
137306
+ return discovered.uid;
137307
+ }
137308
+ } catch {
137309
+ }
137310
+ await dependencies.postman.updateEnvironment(discovered.uid, displayName, values);
137311
+ dependencies.core.info(`Updated mock environment ${displayName}: ${discovered.uid}`);
137312
+ return discovered.uid;
137313
+ }
137314
+ const uid = await dependencies.postman.createEnvironment(
137315
+ inputs.workspaceId,
137316
+ displayName,
137317
+ values
137318
+ );
137319
+ dependencies.core.info(`Created mock environment ${displayName}: ${uid}`);
137320
+ return uid;
137321
+ } catch (error) {
137322
+ dependencies.core.warning(
137323
+ formatOrchestrationIssue({
137324
+ operation: "Mock environment upsert",
137325
+ entity: `workspace ${inputs.workspaceId} environment "${displayName}"`,
137326
+ cause: error,
137327
+ remediation: "verify environment access or disable mock-environment-enabled then rerun",
137328
+ mask
137329
+ })
137330
+ );
137331
+ return "";
137332
+ }
137333
+ }
137192
137334
  function ensureDir(path5) {
137193
137335
  (0, import_node_fs5.mkdirSync)(path5, { recursive: true });
137194
137336
  }
@@ -137827,6 +137969,13 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
137827
137969
  true
137828
137970
  );
137829
137971
  }
137972
+ if (options.mockEnvironmentUid) {
137973
+ writeJsonFile(
137974
+ `${mocksDir}/manual-validation.postman_environment.json`,
137975
+ await dependencies.postman.getEnvironment(options.mockEnvironmentUid),
137976
+ true
137977
+ );
137978
+ }
137830
137979
  const durableWorkspaceId = resolveDurableWorkspaceId({
137831
137980
  candidateId: inputs.workspaceId,
137832
137981
  priorId: options.priorWorkspaceId,
@@ -137885,7 +138034,11 @@ function createRepoSummary(outputs, envUids, pushed) {
137885
138034
  commitSha: outputs["commit-sha"],
137886
138035
  environmentCount: Object.keys(envUids).length,
137887
138036
  environmentSyncStatus: outputs["environment-sync-status"],
138037
+ mockEnvironmentStatus: outputs["mock-environment-status"],
138038
+ mockEnvironmentUid: outputs["mock-environment-uid"],
138039
+ mockAuthRequired: outputs["mock-auth-required"] === "true",
137888
138040
  mockUrl: outputs["mock-url"],
138041
+ mockVisibility: outputs["mock-visibility"],
137889
138042
  monitorId: outputs["monitor-id"],
137890
138043
  pushed,
137891
138044
  resolvedCurrentRef: outputs["resolved-current-ref"],
@@ -138113,6 +138266,7 @@ async function runRepoSyncInner(inputs, dependencies) {
138113
138266
  const mockEnvUid = envUids.dev || envUids.prod || Object.values(envUids)[0];
138114
138267
  if (mockEnvUid) {
138115
138268
  let resolvedMockUrl = "";
138269
+ let resolvedMockVisibility = "";
138116
138270
  const mockName = `${assetProjectName} Mock`;
138117
138271
  if (inputs.mockUrl) {
138118
138272
  let mocks;
@@ -138130,12 +138284,15 @@ async function runRepoSyncInner(inputs, dependencies) {
138130
138284
  { cause: error }
138131
138285
  );
138132
138286
  }
138133
- resolvedMockUrl = resolveExplicitPublicMock(
138287
+ const resolved = resolveExplicitMock(
138134
138288
  mocks,
138135
138289
  inputs.mockUrl,
138136
138290
  inputs.baselineCollectionId,
138137
- mockEnvUid
138138
- ).mockUrl;
138291
+ mockEnvUid,
138292
+ inputs.mockVisibility
138293
+ );
138294
+ resolvedMockUrl = resolved.mockUrl;
138295
+ resolvedMockVisibility = resolved.visibility;
138139
138296
  dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
138140
138297
  }
138141
138298
  if (!resolvedMockUrl && inputs.baselineCollectionId) {
@@ -138159,7 +138316,9 @@ async function runRepoSyncInner(inputs, dependencies) {
138159
138316
  );
138160
138317
  }
138161
138318
  if (discovered) {
138162
- resolvedMockUrl = requirePublicMock(discovered).mockUrl;
138319
+ const resolved = requireMockVisibility(discovered, inputs.mockVisibility);
138320
+ resolvedMockUrl = resolved.mockUrl;
138321
+ resolvedMockVisibility = resolved.visibility;
138163
138322
  dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
138164
138323
  }
138165
138324
  }
@@ -138172,7 +138331,8 @@ async function runRepoSyncInner(inputs, dependencies) {
138172
138331
  inputs.workspaceId,
138173
138332
  mockName,
138174
138333
  inputs.baselineCollectionId,
138175
- mockEnvUid
138334
+ mockEnvUid,
138335
+ inputs.mockVisibility
138176
138336
  ),
138177
138337
  {
138178
138338
  maxAttempts: 3,
@@ -138194,6 +138354,7 @@ async function runRepoSyncInner(inputs, dependencies) {
138194
138354
  }
138195
138355
  );
138196
138356
  resolvedMockUrl = mock.url;
138357
+ resolvedMockVisibility = mock.visibility ?? inputs.mockVisibility;
138197
138358
  dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
138198
138359
  } catch (error) {
138199
138360
  throw new Error(
@@ -138209,7 +138370,37 @@ async function runRepoSyncInner(inputs, dependencies) {
138209
138370
  }
138210
138371
  }
138211
138372
  outputs["mock-url"] = resolvedMockUrl;
138373
+ outputs["mock-visibility"] = resolvedMockVisibility;
138374
+ outputs["mock-auth-required"] = String(resolvedMockVisibility === "private");
138212
138375
  dependencies.core.setOutput("mock-url", resolvedMockUrl);
138376
+ dependencies.core.setOutput("mock-visibility", resolvedMockVisibility);
138377
+ dependencies.core.setOutput("mock-auth-required", outputs["mock-auth-required"]);
138378
+ if (resolvedMockVisibility === "private") {
138379
+ if (!dependencies.postman.configurePrivateMockRuntimeAuth) {
138380
+ throw new Error(
138381
+ "PRIVATE_MOCK_RUNTIME_AUTH_UNAVAILABLE: The Postman client cannot configure runtime x-api-key injection."
138382
+ );
138383
+ }
138384
+ for (const collectionUid of [inputs.smokeCollectionId, inputs.contractCollectionId]) {
138385
+ if (collectionUid) {
138386
+ await dependencies.postman.configurePrivateMockRuntimeAuth(collectionUid);
138387
+ }
138388
+ }
138389
+ }
138390
+ if (inputs.mockEnvironmentEnabled && isCanonicalWriter) {
138391
+ const mockEnvironmentUid = await upsertMockEnvironment(
138392
+ inputs,
138393
+ dependencies,
138394
+ assetProjectName,
138395
+ resolvedMockUrl
138396
+ );
138397
+ outputs["mock-environment-uid"] = mockEnvironmentUid;
138398
+ outputs["mock-environment-status"] = mockEnvironmentUid ? "success" : "failed";
138399
+ } else if (inputs.mockEnvironmentEnabled) {
138400
+ dependencies.core.warning(
138401
+ "mock-environment-enabled is skipped for preview and channel runs so manual-validation environments cannot escape branch retention cleanup."
138402
+ );
138403
+ }
138213
138404
  }
138214
138405
  }
138215
138406
  if (inputs.workspaceId && inputs.smokeCollectionId && Object.keys(envUids).length > 0) {
@@ -138342,6 +138533,7 @@ async function runRepoSyncInner(inputs, dependencies) {
138342
138533
  workspaceLinkStatus: outputs["workspace-link-status"],
138343
138534
  priorWorkspaceId: resourcesState?.workspace?.id,
138344
138535
  existingSpecs: resourcesState?.cloudResources?.specs,
138536
+ mockEnvironmentUid: outputs["mock-environment-uid"] || void 0,
138345
138537
  releaseLabel,
138346
138538
  priorState: resourcesState,
138347
138539
  preparedPrebuiltCollections
@@ -139162,6 +139354,8 @@ var CLI_INPUT_NAMES = [
139162
139354
  "org-mode",
139163
139355
  "monitor-id",
139164
139356
  "mock-url",
139357
+ "mock-visibility",
139358
+ "mock-environment-enabled",
139165
139359
  "monitor-cron",
139166
139360
  "ssl-client-cert",
139167
139361
  "ssl-client-key",