Skip to content

Bugfix(delta) | References, Entry Mapping, RTE, empty-state, CT count - #1136

Merged
vikrantraut-cstk merged 16 commits into
devfrom
bugfix/cmg-1101-ref-locale
Aug 6, 2026
Merged

Bugfix(delta) | References, Entry Mapping, RTE, empty-state, CT count#1136
vikrantraut-cstk merged 16 commits into
devfrom
bugfix/cmg-1101-ref-locale

Conversation

@chetan-contentstack

@chetan-contentstack chetan-contentstack commented Aug 5, 2026

Copy link
Copy Markdown

🔗 Jira Tickets

Parent story: CMG-789 — Delta Migration | v1.0.0


📋 PR Type

  • ✨ Feature
  • 🐛 Bug Fix
  • 🔥 Hotfix
  • 🧹 Chore / Dependency Update
  • ♻️ Refactor
  • 📝 Documentation

📝 Description

What changed?

  • CMG-1101 — Entry uid-mapper (flat + per-locale) threaded into the update config so entry-update-script.cjs resolves Link(Entry) fields on the delta/localize path; locale-migrated tracking moved after updateEntryCli resolves so silent failures don't permanently flag locales as done.
  • CMG-1102extractEntries.js now uses each content type's displayField with fallbacks (title → name → first localized string → sys.id) instead of hard-coded title/name, so entries with other display fields no longer disappear from Map Entry.
  • CMG-1097 — Asset mapper search-empty state: force .Table height when it contains an .EmptyState and center .Table__centerWrapper so the illustration + heading + description render properly.
  • CMG-1103 — JSON RTE hyperlinks rewritten to Contentstack's shape: plain → type:'a' attrs.url, entry/asset → type:'reference' with display-type:'link'. URLs now survive to destination.
  • CMG-1104 — Entry-mapper selection persists across locales: locale-scoped server toggle, stale-fetch generation guard, unified data-load effect, tableRevision remount so Venus's Table re-reads initialSelectedRowIds.
  • CMG-1095getContentTypes now unions content types from every prior iteration (1..N-1) instead of only N-1, so types migrated in earlier iterations but absent from N-1 are still classified as "old" on iteration N.
  • Dep bumps to clear Snyk SLA (fast-uri, brace-expansion) in root and each sub-project package.
  • Path-traversal SAST fixes on new file reads.

Why?

Six independent delta-migration defects reported against v1.0.0. All share the same delta code paths so grouping keeps the review context tight.


🧩 Affected Areas

  • api — Node.js backend
  • ui — React frontend
  • upload-api — Upload API server
  • docker / docker-compose
  • CI / GitHub Actions workflows
  • Environment variables / config
  • Other: root package.json (dep override bumps)

🧪 How to Test

Fresh project on bugfix/cmg-1101-ref-locale. Migrate 3 iterations using the bundled fixtures.

  1. Iter 1contentful-export.json (3 CTs, 1 locale). Complete migration; references resolve in destination.
  2. Iter 2asic.json (24 CTs incl. gender/moreInformation/tip/width which use internalTitle). On Map Entry, all 24 should appear with entries. Save selections on multiple locales and verify each persists across locale switches.
  3. Iter 3asic-merged.json (27 CTs = iter 1's 3 + iter 2's 24). Map Entry should show 26 content types (one CT genuinely has 0 entries).
  4. Assets tab → search for something not present → verify empty-state renders full illustration + heading + description below the header.
  5. Any entry with a JSON RTE containing a plain hyperlink (e.g. ASIC disclaimer) → verify the link is preserved in the destination JSON RTE.
  6. cd api && npm test passes.

Expected result: All 26 content types visible on iter 3 Map Entry; references and JSON RTE hyperlinks intact in destination; per-locale entry selections persist; assets search empty-state layout correct.


📸 Screenshots / Recordings

Before After

🔗 Related PRs / Dependencies


✅ Author Checklist

  • Branch follows naming convention: bugfix/cmg-1101-ref-locale
  • Jira tickets linked above
  • Self-reviewed the diff
  • .env / example.env updated — N/A
  • No secrets committed
  • Existing tests pass (npm test in api/)
  • New tests written for reference resolution helpers
  • README.md / docs updated — N/A
  • Talisman pre-push scan passes

