Repository navigation
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files
... and 2 files with indirect coverage changes @@ Coverage Diff @@
## development/9.3 #6332 +/- ##
================================================
Coverage 85.35% 85.36%
================================================
Files 207 207
Lines 13473 13480 +7
================================================
+ Hits 11500 11507 +7
Misses 1973 1973
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
leif-scality
left a comment
There was a problem hiding this comment.
A Deny on s3:VersionId now blocks copying that version, in bucket and IAM policies, and a repeated versionId in the copy source is rejected. I found no regressions. The new functional test fails without the fix and passes with it, and the stack's functional tests pass 20/20 against Vault 7.89.0. The other-spelling bypass stays in CLDSRV-1038, as the description says.
57d9720 to
5c5a75b
Compare
5c5a75b to
7a9b5bc
Compare
7a9b5bc to
647a09f
Compare
…sent - Use the copy source version ID as sent by the client, for both the bucket policy and the authorization request, instead of the internal version ID - Return InvalidArgument when the copy source versionId is repeated, so an array never reaches the bucket policy conditions
647a09f to
dd591e5
Compare
Hello tcarmet,My role is to assist you with the merge of this Available options
Available commands
Status report is not available. |
Request integration branchesWaiting for integration branch creation to be requested by the user. To request integration branches, please comment on this pull request with the following command: Alternatively, the |
| const copySourceVersionId = sourceQuery?.versionId; | ||
|
|
||
| return { sourceBucket, sourceObject, sourceVersionId }; | ||
| return { sourceBucket, sourceObject, sourceVersionId, copySourceVersionId }; |
There was a problem hiding this comment.
I was a bit bothered by the fact that we still return the decoded version ID where only the encoded one is really useful. I asked Claude if we could get rid of it, and it seems that it's also more in line with the other API calls, so if you feel like it, I'd suggest to simply return the encoded version ID as sourceVersionId for consistency and simplicity, and defer the actual validation of the version ID to the lower level.
Here's the full response from Claude 🤖 , in case it helps implementing the changes:
Code changes
parseCopySourcewould return only{ sourceBucket, sourceObject, sourceVersionId, parsingError }, withsourceVersionIdnow the raw string. Keep the repeated-versionId(array) check there: it has to run before authorization, because that's what keeps an array out of the policy conditions.- api.js passes the raw ID to both
prepareRequestContextsand the handler. Therequest.copySourceVersionId = ...assignment goes away. objectCopyandobjectPutCopyPartdecode at the top withdecodeVIDand return theInvalidArgumenterror through the callback, askeyLengthErroralready does inobjectCopy. They use the raw ID forpolicyTarget.versionIdand the decoded one forvalGetParams.versionId, theNoSuchVersionand delete-marker checks, andx-amz-copy-source-version-id. That header is currently re-encoded from the decoded ID (objectCopy.js:798), so it could take the raw value directly. Either way, normalize''toundefinedthe waydecodeVersionIddoes.
Behavior changes
- Errors come in a different order. Today, a malformed copy source version ID returns
InvalidArgumentfrom api.js before any authorization. After the change, authorization runs first:- A requester without permission gets
AccessDeniedinstead ofInvalidArgument.GetObjectwith a malformed?versionId=already behaves this way, and checking auth first is the safer order. - An authorized requester still gets
InvalidArgument, now from the handler. The existing functional test at tests/functional/aws-node-sdk/test/versioning/objectPutCopyPart.js:124 uses the bucket owner, so it should still pass. Verify this by running it.
- A requester without permission gets
- Vault would see a malformed ID. The
objectGetVersionrequest context could carry a garbage version ID. The context treats the value as opaque, and other routes already send unvalidated values to Vault, so this is harmless. versionId=(empty string) behaves as it does today. Authorization checks truthiness, so it staysobjectGet, and the handler's decode givesundefinedas before.'null'is unchanged.decodeVID('null')returns'null', so raw and decoded are the same.- Metrics and logging change slightly. The early return in api.js (
process.nextTick(callback, parsingError)) skips the handler. The error would now go through the handler's normal error path. That probably doesn't matter, but malformed version IDs may start showing up in per-API error metrics where they didn't before.
Tests to update
- tests/unit/api/objectCopy.js calls the handler with decoded IDs at lines 979, 989 and 1120 (
versioning.VersionID.decode(...)). Those calls should pass the encoded ID. The CLDSRV-1021 tests also get simpler, since they no longer need to keeprequest.copySourceVersionIdand the decoded argument in sync. - The calls passing
undefinedor'null', including the ones in tests/multipleBackend/, need no change. - Add a unit test for a malformed source version ID reaching the handler, since the handler now owns that check.
Overall it's a modest simplification. Copy becomes structurally the same as the other routes: authorization sees the raw value, and the handler decodes where it needs the internal ID. Before doing it, decide whether you're fine with the AccessDenied-before-InvalidArgument change. I'd keep it, since it matches GetObject.
A policy condition on
s3:VersionIdwas compared with the copy source's internal version ID instead of the version ID the client sent. So a Deny on a specific version blocked a GetObject of that version but not a copy of it, in both bucket and identity policies. The copy source's version ID is now evaluated as sent, like for a direct GetObject. A repeatedversionIdin the copy source is rejected, so it never reaches policy evaluation as a list. Version IDs that decode to the same version under different spellings are still not normalized; that's tracked in CLDSRV-1038 and affects GetObject the same way.Stacked on #6324.