Skip to content

Add profile asset storage baseline#150

Merged
BASIC-BIT merged 2 commits into
mainfrom
profile-asset-storage-baseline
Jun 19, 2026
Merged

Add profile asset storage baseline#150
BASIC-BIT merged 2 commits into
mainfrom
profile-asset-storage-baseline

Conversation

@BASIC-BIT

Copy link
Copy Markdown
Owner

Summary

  • Adds a profile-assets Terraform stack for the private S3 asset bucket, Vercel OIDC runtime role, and hosted Vercel profile asset env vars.
  • Gates provider-backed CI plan/apply until the updated state-mgmt bootstrap role has been applied.
  • Teaches the web S3 client to use Vercel OIDC credentials when VRDEX_PROFILE_ASSET_ROLE_ARN is configured.

Rollout

After merge, apply the updated state-mgmt stack, set TERRAFORM_PROFILE_ASSETS_ENABLED=true, apply the profile-assets stack, redeploy Vercel, then re-probe the profile asset upload route for a non-501 response.

Validation

Local validation passed: pnpm verify:web, pnpm lint:markdown, terraform fmt -check -recursive infra/terraform, and terraform validate for profile-assets and state-mgmt.

@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
vr-dex-web Ready Ready Preview, Comment Jun 19, 2026 1:42pm

Request Review

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Storybook Image Diff

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/27829250502
Artifact: storybook-image-diff

Changed Storybook baselines: none in this PR.

This check compares design-system component screenshots against committed baselines. Inline images show only added or modified Storybook baseline PNGs.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Storybook Component Screenshot Preview

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/27829250502
Artifact: storybook-component-preview

Screenshots: primitive component stories captured on desktop and mobile.

This lane is separate from full-route Playwright screenshots and focuses on design-system component regressions.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Playwright Hosted Data-Flow

Outcome: success
Target: https://staging.vrdex.net
Hosted extended profile flow: enabled
Hosted auth helpers: enabled
Hosted adapter helpers: enabled
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/27829250502
Artifact: playwright-hosted-data-flow

This optional check runs the mutation-backed profile flow against a configured hosted dev/staging target with isolated E2E test data.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Playwright Data-Flow Preview

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/27829250502
Artifact: playwright-data-flow

Captured flow:

  • test-gated profile submission form
  • gated helper rejection without the Playwright token
  • Convex profile creation
  • submission success state
  • public profile page readback
  • discovery search readback

Artifacts include screenshots, traces, and recorded video for the flow run.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Playwright Image Diff

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/27829250502
Artifact: playwright-image-diff

Changed screenshot baselines: none in this PR.

This check compares public route screenshots against committed baselines. Inline images show only added or modified baseline PNGs.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

Playwright Public Screenshot Preview

Outcome: success
Run: https://github.com/BASIC-BIT/VRDex/actions/runs/27829250502
Artifact: playwright-public-preview

Screenshots: all public route checks passed on desktop and mobile.

Full screenshot set is available in the artifact. Pixel diff baselines are handled by the separate Playwright Image Diff check.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

@BASIC-BIT BASIC-BIT marked this pull request as ready for review June 19, 2026 13:28
@greptile-apps

greptile-apps Bot commented Jun 19, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a profile-assets Terraform stack that provisions a private S3 bucket, a Vercel OIDC IAM role, and the matching Vercel environment variables, then teaches the web S3 client to use those OIDC credentials when VRDEX_PROFILE_ASSET_ROLE_ARN is set. CI is gated behind TERRAFORM_PROFILE_ASSETS_ENABLED=true so the stack cannot accidentally run before state-mgmt is updated with the new IAM permissions.

  • The S3 bucket is correctly hardened: Block Public Access, BucketOwnerEnforced ownership, SSE-S3 encryption, and a DenyInsecureTransport bucket policy.
  • The IAM trust policy for the Vercel OIDC role is tightly scoped via StringEquals conditions on both aud and sub, limiting assumption to the specific Vercel project and named environments.
  • The s3Client credential-provider cache is keyed on ${region}:${roleArn} so OIDC-credentialed and default clients stay separate.

Confidence Score: 4/5

Safe to merge; the bootstrap gate prevents the stack from applying before state-mgmt permissions are in place, and the OIDC trust policy is correctly scoped.

The change is well-structured with appropriate security controls on both the Terraform and application sides. The main items worth resolving before or shortly after merge are: the AWS_ROLE_ARN fallback in vercelOidcRoleArn() which could silently pick up an unintended role during bootstrap, the hardcoded staging environment ID as a module variable default, and the absent s3:DeleteObject in the runtime role that will need to be added before any deletion path lands.

apps/web/src/lib/server/profile-asset-storage.ts (credential fallback logic) and infra/terraform/profile-assets/variables.tf (staging environment ID default) are the two spots worth a second look before enabling the stack.

Important Files Changed

Filename Overview
apps/web/src/lib/server/profile-asset-storage.ts Refactors s3Client to accept full StorageConfig and adds Vercel OIDC credential support via awsCredentialsProvider; cache key updated correctly; fallback to AWS_ROLE_ARN when VRDEX_PROFILE_ASSET_ROLE_ARN is absent could silently use an unintended role.
infra/terraform/profile-assets/main.tf Well-structured new stack: private S3 bucket with Block Public Access, SSE-S3, TLS-only policy, Vercel OIDC provider, and scoped IAM role. Runtime role missing s3:DeleteObject for future deletion paths.
infra/terraform/profile-assets/variables.tf Variables are well-described; staging_custom_environment_ids hardcodes a BASIC-BIT hosted environment ID as the module default, which would misfire for any operator applying without a tfvars override.
infra/terraform/state-mgmt/main.tf Adds well-scoped IAM permission statements for profile asset S3 bucket management, Vercel OIDC provider management, and runtime role management; resource ARNs are tightly scoped to the expected bucket and role names.
.github/workflows/terraform.yml Adds profile-assets stack entry with bootstrap gate via TERRAFORM_PROFILE_ASSETS_ENABLED; gate check and requires_profile_assets_enabled propagation to all other stacks look correct.
infra/terraform/profile-assets/versions.tf Provider constraints and S3 backend configuration look correct; uses native S3 lockfile (use_lockfile=true) consistent with other stacks.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Vercel as Vercel Function
    participant OIDC as @vercel/oidc-aws-credentials-provider
    participant STS as AWS STS
    participant S3 as AWS S3 (private bucket)

    Vercel->>OIDC: "awsCredentialsProvider({ roleArn })"
    OIDC->>STS: AssumeRoleWithWebIdentity(VERCEL_OIDC_TOKEN, roleArn)
    STS-->>OIDC: Temporary credentials
    OIDC-->>Vercel: Credentials provider
    Vercel->>S3: PutObject / GetObject (signed with temp creds)
    S3-->>Vercel: Response
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Vercel as Vercel Function
    participant OIDC as @vercel/oidc-aws-credentials-provider
    participant STS as AWS STS
    participant S3 as AWS S3 (private bucket)

    Vercel->>OIDC: "awsCredentialsProvider({ roleArn })"
    OIDC->>STS: AssumeRoleWithWebIdentity(VERCEL_OIDC_TOKEN, roleArn)
    STS-->>OIDC: Temporary credentials
    OIDC-->>Vercel: Credentials provider
    Vercel->>S3: PutObject / GetObject (signed with temp creds)
    S3-->>Vercel: Response
Loading
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
apps/web/src/lib/server/profile-asset-storage.ts:22-25
**Silent fallback to unrelated `AWS_ROLE_ARN`**

When `VRDEX_PROFILE_ASSET_ROLE_ARN` is absent and `isVercelRuntime()` is true, `AWS_ROLE_ARN` is used as the OIDC role. Vercel's own AWS integration also writes `AWS_ROLE_ARN` for its native AWS connectivity feature. If that integration is active, S3 profile-asset requests would silently use an unintended role — either failing confusingly with AccessDenied (if the role lacks S3 access) or, worse, succeeding under a broader role. The Terraform stack always populates `VRDEX_PROFILE_ASSET_ROLE_ARN`, so this fallback only fires during the bootstrap gap or in environments where the var was not set; returning `undefined` in that case and letting the SDK default credential chain handle it would be safer than reaching for an ambient env var that belongs to a different integration.

### Issue 2 of 3
infra/terraform/profile-assets/variables.tf:49-53
**Hardcoded hosted-deployment environment ID as module default**

`staging_custom_environment_ids` defaults to a specific BASIC-BIT Vercel custom environment ID. Any operator who applies this stack without a `tfvars` file (or who forks the module) would create Vercel environment variables bound to an environment they don't own and cannot access. An empty default is safer — the `terraform.tfvars.example` already documents the correct hosted value, so the module default doesn't need to carry it.

```suggestion
variable "staging_custom_environment_ids" {
  description = "Vercel custom environment IDs for staging-like environments that should receive profile asset env vars. Empty leaves custom environments unmanaged."
  type        = set(string)
  default     = []
}
```

### Issue 3 of 3
infra/terraform/profile-assets/main.tf:143-153
**Runtime role missing `s3:DeleteObject`**

The `ReadAndWriteProfileAssets` policy grants only `s3:GetObject` and `s3:PutObject`. The docs list "lifecycle rules and deletion/retention policy" as follow-on work; if a future account-deletion or moderation path calls `DeleteObject` without first updating this policy, the operation will return `AccessDenied` at runtime. Adding `s3:DeleteObject` now (scoped to the same prefix ARN) keeps the policy aligned with the stated intent of full read/write asset management.

Reviews (1): Last reviewed commit: "Add profile asset storage baseline" | Re-trigger Greptile

Comment thread apps/web/src/lib/server/profile-asset-storage.ts Outdated
Comment thread infra/terraform/profile-assets/variables.tf
Comment thread infra/terraform/profile-assets/main.tf

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ccb56a0fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread infra/terraform/state-mgmt/main.tf
@BASIC-BIT BASIC-BIT merged commit cbccf8d into main Jun 19, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant