feat: force api_version 3.2 (NRP) on all entry/asset/taxonomy publish and unpublish#304
Conversation
…lish call sites
- operation-executor.ts: addHeader('api_version', '3.2') on entry and asset instances before SINGLE-mode publish/unpublish
- base-class.ts: replace conditional stackHeaders mutation in publish-assets with unconditional addHeader; add addHeader to publish-entries chain
- create-stack.ts: add api_version: '3.2' to scheduleEntryAction axios headers (raw-axios path, no SDK)
- assets.ts: remove now-dead additionalInfo: { api_version: '3.2' } — base-class owns the header unconditionally
- .talismanrc: whitelist create-stack.ts false-positive (api_key: apiKey is a variable ref, not a secret)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
api_version 3.2 is now hardcoded via addHeader() at the call site (DX-9754) so the flag is no longer needed on bulk-entries. - bulk-entries.ts: remove --api-version flag registration - messages/index.ts: remove API_VERSION constant (TAXONOMY_API_VERSION kept for bulk-taxonomies which still exposes the flag) - config-builder.ts: make apiVersion conditional on flag presence so the validateConfig() check only fires when bulk-taxonomies provides the flag - bulk-entries.test.ts: remove test asserting api-version flag presence - config-builder.test.ts: update default-values expectation to apiVersion: undefined Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…der on publish/unpublish
addHeader() was missing from the sinon mock causing 15 test failures after
DX-9754 introduced .addHeader('api_version', '3.2') calls in the executor.
- Add addHeader: sandbox.stub().returnsThis() to mockStack so the SDK
chaining resolves correctly
- Assert addHeader('api_version', '3.2') is called in all four cases:
entry publish, entry unpublish, asset publish, asset unpublish
Result: 839 passing, 0 failing (was 824 passing, 15 failing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…triggers false positive)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…validation Taxonomy: - Drop --api-version flag from bulk-taxonomies; api_version 3.2 is now hardcoded via addHeader() on the taxonomy SDK instance, matching the same per-call pattern used for entries and assets - Remove DEFAULT_TAXONOMY_API_VERSION constant and apiVersion param chain from TaxonomyService — branch is now the direct second param - Remove TAXONOMY_API_VERSION message constant include-variants: - Remove broken validation that blocked --include-variants whenever --api-version was absent; the guard is redundant now that 3.2 is hardcoded on both BULK and SINGLE paths config-builder: - Remove dead api-version flag validation from validateCommandFlags - Remove dead config.apiVersion validation from validateConfig - Remove the conditional apiVersion spread from buildConfig Tests updated to assert addHeader behaviour and drop variant/api-version coupling tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…sets and publish-entries
addHeader was missing from the asset and entry stubs in the import
base-class test, causing both publish cases to throw at runtime after
DX-9754 added .addHeader('api_version', '3.2') to the SDK call chain.
- Add addHeader: sinon.stub().returnsThis() to asset() and entry() mocks
- Assert addHeader('api_version', '3.2') is called before publish in
both the publish-assets and publish-entries test cases
Result: 1719 passing, 0 failing (was 1717 passing, 2 failing)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
…tionConfig interfaces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
…test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
…ypes Both types only existed to give a typed surface for publish/unpublish after casting through `as any`. Since the instance is already any, calling directly removes the unnecessary intermediate cast and the apiVersion?: string param that modelled the SDK signature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
…ulk payload prepareAssetBulkPayload was deriving locales from items[0].publish_details, which only contains the locale of the first item (always en-us when multiple locales are passed). Since fetchAssets creates one item per asset per locale, the ar (or any non-first) locale was silently dropped from the Bulk API payload. Also fixes duplicate asset UIDs: items had N-assets × M-locales entries, so the assets array contained each UID repeated M times. Now deduplicated by UID. Fix mirrors prepareEntryBulkPayload which already used Array.from(new Set(...)) for locales correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
…sertions Covers all four publish/unpublish paths (entry publish, entry unpublish, asset publish via sys_assets, asset unpublish via sys_assets) and verifies api_version: '3.2' is present in headers on every call. Also asserts branch header inclusion and omission. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
🔒 Security Scan Results
⏱️ SLA Breach Summary
ℹ️ Vulnerabilities Without Available Fixes (Informational Only)The following vulnerabilities were detected but do not have fixes available (no upgrade or patch). These are excluded from failure thresholds:
Consider reviewing these vulnerabilities when fixes become available. |
Backmerge latest v2-dev (PR #304: bulk-operations api_version 3.2 hardening, external-migrate create-stack, taxonomy NRP header). Only conflict was .talismanrc — resolved by taking the union of both sides' allowlist entries (version '1.0'; refreshed the merged pnpm-lock.yaml checksum). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbgqgVDTDmh6c9LwDtMEf9
…st to mocha [DX-9770] The v2-dev backmerge (PR #304) added create-stack.test.ts written in vitest, but this branch converted external-migrate to mocha and removed the vitest dependency, so the file failed to compile ('Cannot find module vitest'). Rewrote its 6 scheduleEntryAction api_version:3.2 header tests using mocha/chai/sinon (stub axios.post + configHandler + authHandler), preserving PR #304's coverage. Refreshed the .talismanrc checksum for the rewritten file. external-migrate: 48 passing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbgqgVDTDmh6c9LwDtMEf9
Summary
Enforces `api_version: 3.2` (NRP — New Release Pipeline) on every entry, asset, and taxonomy publish/unpublish call across both `contentstack-bulk-operations` and `contentstack-import`. Removes the user-facing `--api-version` flag from both commands that exposed it, since the version is no longer configurable. Fixes a permanently broken `--include-variants` validation gate that was inadvertently locked out when the flag was removed. Cleans up all dead interface fields and test assertions left over from the removed flag.
Background
The New Release Pipeline (NRP) requires `api_version: 3.2` to be present on publish and unpublish requests. Previously this was either left to the user to pass via `--api-version 3.2`, or partially hardcoded but only on the bulk path. This PR closes all three code paths:
The `addHeader` approach is copy-on-write — it writes to a `moduleHeadersOwn` symbol on the per-call SDK instance and never mutates the shared `stack.stackHeaders`, so it cannot bleed into other unrelated CMA requests.
Module: `contentstack-bulk-operations`
`src/core/operation-executor.ts`
What changed: Added `.addHeader('api_version', '3.2')` on the entry and asset SDK instances in `executeEntryOperation` and `executeAssetOperation` before any publish/unpublish call is dispatched.
Why: The SINGLE publish path goes directly through `stack.contentType(ct).entry(uid).publish(...)`. Without the header, SINGLE-mode publishes were silently missing the NRP version header even though the BULK path was already hardcoded.
```ts
// Before
const entry = this.stack.contentType(content_type).entry(uid);
// After
const entry = this.stack.contentType(content_type).entry(uid).addHeader('api_version', '3.2');
```
Same pattern applied to `this.stack.asset(uid)`.
`src/services/taxonomy-service.ts`
What changed: Complete rework of the `submit` private method. Removed the `apiVersion` parameter from the public `publish` / `unpublish` signatures and from `submit`. The version is now injected unconditionally via `taxonomyInstance.addHeader('api_version', '3.2')` before calling the SDK's `publish` or `unpublish`.
Why: The old approach passed `apiVersion` as the second positional argument to `taxonomies.publish(data, apiVersion, params)`. The SDK's taxonomy `publish()` clones `stackHeaders` first and then conditionally overwrites `api_version` only if the param is truthy — so passing `undefined` from a caller that forgot the argument would silently drop the header. The `addHeader` approach puts the value into `stackHeaders` before the SDK ever runs, making it impossible to accidentally omit.
```ts
// Before — apiVersion threaded through 3 layers, droppable by callers
async publish(data, apiVersion = '3.2', branch?) { ... }
// After — hardcoded at the point of use, not passable by callers
async publish(data, branch?) {
const taxonomyInstance = this.stack.taxonomy() as any;
taxonomyInstance.addHeader('api_version', '3.2');
...
}
```
Note: the internal `TaxonomyPublishWithBranch` type still carries `apiVersion?: string` as its second param — this reflects the real SDK method signature (`taxonomy.publish(data, apiVersion?, params?)`). We pass `undefined` explicitly there to push `branch` into the third position. The type is not our config; it is the SDK's API.
`src/commands/cm/stacks/bulk-entries.ts`
What changed: Removed the `--api-version` flag definition entirely.
Why: With 3.2 hardcoded in both BULK (`BulkOperationService`) and SINGLE (`OperationExecutor`) paths, exposing `--api-version` to users had no effect on the actual request. Worse, it gave the false impression that passing `--api-version 3` would downgrade the NRP header, which it would not. The flag is now gone so the CLI surface is honest.
Breaking change: `cm:stacks:bulk-entries --api-version` is removed. Any scripts or pipelines passing this flag will receive an unknown flag error.
`src/commands/cm/stacks/bulk-taxonomies.ts`
What changed: Removed the `--api-version` flag definition and its associated `examples` entry. Removed `const apiVersion = this.parsedFlags['api-version'] || '3.2'` and updated the `taxonomyService.publish/unpublish` call signatures to drop the version argument (branch is now the second param).
Why: Same rationale as `bulk-entries` — the flag was decorative since `TaxonomyService` now owns the version. Also removed the example that advertised `--api-version 3.2` as a meaningful option.
Breaking change: `cm:stacks:bulk-taxonomies --api-version` is removed.
`src/utils/config-builder.ts`
What changed: Three removals:
Why for items 1–2: The `apiVersion` config field and `--api-version` flag no longer exist, so these validators were dead code.
Why for item 3 (critical fix): After `--api-version` was removed from `bulk-entries`, `flags['api-version']` was always `undefined`. The guard `flags['include-variants'] && flags['api-version'] !== '3.2'` evaluated to `true` for any invocation that passed `--include-variants`, permanently blocking the feature with a misleading error. The guard is now deleted — `--include-variants` works correctly since 3.2 is always in effect.
`src/interfaces/index.ts`
What changed: Removed `'api-version'?: string` from `CommandFlags` and `apiVersion?: string` from `BulkOperationConfig`.
Why: Both fields are dead. The flag no longer exists on either command so `CommandFlags['api-version']` can never be populated. `BulkOperationConfig.apiVersion` was set by `buildConfig()` from that flag and read nowhere else — removing `buildConfig()`'s assignment made the field permanently `undefined`.
`src/messages/index.ts`
What changed: Removed `API_VERSION` and `TAXONOMY_API_VERSION` string constants from `flagDescriptions`.
Why: These were the description strings for the now-deleted `--api-version` flags.
Module: `contentstack-import`
`src/import/modules/base-class.ts`
What changed: Two publish call sites updated:
`publish-assets` case: Removed the previous workaround that manually spread `api_version` into `assetClient.stackHeaders` via `additionalInfo.api_version`. Replaced with a clean `.addHeader('api_version', '3.2')` call.
```ts
// Before — manual stackHeaders mutation + additionalInfo threading
const assetClient = this.stack.asset(uid);
if (additionalInfo?.api_version) {
(assetClient as any).stackHeaders = { ...stackHeaders, api_version: publishApiVersion };
}
return assetClient.publish(...);
// After — SDK-idiomatic addHeader
return this.stack.asset(uid).addHeader('api_version', '3.2').publish(...);
```
`publish-entries` case: Added `.addHeader('api_version', '3.2')` to the `contentType(ct).entry(uid)` chain before `.publish(...)`.
`src/import/modules/assets.ts`
What changed: Removed `additionalInfo: { api_version: '3.2' }` from the `publish-assets` batch dispatch. This was the mechanism feeding `api_version` into the old `stackHeaders` workaround in `base-class`. Now that `base-class` uses `addHeader` directly, this threading is no longer needed.
Test Coverage
`contentstack-bulk-operations`
Result: 836 passing, 0 failing.
`contentstack-import`
Result: 1719 passing, 3 pending, 0 failing.
Breaking Changes
Test Plan
🤖 Generated with Claude Code