@postman-cse/onboarding-repo-sync 2.5.0 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -185,6 +185,7 @@ with:
185
185
  | `postman-api-key` | Postman API key (PMAK). Used only to mint/re-mint the access token (via postman-resolve-service-token-action) and for the Postman CLI spec-lint login. Asset operations (environments, collections, mocks, monitors) run on the access-token gateway and do not use the PMAK. Optional when a valid postman-access-token is supplied; required only for the CLI lint path. | no | |
186
186
  | `postman-access-token` | Postman access token minted by postman-resolve-service-token-action. Required for all asset operations (environment create/get/update, collection read, mock, monitor) which run through the access-token gateway. Also used for workspace linking, system environment association, and generated API-key creation. When omitted, the action mints one from postman-api-key (service-account PMAK); if that mint also fails the action fails fast — PMAK is never an asset-routing fallback. | no | |
187
187
  | `team-id` | Postman team ID resolved by postman-resolve-service-token-action. Primary team scope for all downstream actions; included as x-entity-team-id in org-mode Bifrost calls. Falls back to POSTMAN_TEAM_ID when omitted. Set explicitly for org-mode teams. | no | `""` |
188
+ | `secrets-resolver` | Cloud secret store the generated environments seed credential slots for: none (default, no secret-store variables are added), aws (AWS Secrets Manager), azure (Azure Key Vault), or gcp (Google Secret Manager). Must match the secrets-resolver value passed to the bootstrap and smoke-flow actions. | no | `none` |
188
189
  | `credential-preflight` | Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created. Both modes warn when postman-access-token is not a service-account token. | no | `warn` |
189
190
  | `branch-strategy` | Branch-aware sync strategy. legacy (default) keeps branch-blind behavior; publish-gate restricts canonical writes to the canonical branch and skips repo-sync on other branches; preview additionally maintains suffixed per-branch preview asset sets. | no | `legacy` |
190
191
  | `canonical-branch` | Explicit canonical branch (the sole writer of canonical assets and tracked state). Defaults to the provider-resolved default branch; required on providers without a default-branch variable (Bitbucket, Azure DevOps) when branch-strategy is not legacy. | no | |
package/action.yml CHANGED
@@ -134,6 +134,10 @@ inputs:
134
134
  description: Postman team ID resolved by postman-resolve-service-token-action. Primary team scope for all downstream actions; included as x-entity-team-id in org-mode Bifrost calls. Falls back to POSTMAN_TEAM_ID when omitted. Set explicitly for org-mode teams.
135
135
  required: false
136
136
  default: ""
137
+ secrets-resolver:
138
+ description: 'Cloud secret store the generated environments seed credential slots for: none (default, no secret-store variables are added), aws (AWS Secrets Manager), azure (Azure Key Vault), or gcp (Google Secret Manager). Must match the secrets-resolver value passed to the bootstrap and smoke-flow actions.'
139
+ required: false
140
+ default: "none"
137
141
  credential-preflight:
138
142
  description: 'Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created. Both modes warn when postman-access-token is not a service-account token.'
139
143
  required: false
package/dist/action.cjs CHANGED
@@ -135759,6 +135759,49 @@ function createLogger(options) {
135759
135759
  return root;
135760
135760
  }
135761
135761
 
135762
+ // node_modules/@postman-cse/automation-core/dist/secrets-resolver.js
135763
+ var SECRETS_RESOLVER_PROVIDERS = ["none", "aws", "azure", "gcp"];
135764
+ var DEFAULT_SECRETS_RESOLVER_PROVIDER = "none";
135765
+ function parseSecretsResolverProvider(value, fallback = DEFAULT_SECRETS_RESOLVER_PROVIDER) {
135766
+ const raw = String(value ?? "").trim().toLowerCase();
135767
+ if (!raw)
135768
+ return fallback;
135769
+ if (raw === "true")
135770
+ return "aws";
135771
+ if (raw === "false" || raw === "off")
135772
+ return "none";
135773
+ if (SECRETS_RESOLVER_PROVIDERS.includes(raw)) {
135774
+ return raw;
135775
+ }
135776
+ throw new Error(`SECRETS_RESOLVER_PROVIDER_INVALID: expected one of ${SECRETS_RESOLVER_PROVIDERS.join(", ")} (or legacy true/false), received "${value}"`);
135777
+ }
135778
+ function secretsResolverEnvironmentKeys(provider) {
135779
+ switch (provider) {
135780
+ case "aws":
135781
+ return [
135782
+ { key: "AWS_ACCESS_KEY_ID", secret: true },
135783
+ { key: "AWS_SECRET_ACCESS_KEY", secret: true },
135784
+ { key: "AWS_REGION", secret: false },
135785
+ { key: "AWS_SECRET_NAME", secret: false }
135786
+ ];
135787
+ case "azure":
135788
+ return [
135789
+ { key: "AZURE_KEY_VAULT_NAME", secret: false },
135790
+ { key: "AZURE_SECRET_NAME", secret: false },
135791
+ { key: "AZURE_ACCESS_TOKEN", secret: true }
135792
+ ];
135793
+ case "gcp":
135794
+ return [
135795
+ { key: "GCP_PROJECT_ID", secret: false },
135796
+ { key: "GCP_SECRET_NAME", secret: false },
135797
+ { key: "GCP_ACCESS_TOKEN", secret: true }
135798
+ ];
135799
+ case "none":
135800
+ default:
135801
+ return [];
135802
+ }
135803
+ }
135804
+
135762
135805
  // src/action-version.ts
135763
135806
  var import_node_fs3 = require("node:fs");
135764
135807
  var import_node_path2 = require("node:path");
@@ -136962,6 +137005,12 @@ var postmanRepoSyncActionContract = {
136962
137005
  required: false,
136963
137006
  default: ""
136964
137007
  },
137008
+ "secrets-resolver": {
137009
+ description: "Cloud secret store the generated environments seed credential slots for (none, aws, azure, gcp). Must match the value passed to bootstrap and smoke-flow.",
137010
+ required: false,
137011
+ default: "none",
137012
+ allowedValues: ["none", "aws", "azure", "gcp"]
137013
+ },
136965
137014
  "credential-preflight": {
136966
137015
  description: "Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created. Both modes warn when postman-access-token is not a service-account token.",
136967
137016
  required: false,
@@ -137519,6 +137568,12 @@ var MockContractError = class extends Error {
137519
137568
  this.name = "MockContractError";
137520
137569
  }
137521
137570
  };
