Skip to content

PROD-2773: warn when content references a CDN container owned by neither the source nor the target - #236

Merged
5PK merged 1 commit into
feature/PROD-2552-verify-commandfrom
PROD-2773-foreign-cdn-warning
Oct 14, 2026
Merged

5PK merged 1 commit into
feature/PROD-2552-verify-commandfrom
PROD-2773-foreign-cdn-warning

Conversation

@5PK

@5PK 5PK commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #235 (PROD-2552), which is stacked on #234. Merge those first; this PR's diff is against #235's branch.

Problem

Content synced before the PROD-915 fix (32b6ab5, 2026-03-20) kept asset URLs that point at the upstream instance's CDN container. Those URLs are now part of the source data. Later syncs can't map them, because the asset mapping only knows the source's own container, so they pass them through without a word.

On a customer instance pair, agility verify (PROD-2552) found:

  • Three banner items point an image field at an image in a third (upstream) instance's container. On the target the field is null. The sync dropped the image and logged nothing about it.
  • Rich text in several more items still links to that upstream container on both sides. Those images render only because the other instance's CDN still serves them.

Change

Sync, push and --preflight now warn when content references an Agility CDN container that belongs to neither the source nor the target. This only reports: item payloads, counts, success and exit codes don't change, and there are no new flags.

What gets flagged

  • Hosts: cdn*.aglty.io, agility-cdn*.azurewebsites.net, cdn*.agilitycms.com, plus custom edge hosts (e.g. cdn.example.com) learned from the pair's asset mappings and pulled assets.
  • Container: the first path segment, compared case-insensitively. It's foreign when it belongs to neither the source's nor the target's containers. Those come from the mapping container URLs (edge and origin) and the pulled asset URLs.
  • If either side's container is unknown, nothing is reported, so there are no false positives on a fresh target. On a real sync the asset phase creates the mappings before content is scanned, so it still reports.
  • Formats handled: image/file fields, attachment lists, plain URL strings, and URLs inside rich text, including JSON-escaped, &, percent-encoded, protocol-relative, and URLs with query strings.

How it's reported

  • One entry per URL per run, listing every item, field and locale that uses it.
  • Image/file field uses are listed first, with the consequence: the target may drop the field.
  • The end-of-run block reads "Foreign CDN references: N URLs in M items (non-blocking)".
  • --jsonSummary warning entries gain code, url, container and references. These fields are additive, so there's no schema version bump.
  • --preflight gets a warnings section that doesn't affect the counts or the exit code.

Where it runs

  • content-pusher.ts scans each locale's items before change detection, so unchanged items and --preflight are covered.
  • Items already skipped for a missing container or model mapping aren't scanned, because they never sync.

New files: foreign-cdn-detector.ts (pure detector), foreign-cdn-report.ts (per-run collector), report-foreign-cdn-references.ts (glue). Also adds a read-only AssetMapper.getMappings().

Testing

  • npx jest (stacked on PROD-2552: add agility verify to compare a synced target against its source #235): 131 suites / 2,517 tests pass. tsc --noEmit is clean. Lint shows 0 errors.
  • The tests cover:
    • each host type and custom domains
    • the source's and target's own containers (no warning)
    • an unknown side (nothing reported)
    • escaped and encoded URL forms
    • de-duplication across items and locales
    • each field kind
    • JSON summary and preflight output
    • payloads byte-identical with and without the scan
  • Live read-only --preflight on a two-locale customer clone pair: exit 0, totals unchanged. It found 17 URLs in 10 items:
    • All 14 expected URLs into the upstream container.
    • Three more URLs into two other containers, both foreign to this clone pair. One is the original (pre-clone) source's container, so on the original pair it would count as the source's own and wouldn't be flagged.
    • No warnings for the pair's own containers or for its custom-domain URLs.
    • An item in a deleted container isn't listed, because it never syncs.

Limitations

  • Only content item fields are scanned; page fields, gallery paths and model defaults are not.
  • In --headless the per-URL warnings go to the log file only. The end-of-run block and the JSON summary always show them.
  • We haven't confirmed that the server drops a foreign attachment URL, so the message says "may drop".

Closes PROD-2773. Related: PROD-915, PROD-2552.

🤖 Generated with Claude Code

…her the source nor the target

PROD-2773: warn about asset URLs into a CDN container owned by neither instance

Content synced before the PROD-915 fix kept the upstream instance's CDN URLs,
so a source can reference a third instance's container (e.g. cdn-usa2.aglty.io/
upstream-qa/...). The asset mapping cannot map those, so they passed through
silently: image/file fields arrived empty on the target and rich-text links kept
pointing at the other instance.

The content pusher now scans each locale's syncable items (also in --preflight
and for unchanged items) and reports every foreign CDN URL once per run, with
the items/fields/locales using it. Reporting only: payloads, counts, success and
exit codes are unchanged.

- foreign-cdn-detector: pure URL extraction (aglty.io, azurewebsites origin,
  cdn*.agilitycms.com, learned custom edge hosts; JSON-escaped, &, query and
  percent-encoded variants) and container-ownership check. Source/target
  containers come from asset mappings and pulled assets; nothing is reported
  while either side's container is unknown.
- foreign-cdn-report: per-run dedupe and rendering; attachment-field URLs are
  called out separately from text occurrences.
- Surfaces: logger warning on first sighting, end-of-run "Foreign CDN
  references: N URLs in M items" block, additive --jsonSummary warnings
  (code "foreignCdnReference", url, container, references), and a preflight
  warnings section that does not affect totals or the exit code.

Preflight totals now include PROD-2542's "invalid" count; the push test expects it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@5PK
5PK force-pushed the PROD-2773-foreign-cdn-warning branch from bc5e87e to 8c6302b Compare October 14, 2026 18:15
@5PK
5PK changed the base branch from main to feature/PROD-2552-verify-command October 14, 2026 18:16
@5PK
5PK requested a review from DerekAgility October 14, 2026 18:25
@5PK
5PK marked this pull request as ready for review October 14, 2026 18:25
@5PK
5PK merged commit 4a8ec0e into feature/PROD-2552-verify-command Oct 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants