@postman-cs/onboarding-repo-sync 2.10.8 → 2.11.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 +11 -2
- package/action.yml +2 -2
- package/dist/action.cjs +183 -43
- package/dist/cli.cjs +183 -43
- package/dist/index.cjs +183 -43
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -69,6 +69,15 @@ The example permissions let `GITHUB_TOKEN` commit generated artifacts and update
|
|
|
69
69
|
|
|
70
70
|
`postman-access-token` is required: every asset operation (environment create/get/update, collection read, mock, monitor) plus workspace-to-repository linking and system environment association runs through the access-token gateway. Use `postman-resolve-service-token-action` to mint it at runtime from a [Postman service account](https://learning.postman.com/docs/administration/service-accounts/) PMAK. Without it the action fails fast — the PMAK is not an asset-routing fallback; it only mints/re-mints the access token, powers the generated CI workflow's `postman login --with-api-key`, and mints the CI `POSTMAN_API_KEY` secret. See [docs/credentials.md](docs/credentials.md).
|
|
71
71
|
|
|
72
|
+
To manage the complete values for an environment, use a rich entry in the same input. String entries remain backward-compatible and receive generated values; rich entries replace the environment values exactly as supplied (plus the action's branch-ownership marker when applicable).
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
environments-json: >-
|
|
76
|
+
[{"slug":"dev","values":[{"key":"baseUrl","value":"https://dev.example.com"},{"key":"jwtToken","value":"","type":"secret"}]}]
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Secret-typed values must be empty. Supply the real secret as a masked runtime variable from the customer's vault when running the collection; repo-sync neither reads nor persists that value. `value`, `type`, and `enabled` default to `""`, `"default"`, and `true`. `env-runtime-urls-json` and generated credential slots apply only to string entries because a rich entry is the complete desired definition.
|
|
80
|
+
|
|
72
81
|
### Disable CI workflow generation
|
|
73
82
|
|
|
74
83
|
For existing repositories that already own their CI workflow, disable workflow generation:
|
|
@@ -169,7 +178,7 @@ with:
|
|
|
169
178
|
| `smoke-collection-id` | Smoke collection ID used for monitor creation. | no | |
|
|
170
179
|
| `contract-collection-id` | Contract collection ID used for exported artifacts. | no | |
|
|
171
180
|
| `onboarding-scope` | Onboarding scope. Use full for the complete pipeline or spec-only for repository linking and workspace/spec state only. | no | `full` |
|
|
172
|
-
| `prebuilt-collections-json` | Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without cloud
|
|
181
|
+
| `prebuilt-collections-json` | Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without a cloud snapshot read. | no | `""` |
|
|
173
182
|
| `collection-sync-mode` | Collection sync lifecycle mode (refresh or version). | no | `refresh` |
|
|
174
183
|
| `spec-sync-mode` | Spec sync lifecycle mode (update or version). | no | `update` |
|
|
175
184
|
| `release-label` | Optional release label used for versioned naming. | no | |
|
|
@@ -178,7 +187,7 @@ with:
|
|
|
178
187
|
| `mock-visibility` | Required mock access policy. Public is anonymous; private requires a runtime x-api-key supplied by the caller and is never persisted by repo-sync. | no | `private` |
|
|
179
188
|
| `mock-environment-enabled` | Create or update a dedicated manual-validation environment whose baseUrl is the validated mock URL. This environment is excluded from runtime CI selection and never contains a mock credential. | no | `false` |
|
|
180
189
|
| `monitor-cron` | Cron expression for monitor scheduling (e.g. '0 */6 * * *'). When empty, the monitor is created disabled and triggered to run once per workflow invocation (and once on every subsequent run). | no | `""` |
|
|
181
|
-
| `environments-json` | JSON array of environment slugs to create or
|
|
190
|
+
| `environments-json` | JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots. | no | `["prod"]` |
|
|
182
191
|
| `git-provider` | Git provider override ('github', 'gitlab', 'bitbucket', 'azure-devops'). Auto-detected from environment when omitted. | no | |
|
|
183
192
|
| `ado-token` | Azure DevOps personal access token or system token used to push commits in Azure Pipelines. Defaults to SYSTEM_ACCESSTOKEN when available. | no | |
|
|
184
193
|
| `repo-url` | Explicit repository URL (GitHub, GitLab, or Azure DevOps). Defaults to the URL inferred from runner environment when omitted. For commit-and-push it must identify the checked-out origin. | no | |
|
package/action.yml
CHANGED
|
@@ -43,7 +43,7 @@ inputs:
|
|
|
43
43
|
required: false
|
|
44
44
|
default: full
|
|
45
45
|
prebuilt-collections-json:
|
|
46
|
-
description: Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without cloud
|
|
46
|
+
description: Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without a cloud snapshot read.
|
|
47
47
|
required: false
|
|
48
48
|
default: ''
|
|
49
49
|
collection-sync-mode:
|
|
@@ -76,7 +76,7 @@ inputs:
|
|
|
76
76
|
required: false
|
|
77
77
|
default: ""
|
|
78
78
|
environments-json:
|
|
79
|
-
description: JSON array of environment slugs to create or
|
|
79
|
+
description: JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.
|
|
80
80
|
required: false
|
|
81
81
|
default: '["prod"]'
|
|
82
82
|
git-provider:
|
package/dist/action.cjs
CHANGED
|
@@ -117719,6 +117719,7 @@ var path6 = __toESM(require("node:path"), 1);
|
|
|
117719
117719
|
var V2 = __toESM(require_v2(), 1);
|
|
117720
117720
|
var import_transforms = __toESM(require_transforms(), 1);
|
|
117721
117721
|
var import_v3 = __toESM(require_node2(), 1);
|
|
117722
|
+
var V2_COLLECTION_MODEL = V2.Collection;
|
|
117722
117723
|
function asArray(value) {
|
|
117723
117724
|
return Array.isArray(value) ? value : [];
|
|
117724
117725
|
}
|
|
@@ -117739,13 +117740,23 @@ function normalizeGraphqlRequests(node) {
|
|
|
117739
117740
|
}
|
|
117740
117741
|
}
|
|
117741
117742
|
async function convertAndSplitCollection(v2Collection, outputDir) {
|
|
117742
|
-
const
|
|
117743
|
-
|
|
117744
|
-
|
|
117743
|
+
const v3 = convertV2CollectionToV3Collection(v2Collection);
|
|
117744
|
+
await writeSplitCollection(v3, outputDir);
|
|
117745
|
+
}
|
|
117746
|
+
function convertV2CollectionToV3Collection(v2Collection) {
|
|
117747
|
+
const parsed = V2_COLLECTION_MODEL.parse(v2Collection ?? {});
|
|
117748
|
+
const v3 = (0, import_transforms.transform)(
|
|
117749
|
+
V2_COLLECTION_MODEL,
|
|
117750
|
+
import_transforms.FormatVersion.V3,
|
|
117751
|
+
parsed
|
|
117752
|
+
);
|
|
117745
117753
|
for (const item of asArray(v3.items)) {
|
|
117746
117754
|
normalizeGraphqlRequests(item);
|
|
117747
117755
|
}
|
|
117748
|
-
|
|
117756
|
+
return v3;
|
|
117757
|
+
}
|
|
117758
|
+
function assertV2CollectionModel(value) {
|
|
117759
|
+
V2_COLLECTION_MODEL.parse(value ?? {});
|
|
117749
117760
|
}
|
|
117750
117761
|
function normalizeV3ExportIds(node) {
|
|
117751
117762
|
if (!node || typeof node !== "object") return;
|
|
@@ -121303,7 +121314,7 @@ var postmanRepoSyncActionContract = {
|
|
|
121303
121314
|
allowedValues: ["full", "spec-only"]
|
|
121304
121315
|
},
|
|
121305
121316
|
"prebuilt-collections-json": {
|
|
121306
|
-
description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without cloud
|
|
121317
|
+
description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without a cloud snapshot read.",
|
|
121307
121318
|
required: false,
|
|
121308
121319
|
default: ""
|
|
121309
121320
|
},
|
|
@@ -121346,7 +121357,7 @@ var postmanRepoSyncActionContract = {
|
|
|
121346
121357
|
default: ""
|
|
121347
121358
|
},
|
|
121348
121359
|
"environments-json": {
|
|
121349
|
-
description: "JSON array of environment slugs to create or
|
|
121360
|
+
description: "JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.",
|
|
121350
121361
|
required: false,
|
|
121351
121362
|
default: '["prod"]'
|
|
121352
121363
|
},
|
|
@@ -127837,8 +127848,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127837
127848
|
}
|
|
127838
127849
|
/**
|
|
127839
127850
|
* Validate and normalize a collection public UID for routes that require the
|
|
127840
|
-
* full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments):
|
|
127841
|
-
*
|
|
127851
|
+
* full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments): populated
|
|
127852
|
+
* collection snapshot, collection-root PATCH/read, and private-mock runtime auth.
|
|
127842
127853
|
*
|
|
127843
127854
|
* - Trims once.
|
|
127844
127855
|
* - Rejects empty values.
|
|
@@ -128150,32 +128161,52 @@ var PostmanGatewayAssetsClient = class {
|
|
|
128150
128161
|
);
|
|
128151
128162
|
return match?.uid ? { uid: match.uid, name: match.name } : null;
|
|
128152
128163
|
}
|
|
128153
|
-
// --- collection read (service:
|
|
128164
|
+
// --- collection read (service: sync, populated v2.1 snapshot) ---
|
|
128154
128165
|
//
|
|
128155
|
-
//
|
|
128156
|
-
//
|
|
128157
|
-
//
|
|
128158
|
-
//
|
|
128159
|
-
//
|
|
128160
|
-
//
|
|
128161
|
-
// is rejected on root mutation routes (403 FORBIDDEN) and must not be used
|
|
128162
|
-
// here either, so the caller is responsible for passing the public UID.
|
|
128166
|
+
// This is the canonical full collection read used by
|
|
128167
|
+
// api-specification-service before whole-tree Sync updates. Collection v3
|
|
128168
|
+
// `/export` performs an expensive projection and has returned 500s for fresh
|
|
128169
|
+
// roots under provider load. The populated Sync read returns the complete
|
|
128170
|
+
// v2.1 model directly and is transformed in memory through the official
|
|
128171
|
+
// runtime.models V2 -> V3 pipeline before repository materialization.
|
|
128163
128172
|
/**
|
|
128164
|
-
* Fetch
|
|
128165
|
-
*
|
|
128166
|
-
*
|
|
128167
|
-
* disk via `convertAndSplitV3Collection`. PMAK is never used for collection
|
|
128168
|
-
* reads.
|
|
128173
|
+
* Fetch one complete v2.1 collection through a single retry-free populated
|
|
128174
|
+
* Sync GET. The response must be a v2.1 model for the requested public UID;
|
|
128175
|
+
* malformed or foreign snapshots fail closed. PMAK is never used.
|
|
128169
128176
|
*/
|
|
128170
128177
|
async getCollection(uid) {
|
|
128171
128178
|
const id = this.requireCollectionPublicUid(uid);
|
|
128172
128179
|
const response = await this.gateway.requestJson({
|
|
128173
|
-
service: "
|
|
128180
|
+
service: "sync",
|
|
128174
128181
|
method: "get",
|
|
128175
|
-
path: `/
|
|
128176
|
-
|
|
128177
|
-
|
|
128178
|
-
|
|
128182
|
+
path: `/collection/${encodeURIComponent(id)}`,
|
|
128183
|
+
query: { populate: "true", format: "2.1.0", uid: "false" },
|
|
128184
|
+
retry: "none",
|
|
128185
|
+
fallback: "none"
|
|
128186
|
+
});
|
|
128187
|
+
const collection = this.asRecord(response?.data);
|
|
128188
|
+
const info2 = this.asRecord(collection?.info);
|
|
128189
|
+
const schema = typeof info2?.schema === "string" ? info2.schema.trim() : "";
|
|
128190
|
+
if (!collection || !info2 || typeof info2.name !== "string" || !info2.name.trim() || !/\/collection\/v2\.1\.0\/collection\.json\/?$/i.test(schema) || !Array.isArray(collection.item)) {
|
|
128191
|
+
throw new Error(
|
|
128192
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync read did not return a complete v2.1 collection"
|
|
128193
|
+
);
|
|
128194
|
+
}
|
|
128195
|
+
try {
|
|
128196
|
+
assertV2CollectionModel(collection);
|
|
128197
|
+
} catch (error2) {
|
|
128198
|
+
throw new Error(
|
|
128199
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync payload failed v2.1 schema validation",
|
|
128200
|
+
{ cause: error2 }
|
|
128201
|
+
);
|
|
128202
|
+
}
|
|
128203
|
+
const observedId = String(info2._postman_id ?? collection.id ?? "").trim();
|
|
128204
|
+
if (!observedId || this.toModelId(observedId).toLowerCase() !== this.toModelId(id).toLowerCase()) {
|
|
128205
|
+
throw new Error(
|
|
128206
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync read returned a different collection identity"
|
|
128207
|
+
);
|
|
128208
|
+
}
|
|
128209
|
+
return collection;
|
|
128179
128210
|
}
|
|
128180
128211
|
// --- mocks (service: mock) ---
|
|
128181
128212
|
async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "private") {
|
|
@@ -129567,13 +129598,117 @@ function parseJsonMap(raw) {
|
|
|
129567
129598
|
])
|
|
129568
129599
|
);
|
|
129569
129600
|
}
|
|
129570
|
-
function
|
|
129571
|
-
if (!raw.trim()) return [];
|
|
129572
|
-
|
|
129601
|
+
function parseEnvironmentInputs(raw) {
|
|
129602
|
+
if (!raw.trim()) return { environments: [], definitions: /* @__PURE__ */ Object.create(null) };
|
|
129603
|
+
let parsed;
|
|
129604
|
+
try {
|
|
129605
|
+
parsed = JSON.parse(raw);
|
|
129606
|
+
} catch {
|
|
129607
|
+
throw new Error("environments-json must contain valid JSON");
|
|
129608
|
+
}
|
|
129573
129609
|
if (!Array.isArray(parsed)) {
|
|
129574
|
-
throw new Error("
|
|
129610
|
+
throw new Error("environments-json must be a JSON array");
|
|
129611
|
+
}
|
|
129612
|
+
const environments = [];
|
|
129613
|
+
const definitions = /* @__PURE__ */ Object.create(null);
|
|
129614
|
+
const seen = /* @__PURE__ */ new Map();
|
|
129615
|
+
parsed.forEach((entry, environmentIndex) => {
|
|
129616
|
+
const label = `environments-json[${environmentIndex}]`;
|
|
129617
|
+
let slug;
|
|
129618
|
+
let rich = false;
|
|
129619
|
+
if (typeof entry === "string") {
|
|
129620
|
+
slug = entry;
|
|
129621
|
+
} else {
|
|
129622
|
+
if (!isPlainObject2(entry)) {
|
|
129623
|
+
throw new Error(`${label} must be a slug string or an environment definition`);
|
|
129624
|
+
}
|
|
129625
|
+
const unknownFields = Object.keys(entry).filter((key) => key !== "slug" && key !== "values");
|
|
129626
|
+
if (unknownFields.length > 0) {
|
|
129627
|
+
throw new Error(`${label} contains unsupported field "${unknownFields[0]}"`);
|
|
129628
|
+
}
|
|
129629
|
+
if (typeof entry.slug !== "string" || !Array.isArray(entry.values)) {
|
|
129630
|
+
throw new Error(`${label} must contain a string slug and a values array`);
|
|
129631
|
+
}
|
|
129632
|
+
slug = entry.slug;
|
|
129633
|
+
rich = true;
|
|
129634
|
+
const keys = /* @__PURE__ */ new Set();
|
|
129635
|
+
definitions[slug] = entry.values.map((value, valueIndex) => {
|
|
129636
|
+
const valueLabel = `${label}.values[${valueIndex}]`;
|
|
129637
|
+
if (!isPlainObject2(value)) {
|
|
129638
|
+
throw new Error(`${valueLabel} must be an object`);
|
|
129639
|
+
}
|
|
129640
|
+
const unknownValueFields = Object.keys(value).filter(
|
|
129641
|
+
(key) => !["key", "value", "type", "enabled"].includes(key)
|
|
129642
|
+
);
|
|
129643
|
+
if (unknownValueFields.length > 0) {
|
|
129644
|
+
throw new Error(`${valueLabel} contains unsupported field "${unknownValueFields[0]}"`);
|
|
129645
|
+
}
|
|
129646
|
+
if (typeof value.key !== "string" || !value.key.trim() || value.key !== value.key.trim()) {
|
|
129647
|
+
throw new Error(`${valueLabel}.key must be a non-empty string without surrounding whitespace`);
|
|
129648
|
+
}
|
|
129649
|
+
if (value.key === "x-pm-onboarding") {
|
|
129650
|
+
throw new Error(`${valueLabel}.key is reserved by repo-sync`);
|
|
129651
|
+
}
|
|
129652
|
+
if (keys.has(value.key)) {
|
|
129653
|
+
throw new Error(`${label} contains duplicate variable key "${value.key}"`);
|
|
129654
|
+
}
|
|
129655
|
+
keys.add(value.key);
|
|
129656
|
+
if (value.value !== void 0 && typeof value.value !== "string") {
|
|
129657
|
+
throw new Error(`${valueLabel}.value must be a string when provided`);
|
|
129658
|
+
}
|
|
129659
|
+
if (value.type !== void 0 && value.type !== "default" && value.type !== "secret") {
|
|
129660
|
+
throw new Error(`${valueLabel}.type must be "default" or "secret"`);
|
|
129661
|
+
}
|
|
129662
|
+
if (value.enabled !== void 0 && typeof value.enabled !== "boolean") {
|
|
129663
|
+
throw new Error(`${valueLabel}.enabled must be a boolean when provided`);
|
|
129664
|
+
}
|
|
129665
|
+
const type = value.type ?? "default";
|
|
129666
|
+
const normalizedValue = value.value ?? "";
|
|
129667
|
+
if (type === "secret" && normalizedValue) {
|
|
129668
|
+
throw new Error(`${valueLabel} cannot contain a populated secret value; inject it at runtime`);
|
|
129669
|
+
}
|
|
129670
|
+
return { key: value.key, value: normalizedValue, type, enabled: value.enabled ?? true };
|
|
129671
|
+
});
|
|
129672
|
+
}
|
|
129673
|
+
if (rich && !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(slug)) {
|
|
129674
|
+
throw new Error(`${label} rich slug must use only letters, numbers, dots, hyphens, or underscores`);
|
|
129675
|
+
}
|
|
129676
|
+
if (rich && Object.prototype.hasOwnProperty.call(Object.prototype, slug)) {
|
|
129677
|
+
throw new Error(`${label} rich slug conflicts with a reserved object property`);
|
|
129678
|
+
}
|
|
129679
|
+
if (rich && /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(slug)) {
|
|
129680
|
+
throw new Error(`${label} rich slug conflicts with a Windows device name`);
|
|
129681
|
+
}
|
|
129682
|
+
if (!rich && !slug.trim()) {
|
|
129683
|
+
throw new Error(`${label} slug must be a non-empty string`);
|
|
129684
|
+
}
|
|
129685
|
+
const priorWasRich = seen.get(slug);
|
|
129686
|
+
if (priorWasRich !== void 0 && (rich || priorWasRich)) {
|
|
129687
|
+
throw new Error(`environments-json contains duplicate slug "${slug}"`);
|
|
129688
|
+
}
|
|
129689
|
+
if (priorWasRich === void 0) seen.set(slug, rich);
|
|
129690
|
+
environments.push(slug);
|
|
129691
|
+
});
|
|
129692
|
+
return { environments, definitions };
|
|
129693
|
+
}
|
|
129694
|
+
function normalizeProgrammaticEnvironmentDefinitions(inputs) {
|
|
129695
|
+
const definitions = inputs.environmentDefinitions;
|
|
129696
|
+
if (!definitions) return inputs;
|
|
129697
|
+
const prototype = Object.getPrototypeOf(definitions);
|
|
129698
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
129699
|
+
throw new Error("environmentDefinitions must be a plain object");
|
|
129700
|
+
}
|
|
129701
|
+
const entries = inputs.environments.map(
|
|
129702
|
+
(slug) => Object.prototype.hasOwnProperty.call(definitions, slug) ? { slug, values: definitions[slug] } : slug
|
|
129703
|
+
);
|
|
129704
|
+
let raw;
|
|
129705
|
+
try {
|
|
129706
|
+
raw = JSON.stringify(entries);
|
|
129707
|
+
} catch {
|
|
129708
|
+
throw new Error("environmentDefinitions must contain JSON-serializable values");
|
|
129575
129709
|
}
|
|
129576
|
-
|
|
129710
|
+
const parsed = parseEnvironmentInputs(raw);
|
|
129711
|
+
return { ...inputs, environments: parsed.environments, environmentDefinitions: parsed.definitions };
|
|
129577
129712
|
}
|
|
129578
129713
|
function readInput(actionCore, name, required = false) {
|
|
129579
129714
|
return actionCore.getInput(name, { required }).trim();
|
|
@@ -129670,7 +129805,7 @@ function resolveInputs(env = process.env) {
|
|
|
129670
129805
|
},
|
|
129671
129806
|
env
|
|
129672
129807
|
);
|
|
129673
|
-
const
|
|
129808
|
+
const parsedEnvironments = parseEnvironmentInputs(getInput2("environments-json", env) || '["prod"]');
|
|
129674
129809
|
const secretsResolverProvider = parseSecretsResolverProvider(getInput2("secrets-resolver", env));
|
|
129675
129810
|
const systemEnvMap = parseJsonMap(getInput2("system-env-map-json", env) || "{}");
|
|
129676
129811
|
const environmentUids = parseJsonMap(getInput2("environment-uids-json", env) || "{}");
|
|
@@ -129708,7 +129843,8 @@ function resolveInputs(env = process.env) {
|
|
|
129708
129843
|
secretsResolverProvider,
|
|
129709
129844
|
specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
|
|
129710
129845
|
releaseLabel: normalizeReleaseLabel(getInput2("release-label", env)) || void 0,
|
|
129711
|
-
environments: environments.length > 0 ? environments : ["prod"],
|
|
129846
|
+
environments: parsedEnvironments.environments.length > 0 ? parsedEnvironments.environments : ["prod"],
|
|
129847
|
+
environmentDefinitions: parsedEnvironments.definitions,
|
|
129712
129848
|
repoUrl: repoContext.repoUrl || "",
|
|
129713
129849
|
integrationBackend: getInput2("integration-backend", env) || "bifrost",
|
|
129714
129850
|
workspaceLinkEnabled: parseBooleanInput(getInput2("workspace-link-enabled", env), true),
|
|
@@ -130376,7 +130512,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130376
130512
|
}
|
|
130377
130513
|
} catch {
|
|
130378
130514
|
}
|
|
130379
|
-
const
|
|
130515
|
+
const definedValues2 = inputs.environmentDefinitions?.[envName];
|
|
130516
|
+
const values2 = definedValues2 ? definedValues2.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130380
130517
|
secretsResolverProvider: inputs.secretsResolverProvider,
|
|
130381
130518
|
preservedCredentialValues: priorValues
|
|
130382
130519
|
});
|
|
@@ -130399,7 +130536,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130399
130536
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
130400
130537
|
continue;
|
|
130401
130538
|
}
|
|
130402
|
-
const
|
|
130539
|
+
const definedValues = inputs.environmentDefinitions?.[envName];
|
|
130540
|
+
const values = definedValues ? definedValues.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130403
130541
|
secretsResolverProvider: inputs.secretsResolverProvider
|
|
130404
130542
|
});
|
|
130405
130543
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
@@ -131183,13 +131321,14 @@ function applyPrivateMockPrebuiltPlans(plans) {
|
|
|
131183
131321
|
}
|
|
131184
131322
|
}
|
|
131185
131323
|
async function preparePrivateMockCloudCollection(role, collectionId, postman) {
|
|
131186
|
-
const
|
|
131187
|
-
const
|
|
131324
|
+
const snapshot = await postman.getCollection(collectionId);
|
|
131325
|
+
const v3Collection = convertV2CollectionToV3Collection(snapshot);
|
|
131326
|
+
const { collection } = applyPrivateMockExportCleanup(v3Collection, {
|
|
131188
131327
|
stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
|
|
131189
131328
|
});
|
|
131190
131329
|
if (!verifyPrivateMockRootHook(collection)) {
|
|
131191
131330
|
throw new Error(
|
|
131192
|
-
`PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from
|
|
131331
|
+
`PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from populated ${role} collection snapshot ${collectionId}`
|
|
131193
131332
|
);
|
|
131194
131333
|
}
|
|
131195
131334
|
return collection;
|
|
@@ -131235,7 +131374,7 @@ async function acquireCollectionArtifact(options) {
|
|
|
131235
131374
|
return { reusePrebuilt: true };
|
|
131236
131375
|
}
|
|
131237
131376
|
if (entry) {
|
|
131238
|
-
core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection;
|
|
131377
|
+
core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection; reading populated cloud snapshot` : `Prebuilt ${role} collection entry present but did not exactly match; reading populated cloud snapshot`);
|
|
131239
131378
|
}
|
|
131240
131379
|
const cloud = privateMockAuth ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
|
|
131241
131380
|
return { reusePrebuilt: false, cloudCollection: cloud };
|
|
@@ -131589,6 +131728,7 @@ async function commitAndPushGeneratedFiles(inputs, dependencies, privateMockAuth
|
|
|
131589
131728
|
};
|
|
131590
131729
|
}
|
|
131591
131730
|
async function runRepoSync(inputs, dependencies, executionContext) {
|
|
131731
|
+
inputs = normalizeProgrammaticEnvironmentDefinitions(inputs);
|
|
131592
131732
|
const telemetry = createTelemetryContext({ action: "postman-repo-sync-action", actionVersion: resolveActionVersion2(), logger: dependencies.core });
|
|
131593
131733
|
telemetry.setTeamId(dependencies.teamId);
|
|
131594
131734
|
const logger = resolveRepoSyncLogger(dependencies);
|
|
@@ -132482,9 +132622,9 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
132482
132622
|
getEnvironment: gatewayAssets.getEnvironment.bind(gatewayAssets),
|
|
132483
132623
|
updateEnvironment: gatewayAssets.updateEnvironment.bind(gatewayAssets),
|
|
132484
132624
|
findEnvironmentByName: gatewayAssets.findEnvironmentByName.bind(gatewayAssets),
|
|
132485
|
-
// Collection read via
|
|
132486
|
-
//
|
|
132487
|
-
//
|
|
132625
|
+
// Collection read via one retry-free populated Sync GET — returns a full
|
|
132626
|
+
// v2.1 snapshot that the official runtime.models transform converts to v3
|
|
132627
|
+
// before repository materialization. PMAK is never used for reads.
|
|
132488
132628
|
getCollection: gatewayAssets.getCollection.bind(gatewayAssets),
|
|
132489
132629
|
// Mocks via the `mock` service, collection-based monitors via the `monitors`
|
|
132490
132630
|
// service (jobTemplates). Both reference the collection by its full public
|
package/dist/cli.cjs
CHANGED
|
@@ -115824,6 +115824,7 @@ var path = __toESM(require("node:path"), 1);
|
|
|
115824
115824
|
var V2 = __toESM(require_v2(), 1);
|
|
115825
115825
|
var import_transforms = __toESM(require_transforms(), 1);
|
|
115826
115826
|
var import_v3 = __toESM(require_node2(), 1);
|
|
115827
|
+
var V2_COLLECTION_MODEL = V2.Collection;
|
|
115827
115828
|
function asArray(value) {
|
|
115828
115829
|
return Array.isArray(value) ? value : [];
|
|
115829
115830
|
}
|
|
@@ -115844,13 +115845,23 @@ function normalizeGraphqlRequests(node) {
|
|
|
115844
115845
|
}
|
|
115845
115846
|
}
|
|
115846
115847
|
async function convertAndSplitCollection(v2Collection, outputDir) {
|
|
115847
|
-
const
|
|
115848
|
-
|
|
115849
|
-
|
|
115848
|
+
const v3 = convertV2CollectionToV3Collection(v2Collection);
|
|
115849
|
+
await writeSplitCollection(v3, outputDir);
|
|
115850
|
+
}
|
|
115851
|
+
function convertV2CollectionToV3Collection(v2Collection) {
|
|
115852
|
+
const parsed = V2_COLLECTION_MODEL.parse(v2Collection ?? {});
|
|
115853
|
+
const v3 = (0, import_transforms.transform)(
|
|
115854
|
+
V2_COLLECTION_MODEL,
|
|
115855
|
+
import_transforms.FormatVersion.V3,
|
|
115856
|
+
parsed
|
|
115857
|
+
);
|
|
115850
115858
|
for (const item of asArray(v3.items)) {
|
|
115851
115859
|
normalizeGraphqlRequests(item);
|
|
115852
115860
|
}
|
|
115853
|
-
|
|
115861
|
+
return v3;
|
|
115862
|
+
}
|
|
115863
|
+
function assertV2CollectionModel(value) {
|
|
115864
|
+
V2_COLLECTION_MODEL.parse(value ?? {});
|
|
115854
115865
|
}
|
|
115855
115866
|
function normalizeV3ExportIds(node) {
|
|
115856
115867
|
if (!node || typeof node !== "object") return;
|
|
@@ -119408,7 +119419,7 @@ var postmanRepoSyncActionContract = {
|
|
|
119408
119419
|
allowedValues: ["full", "spec-only"]
|
|
119409
119420
|
},
|
|
119410
119421
|
"prebuilt-collections-json": {
|
|
119411
|
-
description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without cloud
|
|
119422
|
+
description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without a cloud snapshot read.",
|
|
119412
119423
|
required: false,
|
|
119413
119424
|
default: ""
|
|
119414
119425
|
},
|
|
@@ -119451,7 +119462,7 @@ var postmanRepoSyncActionContract = {
|
|
|
119451
119462
|
default: ""
|
|
119452
119463
|
},
|
|
119453
119464
|
"environments-json": {
|
|
119454
|
-
description: "JSON array of environment slugs to create or
|
|
119465
|
+
description: "JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.",
|
|
119455
119466
|
required: false,
|
|
119456
119467
|
default: '["prod"]'
|
|
119457
119468
|
},
|
|
@@ -125942,8 +125953,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
125942
125953
|
}
|
|
125943
125954
|
/**
|
|
125944
125955
|
* Validate and normalize a collection public UID for routes that require the
|
|
125945
|
-
* full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments):
|
|
125946
|
-
*
|
|
125956
|
+
* full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments): populated
|
|
125957
|
+
* collection snapshot, collection-root PATCH/read, and private-mock runtime auth.
|
|
125947
125958
|
*
|
|
125948
125959
|
* - Trims once.
|
|
125949
125960
|
* - Rejects empty values.
|
|
@@ -126255,32 +126266,52 @@ var PostmanGatewayAssetsClient = class {
|
|
|
126255
126266
|
);
|
|
126256
126267
|
return match?.uid ? { uid: match.uid, name: match.name } : null;
|
|
126257
126268
|
}
|
|
126258
|
-
// --- collection read (service:
|
|
126269
|
+
// --- collection read (service: sync, populated v2.1 snapshot) ---
|
|
126259
126270
|
//
|
|
126260
|
-
//
|
|
126261
|
-
//
|
|
126262
|
-
//
|
|
126263
|
-
//
|
|
126264
|
-
//
|
|
126265
|
-
//
|
|
126266
|
-
// is rejected on root mutation routes (403 FORBIDDEN) and must not be used
|
|
126267
|
-
// here either, so the caller is responsible for passing the public UID.
|
|
126271
|
+
// This is the canonical full collection read used by
|
|
126272
|
+
// api-specification-service before whole-tree Sync updates. Collection v3
|
|
126273
|
+
// `/export` performs an expensive projection and has returned 500s for fresh
|
|
126274
|
+
// roots under provider load. The populated Sync read returns the complete
|
|
126275
|
+
// v2.1 model directly and is transformed in memory through the official
|
|
126276
|
+
// runtime.models V2 -> V3 pipeline before repository materialization.
|
|
126268
126277
|
/**
|
|
126269
|
-
* Fetch
|
|
126270
|
-
*
|
|
126271
|
-
*
|
|
126272
|
-
* disk via `convertAndSplitV3Collection`. PMAK is never used for collection
|
|
126273
|
-
* reads.
|
|
126278
|
+
* Fetch one complete v2.1 collection through a single retry-free populated
|
|
126279
|
+
* Sync GET. The response must be a v2.1 model for the requested public UID;
|
|
126280
|
+
* malformed or foreign snapshots fail closed. PMAK is never used.
|
|
126274
126281
|
*/
|
|
126275
126282
|
async getCollection(uid) {
|
|
126276
126283
|
const id = this.requireCollectionPublicUid(uid);
|
|
126277
126284
|
const response = await this.gateway.requestJson({
|
|
126278
|
-
service: "
|
|
126285
|
+
service: "sync",
|
|
126279
126286
|
method: "get",
|
|
126280
|
-
path: `/
|
|
126281
|
-
|
|
126282
|
-
|
|
126283
|
-
|
|
126287
|
+
path: `/collection/${encodeURIComponent(id)}`,
|
|
126288
|
+
query: { populate: "true", format: "2.1.0", uid: "false" },
|
|
126289
|
+
retry: "none",
|
|
126290
|
+
fallback: "none"
|
|
126291
|
+
});
|
|
126292
|
+
const collection = this.asRecord(response?.data);
|
|
126293
|
+
const info = this.asRecord(collection?.info);
|
|
126294
|
+
const schema = typeof info?.schema === "string" ? info.schema.trim() : "";
|
|
126295
|
+
if (!collection || !info || typeof info.name !== "string" || !info.name.trim() || !/\/collection\/v2\.1\.0\/collection\.json\/?$/i.test(schema) || !Array.isArray(collection.item)) {
|
|
126296
|
+
throw new Error(
|
|
126297
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync read did not return a complete v2.1 collection"
|
|
126298
|
+
);
|
|
126299
|
+
}
|
|
126300
|
+
try {
|
|
126301
|
+
assertV2CollectionModel(collection);
|
|
126302
|
+
} catch (error) {
|
|
126303
|
+
throw new Error(
|
|
126304
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync payload failed v2.1 schema validation",
|
|
126305
|
+
{ cause: error }
|
|
126306
|
+
);
|
|
126307
|
+
}
|
|
126308
|
+
const observedId = String(info._postman_id ?? collection.id ?? "").trim();
|
|
126309
|
+
if (!observedId || this.toModelId(observedId).toLowerCase() !== this.toModelId(id).toLowerCase()) {
|
|
126310
|
+
throw new Error(
|
|
126311
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync read returned a different collection identity"
|
|
126312
|
+
);
|
|
126313
|
+
}
|
|
126314
|
+
return collection;
|
|
126284
126315
|
}
|
|
126285
126316
|
// --- mocks (service: mock) ---
|
|
126286
126317
|
async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "private") {
|
|
@@ -127620,13 +127651,117 @@ function parseJsonMap(raw) {
|
|
|
127620
127651
|
])
|
|
127621
127652
|
);
|
|
127622
127653
|
}
|
|
127623
|
-
function
|
|
127624
|
-
if (!raw.trim()) return [];
|
|
127625
|
-
|
|
127654
|
+
function parseEnvironmentInputs(raw) {
|
|
127655
|
+
if (!raw.trim()) return { environments: [], definitions: /* @__PURE__ */ Object.create(null) };
|
|
127656
|
+
let parsed;
|
|
127657
|
+
try {
|
|
127658
|
+
parsed = JSON.parse(raw);
|
|
127659
|
+
} catch {
|
|
127660
|
+
throw new Error("environments-json must contain valid JSON");
|
|
127661
|
+
}
|
|
127626
127662
|
if (!Array.isArray(parsed)) {
|
|
127627
|
-
throw new Error("
|
|
127663
|
+
throw new Error("environments-json must be a JSON array");
|
|
127664
|
+
}
|
|
127665
|
+
const environments = [];
|
|
127666
|
+
const definitions = /* @__PURE__ */ Object.create(null);
|
|
127667
|
+
const seen = /* @__PURE__ */ new Map();
|
|
127668
|
+
parsed.forEach((entry, environmentIndex) => {
|
|
127669
|
+
const label = `environments-json[${environmentIndex}]`;
|
|
127670
|
+
let slug;
|
|
127671
|
+
let rich = false;
|
|
127672
|
+
if (typeof entry === "string") {
|
|
127673
|
+
slug = entry;
|
|
127674
|
+
} else {
|
|
127675
|
+
if (!isPlainObject2(entry)) {
|
|
127676
|
+
throw new Error(`${label} must be a slug string or an environment definition`);
|
|
127677
|
+
}
|
|
127678
|
+
const unknownFields = Object.keys(entry).filter((key) => key !== "slug" && key !== "values");
|
|
127679
|
+
if (unknownFields.length > 0) {
|
|
127680
|
+
throw new Error(`${label} contains unsupported field "${unknownFields[0]}"`);
|
|
127681
|
+
}
|
|
127682
|
+
if (typeof entry.slug !== "string" || !Array.isArray(entry.values)) {
|
|
127683
|
+
throw new Error(`${label} must contain a string slug and a values array`);
|
|
127684
|
+
}
|
|
127685
|
+
slug = entry.slug;
|
|
127686
|
+
rich = true;
|
|
127687
|
+
const keys = /* @__PURE__ */ new Set();
|
|
127688
|
+
definitions[slug] = entry.values.map((value, valueIndex) => {
|
|
127689
|
+
const valueLabel = `${label}.values[${valueIndex}]`;
|
|
127690
|
+
if (!isPlainObject2(value)) {
|
|
127691
|
+
throw new Error(`${valueLabel} must be an object`);
|
|
127692
|
+
}
|
|
127693
|
+
const unknownValueFields = Object.keys(value).filter(
|
|
127694
|
+
(key) => !["key", "value", "type", "enabled"].includes(key)
|
|
127695
|
+
);
|
|
127696
|
+
if (unknownValueFields.length > 0) {
|
|
127697
|
+
throw new Error(`${valueLabel} contains unsupported field "${unknownValueFields[0]}"`);
|
|
127698
|
+
}
|
|
127699
|
+
if (typeof value.key !== "string" || !value.key.trim() || value.key !== value.key.trim()) {
|
|
127700
|
+
throw new Error(`${valueLabel}.key must be a non-empty string without surrounding whitespace`);
|
|
127701
|
+
}
|
|
127702
|
+
if (value.key === "x-pm-onboarding") {
|
|
127703
|
+
throw new Error(`${valueLabel}.key is reserved by repo-sync`);
|
|
127704
|
+
}
|
|
127705
|
+
if (keys.has(value.key)) {
|
|
127706
|
+
throw new Error(`${label} contains duplicate variable key "${value.key}"`);
|
|
127707
|
+
}
|
|
127708
|
+
keys.add(value.key);
|
|
127709
|
+
if (value.value !== void 0 && typeof value.value !== "string") {
|
|
127710
|
+
throw new Error(`${valueLabel}.value must be a string when provided`);
|
|
127711
|
+
}
|
|
127712
|
+
if (value.type !== void 0 && value.type !== "default" && value.type !== "secret") {
|
|
127713
|
+
throw new Error(`${valueLabel}.type must be "default" or "secret"`);
|
|
127714
|
+
}
|
|
127715
|
+
if (value.enabled !== void 0 && typeof value.enabled !== "boolean") {
|
|
127716
|
+
throw new Error(`${valueLabel}.enabled must be a boolean when provided`);
|
|
127717
|
+
}
|
|
127718
|
+
const type = value.type ?? "default";
|
|
127719
|
+
const normalizedValue = value.value ?? "";
|
|
127720
|
+
if (type === "secret" && normalizedValue) {
|
|
127721
|
+
throw new Error(`${valueLabel} cannot contain a populated secret value; inject it at runtime`);
|
|
127722
|
+
}
|
|
127723
|
+
return { key: value.key, value: normalizedValue, type, enabled: value.enabled ?? true };
|
|
127724
|
+
});
|
|
127725
|
+
}
|
|
127726
|
+
if (rich && !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(slug)) {
|
|
127727
|
+
throw new Error(`${label} rich slug must use only letters, numbers, dots, hyphens, or underscores`);
|
|
127728
|
+
}
|
|
127729
|
+
if (rich && Object.prototype.hasOwnProperty.call(Object.prototype, slug)) {
|
|
127730
|
+
throw new Error(`${label} rich slug conflicts with a reserved object property`);
|
|
127731
|
+
}
|
|
127732
|
+
if (rich && /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(slug)) {
|
|
127733
|
+
throw new Error(`${label} rich slug conflicts with a Windows device name`);
|
|
127734
|
+
}
|
|
127735
|
+
if (!rich && !slug.trim()) {
|
|
127736
|
+
throw new Error(`${label} slug must be a non-empty string`);
|
|
127737
|
+
}
|
|
127738
|
+
const priorWasRich = seen.get(slug);
|
|
127739
|
+
if (priorWasRich !== void 0 && (rich || priorWasRich)) {
|
|
127740
|
+
throw new Error(`environments-json contains duplicate slug "${slug}"`);
|
|
127741
|
+
}
|
|
127742
|
+
if (priorWasRich === void 0) seen.set(slug, rich);
|
|
127743
|
+
environments.push(slug);
|
|
127744
|
+
});
|
|
127745
|
+
return { environments, definitions };
|
|
127746
|
+
}
|
|
127747
|
+
function normalizeProgrammaticEnvironmentDefinitions(inputs) {
|
|
127748
|
+
const definitions = inputs.environmentDefinitions;
|
|
127749
|
+
if (!definitions) return inputs;
|
|
127750
|
+
const prototype = Object.getPrototypeOf(definitions);
|
|
127751
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
127752
|
+
throw new Error("environmentDefinitions must be a plain object");
|
|
127753
|
+
}
|
|
127754
|
+
const entries = inputs.environments.map(
|
|
127755
|
+
(slug) => Object.prototype.hasOwnProperty.call(definitions, slug) ? { slug, values: definitions[slug] } : slug
|
|
127756
|
+
);
|
|
127757
|
+
let raw;
|
|
127758
|
+
try {
|
|
127759
|
+
raw = JSON.stringify(entries);
|
|
127760
|
+
} catch {
|
|
127761
|
+
throw new Error("environmentDefinitions must contain JSON-serializable values");
|
|
127628
127762
|
}
|
|
127629
|
-
|
|
127763
|
+
const parsed = parseEnvironmentInputs(raw);
|
|
127764
|
+
return { ...inputs, environments: parsed.environments, environmentDefinitions: parsed.definitions };
|
|
127630
127765
|
}
|
|
127631
127766
|
function normalizeRepoWriteMode(value) {
|
|
127632
127767
|
if (value === "none" || value === "commit-only" || value === "commit-and-push") {
|
|
@@ -127720,7 +127855,7 @@ function resolveInputs(env = process.env) {
|
|
|
127720
127855
|
},
|
|
127721
127856
|
env
|
|
127722
127857
|
);
|
|
127723
|
-
const
|
|
127858
|
+
const parsedEnvironments = parseEnvironmentInputs(getInput("environments-json", env) || '["prod"]');
|
|
127724
127859
|
const secretsResolverProvider = parseSecretsResolverProvider(getInput("secrets-resolver", env));
|
|
127725
127860
|
const systemEnvMap = parseJsonMap(getInput("system-env-map-json", env) || "{}");
|
|
127726
127861
|
const environmentUids = parseJsonMap(getInput("environment-uids-json", env) || "{}");
|
|
@@ -127758,7 +127893,8 @@ function resolveInputs(env = process.env) {
|
|
|
127758
127893
|
secretsResolverProvider,
|
|
127759
127894
|
specSyncMode: normalizeSpecSyncMode(getInput("spec-sync-mode", env) || "update"),
|
|
127760
127895
|
releaseLabel: normalizeReleaseLabel(getInput("release-label", env)) || void 0,
|
|
127761
|
-
environments: environments.length > 0 ? environments : ["prod"],
|
|
127896
|
+
environments: parsedEnvironments.environments.length > 0 ? parsedEnvironments.environments : ["prod"],
|
|
127897
|
+
environmentDefinitions: parsedEnvironments.definitions,
|
|
127762
127898
|
repoUrl: repoContext.repoUrl || "",
|
|
127763
127899
|
integrationBackend: getInput("integration-backend", env) || "bifrost",
|
|
127764
127900
|
workspaceLinkEnabled: parseBooleanInput(getInput("workspace-link-enabled", env), true),
|
|
@@ -128285,7 +128421,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
128285
128421
|
}
|
|
128286
128422
|
} catch {
|
|
128287
128423
|
}
|
|
128288
|
-
const
|
|
128424
|
+
const definedValues2 = inputs.environmentDefinitions?.[envName];
|
|
128425
|
+
const values2 = definedValues2 ? definedValues2.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
128289
128426
|
secretsResolverProvider: inputs.secretsResolverProvider,
|
|
128290
128427
|
preservedCredentialValues: priorValues
|
|
128291
128428
|
});
|
|
@@ -128308,7 +128445,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
128308
128445
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
128309
128446
|
continue;
|
|
128310
128447
|
}
|
|
128311
|
-
const
|
|
128448
|
+
const definedValues = inputs.environmentDefinitions?.[envName];
|
|
128449
|
+
const values = definedValues ? definedValues.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
128312
128450
|
secretsResolverProvider: inputs.secretsResolverProvider
|
|
128313
128451
|
});
|
|
128314
128452
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
@@ -129092,13 +129230,14 @@ function applyPrivateMockPrebuiltPlans(plans) {
|
|
|
129092
129230
|
}
|
|
129093
129231
|
}
|
|
129094
129232
|
async function preparePrivateMockCloudCollection(role, collectionId, postman) {
|
|
129095
|
-
const
|
|
129096
|
-
const
|
|
129233
|
+
const snapshot = await postman.getCollection(collectionId);
|
|
129234
|
+
const v3Collection = convertV2CollectionToV3Collection(snapshot);
|
|
129235
|
+
const { collection } = applyPrivateMockExportCleanup(v3Collection, {
|
|
129097
129236
|
stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
|
|
129098
129237
|
});
|
|
129099
129238
|
if (!verifyPrivateMockRootHook(collection)) {
|
|
129100
129239
|
throw new Error(
|
|
129101
|
-
`PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from
|
|
129240
|
+
`PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from populated ${role} collection snapshot ${collectionId}`
|
|
129102
129241
|
);
|
|
129103
129242
|
}
|
|
129104
129243
|
return collection;
|
|
@@ -129144,7 +129283,7 @@ async function acquireCollectionArtifact(options) {
|
|
|
129144
129283
|
return { reusePrebuilt: true };
|
|
129145
129284
|
}
|
|
129146
129285
|
if (entry) {
|
|
129147
|
-
core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection;
|
|
129286
|
+
core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection; reading populated cloud snapshot` : `Prebuilt ${role} collection entry present but did not exactly match; reading populated cloud snapshot`);
|
|
129148
129287
|
}
|
|
129149
129288
|
const cloud = privateMockAuth ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
|
|
129150
129289
|
return { reusePrebuilt: false, cloudCollection: cloud };
|
|
@@ -129498,6 +129637,7 @@ async function commitAndPushGeneratedFiles(inputs, dependencies, privateMockAuth
|
|
|
129498
129637
|
};
|
|
129499
129638
|
}
|
|
129500
129639
|
async function runRepoSync(inputs, dependencies, executionContext) {
|
|
129640
|
+
inputs = normalizeProgrammaticEnvironmentDefinitions(inputs);
|
|
129501
129641
|
const telemetry = createTelemetryContext({ action: "postman-repo-sync-action", actionVersion: resolveActionVersion2(), logger: dependencies.core });
|
|
129502
129642
|
telemetry.setTeamId(dependencies.teamId);
|
|
129503
129643
|
const logger = resolveRepoSyncLogger(dependencies);
|
|
@@ -130391,9 +130531,9 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
130391
130531
|
getEnvironment: gatewayAssets.getEnvironment.bind(gatewayAssets),
|
|
130392
130532
|
updateEnvironment: gatewayAssets.updateEnvironment.bind(gatewayAssets),
|
|
130393
130533
|
findEnvironmentByName: gatewayAssets.findEnvironmentByName.bind(gatewayAssets),
|
|
130394
|
-
// Collection read via
|
|
130395
|
-
//
|
|
130396
|
-
//
|
|
130534
|
+
// Collection read via one retry-free populated Sync GET — returns a full
|
|
130535
|
+
// v2.1 snapshot that the official runtime.models transform converts to v3
|
|
130536
|
+
// before repository materialization. PMAK is never used for reads.
|
|
130397
130537
|
getCollection: gatewayAssets.getCollection.bind(gatewayAssets),
|
|
130398
130538
|
// Mocks via the `mock` service, collection-based monitors via the `monitors`
|
|
130399
130539
|
// service (jobTemplates). Both reference the collection by its full public
|
package/dist/index.cjs
CHANGED
|
@@ -117745,6 +117745,7 @@ var path6 = __toESM(require("node:path"), 1);
|
|
|
117745
117745
|
var V2 = __toESM(require_v2(), 1);
|
|
117746
117746
|
var import_transforms = __toESM(require_transforms(), 1);
|
|
117747
117747
|
var import_v3 = __toESM(require_node2(), 1);
|
|
117748
|
+
var V2_COLLECTION_MODEL = V2.Collection;
|
|
117748
117749
|
function asArray(value) {
|
|
117749
117750
|
return Array.isArray(value) ? value : [];
|
|
117750
117751
|
}
|
|
@@ -117765,13 +117766,23 @@ function normalizeGraphqlRequests(node) {
|
|
|
117765
117766
|
}
|
|
117766
117767
|
}
|
|
117767
117768
|
async function convertAndSplitCollection(v2Collection, outputDir) {
|
|
117768
|
-
const
|
|
117769
|
-
|
|
117770
|
-
|
|
117769
|
+
const v3 = convertV2CollectionToV3Collection(v2Collection);
|
|
117770
|
+
await writeSplitCollection(v3, outputDir);
|
|
117771
|
+
}
|
|
117772
|
+
function convertV2CollectionToV3Collection(v2Collection) {
|
|
117773
|
+
const parsed = V2_COLLECTION_MODEL.parse(v2Collection ?? {});
|
|
117774
|
+
const v3 = (0, import_transforms.transform)(
|
|
117775
|
+
V2_COLLECTION_MODEL,
|
|
117776
|
+
import_transforms.FormatVersion.V3,
|
|
117777
|
+
parsed
|
|
117778
|
+
);
|
|
117771
117779
|
for (const item of asArray(v3.items)) {
|
|
117772
117780
|
normalizeGraphqlRequests(item);
|
|
117773
117781
|
}
|
|
117774
|
-
|
|
117782
|
+
return v3;
|
|
117783
|
+
}
|
|
117784
|
+
function assertV2CollectionModel(value) {
|
|
117785
|
+
V2_COLLECTION_MODEL.parse(value ?? {});
|
|
117775
117786
|
}
|
|
117776
117787
|
function normalizeV3ExportIds(node) {
|
|
117777
117788
|
if (!node || typeof node !== "object") return;
|
|
@@ -121329,7 +121340,7 @@ var postmanRepoSyncActionContract = {
|
|
|
121329
121340
|
allowedValues: ["full", "spec-only"]
|
|
121330
121341
|
},
|
|
121331
121342
|
"prebuilt-collections-json": {
|
|
121332
|
-
description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without cloud
|
|
121343
|
+
description: "Optional digest-bound JSON manifest of unique baseline, smoke, or contract roles with confined repo-relative path, SHA-256 artifact digest of the on-disk v3 collection tree (sorted relative-path + NUL + bytes + NUL), and canonical cloud ID. The optional payloadDigest field is the semantic v2 payload digest carried for provenance (format-validated only, not the reuse gate). Exact role, path, cloudId, and artifactDigest matches reuse the on-disk tree without a cloud snapshot read.",
|
|
121333
121344
|
required: false,
|
|
121334
121345
|
default: ""
|
|
121335
121346
|
},
|
|
@@ -121372,7 +121383,7 @@ var postmanRepoSyncActionContract = {
|
|
|
121372
121383
|
default: ""
|
|
121373
121384
|
},
|
|
121374
121385
|
"environments-json": {
|
|
121375
|
-
description: "JSON array of environment slugs to create or
|
|
121386
|
+
description: "JSON array of environment slugs or full definitions ({slug, values}) to create or replace. Secret-typed values must be empty runtime slots.",
|
|
121376
121387
|
required: false,
|
|
121377
121388
|
default: '["prod"]'
|
|
121378
121389
|
},
|
|
@@ -127863,8 +127874,8 @@ var PostmanGatewayAssetsClient = class {
|
|
|
127863
127874
|
}
|
|
127864
127875
|
/**
|
|
127865
127876
|
* Validate and normalize a collection public UID for routes that require the
|
|
127866
|
-
* full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments):
|
|
127867
|
-
*
|
|
127877
|
+
* full owner-prefixed UID (`<owner>-<uuid>`, 6 hyphen segments): populated
|
|
127878
|
+
* collection snapshot, collection-root PATCH/read, and private-mock runtime auth.
|
|
127868
127879
|
*
|
|
127869
127880
|
* - Trims once.
|
|
127870
127881
|
* - Rejects empty values.
|
|
@@ -128176,32 +128187,52 @@ var PostmanGatewayAssetsClient = class {
|
|
|
128176
128187
|
);
|
|
128177
128188
|
return match?.uid ? { uid: match.uid, name: match.name } : null;
|
|
128178
128189
|
}
|
|
128179
|
-
// --- collection read (service:
|
|
128190
|
+
// --- collection read (service: sync, populated v2.1 snapshot) ---
|
|
128180
128191
|
//
|
|
128181
|
-
//
|
|
128182
|
-
//
|
|
128183
|
-
//
|
|
128184
|
-
//
|
|
128185
|
-
//
|
|
128186
|
-
//
|
|
128187
|
-
// is rejected on root mutation routes (403 FORBIDDEN) and must not be used
|
|
128188
|
-
// here either, so the caller is responsible for passing the public UID.
|
|
128192
|
+
// This is the canonical full collection read used by
|
|
128193
|
+
// api-specification-service before whole-tree Sync updates. Collection v3
|
|
128194
|
+
// `/export` performs an expensive projection and has returned 500s for fresh
|
|
128195
|
+
// roots under provider load. The populated Sync read returns the complete
|
|
128196
|
+
// v2.1 model directly and is transformed in memory through the official
|
|
128197
|
+
// runtime.models V2 -> V3 pipeline before repository materialization.
|
|
128189
128198
|
/**
|
|
128190
|
-
* Fetch
|
|
128191
|
-
*
|
|
128192
|
-
*
|
|
128193
|
-
* disk via `convertAndSplitV3Collection`. PMAK is never used for collection
|
|
128194
|
-
* reads.
|
|
128199
|
+
* Fetch one complete v2.1 collection through a single retry-free populated
|
|
128200
|
+
* Sync GET. The response must be a v2.1 model for the requested public UID;
|
|
128201
|
+
* malformed or foreign snapshots fail closed. PMAK is never used.
|
|
128195
128202
|
*/
|
|
128196
128203
|
async getCollection(uid) {
|
|
128197
128204
|
const id = this.requireCollectionPublicUid(uid);
|
|
128198
128205
|
const response = await this.gateway.requestJson({
|
|
128199
|
-
service: "
|
|
128206
|
+
service: "sync",
|
|
128200
128207
|
method: "get",
|
|
128201
|
-
path: `/
|
|
128202
|
-
|
|
128203
|
-
|
|
128204
|
-
|
|
128208
|
+
path: `/collection/${encodeURIComponent(id)}`,
|
|
128209
|
+
query: { populate: "true", format: "2.1.0", uid: "false" },
|
|
128210
|
+
retry: "none",
|
|
128211
|
+
fallback: "none"
|
|
128212
|
+
});
|
|
128213
|
+
const collection = this.asRecord(response?.data);
|
|
128214
|
+
const info2 = this.asRecord(collection?.info);
|
|
128215
|
+
const schema = typeof info2?.schema === "string" ? info2.schema.trim() : "";
|
|
128216
|
+
if (!collection || !info2 || typeof info2.name !== "string" || !info2.name.trim() || !/\/collection\/v2\.1\.0\/collection\.json\/?$/i.test(schema) || !Array.isArray(collection.item)) {
|
|
128217
|
+
throw new Error(
|
|
128218
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync read did not return a complete v2.1 collection"
|
|
128219
|
+
);
|
|
128220
|
+
}
|
|
128221
|
+
try {
|
|
128222
|
+
assertV2CollectionModel(collection);
|
|
128223
|
+
} catch (error2) {
|
|
128224
|
+
throw new Error(
|
|
128225
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync payload failed v2.1 schema validation",
|
|
128226
|
+
{ cause: error2 }
|
|
128227
|
+
);
|
|
128228
|
+
}
|
|
128229
|
+
const observedId = String(info2._postman_id ?? collection.id ?? "").trim();
|
|
128230
|
+
if (!observedId || this.toModelId(observedId).toLowerCase() !== this.toModelId(id).toLowerCase()) {
|
|
128231
|
+
throw new Error(
|
|
128232
|
+
"COLLECTION_SNAPSHOT_INVALID: populated Sync read returned a different collection identity"
|
|
128233
|
+
);
|
|
128234
|
+
}
|
|
128235
|
+
return collection;
|
|
128205
128236
|
}
|
|
128206
128237
|
// --- mocks (service: mock) ---
|
|
128207
128238
|
async createMock(workspaceId, name, collectionUid, environmentUid, requestedVisibility = "private") {
|
|
@@ -129593,13 +129624,117 @@ function parseJsonMap(raw) {
|
|
|
129593
129624
|
])
|
|
129594
129625
|
);
|
|
129595
129626
|
}
|
|
129596
|
-
function
|
|
129597
|
-
if (!raw.trim()) return [];
|
|
129598
|
-
|
|
129627
|
+
function parseEnvironmentInputs(raw) {
|
|
129628
|
+
if (!raw.trim()) return { environments: [], definitions: /* @__PURE__ */ Object.create(null) };
|
|
129629
|
+
let parsed;
|
|
129630
|
+
try {
|
|
129631
|
+
parsed = JSON.parse(raw);
|
|
129632
|
+
} catch {
|
|
129633
|
+
throw new Error("environments-json must contain valid JSON");
|
|
129634
|
+
}
|
|
129599
129635
|
if (!Array.isArray(parsed)) {
|
|
129600
|
-
throw new Error("
|
|
129636
|
+
throw new Error("environments-json must be a JSON array");
|
|
129637
|
+
}
|
|
129638
|
+
const environments = [];
|
|
129639
|
+
const definitions = /* @__PURE__ */ Object.create(null);
|
|
129640
|
+
const seen = /* @__PURE__ */ new Map();
|
|
129641
|
+
parsed.forEach((entry, environmentIndex) => {
|
|
129642
|
+
const label = `environments-json[${environmentIndex}]`;
|
|
129643
|
+
let slug;
|
|
129644
|
+
let rich = false;
|
|
129645
|
+
if (typeof entry === "string") {
|
|
129646
|
+
slug = entry;
|
|
129647
|
+
} else {
|
|
129648
|
+
if (!isPlainObject2(entry)) {
|
|
129649
|
+
throw new Error(`${label} must be a slug string or an environment definition`);
|
|
129650
|
+
}
|
|
129651
|
+
const unknownFields = Object.keys(entry).filter((key) => key !== "slug" && key !== "values");
|
|
129652
|
+
if (unknownFields.length > 0) {
|
|
129653
|
+
throw new Error(`${label} contains unsupported field "${unknownFields[0]}"`);
|
|
129654
|
+
}
|
|
129655
|
+
if (typeof entry.slug !== "string" || !Array.isArray(entry.values)) {
|
|
129656
|
+
throw new Error(`${label} must contain a string slug and a values array`);
|
|
129657
|
+
}
|
|
129658
|
+
slug = entry.slug;
|
|
129659
|
+
rich = true;
|
|
129660
|
+
const keys = /* @__PURE__ */ new Set();
|
|
129661
|
+
definitions[slug] = entry.values.map((value, valueIndex) => {
|
|
129662
|
+
const valueLabel = `${label}.values[${valueIndex}]`;
|
|
129663
|
+
if (!isPlainObject2(value)) {
|
|
129664
|
+
throw new Error(`${valueLabel} must be an object`);
|
|
129665
|
+
}
|
|
129666
|
+
const unknownValueFields = Object.keys(value).filter(
|
|
129667
|
+
(key) => !["key", "value", "type", "enabled"].includes(key)
|
|
129668
|
+
);
|
|
129669
|
+
if (unknownValueFields.length > 0) {
|
|
129670
|
+
throw new Error(`${valueLabel} contains unsupported field "${unknownValueFields[0]}"`);
|
|
129671
|
+
}
|
|
129672
|
+
if (typeof value.key !== "string" || !value.key.trim() || value.key !== value.key.trim()) {
|
|
129673
|
+
throw new Error(`${valueLabel}.key must be a non-empty string without surrounding whitespace`);
|
|
129674
|
+
}
|
|
129675
|
+
if (value.key === "x-pm-onboarding") {
|
|
129676
|
+
throw new Error(`${valueLabel}.key is reserved by repo-sync`);
|
|
129677
|
+
}
|
|
129678
|
+
if (keys.has(value.key)) {
|
|
129679
|
+
throw new Error(`${label} contains duplicate variable key "${value.key}"`);
|
|
129680
|
+
}
|
|
129681
|
+
keys.add(value.key);
|
|
129682
|
+
if (value.value !== void 0 && typeof value.value !== "string") {
|
|
129683
|
+
throw new Error(`${valueLabel}.value must be a string when provided`);
|
|
129684
|
+
}
|
|
129685
|
+
if (value.type !== void 0 && value.type !== "default" && value.type !== "secret") {
|
|
129686
|
+
throw new Error(`${valueLabel}.type must be "default" or "secret"`);
|
|
129687
|
+
}
|
|
129688
|
+
if (value.enabled !== void 0 && typeof value.enabled !== "boolean") {
|
|
129689
|
+
throw new Error(`${valueLabel}.enabled must be a boolean when provided`);
|
|
129690
|
+
}
|
|
129691
|
+
const type = value.type ?? "default";
|
|
129692
|
+
const normalizedValue = value.value ?? "";
|
|
129693
|
+
if (type === "secret" && normalizedValue) {
|
|
129694
|
+
throw new Error(`${valueLabel} cannot contain a populated secret value; inject it at runtime`);
|
|
129695
|
+
}
|
|
129696
|
+
return { key: value.key, value: normalizedValue, type, enabled: value.enabled ?? true };
|
|
129697
|
+
});
|
|
129698
|
+
}
|
|
129699
|
+
if (rich && !/^[A-Za-z0-9]+(?:[._-][A-Za-z0-9]+)*$/.test(slug)) {
|
|
129700
|
+
throw new Error(`${label} rich slug must use only letters, numbers, dots, hyphens, or underscores`);
|
|
129701
|
+
}
|
|
129702
|
+
if (rich && Object.prototype.hasOwnProperty.call(Object.prototype, slug)) {
|
|
129703
|
+
throw new Error(`${label} rich slug conflicts with a reserved object property`);
|
|
129704
|
+
}
|
|
129705
|
+
if (rich && /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(slug)) {
|
|
129706
|
+
throw new Error(`${label} rich slug conflicts with a Windows device name`);
|
|
129707
|
+
}
|
|
129708
|
+
if (!rich && !slug.trim()) {
|
|
129709
|
+
throw new Error(`${label} slug must be a non-empty string`);
|
|
129710
|
+
}
|
|
129711
|
+
const priorWasRich = seen.get(slug);
|
|
129712
|
+
if (priorWasRich !== void 0 && (rich || priorWasRich)) {
|
|
129713
|
+
throw new Error(`environments-json contains duplicate slug "${slug}"`);
|
|
129714
|
+
}
|
|
129715
|
+
if (priorWasRich === void 0) seen.set(slug, rich);
|
|
129716
|
+
environments.push(slug);
|
|
129717
|
+
});
|
|
129718
|
+
return { environments, definitions };
|
|
129719
|
+
}
|
|
129720
|
+
function normalizeProgrammaticEnvironmentDefinitions(inputs) {
|
|
129721
|
+
const definitions = inputs.environmentDefinitions;
|
|
129722
|
+
if (!definitions) return inputs;
|
|
129723
|
+
const prototype = Object.getPrototypeOf(definitions);
|
|
129724
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
129725
|
+
throw new Error("environmentDefinitions must be a plain object");
|
|
129726
|
+
}
|
|
129727
|
+
const entries = inputs.environments.map(
|
|
129728
|
+
(slug) => Object.prototype.hasOwnProperty.call(definitions, slug) ? { slug, values: definitions[slug] } : slug
|
|
129729
|
+
);
|
|
129730
|
+
let raw;
|
|
129731
|
+
try {
|
|
129732
|
+
raw = JSON.stringify(entries);
|
|
129733
|
+
} catch {
|
|
129734
|
+
throw new Error("environmentDefinitions must contain JSON-serializable values");
|
|
129601
129735
|
}
|
|
129602
|
-
|
|
129736
|
+
const parsed = parseEnvironmentInputs(raw);
|
|
129737
|
+
return { ...inputs, environments: parsed.environments, environmentDefinitions: parsed.definitions };
|
|
129603
129738
|
}
|
|
129604
129739
|
function readInput(actionCore, name, required = false) {
|
|
129605
129740
|
return actionCore.getInput(name, { required }).trim();
|
|
@@ -129696,7 +129831,7 @@ function resolveInputs(env = process.env) {
|
|
|
129696
129831
|
},
|
|
129697
129832
|
env
|
|
129698
129833
|
);
|
|
129699
|
-
const
|
|
129834
|
+
const parsedEnvironments = parseEnvironmentInputs(getInput2("environments-json", env) || '["prod"]');
|
|
129700
129835
|
const secretsResolverProvider = parseSecretsResolverProvider(getInput2("secrets-resolver", env));
|
|
129701
129836
|
const systemEnvMap = parseJsonMap(getInput2("system-env-map-json", env) || "{}");
|
|
129702
129837
|
const environmentUids = parseJsonMap(getInput2("environment-uids-json", env) || "{}");
|
|
@@ -129734,7 +129869,8 @@ function resolveInputs(env = process.env) {
|
|
|
129734
129869
|
secretsResolverProvider,
|
|
129735
129870
|
specSyncMode: normalizeSpecSyncMode(getInput2("spec-sync-mode", env) || "update"),
|
|
129736
129871
|
releaseLabel: normalizeReleaseLabel(getInput2("release-label", env)) || void 0,
|
|
129737
|
-
environments: environments.length > 0 ? environments : ["prod"],
|
|
129872
|
+
environments: parsedEnvironments.environments.length > 0 ? parsedEnvironments.environments : ["prod"],
|
|
129873
|
+
environmentDefinitions: parsedEnvironments.definitions,
|
|
129738
129874
|
repoUrl: repoContext.repoUrl || "",
|
|
129739
129875
|
integrationBackend: getInput2("integration-backend", env) || "bifrost",
|
|
129740
129876
|
workspaceLinkEnabled: parseBooleanInput(getInput2("workspace-link-enabled", env), true),
|
|
@@ -130402,7 +130538,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130402
130538
|
}
|
|
130403
130539
|
} catch {
|
|
130404
130540
|
}
|
|
130405
|
-
const
|
|
130541
|
+
const definedValues2 = inputs.environmentDefinitions?.[envName];
|
|
130542
|
+
const values2 = definedValues2 ? definedValues2.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130406
130543
|
secretsResolverProvider: inputs.secretsResolverProvider,
|
|
130407
130544
|
preservedCredentialValues: priorValues
|
|
130408
130545
|
});
|
|
@@ -130425,7 +130562,8 @@ async function upsertEnvironments(inputs, dependencies, resourcesState, assetMar
|
|
|
130425
130562
|
dependencies.core.setOutput("environment-uids-json", JSON.stringify(envUids));
|
|
130426
130563
|
continue;
|
|
130427
130564
|
}
|
|
130428
|
-
const
|
|
130565
|
+
const definedValues = inputs.environmentDefinitions?.[envName];
|
|
130566
|
+
const values = definedValues ? definedValues.map((value) => ({ ...value })) : buildEnvironmentValues(envName, runtimeUrl, {
|
|
130429
130567
|
secretsResolverProvider: inputs.secretsResolverProvider
|
|
130430
130568
|
});
|
|
130431
130569
|
if (assetMarker) values.push({ key: "x-pm-onboarding", value: JSON.stringify(assetMarker), type: "default" });
|
|
@@ -131209,13 +131347,14 @@ function applyPrivateMockPrebuiltPlans(plans) {
|
|
|
131209
131347
|
}
|
|
131210
131348
|
}
|
|
131211
131349
|
async function preparePrivateMockCloudCollection(role, collectionId, postman) {
|
|
131212
|
-
const
|
|
131213
|
-
const
|
|
131350
|
+
const snapshot = await postman.getCollection(collectionId);
|
|
131351
|
+
const v3Collection = convertV2CollectionToV3Collection(snapshot);
|
|
131352
|
+
const { collection } = applyPrivateMockExportCleanup(v3Collection, {
|
|
131214
131353
|
stripManagedBlocks: isPrivateMockLegacyExportCleanupEnabled()
|
|
131215
131354
|
});
|
|
131216
131355
|
if (!verifyPrivateMockRootHook(collection)) {
|
|
131217
131356
|
throw new Error(
|
|
131218
|
-
`PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from
|
|
131357
|
+
`PRIVATE_MOCK_AUTH_ROOT_UNVERIFIED: Managed root hook missing from populated ${role} collection snapshot ${collectionId}`
|
|
131219
131358
|
);
|
|
131220
131359
|
}
|
|
131221
131360
|
return collection;
|
|
@@ -131261,7 +131400,7 @@ async function acquireCollectionArtifact(options) {
|
|
|
131261
131400
|
return { reusePrebuilt: true };
|
|
131262
131401
|
}
|
|
131263
131402
|
if (entry) {
|
|
131264
|
-
core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection;
|
|
131403
|
+
core.info(privateMockAuth ? `Private mock has no locally reconciled exact prebuilt ${role} collection; reading populated cloud snapshot` : `Prebuilt ${role} collection entry present but did not exactly match; reading populated cloud snapshot`);
|
|
131265
131404
|
}
|
|
131266
131405
|
const cloud = privateMockAuth ? await preparePrivateMockCloudCollection(role, collectionId, postman) : await postman.getCollection(collectionId);
|
|
131267
131406
|
return { reusePrebuilt: false, cloudCollection: cloud };
|
|
@@ -131615,6 +131754,7 @@ async function commitAndPushGeneratedFiles(inputs, dependencies, privateMockAuth
|
|
|
131615
131754
|
};
|
|
131616
131755
|
}
|
|
131617
131756
|
async function runRepoSync(inputs, dependencies, executionContext) {
|
|
131757
|
+
inputs = normalizeProgrammaticEnvironmentDefinitions(inputs);
|
|
131618
131758
|
const telemetry = createTelemetryContext({ action: "postman-repo-sync-action", actionVersion: resolveActionVersion2(), logger: dependencies.core });
|
|
131619
131759
|
telemetry.setTeamId(dependencies.teamId);
|
|
131620
131760
|
const logger = resolveRepoSyncLogger(dependencies);
|
|
@@ -132508,9 +132648,9 @@ function createRepoSyncDependencies(inputs, resolved, factories, options = {}) {
|
|
|
132508
132648
|
getEnvironment: gatewayAssets.getEnvironment.bind(gatewayAssets),
|
|
132509
132649
|
updateEnvironment: gatewayAssets.updateEnvironment.bind(gatewayAssets),
|
|
132510
132650
|
findEnvironmentByName: gatewayAssets.findEnvironmentByName.bind(gatewayAssets),
|
|
132511
|
-
// Collection read via
|
|
132512
|
-
//
|
|
132513
|
-
//
|
|
132651
|
+
// Collection read via one retry-free populated Sync GET — returns a full
|
|
132652
|
+
// v2.1 snapshot that the official runtime.models transform converts to v3
|
|
132653
|
+
// before repository materialization. PMAK is never used for reads.
|
|
132514
132654
|
getCollection: gatewayAssets.getCollection.bind(gatewayAssets),
|
|
132515
132655
|
// Mocks via the `mock` service, collection-based monitors via the `monitors`
|
|
132516
132656
|
// service (jobTemplates). Both reference the collection by its full public
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@postman-cs/onboarding-repo-sync",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Postman repo sync GitHub Action.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"verify:dist:assert": "npm run verify:dist:shape && npm run verify:dist:parity",
|
|
26
26
|
"verify:dist": "npm run build && npm run verify:dist:assert",
|
|
27
27
|
"docs:tables": "node scripts/render-action-tables.mjs",
|
|
28
|
+
"docs:pins": "node scripts/check-doc-pins.mjs",
|
|
28
29
|
"lint": "eslint .",
|
|
29
30
|
"lint:fix": "eslint . --fix",
|
|
30
31
|
"test": "vitest run --exclude tests/ci-workflow-template.test.ts && vitest run tests/ci-workflow-template.test.ts && node --test .github/scripts/dispatch-e2e-monitor.test.mjs .github/scripts/prefetch-vendored-deps.test.mjs .github/scripts/verify-e2e-release.test.mjs",
|