@postman-cse/onboarding-repo-sync 2.6.4 → 2.6.5

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/action.cjs CHANGED
@@ -140555,6 +140555,10 @@ var PREBUILT_COLLECTION_ROLES = /* @__PURE__ */ new Set([
140555
140555
  ]);
140556
140556
  var SHA256_HEX = /^[a-f0-9]{64}$/;
140557
140557
  var PREBUILT_CLOUD_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
140558
+ var PREBUILT_COLLECTION_MAX_DEPTH = 128;
140559
+ var PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES = LOCAL_SPEC_DISCOVERY_MAX_TRAVERSAL_ENTRIES;
140560
+ var PREBUILT_COLLECTION_MAX_FILE_BYTES = 32 * 1024 * 1024;
140561
+ var PREBUILT_COLLECTION_MAX_TOTAL_BYTES = 100 * 1024 * 1024;
140558
140562
  function failPrebuiltCollections(detail) {
140559
140563
  throw new Error(`CONTRACT_PREBUILT_COLLECTIONS_INVALID: ${detail}`);
140560
140564
  }
@@ -140666,8 +140670,9 @@ function assertPathWithinArtifactRoot(targetPath, artifactDir, fieldName) {
140666
140670
  existingPath = parent;
140667
140671
  }
140668
140672
  const realExisting = (0, import_node_fs5.realpathSync)(existingPath);
140669
- const realRelative = path8.relative(artifactRoot, realExisting);
140670
- if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
140673
+ const realArtifactRoot = (0, import_node_fs5.existsSync)(artifactRoot) ? (0, import_node_fs5.realpathSync)(artifactRoot) : void 0;
140674
+ const realRelative = realArtifactRoot ? path8.relative(realArtifactRoot, realExisting) : "";
140675
+ if (realArtifactRoot && (realRelative.startsWith("..") || path8.isAbsolute(realRelative))) {
140671
140676
  failPrebuiltCollections(
140672
140677
  `${fieldName} resolves outside artifact-dir via symlink; received ${targetPath}`
140673
140678
  );
@@ -140709,13 +140714,16 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140709
140714
  return [];
140710
140715
  }
140711
140716
  const files = [];
140712
- const pendingDirectories = [absRoot];
140717
+ const pendingDirectories = [{ absolute: absRoot, depth: 0 }];
140713
140718
  const seenDirectories = /* @__PURE__ */ new Set();
140719
+ let traversalEntries = 1;
140720
+ let totalBytes = 0;
140714
140721
  while (pendingDirectories.length > 0) {
140715
- const currentAbsolute = pendingDirectories.pop();
140716
- if (!currentAbsolute) {
140722
+ const current = pendingDirectories.pop();
140723
+ if (!current) {
140717
140724
  break;
140718
140725
  }
140726
+ const { absolute: currentAbsolute, depth: currentDepth } = current;
140719
140727
  const currentStat = (0, import_node_fs5.lstatSync)(currentAbsolute);
140720
140728
  if (currentStat.isSymbolicLink() || !currentStat.isDirectory()) {
140721
140729
  failPrebuiltCollections(
@@ -140729,8 +140737,16 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140729
140737
  );
140730
140738
  }
140731
140739
  seenDirectories.add(currentKey);
140732
- const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true });
140740
+ const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true }).sort(
140741
+ (left, right) => left.name.localeCompare(right.name)
140742
+ );
140733
140743
  for (const entry of entries) {
140744
+ traversalEntries += 1;
140745
+ if (traversalEntries > PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES) {
140746
+ failPrebuiltCollections(
140747
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES} traversal-entry budget`
140748
+ );
140749
+ }
140734
140750
  const abs = path8.join(currentAbsolute, entry.name);
140735
140751
  if (entry.isSymbolicLink()) {
140736
140752
  failPrebuiltCollections(
@@ -140738,7 +140754,13 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140738
140754
  );
140739
140755
  }
140740
140756
  if (entry.isDirectory()) {
140741
- pendingDirectories.push(abs);
140757
+ const nextDepth = currentDepth + 1;
140758
+ if (nextDepth > PREBUILT_COLLECTION_MAX_DEPTH) {
140759
+ failPrebuiltCollections(
140760
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_DEPTH} directory-depth budget`
140761
+ );
140762
+ }
140763
+ pendingDirectories.push({ absolute: abs, depth: nextDepth });
140742
140764
  continue;
140743
140765
  }
140744
140766
  if (!entry.isFile()) {
@@ -140752,6 +140774,17 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140752
140774
  `prebuilt collection tree file changed or became unsupported at ${normalizeToPosix(path8.relative(absRoot, abs))}`
140753
140775
  );
140754
140776
  }
140777
+ if (fileLstat.size > PREBUILT_COLLECTION_MAX_FILE_BYTES) {
140778
+ failPrebuiltCollections(
140779
+ `prebuilt collection tree file ${normalizeToPosix(path8.relative(absRoot, abs))} exceeds the ${PREBUILT_COLLECTION_MAX_FILE_BYTES / (1024 * 1024)} MiB individual-file budget`
140780
+ );
140781
+ }
140782
+ totalBytes += fileLstat.size;
140783
+ if (totalBytes > PREBUILT_COLLECTION_MAX_TOTAL_BYTES) {
140784
+ failPrebuiltCollections(
140785
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_TOTAL_BYTES / (1024 * 1024)} MiB total-byte budget`
140786
+ );
140787
+ }
140755
140788
  files.push({
140756
140789
  absolute: abs,
140757
140790
  relative: normalizeToPosix(path8.relative(absRoot, abs)),
@@ -140886,63 +140919,69 @@ async function preparePrivateMockCloudCollection(role, collectionId, postman) {
140886
140919
  }
140887
140920
  return collection;
140888
140921
  }
140922
+ var ARTIFACT_ACQUISITION_WIDTH = 2;
140923
+ async function runBoundedInOrder(items, width, worker) {
140924
+ const results = new Array(items.length);
140925
+ let nextIndex = 0;
140926
+ const failures = /* @__PURE__ */ new Map();
140927
+ const runWorker = async () => {
140928
+ while (failures.size === 0 && nextIndex < items.length) {
140929
+ const index = nextIndex;
140930
+ nextIndex += 1;
140931
+ try {
140932
+ results[index] = await worker(items[index], index);
140933
+ } catch (error2) {
140934
+ failures.set(index, error2);
140935
+ return;
140936
+ }
140937
+ }
140938
+ };
140939
+ await Promise.all(Array.from({ length: Math.min(width, items.length) }, () => runWorker()));
140940
+ const failedIndex = Math.min(...failures.keys());
140941
+ if (Number.isFinite(failedIndex)) {
140942
+ throw failures.get(failedIndex);
140943
+ }
140944
+ return results;
140945
+ }
140946
+ async function acquireCollectionArtifact(options) {
140947
+ const { role, collectionId, dirName, collectionsDir, prebuiltByRole, postman, core, privateMockAuth = false } = options;
140948
+ const expectedPath = `${collectionsDir}/${dirName}`;
140949
+ const forceCloudExport = privateMockAuth && (role === "smoke" || role === "contract");
140950
+ const entry = prebuiltByRole.get(role);
140951
+ if (entry && !forceCloudExport && tryReusePrebuiltCollection({
140952
+ prepared: entry,
140953
+ expectedPath,
140954
+ expectedCloudId: collectionId
140955
+ })) {
140956
+ core.info(`Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`);
140957
+ return { reusePrebuilt: true };
140958
+ }
140959
+ if (entry) {
140960
+ core.info(forceCloudExport ? `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud` : `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`);
140961
+ }
140962
+ const cloud = forceCloudExport ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
140963
+ return { reusePrebuilt: false, cloudCollection: cloud };
140964
+ }
140889
140965
  async function exportCollectionArtifact(options) {
140890
140966
  const {
140891
- role,
140892
140967
  collectionId,
140893
140968
  dirName,
140894
140969
  collectionsDir,
140895
- prebuiltByRole,
140896
- postman,
140897
- core,
140898
- privateMockAuth = false,
140899
- preparedCloudCollection
140970
+ artifactDir,
140971
+ acquisition
140900
140972
  } = options;
140901
140973
  if (!collectionId) {
140902
140974
  return void 0;
140903
140975
  }
140904
140976
  const expectedPath = `${collectionsDir}/${dirName}`;
140905
- const forceCloudExport = privateMockAuth && (role === "smoke" || role === "contract");
140906
- const entry = prebuiltByRole.get(role);
140907
- if (entry && !forceCloudExport) {
140908
- const reused = tryReusePrebuiltCollection({
140909
- prepared: entry,
140910
- expectedPath,
140911
- expectedCloudId: collectionId
140912
- });
140913
- if (reused) {
140914
- core.info(
140915
- `Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`
140916
- );
140917
- return `../${expectedPath}`;
140918
- }
140919
- core.info(
140920
- `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`
140921
- );
140922
- } else if (entry && forceCloudExport) {
140923
- core.info(
140924
- `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud`
140925
- );
140977
+ if (acquisition.reusePrebuilt) {
140978
+ return `../${expectedPath}`;
140926
140979
  }
140927
- let collectionForExport;
140928
- if (forceCloudExport && preparedCloudCollection) {
140929
- collectionForExport = preparedCloudCollection;
140930
- } else if (forceCloudExport) {
140931
- const col = await postman.getCollection(collectionId);
140932
- const { collection } = applyPrivateMockExportCleanup(col, {
140933
- stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
140934
- });
140935
- if (!verifyPrivateMockRootHook(collection)) {
140936
- throw new Error(
140937
- `PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from exported ${role} collection ${collectionId}`
140938
- );
140939
- }
140940
- collectionForExport = collection;
140941
- } else {
140942
- const col = await postman.getCollection(collectionId);
140943
- collectionForExport = col;
140944
- }
140945
- await convertAndSplitAnyCollection(collectionForExport, expectedPath);
140980
+ assertPathWithinArtifactRoot(expectedPath, artifactDir, "collection target");
140981
+ await convertAndSplitAnyCollection(
140982
+ acquisition.cloudCollection,
140983
+ expectedPath
140984
+ );
140946
140985
  return `../${expectedPath}`;
140947
140986
  }
140948
140987
  function hasControlCharacter2(value) {
@@ -141007,65 +141046,45 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141007
141046
  ) : void 0;
141008
141047
  const prebuiltByRole = options.preparedPrebuiltCollections;
141009
141048
  const privateMockAuth = options.privateMockAuth === true;
141010
- const preparedPrivateMockCollections = /* @__PURE__ */ new Map();
141011
- if (privateMockAuth) {
141012
- for (const spec of [
141013
- { role: "smoke", collectionId: inputs.smokeCollectionId },
141014
- { role: "contract", collectionId: inputs.contractCollectionId }
141015
- ]) {
141016
- if (!spec.collectionId) {
141017
- continue;
141018
- }
141019
- preparedPrivateMockCollections.set(
141020
- spec.role,
141021
- await preparePrivateMockCloudCollection(
141022
- spec.role,
141023
- spec.collectionId,
141024
- dependencies.postman
141025
- )
141026
- );
141027
- }
141028
- }
141029
- const baselineRef = await exportCollectionArtifact({
141030
- role: "baseline",
141031
- collectionId: inputs.baselineCollectionId,
141032
- dirName: getCollectionDirectoryName("Baseline", assetProjectName),
141033
- collectionsDir,
141034
- prebuiltByRole,
141035
- postman: dependencies.postman,
141036
- core: dependencies.core,
141037
- privateMockAuth
141038
- });
141039
- if (baselineRef) {
141040
- manifestCollections[baselineRef] = inputs.baselineCollectionId;
141041
- }
141042
- const smokeRef = await exportCollectionArtifact({
141043
- role: "smoke",
141044
- collectionId: inputs.smokeCollectionId,
141045
- dirName: getCollectionDirectoryName("Smoke", assetProjectName),
141046
- collectionsDir,
141047
- prebuiltByRole,
141048
- postman: dependencies.postman,
141049
- core: dependencies.core,
141050
- privateMockAuth,
141051
- preparedCloudCollection: preparedPrivateMockCollections.get("smoke")
141052
- });
141053
- if (smokeRef) {
141054
- manifestCollections[smokeRef] = inputs.smokeCollectionId;
141049
+ const collectionSpecs = [
141050
+ { role: "baseline", collectionId: inputs.baselineCollectionId, dirName: getCollectionDirectoryName("Baseline", assetProjectName) },
141051
+ { role: "smoke", collectionId: inputs.smokeCollectionId, dirName: getCollectionDirectoryName("Smoke", assetProjectName) },
141052
+ { role: "contract", collectionId: inputs.contractCollectionId, dirName: getCollectionDirectoryName("Contract", assetProjectName) }
141053
+ ].filter((spec) => Boolean(spec.collectionId));
141054
+ const collectionStartedAt = Date.now();
141055
+ let collectionStatus = "success";
141056
+ let acquisitions;
141057
+ try {
141058
+ acquisitions = await runBoundedInOrder(
141059
+ collectionSpecs,
141060
+ ARTIFACT_ACQUISITION_WIDTH,
141061
+ (spec) => acquireCollectionArtifact({
141062
+ ...spec,
141063
+ collectionsDir,
141064
+ prebuiltByRole,
141065
+ postman: dependencies.postman,
141066
+ core: dependencies.core,
141067
+ privateMockAuth
141068
+ })
141069
+ );
141070
+ } catch (error2) {
141071
+ collectionStatus = "failed";
141072
+ throw error2;
141073
+ } finally {
141074
+ dependencies.core.info(
141075
+ `collection-acquisition count=${collectionSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - collectionStartedAt} status=${collectionStatus}`
141076
+ );
141055
141077
  }
141056
- const contractRef = await exportCollectionArtifact({
141057
- role: "contract",
141058
- collectionId: inputs.contractCollectionId,
141059
- dirName: getCollectionDirectoryName("Contract", assetProjectName),
141060
- collectionsDir,
141061
- prebuiltByRole,
141062
- postman: dependencies.postman,
141063
- core: dependencies.core,
141064
- privateMockAuth,
141065
- preparedCloudCollection: preparedPrivateMockCollections.get("contract")
141066
- });
141067
- if (contractRef) {
141068
- manifestCollections[contractRef] = inputs.contractCollectionId;
141078
+ for (const [index, spec] of collectionSpecs.entries()) {
141079
+ const ref = await exportCollectionArtifact({
141080
+ ...spec,
141081
+ collectionsDir,
141082
+ artifactDir: inputs.artifactDir,
141083
+ acquisition: acquisitions[index]
141084
+ });
141085
+ if (ref) {
141086
+ manifestCollections[ref] = spec.collectionId;
141087
+ }
141069
141088
  }
141070
141089
  ensureDir(collectionsDir);
141071
141090
  ensureDir(environmentsDir);
@@ -141084,17 +141103,40 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141084
141103
  ensureDir(ciDir);
141085
141104
  }
141086
141105
  }
141087
- for (const [envName, envUid] of Object.entries(envUids)) {
141088
- writeJsonFile(
141089
- `${environmentsDir}/${envName}.postman_environment.json`,
141090
- await dependencies.postman.getEnvironment(envUid),
141091
- true
141106
+ const environmentSpecs = [
141107
+ ...Object.entries(envUids).map(([envName, envUid]) => ({
141108
+ envName,
141109
+ envUid,
141110
+ filePath: `${environmentsDir}/${envName}.postman_environment.json`
141111
+ })),
141112
+ ...options.mockEnvironmentUid ? [{
141113
+ envName: "manual-validation",
141114
+ envUid: options.mockEnvironmentUid,
141115
+ filePath: `${mocksDir}/manual-validation.postman_environment.json`
141116
+ }] : []
141117
+ ];
141118
+ const environmentStartedAt = Date.now();
141119
+ let environmentStatus = "success";
141120
+ let environmentPayloads;
141121
+ try {
141122
+ environmentPayloads = await runBoundedInOrder(
141123
+ environmentSpecs,
141124
+ ARTIFACT_ACQUISITION_WIDTH,
141125
+ (spec) => dependencies.postman.getEnvironment(spec.envUid)
141126
+ );
141127
+ } catch (error2) {
141128
+ environmentStatus = "failed";
141129
+ throw error2;
141130
+ } finally {
141131
+ dependencies.core.info(
141132
+ `environment-artifact-acquisition count=${environmentSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - environmentStartedAt} status=${environmentStatus}`
141092
141133
  );
141093
141134
  }
141094
- if (options.mockEnvironmentUid) {
141135
+ for (const [index, spec] of environmentSpecs.entries()) {
141136
+ assertPathWithinCwd(spec.filePath, "environment target");
141095
141137
  writeJsonFile(
141096
- `${mocksDir}/manual-validation.postman_environment.json`,
141097
- await dependencies.postman.getEnvironment(options.mockEnvironmentUid),
141138
+ spec.filePath,
141139
+ environmentPayloads[index],
141098
141140
  true
141099
141141
  );
141100
141142
  }
@@ -141104,6 +141146,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141104
141146
  workspaceLinkEnabled: inputs.workspaceLinkEnabled,
141105
141147
  workspaceLinkStatus: options.workspaceLinkStatus
141106
141148
  });
141149
+ assertPathWithinCwd(".postman/resources.yaml", "resources state target");
141107
141150
  (0, import_node_fs5.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
141108
141151
  durableWorkspaceId,
141109
141152
  manifestCollections,
@@ -141122,6 +141165,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141122
141165
  } catch {
141123
141166
  existingWorkflows = void 0;
141124
141167
  }
141168
+ assertPathWithinCwd(".postman/workflows.yaml", "workflows state target");
141125
141169
  (0, import_node_fs5.writeFileSync)(
141126
141170
  ".postman/workflows.yaml",
141127
141171
  buildSpecCollectionWorkflowManifest(
@@ -141171,18 +141215,19 @@ function createRepoSummary(outputs, envUids, pushed) {
141171
141215
  }
141172
141216
  async function commitAndPushGeneratedFiles(inputs, dependencies) {
141173
141217
  if (inputs.generateCiWorkflow) {
141174
- assertPathWithinCwd(inputs.ciWorkflowPath, "ci-workflow-path");
141175
141218
  const ciWorkflow = renderCiWorkflow(inputs);
141176
141219
  const parts = inputs.ciWorkflowPath.split("/");
141177
141220
  if (parts.length > 1) {
141178
141221
  const dir = parts.slice(0, -1).join("/");
141179
141222
  ensureDir(dir);
141180
141223
  }
141224
+ assertPathWithinCwd(inputs.ciWorkflowPath, "ci-workflow-path");
141181
141225
  (0, import_node_fs5.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
141182
141226
  if (inputs.provider === "github" || inputs.provider === "unknown") {
141183
141227
  const gcPath = ".github/workflows/postman-preview-gc.yml";
141184
141228
  if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
141185
141229
  ensureDir(".github/workflows");
141230
+ assertPathWithinCwd(gcPath, "preview GC workflow path");
141186
141231
  (0, import_node_fs5.writeFileSync)(gcPath, renderGcWorkflowTemplate());
141187
141232
  }
141188
141233
  }
package/dist/cli.cjs CHANGED
@@ -138463,6 +138463,10 @@ var PREBUILT_COLLECTION_ROLES = /* @__PURE__ */ new Set([
138463
138463
  ]);
138464
138464
  var SHA256_HEX = /^[a-f0-9]{64}$/;
138465
138465
  var PREBUILT_CLOUD_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
138466
+ var PREBUILT_COLLECTION_MAX_DEPTH = 128;
138467
+ var PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES = LOCAL_SPEC_DISCOVERY_MAX_TRAVERSAL_ENTRIES;
138468
+ var PREBUILT_COLLECTION_MAX_FILE_BYTES = 32 * 1024 * 1024;
138469
+ var PREBUILT_COLLECTION_MAX_TOTAL_BYTES = 100 * 1024 * 1024;
138466
138470
  function failPrebuiltCollections(detail) {
138467
138471
  throw new Error(`CONTRACT_PREBUILT_COLLECTIONS_INVALID: ${detail}`);
138468
138472
  }
@@ -138574,8 +138578,9 @@ function assertPathWithinArtifactRoot(targetPath, artifactDir, fieldName) {
138574
138578
  existingPath = parent;
138575
138579
  }
138576
138580
  const realExisting = (0, import_node_fs5.realpathSync)(existingPath);
138577
- const realRelative = path3.relative(artifactRoot, realExisting);
138578
- if (realRelative.startsWith("..") || path3.isAbsolute(realRelative)) {
138581
+ const realArtifactRoot = (0, import_node_fs5.existsSync)(artifactRoot) ? (0, import_node_fs5.realpathSync)(artifactRoot) : void 0;
138582
+ const realRelative = realArtifactRoot ? path3.relative(realArtifactRoot, realExisting) : "";
138583
+ if (realArtifactRoot && (realRelative.startsWith("..") || path3.isAbsolute(realRelative))) {
138579
138584
  failPrebuiltCollections(
138580
138585
  `${fieldName} resolves outside artifact-dir via symlink; received ${targetPath}`
138581
138586
  );
@@ -138617,13 +138622,16 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
138617
138622
  return [];
138618
138623
  }
138619
138624
  const files = [];
138620
- const pendingDirectories = [absRoot];
138625
+ const pendingDirectories = [{ absolute: absRoot, depth: 0 }];
138621
138626
  const seenDirectories = /* @__PURE__ */ new Set();
138627
+ let traversalEntries = 1;
138628
+ let totalBytes = 0;
138622
138629
  while (pendingDirectories.length > 0) {
138623
- const currentAbsolute = pendingDirectories.pop();
138624
- if (!currentAbsolute) {
138630
+ const current = pendingDirectories.pop();
138631
+ if (!current) {
138625
138632
  break;
138626
138633
  }
138634
+ const { absolute: currentAbsolute, depth: currentDepth } = current;
138627
138635
  const currentStat = (0, import_node_fs5.lstatSync)(currentAbsolute);
138628
138636
  if (currentStat.isSymbolicLink() || !currentStat.isDirectory()) {
138629
138637
  failPrebuiltCollections(
@@ -138637,8 +138645,16 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
138637
138645
  );
138638
138646
  }
138639
138647
  seenDirectories.add(currentKey);
138640
- const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true });
138648
+ const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true }).sort(
138649
+ (left, right) => left.name.localeCompare(right.name)
138650
+ );
138641
138651
  for (const entry of entries) {
138652
+ traversalEntries += 1;
138653
+ if (traversalEntries > PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES) {
138654
+ failPrebuiltCollections(
138655
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES} traversal-entry budget`
138656
+ );
138657
+ }
138642
138658
  const abs = path3.join(currentAbsolute, entry.name);
138643
138659
  if (entry.isSymbolicLink()) {
138644
138660
  failPrebuiltCollections(
@@ -138646,7 +138662,13 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
138646
138662
  );
138647
138663
  }
138648
138664
  if (entry.isDirectory()) {
138649
- pendingDirectories.push(abs);
138665
+ const nextDepth = currentDepth + 1;
138666
+ if (nextDepth > PREBUILT_COLLECTION_MAX_DEPTH) {
138667
+ failPrebuiltCollections(
138668
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_DEPTH} directory-depth budget`
138669
+ );
138670
+ }
138671
+ pendingDirectories.push({ absolute: abs, depth: nextDepth });
138650
138672
  continue;
138651
138673
  }
138652
138674
  if (!entry.isFile()) {
@@ -138660,6 +138682,17 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
138660
138682
  `prebuilt collection tree file changed or became unsupported at ${normalizeToPosix(path3.relative(absRoot, abs))}`
138661
138683
  );
138662
138684
  }
138685
+ if (fileLstat.size > PREBUILT_COLLECTION_MAX_FILE_BYTES) {
138686
+ failPrebuiltCollections(
138687
+ `prebuilt collection tree file ${normalizeToPosix(path3.relative(absRoot, abs))} exceeds the ${PREBUILT_COLLECTION_MAX_FILE_BYTES / (1024 * 1024)} MiB individual-file budget`
138688
+ );
138689
+ }
138690
+ totalBytes += fileLstat.size;
138691
+ if (totalBytes > PREBUILT_COLLECTION_MAX_TOTAL_BYTES) {
138692
+ failPrebuiltCollections(
138693
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_TOTAL_BYTES / (1024 * 1024)} MiB total-byte budget`
138694
+ );
138695
+ }
138663
138696
  files.push({
138664
138697
  absolute: abs,
138665
138698
  relative: normalizeToPosix(path3.relative(absRoot, abs)),
@@ -138794,63 +138827,69 @@ async function preparePrivateMockCloudCollection(role, collectionId, postman) {
138794
138827
  }
138795
138828
  return collection;
138796
138829
  }
138830
+ var ARTIFACT_ACQUISITION_WIDTH = 2;
138831
+ async function runBoundedInOrder(items, width, worker) {
138832
+ const results = new Array(items.length);
138833
+ let nextIndex = 0;
138834
+ const failures = /* @__PURE__ */ new Map();
138835
+ const runWorker = async () => {
138836
+ while (failures.size === 0 && nextIndex < items.length) {
138837
+ const index = nextIndex;
138838
+ nextIndex += 1;
138839
+ try {
138840
+ results[index] = await worker(items[index], index);
138841
+ } catch (error) {
138842
+ failures.set(index, error);
138843
+ return;
138844
+ }
138845
+ }
138846
+ };
138847
+ await Promise.all(Array.from({ length: Math.min(width, items.length) }, () => runWorker()));
138848
+ const failedIndex = Math.min(...failures.keys());
138849
+ if (Number.isFinite(failedIndex)) {
138850
+ throw failures.get(failedIndex);
138851
+ }
138852
+ return results;
138853
+ }
138854
+ async function acquireCollectionArtifact(options) {
138855
+ const { role, collectionId, dirName, collectionsDir, prebuiltByRole, postman, core, privateMockAuth = false } = options;
138856
+ const expectedPath = `${collectionsDir}/${dirName}`;
138857
+ const forceCloudExport = privateMockAuth && (role === "smoke" || role === "contract");
138858
+ const entry = prebuiltByRole.get(role);
138859
+ if (entry && !forceCloudExport && tryReusePrebuiltCollection({
138860
+ prepared: entry,
138861
+ expectedPath,
138862
+ expectedCloudId: collectionId
138863
+ })) {
138864
+ core.info(`Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`);
138865
+ return { reusePrebuilt: true };
138866
+ }
138867
+ if (entry) {
138868
+ core.info(forceCloudExport ? `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud` : `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`);
138869
+ }
138870
+ const cloud = forceCloudExport ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
138871
+ return { reusePrebuilt: false, cloudCollection: cloud };
138872
+ }
138797
138873
  async function exportCollectionArtifact(options) {
138798
138874
  const {
138799
- role,
138800
138875
  collectionId,
138801
138876
  dirName,
138802
138877
  collectionsDir,
138803
- prebuiltByRole,
138804
- postman,
138805
- core,
138806
- privateMockAuth = false,
138807
- preparedCloudCollection
138878
+ artifactDir,
138879
+ acquisition
138808
138880
  } = options;
138809
138881
  if (!collectionId) {
138810
138882
  return void 0;
138811
138883
  }
138812
138884
  const expectedPath = `${collectionsDir}/${dirName}`;
138813
- const forceCloudExport = privateMockAuth && (role === "smoke" || role === "contract");
138814
- const entry = prebuiltByRole.get(role);
138815
- if (entry && !forceCloudExport) {
138816
- const reused = tryReusePrebuiltCollection({
138817
- prepared: entry,
138818
- expectedPath,
138819
- expectedCloudId: collectionId
138820
- });
138821
- if (reused) {
138822
- core.info(
138823
- `Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`
138824
- );
138825
- return `../${expectedPath}`;
138826
- }
138827
- core.info(
138828
- `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`
138829
- );
138830
- } else if (entry && forceCloudExport) {
138831
- core.info(
138832
- `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud`
138833
- );
138885
+ if (acquisition.reusePrebuilt) {
138886
+ return `../${expectedPath}`;
138834
138887
  }
138835
- let collectionForExport;
138836
- if (forceCloudExport && preparedCloudCollection) {
138837
- collectionForExport = preparedCloudCollection;
138838
- } else if (forceCloudExport) {
138839
- const col = await postman.getCollection(collectionId);
138840
- const { collection } = applyPrivateMockExportCleanup(col, {
138841
- stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
138842
- });
138843
- if (!verifyPrivateMockRootHook(collection)) {
138844
- throw new Error(
138845
- `PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from exported ${role} collection ${collectionId}`
138846
- );
138847
- }
138848
- collectionForExport = collection;
138849
- } else {
138850
- const col = await postman.getCollection(collectionId);
138851
- collectionForExport = col;
138852
- }
138853
- await convertAndSplitAnyCollection(collectionForExport, expectedPath);
138888
+ assertPathWithinArtifactRoot(expectedPath, artifactDir, "collection target");
138889
+ await convertAndSplitAnyCollection(
138890
+ acquisition.cloudCollection,
138891
+ expectedPath
138892
+ );
138854
138893
  return `../${expectedPath}`;
138855
138894
  }
138856
138895
  function hasControlCharacter2(value) {
@@ -138915,65 +138954,45 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
138915
138954
  ) : void 0;
138916
138955
  const prebuiltByRole = options.preparedPrebuiltCollections;
138917
138956
  const privateMockAuth = options.privateMockAuth === true;
138918
- const preparedPrivateMockCollections = /* @__PURE__ */ new Map();
138919
- if (privateMockAuth) {
138920
- for (const spec of [
138921
- { role: "smoke", collectionId: inputs.smokeCollectionId },
138922
- { role: "contract", collectionId: inputs.contractCollectionId }
138923
- ]) {
138924
- if (!spec.collectionId) {
138925
- continue;
138926
- }
138927
- preparedPrivateMockCollections.set(
138928
- spec.role,
138929
- await preparePrivateMockCloudCollection(
138930
- spec.role,
138931
- spec.collectionId,
138932
- dependencies.postman
138933
- )
138934
- );
138935
- }
138936
- }
138937
- const baselineRef = await exportCollectionArtifact({
138938
- role: "baseline",
138939
- collectionId: inputs.baselineCollectionId,
138940
- dirName: getCollectionDirectoryName("Baseline", assetProjectName),
138941
- collectionsDir,
138942
- prebuiltByRole,
138943
- postman: dependencies.postman,
138944
- core: dependencies.core,
138945
- privateMockAuth
138946
- });
138947
- if (baselineRef) {
138948
- manifestCollections[baselineRef] = inputs.baselineCollectionId;
138949
- }
138950
- const smokeRef = await exportCollectionArtifact({
138951
- role: "smoke",
138952
- collectionId: inputs.smokeCollectionId,
138953
- dirName: getCollectionDirectoryName("Smoke", assetProjectName),
138954
- collectionsDir,
138955
- prebuiltByRole,
138956
- postman: dependencies.postman,
138957
- core: dependencies.core,
138958
- privateMockAuth,
138959
- preparedCloudCollection: preparedPrivateMockCollections.get("smoke")
138960
- });
138961
- if (smokeRef) {
138962
- manifestCollections[smokeRef] = inputs.smokeCollectionId;
138957
+ const collectionSpecs = [
138958
+ { role: "baseline", collectionId: inputs.baselineCollectionId, dirName: getCollectionDirectoryName("Baseline", assetProjectName) },
138959
+ { role: "smoke", collectionId: inputs.smokeCollectionId, dirName: getCollectionDirectoryName("Smoke", assetProjectName) },
138960
+ { role: "contract", collectionId: inputs.contractCollectionId, dirName: getCollectionDirectoryName("Contract", assetProjectName) }
138961
+ ].filter((spec) => Boolean(spec.collectionId));
138962
+ const collectionStartedAt = Date.now();
138963
+ let collectionStatus = "success";
138964
+ let acquisitions;
138965
+ try {
138966
+ acquisitions = await runBoundedInOrder(
138967
+ collectionSpecs,
138968
+ ARTIFACT_ACQUISITION_WIDTH,
138969
+ (spec) => acquireCollectionArtifact({
138970
+ ...spec,
138971
+ collectionsDir,
138972
+ prebuiltByRole,
138973
+ postman: dependencies.postman,
138974
+ core: dependencies.core,
138975
+ privateMockAuth
138976
+ })
138977
+ );
138978
+ } catch (error) {
138979
+ collectionStatus = "failed";
138980
+ throw error;
138981
+ } finally {
138982
+ dependencies.core.info(
138983
+ `collection-acquisition count=${collectionSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - collectionStartedAt} status=${collectionStatus}`
138984
+ );
138963
138985
  }
138964
- const contractRef = await exportCollectionArtifact({
138965
- role: "contract",
138966
- collectionId: inputs.contractCollectionId,
138967
- dirName: getCollectionDirectoryName("Contract", assetProjectName),
138968
- collectionsDir,
138969
- prebuiltByRole,
138970
- postman: dependencies.postman,
138971
- core: dependencies.core,
138972
- privateMockAuth,
138973
- preparedCloudCollection: preparedPrivateMockCollections.get("contract")
138974
- });
138975
- if (contractRef) {
138976
- manifestCollections[contractRef] = inputs.contractCollectionId;
138986
+ for (const [index, spec] of collectionSpecs.entries()) {
138987
+ const ref = await exportCollectionArtifact({
138988
+ ...spec,
138989
+ collectionsDir,
138990
+ artifactDir: inputs.artifactDir,
138991
+ acquisition: acquisitions[index]
138992
+ });
138993
+ if (ref) {
138994
+ manifestCollections[ref] = spec.collectionId;
138995
+ }
138977
138996
  }
138978
138997
  ensureDir(collectionsDir);
138979
138998
  ensureDir(environmentsDir);
@@ -138992,17 +139011,40 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
138992
139011
  ensureDir(ciDir);
138993
139012
  }
138994
139013
  }
138995
- for (const [envName, envUid] of Object.entries(envUids)) {
138996
- writeJsonFile(
138997
- `${environmentsDir}/${envName}.postman_environment.json`,
138998
- await dependencies.postman.getEnvironment(envUid),
138999
- true
139014
+ const environmentSpecs = [
139015
+ ...Object.entries(envUids).map(([envName, envUid]) => ({
139016
+ envName,
139017
+ envUid,
139018
+ filePath: `${environmentsDir}/${envName}.postman_environment.json`
139019
+ })),
139020
+ ...options.mockEnvironmentUid ? [{
139021
+ envName: "manual-validation",
139022
+ envUid: options.mockEnvironmentUid,
139023
+ filePath: `${mocksDir}/manual-validation.postman_environment.json`
139024
+ }] : []
139025
+ ];
139026
+ const environmentStartedAt = Date.now();
139027
+ let environmentStatus = "success";
139028
+ let environmentPayloads;
139029
+ try {
139030
+ environmentPayloads = await runBoundedInOrder(
139031
+ environmentSpecs,
139032
+ ARTIFACT_ACQUISITION_WIDTH,
139033
+ (spec) => dependencies.postman.getEnvironment(spec.envUid)
139034
+ );
139035
+ } catch (error) {
139036
+ environmentStatus = "failed";
139037
+ throw error;
139038
+ } finally {
139039
+ dependencies.core.info(
139040
+ `environment-artifact-acquisition count=${environmentSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - environmentStartedAt} status=${environmentStatus}`
139000
139041
  );
139001
139042
  }
139002
- if (options.mockEnvironmentUid) {
139043
+ for (const [index, spec] of environmentSpecs.entries()) {
139044
+ assertPathWithinCwd(spec.filePath, "environment target");
139003
139045
  writeJsonFile(
139004
- `${mocksDir}/manual-validation.postman_environment.json`,
139005
- await dependencies.postman.getEnvironment(options.mockEnvironmentUid),
139046
+ spec.filePath,
139047
+ environmentPayloads[index],
139006
139048
  true
139007
139049
  );
139008
139050
  }
@@ -139012,6 +139054,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139012
139054
  workspaceLinkEnabled: inputs.workspaceLinkEnabled,
139013
139055
  workspaceLinkStatus: options.workspaceLinkStatus
139014
139056
  });
139057
+ assertPathWithinCwd(".postman/resources.yaml", "resources state target");
139015
139058
  (0, import_node_fs5.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
139016
139059
  durableWorkspaceId,
139017
139060
  manifestCollections,
@@ -139030,6 +139073,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
139030
139073
  } catch {
139031
139074
  existingWorkflows = void 0;
139032
139075
  }
139076
+ assertPathWithinCwd(".postman/workflows.yaml", "workflows state target");
139033
139077
  (0, import_node_fs5.writeFileSync)(
139034
139078
  ".postman/workflows.yaml",
139035
139079
  buildSpecCollectionWorkflowManifest(
@@ -139079,18 +139123,19 @@ function createRepoSummary(outputs, envUids, pushed) {
139079
139123
  }
139080
139124
  async function commitAndPushGeneratedFiles(inputs, dependencies) {
139081
139125
  if (inputs.generateCiWorkflow) {
139082
- assertPathWithinCwd(inputs.ciWorkflowPath, "ci-workflow-path");
139083
139126
  const ciWorkflow = renderCiWorkflow(inputs);
139084
139127
  const parts = inputs.ciWorkflowPath.split("/");
139085
139128
  if (parts.length > 1) {
139086
139129
  const dir = parts.slice(0, -1).join("/");
139087
139130
  ensureDir(dir);
139088
139131
  }
139132
+ assertPathWithinCwd(inputs.ciWorkflowPath, "ci-workflow-path");
139089
139133
  (0, import_node_fs5.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
139090
139134
  if (inputs.provider === "github" || inputs.provider === "unknown") {
139091
139135
  const gcPath = ".github/workflows/postman-preview-gc.yml";
139092
139136
  if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
139093
139137
  ensureDir(".github/workflows");
139138
+ assertPathWithinCwd(gcPath, "preview GC workflow path");
139094
139139
  (0, import_node_fs5.writeFileSync)(gcPath, renderGcWorkflowTemplate());
139095
139140
  }
139096
139141
  }
package/dist/index.cjs CHANGED
@@ -140578,6 +140578,10 @@ var PREBUILT_COLLECTION_ROLES = /* @__PURE__ */ new Set([
140578
140578
  ]);
140579
140579
  var SHA256_HEX = /^[a-f0-9]{64}$/;
140580
140580
  var PREBUILT_CLOUD_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
140581
+ var PREBUILT_COLLECTION_MAX_DEPTH = 128;
140582
+ var PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES = LOCAL_SPEC_DISCOVERY_MAX_TRAVERSAL_ENTRIES;
140583
+ var PREBUILT_COLLECTION_MAX_FILE_BYTES = 32 * 1024 * 1024;
140584
+ var PREBUILT_COLLECTION_MAX_TOTAL_BYTES = 100 * 1024 * 1024;
140581
140585
  function failPrebuiltCollections(detail) {
140582
140586
  throw new Error(`CONTRACT_PREBUILT_COLLECTIONS_INVALID: ${detail}`);
140583
140587
  }
@@ -140689,8 +140693,9 @@ function assertPathWithinArtifactRoot(targetPath, artifactDir, fieldName) {
140689
140693
  existingPath = parent;
140690
140694
  }
140691
140695
  const realExisting = (0, import_node_fs5.realpathSync)(existingPath);
140692
- const realRelative = path8.relative(artifactRoot, realExisting);
140693
- if (realRelative.startsWith("..") || path8.isAbsolute(realRelative)) {
140696
+ const realArtifactRoot = (0, import_node_fs5.existsSync)(artifactRoot) ? (0, import_node_fs5.realpathSync)(artifactRoot) : void 0;
140697
+ const realRelative = realArtifactRoot ? path8.relative(realArtifactRoot, realExisting) : "";
140698
+ if (realArtifactRoot && (realRelative.startsWith("..") || path8.isAbsolute(realRelative))) {
140694
140699
  failPrebuiltCollections(
140695
140700
  `${fieldName} resolves outside artifact-dir via symlink; received ${targetPath}`
140696
140701
  );
@@ -140732,13 +140737,16 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140732
140737
  return [];
140733
140738
  }
140734
140739
  const files = [];
140735
- const pendingDirectories = [absRoot];
140740
+ const pendingDirectories = [{ absolute: absRoot, depth: 0 }];
140736
140741
  const seenDirectories = /* @__PURE__ */ new Set();
140742
+ let traversalEntries = 1;
140743
+ let totalBytes = 0;
140737
140744
  while (pendingDirectories.length > 0) {
140738
- const currentAbsolute = pendingDirectories.pop();
140739
- if (!currentAbsolute) {
140745
+ const current = pendingDirectories.pop();
140746
+ if (!current) {
140740
140747
  break;
140741
140748
  }
140749
+ const { absolute: currentAbsolute, depth: currentDepth } = current;
140742
140750
  const currentStat = (0, import_node_fs5.lstatSync)(currentAbsolute);
140743
140751
  if (currentStat.isSymbolicLink() || !currentStat.isDirectory()) {
140744
140752
  failPrebuiltCollections(
@@ -140752,8 +140760,16 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140752
140760
  );
140753
140761
  }
140754
140762
  seenDirectories.add(currentKey);
140755
- const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true });
140763
+ const entries = (0, import_node_fs5.readdirSync)(currentAbsolute, { withFileTypes: true }).sort(
140764
+ (left, right) => left.name.localeCompare(right.name)
140765
+ );
140756
140766
  for (const entry of entries) {
140767
+ traversalEntries += 1;
140768
+ if (traversalEntries > PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES) {
140769
+ failPrebuiltCollections(
140770
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_TRAVERSAL_ENTRIES} traversal-entry budget`
140771
+ );
140772
+ }
140757
140773
  const abs = path8.join(currentAbsolute, entry.name);
140758
140774
  if (entry.isSymbolicLink()) {
140759
140775
  failPrebuiltCollections(
@@ -140761,7 +140777,13 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140761
140777
  );
140762
140778
  }
140763
140779
  if (entry.isDirectory()) {
140764
- pendingDirectories.push(abs);
140780
+ const nextDepth = currentDepth + 1;
140781
+ if (nextDepth > PREBUILT_COLLECTION_MAX_DEPTH) {
140782
+ failPrebuiltCollections(
140783
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_DEPTH} directory-depth budget`
140784
+ );
140785
+ }
140786
+ pendingDirectories.push({ absolute: abs, depth: nextDepth });
140765
140787
  continue;
140766
140788
  }
140767
140789
  if (!entry.isFile()) {
@@ -140775,6 +140797,17 @@ function listPrebuiltCollectionTreeFiles(collectionPath, artifactDir) {
140775
140797
  `prebuilt collection tree file changed or became unsupported at ${normalizeToPosix(path8.relative(absRoot, abs))}`
140776
140798
  );
140777
140799
  }
140800
+ if (fileLstat.size > PREBUILT_COLLECTION_MAX_FILE_BYTES) {
140801
+ failPrebuiltCollections(
140802
+ `prebuilt collection tree file ${normalizeToPosix(path8.relative(absRoot, abs))} exceeds the ${PREBUILT_COLLECTION_MAX_FILE_BYTES / (1024 * 1024)} MiB individual-file budget`
140803
+ );
140804
+ }
140805
+ totalBytes += fileLstat.size;
140806
+ if (totalBytes > PREBUILT_COLLECTION_MAX_TOTAL_BYTES) {
140807
+ failPrebuiltCollections(
140808
+ `prebuilt collection tree exceeded the ${PREBUILT_COLLECTION_MAX_TOTAL_BYTES / (1024 * 1024)} MiB total-byte budget`
140809
+ );
140810
+ }
140778
140811
  files.push({
140779
140812
  absolute: abs,
140780
140813
  relative: normalizeToPosix(path8.relative(absRoot, abs)),
@@ -140909,63 +140942,69 @@ async function preparePrivateMockCloudCollection(role, collectionId, postman) {
140909
140942
  }
140910
140943
  return collection;
140911
140944
  }
140945
+ var ARTIFACT_ACQUISITION_WIDTH = 2;
140946
+ async function runBoundedInOrder(items, width, worker) {
140947
+ const results = new Array(items.length);
140948
+ let nextIndex = 0;
140949
+ const failures = /* @__PURE__ */ new Map();
140950
+ const runWorker = async () => {
140951
+ while (failures.size === 0 && nextIndex < items.length) {
140952
+ const index = nextIndex;
140953
+ nextIndex += 1;
140954
+ try {
140955
+ results[index] = await worker(items[index], index);
140956
+ } catch (error2) {
140957
+ failures.set(index, error2);
140958
+ return;
140959
+ }
140960
+ }
140961
+ };
140962
+ await Promise.all(Array.from({ length: Math.min(width, items.length) }, () => runWorker()));
140963
+ const failedIndex = Math.min(...failures.keys());
140964
+ if (Number.isFinite(failedIndex)) {
140965
+ throw failures.get(failedIndex);
140966
+ }
140967
+ return results;
140968
+ }
140969
+ async function acquireCollectionArtifact(options) {
140970
+ const { role, collectionId, dirName, collectionsDir, prebuiltByRole, postman, core, privateMockAuth = false } = options;
140971
+ const expectedPath = `${collectionsDir}/${dirName}`;
140972
+ const forceCloudExport = privateMockAuth && (role === "smoke" || role === "contract");
140973
+ const entry = prebuiltByRole.get(role);
140974
+ if (entry && !forceCloudExport && tryReusePrebuiltCollection({
140975
+ prepared: entry,
140976
+ expectedPath,
140977
+ expectedCloudId: collectionId
140978
+ })) {
140979
+ core.info(`Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`);
140980
+ return { reusePrebuilt: true };
140981
+ }
140982
+ if (entry) {
140983
+ core.info(forceCloudExport ? `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud` : `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`);
140984
+ }
140985
+ const cloud = forceCloudExport ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
140986
+ return { reusePrebuilt: false, cloudCollection: cloud };
140987
+ }
140912
140988
  async function exportCollectionArtifact(options) {
140913
140989
  const {
140914
- role,
140915
140990
  collectionId,
140916
140991
  dirName,
140917
140992
  collectionsDir,
140918
- prebuiltByRole,
140919
- postman,
140920
- core,
140921
- privateMockAuth = false,
140922
- preparedCloudCollection
140993
+ artifactDir,
140994
+ acquisition
140923
140995
  } = options;
140924
140996
  if (!collectionId) {
140925
140997
  return void 0;
140926
140998
  }
140927
140999
  const expectedPath = `${collectionsDir}/${dirName}`;
140928
- const forceCloudExport = privateMockAuth && (role === "smoke" || role === "contract");
140929
- const entry = prebuiltByRole.get(role);
140930
- if (entry && !forceCloudExport) {
140931
- const reused = tryReusePrebuiltCollection({
140932
- prepared: entry,
140933
- expectedPath,
140934
- expectedCloudId: collectionId
140935
- });
140936
- if (reused) {
140937
- core.info(
140938
- `Reusing prebuilt ${role} collection tree at ${expectedPath} (artifactDigest match)`
140939
- );
140940
- return `../${expectedPath}`;
140941
- }
140942
- core.info(
140943
- `Prebuilt ${role} collection entry present but did not exactly match; exporting from cloud`
140944
- );
140945
- } else if (entry && forceCloudExport) {
140946
- core.info(
140947
- `Private mock requires cloud export for ${role} collection to reconcile managed root hook; exporting from cloud`
140948
- );
141000
+ if (acquisition.reusePrebuilt) {
141001
+ return `../${expectedPath}`;
140949
141002
  }
140950
- let collectionForExport;
140951
- if (forceCloudExport && preparedCloudCollection) {
140952
- collectionForExport = preparedCloudCollection;
140953
- } else if (forceCloudExport) {
140954
- const col = await postman.getCollection(collectionId);
140955
- const { collection } = applyPrivateMockExportCleanup(col, {
140956
- stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
140957
- });
140958
- if (!verifyPrivateMockRootHook(collection)) {
140959
- throw new Error(
140960
- `PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from exported ${role} collection ${collectionId}`
140961
- );
140962
- }
140963
- collectionForExport = collection;
140964
- } else {
140965
- const col = await postman.getCollection(collectionId);
140966
- collectionForExport = col;
140967
- }
140968
- await convertAndSplitAnyCollection(collectionForExport, expectedPath);
141003
+ assertPathWithinArtifactRoot(expectedPath, artifactDir, "collection target");
141004
+ await convertAndSplitAnyCollection(
141005
+ acquisition.cloudCollection,
141006
+ expectedPath
141007
+ );
140969
141008
  return `../${expectedPath}`;
140970
141009
  }
140971
141010
  function hasControlCharacter2(value) {
@@ -141030,65 +141069,45 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141030
141069
  ) : void 0;
141031
141070
  const prebuiltByRole = options.preparedPrebuiltCollections;
141032
141071
  const privateMockAuth = options.privateMockAuth === true;
141033
- const preparedPrivateMockCollections = /* @__PURE__ */ new Map();
141034
- if (privateMockAuth) {
141035
- for (const spec of [
141036
- { role: "smoke", collectionId: inputs.smokeCollectionId },
141037
- { role: "contract", collectionId: inputs.contractCollectionId }
141038
- ]) {
141039
- if (!spec.collectionId) {
141040
- continue;
141041
- }
141042
- preparedPrivateMockCollections.set(
141043
- spec.role,
141044
- await preparePrivateMockCloudCollection(
141045
- spec.role,
141046
- spec.collectionId,
141047
- dependencies.postman
141048
- )
141049
- );
141050
- }
141051
- }
141052
- const baselineRef = await exportCollectionArtifact({
141053
- role: "baseline",
141054
- collectionId: inputs.baselineCollectionId,
141055
- dirName: getCollectionDirectoryName("Baseline", assetProjectName),
141056
- collectionsDir,
141057
- prebuiltByRole,
141058
- postman: dependencies.postman,
141059
- core: dependencies.core,
141060
- privateMockAuth
141061
- });
141062
- if (baselineRef) {
141063
- manifestCollections[baselineRef] = inputs.baselineCollectionId;
141064
- }
141065
- const smokeRef = await exportCollectionArtifact({
141066
- role: "smoke",
141067
- collectionId: inputs.smokeCollectionId,
141068
- dirName: getCollectionDirectoryName("Smoke", assetProjectName),
141069
- collectionsDir,
141070
- prebuiltByRole,
141071
- postman: dependencies.postman,
141072
- core: dependencies.core,
141073
- privateMockAuth,
141074
- preparedCloudCollection: preparedPrivateMockCollections.get("smoke")
141075
- });
141076
- if (smokeRef) {
141077
- manifestCollections[smokeRef] = inputs.smokeCollectionId;
141072
+ const collectionSpecs = [
141073
+ { role: "baseline", collectionId: inputs.baselineCollectionId, dirName: getCollectionDirectoryName("Baseline", assetProjectName) },
141074
+ { role: "smoke", collectionId: inputs.smokeCollectionId, dirName: getCollectionDirectoryName("Smoke", assetProjectName) },
141075
+ { role: "contract", collectionId: inputs.contractCollectionId, dirName: getCollectionDirectoryName("Contract", assetProjectName) }
141076
+ ].filter((spec) => Boolean(spec.collectionId));
141077
+ const collectionStartedAt = Date.now();
141078
+ let collectionStatus = "success";
141079
+ let acquisitions;
141080
+ try {
141081
+ acquisitions = await runBoundedInOrder(
141082
+ collectionSpecs,
141083
+ ARTIFACT_ACQUISITION_WIDTH,
141084
+ (spec) => acquireCollectionArtifact({
141085
+ ...spec,
141086
+ collectionsDir,
141087
+ prebuiltByRole,
141088
+ postman: dependencies.postman,
141089
+ core: dependencies.core,
141090
+ privateMockAuth
141091
+ })
141092
+ );
141093
+ } catch (error2) {
141094
+ collectionStatus = "failed";
141095
+ throw error2;
141096
+ } finally {
141097
+ dependencies.core.info(
141098
+ `collection-acquisition count=${collectionSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - collectionStartedAt} status=${collectionStatus}`
141099
+ );
141078
141100
  }
141079
- const contractRef = await exportCollectionArtifact({
141080
- role: "contract",
141081
- collectionId: inputs.contractCollectionId,
141082
- dirName: getCollectionDirectoryName("Contract", assetProjectName),
141083
- collectionsDir,
141084
- prebuiltByRole,
141085
- postman: dependencies.postman,
141086
- core: dependencies.core,
141087
- privateMockAuth,
141088
- preparedCloudCollection: preparedPrivateMockCollections.get("contract")
141089
- });
141090
- if (contractRef) {
141091
- manifestCollections[contractRef] = inputs.contractCollectionId;
141101
+ for (const [index, spec] of collectionSpecs.entries()) {
141102
+ const ref = await exportCollectionArtifact({
141103
+ ...spec,
141104
+ collectionsDir,
141105
+ artifactDir: inputs.artifactDir,
141106
+ acquisition: acquisitions[index]
141107
+ });
141108
+ if (ref) {
141109
+ manifestCollections[ref] = spec.collectionId;
141110
+ }
141092
141111
  }
141093
141112
  ensureDir(collectionsDir);
141094
141113
  ensureDir(environmentsDir);
@@ -141107,17 +141126,40 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141107
141126
  ensureDir(ciDir);
141108
141127
  }
141109
141128
  }
141110
- for (const [envName, envUid] of Object.entries(envUids)) {
141111
- writeJsonFile(
141112
- `${environmentsDir}/${envName}.postman_environment.json`,
141113
- await dependencies.postman.getEnvironment(envUid),
141114
- true
141129
+ const environmentSpecs = [
141130
+ ...Object.entries(envUids).map(([envName, envUid]) => ({
141131
+ envName,
141132
+ envUid,
141133
+ filePath: `${environmentsDir}/${envName}.postman_environment.json`
141134
+ })),
141135
+ ...options.mockEnvironmentUid ? [{
141136
+ envName: "manual-validation",
141137
+ envUid: options.mockEnvironmentUid,
141138
+ filePath: `${mocksDir}/manual-validation.postman_environment.json`
141139
+ }] : []
141140
+ ];
141141
+ const environmentStartedAt = Date.now();
141142
+ let environmentStatus = "success";
141143
+ let environmentPayloads;
141144
+ try {
141145
+ environmentPayloads = await runBoundedInOrder(
141146
+ environmentSpecs,
141147
+ ARTIFACT_ACQUISITION_WIDTH,
141148
+ (spec) => dependencies.postman.getEnvironment(spec.envUid)
141149
+ );
141150
+ } catch (error2) {
141151
+ environmentStatus = "failed";
141152
+ throw error2;
141153
+ } finally {
141154
+ dependencies.core.info(
141155
+ `environment-artifact-acquisition count=${environmentSpecs.length} width=${ARTIFACT_ACQUISITION_WIDTH} ms=${Date.now() - environmentStartedAt} status=${environmentStatus}`
141115
141156
  );
141116
141157
  }
141117
- if (options.mockEnvironmentUid) {
141158
+ for (const [index, spec] of environmentSpecs.entries()) {
141159
+ assertPathWithinCwd(spec.filePath, "environment target");
141118
141160
  writeJsonFile(
141119
- `${mocksDir}/manual-validation.postman_environment.json`,
141120
- await dependencies.postman.getEnvironment(options.mockEnvironmentUid),
141161
+ spec.filePath,
141162
+ environmentPayloads[index],
141121
141163
  true
141122
141164
  );
141123
141165
  }
@@ -141127,6 +141169,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141127
141169
  workspaceLinkEnabled: inputs.workspaceLinkEnabled,
141128
141170
  workspaceLinkStatus: options.workspaceLinkStatus
141129
141171
  });
141172
+ assertPathWithinCwd(".postman/resources.yaml", "resources state target");
141130
141173
  (0, import_node_fs5.writeFileSync)(".postman/resources.yaml", buildResourcesManifest(
141131
141174
  durableWorkspaceId,
141132
141175
  manifestCollections,
@@ -141145,6 +141188,7 @@ async function exportArtifacts(inputs, dependencies, envUids, assetProjectName,
141145
141188
  } catch {
141146
141189
  existingWorkflows = void 0;
141147
141190
  }
141191
+ assertPathWithinCwd(".postman/workflows.yaml", "workflows state target");
141148
141192
  (0, import_node_fs5.writeFileSync)(
141149
141193
  ".postman/workflows.yaml",
141150
141194
  buildSpecCollectionWorkflowManifest(
@@ -141194,18 +141238,19 @@ function createRepoSummary(outputs, envUids, pushed) {
141194
141238
  }
141195
141239
  async function commitAndPushGeneratedFiles(inputs, dependencies) {
141196
141240
  if (inputs.generateCiWorkflow) {
141197
- assertPathWithinCwd(inputs.ciWorkflowPath, "ci-workflow-path");
141198
141241
  const ciWorkflow = renderCiWorkflow(inputs);
141199
141242
  const parts = inputs.ciWorkflowPath.split("/");
141200
141243
  if (parts.length > 1) {
141201
141244
  const dir = parts.slice(0, -1).join("/");
141202
141245
  ensureDir(dir);
141203
141246
  }
141247
+ assertPathWithinCwd(inputs.ciWorkflowPath, "ci-workflow-path");
141204
141248
  (0, import_node_fs5.writeFileSync)(inputs.ciWorkflowPath, ciWorkflow);
141205
141249
  if (inputs.provider === "github" || inputs.provider === "unknown") {
141206
141250
  const gcPath = ".github/workflows/postman-preview-gc.yml";
141207
141251
  if (inputs.ciWorkflowPath.endsWith(".github/workflows/ci.yml") || inputs.ciWorkflowPath === ".github/workflows/ci.yml") {
141208
141252
  ensureDir(".github/workflows");
141253
+ assertPathWithinCwd(gcPath, "preview GC workflow path");
141209
141254
  (0, import_node_fs5.writeFileSync)(gcPath, renderGcWorkflowTemplate());
141210
141255
  }
141211
141256
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-repo-sync",
3
- "version": "2.6.4",
3
+ "version": "2.6.5",
4
4
  "description": "Postman repo sync GitHub Action.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",