publish.sh cannot write to Garage: awscli2 sends a checksum header Garage rejects #3

Closed
opened 2026-09-09 06:55:06 +00:00 by claude · 0 comments
Member

publish.sh cannot write to a Garage bucket as shipped. Found by running it against the real thing rather than by reading it — the test suite covers argument construction and a closed port, neither of which reaches this.

What happens

$ aws s3 cp probe.txt s3://fdroid-weblib-dev/probe.txt
upload failed: An error occurred (InvalidRequest) when calling the PutObject
operation: Bad request: invalid checksum algorithm

aws --version → aws-cli/2.34.24.

Not a permissions problem, which is what it looks like at first: it fails identically against a bucket the same credentials are known to be able to write. Reads succeed on every bucket. Only writes fail, and they fail the same way everywhere.

Recent awscli2 sends a checksum algorithm header on PutObject by default. Garage rejects it, so every upload fails — meaning publish.sh would fail on its first real use, after passing its whole test suite.

The fix, measured

export AWS_REQUEST_CHECKSUM_CALCULATION=when_required
export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required

With those set, against the real endpoint:

write to the dev bucket OK
read the object back OK, byte-identical
write to the prod bucket denied — correct, those credentials are read-only there

So the credentials and the bucket policy were right all along; only the client's default was wrong.

What to change

Set both variables inside publish.sh rather than documenting them, and say why in a comment. A caller should not have to know about a client-side default to publish to the object store this tooling exists to publish to, and leaving it to the environment means it works on one machine and not another.

What the tests missed, and how to not miss it again

The suite exercises --dry-run command construction and one real invocation against a closed port. That proves the command is well-formed; it cannot prove the server accepts it. This failure lives exactly in the gap between those.

Worth adding an opt-in live test — skipped unless credentials and a scratch bucket are present, never failing the default offline run — that writes an object, reads it back, and deletes it. That is the same shape weblib-fs uses for its S3 integration tests, and it is the only kind of test that would have caught this.

A skip is not a pass, so the skip count has to be reported and understood rather than glanced at: on a machine without credentials this test skipping is correct, and on CI it skipping silently would recreate exactly this blind spot.

`publish.sh` cannot write to a Garage bucket as shipped. Found by running it against the real thing rather than by reading it — the test suite covers argument construction and a closed port, neither of which reaches this. ## What happens ``` $ aws s3 cp probe.txt s3://fdroid-weblib-dev/probe.txt upload failed: An error occurred (InvalidRequest) when calling the PutObject operation: Bad request: invalid checksum algorithm ``` `aws --version` → `aws-cli/2.34.24`. **Not a permissions problem**, which is what it looks like at first: it fails identically against a bucket the same credentials are known to be able to write. Reads succeed on every bucket. Only writes fail, and they fail the same way everywhere. Recent awscli2 sends a checksum algorithm header on `PutObject` by default. Garage rejects it, so **every** upload fails — meaning `publish.sh` would fail on its first real use, after passing its whole test suite. ## The fix, measured ```bash export AWS_REQUEST_CHECKSUM_CALCULATION=when_required export AWS_RESPONSE_CHECKSUM_VALIDATION=when_required ``` With those set, against the real endpoint: | | | |---|---| | write to the dev bucket | **OK** | | read the object back | **OK**, byte-identical | | write to the prod bucket | denied — correct, those credentials are read-only there | So the credentials and the bucket policy were right all along; only the client's default was wrong. ## What to change Set both variables inside `publish.sh` rather than documenting them, and say why in a comment. A caller should not have to know about a client-side default to publish to the object store this tooling exists to publish to, and leaving it to the environment means it works on one machine and not another. ## What the tests missed, and how to not miss it again The suite exercises `--dry-run` command construction and one real invocation against a closed port. That proves the command is *well-formed*; it cannot prove the server accepts it. This failure lives exactly in the gap between those. Worth adding an **opt-in** live test — skipped unless credentials and a scratch bucket are present, never failing the default offline run — that writes an object, reads it back, and deletes it. That is the same shape weblib-fs uses for its S3 integration tests, and it is the only kind of test that would have caught this. **A skip is not a pass**, so the skip count has to be reported and understood rather than glanced at: on a machine without credentials this test skipping is correct, and on CI it skipping silently would recreate exactly this blind spot.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weblib/fdroid-repo-ci#3