Fix S3 bucket prefix omission for custom endpoints in StorageFactory#242
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Greptile SummaryThis PR fixes a bug where
Confidence Score: 5/5Safe to merge — the change is narrowly scoped to prepending a bucket prefix in two code paths that were previously broken for custom S3 endpoints, and all existing behaviour is preserved for the AWS branch and the no-bucket case. The logic is straightforward: a single $bucketRoot expression guards with the same empty-value pattern already used throughout the file, the Utopia DSN library strips the leading slash from the path so the concatenation produces clean keys, and the AWS branch is explicitly left untouched. The new test class exercises every branch including edge cases (root-is-slash, no-bucket, invalid-DSN fallback). No files require special attention. Important Files Changed
Reviews (2): Last reviewed commit: "Clarify AWS S3 DSN example to use virtua..." | Re-trigger Greptile |
Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Fixes #239
When
OPR_EXECUTOR_CONNECTION_STORAGEpoints to an S3-compatible backend (MinIO, Garage, etc.) via theurl=DSN parameter or a customhost,StorageFactory::getDevice()created the genericS3device without prepending the bucket from the DSN path to the storage root. Since the genericS3device has no separate bucket parameter, requests targeted the wrong bucket/key prefix (e.g.NoSuchBucket: Bucket not found: storagewith path-style access), causing builds to fail withFailed to move built code to storage.Changes
StorageFactory: prepend the DSN bucket to the root for both theurl=and customhostS3 branches, matching Appwrite's owngetDevice()behavior. TheAWSbranch is untouched since it receives the bucket as a separate constructor argument, and setups without a bucket in the DSN path behave exactly as before.StorageFactorycovering local/default fallback, invalid DSN fallback, bucket prefixing forurl=andhostbranches, and the no-bucket cases.url=is used) and documented theurl=parameter for S3-compatible endpoints.With the DSN from the issue,
getDevice('/storage/builds/app-test', $dsn)->getRoot()now returnsmybucket/storage/builds/app-testinstead ofstorage/builds/app-test.Test plan
composer test:unit(20 tests, 72 assertions, all passing)composer format:checkcomposer analyze(phpstan, no errors)composer refactor:check(rector, no changes)Made with Cursor