Skip to content

Conversation

@moskyb
Copy link
Contributor

@moskyb moskyb commented Dec 4, 2025

Description

Fix issue where artifacts uploaded to custom s3 buckets would have a double slash prefix

There's an edge case in URL construction for artifacts uploaded to custom S3 buckets where the key for the object would be generated as /object-key (note preceding slash), and then directly appended to a url like https://my-definitely-realy-s3-bucket.s3.amazonaws.com/, leading to a final object url of https://my-definitely-real-s3-bucket.s3.amazonaws.com//object-key (note the double slash!). See the implementation for more details — u.BucketPath is empty by default in custom artifact bucket cases.

When we were on the AWS Go SDK v1, this was fine, as the SDK cleaned urls by default, leading to the object's key being normalized from /object-key to object-key. However, in an undocumented breaking change (🫠), the SDK v2 doesn't do this cleaning, so the object would be uploaded with a leading slash on its key.

The artifact downloader relied on the URL cleaning functionality of the go SDK, so when attempting to download the artifact, it would generate a key of object-key, without the leading slash, leading to consistent 404s when trying to download artifacts from custom buckets.

This PR updates the artifact upload URL generation logic to do a path-join of the key rather than a crude append, essentially emulating the logic that was present in v1 of the AWS Go SDK.

Context

PS-1470

Testing

  • Tests have run locally (with go test ./...). Buildkite employees may check this if the pipeline has run automatically.
  • Code is formatted (with go tool gofumpt -extra -w .)\

Disclosures / Credits

I used Amp to investigate the issue initially, then wrote the fourteen-character fix all by myself.

@moskyb moskyb requested a review from a team December 4, 2025 00:15
Copy link
Contributor

@zhming0 zhming0 left a comment

Choose a reason for hiding this comment

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

Is this something we can write an new e2e test for?? with our new e2e test gear

@moskyb
Copy link
Contributor Author

moskyb commented Dec 4, 2025

oooh, good call!

@moskyb moskyb force-pushed the fix-double-slashed-custom-bucket-artifacts branch 4 times, most recently from 47cb0e5 to d06c720 Compare December 4, 2025 03:22
pipeline *buildkite.Pipeline
}

var leadingTabsRe = regexp.MustCompile(`(?m)^(\t+)`)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
var leadingTabsRe = regexp.MustCompile(`(?m)^(\t+)`)
var leadingTabsRE = regexp.MustCompile(`(?m)^(\t+)`)

- commands:
- echo "hello world" > artifact.txt
- buildkite-agent artifact upload artifact.txt
- commands:
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this have a depends_on or wait to make the ordering clear?

Comment on lines 31 to 34
logs := tc.fetchLogs(ctx, build)
if !strings.Contains(logs, "\nsuccess") {
t.Errorf("tc.fetchLogs(ctx, build %q) logs as follows, did not contain 'success'\n%s", build.ID, logs)
}
Copy link
Contributor

@DrJosh9000 DrJosh9000 Dec 4, 2025

Choose a reason for hiding this comment

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

Relying on the job to succeed or fail might be enough. Having to pull the job logs might make the test run longer for not much benefit.

Copy link
Contributor

Choose a reason for hiding this comment

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

I assume you're working on a version that uses a custom S3 bucket?

@moskyb moskyb force-pushed the fix-double-slashed-custom-bucket-artifacts branch from d06c720 to cacaf7b Compare December 4, 2025 03:51
Comment on lines 2 to 4
set -eo pipefail

if [[ -z "${BUILDKITE_TRIGGERED_FROM_BUILD_ID}" ]] ; then
Copy link
Contributor

Choose a reason for hiding this comment

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

What about:

Suggested change
set -eo pipefail
if [[ -z "${BUILDKITE_TRIGGERED_FROM_BUILD_ID}" ]] ; then
set -euo pipefail
if [[ -z "${BUILDKITE_TRIGGERED_FROM_BUILD_ID:-}" ]] ; then

@moskyb moskyb force-pushed the fix-double-slashed-custom-bucket-artifacts branch 2 times, most recently from ceb7a1c to e3c643b Compare December 4, 2025 04:10
…double slash prefix

There's an edge case in URL construction for artifacts uploaded to custom S3 buckets where the key for the object would be generated as `/object-key` (note preceding slash), and then directly appended to a url like `https://my-definitely-realy-s3-bucket.s3.amazonaws.com/`, leading to a final object url of `https://buildkite-benno-artifacts-test.s3.amazonaws.com//object-key` (note the double slash!). See [the implementation](https://github.com/buildkite/agent/blob/2a95448832f3fa4c2eb08dabb69db06ff01782fb/internal/artifact/s3_uploader.go#L147) for more details — `u.BucketPath` is empty by default in custom artifact bucket cases.

When we were on the AWS Go SDK v1, this was fine, as the SDK [cleaned urls by default](aws/aws-sdk-go#2559), leading to the object's key being normalized from `/object-key` to `object-key`. However, in an [undocumented breaking change](aws/aws-sdk-go-v2#3095) (🫠), the SDK v2 doesn't do this cleaning, so the object would be uploaded with a leading slash on its key.

The artifact downloader relied on the URL cleaning functionality of the go SDK, so when attempting to download the artifact, it would generate a key of `object-key`, without the leading slash, leading to consistent 404s when trying to download artifacts from custom buckets.

This PR updates the artifact upload URL generation logic to do a path-join of the key rather than a crude append, essentially emulating the logic that was present in v1 of the AWS Go SDK.
@moskyb moskyb force-pushed the fix-double-slashed-custom-bucket-artifacts branch from e3c643b to 8e5dfb5 Compare December 4, 2025 23:04
@moskyb
Copy link
Contributor Author

moskyb commented Dec 4, 2025

i'm going to merge this as is, and add an e2e test for artifact upload/download with a custom bucket in a followup — i've tested this and made sure it works, but there's quite a bit of infra stuff i'll need to do to set up the e2e test, and i don't want that to block shipping a fix to the customer.

@moskyb moskyb enabled auto-merge December 4, 2025 23:06
@moskyb moskyb force-pushed the fix-double-slashed-custom-bucket-artifacts branch from 8e5dfb5 to a79c5af Compare December 4, 2025 23:15
@moskyb moskyb force-pushed the fix-double-slashed-custom-bucket-artifacts branch from a79c5af to 537c838 Compare December 4, 2025 23:15
@moskyb moskyb merged commit a1be636 into main Dec 4, 2025
2 checks passed
@moskyb moskyb deleted the fix-double-slashed-custom-bucket-artifacts branch December 4, 2025 23:22
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.

4 participants