Skip to content

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

  • 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

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? and S3AssetService? parameters; restore non-nullable types
  • Remove cdnHost: String constructor 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 optionalExtra back to requireExtra for image infrastructure config values (imageAssetBucketName, imagePresignRoleArn, imageCdnDomain)
  • Restore unconditional construction of S3AssetService and CdnUrlResolver
  • Remove imageCdnDomain from ItemValidator constructor call

File: src/main/helm/templates/configmap.yaml

  • Change | default "" back to | required for the 4 image infrastructure lines (imageAssetBucketArn, imageAssetBucketName, imagePresignRoleArn, imageCdnDomain)

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.

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.com URLs) 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 from https://$cdnHost/other-tenant/images/file.jpg to https://wrong-host.com/$tenantId/images/file.jpg
    • "validateForCreate maps CDN Composite error to ArgumentValidation with combined message" — URL from https://$cdnHost/bad-path/file.jpg to https://wrong-host.com/bad-path/file.jpg
    • "validateForCreate does not swallow Composite containing unmappable errors" — URL from https://$cdnHost/file.jpg to https://wrong-host.com/file.jpg
  • Remove import io.mockk.coVerify if unused after test removal
  • Restore ApplicationConfTest.kt expected extras count if modified
  • Run make build (full Gradle build including tests)
  • Verify all existing CDN validation tests in ItemValidatorImageUrlTest continue to pass
  • CHANGELOG update per release-lifecycle conventions
  • Commit all changes
  • 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
  • null imageUrl and unchanged imageUrl continue to pass (TD-15 grandfather clause)
  • make build passes
  • No nullable CDN dependencies remain in ItemValidator, ItemService, or Module.kt
SkillUsage
kotlin-codingKotlin code conventions
unit-tests-backendTest restoration and verification
release-lifecycleCHANGELOG update

Copyright: (c) Arda Systems 2025-2026, All rights reserved