@postman-cse/onboarding-repo-sync 2.1.7 → 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;
@@ -124998,7 +125151,106 @@ var BifrostInternalIntegrationAdapter = class {
124998
125151
  throw advised ?? httpErr;
124999
125152
  }
125000
125153
  }
125001
- async connectWorkspaceToRepository(workspaceId, repoUrl) {
125154
+ /**
125155
+ * Probe who (if anyone) already owns the global `(repo, path)` filesystem
125156
+ * link. Non-fatal: unexpected statuses / network errors yield `unknown` so
125157
+ * callers can proceed and rely on reactive POST conflict handling.
125158
+ *
125159
+ * Bifrost states (FileSystemController.fetchWorkspaceForFileSystem):
125160
+ * - 200 + data null -> free
125161
+ * - 200 + data -> linked-visible (workspace payload)
125162
+ * - 403 + error.meta.workspaceId -> linked-invisible
125163
+ * - 200 + error.meta.workspaceId -> linked-invisible (proxy envelope)
125164
+ */
125165
+ async findWorkspaceForRepo(repoUrl, path5 = "/") {
125166
+ const fsPath = path5 && path5.trim() ? path5.trim() : "/";
125167
+ const url = `${this.bifrostBaseUrl}/ws/proxy`;
125168
+ const payload = {
125169
+ service: "workspaces",
125170
+ method: "GET",
125171
+ path: `/workspaces/filesystem?repo=${encodeURIComponent(repoUrl)}&path=${encodeURIComponent(fsPath)}`
125172
+ };
125173
+ try {
125174
+ const response = await this.fetchImpl(url, {
125175
+ method: "POST",
125176
+ headers: this.bifrostHeaders(),
125177
+ body: JSON.stringify(payload)
125178
+ });
125179
+ let parsed = {};
125180
+ try {
125181
+ parsed = await response.json();
125182
+ } catch {
125183
+ return {
125184
+ state: "unknown",
125185
+ reason: this.unknownFilesystemLookupReason(
125186
+ repoUrl,
125187
+ fsPath,
125188
+ `returned non-JSON body (HTTP ${response.status})`
125189
+ )
125190
+ };
125191
+ }
125192
+ const errorMetaWorkspaceId = typeof parsed?.error?.meta?.workspaceId === "string" && parsed.error.meta.workspaceId.trim() ? parsed.error.meta.workspaceId.trim() : void 0;
125193
+ if (errorMetaWorkspaceId) {
125194
+ return { state: "linked-invisible", workspaceId: errorMetaWorkspaceId };
125195
+ }
125196
+ if (response.ok) {
125197
+ if (parsed?.data == null) {
125198
+ return { state: "free" };
125199
+ }
125200
+ const id = typeof parsed.data.id === "string" ? parsed.data.id.trim() : "";
125201
+ if (!id) {
125202
+ return {
125203
+ state: "unknown",
125204
+ reason: this.unknownFilesystemLookupReason(
125205
+ repoUrl,
125206
+ fsPath,
125207
+ "returned 200 without a workspace id"
125208
+ )
125209
+ };
125210
+ }
125211
+ const name = typeof parsed.data.name === "string" && parsed.data.name.trim() ? parsed.data.name.trim() : void 0;
125212
+ return {
125213
+ state: "linked-visible",
125214
+ workspace: name ? { id, name } : { id }
125215
+ };
125216
+ }
125217
+ if (response.status === 403) {
125218
+ const workspaceId = extractDuplicateWorkspaceId(
125219
+ JSON.stringify(parsed)
125220
+ );
125221
+ if (workspaceId) {
125222
+ return { state: "linked-invisible", workspaceId };
125223
+ }
125224
+ return {
125225
+ state: "unknown",
125226
+ reason: this.unknownFilesystemLookupReason(
125227
+ repoUrl,
125228
+ fsPath,
125229
+ "returned 403 without error.meta.workspaceId"
125230
+ )
125231
+ };
125232
+ }
125233
+ return {
125234
+ state: "unknown",
125235
+ reason: this.unknownFilesystemLookupReason(
125236
+ repoUrl,
125237
+ fsPath,
125238
+ `returned HTTP ${response.status}`
125239
+ )
125240
+ };
125241
+ } catch (error) {
125242
+ const cause = error instanceof Error ? error.message : String(error);
125243
+ return {
125244
+ state: "unknown",
125245
+ reason: this.unknownFilesystemLookupReason(
125246
+ repoUrl,
125247
+ fsPath,
125248
+ `failed: ${cause}`
125249
+ )
125250
+ };
125251
+ }
125252
+ }
125253
+ async connectWorkspaceToRepository(workspaceId, repoUrl, options) {
125002
125254
  const url = `${this.bifrostBaseUrl}/ws/proxy`;
125003
125255
  const payload = {
125004
125256
  service: "workspaces",
@@ -125025,6 +125277,11 @@ var BifrostInternalIntegrationAdapter = class {
125025
125277
  if (isDuplicate) {
125026
125278
  const existingWorkspaceId = extractDuplicateWorkspaceId(body);
125027
125279
  if (existingWorkspaceId && existingWorkspaceId !== workspaceId) {
125280
+ if (options?.preflightWasFree) {
125281
+ throw new Error(
125282
+ `REPOSITORY_LINK_CONFLICT_UNRESOLVED: Preflight found no active owner, but link creation reported workspace ${existingWorkspaceId}. Stop and contact Postman support; do not alter the repository URL.`
125283
+ );
125284
+ }
125028
125285
  throw new Error(
125029
125286
  await this.describeWorkspaceLinkConflict(existingWorkspaceId, workspaceId, repoUrl)
125030
125287
  );
@@ -125203,6 +125460,12 @@ var postmanRepoSyncActionContract = {
125203
125460
  required: false,
125204
125461
  default: ".github/workflows/ci.yml"
125205
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
+ },
125206
125469
  "project-name": {
125207
125470
  description: "Service project name used for environment, mock, and monitor naming.",
125208
125471
  required: true
@@ -126862,6 +127125,25 @@ function parseAssetMarker(description) {
126862
127125
  }
126863
127126
 
126864
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
+ }
126865
127147
  function parseBooleanInput(value, defaultValue) {
126866
127148
  const normalized = String(value || "").trim().toLowerCase();
126867
127149
  if (!normalized) return defaultValue;
@@ -126958,6 +127240,17 @@ function parseBranchStrategy(value) {
126958
127240
  `Unsupported branch-strategy "${normalized}". Supported values: ${allowed.join(", ")}`
126959
127241
  );
126960
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
+ }
126961
127254
  function normalizeReleaseLabel(value) {
126962
127255
  const cleaned = normalizeInputValue(value).replace(/^refs\/heads\//, "").replace(/^refs\/tags\//, "").replace(/\s+/g, "-").replace(/[^A-Za-z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
126963
127256
  return cleaned;
@@ -127035,6 +127328,7 @@ function resolveInputs(env = process.env) {
127035
127328
  provider: repoContext.provider,
127036
127329
  ciWorkflowBase64: getInput("ci-workflow-base64", env),
127037
127330
  generateCiWorkflow: parseBooleanInput(getInput("generate-ci-workflow", env), true),
127331
+ ciRunnerOs: parseCiRunnerOs(getInput("ci-runner-os", env)),
127038
127332
  monitorType: getInput("monitor-type", env) || "cloud",
127039
127333
  ciWorkflowPath: getInput("ci-workflow-path", env) || (repoContext.provider === "azure-devops" ? "azure-pipelines.yml" : ".github/workflows/ci.yml"),
127040
127334
  orgMode: parseBooleanInput(getInput("org-mode", env), false),
@@ -127053,6 +127347,7 @@ function resolveInputs(env = process.env) {
127053
127347
  postmanBifrostBase: endpointProfile.bifrostBaseUrl,
127054
127348
  postmanFallbackBase: endpointProfile.fallbackBaseUrl,
127055
127349
  postmanCliInstallUrl: endpointProfile.cliInstallUrl,
127350
+ postmanCliWindowsInstallUrl: endpointProfile.cliWindowsInstallUrl,
127056
127351
  postmanIapubBase: endpointProfile.iapubBaseUrl
127057
127352
  };
127058
127353
  }
@@ -127301,19 +127596,34 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
127301
127596
  if (!inputs.workspaceId) {
127302
127597
  return envUids;
127303
127598
  }
127599
+ const mask = resolveRepoSyncMasker(dependencies);
127600
+ const envRemediation = "verify access-token/team/workspace permissions then rerun";
127304
127601
  for (const envName of inputs.environments) {
127305
127602
  const runtimeUrl = String(inputs.envRuntimeUrls[envName] || "").trim();
127306
127603
  const displayName = `${inputs.projectName} - ${envName}`;
127307
127604
  let existingUid = String(envUids[envName] || "").trim();
127308
127605
  if (!existingUid) {
127309
- const discovered = await dependencies.postman.findEnvironmentByName(
127310
- inputs.workspaceId,
127311
- displayName
127312
- );
127313
- if (discovered?.uid) {
127314
- existingUid = discovered.uid;
127315
- dependencies.core.info(
127316
- `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 }
127317
127627
  );
127318
127628
  }
127319
127629
  }
@@ -127333,17 +127643,43 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
127333
127643
  }
127334
127644
  const values2 = buildEnvironmentValues(envName, runtimeUrl);
127335
127645
  if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
127336
- 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
+ }
127337
127660
  envUids[envName] = existingUid;
127338
127661
  continue;
127339
127662
  }
127340
127663
  const values = buildEnvironmentValues(envName, runtimeUrl);
127341
127664
  if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
127342
- envUids[envName] = await dependencies.postman.createEnvironment(
127343
- inputs.workspaceId,
127344
- displayName,
127345
- values
127346
- );
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
+ }
127347
127683
  }
127348
127684
  return envUids;
127349
127685
  }
@@ -127600,11 +127936,15 @@ function renderCiWorkflow(inputs) {
127600
127936
  if (inputs.provider === "azure-devops") {
127601
127937
  return getCiWorkflowTemplate(inputs.provider, {
127602
127938
  postmanCliInstallUrl: inputs.postmanCliInstallUrl,
127939
+ postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
127940
+ runnerOs: inputs.ciRunnerOs,
127603
127941
  postmanRegion: inputs.postmanRegion
127604
127942
  });
127605
127943
  }
127606
127944
  return renderCiWorkflowTemplate({
127607
127945
  postmanCliInstallUrl: inputs.postmanCliInstallUrl,
127946
+ postmanCliWindowsInstallUrl: inputs.postmanCliWindowsInstallUrl,
127947
+ runnerOs: inputs.ciRunnerOs,
127608
127948
  postmanRegion: inputs.postmanRegion
127609
127949
  });
127610
127950
  }
@@ -127699,6 +128039,7 @@ async function runRepoSync(inputs, dependencies) {
127699
128039
  }
127700
128040
  }
127701
128041
  async function runRepoSyncInner(inputs, dependencies) {
128042
+ const mask = resolveRepoSyncMasker(dependencies);
127702
128043
  const branchDecision = decideBranchTier(inputs);
127703
128044
  assertBranchAssetIds(inputs, branchDecision);
127704
128045
  const isCanonicalWriter = branchDecision.tier === "legacy" || branchDecision.tier === "canonical";
@@ -127758,6 +128099,39 @@ async function runRepoSyncInner(inputs, dependencies) {
127758
128099
  }
127759
128100
  }
127760
128101
  }
128102
+ let skipRepositoryLinkPost = false;
128103
+ let repositoryLinkPreflightWasFree = false;
128104
+ if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration?.findWorkspaceForRepo) {
128105
+ const probe = await dependencies.internalIntegration.findWorkspaceForRepo(
128106
+ inputs.repoUrl,
128107
+ "/"
128108
+ );
128109
+ if (probe.state === "linked-visible") {
128110
+ if (probe.workspace.id === inputs.workspaceId) {
128111
+ skipRepositoryLinkPost = true;
128112
+ dependencies.core.info(
128113
+ `REPOSITORY_LINK_ALREADY_TARGET: Repository ${inputs.repoUrl} at path / is already linked to target workspace ${inputs.workspaceId}; continuing.`
128114
+ );
128115
+ } else {
128116
+ const ownerName = probe.workspace.name?.trim() || "unknown";
128117
+ throw new Error(
128118
+ `REPOSITORY_LINK_CONFLICT_VISIBLE: Repository ${inputs.repoUrl} at path / is already linked to workspace ${probe.workspace.id} ("${ownerName}"). No Postman assets were changed. Reuse that workspace or disconnect it in Workspace Settings, then rerun.`
128119
+ );
128120
+ }
128121
+ } else if (probe.state === "linked-invisible") {
128122
+ let message = `REPOSITORY_LINK_CONFLICT_INVISIBLE: Repository ${inputs.repoUrl} at path / is linked to workspace ${probe.workspaceId}, but these credentials cannot view it. No Postman assets were changed. Ask its owner or a team admin to disconnect it.`;
128123
+ if (inputs.orgMode) {
128124
+ message += " Verify workspace-team-id; if the owner is in another sub-team, ask that sub-team's admin to disconnect it.";
128125
+ }
128126
+ throw new Error(message);
128127
+ } else if (probe.state === "free") {
128128
+ repositoryLinkPreflightWasFree = true;
128129
+ } else {
128130
+ dependencies.core.warning(
128131
+ `REPOSITORY_LINK_PREFLIGHT_UNKNOWN: Unable to determine the existing repository link (${probe.reason}); continuing and relying on link creation conflict handling.`
128132
+ );
128133
+ }
128134
+ }
127761
128135
  const branchAssetMarker = buildBranchAssetMarker(branchDecision, inputs);
127762
128136
  const envUids = await upsertEnvironments(inputs, dependencies, resourcesState, branchAssetMarker);
127763
128137
  outputs["environment-uids-json"] = JSON.stringify(envUids);
@@ -127775,8 +128149,15 @@ async function runRepoSyncInner(inputs, dependencies) {
127775
128149
  outputs["environment-sync-status"] = "success";
127776
128150
  } catch (error) {
127777
128151
  outputs["environment-sync-status"] = "failed";
128152
+ const associationSummary = associations.map((entry) => `${entry.envUid}->${entry.systemEnvId}`).join(", ");
127778
128153
  dependencies.core.warning(
127779
- `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
+ })
127780
128161
  );
127781
128162
  }
127782
128163
  } else if (Object.keys(envUids).length > 0) {
@@ -127804,37 +128185,72 @@ async function runRepoSyncInner(inputs, dependencies) {
127804
128185
  dependencies.core.info(`Reusing mock from explicit input: ${resolvedMockUrl}`);
127805
128186
  }
127806
128187
  if (!resolvedMockUrl && inputs.baselineCollectionId) {
127807
- const discovered = await dependencies.postman.findMockByCollection(
127808
- inputs.baselineCollectionId,
127809
- mockEnvUid,
127810
- mockName
127811
- );
127812
- if (discovered) {
127813
- resolvedMockUrl = discovered.mockUrl;
127814
- 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
+ );
127815
128209
  }
127816
128210
  }
127817
128211
  if (!resolvedMockUrl) {
127818
- const mock = await retry(
127819
- () => dependencies.postman.createMock(
127820
- inputs.workspaceId,
127821
- mockName,
127822
- inputs.baselineCollectionId,
127823
- mockEnvUid
127824
- ),
127825
- {
127826
- maxAttempts: 3,
127827
- delayMs: 2e3,
127828
- backoffMultiplier: 2,
127829
- onRetry: ({ attempt, error }) => {
127830
- dependencies.core.warning(
127831
- `Mock create attempt ${attempt} failed (${error instanceof Error ? error.message : String(error)}); retrying`
127832
- );
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
+ }
127833
128238
  }
127834
- }
127835
- );
127836
- resolvedMockUrl = mock.url;
127837
- 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
+ }
127838
128254
  }
127839
128255
  outputs["mock-url"] = resolvedMockUrl;
127840
128256
  }
@@ -127845,35 +128261,71 @@ async function runRepoSyncInner(inputs, dependencies) {
127845
128261
  if (monitorEnvUid && inputs.monitorType !== "cli") {
127846
128262
  let resolvedMonitorId = "";
127847
128263
  const monitorName = `${assetProjectName} - Smoke Monitor`;
128264
+ const monitorRemediation = "verify monitor IDs/access or set monitor-cron then rerun";
127848
128265
  if (inputs.monitorId) {
127849
128266
  const valid = await dependencies.postman.monitorExists(inputs.monitorId);
127850
128267
  if (valid) {
127851
128268
  resolvedMonitorId = inputs.monitorId;
127852
128269
  dependencies.core.info(`Reusing monitor from explicit input: ${resolvedMonitorId}`);
127853
128270
  } else {
127854
- 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
+ );
127855
128281
  }
127856
128282
  }
127857
128283
  if (!resolvedMonitorId && inputs.smokeCollectionId) {
127858
- const discovered = await dependencies.postman.findMonitorByCollection(
127859
- inputs.smokeCollectionId,
127860
- monitorEnvUid,
127861
- monitorName
127862
- );
127863
- if (discovered) {
127864
- resolvedMonitorId = discovered.uid;
127865
- 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
+ );
127866
128305
  }
127867
128306
  }
127868
128307
  if (!resolvedMonitorId) {
127869
- resolvedMonitorId = await dependencies.postman.createMonitor(
127870
- inputs.workspaceId,
127871
- monitorName,
127872
- inputs.smokeCollectionId,
127873
- monitorEnvUid,
127874
- effectiveCron || void 0
127875
- );
127876
- 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
+ }
127877
128329
  }
127878
128330
  outputs["monitor-id"] = resolvedMonitorId;
127879
128331
  if (!effectiveCron && resolvedMonitorId) {
@@ -127882,7 +128334,13 @@ async function runRepoSyncInner(inputs, dependencies) {
127882
128334
  dependencies.core.info(`Triggered one-time run for monitor: ${resolvedMonitorId}`);
127883
128335
  } catch (error) {
127884
128336
  dependencies.core.warning(
127885
- `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
+ })
127886
128344
  );
127887
128345
  }
127888
128346
  }
@@ -127890,18 +128348,33 @@ async function runRepoSyncInner(inputs, dependencies) {
127890
128348
  }
127891
128349
  if (inputs.workspaceLinkEnabled && inputs.workspaceId && inputs.repoUrl && dependencies.internalIntegration) {
127892
128350
  try {
127893
- await dependencies.internalIntegration.connectWorkspaceToRepository(
127894
- inputs.workspaceId,
127895
- inputs.repoUrl
127896
- );
127897
- outputs["workspace-link-status"] = "success";
127898
- dependencies.core.info(
127899
- `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
127900
- );
128351
+ if (skipRepositoryLinkPost) {
128352
+ outputs["workspace-link-status"] = "success";
128353
+ dependencies.core.info(
128354
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl} (preflight already-target; link POST skipped)`
128355
+ );
128356
+ } else {
128357
+ await dependencies.internalIntegration.connectWorkspaceToRepository(
128358
+ inputs.workspaceId,
128359
+ inputs.repoUrl,
128360
+ repositoryLinkPreflightWasFree ? { preflightWasFree: true } : void 0
128361
+ );
128362
+ outputs["workspace-link-status"] = "success";
128363
+ dependencies.core.info(
128364
+ `workspace-link-status=success workspace-id=${inputs.workspaceId} repo=${inputs.repoUrl}`
128365
+ );
128366
+ }
127901
128367
  } catch (error) {
127902
128368
  outputs["workspace-link-status"] = "failed";
127903
- const message = `Workspace link failed: ${error instanceof Error ? error.message : String(error)}`;
128369
+ const rawMessage = error instanceof Error ? error.message : String(error);
128370
+ const isUnresolvedContract = rawMessage.startsWith(
128371
+ "REPOSITORY_LINK_CONFLICT_UNRESOLVED:"
128372
+ );
128373
+ const message = isUnresolvedContract ? rawMessage : `Workspace link failed: ${rawMessage}`;
127904
128374
  if (branchDecision.tier === "canonical") {
128375
+ if (isUnresolvedContract && error instanceof Error) {
128376
+ throw error;
128377
+ }
127905
128378
  throw new Error(message, { cause: error });
127906
128379
  }
127907
128380
  dependencies.core.warning(message);
@@ -127932,18 +128405,57 @@ async function runRepoSyncInner(inputs, dependencies) {
127932
128405
  dependencies.core.info(`Tagged spec version at finalize: ${tag.name || tagName}`);
127933
128406
  } catch (error) {
127934
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";
127935
128410
  if (status === 409) {
127936
- 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
+ }
127937
128420
  const latest = tags[0];
127938
- 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))) {
127939
128422
  outputs["spec-version-tag"] = latest.name;
127940
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)}`;
127941
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
+ );
127942
128436
  } else {
127943
- 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
+ );
127944
128447
  }
127945
128448
  } else {
127946
- 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
+ );
127947
128459
  }
127948
128460
  }