👀 Reviewer Notes

  • Reference resolution precedence: per-locale new → per-locale old → flat new → flat old → identity fallback.
  • CMG-1095 union-of-prior-iterations approach is O(iteration count) lowdb reads — fine for single-digit iterations.
  • Dep bumps are in a separate concern from the delta fixes; splitting into its own PR would be cleaner but was kept here to unblock the Snyk SLA check.

Migration v2 · Docs · Issues

chetan-contentstack added 9 commits August 5, 2026 13:13
…le-migrated tracking

Reference fields (Link/Array Entry) written during a locale-localize restart
kept the source CMS entry id instead of the real Contentstack uid, since only
the master-locale bulk import resolved references correctly. Threads entry
uid-mapper data into the update config so entry-update-script.cjs can resolve
them, mirroring the existing asset uid resolution.

Also fixes a bug where finishing any locale marked ALL configured locales as
migrated, causing not-yet-migrated locales to be silently skipped on later
delta restarts. Now only locales actually processed in that run are recorded.
Was reading a literal .id property on the entryId map instead of the
dynamic key, so the single-reference branch never took the array path
when the mapper legitimately held an array of destination uids.
…le-migrated tracking

Address review comments on #1128:

- Move iteration 2+ recordMigratedLocales out of runCli into migration.service.ts,
  after utilsUpdateCli.updateEntryCli resolves. Recording pre-update meant a silent
  update-CLI failure would still flag the locales as migrated, permanently skipping
  them on later restarts — same class of bug this PR fixes.
- Union in Object.keys(uid-mapper.entryByLocale) so brand-new-entries-only locales
  (no rows in updated-entries.json because they had no prior csEntryUid) are also
  recorded as migrated.
- Extract flattenNestedUidMap into uid-mapper.utils.js and reuse it in both
  contentMapper.service and entry-update.utils. entry-update.utils.enrichConfigWithEntryMapping
  now handles the nested per-content-type shape (and the entryUid variant) instead
  of assuming a flat map.
- entry-update-script.isReferenceArray: switch from .every() to .some(), and pass
  non-reference items through in resolveReferenceField. Producers legitimately emit
  mixed arrays (raw Contentful Link objects for unresolved refs, [undefined] from
  the single-ref fallback) — one such item no longer disables resolution for the
  whole field.
…action

- Clear iter-1 logs and completion flag on new Start Migration; accept
  'Entry Update Process Completed' as terminal on the delta path.
- Move 'already migrated' placeholder outside the log map so it no
  longer repeats per line and doesn't hide iter-2 live logs.
- extractEntries: use CT displayField with fallbacks instead of
  hard-coded title/name (fixes CMG-1102 empty Map Entry table).
…traversal

Snyk SAST flagged fs.readFileSync on paths derived from projectId. Add
explicit assertResolvedPathUnderBase checks so the sink is visibly
sanitized against the database dir.
…sanitizer

assertResolvedPathUnderBase is a custom helper Snyk SAST doesn't
recognize. Apply path.basename inline to every user-derived path
segment — the pattern Snyk accepts as a Path Traversal sanitizer.
Direct fs.readFileSync on a projectId-derived path kept flagging as
Path Traversal even after path.basename sanitizers. Route the read
through the existing getUidMapperDb model — same path resolution but
no direct sink in this file.
runCli emits 'Migration Process Completed' but writes uid-mapper and
'No config file generated' lines after it, so a last-log-only check
never fired on delta runs. Scan the whole logs array instead — the
purge-on-start effect makes this safe from cross-iteration replays.
- CMG-1103 JSON RTE hyperlinks: plain -> type:'a', entry/asset -> type:'reference'
  with display-type:'link' so URLs survive in destination JSON RTE.
- CMG-1104 entry-mapper selection persistence: locale-scoped server toggle,
  stale-fetch generation guard, unified data-load effect on both contentTypeUid
  and selectedLocale, tableRevision-based remount so Venus's Table picks up
  the fresh initialSelectedRowIds after each locale switch.
- CMG-1097 asset mapper search-empty state: force .Table height when it
  contains an .EmptyState and center the .Table__centerWrapper so the
  illustration + heading + description render properly.
- CMG-1105 map-entry count mismatch: getContentTypes now unions content
  types across all prior iterations (1..N-1) instead of only N-1, so
  types migrated in earlier iterations but absent from N-1 are still
  classified as 'old' on iteration N.
@chetan-contentstack
chetan-contentstack requested a review from a team as a code owner August 5, 2026 07:46
@snyk-io

snyk-io Bot commented Aug 5, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@chetan-contentstack chetan-contentstack changed the title CMG-1101, CMG-1102, CMG-1097, CMG-1103, CMG-1104, CMG-1095: delta migration fixes for references, entry mapping, RTE hyperlinks & content-type count Bugfix(delta) | References, Entry Mapping, RTE, empty-state, CT count Aug 5, 2026
@chetan-contentstack chetan-contentstack self-assigned this Aug 5, 2026
- CMG-1106: asset download falls back to fields.file.upload when .url
  is missing (newly-added, not-yet-CDN-processed Contentful assets).
  Same fallback in extractAssets.js; skip rows with neither.
- CMG-1105: on iteration 2+, Map Entry Assets tab shows only assets
  already migrated in a prior iteration (has contentstackAssetUid).
  Brand-new assets upload automatically without a row to select.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@umesh-more-cstk umesh-more-cstk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review summary

Six delta defects in one PR. I traced each fix through the real code paths (uid-mapper write order in runCli, removeEntriesFromDatabase config-key shape, Venus InfiniteScrollTable internals, createRefrence output shape) rather than reading the diff alone. Most of the reasoning is sound and several fixes are provably correct. Two changed code paths look broken in ways that will show up on real exports, and there are a few undisclosed behaviour changes worth a conscious decision before merge.

Blocking

  1. api/src/services/contentful/jsonRTE.ts:399parseEntryHyperlink reads content-type-uid from target.sys.contentType.sys.id, which does not exist on a Contentful export Link ({sys:{type:'Link',linkType:'Entry',id}}). It will always be '', and even when present it would be the camelCase Contentful id, not the snake_case CT uid this repo generates. parseBlockReference (lines 218-249) already solves exactly this by reading _content_type_uid out of the rte-references file.
  2. api/src/services/contentful.service.ts:675 — the new .upload fallback lets unprocessed Contentful assets reach the download path, but the code immediately below still dereferences fields.file[locale].fileName (688-691) and .details.size (725, and again 759 with no optional chaining). Unprocessed assets have no details (that is why they have no .url), so the very case CMG-1106 targets throws, downloads twice, and is dropped with no failedJSON entry.

Non-blocking (questions / nits)

  • Locale bookkeeping now lives only inside if (configFilePath) in migration.service.ts while runCli only records for iteration ≤ 1 — iteration ≥ 2 runs where removeEntriesFromDatabase returns null record nothing at all (see inline).
  • getAssetMapping's new displayMapping filter is a user-visible behaviour change with no ticket in the description.
  • entryMapper.tsx: entries are now fetched only from the locale effect, so a project whose locale map can't be resolved shows a permanently empty Map Entry table; and each content-type click now fires two identical requests.
  • MigrationLogViewer: 'Migration Process Completed' is written by runCli before the delta update CLI runs, so adding 'Entry Update Process Completed' as an OR doesn't stop the early completion flip on iteration 2+.
  • Reference resolution in entry-update-script.cjs is top-level-only (group / modular-block nesting still keeps source uids).
  • Small doc/code mismatch in flattenNestedUidMap, a truthiness check in updateEntryStatus, and a pickEntryTitle edge case — all inline.

Scope / process (out of diff, so noted here)

  • The description claims dep bumps for fast-uri / brace-expansion in root and each sub-project plus a root package.json entry under Affected Areas. There is no package.json or lockfile in this diff at all (18 files, all source/test). Either the bumps were dropped or the description is stale — please reconcile, since the stated reason for keeping them here was to unblock the Snyk SLA check.
  • Conversely, four changes in the diff have no listed ticket: the asset .upload fallback (contentful.service.ts + extractAssets.js, code comment references CMG-1106 which isn't in the ticket list), the getAssetMapping delta display filter, the MigrationLogViewer completion/purge rework, and the migrationCompleted: false reset in pages/Migration/index.tsx. Each is defensible, but they widen the blast radius beyond the six linked tickets.

Verified good (worth calling out)

  • contentful.service.ts:439 Array.isArray(entryId?.[id]) is a genuine fix — the old entryId?.id tested a literal id property, so the array branch was dead and already-array values got double-wrapped.
  • parseAssetHyperlink's attrs (asset.uid / asset.filename / asset.content_type) match exactly what saveAsset writes into the assets schema — unlike the pre-existing parseBlockAsset, which reads asset.fileName and gets undefined.
  • parseHyperlinktype:'a' + attrs.url is the correct Contentstack JSON RTE anchor shape.
  • Deferring locale recording until after updateEntryCli is right: updateEntryCli.service.ts:240-249 really does swallow failures, so the old position could permanently skip a locale.
  • writeUidMapping runs before writePerLocaleEntryUidMapping in runCli (it assigns data = {assets, entry} wholesale), so the new entryByLocale read in migration.service.ts isn't reading a clobbered key. Good ordering.
  • setTableRevision is correctly inside the seedSelection branch, so pagination/search don't remount the table; and I confirmed in the bundled Venus source that getSelectedRow is called with Object.keys(selectedRowIds) (seeded from initialSelectedRowIds), so dropping initialRowSelectedData does not change the id set the app receives — only the unused second arg / maxSelect bookkeeping.
  • extractAssets.js's new continue is inside a for…of, so it's valid; and locale codes flowing into migrated_locales are consistently destination codes across extractLocalesFromUpdateConfig, entryByLocale and master_locale keys.

Needs a human at a browser

The index.scss empty-state rules can't be verified statically. One thing to check: .asset-mapper-table .Table__body already carries flex: 0 0 auto !important (line ~858), so the new display:flex; flex-direction:column on the body won't let it grow into the forced calc(100vh - 22rem) table height — the illustration may be centred only because of min-height: 300px on .Table__centerWrapper. Please confirm at a couple of viewport heights / zoom levels.

Comment thread api/src/services/contentful/jsonRTE.ts Outdated
Comment thread api/src/services/contentful.service.ts
Comment thread api/src/services/migration.service.ts Outdated
Comment thread api/src/services/contentMapper.service.ts
Comment thread api/src/services/contentMapper.service.ts Outdated
Comment thread api/src/utils/uid-mapper.utils.ts Outdated
Comment thread ui/src/components/ContentMapper/entryMapper.tsx
Comment thread ui/src/components/ContentMapper/entryMapper.tsx
Comment thread ui/src/components/LogScreen/MigrationLogViewer.tsx Outdated
Comment thread upload-api/migration-contentful/libs/extractEntries.js
- entry hyperlinks resolve content-type uid from rte-references instead
  of a field the Contentful export never populates; fall back to plain
  text when unresolvable.
- asset download no longer crashes on .upload-only assets missing
  details/fileName; derived once, reused everywhere.
- record delta locales even when no update-config was generated this
  iteration (iteration >= 2, nothing to localize).
- entryMapper: safety-net fetch when locale resolution settles empty;
  drop now-duplicate direct fetchEntries calls.
- MigrationLogViewer: terminal-message check is iteration-aware
  (delta requires the update-CLI's completion message, not the bulk
  import's).
- updateEntryStatus returns 404 instead of a fake 200 when the locale
  filter matches zero rows.
- entry-update-script: resolve references nested inside groups and
  modular blocks, not just top-level fields.
- flattenNestedUidMap: per-key check instead of all-or-nothing, so
  mixed flat/nested uid maps normalize correctly.
- extractEntries: hasAnyLocaleContent checks for meaningful content,
  not just key presence.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@umesh-more-cstk umesh-more-cstk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed all six fixes against the surrounding delta code paths and ran the API test suite locally (79 files, 725 tests — all passing). Overall a solid PR: the fixes are well-scoped, the intent comments are genuinely useful, and the new tests cover the resolver precedence and locale-extraction logic well.

Verified during review

  • The tableRevision remount only bumps on seedSelection fetches, so pagination/search don't reset the entry table.
  • The UI sends locale in the updateEntryStatus body (entryMapper.tsx:439), so the server-side scoping is actually exercised.
  • __locale (destination dir name) and entryByLocale keys agree, so the per-locale resolver lookups line up.
  • The union-of-prior-iterations CT fix is safe: filterContentTypesByIteration only consumes otherCmsUid from the prior list, so keeping the first-seen CT object per uid is harmless.
  • The Array.isArray(entryId?.[id]) typo fix in contentful.service.ts is correct.

Findings (details in the line comments)

  1. Medium — locale recording for iteration ≥ 2 is skipped entirely when no update config exists (migration.service.ts), which can reproduce the "locale permanently skipped" bug this PR fixes via a different trigger.
  2. MinorupdateEntryStatus's locale guard silently no-ops on legacy rows without a language tag.
  3. NitflattenNestedUidMap doc comment says "ANY" where the code does every.
  4. Two informational notes on pre-existing behavior (early completion modal on delta runs; RTE entry-uid not remapped on the update-script path).

Description mismatch: the PR description claims dep bumps (fast-uri, brace-expansion) across root and sub-project manifests, but the diff contains no package.json changes — Snyk reports "No manifest changes detected in 8 projects". Presumably those landed on dev separately; please update the description so release notes aren't misled.


Generated by Claude Code

Comment thread api/src/services/migration.service.ts
Comment thread api/src/services/contentMapper.service.ts Outdated
Comment thread api/src/utils/uid-mapper.utils.ts
Comment thread ui/src/components/LogScreen/MigrationLogViewer.tsx
Comment thread api/src/services/contentful/jsonRTE.ts
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@umesh-more-cstk umesh-more-cstk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — 1 blocker, 4 questions, 1 nit

Reviewed at head 4fb87ff, base dev (85b1049) — 18 files, +1002/−163. Six delta-migration defects grouped into one PR. The core mechanisms hold up well: the union-of-prior-iterations fix for CMG-1095 is right, the locale plumbing is consistent (I traced entryByLocale → destination locale dir names in writePerLocaleEntryUidMapping, __locale/:: suffix → localeCode in removeEntriesFromDatabase, and migrated_localesisFullMigrationForLocale — all destination codes, no source/destination mismatch), the updateEntryStatus locale scoping matches getEntryMapping's read-side filter exactly, and moving recordMigratedLocales after updateEntryCli resolves is the correct call. flattenNestedUidMap moving to uid-mapper.utils.ts with the per-key (rather than all-or-nothing) check is a genuine improvement over the version it replaces. Test coverage on the new helpers is good.

One blocker, on the UI completion path. The rest are questions where I want the author's read before calling them bugs.

Blocker

  • ui/src/components/LogScreen/MigrationLogViewer.tsx:214 — on iteration ≥ 2 the completion detector requires the literal 'Entry Update Process Completed', which only updateEntryCli's success path writes. Two reachable paths never write it (update CLI skipped entirely when there's no config file and no asset updates; update CLI's catch, which swallows the error). MigrationLogViewer.tsx:232 is the only place in the UI that ever sets migrationCompleted: true, so in both cases the user is stranded on the Execution Logs spinner after a fully successful run. Details and two suggested fixes inline.

Questions

  • api/src/services/contentMapper.service.ts:2031if (foundEntry.length) correctly replaces an always-truthy check, but updateEntryStatus lacks the previous-iteration fallback that getEntryMapping has, so rows rendered from iteration N−1 now save with a hard 404 + "Failed to save entries" toast instead of the old silent 200.
  • api/src/services/contentMapper.service.ts:2414 — the new iteration-2+ Assets filter can empty the tab when the uid-mapper assets map hasn't been written yet, which is indistinguishable from "nothing to update" — awkward given CMG-1097 is about that very empty state.
  • api/src/services/contentful/jsonRTE.ts:396parseBlockquote and parseHeading1parseHeading6 don't forward lang/destination_stack_id, so entry/asset hyperlinks nested in a heading or blockquote still lose their URL. CMG-1103 is only partly fixed.
  • api/src/utils/entry-update-script.cjs:83.some()-based isReferenceArray short-circuits the deep walk for mixed arrays, so nested references inside sibling block objects would be skipped. Looks unreachable with today's Contentful producer; raising it as a latent trap.

Nit

  • ui/src/components/ContentMapper/entryMapper.tsx:695 — removing the initialRowSelectedData prop leaves the backing state write-only (declared L113, set L255/L398, never read).

Scope

Flagging two things about the diff-vs-description fit — no action needed on the code itself, but the description should match what actually ships.

  1. The dependency bumps described aren't in this PR. The description says "Dep bumps to clear Snyk SLA (fast-uri, brace-expansion) in root and each sub-project package.json", and Affected Areas checks "Other: root package.json (dep override bumps)". No package.json or lockfile appears in the diff against dev. Either the bumps were dropped during a rebase or the description is stale — worth confirming, because the Reviewer Notes cite unblocking the Snyk SLA check as the reason for keeping them in this PR, and that reason no longer applies. (For what it's worth, splitting them out would have been the cleaner call anyway, as the notes acknowledge.)

  2. Several substantive changes aren't attributable to any of the six linked tickets. All within the checked Affected Areas, so the checkboxes are accurate, but "What changed?" doesn't mention them and QA won't know to test them:

    • contentful.service.ts saveAssetfile.upload fallback and defensive fileName/details.size/contentType handling. The code comment cites CMG-1106, which isn't in the ticket list. Good change (it removes a real https:undefined axios call and a path.basename(undefined) throw), just untracked.
    • upload-api/migration-contentful/libs/extractAssets.js — same .upload fallback, plus assets with no downloadable source are now skipped entirely rather than emitted with assetPath: ''. Behaviour change to Map Entry's asset list.
    • contentMapper.service.ts getAssetMapping — the iteration-2+ filter (see question above).
    • MigrationLogViewer.tsx — log purge on run start, single-pass terminal detection, and moving the "already migrated" placeholder out of the .map (that last one is a real fix — it previously rendered once per log line).
    • ui/src/pages/Migration/index.tsx — explicit migrationCompleted: false on start.
    • contentful.service.ts:439Array?.isArray(entryId?.id)Array.isArray(entryId?.[id]). The old expression tested a literal id key and was always false, so this actually activates a previously-dead branch and stops double-wrapping already-array reference values. Correct, but a real behaviour change hidden in a one-line diff. Note the else still returns [entryId?.[id]], which yields [undefined] for an unmapped reference — the same [undefined] that entry-update-script.cjs's new isReferenceArray comment works around. Worth fixing at the source rather than tolerating downstream.

Adding a line per item to the description (and a ticket for CMG-1106) would keep the delta-migration audit trail intact.


Generated by Claude Code

Comment thread ui/src/components/LogScreen/MigrationLogViewer.tsx
Comment thread api/src/services/contentMapper.service.ts
Comment thread api/src/services/contentMapper.service.ts Outdated
Comment thread api/src/services/contentful/jsonRTE.ts
Comment thread api/src/utils/entry-update-script.cjs Outdated
Comment thread ui/src/components/ContentMapper/entryMapper.tsx
chetan-contentstack added 2 commits August 6, 2026 13:35
- contentful.service.ts: fix cs_failed.json double-nested write path;
  add retryFailedAsset() to re-download a single asset that failed
  during the last migration run.
- extractAssets.js: no longer skip assets with no url/upload — emit
  with hasSource:false so the UI can show a reason instead of hiding
  them silently.
- contentMapper.service.ts: enrich getAssetMapping rows with
  status ('ok'|'missing'|'failed') + errorMessage; new
  retryAssetDownload service fn; ?status= filter param; aggregate
  missingCount/failedCount for the UI banner.
- New route/controller: PUT /mapper/retryAsset/:projectId/:assetUid.
- assetMapper.tsx: Status column with 'No source'/'Failed' badges +
  Retry button; broken-asset count banner; status filter dropdown.
- migration.service.ts: write a guaranteed terminal log line after the
  delta branch regardless of outcome — fixes UI stuck on Execution
  Logs forever when nothing was selected to update or updateEntryCli
  failed internally.
- contentMapper.service.ts (updateEntryStatus): locale guard only
  enforced when the row has a language tag (legacy rows are no longer
  permanently untoggleable); add iteration N-1 fallback mirroring the
  read side, so restart-fallback rows can be saved without a 404.
- contentMapper.service.ts (getAssetMapping): only apply the delta
  asset filter once uid-mapper data actually exists — avoids showing
  an empty tab during the restart race before this iteration's uid
  data is written.
- jsonRTE.ts: thread lang/destination_stack_id through
  parseBlockquote and parseHeading1-6 so hyperlinks nested in a
  heading/blockquote resolve instead of degrading to plain text.
- entry-update-script.cjs: resolveReferencesDeep recurses into every
  array element instead of delegating arrays to the shallow
  isReferenceArray path, fixing mixed arrays (bare ref + nested-ref
  object) where the nested one was left unresolved. Added unit tests.
- entryMapper.tsx: remove dead initialRowSelectedData state, unused
  since the InfiniteScrollTable prop was dropped.
Comment thread api/src/services/contentMapper.service.ts
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

….json

Fixes Snyk path-traversal finding in getAssetMapping by reusing the
existing sanitizeStackId/assertResolvedPathUnderBase helpers. Also adds
unit tests for getAssetMapping and retryFailedAsset to close the
function-coverage CI gap.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

Adds icons to status badges, an amber (not red) heads-up banner, header/
column overflow fixes so long labels and UIDs stop bleeding into
neighboring rows/columns, and rebalanced column widths for Size and
Contentstack UID.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

🔒 Security Scan Results

ℹ️ Note: Only vulnerabilities with available fixes (upgrades or patches) are counted toward thresholds.

Check Type Count (with fixes) Without fixes Threshold Result
🔴 Critical Severity 0 0 10 ✅ Passed
🟠 High Severity 15 378 25 ✅ Passed
🟡 Medium Severity 18 11 500 ✅ Passed
🔵 Low Severity 2 0 1000 ✅ Passed

⏱️ SLA Breach Summary

✅ No SLA breaches detected. All vulnerabilities are within acceptable time thresholds.

Severity Breaches (with fixes) Breaches (no fixes) SLA Threshold (with/no fixes) Status
🔴 Critical 0 0 15 / 30 days ✅ Passed
🟠 High 0 0 30 / 120 days ✅ Passed
🟡 Medium 0 0 90 / 365 days ✅ Passed
🔵 Low 0 0 180 / 365 days ✅ Passed

ℹ️ 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:

  • Critical without fixes: 0
  • High without fixes: 378
  • Medium without fixes: 11
  • Low without fixes: 0

✅ BUILD PASSED - All security checks passed

@vikrantraut-cstk
vikrantraut-cstk merged commit 51c9cbd into dev Aug 6, 2026
9 checks passed
@vikrantraut-cstk
vikrantraut-cstk deleted the bugfix/cmg-1101-ref-locale branch August 6, 2026 10:54
chetan-contentstack pushed a commit that referenced this pull request Aug 14, 2026
- entry hyperlinks resolve content-type uid from rte-references instead
  of a field the Contentful export never populates; fall back to plain
  text when unresolvable.
- asset download no longer crashes on .upload-only assets missing
  details/fileName; derived once, reused everywhere.
- record delta locales even when no update-config was generated this
  iteration (iteration >= 2, nothing to localize).
- entryMapper: safety-net fetch when locale resolution settles empty;
  drop now-duplicate direct fetchEntries calls.
- MigrationLogViewer: terminal-message check is iteration-aware
  (delta requires the update-CLI's completion message, not the bulk
  import's).
- updateEntryStatus returns 404 instead of a fake 200 when the locale
  filter matches zero rows.
- entry-update-script: resolve references nested inside groups and
  modular blocks, not just top-level fields.
- flattenNestedUidMap: per-key check instead of all-or-nothing, so
  mixed flat/nested uid maps normalize correctly.
- extractEntries: hasAnyLocaleContent checks for meaningful content,
  not just key presence.
chetan-contentstack pushed a commit that referenced this pull request Aug 14, 2026
- migration.service.ts: write a guaranteed terminal log line after the
  delta branch regardless of outcome — fixes UI stuck on Execution
  Logs forever when nothing was selected to update or updateEntryCli
  failed internally.
- contentMapper.service.ts (updateEntryStatus): locale guard only
  enforced when the row has a language tag (legacy rows are no longer
  permanently untoggleable); add iteration N-1 fallback mirroring the
  read side, so restart-fallback rows can be saved without a 404.
- contentMapper.service.ts (getAssetMapping): only apply the delta
  asset filter once uid-mapper data actually exists — avoids showing
  an empty tab during the restart race before this iteration's uid
  data is written.
- jsonRTE.ts: thread lang/destination_stack_id through
  parseBlockquote and parseHeading1-6 so hyperlinks nested in a
  heading/blockquote resolve instead of degrading to plain text.
- entry-update-script.cjs: resolveReferencesDeep recurses into every
  array element instead of delegating arrays to the shallow
  isReferenceArray path, fixing mixed arrays (bare ref + nested-ref
  object) where the nested one was left unresolved. Added unit tests.
- entryMapper.tsx: remove dead initialRowSelectedData state, unused
  since the InfiniteScrollTable prop was dropped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants