Specification: Phase 3.6b — Backend Strict Validation
Restore strict CDN image URL validation in operations that was relaxed
for backward compatibility during Phase 2. Now that the frontend sends
only CDN URLs (Phase 3.6 complete), the backend can enforce that all
persisted image URLs originate from managed storage.
Issue: Arda-cards/operations#164
Entry Criteria
Section titled “Entry Criteria”- Phase 3.6 complete: frontend sends only CDN URLs for image uploads
- CDN infrastructure (S3, CloudFront, IAM presign role) deployed to all environments
- CloudFormation exports (
ImageAssetBucketArn,ImageAssetBucketName,ImagePresignRoleArn,ImageCdnDomain) exist in all environments
Context
Section titled “Context”PR #163 introduced CDN image URL validation in ItemValidator. Subsequent
commits (9ad1c03, final: 140a7c8) relaxed this validation to maintain
backward compatibility with the frontend on main, which at the time sent
non-CDN external URLs (e.g., https://m.media-amazon.com/...).
This phase restores the strict validation that was intentionally relaxed. Every change is a revert to a known prior state — no new design decisions are required.
T-1: Restore ItemValidator strict constructor and validation
Section titled “T-1: Restore ItemValidator strict constructor and validation”File: src/main/kotlin/cards/arda/operations/reference/item/persistence/ItemValidator.kt
- Remove nullable
CdnUrlResolver?andS3AssetService?parameters; restore non-nullable types - Remove
cdnHost: Stringconstructor parameter entirely - Remove three bypass branches from
validateImageUrl():cdnHost.isBlank() -> Result.success(Unit)!payload.imageUrl.host.equals(cdnHost, ignoreCase = true) -> Result.success(Unit)cdnUrlResolver == null || s3AssetService == null -> Result.success(Unit)
After restoration, the when block should only contain:
when { payload.imageUrl == null -> Result.success(Unit) payload.imageUrl.toString() == previous?.payload?.imageUrl?.toString() -> Result.success(Unit) else -> cdnUrlResolver.validate(payload.imageUrl.toString()).flatMap { ... }}T-2: Restore ItemService non-nullable parameters
Section titled “T-2: Restore ItemService non-nullable parameters”File: src/main/kotlin/cards/arda/operations/reference/item/ItemService.kt
- Restore non-nullable constructor parameters for CDN dependencies
- Remove null guard on upload path
- Remove
!!operators
T-3: Restore Module.kt required configuration
Section titled “T-3: Restore Module.kt required configuration”File: src/main/kotlin/cards/arda/operations/reference/item/Module.kt
- Change
optionalExtraback torequireExtrafor image infrastructure config values (imageAssetBucketName,imagePresignRoleArn,imageCdnDomain) - Restore unconditional construction of
S3AssetServiceandCdnUrlResolver - Remove
imageCdnDomainfromItemValidatorconstructor call
T-4: Restore Helm chart required values
Section titled “T-4: Restore Helm chart required values”File: src/main/helm/templates/configmap.yaml
- Change
| default ""back to| requiredfor the 4 image infrastructure lines (imageAssetBucketArn,imageAssetBucketName,imagePresignRoleArn,imageCdnDomain)
T-5: Restore CloudFormation export reads
Section titled “T-5: Restore CloudFormation export reads”File: src/main/helm/read-cloudFormation-values.cmd
Remove || true from the 4 image export readExport lines. Despite
issue comment stating this was reverted in 140a7c8, the file still
contains the || true suffixes on the working branch.
T-6: Restore tests
Section titled “T-6: Restore tests”File: ItemValidatorImageUrlTest.kt
- Remove backward-compatibility tests:
"accepts non-CDN external URL without validation""accepts any URL when CDN is not configured"
- Restore original test URLs (change CDN-host URLs back to
wrong-host.comURLs) in 3 tests and restore original test name:"validateForCreate with CDN URL that fails CDN validation returns ArgumentValidation"→ restore name to"validateForCreate with invalid CDN URL returns ArgumentValidation"and URL fromhttps://$cdnHost/other-tenant/images/file.jpgtohttps://wrong-host.com/$tenantId/images/file.jpg"validateForCreate maps CDN Composite error to ArgumentValidation with combined message"— URL fromhttps://$cdnHost/bad-path/file.jpgtohttps://wrong-host.com/bad-path/file.jpg"validateForCreate does not swallow Composite containing unmappable errors"— URL fromhttps://$cdnHost/file.jpgtohttps://wrong-host.com/file.jpg
- Remove
import io.mockk.coVerifyif unused after test removal - Restore
ApplicationConfTest.ktexpected extras count if modified
T-7: Build verification
Section titled “T-7: Build verification”- Run
make build(full Gradle build including tests) - Verify all existing CDN validation tests in
ItemValidatorImageUrlTestcontinue to pass
T-8: CHANGELOG and commit
Section titled “T-8: CHANGELOG and commit”- CHANGELOG update per
release-lifecycleconventions - Commit all changes
Exit Criteria
Section titled “Exit Criteria”- All image URLs must be CDN URLs — external HTTPS URLs are rejected with 400
- Module fails to start if image infrastructure config values are missing
- Helm deploy fails if CloudFormation exports are missing
nullimageUrl and unchanged imageUrl continue to pass (TD-15 grandfather clause)make buildpasses- No nullable CDN dependencies remain in
ItemValidator,ItemService, orModule.kt
Applicable Skills
Section titled “Applicable Skills”| Skill | Usage |
|---|---|
kotlin-coding | Kotlin code conventions |
unit-tests-backend | Test restoration and verification |
release-lifecycle | CHANGELOG update |
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved