@@ -482,6 +482,142 @@ jobs:
482482 - name : Generate GraphQL schema file
483483 run : pnpm dev:generate-graphql-schema graphql-schema-gen
484484
485+ # Test content-api integration with packed packages. Each job runs its own
486+ # ephemeral Content API instance pulled from Figma's ECR, backed by a Postgres
487+ # service container and a LocalStack container for S3 storage tests. This
488+ # gives each run an isolated sandbox, avoiding data collisions between
489+ # concurrent CI runs and removing the need for shared credentials.
490+ tests-content-api :
491+ name : Content API Tests
492+ runs-on : ubuntu-24.04
493+ needs : [changes, build]
494+ # Skip fork PRs: this job uses credentials fork workflows must not reach.
495+ if : needs.changes.outputs.needs_tests == 'true' && github.event.pull_request.head.repo.fork == false
496+ # Non-blocking while adapter coverage is incomplete. Once the full suite
497+ # passes, migrate to the `tests-int` matrix pattern (`pnpm test:int`
498+ # with --shard); `test:int:summary` cannot shard.
499+ continue-on-error : true
500+ permissions :
501+ id-token : write
502+ contents : read
503+ services :
504+ postgres :
505+ image : postgres:13
506+ env :
507+ POSTGRES_DB : figma_content_api
508+ POSTGRES_USER : postgres
509+ POSTGRES_PASSWORD : postgres
510+ ports :
511+ - 5432:5432
512+ options : >-
513+ --health-cmd "pg_isready -U postgres"
514+ --health-interval 10s
515+ --health-timeout 5s
516+ --health-retries 5
517+ localstack :
518+ image : localstack/localstack:4.10.0
519+ env :
520+ SERVICES : s3
521+ ports :
522+ - 4566:4566
523+ options : >-
524+ --health-cmd "curl -f http://localhost:4566/_localstack/health || exit 1"
525+ --health-interval 10s
526+ --health-timeout 5s
527+ --health-retries 10
528+ steps :
529+ - uses : actions/checkout@v5
530+
531+ - name : Node setup
532+ uses : ./.github/actions/setup
533+ with :
534+ restore-build : true
535+
536+ - name : Configure AWS credentials
537+ uses : aws-actions/configure-aws-credentials@v4
538+ with :
539+ role-to-assume : arn:aws:iam::060562746757:role/content-api-external-ci-pull
540+ aws-region : us-west-2
541+
542+ - name : Login to Amazon ECR
543+ uses : aws-actions/amazon-ecr-login@v2
544+
545+ # Figma publishes ECR tags as the 40-char SHA of the figma/figma commit
546+ # that built the image. There is no reliable floating alias, so pick the
547+ # most recently pushed SHA tag (skipping cosign `.sig` signatures).
548+ # `--max-results 100 --no-paginate` bounds the call to a single page;
549+ # without it the CLI pages through the full history and takes ~50s.
550+ - name : Resolve latest Content API image tag
551+ id : resolve-image
552+ run : |
553+ TAG=$(aws ecr describe-images \
554+ --repository-name payload/content-api \
555+ --region us-west-2 \
556+ --max-results 100 \
557+ --no-paginate \
558+ --query 'reverse(sort_by(imageDetails,& imagePushedAt))[].imageTags[]' \
559+ --output text | tr '\t' '\n' | grep -E '^[a-f0-9]{40}$' | head -n1)
560+ if [ -z "$TAG" ]; then
561+ echo "::error::No git-SHA-like tag found in payload/content-api ECR"
562+ exit 1
563+ fi
564+ echo "Using tag: $TAG"
565+ echo "tag=$TAG" >> "$GITHUB_OUTPUT"
566+
567+ # Cache the image tarball by resolved SHA so repeated runs on the same
568+ # figma/figma image skip the ~55s ECR pull.
569+ - name : Cache Content API image
570+ id : cache-content-api-image
571+ uses : actions/cache@v4
572+ with :
573+ path : /tmp/content-api-image.tar
574+ key : content-api-image-${{ steps.resolve-image.outputs.tag }}
575+
576+ - name : Start Content API
577+ run : |
578+ IMAGE=060562746757.dkr.ecr.us-west-2.amazonaws.com/payload/content-api:${{ steps.resolve-image.outputs.tag }}
579+ if [ -f /tmp/content-api-image.tar ]; then
580+ echo "Loading Content API image from cache"
581+ docker load -i /tmp/content-api-image.tar
582+ else
583+ echo "Pulling Content API image from ECR"
584+ docker pull "$IMAGE"
585+ docker save -o /tmp/content-api-image.tar "$IMAGE"
586+ fi
587+ docker run -d \
588+ --name content-api \
589+ --network host \
590+ -e DATABASE_URL="postgresql://postgres:postgres@localhost:5432/figma_content_api" \
591+ -e NODE_ENV=development \
592+ -e TARGET_ENV=development \
593+ -e CONTENT_API_PORT=8080 \
594+ -e S3_ENDPOINT=http://localhost:4566 \
595+ "$IMAGE"
596+
597+ - name : Wait for Content API to be ready
598+ run : |
599+ for i in $(seq 1 60); do
600+ if curl -sf http://localhost:8080/health > /dev/null; then
601+ echo "Content API is ready"
602+ exit 0
603+ fi
604+ sleep 2
605+ done
606+ echo "Content API failed to start within timeout"
607+ docker logs content-api || true
608+ exit 1
609+
610+ - name : Run Content API Integration Tests
611+ continue-on-error : true
612+ run : pnpm test:int:summary
613+ env :
614+ NODE_OPTIONS : --max-old-space-size=8096
615+ PAYLOAD_DATABASE : content-api
616+
617+ - name : Dump Content API logs on failure
618+ if : failure()
619+ run : docker logs content-api || true
620+
485621 all-green :
486622 name : All Green
487623 if : always()
@@ -496,6 +632,7 @@ jobs:
496632 tests-e2e,
497633 tests-types,
498634 tests-type-generation,
635+ tests-content-api,
499636 ]
500637
501638 steps :
0 commit comments