Skip to content

Verification: AWS Infrastructure for Item Image Upload

Verification criteria for the AWS Infrastructure project. Each criterion maps to a deliverable in specification.md and a success criterion in goal.md. Criteria are grouped by phase (Phase 0: DNS Foundation, Phase 1: Partition Resources).


Deliverable: assets.arda.cards hosted zone in Root Account (specification.md section 2.4).

Verification steps:

  1. Run deploy-root.sh against the root account.
  2. cdk synth for root configuration includes the new assetsZone export.
  3. After deploy, verify the hosted zone exists:
    Terminal window
    aws route53 list-hosted-zones-by-name \
    --dns-name assets.arda.cards \
    --max-items 1
    Expected: one zone with Name: assets.arda.cards.
  4. Verify the zone ID is exported:
    Terminal window
    aws cloudformation list-exports \
    --query "Exports[?Name=='arda-assets-zone'].Value"
    Expected: non-empty zone ID.

Pass criteria: Zone exists in root account, export is available.

V-002: Infrastructure Subdomain Zone and Certificate

Section titled “V-002: Infrastructure Subdomain Zone and Certificate”

Deliverable: <infra>.assets.arda.cards subdomain zone + ACM cert (specification.md section 2.4).

Verification steps:

  1. Run amm.sh <infrastructure> <partition> (e.g., amm.sh Alpha002 dev).
  2. Verify the subdomain zone exists:
    Terminal window
    aws route53 list-hosted-zones-by-name \
    --dns-name alpha002.assets.arda.cards \
    --max-items 1
  3. Verify NS delegation — the root assets.arda.cards zone contains NS records for the subdomain:
    Terminal window
    dig NS alpha002.assets.arda.cards
    Expected: returns name servers matching the subdomain zone.
  4. Verify the ACM certificate:
    Terminal window
    aws acm list-certificates \
    --query "CertificateSummaryList[?DomainName=='*.alpha002.assets.arda.cards']"
    Expected: one certificate with Status: ISSUED.
  5. Verify CloudFormation exports include the new assets entries:
    Terminal window
    aws cloudformation list-exports \
    --query "Exports[?contains(Name, 'AssetsDomainName')]"

Pass criteria: Subdomain zone resolves, NS delegation works, ACM cert is ISSUED, exports are available.

Deliverable: No regressions to existing stacks.

Verification steps:

  1. Run npm run ci-check (synthesizes all infrastructure and partition targets).
  2. All targets produce valid CloudFormation templates.
  3. No existing exports are removed or renamed.

Pass criteria: ci-check passes with zero errors.

Deliverable: deploy-root.sh (specification.md section 2.4).

Verification steps:

  1. Script exists at infrastructure/deploy-root.sh.
  2. Script is executable (chmod +x).
  3. Script bootstraps CDK and deploys r53-zones.ts to the root account.
  4. Idempotent: running twice produces no errors and no changes on second run.

Pass criteria: Script deploys root configuration successfully.


Deliverable: All new constructs and stack modifications (specification.md sections 1 and 2).

Maps to: Goal SC-1.

Verification steps:

  1. Run npm run ci-check.
  2. Verify the synthesized templates include:
    • ImageAssetBucket S3 bucket resource with versioning enabled, SSE-S3, RETAIN removal policy.
    • ImageUploadPresigningRole IAM role with s3:PutObject, s3:GetObject, multipart actions.
    • ImageStorageStack with CloudFront distribution, OAC, trusted key groups.
    • CloudFrontSigningKeyGroup with public key and Secrets Manager secret.
  3. Verify 6 new cross-stack exports are present in the synthesized templates.

Pass criteria: ci-check passes; templates contain all expected resources and exports.

Deliverable: Stacks deploy without errors.

Maps to: Goal SC-2.

Verification steps:

  1. Run amm.sh <infrastructure> <partition> against dev environment.
  2. All stacks (including new ImageStorageStack) deploy successfully.
  3. No rollbacks.

Pass criteria: All stacks reach CREATE_COMPLETE or UPDATE_COMPLETE.

Deliverable: ImageUploadPresigningRole (specification.md section 1.1).

Maps to: Goal SC-3.

Verification steps:

  1. From the EKS pod role (or equivalent test credentials), call sts:AssumeRole on the presigning role ARN.
  2. Temporary credentials are returned.

Pass criteria: AssumeRole succeeds; credentials are valid.

Automated by: verify-image-cdn.ts step 1.

Deliverable: ImageAssetBucket with presigning role (specification.md section 1.1).

Maps to: Goal SC-4.

Verification steps:

  1. Using assumed-role credentials, generate a presigned POST form for key <tenantId>/images/test-<uuid>.jpg.
  2. POST a test JPEG to S3 using the presigned form fields.
  3. HeadObject on the uploaded key returns metadata matching the policy conditions (x-amz-meta-tenant-id, Content-Type: image/jpeg, SSE-S3).

Pass criteria: Upload succeeds (HTTP 204); HeadObject confirms object exists with correct metadata.

Automated by: verify-image-cdn.ts steps 2-4.

V-105: CloudFront Unauthenticated Rejection

Section titled “V-105: CloudFront Unauthenticated Rejection”

Deliverable: ImageAssetCdn with trusted key groups (specification.md section 1.2).

