Problem
Volume bucket names are account-global, not stage-scoped: Volume.getBucketName() returns boxlite-volume-${id} (apps/api/src/box/entities/volume.entity.ts:48), while multiple stages (dev, e2e-ci, personal) share one AWS account.
Because the bucket name is the only stage signal available to IAM, every policy that scopes to arn:aws:s3:::boxlite-volume-* — the Api task role's volume statement and the runner's RunnerVolumeS3Policy (apps/infra/sst.config.ts) — necessarily spans all stages' volume buckets. Concretely: dev's API/runner can list, read, and delete e2e-ci's volume buckets, and vice versa. PR #732 narrowed the actions on these grants but could not narrow the resources further without this rename.
Proposed fix
- Make the prefix configurable:
VOLUME_BUCKET_PREFIX env (default boxlite-volume- for compatibility), set from sst.config.ts as ${$app.name}-${$app.stage}-volume-.
- Persist
bucketName on the volume row at creation time so existing volumes keep their current buckets while new volumes get the stage-scoped prefix (avoids orphaning boxlite-volume-<id> buckets already in use).
- Tighten both IAM resource patterns to the stage prefix once the fleet of old-prefix volumes drains (or keep a temporary dual-pattern grant during transition).
Notes
- Bucket names are globally unique across AWS; the UUID suffix already prevents collisions — this is purely an isolation/IAM-scoping concern.
- The runner mounts buckets by name received from the control plane (
apps/runner/pkg/boxlite/volumes.go), so no runner code change is needed beyond the IAM pattern.
Problem
Volume bucket names are account-global, not stage-scoped:
Volume.getBucketName()returnsboxlite-volume-${id}(apps/api/src/box/entities/volume.entity.ts:48), while multiple stages (dev, e2e-ci, personal) share one AWS account.Because the bucket name is the only stage signal available to IAM, every policy that scopes to
arn:aws:s3:::boxlite-volume-*— the Api task role's volume statement and the runner'sRunnerVolumeS3Policy(apps/infra/sst.config.ts) — necessarily spans all stages' volume buckets. Concretely: dev's API/runner can list, read, and delete e2e-ci's volume buckets, and vice versa. PR #732 narrowed the actions on these grants but could not narrow the resources further without this rename.Proposed fix
VOLUME_BUCKET_PREFIXenv (defaultboxlite-volume-for compatibility), set fromsst.config.tsas${$app.name}-${$app.stage}-volume-.bucketNameon the volume row at creation time so existing volumes keep their current buckets while new volumes get the stage-scoped prefix (avoids orphaningboxlite-volume-<id>buckets already in use).Notes
apps/runner/pkg/boxlite/volumes.go), so no runner code change is needed beyond the IAM pattern.