Artifacts Storage

how build artifacts are stored and delivered

πŸ“¦ Artifacts Repository Overview

The igaawi-artifacts repository is a dedicated storage for large static build artifacts used by the frontend application at runtime β€” such as ML model weights (*.bin), 3D models (*.glb, *.GLB), and other precomputed assets that should not live in the application source tree.

Because these files are large binary blobs, the repository uses Git LFS to keep the Git history light. Tracked patterns are defined in .gitattributes:

# glb files
*.glb filter=lfs diff=lfs merge=lfs-text
*.GLB filter=lfs diff=lfs merge=lfs-text

# tfjs model weight shards
*.bin filter=lfs diff=lfs merge=lfs-text

πŸ—‚ Repository Layout

igaawi-artifacts/
β”œβ”€β”€ .github/
β”‚   β”œβ”€β”€ actions/sync_bucket/action.yaml   # composite action: gzip + upload + invalidate
β”‚   └── workflows/sync_bucket.yaml        # manual workflow_dispatch entrypoint
└── artifacts/                            # source of truth for all delivered assets
    β”œβ”€β”€ public/
    └── web/

Everything under artifacts/ is what ends up in the target S3 bucket β€” the directory structure is preserved as S3 keys.

πŸš€ Delivery Flow

graph LR;
    A[git push / LFS] --> B[igaawi-artifacts repo]
    B --> C[GHA: Sync Bucket]
    C --> D[gzip + aws s3 cp]
    D --> E[(S3 bucket)]
    E --> F[CloudFront]
    F --> G[Frontend]
  1. A developer commits new/updated assets into artifacts/ (large files go through Git LFS).
  2. A maintainer triggers the Sync Bucket workflow manually via workflow_dispatch, choosing the target environment (development, staging, production).
  3. The workflow assumes an AWS IAM role via GitHub OIDC, gzips every file in place, uploads the tree to S3 with Content-Encoding: gzip, and β€” for production β€” creates a CloudFront invalidation.
  4. The frontend and CloudFront read from the same bucket (see CloudFront).

πŸ” IAM Permissions

The IAM role used by GitHub Actions is provisioned by Terraform in envs/prod/platforms/github/actions/prod.tfvars.

Only the igaawi-artifacts repository is allowed to assume this role via OIDC, and it is scoped to a single bucket plus one CloudFront distribution:

gha_roles = {
  "github-actions-oidc" = {
    identifier         = "artifacts-s3",
    description_policy = "Allows syncing build artifacts into the API backend S3 bucket"
    description_role   = "Role used by GHA to sync build artifacts into the API backend S3 bucket"
    github_oidc_repositories = [
      "igaawi-artifacts"
    ],
    extra_oidc_iam_role_policies = [
      {
        actions = [
          "s3:DeleteObject",
          "s3:GetBucketLocation",
          "s3:GetObject",
          "s3:ListBucket",
          "s3:PutObject"
        ]
        resources = [
          "arn:aws:s3:::igaawi-prod-api-backend-bucket",
          "arn:aws:s3:::igaawi-prod-api-backend-bucket/*"
        ]
      },
      {
        actions = [
          "cloudfront:CreateInvalidation",
          "cloudfront:GetInvalidation",
          "cloudfront:ListInvalidations"
        ]
        resources = [
          "arn:aws:cloudfront::187528943262:distribution/E3V0XRM5MEK3WZ"
        ]
      }
    ]
  }
}

Key points:

  • No long-lived AWS credentials β€” auth is done via GitHub OIDC, tokens are short-lived and scoped to the workflow run.
  • The role can Get/Put/Delete/List only on igaawi-prod-api-backend-bucket.
  • The role can create and read CloudFront invalidations only for distribution E3V0XRM5MEK3WZ β€” the frontend distribution.
  • Trust policy accepts OIDC subjects only from saritasa-nest/igaawi-artifacts, so no other repo in the org can borrow this role.

βš™οΈ Sync Workflow

The workflow is defined in .github/workflows/sync_bucket.yaml and delegates the heavy lifting to a composite action .github/actions/sync_bucket/action.yaml.

on:
  workflow_dispatch:
    inputs:
      environment:
        description: "Target environment"
        type: choice
        required: true
        options:
          - development
          - staging
          - production

The environment selector controls which set of GitHub Environment variables is used (AWS_ROLE_ARN, AWS_DEFAULT_REGION, AWS_S3_BUCKET, CLOUDFRONT_DISTRIBUTION_ID). CloudFront invalidation runs only for production, other environments just refresh the bucket.

What the composite action does

  1. Install aws-cli if the runner image doesn’t already have it.

  2. Configure AWS credentials via OIDC using aws-actions/configure-aws-credentials@v4 and the role ARN above.

  3. Gzip every file under artifacts/ in place with gzip -n -9, then strip the .gz suffix so that S3 keys stay clean (artifacts/web/foo.bin, not artifacts/web/foo.bin.gz).

  4. Recursive upload via aws s3 cp --recursive with:

    • --content-type application/octet-stream
    • --content-encoding gzip

    This lets browsers and CloudFront transparently decompress the payload, while we store and transfer it compressed.

  5. Invalidate CloudFront (/*) so the new artifacts are visible immediately β€” see CloudFront for details on how caching works.

  • CloudFront β€” how the frontend serves these artifacts through the CDN.
  • CI/CD β€” how application code (not artifacts) is built and deployed.