Maps to: Goal SC-5.

Verification steps:

  1. GET the uploaded image URL from CloudFront without any cookies.
  2. Response is HTTP 403 Forbidden.

Pass criteria: Unauthenticated request returns 403.

Automated by: verify-image-cdn.ts step 5.

Deliverable: CloudFrontSigningKeyGroup + ImageAssetCdn (specification.md sections 1.2 and 1.3).

Maps to: Goal SC-6.

Verification steps:

  1. Retrieve the signing private key from Secrets Manager.
  2. Generate CloudFront signed cookies with a custom policy scoped to https://<cdn-domain>/<tenantId>/*.
  3. GET the uploaded image URL with the three signed cookies (CloudFront-Policy, CloudFront-Signature, CloudFront-Key-Pair-Id).
  4. Response is HTTP 200 with image content.

Pass criteria: Authenticated request with valid cookies returns 200.

Automated by: verify-image-cdn.ts steps 6-8.

Deliverable: Signed cookie tenant scoping (specification.md section 1.2).

Maps to: Goal SC-7.

Verification steps:

  1. Generate signed cookies scoped to a different tenant ID (Tenant B).
  2. GET the original image (uploaded under Tenant A) with Tenant B’s cookies.
  3. Response is HTTP 403 Forbidden.

Pass criteria: Wrong-tenant cookies are rejected.

Automated by: verify-image-cdn.ts steps 9-10.

Deliverable: tools/verify-image-cdn.ts (specification.md section 3).

Maps to: Goal SC-8.

Verification steps:

  1. Script exists and compiles (npx ts-node tools/verify-image-cdn.ts --help).
  2. Run the script with valid parameters against the deployed dev environment.
  3. All steps (V-103 through V-107) pass.
  4. Test object is cleaned up from S3 after the run.

Pass criteria: Script exits with code 0; no test artifacts remain.

Deliverable: partition.ts wiring (specification.md section 2.3).

Verification steps:

  1. Deploy a second partition in the same infrastructure (e.g., stage after dev).
  2. The new partition receives its own image bucket, CDN distribution, presigning role, and signing key group.
  3. CDN domains are distinct per partition (dev.<infra>.assets.arda.cards vs. stage.<infra>.assets.arda.cards).
  4. S3 bucket names are distinct per partition.

Pass criteria: Multiple partitions coexist with independent image infrastructure.

Deliverable: Existing stacks unaffected.

Verification steps:

  1. After deploying Phase 1, verify existing resources are unchanged:
    • Upload bucket (CSV) still works.
    • API Gateway still serves requests.
    • Cognito authentication still works.
    • Aurora database still accessible.
  2. All existing CloudFormation exports are present and unchanged.

Pass criteria: No existing functionality is broken.

Deliverable: Test infrastructure and construct tests (specification.md section 5).

Verification steps:

  1. npm test runs successfully.
  2. Unit tests for ImageAssetBucket verify: naming, versioning, RETAIN policy, SSE-S3, BlockPublicAccess, no expiration lifecycle, CORS POST-only, presigning role conditions, validation.
  3. Unit tests for ImageAssetCdn verify: OAC origin, HTTPS-only, GET/HEAD only, CachingOptimized, PriceClass_100, trusted key groups, custom domain, Route53 record, validation.
  4. Unit tests for CloudFrontSigningKeyGroup verify: public key, key group, Secrets Manager secret, RETAIN policies.
  5. Snapshot tests for ImageStorageStack capture the full template with all 6 exports.

Pass criteria: npm test exits with code 0; all assertions pass.

Deliverable: AwsSolutions compliance (specification.md section 5).

Verification steps:

  1. cdk synth with AwsSolutionsChecks aspect applied.
  2. No unsuppressed findings for new constructs.
  3. All suppressions have documented reasons.

Pass criteria: Synth succeeds; no unaddressed cdk-nag findings.

Deliverable: .github/workflows/ci.yaml updated (specification.md section 5).

Verification steps:

  1. Open a PR in the infrastructure repo with a deliberate test failure (e.g., wrong bucket name assertion).
  2. The build job in ci.yaml runs npm test and fails.
  3. PR cannot merge while the build job is failing.
  4. Fix the test, push — build job passes, PR is mergeable.

Pass criteria: npm test is a required step in the build job; a failing test blocks PR merge.


IDPhaseCriterionAutomatedGoal SC
V-0010Root zone deploymentManual
V-0020Infra subdomain zone + certManual
V-0030CDK synth regressionci-check
V-0040deploy-root.sh scriptManual
V-1011CDK synthci-checkSC-1
V-1021Stack deploymentamm.shSC-2
V-1031Presigning role assumptionverify-image-cdn.tsSC-3
V-1041S3 upload via presigned POSTverify-image-cdn.tsSC-4
V-1051CloudFront unauthenticated rejectionverify-image-cdn.tsSC-5
V-1061CloudFront signed cookie accessverify-image-cdn.tsSC-6
V-1071Tenant isolationverify-image-cdn.tsSC-7
V-1081Verification scriptManual + scriptSC-8
V-1091Partition integrationManual
V-1101No regressionsci-check + manual
V-1111Unit tests passnpm test
V-1121cdk-nag compliancecdk synth
V-1131CI gates PRs with testsci.yaml

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