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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -113,9 +113,9 @@ with:
113
113
  monitor-id: 1e2f3a4b-monitor-id
114
114
  ```
115
115
 
116
- Repo-sync supports public mocks for anonymous validation. An explicit `mock-url` must match one mock in the resolved workspace and reference the expected baseline collection and environment. Discovered and newly created mocks pass the same live visibility check. Private mocks, responses without a recognized visibility field, stale URLs, and identity mismatches fail before `mock-url` is emitted; repo-sync never places a Postman API key in a collection or environment to make a private mock callable.
116
+ Repo-sync defaults to public mocks for anonymous validation. Set `mock-visibility: private` for teams that prohibit public mocks. Explicit, discovered, and newly created mocks must match the requested visibility and the expected baseline collection/environment; unknown visibility, stale URLs, and identity mismatches fail before `mock-url` is emitted. For private mocks, repo-sync emits `mock-auth-required: true` and installs a secret-free request hook in the smoke and contract collections. The runner must supply its PMAK as the transient `postmanPrivateMockApiKey` variable. Repo-sync never writes that credential to a collection, environment, output, or repository artifact.
117
117
 
118
- For manual collection validation against that public mock, opt in to a dedicated Postman environment:
118
+ For manual collection validation against the resolved mock, opt in to a dedicated Postman environment:
119
119
 
120
120
  ```yaml
121
121
  with:
@@ -155,7 +155,8 @@ with:
155
155
  | `release-label` | Optional release label used for versioned naming. | no | |
156
156
  | `monitor-id` | Existing smoke monitor ID. When set, the action validates and reuses this monitor instead of creating a new one. | no | |
157
157
  | `mock-url` | Existing mock server URL. When set, the action validates and reuses this mock instead of creating a new one. | no | |
158
- | `mock-environment-enabled` | Create or update a dedicated manual-validation environment whose baseUrl is the validated public mock URL. This environment is excluded from runtime CI selection. | no | `false` |
158
+ | `mock-visibility` | 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. | no | `public` |
159
+ | `mock-environment-enabled` | 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. | no | `false` |
159
160
  | `monitor-cron` | 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). | no | `""` |
160
161
  | `environments-json` | JSON array of environment slugs to create or update. | no | `["prod"]` |
161
162
  | `git-provider` | Git provider override ('github', 'gitlab', 'bitbucket', 'azure-devops'). Auto-detected from environment when omitted. | no | |
@@ -203,6 +204,8 @@ with:
203
204
  | `environment-sync-status` | Whether environment sync succeeded, was skipped, or failed. |
204
205
  | `environment-uids-json` | JSON map of environment slug to Postman environment uid. |
205
206
  | `mock-url` | Created or reused mock server URL. |
207
+ | `mock-visibility` | Authoritatively observed mock visibility: public or private. |
208
+ | `mock-auth-required` | Whether the collection runner must supply postmanPrivateMockApiKey at runtime. |
206
209
  | `mock-environment-uid` | Dedicated manual-validation environment UID when mock-environment-enabled succeeds. |
207
210
  | `mock-environment-status` | Whether the optional manual-validation mock environment succeeded, was skipped, or failed. |
208
211
  | `monitor-id` | Created or reused smoke monitor ID. |
package/action.yml CHANGED
@@ -57,8 +57,12 @@ inputs:
57
57
  mock-url:
58
58
  description: Existing mock server URL. When set, the action validates and reuses this mock instead of creating a new one.
59
59
  required: false
60
+ mock-visibility:
61
+ 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.
62
+ required: false
63
+ default: public
60
64
  mock-environment-enabled:
61
- description: Create or update a dedicated manual-validation environment whose baseUrl is the validated public mock URL. This environment is excluded from runtime CI selection.
65
+ 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.
62
66
  required: false
63
67
  default: "false"
64
68
  monitor-cron:
@@ -204,6 +208,10 @@ outputs:
204
208
  description: JSON map of environment slug to Postman environment uid.
205
209
  mock-url:
206
210
  description: Created or reused mock server URL.
211
+ mock-visibility:
212
+ description: "Authoritatively observed mock visibility: public or private."
213
+ mock-auth-required:
214
+ description: Whether the collection runner must supply postmanPrivateMockApiKey at runtime.
207
215
  mock-environment-uid:
208
216
  description: Dedicated manual-validation environment UID when mock-environment-enabled succeeds.
209
217
  mock-environment-status:
package/dist/action.cjs CHANGED
@@ -136660,8 +136660,14 @@ var postmanRepoSyncActionContract = {
136660
136660
  description: "Existing mock server URL. When set, the action validates and reuses this mock instead of creating a new one.",
136661
136661
  required: false
136662
136662
  },
136663
+ "mock-visibility": {
136664
+ 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.",
136665
+ required: false,
136666
+ default: "public",
136667
+ allowedValues: ["public", "private"]
136668
+ },
136663
136669
  "mock-environment-enabled": {
136664
- description: "Create or update a dedicated manual-validation environment whose baseUrl is the validated public mock URL. This environment is excluded from runtime CI selection.",
136670
+ 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.",
136665
136671
  required: false,
136666
136672
  default: "false"
136667
136673
  },
@@ -136858,6 +136864,12 @@ var postmanRepoSyncActionContract = {
136858
136864
  "mock-url": {
136859
136865
  description: "Created or reused mock server URL."
136860
136866
  },
136867
+ "mock-visibility": {
136868
+ description: "Authoritatively observed mock visibility: public or private."
136869
+ },
136870
+ "mock-auth-required": {
136871
+ description: "Whether the collection runner must supply postmanPrivateMockApiKey at runtime."
136872
+ },
136861
136873
  "mock-environment-uid": {
136862
136874
  description: "Dedicated manual-validation environment UID when mock-environment-enabled succeeds."
136863
136875
  },
@@ -136958,19 +136970,30 @@ var MockContractError = class extends Error {
136958
136970
  this.name = "MockContractError";
136959
136971
  }
136960
136972
  };
136961
- function requirePublicMock(mock) {
136962
- if (mock.visibility === "private") {
136973
+ function requireMockVisibility(mock, requested) {
136974
+ if (mock.visibility === "unknown") {
136963
136975
  throw new MockContractError(
136964
- `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.`
136976
+ `MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is callable.`
136965
136977
  );
136966
136978
  }
136967
- if (mock.visibility !== "public") {
136979
+ if (mock.visibility !== requested) {
136980
+ const code = requested === "public" ? "MOCK_NOT_PUBLIC" : "MOCK_NOT_PRIVATE";
136968
136981
  throw new MockContractError(
136969
- `MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is publicly callable.`
136982
+ `${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}.`
136970
136983
  );
136971
136984
  }
136972
136985
  return mock;
136973
136986
  }
136987
+ var PRIVATE_MOCK_AUTH_MARKER = "postman-enterprise-automation: private-mock-auth";
136988
+ var PRIVATE_MOCK_AUTH_VARIABLE = "postmanPrivateMockApiKey";
136989
+ var PRIVATE_MOCK_AUTH_SCRIPT = [
136990
+ `// ${PRIVATE_MOCK_AUTH_MARKER}`,
136991
+ `var privateMockApiKey = pm.variables.get('${PRIVATE_MOCK_AUTH_VARIABLE}');`,
136992
+ "var privateMockHost = String(pm.request.url && pm.request.url.getHost ? pm.request.url.getHost() : '');",
136993
+ "if (privateMockApiKey && /(^|\\.)mock\\.pstmn\\.io$/i.test(privateMockHost)) {",
136994
+ " pm.request.headers.upsert({ key: 'x-api-key', value: privateMockApiKey });",
136995
+ "}"
136996
+ ].join("\n");
136974
136997
  var MAX_CREATE_FLIGHTS = 256;
136975
136998
  var createFlights = /* @__PURE__ */ new Map();
136976
136999
  var PostmanGatewayAssetsClient = class {
@@ -137478,22 +137501,22 @@ var PostmanGatewayAssetsClient = class {
137478
137501
  return data?.collection ?? null;
137479
137502
  }
137480
137503
  // --- mocks (service: mock) ---
137481
- async createMock(workspaceId, name, collectionUid, environmentUid) {
137504
+ async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "public") {
137482
137505
  const ws = workspaceId || this.workspaceId;
137483
137506
  const mockName = String(name ?? "").trim();
137484
137507
  const collection = String(collectionUid ?? "").trim();
137485
137508
  const environment = String(environmentUid ?? "").trim();
137486
- const flightKey = `mock:${ws}:${collection}:${environment}:${mockName}`;
137509
+ const flightKey = `mock:${ws}:${collection}:${environment}:${requestedVisibility}:${mockName}`;
137487
137510
  return this.singleFlight(flightKey, flightKey, "mock", async () => {
137488
137511
  const existing = await this.findMockByCollection(collection, environment, mockName);
137489
137512
  if (existing) {
137490
- const reusable = requirePublicMock(existing);
137491
- return { uid: reusable.uid, url: reusable.mockUrl };
137513
+ const reusable = requireMockVisibility(existing, requestedVisibility);
137514
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
137492
137515
  }
137493
137516
  const body = {
137494
137517
  name: mockName,
137495
137518
  collection,
137496
- private: false,
137519
+ private: requestedVisibility === "private",
137497
137520
  ...environment ? { environment } : {}
137498
137521
  };
137499
137522
  const send2 = (fallback) => this.gateway.requestJson(
@@ -137511,12 +137534,14 @@ var PostmanGatewayAssetsClient = class {
137511
137534
  );
137512
137535
  const parseMock = (response) => {
137513
137536
  const record = this.dataOf(response);
137514
- const created = requirePublicMock(
137515
- this.decodeMockRecord(record, "Mock create")
137537
+ const created = requireMockVisibility(
137538
+ this.decodeMockRecord(record, "Mock create"),
137539
+ requestedVisibility
137516
137540
  );
137517
137541
  return {
137518
137542
  uid: created.uid,
137519
- url: created.mockUrl
137543
+ url: created.mockUrl,
137544
+ visibility: requestedVisibility
137520
137545
  };
137521
137546
  };
137522
137547
  try {
@@ -137527,8 +137552,8 @@ var PostmanGatewayAssetsClient = class {
137527
137552
  error2
137528
137553
  );
137529
137554
  if (adopted) {
137530
- const reusable = requirePublicMock(adopted);
137531
- return { uid: reusable.uid, url: reusable.mockUrl };
137555
+ const reusable = requireMockVisibility(adopted, requestedVisibility);
137556
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
137532
137557
  }
137533
137558
  if (adopted === void 0) {
137534
137559
  const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
@@ -137538,6 +137563,51 @@ var PostmanGatewayAssetsClient = class {
137538
137563
  }
137539
137564
  });
137540
137565
  }
137566
+ /**
137567
+ * Add a secret-free runtime hook to every HTTP request in a collection. The
137568
+ * PMAK value is supplied only by the runner as a transient variable; this
137569
+ * method persists the variable name and header wiring, never the credential.
137570
+ */
137571
+ async configurePrivateMockRuntimeAuth(collectionUid) {
137572
+ const cid = String(collectionUid ?? "").trim();
137573
+ if (!cid) return 0;
137574
+ const listed = await this.gateway.requestJson({
137575
+ service: "collection",
137576
+ method: "get",
137577
+ path: `/v3/collections/${cid}/items/`
137578
+ });
137579
+ const items = Array.isArray(listed?.data) ? listed.data : [];
137580
+ let patched = 0;
137581
+ for (const listedItem of items) {
137582
+ if (String(listedItem.$kind ?? "") !== "http-request") continue;
137583
+ const itemId = String(listedItem.id ?? "").trim();
137584
+ if (!itemId) continue;
137585
+ const response = await this.gateway.requestJson({
137586
+ service: "collection",
137587
+ method: "get",
137588
+ path: `/v3/collections/${cid}/items/${itemId}`,
137589
+ headers: { "X-Entity-Type": "http-request" }
137590
+ });
137591
+ const item = this.asRecord(response?.data) ?? listedItem;
137592
+ const scripts = Array.isArray(item.scripts) ? item.scripts.filter((entry) => Boolean(this.asRecord(entry))) : [];
137593
+ const before = scripts.find((script) => String(script.type ?? "") === "beforeRequest");
137594
+ if (String(before?.code ?? "").includes(PRIVATE_MOCK_AUTH_MARKER)) continue;
137595
+ const code = [String(before?.code ?? "").trim(), PRIVATE_MOCK_AUTH_SCRIPT].filter(Boolean).join("\n");
137596
+ const nextScripts = [
137597
+ ...scripts.filter((script) => String(script.type ?? "") !== "beforeRequest"),
137598
+ { type: "beforeRequest", code, language: "text/javascript" }
137599
+ ];
137600
+ await this.gateway.requestJson({
137601
+ service: "collection",
137602
+ method: "patch",
137603
+ path: `/v3/collections/${cid}/items/${itemId}`,
137604
+ headers: { "X-Entity-Type": "http-request" },
137605
+ body: [{ op: "add", path: "/scripts", value: nextScripts }]
137606
+ });
137607
+ patched += 1;
137608
+ }
137609
+ return patched;
137610
+ }
137541
137611
  async listMocks() {
137542
137612
  const response = await this.gateway.requestJson({
137543
137613
  service: "mock",
@@ -138552,7 +138622,7 @@ function normalizeMockUrl(value, source) {
138552
138622
  url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
138553
138623
  return url.toString();
138554
138624
  }
138555
- function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
138625
+ function resolveExplicitMock(mocks, explicitUrl, collectionUid, environmentUid, requestedVisibility) {
138556
138626
  const normalized = normalizeMockUrl(explicitUrl, "mock-url");
138557
138627
  const matches = mocks.filter(
138558
138628
  (mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
@@ -138578,7 +138648,7 @@ function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmen
138578
138648
  `EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
138579
138649
  );
138580
138650
  }
138581
- return requirePublicMock(match);
138651
+ return requireMockVisibility(match, requestedVisibility);
138582
138652
  }
138583
138653
  function shouldRetryMockCreate(error2) {
138584
138654
  if (error2 instanceof MockContractError) return false;
@@ -138690,6 +138760,15 @@ function parseCredentialPreflight(value) {
138690
138760
  `Unsupported credential-preflight "${normalized}". Supported values: ${allowed.join(", ")}`
138691
138761
  );
138692
138762
  }
138763
+ function parseMockVisibility(value) {
138764
+ const definition = postmanRepoSyncActionContract.inputs["mock-visibility"];
138765
+ const allowed = definition.allowedValues ?? [];
138766
+ const normalized = String(value || "").trim() || (definition.default ?? "public");
138767
+ if (allowed.includes(normalized)) return normalized;
138768
+ throw new Error(
138769
+ `Unsupported mock-visibility "${normalized}". Supported values: ${allowed.join(", ")}`
138770
+ );
138771
+ }
138693
138772
  function parseBranchStrategy(value) {
138694
138773
  const definition = postmanRepoSyncActionContract.inputs["branch-strategy"];
138695
138774
  const allowed = definition.allowedValues ?? [];
@@ -138796,6 +138875,7 @@ function resolveInputs(env = process.env) {
138796
138875
  orgMode: parseBooleanInput(getInput2("org-mode", env), false),
138797
138876
  monitorId: getInput2("monitor-id", env),
138798
138877
  mockUrl: getInput2("mock-url", env),
138878
+ mockVisibility: parseMockVisibility(getInput2("mock-visibility", env)),
138799
138879
  mockEnvironmentEnabled: parseBooleanInput(getInput2("mock-environment-enabled", env), false),
138800
138880
  monitorCron: getInput2("monitor-cron", env),
138801
138881
  sslClientCert: getInput2("ssl-client-cert", env),
@@ -139023,6 +139103,8 @@ function createOutputs(inputs) {
139023
139103
  "environment-sync-status": "skipped",
139024
139104
  "environment-uids-json": JSON.stringify(inputs.environmentUids),
139025
139105
  "mock-url": "",
139106
+ "mock-visibility": "",
139107
+ "mock-auth-required": "false",
139026
139108
  "mock-environment-uid": "",
139027
139109
  "mock-environment-status": "skipped",
139028
139110
  "monitor-id": "",
@@ -139092,6 +139174,7 @@ function readActionInputs(actionCore) {
139092
139174
  INPUT_ORG_MODE: readInput(actionCore, "org-mode"),
139093
139175
  INPUT_MONITOR_ID: readInput(actionCore, "monitor-id"),
139094
139176
  INPUT_MOCK_URL: readInput(actionCore, "mock-url"),
139177
+ INPUT_MOCK_VISIBILITY: readInput(actionCore, "mock-visibility"),
139095
139178
  INPUT_MOCK_ENVIRONMENT_ENABLED: readInput(actionCore, "mock-environment-enabled"),
139096
139179
  INPUT_MONITOR_CRON: readInput(actionCore, "monitor-cron"),
139097
139180
  INPUT_SSL_CLIENT_CERT: sslClientCert,
@@ -140045,7 +140128,9 @@ function createRepoSummary(outputs, envUids, pushed) {
140045
140128
  environmentSyncStatus: outputs["environment-sync-status"],
140046
140129
  mockEnvironmentStatus: outputs["mock-environment-status"],
140047
140130
  mockEnvironmentUid: outputs["mock-environment-uid"],
140131
+ mockAuthRequired: outputs["mock-auth-required"] === "true",
140048
140132
  mockUrl: outputs["mock-url"],
140133
+ mockVisibility: outputs["mock-visibility"],
140049
140134
  monitorId: outputs["monitor-id"],
140050
140135
  pushed,
140051
140136
  resolvedCurrentRef: outputs["resolved-current-ref"],
@@ -140273,6 +140358,7 @@ async function runRepoSyncInner(inputs, dependencies) {
140273
140358
  const mockEnvUid = envUids.dev || envUids.prod || Object.values(envUids)[0];
140274
140359
  if (mockEnvUid) {
140275
140360
  let resolvedMockUrl = "";
140361
+ let resolvedMockVisibility = "";
140276
140362
  const mockName = `${assetProjectName} Mock`;
140277
140363
  if (inputs.mockUrl) {
140278
140364
  let mocks;
@@ -140290,12 +140376,15 @@ async function runRepoSyncInner(inputs, dependencies) {
140290
140376
  { cause: error2 }
140291
140377
  );
140292
140378
  }
140293
- resolvedMockUrl = resolveExplicitPublicMock(
140379
+ const resolved = resolveExplicitMock(
140294
140380
  mocks,
140295
140381
  inputs.mockUrl,
140296
140382
  inputs.baselineCollectionId,
140297
- mockEnvUid
140298
- ).mockUrl;
140383
+ mockEnvUid,
140384
+ inputs.mockVisibility
140385
+ );
140386
+ resolvedMockUrl = resolved.mockUrl;
140387
+ resolvedMockVisibility = resolved.visibility;
140299
140388
  dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
140300
140389
  }
140301
140390
  if (!resolvedMockUrl && inputs.baselineCollectionId) {
@@ -140319,7 +140408,9 @@ async function runRepoSyncInner(inputs, dependencies) {
140319
140408
  );
140320
140409
  }
140321
140410
  if (discovered) {
140322
- resolvedMockUrl = requirePublicMock(discovered).mockUrl;
140411
+ const resolved = requireMockVisibility(discovered, inputs.mockVisibility);
140412
+ resolvedMockUrl = resolved.mockUrl;
140413
+ resolvedMockVisibility = resolved.visibility;
140323
140414
  dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
140324
140415
  }
140325
140416
  }
@@ -140332,7 +140423,8 @@ async function runRepoSyncInner(inputs, dependencies) {
140332
140423
  inputs.workspaceId,
140333
140424
  mockName,
140334
140425
  inputs.baselineCollectionId,
140335
- mockEnvUid
140426
+ mockEnvUid,
140427
+ inputs.mockVisibility
140336
140428
  ),
140337
140429
  {
140338
140430
  maxAttempts: 3,
@@ -140354,6 +140446,7 @@ async function runRepoSyncInner(inputs, dependencies) {
140354
140446
  }
140355
140447
  );
140356
140448
  resolvedMockUrl = mock.url;
140449
+ resolvedMockVisibility = mock.visibility ?? inputs.mockVisibility;
140357
140450
  dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
140358
140451
  } catch (error2) {
140359
140452
  throw new Error(
@@ -140369,7 +140462,23 @@ async function runRepoSyncInner(inputs, dependencies) {
140369
140462
  }
140370
140463
  }
140371
140464
  outputs["mock-url"] = resolvedMockUrl;
140465
+ outputs["mock-visibility"] = resolvedMockVisibility;
140466
+ outputs["mock-auth-required"] = String(resolvedMockVisibility === "private");
140372
140467
  dependencies.core.setOutput("mock-url", resolvedMockUrl);
140468
+ dependencies.core.setOutput("mock-visibility", resolvedMockVisibility);
140469
+ dependencies.core.setOutput("mock-auth-required", outputs["mock-auth-required"]);
140470
+ if (resolvedMockVisibility === "private") {
140471
+ if (!dependencies.postman.configurePrivateMockRuntimeAuth) {
140472
+ throw new Error(
140473
+ "PRIVATE_MOCK_RUNTIME_AUTH_UNAVAILABLE: The Postman client cannot configure runtime x-api-key injection."
140474
+ );
140475
+ }
140476
+ for (const collectionUid of [inputs.smokeCollectionId, inputs.contractCollectionId]) {
140477
+ if (collectionUid) {
140478
+ await dependencies.postman.configurePrivateMockRuntimeAuth(collectionUid);
140479
+ }
140480
+ }
140481
+ }
140373
140482
  if (inputs.mockEnvironmentEnabled && isCanonicalWriter) {
140374
140483
  const mockEnvironmentUid = await upsertMockEnvironment(
140375
140484
  inputs,
package/dist/cli.cjs CHANGED
@@ -134765,8 +134765,14 @@ 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
+ },
134768
134774
  "mock-environment-enabled": {
134769
- description: "Create or update a dedicated manual-validation environment whose baseUrl is the validated public mock URL. This environment is excluded from runtime CI selection.",
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.",
134770
134776
  required: false,
134771
134777
  default: "false"
134772
134778
  },
@@ -134963,6 +134969,12 @@ var postmanRepoSyncActionContract = {
134963
134969
  "mock-url": {
134964
134970
  description: "Created or reused mock server URL."
134965
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
+ },
134966
134978
  "mock-environment-uid": {
134967
134979
  description: "Dedicated manual-validation environment UID when mock-environment-enabled succeeds."
134968
134980
  },
@@ -135063,19 +135075,30 @@ var MockContractError = class extends Error {
135063
135075
  this.name = "MockContractError";
135064
135076
  }
135065
135077
  };
135066
- function requirePublicMock(mock) {
135067
- if (mock.visibility === "private") {
135078
+ function requireMockVisibility(mock, requested) {
135079
+ if (mock.visibility === "unknown") {
135068
135080
  throw new MockContractError(
135069
- `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.`
135070
135082
  );
135071
135083
  }
135072
- if (mock.visibility !== "public") {
135084
+ if (mock.visibility !== requested) {
135085
+ const code = requested === "public" ? "MOCK_NOT_PUBLIC" : "MOCK_NOT_PRIVATE";
135073
135086
  throw new MockContractError(
135074
- `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}.`
135075
135088
  );
135076
135089
  }
135077
135090
  return mock;
135078
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");
135079
135102
  var MAX_CREATE_FLIGHTS = 256;
135080
135103
  var createFlights = /* @__PURE__ */ new Map();
135081
135104
  var PostmanGatewayAssetsClient = class {
@@ -135583,22 +135606,22 @@ var PostmanGatewayAssetsClient = class {
135583
135606
  return data?.collection ?? null;
135584
135607
  }
135585
135608
  // --- mocks (service: mock) ---
135586
- async createMock(workspaceId, name, collectionUid, environmentUid) {
135609
+ async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "public") {
135587
135610
  const ws = workspaceId || this.workspaceId;
135588
135611
  const mockName = String(name ?? "").trim();
135589
135612
  const collection = String(collectionUid ?? "").trim();
135590
135613
  const environment = String(environmentUid ?? "").trim();
135591
- const flightKey = `mock:${ws}:${collection}:${environment}:${mockName}`;
135614
+ const flightKey = `mock:${ws}:${collection}:${environment}:${requestedVisibility}:${mockName}`;
135592
135615
  return this.singleFlight(flightKey, flightKey, "mock", async () => {
135593
135616
  const existing = await this.findMockByCollection(collection, environment, mockName);
135594
135617
  if (existing) {
135595
- const reusable = requirePublicMock(existing);
135596
- return { uid: reusable.uid, url: reusable.mockUrl };
135618
+ const reusable = requireMockVisibility(existing, requestedVisibility);
135619
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
135597
135620
  }
135598
135621
  const body = {
135599
135622
  name: mockName,
135600
135623
  collection,
135601
- private: false,
135624
+ private: requestedVisibility === "private",
135602
135625
  ...environment ? { environment } : {}
135603
135626
  };
135604
135627
  const send2 = (fallback) => this.gateway.requestJson(
@@ -135616,12 +135639,14 @@ var PostmanGatewayAssetsClient = class {
135616
135639
  );
135617
135640
  const parseMock = (response) => {
135618
135641
  const record = this.dataOf(response);
135619
- const created = requirePublicMock(
135620
- this.decodeMockRecord(record, "Mock create")
135642
+ const created = requireMockVisibility(
135643
+ this.decodeMockRecord(record, "Mock create"),
135644
+ requestedVisibility
135621
135645
  );
135622
135646
  return {
135623
135647
  uid: created.uid,
135624
- url: created.mockUrl
135648
+ url: created.mockUrl,
135649
+ visibility: requestedVisibility
135625
135650
  };
135626
135651
  };
135627
135652
  try {
@@ -135632,8 +135657,8 @@ var PostmanGatewayAssetsClient = class {
135632
135657
  error
135633
135658
  );
135634
135659
  if (adopted) {
135635
- const reusable = requirePublicMock(adopted);
135636
- return { uid: reusable.uid, url: reusable.mockUrl };
135660
+ const reusable = requireMockVisibility(adopted, requestedVisibility);
135661
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
135637
135662
  }
135638
135663
  if (adopted === void 0) {
135639
135664
  const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
@@ -135643,6 +135668,51 @@ var PostmanGatewayAssetsClient = class {
135643
135668
  }
135644
135669
  });
135645
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
+ }
135646
135716
  async listMocks() {
135647
135717
  const response = await this.gateway.requestJson({
135648
135718
  service: "mock",
@@ -136605,7 +136675,7 @@ function normalizeMockUrl(value, source) {
136605
136675
  url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
136606
136676
  return url.toString();
136607
136677
  }
136608
- function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
136678
+ function resolveExplicitMock(mocks, explicitUrl, collectionUid, environmentUid, requestedVisibility) {
136609
136679
  const normalized = normalizeMockUrl(explicitUrl, "mock-url");
136610
136680
  const matches = mocks.filter(
136611
136681
  (mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
@@ -136631,7 +136701,7 @@ function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmen
136631
136701
  `EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
136632
136702
  );
136633
136703
  }
136634
- return requirePublicMock(match);
136704
+ return requireMockVisibility(match, requestedVisibility);
136635
136705
  }
136636
136706
  function shouldRetryMockCreate(error) {
136637
136707
  if (error instanceof MockContractError) return false;
@@ -136740,6 +136810,15 @@ function parseCredentialPreflight(value) {
136740
136810
  `Unsupported credential-preflight "${normalized}". Supported values: ${allowed.join(", ")}`
136741
136811
  );
136742
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
+ }
136743
136822
  function parseBranchStrategy(value) {
136744
136823
  const definition = postmanRepoSyncActionContract.inputs["branch-strategy"];
136745
136824
  const allowed = definition.allowedValues ?? [];
@@ -136846,6 +136925,7 @@ function resolveInputs(env = process.env) {
136846
136925
  orgMode: parseBooleanInput(getInput("org-mode", env), false),
136847
136926
  monitorId: getInput("monitor-id", env),
136848
136927
  mockUrl: getInput("mock-url", env),
136928
+ mockVisibility: parseMockVisibility(getInput("mock-visibility", env)),
136849
136929
  mockEnvironmentEnabled: parseBooleanInput(getInput("mock-environment-enabled", env), false),
136850
136930
  monitorCron: getInput("monitor-cron", env),
136851
136931
  sslClientCert: getInput("ssl-client-cert", env),
@@ -137073,6 +137153,8 @@ function createOutputs(inputs) {
137073
137153
  "environment-sync-status": "skipped",
137074
137154
  "environment-uids-json": JSON.stringify(inputs.environmentUids),
137075
137155
  "mock-url": "",
137156
+ "mock-visibility": "",
137157
+ "mock-auth-required": "false",
137076
137158
  "mock-environment-uid": "",
137077
137159
  "mock-environment-status": "skipped",
137078
137160
  "monitor-id": "",
@@ -137954,7 +138036,9 @@ function createRepoSummary(outputs, envUids, pushed) {
137954
138036
  environmentSyncStatus: outputs["environment-sync-status"],
137955
138037
  mockEnvironmentStatus: outputs["mock-environment-status"],
137956
138038
  mockEnvironmentUid: outputs["mock-environment-uid"],
138039
+ mockAuthRequired: outputs["mock-auth-required"] === "true",
137957
138040
  mockUrl: outputs["mock-url"],
138041
+ mockVisibility: outputs["mock-visibility"],
137958
138042
  monitorId: outputs["monitor-id"],
137959
138043
  pushed,
137960
138044
  resolvedCurrentRef: outputs["resolved-current-ref"],
@@ -138182,6 +138266,7 @@ async function runRepoSyncInner(inputs, dependencies) {
138182
138266
  const mockEnvUid = envUids.dev || envUids.prod || Object.values(envUids)[0];
138183
138267
  if (mockEnvUid) {
138184
138268
  let resolvedMockUrl = "";
138269
+ let resolvedMockVisibility = "";
138185
138270
  const mockName = `${assetProjectName} Mock`;
138186
138271
  if (inputs.mockUrl) {
138187
138272
  let mocks;
@@ -138199,12 +138284,15 @@ async function runRepoSyncInner(inputs, dependencies) {
138199
138284
  { cause: error }
138200
138285
  );
138201
138286
  }
138202
- resolvedMockUrl = resolveExplicitPublicMock(
138287
+ const resolved = resolveExplicitMock(
138203
138288
  mocks,
138204
138289
  inputs.mockUrl,
138205
138290
  inputs.baselineCollectionId,
138206
- mockEnvUid
138207
- ).mockUrl;
138291
+ mockEnvUid,
138292
+ inputs.mockVisibility
138293
+ );
138294
+ resolvedMockUrl = resolved.mockUrl;
138295
+ resolvedMockVisibility = resolved.visibility;
138208
138296
  dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
138209
138297
  }
138210
138298
  if (!resolvedMockUrl && inputs.baselineCollectionId) {
@@ -138228,7 +138316,9 @@ async function runRepoSyncInner(inputs, dependencies) {
138228
138316
  );
138229
138317
  }
138230
138318
  if (discovered) {
138231
- resolvedMockUrl = requirePublicMock(discovered).mockUrl;
138319
+ const resolved = requireMockVisibility(discovered, inputs.mockVisibility);
138320
+ resolvedMockUrl = resolved.mockUrl;
138321
+ resolvedMockVisibility = resolved.visibility;
138232
138322
  dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
138233
138323
  }
138234
138324
  }
@@ -138241,7 +138331,8 @@ async function runRepoSyncInner(inputs, dependencies) {
138241
138331
  inputs.workspaceId,
138242
138332
  mockName,
138243
138333
  inputs.baselineCollectionId,
138244
- mockEnvUid
138334
+ mockEnvUid,
138335
+ inputs.mockVisibility
138245
138336
  ),
138246
138337
  {
138247
138338
  maxAttempts: 3,
@@ -138263,6 +138354,7 @@ async function runRepoSyncInner(inputs, dependencies) {
138263
138354
  }
138264
138355
  );
138265
138356
  resolvedMockUrl = mock.url;
138357
+ resolvedMockVisibility = mock.visibility ?? inputs.mockVisibility;
138266
138358
  dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
138267
138359
  } catch (error) {
138268
138360
  throw new Error(
@@ -138278,7 +138370,23 @@ async function runRepoSyncInner(inputs, dependencies) {
138278
138370
  }
138279
138371
  }
138280
138372
  outputs["mock-url"] = resolvedMockUrl;
138373
+ outputs["mock-visibility"] = resolvedMockVisibility;
138374
+ outputs["mock-auth-required"] = String(resolvedMockVisibility === "private");
138281
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
+ }
138282
138390
  if (inputs.mockEnvironmentEnabled && isCanonicalWriter) {
138283
138391
  const mockEnvironmentUid = await upsertMockEnvironment(
138284
138392
  inputs,
@@ -139246,6 +139354,7 @@ var CLI_INPUT_NAMES = [
139246
139354
  "org-mode",
139247
139355
  "monitor-id",
139248
139356
  "mock-url",
139357
+ "mock-visibility",
139249
139358
  "mock-environment-enabled",
139250
139359
  "monitor-cron",
139251
139360
  "ssl-client-cert",
package/dist/index.cjs CHANGED
@@ -136682,8 +136682,14 @@ var postmanRepoSyncActionContract = {
136682
136682
  description: "Existing mock server URL. When set, the action validates and reuses this mock instead of creating a new one.",
136683
136683
  required: false
136684
136684
  },
136685
+ "mock-visibility": {
136686
+ 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.",
136687
+ required: false,
136688
+ default: "public",
136689
+ allowedValues: ["public", "private"]
136690
+ },
136685
136691
  "mock-environment-enabled": {
136686
- description: "Create or update a dedicated manual-validation environment whose baseUrl is the validated public mock URL. This environment is excluded from runtime CI selection.",
136692
+ 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.",
136687
136693
  required: false,
136688
136694
  default: "false"
136689
136695
  },
@@ -136880,6 +136886,12 @@ var postmanRepoSyncActionContract = {
136880
136886
  "mock-url": {
136881
136887
  description: "Created or reused mock server URL."
136882
136888
  },
136889
+ "mock-visibility": {
136890
+ description: "Authoritatively observed mock visibility: public or private."
136891
+ },
136892
+ "mock-auth-required": {
136893
+ description: "Whether the collection runner must supply postmanPrivateMockApiKey at runtime."
136894
+ },
136883
136895
  "mock-environment-uid": {
136884
136896
  description: "Dedicated manual-validation environment UID when mock-environment-enabled succeeds."
136885
136897
  },
@@ -136980,19 +136992,30 @@ var MockContractError = class extends Error {
136980
136992
  this.name = "MockContractError";
136981
136993
  }
136982
136994
  };
136983
- function requirePublicMock(mock) {
136984
- if (mock.visibility === "private") {
136995
+ function requireMockVisibility(mock, requested) {
136996
+ if (mock.visibility === "unknown") {
136985
136997
  throw new MockContractError(
136986
- `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.`
136998
+ `MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is callable.`
136987
136999
  );
136988
137000
  }
136989
- if (mock.visibility !== "public") {
137001
+ if (mock.visibility !== requested) {
137002
+ const code = requested === "public" ? "MOCK_NOT_PUBLIC" : "MOCK_NOT_PRIVATE";
136990
137003
  throw new MockContractError(
136991
- `MOCK_VISIBILITY_UNKNOWN: Mock ${mock.uid} did not expose a supported visibility field. Refusing to assume it is publicly callable.`
137004
+ `${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}.`
136992
137005
  );
136993
137006
  }
136994
137007
  return mock;
136995
137008
  }
137009
+ var PRIVATE_MOCK_AUTH_MARKER = "postman-enterprise-automation: private-mock-auth";
137010
+ var PRIVATE_MOCK_AUTH_VARIABLE = "postmanPrivateMockApiKey";
137011
+ var PRIVATE_MOCK_AUTH_SCRIPT = [
137012
+ `// ${PRIVATE_MOCK_AUTH_MARKER}`,
137013
+ `var privateMockApiKey = pm.variables.get('${PRIVATE_MOCK_AUTH_VARIABLE}');`,
137014
+ "var privateMockHost = String(pm.request.url && pm.request.url.getHost ? pm.request.url.getHost() : '');",
137015
+ "if (privateMockApiKey && /(^|\\.)mock\\.pstmn\\.io$/i.test(privateMockHost)) {",
137016
+ " pm.request.headers.upsert({ key: 'x-api-key', value: privateMockApiKey });",
137017
+ "}"
137018
+ ].join("\n");
136996
137019
  var MAX_CREATE_FLIGHTS = 256;
136997
137020
  var createFlights = /* @__PURE__ */ new Map();
136998
137021
  var PostmanGatewayAssetsClient = class {
@@ -137500,22 +137523,22 @@ var PostmanGatewayAssetsClient = class {
137500
137523
  return data?.collection ?? null;
137501
137524
  }
137502
137525
  // --- mocks (service: mock) ---
137503
- async createMock(workspaceId, name, collectionUid, environmentUid) {
137526
+ async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "public") {
137504
137527
  const ws = workspaceId || this.workspaceId;
137505
137528
  const mockName = String(name ?? "").trim();
137506
137529
  const collection = String(collectionUid ?? "").trim();
137507
137530
  const environment = String(environmentUid ?? "").trim();
137508
- const flightKey = `mock:${ws}:${collection}:${environment}:${mockName}`;
137531
+ const flightKey = `mock:${ws}:${collection}:${environment}:${requestedVisibility}:${mockName}`;
137509
137532
  return this.singleFlight(flightKey, flightKey, "mock", async () => {
137510
137533
  const existing = await this.findMockByCollection(collection, environment, mockName);
137511
137534
  if (existing) {
137512
- const reusable = requirePublicMock(existing);
137513
- return { uid: reusable.uid, url: reusable.mockUrl };
137535
+ const reusable = requireMockVisibility(existing, requestedVisibility);
137536
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
137514
137537
  }
137515
137538
  const body = {
137516
137539
  name: mockName,
137517
137540
  collection,
137518
- private: false,
137541
+ private: requestedVisibility === "private",
137519
137542
  ...environment ? { environment } : {}
137520
137543
  };
137521
137544
  const send2 = (fallback) => this.gateway.requestJson(
@@ -137533,12 +137556,14 @@ var PostmanGatewayAssetsClient = class {
137533
137556
  );
137534
137557
  const parseMock = (response) => {
137535
137558
  const record = this.dataOf(response);
137536
- const created = requirePublicMock(
137537
- this.decodeMockRecord(record, "Mock create")
137559
+ const created = requireMockVisibility(
137560
+ this.decodeMockRecord(record, "Mock create"),
137561
+ requestedVisibility
137538
137562
  );
137539
137563
  return {
137540
137564
  uid: created.uid,
137541
- url: created.mockUrl
137565
+ url: created.mockUrl,
137566
+ visibility: requestedVisibility
137542
137567
  };
137543
137568
  };
137544
137569
  try {
@@ -137549,8 +137574,8 @@ var PostmanGatewayAssetsClient = class {
137549
137574
  error2
137550
137575
  );
137551
137576
  if (adopted) {
137552
- const reusable = requirePublicMock(adopted);
137553
- return { uid: reusable.uid, url: reusable.mockUrl };
137577
+ const reusable = requireMockVisibility(adopted, requestedVisibility);
137578
+ return { uid: reusable.uid, url: reusable.mockUrl, visibility: requestedVisibility };
137554
137579
  }
137555
137580
  if (adopted === void 0) {
137556
137581
  const retried = await this.resendAbsentCreate(async () => parseMock(await send2("auto")));
@@ -137560,6 +137585,51 @@ var PostmanGatewayAssetsClient = class {
137560
137585
  }
137561
137586
  });
137562
137587
  }
137588
+ /**
137589
+ * Add a secret-free runtime hook to every HTTP request in a collection. The
137590
+ * PMAK value is supplied only by the runner as a transient variable; this
137591
+ * method persists the variable name and header wiring, never the credential.
137592
+ */
137593
+ async configurePrivateMockRuntimeAuth(collectionUid) {
137594
+ const cid = String(collectionUid ?? "").trim();
137595
+ if (!cid) return 0;
137596
+ const listed = await this.gateway.requestJson({
137597
+ service: "collection",
137598
+ method: "get",
137599
+ path: `/v3/collections/${cid}/items/`
137600
+ });
137601
+ const items = Array.isArray(listed?.data) ? listed.data : [];
137602
+ let patched = 0;
137603
+ for (const listedItem of items) {
137604
+ if (String(listedItem.$kind ?? "") !== "http-request") continue;
137605
+ const itemId = String(listedItem.id ?? "").trim();
137606
+ if (!itemId) continue;
137607
+ const response = await this.gateway.requestJson({
137608
+ service: "collection",
137609
+ method: "get",
137610
+ path: `/v3/collections/${cid}/items/${itemId}`,
137611
+ headers: { "X-Entity-Type": "http-request" }
137612
+ });
137613
+ const item = this.asRecord(response?.data) ?? listedItem;
137614
+ const scripts = Array.isArray(item.scripts) ? item.scripts.filter((entry) => Boolean(this.asRecord(entry))) : [];
137615
+ const before = scripts.find((script) => String(script.type ?? "") === "beforeRequest");
137616
+ if (String(before?.code ?? "").includes(PRIVATE_MOCK_AUTH_MARKER)) continue;
137617
+ const code = [String(before?.code ?? "").trim(), PRIVATE_MOCK_AUTH_SCRIPT].filter(Boolean).join("\n");
137618
+ const nextScripts = [
137619
+ ...scripts.filter((script) => String(script.type ?? "") !== "beforeRequest"),
137620
+ { type: "beforeRequest", code, language: "text/javascript" }
137621
+ ];
137622
+ await this.gateway.requestJson({
137623
+ service: "collection",
137624
+ method: "patch",
137625
+ path: `/v3/collections/${cid}/items/${itemId}`,
137626
+ headers: { "X-Entity-Type": "http-request" },
137627
+ body: [{ op: "add", path: "/scripts", value: nextScripts }]
137628
+ });
137629
+ patched += 1;
137630
+ }
137631
+ return patched;
137632
+ }
137563
137633
  async listMocks() {
137564
137634
  const response = await this.gateway.requestJson({
137565
137635
  service: "mock",
@@ -138574,7 +138644,7 @@ function normalizeMockUrl(value, source) {
138574
138644
  url.pathname = url.pathname.replace(/\/+$/g, "") || "/";
138575
138645
  return url.toString();
138576
138646
  }
138577
- function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmentUid) {
138647
+ function resolveExplicitMock(mocks, explicitUrl, collectionUid, environmentUid, requestedVisibility) {
138578
138648
  const normalized = normalizeMockUrl(explicitUrl, "mock-url");
138579
138649
  const matches = mocks.filter(
138580
138650
  (mock) => normalizeMockUrl(mock.mockUrl, `mock ${mock.uid} URL`) === normalized
@@ -138600,7 +138670,7 @@ function resolveExplicitPublicMock(mocks, explicitUrl, collectionUid, environmen
138600
138670
  `EXPLICIT_MOCK_IDENTITY_MISMATCH: Mock ${match.uid} references environment ${match.environment || "(none)"}, expected ${environmentUid}`
138601
138671
  );
138602
138672
  }
138603
- return requirePublicMock(match);
138673
+ return requireMockVisibility(match, requestedVisibility);
138604
138674
  }
138605
138675
  function shouldRetryMockCreate(error2) {
138606
138676
  if (error2 instanceof MockContractError) return false;
@@ -138712,6 +138782,15 @@ function parseCredentialPreflight(value) {
138712
138782
  `Unsupported credential-preflight "${normalized}". Supported values: ${allowed.join(", ")}`
138713
138783
  );
138714
138784
  }
138785
+ function parseMockVisibility(value) {
138786
+ const definition = postmanRepoSyncActionContract.inputs["mock-visibility"];
138787
+ const allowed = definition.allowedValues ?? [];
138788
+ const normalized = String(value || "").trim() || (definition.default ?? "public");
138789
+ if (allowed.includes(normalized)) return normalized;
138790
+ throw new Error(
138791
+ `Unsupported mock-visibility "${normalized}". Supported values: ${allowed.join(", ")}`
138792
+ );
138793
+ }
138715
138794
  function parseBranchStrategy(value) {
138716
138795
  const definition = postmanRepoSyncActionContract.inputs["branch-strategy"];
138717
138796
  const allowed = definition.allowedValues ?? [];
@@ -138818,6 +138897,7 @@ function resolveInputs(env = process.env) {
138818
138897
  orgMode: parseBooleanInput(getInput2("org-mode", env), false),
138819
138898
  monitorId: getInput2("monitor-id", env),
138820
138899
  mockUrl: getInput2("mock-url", env),
138900
+ mockVisibility: parseMockVisibility(getInput2("mock-visibility", env)),
138821
138901
  mockEnvironmentEnabled: parseBooleanInput(getInput2("mock-environment-enabled", env), false),
138822
138902
  monitorCron: getInput2("monitor-cron", env),
138823
138903
  sslClientCert: getInput2("ssl-client-cert", env),
@@ -139045,6 +139125,8 @@ function createOutputs(inputs) {
139045
139125
  "environment-sync-status": "skipped",
139046
139126
  "environment-uids-json": JSON.stringify(inputs.environmentUids),
139047
139127
  "mock-url": "",
139128
+ "mock-visibility": "",
139129
+ "mock-auth-required": "false",
139048
139130
  "mock-environment-uid": "",
139049
139131
  "mock-environment-status": "skipped",
139050
139132
  "monitor-id": "",
@@ -139114,6 +139196,7 @@ function readActionInputs(actionCore) {
139114
139196
  INPUT_ORG_MODE: readInput(actionCore, "org-mode"),
139115
139197
  INPUT_MONITOR_ID: readInput(actionCore, "monitor-id"),
139116
139198
  INPUT_MOCK_URL: readInput(actionCore, "mock-url"),
139199
+ INPUT_MOCK_VISIBILITY: readInput(actionCore, "mock-visibility"),
139117
139200
  INPUT_MOCK_ENVIRONMENT_ENABLED: readInput(actionCore, "mock-environment-enabled"),
139118
139201
  INPUT_MONITOR_CRON: readInput(actionCore, "monitor-cron"),
139119
139202
  INPUT_SSL_CLIENT_CERT: sslClientCert,
@@ -140067,7 +140150,9 @@ function createRepoSummary(outputs, envUids, pushed) {
140067
140150
  environmentSyncStatus: outputs["environment-sync-status"],
140068
140151
  mockEnvironmentStatus: outputs["mock-environment-status"],
140069
140152
  mockEnvironmentUid: outputs["mock-environment-uid"],
140153
+ mockAuthRequired: outputs["mock-auth-required"] === "true",
140070
140154
  mockUrl: outputs["mock-url"],
140155
+ mockVisibility: outputs["mock-visibility"],
140071
140156
  monitorId: outputs["monitor-id"],
140072
140157
  pushed,
140073
140158
  resolvedCurrentRef: outputs["resolved-current-ref"],
@@ -140295,6 +140380,7 @@ async function runRepoSyncInner(inputs, dependencies) {
140295
140380
  const mockEnvUid = envUids.dev || envUids.prod || Object.values(envUids)[0];
140296
140381
  if (mockEnvUid) {
140297
140382
  let resolvedMockUrl = "";
140383
+ let resolvedMockVisibility = "";
140298
140384
  const mockName = `${assetProjectName} Mock`;
140299
140385
  if (inputs.mockUrl) {
140300
140386
  let mocks;
@@ -140312,12 +140398,15 @@ async function runRepoSyncInner(inputs, dependencies) {
140312
140398
  { cause: error2 }
140313
140399
  );
140314
140400
  }
140315
- resolvedMockUrl = resolveExplicitPublicMock(
140401
+ const resolved = resolveExplicitMock(
140316
140402
  mocks,
140317
140403
  inputs.mockUrl,
140318
140404
  inputs.baselineCollectionId,
140319
- mockEnvUid
140320
- ).mockUrl;
140405
+ mockEnvUid,
140406
+ inputs.mockVisibility
140407
+ );
140408
+ resolvedMockUrl = resolved.mockUrl;
140409
+ resolvedMockVisibility = resolved.visibility;
140321
140410
  dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
140322
140411
  }
140323
140412
  if (!resolvedMockUrl && inputs.baselineCollectionId) {
@@ -140341,7 +140430,9 @@ async function runRepoSyncInner(inputs, dependencies) {
140341
140430
  );
140342
140431
  }
140343
140432
  if (discovered) {
140344
- resolvedMockUrl = requirePublicMock(discovered).mockUrl;
140433
+ const resolved = requireMockVisibility(discovered, inputs.mockVisibility);
140434
+ resolvedMockUrl = resolved.mockUrl;
140435
+ resolvedMockVisibility = resolved.visibility;
140345
140436
  dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
140346
140437
  }
140347
140438
  }
@@ -140354,7 +140445,8 @@ async function runRepoSyncInner(inputs, dependencies) {
140354
140445
  inputs.workspaceId,
140355
140446
  mockName,
140356
140447
  inputs.baselineCollectionId,
140357
- mockEnvUid
140448
+ mockEnvUid,
140449
+ inputs.mockVisibility
140358
140450
  ),
140359
140451
  {
140360
140452
  maxAttempts: 3,
@@ -140376,6 +140468,7 @@ async function runRepoSyncInner(inputs, dependencies) {
140376
140468
  }
140377
140469
  );
140378
140470
  resolvedMockUrl = mock.url;
140471
+ resolvedMockVisibility = mock.visibility ?? inputs.mockVisibility;
140379
140472
  dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
140380
140473
  } catch (error2) {
140381
140474
  throw new Error(
@@ -140391,7 +140484,23 @@ async function runRepoSyncInner(inputs, dependencies) {
140391
140484
  }
140392
140485
  }
140393
140486
  outputs["mock-url"] = resolvedMockUrl;
140487
+ outputs["mock-visibility"] = resolvedMockVisibility;
140488
+ outputs["mock-auth-required"] = String(resolvedMockVisibility === "private");
140394
140489
  dependencies.core.setOutput("mock-url", resolvedMockUrl);
140490
+ dependencies.core.setOutput("mock-visibility", resolvedMockVisibility);
140491
+ dependencies.core.setOutput("mock-auth-required", outputs["mock-auth-required"]);
140492
+ if (resolvedMockVisibility === "private") {
140493
+ if (!dependencies.postman.configurePrivateMockRuntimeAuth) {
140494
+ throw new Error(
140495
+ "PRIVATE_MOCK_RUNTIME_AUTH_UNAVAILABLE: The Postman client cannot configure runtime x-api-key injection."
140496
+ );
140497
+ }
140498
+ for (const collectionUid of [inputs.smokeCollectionId, inputs.contractCollectionId]) {
140499
+ if (collectionUid) {
140500
+ await dependencies.postman.configurePrivateMockRuntimeAuth(collectionUid);
140501
+ }
140502
+ }
140503
+ }
140395
140504
  if (inputs.mockEnvironmentEnabled && isCanonicalWriter) {
140396
140505
  const mockEnvironmentUid = await upsertMockEnvironment(
140397
140506
  inputs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-repo-sync",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Postman repo sync GitHub Action.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",