@postman-cse/onboarding-repo-sync 2.5.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/action.yml +4 -0
- package/dist/action.cjs +180 -7
- package/dist/cli.cjs +181 -7
- package/dist/index.cjs +180 -7
- package/package.json +2 -2
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"],
|
|
@@ -139642,10 +139766,14 @@ function buildEnvironmentValues(envName, baseUrl, options = {}) {
|
|
|
139642
139766
|
...options.privateMockAuth ? [{ key: PRIVATE_MOCK_AUTH_VARIABLE2, value: "", type: "secret" }] : [],
|
|
139643
139767
|
{ key: "CI", value: "false", type: "default" },
|
|
139644
139768
|
{ key: "RESPONSE_TIME_THRESHOLD", value: "2000", type: "default" },
|
|
139645
|
-
|
|
139646
|
-
|
|
139647
|
-
|
|
139648
|
-
|
|
139769
|
+
// Provider-scoped credential slots. `none` (the default) seeds nothing, so a
|
|
139770
|
+
// consumer that does not use a cloud secret store gets a clean environment
|
|
139771
|
+
// instead of four dead AWS variables.
|
|
139772
|
+
...secretsResolverEnvironmentKeys(options.secretsResolverProvider ?? "none").map((entry) => ({
|
|
139773
|
+
key: entry.key,
|
|
139774
|
+
value: entry.key.endsWith("_SECRET_NAME") && !entry.secret ? `api-credentials-${envName}` : entry.defaultValue ?? "",
|
|
139775
|
+
type: entry.secret ? "secret" : "default"
|
|
139776
|
+
}))
|
|
139649
139777
|
];
|
|
139650
139778
|
}
|
|
139651
139779
|
var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
|
|
@@ -140143,7 +140271,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
140143
140271
|
} catch {
|
|
140144
140272
|
}
|
|
140145
140273
|
}
|
|
140146
|
-
const values2 = buildEnvironmentValues(envName, runtimeUrl
|
|
140274
|
+
const values2 = buildEnvironmentValues(envName, runtimeUrl, {
|
|
140275
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
140276
|
+
});
|
|
140147
140277
|
if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
|
|
140148
140278
|
try {
|
|
140149
140279
|
await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
|
|
@@ -140163,7 +140293,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
140163
140293
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
140164
140294
|
continue;
|
|
140165
140295
|
}
|
|
140166
|
-
const values = buildEnvironmentValues(envName, runtimeUrl
|
|
140296
|
+
const values = buildEnvironmentValues(envName, runtimeUrl, {
|
|
140297
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
140298
|
+
});
|
|
140167
140299
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
140168
140300
|
try {
|
|
140169
140301
|
envUids[envName] = await dependencies.postman.createEnvironment(
|
|
@@ -140192,7 +140324,10 @@ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, moc
|
|
|
140192
140324
|
return "";
|
|
140193
140325
|
}
|
|
140194
140326
|
const displayName = `${assetProjectName} - Mock`;
|
|
140195
|
-
const values = buildEnvironmentValues("mock", mockUrl, {
|
|
140327
|
+
const values = buildEnvironmentValues("mock", mockUrl, {
|
|
140328
|
+
privateMockAuth,
|
|
140329
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
140330
|
+
});
|
|
140196
140331
|
const mask = resolveRepoSyncMasker(dependencies);
|
|
140197
140332
|
try {
|
|
140198
140333
|
const discovered = await dependencies.postman.findEnvironmentByName(
|
|
@@ -141463,6 +141598,43 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
141463
141598
|
);
|
|
141464
141599
|
}
|
|
141465
141600
|
}
|
|
141601
|
+
if (!resolvedMonitorId && inputs.smokeCollectionId && dependencies.postman.rebindMonitorByName) {
|
|
141602
|
+
try {
|
|
141603
|
+
const rebound = await dependencies.postman.rebindMonitorByName(
|
|
141604
|
+
monitorName,
|
|
141605
|
+
inputs.smokeCollectionId,
|
|
141606
|
+
monitorEnvUid
|
|
141607
|
+
);
|
|
141608
|
+
if (rebound) {
|
|
141609
|
+
resolvedMonitorId = rebound.uid;
|
|
141610
|
+
dependencies.core.info(
|
|
141611
|
+
`Rebound existing monitor ${rebound.uid} ("${monitorName}") from collection ${rebound.previousCollectionUid} to ${inputs.smokeCollectionId}`
|
|
141612
|
+
);
|
|
141613
|
+
}
|
|
141614
|
+
} catch (error2) {
|
|
141615
|
+
if (error2 instanceof AmbiguousMonitorRebindError) {
|
|
141616
|
+
throw new Error(
|
|
141617
|
+
formatOrchestrationIssue({
|
|
141618
|
+
operation: "Monitor rebind",
|
|
141619
|
+
entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
|
|
141620
|
+
cause: error2,
|
|
141621
|
+
remediation: monitorRemediation,
|
|
141622
|
+
mask
|
|
141623
|
+
}),
|
|
141624
|
+
{ cause: error2 }
|
|
141625
|
+
);
|
|
141626
|
+
}
|
|
141627
|
+
dependencies.core.warning(
|
|
141628
|
+
formatOrchestrationIssue({
|
|
141629
|
+
operation: "Monitor rebind",
|
|
141630
|
+
entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
|
|
141631
|
+
cause: error2,
|
|
141632
|
+
remediation: monitorRemediation,
|
|
141633
|
+
mask
|
|
141634
|
+
})
|
|
141635
|
+
);
|
|
141636
|
+
}
|
|
141637
|
+
}
|
|
141466
141638
|
if (!resolvedMonitorId) {
|
|
141467
141639
|
try {
|
|
141468
141640
|
resolvedMonitorId = await dependencies.postman.createMonitor(
|
|
@@ -141884,6 +142056,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
141884
142056
|
listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
|
|
141885
142057
|
monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
|
|
141886
142058
|
findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
|
|
142059
|
+
rebindMonitorByName: gatewayAssets.rebindMonitorByName.bind(gatewayAssets),
|
|
141887
142060
|
runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
|
|
141888
142061
|
listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
|
|
141889
142062
|
// 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"],
|
|
@@ -137692,10 +137816,14 @@ function buildEnvironmentValues(envName, baseUrl, options = {}) {
|
|
|
137692
137816
|
...options.privateMockAuth ? [{ key: PRIVATE_MOCK_AUTH_VARIABLE2, value: "", type: "secret" }] : [],
|
|
137693
137817
|
{ key: "CI", value: "false", type: "default" },
|
|
137694
137818
|
{ key: "RESPONSE_TIME_THRESHOLD", value: "2000", type: "default" },
|
|
137695
|
-
|
|
137696
|
-
|
|
137697
|
-
|
|
137698
|
-
|
|
137819
|
+
// Provider-scoped credential slots. `none` (the default) seeds nothing, so a
|
|
137820
|
+
// consumer that does not use a cloud secret store gets a clean environment
|
|
137821
|
+
// instead of four dead AWS variables.
|
|
137822
|
+
...secretsResolverEnvironmentKeys(options.secretsResolverProvider ?? "none").map((entry) => ({
|
|
137823
|
+
key: entry.key,
|
|
137824
|
+
value: entry.key.endsWith("_SECRET_NAME") && !entry.secret ? `api-credentials-${envName}` : entry.defaultValue ?? "",
|
|
137825
|
+
type: entry.secret ? "secret" : "default"
|
|
137826
|
+
}))
|
|
137699
137827
|
];
|
|
137700
137828
|
}
|
|
137701
137829
|
var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
|
|
@@ -138051,7 +138179,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
138051
138179
|
} catch {
|
|
138052
138180
|
}
|
|
138053
138181
|
}
|
|
138054
|
-
const values2 = buildEnvironmentValues(envName, runtimeUrl
|
|
138182
|
+
const values2 = buildEnvironmentValues(envName, runtimeUrl, {
|
|
138183
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
138184
|
+
});
|
|
138055
138185
|
if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
|
|
138056
138186
|
try {
|
|
138057
138187
|
await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
|
|
@@ -138071,7 +138201,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
138071
138201
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
138072
138202
|
continue;
|
|
138073
138203
|
}
|
|
138074
|
-
const values = buildEnvironmentValues(envName, runtimeUrl
|
|
138204
|
+
const values = buildEnvironmentValues(envName, runtimeUrl, {
|
|
138205
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
138206
|
+
});
|
|
138075
138207
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
138076
138208
|
try {
|
|
138077
138209
|
envUids[envName] = await dependencies.postman.createEnvironment(
|
|
@@ -138100,7 +138232,10 @@ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, moc
|
|
|
138100
138232
|
return "";
|
|
138101
138233
|
}
|
|
138102
138234
|
const displayName = `${assetProjectName} - Mock`;
|
|
138103
|
-
const values = buildEnvironmentValues("mock", mockUrl, {
|
|
138235
|
+
const values = buildEnvironmentValues("mock", mockUrl, {
|
|
138236
|
+
privateMockAuth,
|
|
138237
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
138238
|
+
});
|
|
138104
138239
|
const mask = resolveRepoSyncMasker(dependencies);
|
|
138105
138240
|
try {
|
|
138106
138241
|
const discovered = await dependencies.postman.findEnvironmentByName(
|
|
@@ -139371,6 +139506,43 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
139371
139506
|
);
|
|
139372
139507
|
}
|
|
139373
139508
|
}
|
|
139509
|
+
if (!resolvedMonitorId && inputs.smokeCollectionId && dependencies.postman.rebindMonitorByName) {
|
|
139510
|
+
try {
|
|
139511
|
+
const rebound = await dependencies.postman.rebindMonitorByName(
|
|
139512
|
+
monitorName,
|
|
139513
|
+
inputs.smokeCollectionId,
|
|
139514
|
+
monitorEnvUid
|
|
139515
|
+
);
|
|
139516
|
+
if (rebound) {
|
|
139517
|
+
resolvedMonitorId = rebound.uid;
|
|
139518
|
+
dependencies.core.info(
|
|
139519
|
+
`Rebound existing monitor ${rebound.uid} ("${monitorName}") from collection ${rebound.previousCollectionUid} to ${inputs.smokeCollectionId}`
|
|
139520
|
+
);
|
|
139521
|
+
}
|
|
139522
|
+
} catch (error) {
|
|
139523
|
+
if (error instanceof AmbiguousMonitorRebindError) {
|
|
139524
|
+
throw new Error(
|
|
139525
|
+
formatOrchestrationIssue({
|
|
139526
|
+
operation: "Monitor rebind",
|
|
139527
|
+
entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
|
|
139528
|
+
cause: error,
|
|
139529
|
+
remediation: monitorRemediation,
|
|
139530
|
+
mask
|
|
139531
|
+
}),
|
|
139532
|
+
{ cause: error }
|
|
139533
|
+
);
|
|
139534
|
+
}
|
|
139535
|
+
dependencies.core.warning(
|
|
139536
|
+
formatOrchestrationIssue({
|
|
139537
|
+
operation: "Monitor rebind",
|
|
139538
|
+
entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
|
|
139539
|
+
cause: error,
|
|
139540
|
+
remediation: monitorRemediation,
|
|
139541
|
+
mask
|
|
139542
|
+
})
|
|
139543
|
+
);
|
|
139544
|
+
}
|
|
139545
|
+
}
|
|
139374
139546
|
if (!resolvedMonitorId) {
|
|
139375
139547
|
try {
|
|
139376
139548
|
resolvedMonitorId = await dependencies.postman.createMonitor(
|
|
@@ -139792,6 +139964,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
139792
139964
|
listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
|
|
139793
139965
|
monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
|
|
139794
139966
|
findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
|
|
139967
|
+
rebindMonitorByName: gatewayAssets.rebindMonitorByName.bind(gatewayAssets),
|
|
139795
139968
|
runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
|
|
139796
139969
|
listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
|
|
139797
139970
|
// GC path (preview/channel retention machine — lib/repo/preview-gc.ts).
|
|
@@ -140292,6 +140465,7 @@ var CLI_INPUT_NAMES = [
|
|
|
140292
140465
|
"spec-content-changed",
|
|
140293
140466
|
"spec-path",
|
|
140294
140467
|
"team-id",
|
|
140468
|
+
"secrets-resolver",
|
|
140295
140469
|
"postman-region",
|
|
140296
140470
|
"postman-stack",
|
|
140297
140471
|
"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"],
|
|
@@ -139665,10 +139789,14 @@ function buildEnvironmentValues(envName, baseUrl, options = {}) {
|
|
|
139665
139789
|
...options.privateMockAuth ? [{ key: PRIVATE_MOCK_AUTH_VARIABLE2, value: "", type: "secret" }] : [],
|
|
139666
139790
|
{ key: "CI", value: "false", type: "default" },
|
|
139667
139791
|
{ key: "RESPONSE_TIME_THRESHOLD", value: "2000", type: "default" },
|
|
139668
|
-
|
|
139669
|
-
|
|
139670
|
-
|
|
139671
|
-
|
|
139792
|
+
// Provider-scoped credential slots. `none` (the default) seeds nothing, so a
|
|
139793
|
+
// consumer that does not use a cloud secret store gets a clean environment
|
|
139794
|
+
// instead of four dead AWS variables.
|
|
139795
|
+
...secretsResolverEnvironmentKeys(options.secretsResolverProvider ?? "none").map((entry) => ({
|
|
139796
|
+
key: entry.key,
|
|
139797
|
+
value: entry.key.endsWith("_SECRET_NAME") && !entry.secret ? `api-credentials-${envName}` : entry.defaultValue ?? "",
|
|
139798
|
+
type: entry.secret ? "secret" : "default"
|
|
139799
|
+
}))
|
|
139672
139800
|
];
|
|
139673
139801
|
}
|
|
139674
139802
|
var LEGACY_BASELINE_COLLECTION_PREFIX = "[Baseline]";
|
|
@@ -140166,7 +140294,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
140166
140294
|
} catch {
|
|
140167
140295
|
}
|
|
140168
140296
|
}
|
|
140169
|
-
const values2 = buildEnvironmentValues(envName, runtimeUrl
|
|
140297
|
+
const values2 = buildEnvironmentValues(envName, runtimeUrl, {
|
|
140298
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
140299
|
+
});
|
|
140170
140300
|
if (marker) values2.push({ key: "x-pm-onboarding", value: JSON.stringify(marker), type: "default" });
|
|
140171
140301
|
try {
|
|
140172
140302
|
await dependencies.postman.updateEnvironment(existingUid, displayName, values2);
|
|
@@ -140186,7 +140316,9 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
140186
140316
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
140187
140317
|
continue;
|
|
140188
140318
|
}
|
|
140189
|
-
const values = buildEnvironmentValues(envName, runtimeUrl
|
|
140319
|
+
const values = buildEnvironmentValues(envName, runtimeUrl, {
|
|
140320
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
140321
|
+
});
|
|
140190
140322
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
140191
140323
|
try {
|
|
140192
140324
|
envUids[envName] = await dependencies.postman.createEnvironment(
|
|
@@ -140215,7 +140347,10 @@ async function upsertMockEnvironment(inputs, dependencies, assetProjectName, moc
|
|
|
140215
140347
|
return "";
|
|
140216
140348
|
}
|
|
140217
140349
|
const displayName = `${assetProjectName} - Mock`;
|
|
140218
|
-
const values = buildEnvironmentValues("mock", mockUrl, {
|
|
140350
|
+
const values = buildEnvironmentValues("mock", mockUrl, {
|
|
140351
|
+
privateMockAuth,
|
|
140352
|
+
secretsResolverProvider: inputs.secretsResolverProvider
|
|
140353
|
+
});
|
|
140219
140354
|
const mask = resolveRepoSyncMasker(dependencies);
|
|
140220
140355
|
try {
|
|
140221
140356
|
const discovered = await dependencies.postman.findEnvironmentByName(
|
|
@@ -141486,6 +141621,43 @@ async function runRepoSyncInner(inputs, dependencies) {
|
|
|
141486
141621
|
);
|
|
141487
141622
|
}
|
|
141488
141623
|
}
|
|
141624
|
+
if (!resolvedMonitorId && inputs.smokeCollectionId && dependencies.postman.rebindMonitorByName) {
|
|
141625
|
+
try {
|
|
141626
|
+
const rebound = await dependencies.postman.rebindMonitorByName(
|
|
141627
|
+
monitorName,
|
|
141628
|
+
inputs.smokeCollectionId,
|
|
141629
|
+
monitorEnvUid
|
|
141630
|
+
);
|
|
141631
|
+
if (rebound) {
|
|
141632
|
+
resolvedMonitorId = rebound.uid;
|
|
141633
|
+
dependencies.core.info(
|
|
141634
|
+
`Rebound existing monitor ${rebound.uid} ("${monitorName}") from collection ${rebound.previousCollectionUid} to ${inputs.smokeCollectionId}`
|
|
141635
|
+
);
|
|
141636
|
+
}
|
|
141637
|
+
} catch (error2) {
|
|
141638
|
+
if (error2 instanceof AmbiguousMonitorRebindError) {
|
|
141639
|
+
throw new Error(
|
|
141640
|
+
formatOrchestrationIssue({
|
|
141641
|
+
operation: "Monitor rebind",
|
|
141642
|
+
entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
|
|
141643
|
+
cause: error2,
|
|
141644
|
+
remediation: monitorRemediation,
|
|
141645
|
+
mask
|
|
141646
|
+
}),
|
|
141647
|
+
{ cause: error2 }
|
|
141648
|
+
);
|
|
141649
|
+
}
|
|
141650
|
+
dependencies.core.warning(
|
|
141651
|
+
formatOrchestrationIssue({
|
|
141652
|
+
operation: "Monitor rebind",
|
|
141653
|
+
entity: `monitor "${monitorName}" workspace ${inputs.workspaceId} collection ${inputs.smokeCollectionId} environment ${monitorEnvUid}`,
|
|
141654
|
+
cause: error2,
|
|
141655
|
+
remediation: monitorRemediation,
|
|
141656
|
+
mask
|
|
141657
|
+
})
|
|
141658
|
+
);
|
|
141659
|
+
}
|
|
141660
|
+
}
|
|
141489
141661
|
if (!resolvedMonitorId) {
|
|
141490
141662
|
try {
|
|
141491
141663
|
resolvedMonitorId = await dependencies.postman.createMonitor(
|
|
@@ -141907,6 +142079,7 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
141907
142079
|
listMonitors: gatewayAssets.listMonitors.bind(gatewayAssets),
|
|
141908
142080
|
monitorExists: gatewayAssets.monitorExists.bind(gatewayAssets),
|
|
141909
142081
|
findMonitorByCollection: gatewayAssets.findMonitorByCollection.bind(gatewayAssets),
|
|
142082
|
+
rebindMonitorByName: gatewayAssets.rebindMonitorByName.bind(gatewayAssets),
|
|
141910
142083
|
runMonitor: gatewayAssets.runMonitor.bind(gatewayAssets),
|
|
141911
142084
|
listEnvironments: gatewayAssets.listEnvironments.bind(gatewayAssets),
|
|
141912
142085
|
// 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.
|
|
3
|
+
"version": "2.6.0",
|
|
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.
|
|
47
|
+
"@postman-cse/automation-core": "^1.2.0",
|
|
48
48
|
"@postman/runtime.models": "^1.13.1",
|
|
49
49
|
"@postman/v3.export": "0.2.28",
|
|
50
50
|
"js-yaml": "^5.2.1",
|