Support inserting embargoed (Access Control-restricted) assets into the Image content block - #6
Open
greg-pene wants to merge 1 commit into
Conversation
Today, an asset with a Cloudinary Access Control `token` rule always shows "This asset is restricted" in the Media Library Widget and can't be inserted at all — even when it's just embargoed (token now, becomes public automatically at a scheduled date), not permanently restricted. Adds a new standalone `preview-server` (the only place the account's Access Control Key ever lives, since `cloudinary-sfmc` is a pure client-side app with no access to any Cloudinary secret) that verifies an asset is genuinely token-restricted via the Admin API and, if so, signs a short-lived preview URL. `isNotRestricted` now tries that before giving up, and resolves instead of rejecting when the asset is confirmed to be a real embargo case, attaching the signed preview URL and access_control rule to the asset. The image content block then previews and polls against that signed URL on-canvas, but the saved/sent HTML always uses the plain public URL — so the actual email works the moment the embargo lifts and never depends on the preview server or an expired token. The field's own thumbnail (`CldAssetSelector`) shows the same signed preview plus a warning banner, and re-requests a fresh signed URL on its own if the current one goes stale (e.g. reopening the block after the preview server's TTL expired). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Today, selecting a Cloudinary asset with an Access Control
tokenrule always shows "This asset is restricted" in the Media Library Widget and blocks insertion into the Image content block — even when the asset is just embargoed (token-gated now, scheduled to become public automatically at a futurestartdate) rather than permanently restricted.This PR adds embargo support:
preview-server/— a small standalone Express service, the only place the account's Cloudinary Access Control Key ever lives (cloudinary-sfmcis a pure client-side app with no access to any Cloudinary secret).POST /api/embargo-preview-urlre-verifies via the Admin API that an asset is genuinelytoken-restricted (never trusts the client's claim) and, if so, signs a short-lived preview URL.isNotRestricted(mediaLibValidators.js) now calls this service before giving up, and resolves instead of rejecting when the asset is a confirmed embargo case — attaching the signed preview URL andaccess_controlrule to the asset rather than blocking it.CldAssetSelector) shows the same signed preview plus a "Temporary preview only — embargoed…" warning banner, and re-requests a fresh signed URL on its own if the current one goes stale (e.g. reopening the block after the preview server's TTL has expired).Scope: the Image content block only. Video-to-GIF's source-video restriction check is unchanged (see
preview-server/README.md's "Known limitations").Why resolve instead of reject
The existing
isNotRestrictedvalidator did an unauthenticatedHEADrequest against the asset's plain delivery URL and treated any non-200 as "restricted" — which can't distinguish a genuinely embargoed asset from a permanently-restricted one, or even a transient network hiccup. The new flow asks a dedicated backend (which alone holds the Access Control Key) to confirm the specific reason via the Admin API, and only unblocks the ones that are actually time-bound embargoes.New deployment requirement
preview-serverneeds to be deployed and configured (CLOUDINARY_ACCESS_CONTROL_KEY,CLOUDINARY_API_KEY/SECRET,ALLOWED_ORIGINS) alongside the existingcloudinary-sfmcapp; seepreview-server/README.md. Without it configured (previewServerUrlquery param unset), behavior is unchanged from today — embargoed assets still show the existing "restricted" block.Test plan
yarn test:unitat repo root — 45 passedyarn test:lint— clean (0 errors)cloudinary-sfmc:yarn test:unit— 34 passed;yarn buildsucceedspreview-server:yarn test(Node's built-in test runner, mocked Cloudinary client) — 7 passed🤖 Generated with Claude Code