@postman-cse/onboarding-repo-sync 2.1.8 → 2.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -123219,6 +123219,7 @@ var POSTMAN_ENDPOINT_PROFILES = {
123219
123219
  bifrostBaseUrl: "https://bifrost-premium-https-v4.gw.postman.com",
123220
123220
  fallbackBaseUrl: "https://go.postman.co/_api",
123221
123221
  cliInstallUrl: "https://dl-cli.pstmn.io/install/unix.sh",
123222
+ cliWindowsInstallUrl: "https://dl-cli.pstmn.io/install/win64.ps1",
123222
123223
  iapubBaseUrl: "https://iapub.postman.co"
123223
123224
  },
123224
123225
  beta: {
@@ -123226,6 +123227,7 @@ var POSTMAN_ENDPOINT_PROFILES = {
123226
123227
  bifrostBaseUrl: "https://bifrost-https-v4.gw.postman-beta.com",
123227
123228
  fallbackBaseUrl: "https://go.postman-beta.co/_api",
123228
123229
  cliInstallUrl: "https://dl-cli.pstmn-beta.io/install/unix.sh",
123230
+ cliWindowsInstallUrl: "https://dl-cli.pstmn-beta.io/install/win64.ps1",
123229
123231
  iapubBaseUrl: "https://iapub.postman.co"
123230
123232
  }
123231
123233
  };