137571
+ var AmbiguousMonitorRebindError = class extends Error {
137572
+ constructor(message, options) {
137573
+ super(message, options);
137574
+ this.name = "AmbiguousMonitorRebindError";
137575
+ }
137576
+ };
137522
137577
  function requireMockVisibility(mock, requested) {
137523
137578
  if (mock.visibility === "unknown") {
137524
137579
  throw new MockContractError(
@@ -138355,6 +138410,73 @@ var PostmanGatewayAssetsClient = class {
138355
138410
  );
138356
138411
  return match?.uid ? { uid: match.uid, name: match.name } : null;
138357
138412
  }
138413
+ pickRebindMonitorCandidates(monitors, monitorName, environment) {
138414
+ const nameOnly = monitors.filter((monitor) => monitor.name === monitorName);
138415
+ const nameOnlyEnvironments = [
138416
+ ...new Set(nameOnly.map((monitor) => monitor.environmentUid || "(none)"))
138417
+ ];
138418
+ const candidates = nameOnly.filter((monitor) => monitor.environmentUid === environment);
138419
+ return { candidates, nameOnlyMatchCount: nameOnly.length, nameOnlyEnvironments };
138420
+ }
138421
+ /**
138422
+ * Rebind the sole same-name monitor in this workspace onto the current
138423
+ * collection UID.
138424
+ *
138425
+ * The canonical Smoke collection can legitimately change UID (a bootstrap
138426
+ * re-import after a marker/stranger miss, or an operator rebuild). The
138427
+ * monitor still points at the previous UID, so `findMonitorByCollection`
138428
+ * (which requires the full collection+environment+name triple) misses and a
138429
+ * second monitor with the same name would be created on every run, orphaning
138430
+ * the old one. Name plus environment is the stable identity across a
138431
+ * collection re-import, so recover it here instead.
138432
+ *
138433
+ * Returns null when nothing needs rebinding (no same-name monitor, or it is
138434
+ * already bound to this collection). Refuses to guess when several same-name
138435
+ * monitors match, matching `selectExactMatch` semantics elsewhere.
138436
+ */
138437
+ async rebindMonitorByName(name, collectionUid, environmentUid) {
138438
+ const monitorName = String(name ?? "").trim();
138439
+ const collection = String(collectionUid ?? "").trim();
138440
+ const environment = String(environmentUid ?? "").trim();
138441
+ if (!monitorName || !collection) {
138442
+ return null;
138443
+ }
138444
+ const monitors = await this.listMonitors();
138445
+ const { candidates, nameOnlyMatchCount, nameOnlyEnvironments } = this.pickRebindMonitorCandidates(
138446
+ monitors,
138447
+ monitorName,
138448
+ environment
138449
+ );
138450
+ let match;
138451
+ try {
138452
+ match = this.selectExactMatch(
138453
+ "monitor",
138454
+ `workspace ${this.workspaceId}, name "${monitorName}", and environment ${environment || "(none)"}`,
138455
+ candidates
138456
+ );
138457
+ } catch (error2) {
138458
+ const message = error2 instanceof Error && nameOnlyMatchCount > 0 ? `${error2.message} Same-name monitor(s) also exist on environment(s): ${nameOnlyEnvironments.join(", ")}.` : error2 instanceof Error ? error2.message : String(error2);
138459
+ throw new AmbiguousMonitorRebindError(message, { cause: error2 });
138460
+ }
138461
+ if (!match?.uid) {
138462
+ if (nameOnlyMatchCount > 0) {
138463
+ }
138464
+ return null;
138465
+ }
138466
+ if (match.collectionUid === collection) {
138467
+ return null;
138468
+ }
138469
+ await this.gateway.requestJson(
138470
+ {
138471
+ service: "monitors",
138472
+ method: "put",
138473
+ path: `/jobTemplates/${this.toModelId(match.uid)}?_etc=true`,
138474
+ body: { collection }
138475
+ },
138476
+ { retryTransient: false }
138477
+ );
138478
+ return { uid: match.uid, previousCollectionUid: match.collectionUid };
138479
+ }
138358
138480
  async runMonitor(uid) {
138359
138481
  await this.gateway.requestJson(
138360
138482
  {
@@ -139527,6 +139649,7 @@ function resolveInputs(env = process.env) {
139527
139649
  env
139528
139650
  );
139529
139651
  const environments = parseJsonArray(getInput2("environments-json", env) || '["prod"]');
139652
+ const secretsResolverProvider = parseSecretsResolverProvider(getInput2("secrets-resolver", env));
139530
139653
  const systemEnvMap = parseJsonMap(getInput2("system-env-map-json", env) || "{}");
139531
139654
  const environmentUids = parseJsonMap(getInput2("environment-uids-json", env) || "{}");
139532
139655
  const envRuntimeUrls = parseJsonMap(getInput2("env-runtime-urls-json", env) || "{}");
@@ -139544,6 +139667,7 @@ function resolveInputs(env = process.env) {
139544
139667
  specContentChanged: parseBooleanInput(getInput2("spec-content-changed", env), true),
139545
139668
  specPath: getInput2("spec-path", env),
139546
139669
  collectionSyncMode: normalizeCollectionSyncMode(getInput2("collection-sync-mode", env) || "refresh"),
139670
+ secretsResolverProvider,
139547
139671
  specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
139548
139672
  releaseLabel: normalizeReleaseLabel(getInput2("release-label", env)) || void 0,
139549
139673
  environments: environments.length > 0 ? environments : ["prod"],
@@ -139633,7 +139757,20 @@ function assertBranchAssetIds(inputs, decision, branchOwnedIds = process.env.POS
139633
139757
  );
139634
139758
  }
139635
139759
  }
139760
+ var CREDENTIAL_SLOT_PREFIXES = ["AWS_", "AZURE_", "GCP_"];
139761
+ function isCredentialSlotKey(key) {
139762
+ return typeof key === "string" && CREDENTIAL_SLOT_PREFIXES.some((prefix) => key.startsWith(prefix));
139763
+ }
139636
139764
  function buildEnvironmentValues(envName, baseUrl, options = {}) {
139765
+ const seeded = secretsResolverEnvironmentKeys(options.secretsResolverProvider ?? "none").map((entry) => ({
139766
+ key: entry.key,
139767
+ value: entry.key.endsWith("_SECRET_NAME") && !entry.secret ? `api-credentials-${envName}` : entry.defaultValue ?? "",
139768
+ type: entry.secret ? "secret" : "default"
139769
+ }));
139770
+ const seededKeys = new Set(seeded.map((entry) => entry.key));
139771
+ const preserved = (options.preservedCredentialValues ?? []).filter(
139772
+ (entry) => isCredentialSlotKey(entry.key) && !seededKeys.has(entry.key)
139773
+ );
139637
139774
  return [
139638
139775
  { key: "baseUrl", value: baseUrl, type: "default" },
139639
139776
  // A private mock refuses anonymous calls, so the manual-validation environment
@@ -139642,10 +139779,11 @@ function buildEnvironmentValues(envName, baseUrl, options = {}) {
139642
139779
  ...options.privateMockAuth ? [{ key: PRIVATE_MOCK_AUTH_VARIABLE2, value: "", type: "secret" }] : [],
139643
139780
  { key: "CI", value: "false", type: "default" },
139644
139781
  { key: "RESPONSE_TIME_THRESHOLD", value: "2000", type: "default" },
139645
- { key: "AWS_ACCESS_KEY_ID", value: "", type: "secret" },
139646
- { key: "AWS_SECRET_ACCESS_KEY", value: "", type: "secret" },
139647
- { key: "AWS_REGION", value: "eu-west-2", type: "default" },
139648
- { key: "AWS_SECRET_NAME", value: `api-credentials-${envName}`, type: "default" }
139782
+ // Provider-scoped credential slots. `none` (the default) seeds nothing, so a
139783
+ // consumer that does not use a cloud secret store gets a clean environment
139784
+ // instead of four dead AWS variables.
139785
+ ...seeded,
139786
+ ...preserved
139649
139787
  ];
139650
139788
  }
139651
139789
  var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
@@ -140131,19 +140269,28 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
140131
140269
  }
140132
140270
  if (existingUid) {
140133
140271
  let marker = assetMarker;
140134
- if (marker) {
140135
- try {
140136
- const existing = await dependencies.postman.getEnvironment(existingUid);
140137
- const values3 = existing.data?.values ?? existing.values ?? [];
140138
- const prior = values3.find((value) => value.key === "x-pm-onboarding")?.value;
140272
+ let priorValues = [];
140273
+ try {
140274
+ const existing = await dependencies.postman.getEnvironment(existingUid);
140275
+ const values3 = existing?.data?.values ?? existing?.values ?? [];
140276
+ priorValues = values3.filter((value) => typeof value?.key === "string").map((value) => ({
140277
+ key: value.key,
140278
+ value: typeof value.value === "string" ? value.value : "",
140279
+ type: value.type === "secret" ? "secret" : "default"
140280
+ }));
140281
+ if (marker) {
140282
+ const prior = priorValues.find((value) => value.key === "x-pm-onboarding")?.value;
140139
140283
  const priorMarker = parseAssetMarker(prior ? `x-pm-onboarding: ${prior}` : void 0);
140140
140284
  if (priorMarker?.repo === marker.repo && priorMarker.rawBranch === marker.rawBranch) {
140141
140285
  marker = { ...marker, createdAt: priorMarker.createdAt };
140142
140286
  }
140143
- } catch {
140144
140287
  }
140288
+ } catch {
140145
140289
  }
140146
- const values2 = buildEnvironmentValues(envName, runtimeUrl);
140290
+ const values2 = buildEnvironmentValues(envName, runtimeUrl, {
140291
+ secretsResolverProvider: inputs.secretsResolverProvider,
140292
+ preservedCredentialValues: priorValues
140293
+ });
140147
140294
  if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
140148
140295
  try {
140149
140296
  await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
@@ -140163,7 +140310,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
140163
140310
  dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
140164
140311
  continue;
140165
140312
  }
140166
- const values = buildEnvironmentValues(envName, runtimeUrl);
140313
+ const values = buildEnvironmentValues(envName, runtimeUrl, {
140314
+ secretsResolverProvider: inputs.secretsResolverProvider
140315
+ });
140167
140316
  if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
140168
140317
  try {
140169
140318
  envUids[envName] = await dependencies.postman.createEnvironment(
@@ -140192,7 +140341,10 @@ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, moc
140192
140341
  return "";
140193
140342
  }
140194
140343
  const displayName = `${assetProjectName} - Mock`;
140195
- const values = buildEnvironmentValues("mock", mockUrl, { privateMockAuth });
140344
+ const values = buildEnvironmentValues("mock", mockUrl, {
140345
+ privateMockAuth,
140346
+ secretsResolverProvider: inputs.secretsResolverProvider
140347
+ });
140196
140348
  const mask = resolveRepoSyncMasker(dependencies);
140197
140349
  try {
140198
140350
  const discovered = await dependencies.postman.findEnvironmentByName(
@@ -141463,6 +141615,43 @@ async function runRepoSyncInner(inputs, dependencies) {
141463
141615
  );
141464
141616
  }
141465
141617
  }
141618
+ if (!resolvedMonitorId && inputs.smokeCollectionId && dependencies.postman.rebindMonitorByName) {
141619
+ try {
141620
+ const rebound = await dependencies.postman.rebindMonitorByName(
141621
+ monitorName,
141622
+ inputs.smokeCollectionId,
141623
+ monitorEnvUid
141624
+ );
141625
+ if (rebound) {
141626
+ resolvedMonitorId = rebound.uid;
141627
+ dependencies.core.info(
141628
+ `Rebound existing monitor ${rebound.uid} ("${monitorName}") from collection ${rebound.previousCollectionUid} to ${inputs.smokeCollectionId}`
141629
+ );
141630
+ }
141631
+ } catch (error2) {
141632
+ if (error2 instanceof AmbiguousMonitorRebindError) {
141633
+ throw new Error(
141634
+ formatOrchestrationIssue({
141635
+ operation: "Monitor rebind",
141636
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
141637
+ cause: error2,
141638
+ remediation: monitorRemediation,
141639
+ mask
141640
+ }),
141641
+ { cause: error2 }
141642
+ );
141643
+ }
141644
+ dependencies.core.warning(
141645
+ formatOrchestrationIssue({
141646
+ operation: "Monitor rebind",
141647
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
141648
+ cause: error2,
141649
+ remediation: monitorRemediation,
141650
+ mask
141651
+ })
141652
+ );
141653
+ }
141654
+ }
141466
141655
  if (!resolvedMonitorId) {
141467
141656
  try {
141468
141657
  resolvedMonitorId = await dependencies.postman.createMonitor(
@@ -141884,6 +142073,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
141884
142073
  listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
141885
142074
  monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
141886
142075
  findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
142076
+ rebindMonitorByName: gatewayAssets.rebindMonitorByName.bind(gatewayAssets),
141887
142077
  runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
141888
142078
  listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
141889
142079
  // GC path (preview/channel retention machine — lib/repo/preview-gc.ts).
package/dist/cli.cjs CHANGED
@@ -133864,6 +133864,49 @@ function createLogger(options) {
133864
133864
  return root;
133865
133865
  }
133866
133866
 
133867
+ // node_modules/@postman-cse/automation-core/dist/secrets-resolver.js
133868
+ var SECRETS_RESOLVER_PROVIDERS = ["none", "aws", "azure", "gcp"];
133869
+ var DEFAULT_SECRETS_RESOLVER_PROVIDER = "none";
133870
+ function parseSecretsResolverProvider(value, fallback = DEFAULT_SECRETS_RESOLVER_PROVIDER) {
133871
+ const raw = String(value ?? "").trim().toLowerCase();
133872
+ if (!raw)
133873
+ return fallback;
133874
+ if (raw === "true")
133875
+ return "aws";
133876
+ if (raw === "false" || raw === "off")
133877
+ return "none";
133878
+ if (SECRETS_RESOLVER_PROVIDERS.includes(raw)) {
133879
+ return raw;
133880
+ }
133881
+ throw new Error(`SECRETS_RESOLVER_PROVIDER_INVALID: expected one of ${SECRETS_RESOLVER_PROVIDERS.join(", ")} (or legacy true/false), received "${value}"`);
133882
+ }
133883
+ function secretsResolverEnvironmentKeys(provider) {
133884
+ switch (provider) {
133885
+ case "aws":
133886
+ return [
133887
+ { key: "AWS_ACCESS_KEY_ID", secret: true },
133888
+ { key: "AWS_SECRET_ACCESS_KEY", secret: true },
133889
+ { key: "AWS_REGION", secret: false },
133890
+ { key: "AWS_SECRET_NAME", secret: false }
133891
+ ];
133892
+ case "azure":
133893
+ return [
133894
+ { key: "AZURE_KEY_VAULT_NAME", secret: false },
133895
+ { key: "AZURE_SECRET_NAME", secret: false },
133896
+ { key: "AZURE_ACCESS_TOKEN", secret: true }
133897
+ ];
133898
+ case "gcp":
133899
+ return [
133900
+ { key: "GCP_PROJECT_ID", secret: false },
133901
+ { key: "GCP_SECRET_NAME", secret: false },
133902
+ { key: "GCP_ACCESS_TOKEN", secret: true }
133903
+ ];
133904
+ case "none":
133905
+ default:
133906
+ return [];
133907
+ }
133908
+ }
133909
+
133867
133910
  // src/action-version.ts
133868
133911
  var import_node_fs3 = require("node:fs");
133869
133912
  var import_node_path2 = require("node:path");
@@ -135067,6 +135110,12 @@ var postmanRepoSyncActionContract = {
135067
135110
  required: false,
135068
135111
  default: ""
135069
135112
  },
135113
+ "secrets-resolver": {
135114
+ description: "Cloud secret store the generated environments seed credential slots for (none, aws, azure, gcp). Must match the value passed to bootstrap and smoke-flow.",
135115
+ required: false,
135116
+ default: "none",
135117
+ allowedValues: ["none", "aws", "azure", "gcp"]
135118
+ },
135070
135119
  "credential-preflight": {
135071
135120
  description: "Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created. Both modes warn when postman-access-token is not a service-account token.",
135072
135121
  required: false,
@@ -135624,6 +135673,12 @@ var MockContractError = class extends Error {
135624
135673
  this.name = "MockContractError";
135625
135674
  }
135626
135675
  };
135676
+ var AmbiguousMonitorRebindError = class extends Error {
135677
+ constructor(message, options) {
135678
+ super(message, options);
135679
+ this.name = "AmbiguousMonitorRebindError";
135680
+ }
135681
+ };
135627
135682
  function requireMockVisibility(mock, requested) {
135628
135683
  if (mock.visibility === "unknown") {
135629
135684
  throw new MockContractError(
@@ -136460,6 +136515,73 @@ var PostmanGatewayAssetsClient = class {
136460
136515
  );
136461
136516
  return match?.uid ? { uid: match.uid, name: match.name } : null;
136462
136517
  }
136518
+ pickRebindMonitorCandidates(monitors, monitorName, environment) {
136519
+ const nameOnly = monitors.filter((monitor) => monitor.name === monitorName);
136520
+ const nameOnlyEnvironments = [
136521
+ ...new Set(nameOnly.map((monitor) => monitor.environmentUid || "(none)"))
136522
+ ];
136523
+ const candidates = nameOnly.filter((monitor) => monitor.environmentUid === environment);
136524
+ return { candidates, nameOnlyMatchCount: nameOnly.length, nameOnlyEnvironments };
136525
+ }
136526
+ /**
136527
+ * Rebind the sole same-name monitor in this workspace onto the current
136528
+ * collection UID.
136529
+ *
136530
+ * The canonical Smoke collection can legitimately change UID (a bootstrap
136531
+ * re-import after a marker/stranger miss, or an operator rebuild). The
136532
+ * monitor still points at the previous UID, so `findMonitorByCollection`
136533
+ * (which requires the full collection+environment+name triple) misses and a
136534
+ * second monitor with the same name would be created on every run, orphaning
136535
+ * the old one. Name plus environment is the stable identity across a
136536
+ * collection re-import, so recover it here instead.
136537
+ *
136538
+ * Returns null when nothing needs rebinding (no same-name monitor, or it is
136539
+ * already bound to this collection). Refuses to guess when several same-name
136540
+ * monitors match, matching `selectExactMatch` semantics elsewhere.
136541
+ */
136542
+ async rebindMonitorByName(name, collectionUid, environmentUid) {
136543
+ const monitorName = String(name ?? "").trim();
136544
+ const collection = String(collectionUid ?? "").trim();
136545
+ const environment = String(environmentUid ?? "").trim();
136546
+ if (!monitorName || !collection) {
136547
+ return null;
136548
+ }
136549
+ const monitors = await this.listMonitors();
136550
+ const { candidates, nameOnlyMatchCount, nameOnlyEnvironments } = this.pickRebindMonitorCandidates(
136551
+ monitors,
136552
+ monitorName,
136553
+ environment
136554
+ );
136555
+ let match;
136556
+ try {
136557
+ match = this.selectExactMatch(
136558
+ "monitor",
136559
+ `workspace ${this.workspaceId}, name "${monitorName}", and environment ${environment || "(none)"}`,
136560
+ candidates
136561
+ );
136562
+ } catch (error) {
136563
+ const message = error instanceof Error && nameOnlyMatchCount > 0 ? `${error.message} Same-name monitor(s) also exist on environment(s): ${nameOnlyEnvironments.join(", ")}.` : error instanceof Error ? error.message : String(error);
136564
+ throw new AmbiguousMonitorRebindError(message, { cause: error });
136565
+ }
136566
+ if (!match?.uid) {
136567
+ if (nameOnlyMatchCount > 0) {
136568
+ }
136569
+ return null;
136570
+ }
136571
+ if (match.collectionUid === collection) {
136572
+ return null;
136573
+ }
136574
+ await this.gateway.requestJson(
136575
+ {
136576
+ service: "monitors",
136577
+ method: "put",
136578
+ path: `/jobTemplates/${this.toModelId(match.uid)}?_etc=true`,
136579
+ body: { collection }
136580
+ },
136581
+ { retryTransient: false }
136582
+ );
136583
+ return { uid: match.uid, previousCollectionUid: match.collectionUid };
136584
+ }
136463
136585
  async runMonitor(uid) {
136464
136586
  await this.gateway.requestJson(
136465
136587
  {
@@ -137577,6 +137699,7 @@ function resolveInputs(env = process.env) {
137577
137699
  env
137578
137700
  );
137579
137701
  const environments = parseJsonArray(getInput("environments-json", env) || '["prod"]');
137702
+ const secretsResolverProvider = parseSecretsResolverProvider(getInput("secrets-resolver", env));
137580
137703
  const systemEnvMap = parseJsonMap(getInput("system-env-map-json", env) || "{}");
137581
137704
  const environmentUids = parseJsonMap(getInput("environment-uids-json", env) || "{}");
137582
137705
  const envRuntimeUrls = parseJsonMap(getInput("env-runtime-urls-json", env) || "{}");
@@ -137594,6 +137717,7 @@ function resolveInputs(env = process.env) {
137594
137717
  specContentChanged: parseBooleanInput(getInput("spec-content-changed", env), true),
137595
137718
  specPath: getInput("spec-path", env),
137596
137719
  collectionSyncMode: normalizeCollectionSyncMode(getInput("collection-sync-mode", env) || "refresh"),
137720
+ secretsResolverProvider,
137597
137721
  specSyncMode: normalizeSpecSyncMode(getInput("spec-sync-mode", env) || "update"),
137598
137722
  releaseLabel: normalizeReleaseLabel(getInput("release-label", env)) || void 0,
137599
137723
  environments: environments.length > 0 ? environments : ["prod"],
@@ -137683,7 +137807,20 @@ function assertBranchAssetIds(inputs, decision, branchOwnedIds = process.env.POS
137683
137807
  );
137684
137808
  }
137685
137809
  }
137810
+ var CREDENTIAL_SLOT_PREFIXES = ["AWS_", "AZURE_", "GCP_"];
137811
+ function isCredentialSlotKey(key) {
137812
+ return typeof key === "string" && CREDENTIAL_SLOT_PREFIXES.some((prefix) => key.startsWith(prefix));
137813
+ }
137686
137814
  function buildEnvironmentValues(envName, baseUrl, options = {}) {
137815
+ const seeded = secretsResolverEnvironmentKeys(options.secretsResolverProvider ?? "none").map((entry) => ({
137816
+ key: entry.key,
137817
+ value: entry.key.endsWith("_SECRET_NAME") && !entry.secret ? `api-credentials-${envName}` : entry.defaultValue ?? "",
137818
+ type: entry.secret ? "secret" : "default"
137819
+ }));
137820
+ const seededKeys = new Set(seeded.map((entry) => entry.key));
137821
+ const preserved = (options.preservedCredentialValues ?? []).filter(
137822
+ (entry) => isCredentialSlotKey(entry.key) && !seededKeys.has(entry.key)
137823
+ );
137687
137824
  return [
137688
137825
  { key: "baseUrl", value: baseUrl, type: "default" },
137689
137826
  // A private mock refuses anonymous calls, so the manual-validation environment
@@ -137692,10 +137829,11 @@ function buildEnvironmentValues(envName, baseUrl, options = {}) {
137692
137829
  ...options.privateMockAuth ? [{ key: PRIVATE_MOCK_AUTH_VARIABLE2, value: "", type: "secret" }] : [],
137693
137830
  { key: "CI", value: "false", type: "default" },
137694
137831
  { key: "RESPONSE_TIME_THRESHOLD", value: "2000", type: "default" },
137695
- { key: "AWS_ACCESS_KEY_ID", value: "", type: "secret" },
137696
- { key: "AWS_SECRET_ACCESS_KEY", value: "", type: "secret" },
137697
- { key: "AWS_REGION", value: "eu-west-2", type: "default" },
137698
- { key: "AWS_SECRET_NAME", value: `api-credentials-${envName}`, type: "default" }
137832
+ // Provider-scoped credential slots. `none` (the default) seeds nothing, so a
137833
+ // consumer that does not use a cloud secret store gets a clean environment
137834
+ // instead of four dead AWS variables.
137835
+ ...seeded,
137836
+ ...preserved
137699
137837
  ];
137700
137838
  }
137701
137839
  var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
@@ -138039,19 +138177,28 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
138039
138177
  }
138040
138178
  if (existingUid) {
138041
138179
  let marker = assetMarker;
138042
- if (marker) {
138043
- try {
138044
- const existing = await dependencies.postman.getEnvironment(existingUid);
138045
- const values3 = existing.data?.values ?? existing.values ?? [];
138046
- const prior = values3.find((value) => value.key === "x-pm-onboarding")?.value;
138180
+ let priorValues = [];
138181
+ try {
138182
+ const existing = await dependencies.postman.getEnvironment(existingUid);
138183
+ const values3 = existing?.data?.values ?? existing?.values ?? [];
138184
+ priorValues = values3.filter((value) => typeof value?.key === "string").map((value) => ({
138185
+ key: value.key,
138186
+ value: typeof value.value === "string" ? value.value : "",
138187
+ type: value.type === "secret" ? "secret" : "default"
138188
+ }));
138189
+ if (marker) {
138190
+ const prior = priorValues.find((value) => value.key === "x-pm-onboarding")?.value;
138047
138191
  const priorMarker = parseAssetMarker(prior ? `x-pm-onboarding: ${prior}` : void 0);
138048
138192
  if (priorMarker?.repo === marker.repo && priorMarker.rawBranch === marker.rawBranch) {
138049
138193
  marker = { ...marker, createdAt: priorMarker.createdAt };
138050
138194
  }
138051
- } catch {
138052
138195
  }
138196
+ } catch {
138053
138197
  }
138054
- const values2 = buildEnvironmentValues(envName, runtimeUrl);
138198
+ const values2 = buildEnvironmentValues(envName, runtimeUrl, {
138199
+ secretsResolverProvider: inputs.secretsResolverProvider,
138200
+ preservedCredentialValues: priorValues
138201
+ });
138055
138202
  if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
138056
138203
  try {
138057
138204
  await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
@@ -138071,7 +138218,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
138071
138218
  dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
138072
138219
  continue;
138073
138220
  }
138074
- const values = buildEnvironmentValues(envName, runtimeUrl);
138221
+ const values = buildEnvironmentValues(envName, runtimeUrl, {
138222
+ secretsResolverProvider: inputs.secretsResolverProvider
138223
+ });
138075
138224
  if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
138076
138225
  try {
138077
138226
  envUids[envName] = await dependencies.postman.createEnvironment(
@@ -138100,7 +138249,10 @@ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, moc
138100
138249
  return "";
138101
138250
  }
138102
138251
  const displayName = `${assetProjectName} - Mock`;
138103
- const values = buildEnvironmentValues("mock", mockUrl, { privateMockAuth });
138252
+ const values = buildEnvironmentValues("mock", mockUrl, {
138253
+ privateMockAuth,
138254
+ secretsResolverProvider: inputs.secretsResolverProvider
138255
+ });
138104
138256
  const mask = resolveRepoSyncMasker(dependencies);
138105
138257
  try {
138106
138258
  const discovered = await dependencies.postman.findEnvironmentByName(
@@ -139371,6 +139523,43 @@ async function runRepoSyncInner(inputs, dependencies) {
139371
139523
  );
139372
139524
  }
139373
139525
  }
139526
+ if (!resolvedMonitorId && inputs.smokeCollectionId && dependencies.postman.rebindMonitorByName) {
139527
+ try {
139528
+ const rebound = await dependencies.postman.rebindMonitorByName(
139529
+ monitorName,
139530
+ inputs.smokeCollectionId,
139531
+ monitorEnvUid
139532
+ );
139533
+ if (rebound) {
139534
+ resolvedMonitorId = rebound.uid;
139535
+ dependencies.core.info(
139536
+ `Rebound existing monitor ${rebound.uid} ("${monitorName}") from collection ${rebound.previousCollectionUid} to ${inputs.smokeCollectionId}`
139537
+ );
139538
+ }
139539
+ } catch (error) {
139540
+ if (error instanceof AmbiguousMonitorRebindError) {
139541
+ throw new Error(
139542
+ formatOrchestrationIssue({
139543
+ operation: "Monitor rebind",
139544
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
139545
+ cause: error,
139546
+ remediation: monitorRemediation,
139547
+ mask
139548
+ }),
139549
+ { cause: error }
139550
+ );
139551
+ }
139552
+ dependencies.core.warning(
139553
+ formatOrchestrationIssue({
139554
+ operation: "Monitor rebind",
139555
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
139556
+ cause: error,
139557
+ remediation: monitorRemediation,
139558
+ mask
139559
+ })
139560
+ );
139561
+ }
139562
+ }
139374
139563
  if (!resolvedMonitorId) {
139375
139564
  try {
139376
139565
  resolvedMonitorId = await dependencies.postman.createMonitor(
@@ -139792,6 +139981,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
139792
139981
  listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
139793
139982
  monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
139794
139983
  findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
139984
+ rebindMonitorByName: gatewayAssets.rebindMonitorByName.bind(gatewayAssets),
139795
139985
  runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
139796
139986
  listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
139797
139987
  // GC path (preview/channel retention machine — lib/repo/preview-gc.ts).
@@ -140292,6 +140482,7 @@ var CLI_INPUT_NAMES = [
140292
140482
  "spec-content-changed",
140293
140483
  "spec-path",
140294
140484
  "team-id",
140485
+ "secrets-resolver",
140295
140486
  "postman-region",
140296
140487
  "postman-stack",
140297
140488
  "branch-strategy",
package/dist/index.cjs CHANGED
@@ -135782,6 +135782,49 @@ function createLogger(options) {
135782
135782
  return root;
135783
135783
  }
135784
135784
 
135785
+ // node_modules/@postman-cse/automation-core/dist/secrets-resolver.js
135786
+ var SECRETS_RESOLVER_PROVIDERS = ["none", "aws", "azure", "gcp"];
135787
+ var DEFAULT_SECRETS_RESOLVER_PROVIDER = "none";
135788
+ function parseSecretsResolverProvider(value, fallback = DEFAULT_SECRETS_RESOLVER_PROVIDER) {
135789
+ const raw = String(value ?? "").trim().toLowerCase();
135790
+ if (!raw)
135791
+ return fallback;
135792
+ if (raw === "true")
135793
+ return "aws";
135794
+ if (raw === "false" || raw === "off")
135795
+ return "none";
135796
+ if (SECRETS_RESOLVER_PROVIDERS.includes(raw)) {
135797
+ return raw;
135798
+ }
135799
+ throw new Error(`SECRETS_RESOLVER_PROVIDER_INVALID: expected one of ${SECRETS_RESOLVER_PROVIDERS.join(", ")} (or legacy true/false), received "${value}"`);
135800
+ }
135801
+ function secretsResolverEnvironmentKeys(provider) {
135802
+ switch (provider) {
135803
+ case "aws":
135804
+ return [
135805
+ { key: "AWS_ACCESS_KEY_ID", secret: true },
135806
+ { key: "AWS_SECRET_ACCESS_KEY", secret: true },
135807
+ { key: "AWS_REGION", secret: false },
135808
+ { key: "AWS_SECRET_NAME", secret: false }
135809
+ ];
135810
+ case "azure":
135811
+ return [
135812
+ { key: "AZURE_KEY_VAULT_NAME", secret: false },
135813
+ { key: "AZURE_SECRET_NAME", secret: false },
135814
+ { key: "AZURE_ACCESS_TOKEN", secret: true }
135815
+ ];
135816
+ case "gcp":
135817
+ return [
135818
+ { key: "GCP_PROJECT_ID", secret: false },
135819
+ { key: "GCP_SECRET_NAME", secret: false },
135820
+ { key: "GCP_ACCESS_TOKEN", secret: true }
135821
+ ];
135822
+ case "none":
135823
+ default:
135824
+ return [];
135825
+ }
135826
+ }
135827
+
135785
135828
  // src/action-version.ts
135786
135829
  var import_node_fs3 = require("node:fs");
135787
135830
  var import_node_path2 = require("node:path");
@@ -136985,6 +137028,12 @@ var postmanRepoSyncActionContract = {
136985
137028
  required: false,
136986
137029
  default: ""
136987
137030
  },
137031
+ "secrets-resolver": {
137032
+ description: "Cloud secret store the generated environments seed credential slots for (none, aws, azure, gcp). Must match the value passed to bootstrap and smoke-flow.",
137033
+ required: false,
137034
+ default: "none",
137035
+ allowedValues: ["none", "aws", "azure", "gcp"]
137036
+ },
136988
137037
  "credential-preflight": {
136989
137038
  description: "Credential identity preflight policy. warn (default) logs a note and continues when postman-api-key and postman-access-token resolve to different parent orgs; enforce fails the run on that condition before any workspace is created. Both modes warn when postman-access-token is not a service-account token.",
136990
137039
  required: false,
@@ -137542,6 +137591,12 @@ var MockContractError = class extends Error {
137542
137591
  this.name = "MockContractError";
137543
137592
  }
137544
137593
  };
137594
+ var AmbiguousMonitorRebindError = class extends Error {
137595
+ constructor(message, options) {
137596
+ super(message, options);
137597
+ this.name = "AmbiguousMonitorRebindError";
137598
+ }
137599
+ };
137545
137600
  function requireMockVisibility(mock, requested) {
137546
137601
  if (mock.visibility === "unknown") {
137547
137602
  throw new MockContractError(
@@ -138378,6 +138433,73 @@ var PostmanGatewayAssetsClient = class {
138378
138433
  );
138379
138434
  return match?.uid ? { uid: match.uid, name: match.name } : null;
138380
138435
  }
138436
+ pickRebindMonitorCandidates(monitors, monitorName, environment) {
138437
+ const nameOnly = monitors.filter((monitor) => monitor.name === monitorName);
138438
+ const nameOnlyEnvironments = [
138439
+ ...new Set(nameOnly.map((monitor) => monitor.environmentUid || "(none)"))
138440
+ ];
138441
+ const candidates = nameOnly.filter((monitor) => monitor.environmentUid === environment);
138442
+ return { candidates, nameOnlyMatchCount: nameOnly.length, nameOnlyEnvironments };
138443
+ }
138444
+ /**
138445
+ * Rebind the sole same-name monitor in this workspace onto the current
138446
+ * collection UID.
138447
+ *
138448
+ * The canonical Smoke collection can legitimately change UID (a bootstrap
138449
+ * re-import after a marker/stranger miss, or an operator rebuild). The
138450
+ * monitor still points at the previous UID, so `findMonitorByCollection`
138451
+ * (which requires the full collection+environment+name triple) misses and a
138452
+ * second monitor with the same name would be created on every run, orphaning
138453
+ * the old one. Name plus environment is the stable identity across a
138454
+ * collection re-import, so recover it here instead.
138455
+ *
138456
+ * Returns null when nothing needs rebinding (no same-name monitor, or it is
138457
+ * already bound to this collection). Refuses to guess when several same-name
138458
+ * monitors match, matching `selectExactMatch` semantics elsewhere.
138459
+ */
138460
+ async rebindMonitorByName(name, collectionUid, environmentUid) {
138461
+ const monitorName = String(name ?? "").trim();
138462
+ const collection = String(collectionUid ?? "").trim();
138463
+ const environment = String(environmentUid ?? "").trim();
138464
+ if (!monitorName || !collection) {
138465
+ return null;
138466
+ }
138467
+ const monitors = await this.listMonitors();
138468
+ const { candidates, nameOnlyMatchCount, nameOnlyEnvironments } = this.pickRebindMonitorCandidates(
138469
+ monitors,
138470
+ monitorName,
138471
+ environment
138472
+ );
138473
+ let match;
138474
+ try {
138475
+ match = this.selectExactMatch(
138476
+ "monitor",
138477
+ `workspace ${this.workspaceId}, name "${monitorName}", and environment ${environment || "(none)"}`,
138478
+ candidates
138479
+ );
138480
+ } catch (error2) {
138481
+ const message = error2 instanceof Error && nameOnlyMatchCount > 0 ? `${error2.message} Same-name monitor(s) also exist on environment(s): ${nameOnlyEnvironments.join(", ")}.` : error2 instanceof Error ? error2.message : String(error2);
138482
+ throw new AmbiguousMonitorRebindError(message, { cause: error2 });
138483
+ }
138484
+ if (!match?.uid) {
138485
+ if (nameOnlyMatchCount > 0) {
138486
+ }
138487
+ return null;
138488
+ }
138489
+ if (match.collectionUid === collection) {
138490
+ return null;
138491
+ }
138492
+ await this.gateway.requestJson(
138493
+ {
138494
+ service: "monitors",
138495
+ method: "put",
138496
+ path: `/jobTemplates/${this.toModelId(match.uid)}?_etc=true`,
138497
+ body: { collection }
138498
+ },
138499
+ { retryTransient: false }
138500
+ );
138501
+ return { uid: match.uid, previousCollectionUid: match.collectionUid };
138502
+ }
138381
138503
  async runMonitor(uid) {
138382
138504
  await this.gateway.requestJson(
138383
138505
  {
@@ -139550,6 +139672,7 @@ function resolveInputs(env = process.env) {
139550
139672
  env
139551
139673
  );
139552
139674
  const environments = parseJsonArray(getInput2("environments-json", env) || '["prod"]');
139675
+ const secretsResolverProvider = parseSecretsResolverProvider(getInput2("secrets-resolver", env));
139553
139676
  const systemEnvMap = parseJsonMap(getInput2("system-env-map-json", env) || "{}");
139554
139677
  const environmentUids = parseJsonMap(getInput2("environment-uids-json", env) || "{}");
139555
139678
  const envRuntimeUrls = parseJsonMap(getInput2("env-runtime-urls-json", env) || "{}");
@@ -139567,6 +139690,7 @@ function resolveInputs(env = process.env) {
139567
139690
  specContentChanged: parseBooleanInput(getInput2("spec-content-changed", env), true),
139568
139691
  specPath: getInput2("spec-path", env),
139569
139692
  collectionSyncMode: normalizeCollectionSyncMode(getInput2("collection-sync-mode", env) || "refresh"),
139693
+ secretsResolverProvider,
139570
139694
  specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
139571
139695
  releaseLabel: normalizeReleaseLabel(getInput2("release-label", env)) || void 0,
139572
139696
  environments: environments.length > 0 ? environments : ["prod"],
@@ -139656,7 +139780,20 @@ function assertBranchAssetIds(inputs, decision, branchOwnedIds = process.env.POS
139656
139780
  );
139657
139781
  }
139658
139782
  }
139783
+ var CREDENTIAL_SLOT_PREFIXES = ["AWS_", "AZURE_", "GCP_"];
139784
+ function isCredentialSlotKey(key) {
139785
+ return typeof key === "string" && CREDENTIAL_SLOT_PREFIXES.some((prefix) => key.startsWith(prefix));
139786
+ }
139659
139787
  function buildEnvironmentValues(envName, baseUrl, options = {}) {
139788
+ const seeded = secretsResolverEnvironmentKeys(options.secretsResolverProvider ?? "none").map((entry) => ({
139789
+ key: entry.key,
139790
+ value: entry.key.endsWith("_SECRET_NAME") && !entry.secret ? `api-credentials-${envName}` : entry.defaultValue ?? "",
139791
+ type: entry.secret ? "secret" : "default"
139792
+ }));
139793
+ const seededKeys = new Set(seeded.map((entry) => entry.key));
139794
+ const preserved = (options.preservedCredentialValues ?? []).filter(
139795
+ (entry) => isCredentialSlotKey(entry.key) && !seededKeys.has(entry.key)
139796
+ );
139660
139797
  return [
139661
139798
  { key: "baseUrl", value: baseUrl, type: "default" },
139662
139799
  // A private mock refuses anonymous calls, so the manual-validation environment
@@ -139665,10 +139802,11 @@ function buildEnvironmentValues(envName, baseUrl, options = {}) {
139665
139802
  ...options.privateMockAuth ? [{ key: PRIVATE_MOCK_AUTH_VARIABLE2, value: "", type: "secret" }] : [],
139666
139803
  { key: "CI", value: "false", type: "default" },
139667
139804
  { key: "RESPONSE_TIME_THRESHOLD", value: "2000", type: "default" },
139668
- { key: "AWS_ACCESS_KEY_ID", value: "", type: "secret" },
139669
- { key: "AWS_SECRET_ACCESS_KEY", value: "", type: "secret" },
139670
- { key: "AWS_REGION", value: "eu-west-2", type: "default" },
139671
- { key: "AWS_SECRET_NAME", value: `api-credentials-${envName}`, type: "default" }
139805
+ // Provider-scoped credential slots. `none` (the default) seeds nothing, so a
139806
+ // consumer that does not use a cloud secret store gets a clean environment
139807
+ // instead of four dead AWS variables.
139808
+ ...seeded,
139809
+ ...preserved
139672
139810
  ];
139673
139811
  }
139674
139812
  var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
@@ -140154,19 +140292,28 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
140154
140292
  }
140155
140293
  if (existingUid) {
140156
140294
  let marker = assetMarker;
140157
- if (marker) {
140158
- try {
140159
- const existing = await dependencies.postman.getEnvironment(existingUid);
140160
- const values3 = existing.data?.values ?? existing.values ?? [];
140161
- const prior = values3.find((value) => value.key === "x-pm-onboarding")?.value;
140295
+ let priorValues = [];
140296
+ try {
140297
+ const existing = await dependencies.postman.getEnvironment(existingUid);
140298
+ const values3 = existing?.data?.values ?? existing?.values ?? [];
140299
+ priorValues = values3.filter((value) => typeof value?.key === "string").map((value) => ({
140300
+ key: value.key,
140301
+ value: typeof value.value === "string" ? value.value : "",
140302
+ type: value.type === "secret" ? "secret" : "default"
140303
+ }));
140304
+ if (marker) {
140305
+ const prior = priorValues.find((value) => value.key === "x-pm-onboarding")?.value;
140162
140306
  const priorMarker = parseAssetMarker(prior ? `x-pm-onboarding: ${prior}` : void 0);
140163
140307
  if (priorMarker?.repo === marker.repo && priorMarker.rawBranch === marker.rawBranch) {
140164
140308
  marker = { ...marker, createdAt: priorMarker.createdAt };
140165
140309
  }
140166
- } catch {
140167
140310
  }
140311
+ } catch {
140168
140312
  }
140169
- const values2 = buildEnvironmentValues(envName, runtimeUrl);
140313
+ const values2 = buildEnvironmentValues(envName, runtimeUrl, {
140314
+ secretsResolverProvider: inputs.secretsResolverProvider,
140315
+ preservedCredentialValues: priorValues
140316
+ });
140170
140317
  if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
140171
140318
  try {
140172
140319
  await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
@@ -140186,7 +140333,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
140186
140333
  dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
140187
140334
  continue;
140188
140335
  }
140189
- const values = buildEnvironmentValues(envName, runtimeUrl);
140336
+ const values = buildEnvironmentValues(envName, runtimeUrl, {
140337
+ secretsResolverProvider: inputs.secretsResolverProvider
140338
+ });
140190
140339
  if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
140191
140340
  try {
140192
140341
  envUids[envName] = await dependencies.postman.createEnvironment(
@@ -140215,7 +140364,10 @@ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, moc
140215
140364
  return "";
140216
140365
  }
140217
140366
  const displayName = `${assetProjectName} - Mock`;
140218
- const values = buildEnvironmentValues("mock", mockUrl, { privateMockAuth });
140367
+ const values = buildEnvironmentValues("mock", mockUrl, {
140368
+ privateMockAuth,
140369
+ secretsResolverProvider: inputs.secretsResolverProvider
140370
+ });
140219
140371
  const mask = resolveRepoSyncMasker(dependencies);
140220
140372
  try {
140221
140373
  const discovered = await dependencies.postman.findEnvironmentByName(
@@ -141486,6 +141638,43 @@ async function runRepoSyncInner(inputs, dependencies) {
141486
141638
  );
141487
141639
  }
141488
141640
  }
141641
+ if (!resolvedMonitorId && inputs.smokeCollectionId && dependencies.postman.rebindMonitorByName) {
141642
+ try {
141643
+ const rebound = await dependencies.postman.rebindMonitorByName(
141644
+ monitorName,
141645
+ inputs.smokeCollectionId,
141646
+ monitorEnvUid
141647
+ );
141648
+ if (rebound) {
141649
+ resolvedMonitorId = rebound.uid;
141650
+ dependencies.core.info(
141651
+ `Rebound existing monitor ${rebound.uid} ("${monitorName}") from collection ${rebound.previousCollectionUid} to ${inputs.smokeCollectionId}`
141652
+ );
141653
+ }
141654
+ } catch (error2) {
141655
+ if (error2 instanceof AmbiguousMonitorRebindError) {
141656
+ throw new Error(
141657
+ formatOrchestrationIssue({
141658
+ operation: "Monitor rebind",
141659
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
141660
+ cause: error2,
141661
+ remediation: monitorRemediation,
141662
+ mask
141663
+ }),
141664
+ { cause: error2 }
141665
+ );
141666
+ }
141667
+ dependencies.core.warning(
141668
+ formatOrchestrationIssue({
141669
+ operation: "Monitor rebind",
141670
+ entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
141671
+ cause: error2,
141672
+ remediation: monitorRemediation,
141673
+ mask
141674
+ })
141675
+ );
141676
+ }
141677
+ }
141489
141678
  if (!resolvedMonitorId) {
141490
141679
  try {
141491
141680
  resolvedMonitorId = await dependencies.postman.createMonitor(
@@ -141907,6 +142096,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
141907
142096
  listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
141908
142097
  monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
141909
142098
  findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
142099
+ rebindMonitorByName: gatewayAssets.rebindMonitorByName.bind(gatewayAssets),
141910
142100
  runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
141911
142101
  listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
141912
142102
  // GC path (preview/channel retention machine — lib/repo/preview-gc.ts).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postman-cse/onboarding-repo-sync",
3
- "version": "2.5.0",
3
+ "version": "2.6.1",
4
4
  "description": "Postman repo sync GitHub Action.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -44,7 +44,7 @@
44
44
  "dependencies": {
45
45
  "@actions/core": "^3.0.1",
46
46
  "@actions/exec": "^3.0.0",
47
- "@postman-cse/automation-core": "^1.1.0",
47
+ "@postman-cse/automation-core": "^1.2.1",
48
48
  "@postman/runtime.models": "^1.13.1",
49
49
  "@postman/v3.export": "0.2.28",
50
50
  "js-yaml": "^5.2.1",