127949
128461
  }
@@ -127974,7 +128486,16 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
127974
128486
  }
127975
128487
  } catch (error) {
127976
128488
  if (typeof error === "object" && error !== null && "status" in error && (error.status === 401 || error.status === 403)) {
127977
- 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
+ );
127978
128499
  } else {
127979
128500
  throw error;
127980
128501
  }
@@ -127996,6 +128517,7 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
127996
128517
  const keyName = `repo-sync-action-${Date.now()}`;
127997
128518
  apiKey = await internalIntegration.createApiKey(keyName);
127998
128519
  actionCore.setSecret(apiKey);
128520
+ const persistSecretRemediation = "grant Actions secrets write permission or set POSTMAN_API_KEY manually then rerun";
127999
128521
  if (inputs.provider === "azure-devops") {
128000
128522
  if (options.persistGeneratedApiKeySecret ?? true) {
128001
128523
  actionCore.warning(
@@ -128022,16 +128544,48 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
128022
128544
  ignoreReturnCode: true
128023
128545
  });
128024
128546
  if (ghCommand.exitCode !== 0) {
128025
- 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
+ );
128026
128556
  }
128027
128557
  } catch (error) {
128028
128558
  actionCore.warning(
128029
- `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
+ })
128030
128566
  );
128031
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
+ );
128032
128578
  }
128033
128579
  } else if (options.persistGeneratedApiKeySecret ?? true) {
128034
- 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
+ );
128035
128589
  } else {
128036
128590
  actionCore.info("Skipping generated POSTMAN_API_KEY GitHub secret persistence for this run.");
128037
128591
  }
@@ -128070,7 +128624,13 @@ async function resolvePostmanApiKeyAndTeamId(inputs, actionCore, actionExec, mas
128070
128624
  const isNonOrgSquads = error instanceof HttpError && error.status === 400 && /squad feature is not available/i.test(error.responseBody);
128071
128625
  if (!isNonOrgSquads) {
128072
128626
  actionCore.warning(
128073
- `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
+ })
128074
128634
  );
128075
128635
  }
128076
128636
  }
@@ -128190,7 +128750,8 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
128190
128750
  core: factories.core,
128191
128751
  postman,
128192
128752
  internalIntegration,
128193
- repoMutation
128753
+ repoMutation,
128754
+ secretMasker: masker
128194
128755
  };
128195
128756
  }
128196
128757
  function decideBranchTier(inputs, env = process.env) {
@@ -128624,6 +129185,7 @@ var CLI_INPUT_NAMES = [
128624
129185
  "gh-fallback-token",
128625
129186
  "ci-workflow-base64",
128626
129187
  "generate-ci-workflow",
129188
+ "ci-runner-os",
128627
129189
  "monitor-type",
128628
129190
  "ci-workflow-path",
128629
129191
  "org-mode",