@@ -123259,6 +123261,7 @@ function resolvePostmanEndpointProfile(stack, region = "us") {
123259
123261
 
123260
123262
  // src/lib/ci-workflow-template.ts
123261
123263
  var DEFAULT_POSTMAN_CLI_INSTALL_URL = POSTMAN_ENDPOINT_PROFILES.prod.cliInstallUrl;
123264
+ var DEFAULT_POSTMAN_CLI_WINDOWS_INSTALL_URL = POSTMAN_ENDPOINT_PROFILES.prod.cliWindowsInstallUrl;
123262
123265
  function validateHttpsInstallUrl(url) {
123263
123266
  const safeUrlPattern = /^https:\/\/[A-Za-z0-9.-]+\/[A-Za-z0-9._~/?=&%-]+$/;
123264
123267
  if (!safeUrlPattern.test(url)) {
@@ -123275,7 +123278,18 @@ function resolvePostmanRegion(postmanRegionOption) {
123275
123278
  }
123276
123279
  return postmanRegion;
123277
123280
  }
123281
+ function resolveCiRunnerOs(runnerOsOption) {
123282
+ const runnerOs = String(runnerOsOption || "").trim() || "linux";
123283
+ if (runnerOs === "linux" || runnerOs === "windows") {
123284
+ return runnerOs;
123285
+ }
123286
+ throw new Error("ci-runner-os must be one of: linux, windows; got: " + runnerOs);
123287
+ }
123278
123288
  function renderCiWorkflowTemplate(options = {}) {
123289
+ const runnerOs = resolveCiRunnerOs(options.runnerOs);
123290
+ if (runnerOs === "windows") {
123291
+ throw new Error("ci-runner-os=windows is currently supported for azure-devops workflows only");
123292
+ }
123279
123293
  const rawUrl = String(options.postmanCliInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_INSTALL_URL;
123280
123294
  const installUrl = validateHttpsInstallUrl(rawUrl);
123281
123295
  const postmanRegion = resolvePostmanRegion(options.postmanRegion);
@@ -123382,6 +123396,132 @@ function buildCiWorkflowLines(installUrl, postmanRegion) {
123382
123396
  ];
123383
123397
  }
123384
123398
  var CI_WORKFLOW_TEMPLATE = renderCiWorkflowTemplate();
123399
+ function buildAdoWindowsCollectionRunLines(displayName, collectionEnvironmentName) {
123400
+ return [
123401
+ " - pwsh: |",
123402
+ " $ErrorActionPreference = 'Stop'",
123403
+ " function Resolve-AdoOptional([string]$Value) {",
123404
+ " if ($Value -match '^\\$\\([^)]+\\)$') { return '' }",
123405
+ " return $Value",
123406
+ " }",
123407
+ ` $collectionUid = $env:${collectionEnvironmentName}`,
123408
+ " $ciEnvironment = Resolve-AdoOptional $env:CI_ENVIRONMENT",
123409
+ " if ([string]::IsNullOrWhiteSpace($ciEnvironment)) { $ciEnvironment = 'Production' }",
123410
+ ` $arguments = @('collection', 'run', $collectionUid, '-e', $env:POSTMAN_ENVIRONMENT_UID, '--report-events', '--env-var', "CI_ENVIRONMENT=$ciEnvironment")`,
123411
+ " $sslRoot = Join-Path $env:AGENT_TEMPDIRECTORY 'postman-ssl'",
123412
+ " $clientCert = Join-Path $sslRoot 'client.crt'",
123413
+ " $clientKey = Join-Path $sslRoot 'client.key'",
123414
+ " $caCert = Join-Path $sslRoot 'ca.crt'",
123415
+ " if (Test-Path -LiteralPath $clientCert) {",
123416
+ " $arguments += @('--ssl-client-cert', $clientCert, '--ssl-client-key', $clientKey)",
123417
+ " $passphrase = Resolve-AdoOptional $env:POSTMAN_SSL_CLIENT_PASSPHRASE",
123418
+ " if (-not [string]::IsNullOrWhiteSpace($passphrase)) {",
123419
+ " $arguments += @('--ssl-client-passphrase', $passphrase)",
123420
+ " }",
123421
+ " if (Test-Path -LiteralPath $caCert) {",
123422
+ " $arguments += @('--ssl-extra-ca-certs', $caCert)",
123423
+ " }",
123424
+ " }",
123425
+ " & postman @arguments",
123426
+ ` if ($LASTEXITCODE -ne 0) { throw '${displayName} failed with exit code ' + $LASTEXITCODE }`,
123427
+ ` displayName: ${displayName}`,
123428
+ " env:",
123429
+ ` ${collectionEnvironmentName}: $(${collectionEnvironmentName})`,
123430
+ " POSTMAN_ENVIRONMENT_UID: $(POSTMAN_ENVIRONMENT_UID)",
123431
+ " CI_ENVIRONMENT: $(CI_ENVIRONMENT)",
123432
+ " POSTMAN_SSL_CLIENT_PASSPHRASE: $(POSTMAN_SSL_CLIENT_PASSPHRASE)"
123433
+ ];
123434
+ }
123435
+ function buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion) {
123436
+ return [
123437
+ "trigger:",
123438
+ " branches:",
123439
+ " include:",
123440
+ " - main",
123441
+ "schedules:",
123442
+ ' - cron: "0 */6 * * *"',
123443
+ " displayName: Scheduled run",
123444
+ " branches:",
123445
+ " include:",
123446
+ " - main",
123447
+ " always: true",
123448
+ "pool:",
123449
+ " vmImage: windows-latest",
123450
+ "steps:",
123451
+ " - checkout: self",
123452
+ " persistCredentials: true",
123453
+ " - pwsh: |",
123454
+ " $ErrorActionPreference = 'Stop'",
123455
+ " if (-not (Get-Command postman -ErrorAction SilentlyContinue)) {",
123456
+ " [System.Net.ServicePointManager]::SecurityProtocol = 3072",
123457
+ " Invoke-Expression ((New-Object System.Net.WebClient).DownloadString($env:POSTMAN_CLI_INSTALL_URL))",
123458
+ " }",
123459
+ " & postman --version",
123460
+ " if ($LASTEXITCODE -ne 0) { throw 'Postman CLI installation failed' }",
123461
+ " displayName: Install Postman CLI",
123462
+ " env:",
123463
+ ` POSTMAN_CLI_INSTALL_URL: ${installUrl}`,
123464
+ " - pwsh: |",
123465
+ " $ErrorActionPreference = 'Stop'",
123466
+ " $arguments = @('login', '--with-api-key', $env:POSTMAN_API_KEY)",
123467
+ ...postmanRegion === "eu" ? [" $arguments += @('--region', 'eu')"] : [],
123468
+ " & postman @arguments",
123469
+ " if ($LASTEXITCODE -ne 0) { throw 'Postman CLI login failed' }",
123470
+ " displayName: Login to Postman CLI",
123471
+ " env:",
123472
+ " POSTMAN_API_KEY: $(POSTMAN_API_KEY)",
123473
+ " - pwsh: |",
123474
+ " $ErrorActionPreference = 'Stop'",
123475
+ " $section = ''",
123476
+ " $smoke = ''",
123477
+ " $contract = ''",
123478
+ " $environment = ''",
123479
+ " $fallbackEnvironment = ''",
123480
+ " foreach ($line in Get-Content -LiteralPath '.postman/resources.yaml') {",
123481
+ " if ($line -match '^ (collections|environments):\\s*$') { $section = $Matches[1]; continue }",
123482
+ " if ($line -notmatch '^ (.+?):\\s+(.+?)\\s*$') { continue }",
123483
+ ` $key = $Matches[1].Trim().Trim("'").Trim('"')`,
123484
+ ` $value = $Matches[2].Trim().Trim("'").Trim('"')`,
123485
+ " if ($section -eq 'collections' -and $key -match '\\[Smoke\\]') { $smoke = $value }",
123486
+ " if ($section -eq 'collections' -and $key -match '\\[Contract\\]') { $contract = $value }",
123487
+ " if ($section -eq 'environments') {",
123488
+ " if ([string]::IsNullOrWhiteSpace($fallbackEnvironment)) { $fallbackEnvironment = $value }",
123489
+ " if ($key -match 'prod\\.postman_environment\\.json$') { $environment = $value }",
123490
+ " }",
123491
+ " }",
123492
+ " if ([string]::IsNullOrWhiteSpace($environment)) { $environment = $fallbackEnvironment }",
123493
+ " if ([string]::IsNullOrWhiteSpace($smoke)) { throw 'Missing smoke collection UID in .postman/resources.yaml' }",
123494
+ " if ([string]::IsNullOrWhiteSpace($contract)) { throw 'Missing contract collection UID in .postman/resources.yaml' }",
123495
+ " if ([string]::IsNullOrWhiteSpace($environment)) { throw 'Missing environment UID in .postman/resources.yaml' }",
123496
+ ' Write-Host "##vso[task.setvariable variable=POSTMAN_SMOKE_COLLECTION_UID]$smoke"',
123497
+ ' Write-Host "##vso[task.setvariable variable=POSTMAN_CONTRACT_COLLECTION_UID]$contract"',
123498
+ ' Write-Host "##vso[task.setvariable variable=POSTMAN_ENVIRONMENT_UID]$environment"',
123499
+ " displayName: Resolve Postman Resource IDs",
123500
+ " - pwsh: |",
123501
+ " $ErrorActionPreference = 'Stop'",
123502
+ " function Resolve-AdoOptional([string]$Value) {",
123503
+ " if ($Value -match '^\\$\\([^)]+\\)$') { return '' }",
123504
+ " return $Value",
123505
+ " }",
123506
+ " $sslRoot = Join-Path $env:AGENT_TEMPDIRECTORY 'postman-ssl'",
123507
+ " New-Item -ItemType Directory -Path $sslRoot -Force | Out-Null",
123508
+ " [IO.File]::WriteAllBytes((Join-Path $sslRoot 'client.crt'), [Convert]::FromBase64String($env:POSTMAN_SSL_CLIENT_CERT_B64))",
123509
+ " [IO.File]::WriteAllBytes((Join-Path $sslRoot 'client.key'), [Convert]::FromBase64String($env:POSTMAN_SSL_CLIENT_KEY_B64))",
123510
+ " $extraCa = Resolve-AdoOptional $env:POSTMAN_SSL_EXTRA_CA_CERTS_B64",
123511
+ " if (-not [string]::IsNullOrWhiteSpace($extraCa)) {",
123512
+ " [IO.File]::WriteAllBytes((Join-Path $sslRoot 'ca.crt'), [Convert]::FromBase64String($extraCa))",
123513
+ " }",
123514
+ " condition: ne(variables['POSTMAN_SSL_CLIENT_CERT_B64'], '')",
123515
+ " displayName: Decode SSL certificates",
123516
+ " env:",
123517
+ " POSTMAN_SSL_CLIENT_CERT_B64: $(POSTMAN_SSL_CLIENT_CERT_B64)",
123518
+ " POSTMAN_SSL_CLIENT_KEY_B64: $(POSTMAN_SSL_CLIENT_KEY_B64)",
123519
+ " POSTMAN_SSL_EXTRA_CA_CERTS_B64: $(POSTMAN_SSL_EXTRA_CA_CERTS_B64)",
123520
+ ...buildAdoWindowsCollectionRunLines("Run Smoke Tests", "POSTMAN_SMOKE_COLLECTION_UID"),
123521
+ ...buildAdoWindowsCollectionRunLines("Run Contract Tests", "POSTMAN_CONTRACT_COLLECTION_UID"),
123522
+ ""
123523
+ ];
123524
+ }
123385
123525
  function buildAdoCiWorkflowLines(installUrl, postmanRegion) {
123386
123526
  return [
123387
123527
  "trigger:",
@@ -123561,10 +123701,12 @@ function renderGcWorkflowTemplate() {
123561
123701
  }
123562
123702
  var GC_WORKFLOW_TEMPLATE = renderGcWorkflowTemplate();
123563
123703
  function getCiWorkflowTemplate(provider, options = {}) {
123704
+ const runnerOs = resolveCiRunnerOs(options.runnerOs);
123564
123705
  if (provider === "azure-devops") {
123565
- const rawUrl = String(options.postmanCliInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_INSTALL_URL;
123706
+ const rawUrl = runnerOs === "windows" ? String(options.postmanCliWindowsInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_WINDOWS_INSTALL_URL : String(options.postmanCliInstallUrl || "").trim() || DEFAULT_POSTMAN_CLI_INSTALL_URL;
123566
123707
  const postmanRegion = resolvePostmanRegion(options.postmanRegion);
123567
- return buildAdoCiWorkflowLines(validateHttpsInstallUrl(rawUrl), postmanRegion).join("\n");
123708
+ const installUrl = validateHttpsInstallUrl(rawUrl);
123709
+ return (runnerOs === "windows" ? buildAdoWindowsCiWorkflowLines(installUrl, postmanRegion) : buildAdoCiWorkflowLines(installUrl, postmanRegion)).join("\n");
123568
123710
  }
123569
123711
  return renderCiWorkflowTemplate(options);
123570
123712
  }
@@ -124959,6 +125101,17 @@ var BifrostInternalIntegrationAdapter = class {
124959
125101
  mask: this.secretMasker
124960
125102
  };
124961
125103
  }
125104
+ /**
125105
+ * One-line non-fatal preflight reason: operation + entity (repo/path) + cause +
125106
+ * operator action. Secrets are redacted via secretMasker, then CR/LF and other
125107
+ * line-breaking whitespace are collapsed to spaces so CI logs stay one line.
125108
+ * Display-only: does not alter request repoUrl/path or probe classification.
125109
+ */
125110
+ unknownFilesystemLookupReason(repoUrl, fsPath, cause) {
125111
+ return this.secretMasker(
125112
+ `filesystem lookup for repository ${repoUrl} path ${fsPath} ${cause}; verify Bifrost connectivity/credentials then rerun`
125113
+ ).replace(/[\r\n\v\f\u2028\u2029]+/g, " ");
125114
+ }
124962
125115
  async associateSystemEnvironments(workspaceId, associations) {
124963
125116
  if (associations.length === 0) {
124964
125117
  return;
@@ -125029,7 +125182,11 @@ var BifrostInternalIntegrationAdapter = class {
125029
125182
  } catch {
125030
125183
  return {
125031
125184
  state: "unknown",
125032
- reason: `filesystem lookup returned non-JSON body (HTTP ${response.status})`
125185
+ reason: this.unknownFilesystemLookupReason(
125186
+ repoUrl,
125187
+ fsPath,
125188
+ `returned non-JSON body (HTTP ${response.status})`
125189
+ )
125033
125190
  };
125034
125191
  }
125035
125192
  const errorMetaWorkspaceId = typeof parsed?.error?.meta?.workspaceId === "string" && parsed.error.meta.workspaceId.trim() ? parsed.error.meta.workspaceId.trim() : void 0;
@@ -125044,7 +125201,11 @@ var BifrostInternalIntegrationAdapter = class {
125044
125201
  if (!id) {
125045
125202
  return {
125046
125203
  state: "unknown",
125047
- reason: "filesystem lookup returned 200 without a workspace id"
125204
+ reason: this.unknownFilesystemLookupReason(
125205
+ repoUrl,
125206
+ fsPath,
125207
+ "returned 200 without a workspace id"
125208
+ )
125048
125209
  };
125049
125210
  }
125050
125211
  const name = typeof parsed.data.name === "string" && parsed.data.name.trim() ? parsed.data.name.trim() : void 0;
@@ -125062,17 +125223,30 @@ var BifrostInternalIntegrationAdapter = class {
125062
125223
  }
125063
125224
  return {
125064
125225
  state: "unknown",
125065
- reason: "filesystem lookup returned 403 without error.meta.workspaceId"
125226
+ reason: this.unknownFilesystemLookupReason(
125227
+ repoUrl,
125228
+ fsPath,
125229
+ "returned 403 without error.meta.workspaceId"
125230
+ )
125066
125231
  };
125067
125232
  }
125068
125233
  return {
125069
125234
  state: "unknown",
125070
- reason: `filesystem lookup returned HTTP ${response.status}`
125235
+ reason: this.unknownFilesystemLookupReason(
125236
+ repoUrl,
125237
+ fsPath,
125238
+ `returned HTTP ${response.status}`
125239
+ )
125071
125240
  };
125072
125241
  } catch (error) {
125242
+ const cause = error instanceof Error ? error.message : String(error);
125073
125243
  return {
125074
125244
  state: "unknown",
125075
- reason: error instanceof Error ? error.message : String(error)
125245
+ reason: this.unknownFilesystemLookupReason(
125246
+ repoUrl,
125247
+ fsPath,
125248
+ `failed: ${cause}`
125249
+ )
125076
125250
  };
125077
125251
  }
125078
125252
  }
@@ -125286,6 +125460,12 @@ var postmanRepoSyncActionContract = {
125286
125460
  required: false,
125287
125461
  default: ".github/workflows/ci.yml"
125288
125462
  },
125463
+ "ci-runner-os": {
125464
+ description: "Runner operating system for the generated CI workflow.",
125465
+ required: false,
125466
+ default: "linux",
125467
+ allowedValues: ["linux", "windows"]
125468
+ },
125289
125469
  "project-name": {
125290
125470
  description: "Service project name used for environment, mock, and monitor naming.",
125291
125471
  required: true
@@ -126945,6 +127125,25 @@ function parseAssetMarker(description) {
126945
127125
  }
126946
127126
 
126947
127127
  // src/index.ts
127128
+ var identitySecretMasker = (input) => input;
127129
+ function resolveRepoSyncMasker(dependencies) {
127130
+ return dependencies.secretMasker ?? identitySecretMasker;
127131
+ }
127132
+ function causeText(cause) {
127133
+ return cause instanceof Error ? cause.message : String(cause);
127134
+ }
127135
+ function toOneLineDisplay(value) {
127136
+ return String(value ?? "").replace(/[\r\n\u0085\u2028\u2029\v\f]+/g, " ").replace(/[ \t]{2,}/g, " ").trim();
127137
+ }
127138
+ function formatOrchestrationIssue(params) {
127139
+ const operation = toOneLineDisplay(params.mask(params.operation));
127140
+ const entity = toOneLineDisplay(params.mask(params.entity));
127141
+ const maskedCause = toOneLineDisplay(params.mask(causeText(params.cause)));
127142
+ const detail = toOneLineDisplay(params.mask(params.detail ?? ""));
127143
+ const remediation = toOneLineDisplay(params.mask(params.remediation));
127144
+ const body = `${operation} failed for ${entity}: ${maskedCause}${detail}`.replace(/[.]+$/u, "");
127145
+ return toOneLineDisplay(`${body}. ${remediation}`);
127146
+ }
126948
127147
  function parseBooleanInput(value, defaultValue) {
126949
127148
  const normalized = String(value || "").trim().toLowerCase();
126950
127149
  if (!normalized) return defaultValue;
@@ -127041,6 +127240,17 @@ function parseBranchStrategy(value) {
127041
127240
  `Unsupported branch-strategy "${normalized}". Supported values: ${allowed.join(", ")}`
127042
127241
  );
127043
127242
  }
127243
+ function parseCiRunnerOs(value) {
127244
+ const definition = postmanRepoSyncActionContract.inputs["ci-runner-os"];
127245
+ const allowed = definition.allowedValues ?? [];
127246
+ const normalized = String(value || "").trim() || (definition.default ?? "linux");
127247
+ if (allowed.includes(normalized)) {
127248
+ return normalized;
127249
+ }
127250
+ throw new Error(
127251
+ `Unsupported ci-runner-os "${normalized}". Supported values: ${allowed.join(", ")}`
127252
+ );
127253
+ }
127044
127254
  function normalizeReleaseLabel(value) {
127045
127255
  const cleaned = normalizeInputValue(value).replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
127046
127256
  return cleaned;
@@ -127118,6 +127328,7 @@ function resolveInputs(env = process.env) {
127118
127328
  provider: repoContext.provider,
127119
127329
  ciWorkflowBase64: getInput("ci-workflow-base64", env),
127120
127330
  generateCiWorkflow: parseBooleanInput(getInput("generate-ci-workflow", env), true),
127331
+ ciRunnerOs: parseCiRunnerOs(getInput("ci-runner-os", env)),
127121
127332
  monitorType: getInput("monitor-type", env) || "cloud",
127122
127333
  ciWorkflowPath: getInput("ci-workflow-path", env) || (repoContext.provider === "azure-devops" ? "azure-pipelines.yml" : ".github/workflows/ci.yml"),
127123
127334
  orgMode: parseBooleanInput(getInput("org-mode", env), false),
@@ -127136,6 +127347,7 @@ function resolveInputs(env = process.env) {
127136
127347
  postmanBifrostBase: endpointProfile.bifrostBaseUrl,
127137
127348
  postmanFallbackBase: endpointProfile.fallbackBaseUrl,
127138
127349
  postmanCliInstallUrl: endpointProfile.cliInstallUrl,
127350
+ postmanCliWindowsInstallUrl: endpointProfile.cliWindowsInstallUrl,
127139
127351
  postmanIapubBase: endpointProfile.iapubBaseUrl
127140
127352
  };
127141
127353
  }
@@ -127384,19 +127596,34 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
127384
127596
  if (!inputs.workspaceId) {
127385
127597
  return envUids;
127386
127598
  }
127599
+ const mask = resolveRepoSyncMasker(dependencies);
127600
+ const envRemediation = "verify access-token/team/workspace permissions then rerun";
127387
127601
  for (const envName of inputs.environments) {
127388
127602
  const runtimeUrl = String(inputs.envRuntimeUrls[envName] || "").trim();
127389
127603
  const displayName = `${inputs.projectName} - ${envName}`;
127390
127604
  let existingUid = String(envUids[envName] || "").trim();
127391
127605
  if (!existingUid) {
127392
- const discovered = await dependencies.postman.findEnvironmentByName(
127393
- inputs.workspaceId,
127394
- displayName
127395
- );
127396
- if (discovered?.uid) {
127397
- existingUid = discovered.uid;
127398
- dependencies.core.info(
127399
- `Discovered existing environment for ${displayName}: ${existingUid}`
127606
+ try {
127607
+ const discovered = await dependencies.postman.findEnvironmentByName(
127608
+ inputs.workspaceId,
127609
+ displayName
127610
+ );
127611
+ if (discovered?.uid) {
127612
+ existingUid = discovered.uid;
127613
+ dependencies.core.info(
127614
+ `Discovered existing environment for ${displayName}: ${existingUid}`
127615
+ );
127616
+ }
127617
+ } catch (error) {
127618
+ throw new Error(
127619
+ formatOrchestrationIssue({
127620
+ operation: "Environment discovery",
127621
+ entity: `workspace ${inputs.workspaceId} environment "${displayName}"`,
127622
+ cause: error,
127623
+ remediation: envRemediation,
127624
+ mask
127625
+ }),
127626
+ { cause: error }
127400
127627
  );
127401
127628
  }
127402
127629
  }
@@ -127416,17 +127643,43 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
127416
127643
  }
127417
127644
  const values2 = buildEnvironmentValues(envName, runtimeUrl);
127418
127645
  if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
127419
- await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
127646
+ try {
127647
+ await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
127648
+ } catch (error) {
127649
+ throw new Error(
127650
+ formatOrchestrationIssue({
127651
+ operation: "Environment update",
127652
+ entity: `workspace ${inputs.workspaceId} environment "${displayName}" (uid ${existingUid})`,
127653
+ cause: error,
127654
+ remediation: envRemediation,
127655
+ mask
127656
+ }),
127657
+ { cause: error }
127658
+ );
127659
+ }
127420
127660
  envUids[envName] = existingUid;
127421
127661
  continue;
127422
127662
  }
127423
127663
  const values = buildEnvironmentValues(envName, runtimeUrl);
127424
127664
  if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
127425
- envUids[envName] = await dependencies.postman.createEnvironment(
127426
- inputs.workspaceId,
127427
- displayName,
127428
- values
127429
- );
127665
+ try {
127666
+ envUids[envName] = await dependencies.postman.createEnvironment(
127667
+ inputs.workspaceId,
127668
+ displayName,
127669
+ values
127670
+ );
127671
+ } catch (error) {
127672
+ throw new Error(
127673
+ formatOrchestrationIssue({
127674
+ operation: "Environment create",
127675
+ entity: `workspace ${inputs.workspaceId} environment "${displayName}"`,
127676
+ cause: error,
127677
+ remediation: envRemediation,
127678
+ mask
127679
+ }),
127680
+ { cause: error }
127681
+ );
127682
+ }
127430
127683
  }
127431
127684
  return envUids;
127432
127685
  }
@@ -127683,11 +127936,15 @@ function renderCiWorkflow(inputs) {
127683
127936
  if (inputs.provider === "azure-devops") {
127684
127937
  return getCiWorkflowTemplate(inputs.provider, {
127685
127938
  postmanCliInstallUrl: inputs.postmanCliInstallUrl,
127939
+ postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
127940
+ runnerOs: inputs.ciRunnerOs,
127686
127941
  postmanRegion: inputs.postmanRegion
127687
127942
  });
127688
127943
  }
127689
127944
  return renderCiWorkflowTemplate({
127690
127945
  postmanCliInstallUrl: inputs.postmanCliInstallUrl,
127946
+ postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
127947
+ runnerOs: inputs.ciRunnerOs,
127691
127948
  postmanRegion: inputs.postmanRegion
127692
127949
  });
127693
127950
  }
@@ -127782,6 +128039,7 @@ async function runRepoSync(inputs, dependencies) {
127782
128039
  }
127783
128040
  }
127784
128041
  async function runRepoSyncInner(inputs, dependencies) {
128042
+ const mask = resolveRepoSyncMasker(dependencies);
127785
128043
  const branchDecision = decideBranchTier(inputs);
127786
128044
  assertBranchAssetIds(inputs, branchDecision);
127787
128045
  const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
@@ -127891,8 +128149,15 @@ async function runRepoSyncInner(inputs, dependencies) {
127891
128149
  outputs["environment-sync-status"] = "success";
127892
128150
  } catch (error) {
127893
128151
  outputs["environment-sync-status"] = "failed";
128152
+ const associationSummary = associations.map((entry) => `${entry.envUid}->${entry.systemEnvId}`).join(", ");
127894
128153
  dependencies.core.warning(
127895
- `System environment association failed: ${error instanceof Error ? error.message : String(error)}`
128154
+ formatOrchestrationIssue({
128155
+ operation: "System environment association",
128156
+ entity: `workspace ${inputs.workspaceId} (${associationSummary})`,
128157
+ cause: error,
128158
+ remediation: "verify access-token/team/system-env mapping then rerun",
128159
+ mask
128160
+ })
127896
128161
  );
127897
128162
  }
127898
128163
  } else if (Object.keys(envUids).length > 0) {
@@ -127920,37 +128185,72 @@ async function runRepoSyncInner(inputs, dependencies) {
127920
128185
  dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
127921
128186
  }
127922
128187
  if (!resolvedMockUrl && inputs.baselineCollectionId) {
127923
- const discovered = await dependencies.postman.findMockByCollection(
127924
- inputs.baselineCollectionId,
127925
- mockEnvUid,
127926
- mockName
127927
- );
127928
- if (discovered) {
127929
- resolvedMockUrl = discovered.mockUrl;
127930
- dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
128188
+ try {
128189
+ const discovered = await dependencies.postman.findMockByCollection(
128190
+ inputs.baselineCollectionId,
128191
+ mockEnvUid,
128192
+ mockName
128193
+ );
128194
+ if (discovered) {
128195
+ resolvedMockUrl = discovered.mockUrl;
128196
+ dependencies.core.info(`Discovered existing mock for collection ${inputs.baselineCollectionId}: ${resolvedMockUrl}`);
128197
+ }
128198
+ } catch (error) {
128199
+ throw new Error(
128200
+ formatOrchestrationIssue({
128201
+ operation: "Mock discovery",
128202
+ entity: `mock "${mockName}" workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`,
128203
+ cause: error,
128204
+ remediation: "verify collection/environment access then rerun",
128205
+ mask
128206
+ }),
128207
+ { cause: error }
128208
+ );
127931
128209
  }
127932
128210
  }
127933
128211
  if (!resolvedMockUrl) {
127934
- const mock = await retry(
127935
- () => dependencies.postman.createMock(
127936
- inputs.workspaceId,
127937
- mockName,
127938
- inputs.baselineCollectionId,
127939
- mockEnvUid
127940
- ),
127941
- {
127942
- maxAttempts: 3,
127943
- delayMs: 2e3,
127944
- backoffMultiplier: 2,
127945
- onRetry: ({ attempt, error }) => {
127946
- dependencies.core.warning(
127947
- `Mock create attempt ${attempt} failed (${error instanceof Error ? error.message : String(error)}); retrying`
127948
- );
128212
+ const mockEntity = `mock "${mockName}" workspace ${inputs.workspaceId} collection ${inputs.baselineCollectionId} environment ${mockEnvUid}`;
128213
+ const mockRemediation = "verify collection/environment access then rerun";
128214
+ try {
128215
+ const mock = await retry(
128216
+ () => dependencies.postman.createMock(
128217
+ inputs.workspaceId,
128218
+ mockName,
128219
+ inputs.baselineCollectionId,
128220
+ mockEnvUid
128221
+ ),
128222
+ {
128223
+ maxAttempts: 3,
128224
+ delayMs: 2e3,
128225
+ backoffMultiplier: 2,
128226
+ onRetry: ({ attempt, maxAttempts, error }) => {
128227
+ dependencies.core.warning(
128228
+ formatOrchestrationIssue({
128229
+ operation: `Mock create attempt ${attempt}/${maxAttempts}`,
128230
+ entity: mockEntity,
128231
+ cause: error,
128232
+ remediation: mockRemediation,
128233
+ mask,
128234
+ detail: "; retrying"
128235
+ })
128236
+ );
128237
+ }
127949
128238
  }
127950
- }
127951
- );
127952
- resolvedMockUrl = mock.url;
127953
- dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
128239
+ );
128240
+ resolvedMockUrl = mock.url;
128241
+ dependencies.core.info(`Created new mock: ${resolvedMockUrl}`);
128242
+ } catch (error) {
128243
+ throw new Error(
128244
+ formatOrchestrationIssue({
128245
+ operation: "Mock create",
128246
+ entity: mockEntity,
128247
+ cause: error,
128248
+ remediation: mockRemediation,
128249
+ mask
128250
+ }),
128251
+ { cause: error }
128252
+ );
128253
+ }
127954
128254
  }
127955
128255
  outputs["mock-url"] = resolvedMockUrl;
127956
128256
  }
@@ -127961,35 +128261,71 @@ async function runRepoSyncInner(inputs, dependencies) {
127961
128261
  if (monitorEnvUid && inputs.monitorType !== "cli") {
127962
128262
  let resolvedMonitorId = "";
127963
128263
  const monitorName = `${assetProjectName} - Smoke Monitor`;
128264
+ const monitorRemediation = "verify monitor IDs/access or set monitor-cron then rerun";
127964
128265
  if (inputs.monitorId) {
127965
128266
  const valid = await dependencies.postman.monitorExists(inputs.monitorId);
127966
128267
  if (valid) {
127967
128268
  resolvedMonitorId = inputs.monitorId;
127968
128269
  dependencies.core.info(`Reusing monitor from explicit input: ${resolvedMonitorId}`);
127969
128270
  } else {
127970
- dependencies.core.warning(`Explicit monitor-id ${inputs.monitorId} not found in Postman, falling through to discovery.`);
128271
+ dependencies.core.warning(
128272
+ formatOrchestrationIssue({
128273
+ operation: "Explicit monitor-id lookup",
128274
+ entity: `monitor-id ${inputs.monitorId} workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
128275
+ cause: "not found in Postman",
128276
+ remediation: monitorRemediation,
128277
+ mask,
128278
+ detail: "; falling through to discovery"
128279
+ })
128280
+ );
127971
128281
  }
127972
128282
  }
127973
128283
  if (!resolvedMonitorId && inputs.smokeCollectionId) {
127974
- const discovered = await dependencies.postman.findMonitorByCollection(
127975
- inputs.smokeCollectionId,
127976
- monitorEnvUid,
127977
- monitorName
127978
- );
127979
- if (discovered) {
127980
- resolvedMonitorId = discovered.uid;
127981
- dependencies.core.info(`Discovered existing monitor for collection ${inputs.smokeCollectionId}: ${resolvedMonitorId}`);
128284
+ try {
128285
+ const discovered = await dependencies.postman.findMonitorByCollection(
128286
+ inputs.smokeCollectionId,
128287
+ monitorEnvUid,
128288
+ monitorName
128289
+ );
128290
+ if (discovered) {
128291
+ resolvedMonitorId = discovered.uid;
128292
+ dependencies.core.info(`Discovered existing monitor for collection ${inputs.smokeCollectionId}: ${resolvedMonitorId}`);
128293
+ }
128294
+ } catch (error) {
128295
+ throw new Error(
128296
+ formatOrchestrationIssue({
128297
+ operation: "Monitor discovery",
128298
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
128299
+ cause: error,
128300
+ remediation: monitorRemediation,
128301
+ mask
128302
+ }),
128303
+ { cause: error }
128304
+ );
127982
128305
  }
127983
128306
  }
127984
128307
  if (!resolvedMonitorId) {
127985
- resolvedMonitorId = await dependencies.postman.createMonitor(
127986
- inputs.workspaceId,
127987
- monitorName,
127988
- inputs.smokeCollectionId,
127989
- monitorEnvUid,
127990
- effectiveCron || void 0
127991
- );
127992
- dependencies.core.info(`Created new monitor: ${resolvedMonitorId}${effectiveCron ? "" : " (disabled \u2014 no cron configured; will trigger a one-time run)"}`);
128308
+ try {
128309
+ resolvedMonitorId = await dependencies.postman.createMonitor(
128310
+ inputs.workspaceId,
128311
+ monitorName,
128312
+ inputs.smokeCollectionId,
128313
+ monitorEnvUid,
128314
+ effectiveCron || void 0
128315
+ );
128316
+ dependencies.core.info(`Created new monitor: ${resolvedMonitorId}${effectiveCron ? "" : " (disabled \u2014 no cron configured; will trigger a one-time run)"}`);
128317
+ } catch (error) {
128318
+ throw new Error(
128319
+ formatOrchestrationIssue({
128320
+ operation: "Monitor create",
128321
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
128322
+ cause: error,
128323
+ remediation: monitorRemediation,
128324
+ mask
128325
+ }),
128326
+ { cause: error }
128327
+ );
128328
+ }
127993
128329
  }
127994
128330
  outputs["monitor-id"] = resolvedMonitorId;
127995
128331
  if (!effectiveCron && resolvedMonitorId) {
@@ -127998,7 +128334,13 @@ async function runRepoSyncInner(inputs, dependencies) {
127998
128334
  dependencies.core.info(`Triggered one-time run for monitor: ${resolvedMonitorId}`);
127999
128335
  } catch (error) {
128000
128336
  dependencies.core.warning(
128001
- `Failed to trigger one-time run for monitor ${resolvedMonitorId}: ${error instanceof Error ? error.message : String(error)}`
128337
+ formatOrchestrationIssue({
128338
+ operation: "Monitor one-time run",
128339
+ entity: `monitor ${resolvedMonitorId} name "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
128340
+ cause: error,
128341
+ remediation: monitorRemediation,
128342
+ mask
128343
+ })
128002
128344
  );
128003
128345
  }
128004
128346
  }
@@ -128063,18 +128405,57 @@ async function runRepoSyncInner(inputs, dependencies) {
128063
128405
  dependencies.core.info(`Tagged spec version at finalize: ${tag.name || tagName}`);
128064
128406
  } catch (error) {
128065
128407
  const status = error.status;
128408
+ const specEntity = `spec ${inputs.specId} tag "${tagName}" workspace ${inputs.workspaceId}`;
128409
+ const specRemediation = "inspect existing tags/access and rerun";
128066
128410
  if (status === 409) {
128067
- const tags = await dependencies.postman.listSpecVersionTags?.(inputs.specId).catch(() => []) ?? [];
128411
+ let tags = [];
128412
+ let listError;
128413
+ if (dependencies.postman.listSpecVersionTags) {
128414
+ try {
128415
+ tags = await dependencies.postman.listSpecVersionTags(inputs.specId);
128416
+ } catch (lookupError) {
128417
+ listError = lookupError;
128418
+ }
128419
+ }
128068
128420
  const latest = tags[0];
128069
- if (latest && (latest.name === tagName || /\([0-9a-f]{7}\)$/.test(latest.name) || /^[0-9a-f]{7}$/.test(latest.name))) {
128421
+ if (!listError && latest && (latest.name === tagName || /\([0-9a-f]{7}\)$/.test(latest.name) || /^[0-9a-f]{7}$/.test(latest.name))) {
128070
128422
  outputs["spec-version-tag"] = latest.name;
128071
128423
  outputs["spec-version-url"] = `https://web.postman.co/workspace/${encodeURIComponent(inputs.workspaceId)}/specification/${encodeURIComponent(inputs.specId)}?tagId=${encodeURIComponent(latest.id)}&versionLabel=${encodeURIComponent(latest.name)}`;
128072
128424
  dependencies.core.info(`Latest changelog group already tagged as "${latest.name}"; adopting.`);
128425
+ } else if (listError) {
128426
+ dependencies.core.warning(
128427
+ formatOrchestrationIssue({
128428
+ operation: "Spec Hub tagging conflict",
128429
+ entity: specEntity,
128430
+ cause: `create=${causeText(error)}; listSpecVersionTags=${causeText(listError)}`,
128431
+ remediation: specRemediation,
128432
+ mask,
128433
+ detail: "; could not list existing tags to confirm adoption"
128434
+ })
128435
+ );
128073
128436
  } else {
128074
- dependencies.core.warning("Latest changelog group already carries a hand-applied tag; leaving it in place.");
128437
+ dependencies.core.warning(
128438
+ formatOrchestrationIssue({
128439
+ operation: "Spec Hub tagging conflict",
128440
+ entity: specEntity,
128441
+ cause: error,
128442
+ remediation: specRemediation,
128443
+ mask,
128444
+ detail: "; latest changelog group already carries a hand-applied or nonmatching tag; leaving it in place"
128445
+ })
128446
+ );
128075
128447
  }
128076
128448
  } else {
128077
- dependencies.core.warning(`Spec version tagging failed (non-fatal): ${error instanceof Error ? error.message : String(error)}`);
128449
+ dependencies.core.warning(
128450
+ formatOrchestrationIssue({
128451
+ operation: "Spec version tagging",
128452
+ entity: specEntity,
128453
+ cause: error,
128454
+ remediation: specRemediation,
128455
+ mask,
128456
+ detail: " (non-fatal)"
128457
+ })
128458
+ );
128078
128459
  }
128079
128460
  }
128080
128461
  }
@@ -128105,7 +128486,16 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
128105
128486
  }
128106
128487
  } catch (error) {
128107
128488
  if (typeof error === "object" && error !== null && "status" in error && (error.status === 401 || error.status === 403)) {
128108
- actionCore.warning("Provided postman-api-key is invalid or expired.");
128489
+ const status = error.status;
128490
+ actionCore.warning(
128491
+ formatOrchestrationIssue({
128492
+ operation: "PMAK GET /me validation",
128493
+ entity: `status ${status}`,
128494
+ cause: error,
128495
+ remediation: "replace postman-api-key or provide a valid postman-access-token then rerun",
128496
+ mask: masker
128497
+ })
128498
+ );
128109
128499
  } else {
128110
128500
  throw error;
128111
128501
  }
@@ -128127,6 +128517,7 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
128127
128517
  const keyName = `repo-sync-action-${Date.now()}`;
128128
128518
  apiKey = await internalIntegration.createApiKey(keyName);
128129
128519
  actionCore.setSecret(apiKey);
128520
+ const persistSecretRemediation = "grant Actions secrets write permission or set POSTMAN_API_KEY manually then rerun";
128130
128521
  if (inputs.provider === "azure-devops") {
128131
128522
  if (options.persistGeneratedApiKeySecret ?? true) {
128132
128523
  actionCore.warning(
@@ -128153,16 +128544,48 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
128153
128544
  ignoreReturnCode: true
128154
128545
  });
128155
128546
  if (ghCommand.exitCode !== 0) {
128156
- actionCore.warning(`Failed to save POSTMAN_API_KEY secret: ${ghCommand.stderr}`);
128547
+ actionCore.warning(
128548
+ formatOrchestrationIssue({
128549
+ operation: "gh secret set POSTMAN_API_KEY",
128550
+ entity: `repository ${repo}`,
128551
+ cause: ghCommand.stderr || `exit code ${ghCommand.exitCode}`,
128552
+ remediation: persistSecretRemediation,
128553
+ mask: masker
128554
+ })
128555
+ );
128157
128556
  }
128158
128557
  } catch (error) {
128159
128558
  actionCore.warning(
128160
- `Error saving POSTMAN_API_KEY secret: ${error instanceof Error ? error.message : String(error)}`
128559
+ formatOrchestrationIssue({
128560
+ operation: "gh secret set POSTMAN_API_KEY",
128561
+ entity: `repository ${repo}`,
128562
+ cause: error,
128563
+ remediation: persistSecretRemediation,
128564
+ mask: masker
128565
+ })
128161
128566
  );
128162
128567
  }
128568
+ } else {
128569
+ actionCore.warning(
128570
+ formatOrchestrationIssue({
128571
+ operation: "gh secret set POSTMAN_API_KEY",
128572
+ entity: "repository (missing)",
128573
+ cause: "repository context is empty",
128574
+ remediation: "set repository context or persist POSTMAN_API_KEY manually then rerun",
128575
+ mask: masker
128576
+ })
128577
+ );
128163
128578
  }
128164
128579
  } else if (options.persistGeneratedApiKeySecret ?? true) {
128165
- actionCore.warning("No GitHub token provided; cannot save generated POSTMAN_API_KEY secret.");
128580
+ actionCore.warning(
128581
+ formatOrchestrationIssue({
128582
+ operation: "gh secret set POSTMAN_API_KEY",
128583
+ entity: inputs.repository ? `repository ${inputs.repository}` : "repository (unknown)",
128584
+ cause: "no GitHub token provided",
128585
+ remediation: "provide github-token/gh-fallback-token or set POSTMAN_API_KEY manually then rerun",
128586
+ mask: masker
128587
+ })
128588
+ );
128166
128589
  } else {
128167
128590
  actionCore.info("Skipping generated POSTMAN_API_KEY GitHub secret persistence for this run.");
128168
128591
  }
@@ -128201,7 +128624,13 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
128201
128624
  const isNonOrgSquads = error instanceof HttpError && error.status === 400 && /squad feature is not available/i.test(error.responseBody);
128202
128625
  if (!isNonOrgSquads) {
128203
128626
  actionCore.warning(
128204
- `Org-mode auto-detection via ums squads failed (non-fatal; set org-mode explicitly if Bifrost calls fail): ${error instanceof Error ? error.message : String(error)}`
128627
+ formatOrchestrationIssue({
128628
+ operation: "Org-mode auto-detection via ums squads",
128629
+ entity: `team ${teamId}`,
128630
+ cause: error,
128631
+ remediation: "set org-mode and team-id explicitly then rerun",
128632
+ mask: masker
128633
+ })
128205
128634
  );
128206
128635
  }
128207
128636
  }
@@ -128321,7 +128750,8 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
128321
128750
  core: factories.core,
128322
128751
  postman,
128323
128752
  internalIntegration,
128324
- repoMutation
128753
+ repoMutation,
128754
+ secretMasker: masker
128325
128755
  };
128326
128756
  }
128327
128757
  function decideBranchTier(inputs, env = process.env) {
@@ -128755,6 +129185,7 @@ var CLI_INPUT_NAMES = [
128755
129185
  "gh-fallback-token",
128756
129186
  "ci-workflow-base64",
128757
129187
  "generate-ci-workflow",
129188
+ "ci-runner-os",
128758
129189
  "monitor-type",
128759
129190
  "ci-workflow-path",
128760
129191
  "org-mode",