fix(import): remap nested entry-data extension UIDs for is_asset custom fields [DX-7312] - #359
fix(import): remap nested entry-data extension UIDs for is_asset custom fields [DX-7312]#359harshitha-cstk wants to merge 5 commits into
Conversation
…om fields Marketplace-app / extension references embedded in entry DATA (e.g. an `image_presets` value's `metadata.extension_uid`) are stack-scoped and must be remapped to the destination app's extension_uid during import. The remap in `lookupAssets` (`findAssetIdsFromJsonCustomFields`) only walked top-level schema fields, so any `is_asset` JSON custom field nested inside a group / global_field / blocks was skipped. Consequences of the miss: - the entry kept the source app's extension_uid, leaving an orphaned reference on the destination stack; and - on a subsequent import the audit flagged that UID as a missing reference and stripped the whole field (silent data loss of image-preset configs). Replace the flat `ctSchema.map` with a recursive walk (`remapJsonCustomFieldExtensionUids`) that follows the entry-data shape through group / global_field / blocks and handles multiple-valued fields, remapping `metadata.extension_uid` (and the schema field's extension_uid) via the marketplace_apps mapping. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
🔒 Security Scan Results
⏱️ SLA Breach Summary
✅ BUILD PASSED - All security checks passed |
| const values = Array.isArray(value) ? value : [value]; | ||
| for (const val of values) { | ||
| const currentUid = val?.metadata?.extension_uid; | ||
| if (currentUid && installedExtensions && installedExtensions[currentUid]) { |
There was a problem hiding this comment.
can we use switch case here instead of multiple if...else
There was a problem hiding this comment.
Pull request overview
This PR remaps marketplace extension UIDs in nested JSON asset fields during imports.
Changes:
- Recursively traverses groups, global fields, blocks, and arrays.
- Remaps entry metadata and schema extension UIDs.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| } else if (data_type === 'group' || data_type === 'global_field') { | ||
| remapJsonCustomFieldExtensionUids(field.schema, value); | ||
| } else if (data_type === 'blocks' && Array.isArray(field.blocks)) { | ||
| const blockInstances = Array.isArray(value) ? value : [value]; | ||
| for (const blockInstance of blockInstances) { |
| } else if (data_type === 'group' || data_type === 'global_field') { | ||
| remapJsonCustomFieldExtensionUids(field.schema, value); |
…borting the module `updateAppsConfig` called `nodeCrypto.decrypt(configuration)` inline as the argument to `.setConfiguration(...)` / `.setServerConfig(...)`. A bad-decrypt (e.g. ERR_OSSL_BAD_DECRYPT when an app's exported `configuration` was encrypted with a different key) therefore threw synchronously — outside the promise chain's `.catch` — and propagated up through `installApps` (which re-throws), aborting the entire marketplace-apps module. Because the module aborted, `mapper/marketplace_apps/uid-mapping.json` was never written. Global fields / content types (and entry data) then had no marketplace extension mapping to remap against, so their imports failed with "extension_uid ... does not exist in destination stack". Fix: decrypt inside a try/catch for both configuration and server_configuration. On failure, log a warning and skip only that app's config push; the app stays installed and its extension_uid mapping is still recorded, so downstream GF/CT/entry remapping works and the uid-mapping file is written. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… fix/dx-7312-entry-data-extension-uid-remap
🔒 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:
✅ BUILD PASSED - All security checks passed |
Address PR review on the entry-data remap: - Replace the schema-driven walker with `remapEntryMetadataExtensionUids`, a schema-independent deep walk of the entry data that remaps any `metadata.extension_uid` via the marketplace_apps mapping. This is robust to is_asset custom fields nested in group / global_field / blocks AND to content-type schemas that carry a reference-only global_field stub (no expanded `schema`, e.g. from query-export), which the previous schema-driven walk would silently skip. - Run it once, unconditionally, after `find()` (idempotent — already-mapped UIDs are no-ops). - Guard `find()` against a missing schema so a global_field stub no longer throws while collecting assets. - Keep the schema field `extension_uid` remap for parity. Co-Authored-By: Claude Opus 4.8 <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:
✅ BUILD PASSED - All security checks passed |
Address PR review on the entry-data remap: - Replace the schema-driven walker with `remapEntryMetadataExtensionUids`, a schema-independent deep walk of the entry data that remaps any `metadata.extension_uid` via the marketplace_apps mapping. This is robust to is_asset custom fields nested in group / global_field / blocks AND to content-type schemas that carry a reference-only global_field stub (no expanded `schema`, e.g. from query-export), which the previous schema-driven walk would silently skip. - Run it once, unconditionally, after `find()` (idempotent — already-mapped UIDs are no-ops). - Guard `find()` against a missing schema so a global_field stub no longer throws while collecting assets. - Keep the schema field `extension_uid` remap for parity. Co-Authored-By: Claude Opus 4.8 <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:
✅ BUILD PASSED - All security checks passed |
Summary
Closes both halves of DX-7312 (marketplace-app extension UIDs not remapped on clone/import):
is_assetcustom-field values (e.g.image_presets) kept the source app'sextension_uid, which the audit then stripped.extension_uid … does not exist in destination stack, because the marketplace UID mapping was never written.Root Causes & Fixes
1. Entry-data remap —
utils/asset-helper.tslookupAssets→findAssetIdsFromJsonCustomFieldsonly walked top-level schema fields, so anis_assetJSON custom field nested inside agroup/global_field/blocksnever had itsmetadata.extension_uidremapped → orphaned reference → the audit deleted the field (silent data loss).Fix: replaced the flat
mapwith a recursive walk (remapJsonCustomFieldExtensionUids) that follows the entry-data shape throughgroup/global_field/blocks, handles multiple-valued fields, and remaps via themarketplace_appsmapper.2. Marketplace config decrypt resilience —
import/modules/marketplace-apps.tsupdateAppsConfigdecrypted inline as the call argument:nodeCrypto.decryptis synchronous, so a bad-decrypt (ERR_OSSL_BAD_DECRYPT— an app config encrypted with a different key) threw outside the promise chain's.catch, propagated throughinstallApps(which re-throws), and aborted the entire marketplace-apps module →mapper/marketplace_apps/uid-mapping.jsonwas never written → GF/CT/entry remap had nothing to map against.Fix: decrypt inside a
try/catchfor bothconfigurationandserver_configuration. On failure, log awarnand skip only that app's config push. The app stays installed, itsextension_uidmapping is still recorded, the module completes, and the mapping file is written.Testing
Validated with the dev CLI (
node bin/dev cm:stacks:import) into fresh stacks:image_presetsremappedblt8eb76d16603badf3→ destination IPB UID; field preserved; 391/391 items, 0 stripped.marketplace_apps/uid-mapping.jsonempty,page_banner/tablefailed withextension_uid … does not exist.WARN: Failed to decrypt configuration for 'Image Preset Builder' … skipping; Install Apps 4/4; mapping written with 8 extension entries; Global Fields 36/36, 0extension does not existerrors.🤖 Generated with Claude Code