Skip to content

fix(store): S3 upload policies are scoped to a directory and signed through a private _post_policy - #93

Merged
earakely-scale merged 2 commits into
mainfrom
edgararakelyan/s3-post-policy
Oct 7, 2026
Merged

earakely-scale merged 2 commits into
mainfrom
edgararakelyan/s3-post-policy

Conversation

@earakely-scale

@earakely-scale earakely-scale commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

S3ObjectStore.issue_upload_policy built its POST policy by calling the store's public signed_post. It now calls a private _post_policy(url_prefix, expires_in, max_bytes), which holds the existing generate_presigned_post body. This is the arrangement GCSObjectStore already has. signed_post calls _post_policy too.

_post_policy also scopes the policy to a directory, as GCS's does: it appends / to the prefix if it's missing. Before, signed_post("s3://bucket/root") signed starts-with $key root, which also admitted root-evil/…. issue_upload_policy already appended the slash, and it no longer needs to.

  • Every in-tree caller already passes a prefix ending in /: the namespace grant in object_transfer, and the routing store, which forwards. So their policies are unchanged.
  • A caller that passed root meaning a filename prefix now gets root/. Nothing in this repo does that, and the GCS store has never allowed it.

This is the first step toward retiring signed_post in favour of the typed issue_upload_policy. A store layered on S3ObjectStore can now issue upload policies through _post_policy. Later, signed_post can become a deprecated shim over issue_upload_policy without the two calling each other.

Testing

  • New unit tests:
    • An S3ObjectStore whose signed_post raises still issues an upload policy, with the same key template, size condition and grant field names. This fails on main.
    • A signed_post prefix without a trailing slash gets the root/ key template and starts-with condition.
  • Mutant: with the normalization removed from _post_policy, both prefix tests fail.
  • Existing tests: the existing signed_post unit tests pass unchanged. They pin the exact generate_presigned_post call.
  • Not covered: a real POST round trip through the policy has no test on main either. It would need moto's server mode, which isn't a dev dependency today.
  • Suite: tst/unit 6023 passed (13 skipped), protocol 330 passed.
  • Plugin API: no break.

🤖 Generated with Claude Code

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no blocking issue remains.

What we checked:

  • Sibling keys stay outside the upload prefix: No. _post_policy signs the prefix with a trailing slash, so the sibling key does not match.

Summary

S3’s typed and raw upload-policy methods now use one private signing builder, so the typed path no longer depends on signed_post. A bare prefix like captures/one is also treated as the captures/one/ folder.

  • S3 upload policies use one private signing path.
  • A bare S3 prefix now names only that folder.

Reviews (2) · Last reviewed commit: "Scope S3 upload policies to a directory ..." · Reviewed by Greptile

…icy, as GCS does

issue_upload_policy built its policy by calling the public signed_post. It now calls a private
_post_policy, which signed_post also calls, so signed_post behaves as before. A store layered on
S3ObjectStore can then issue upload policies, and later make signed_post a shim over
issue_upload_policy, without the two calling each other.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@earakely-scale
earakely-scale requested a review from a team as a code owner October 7, 2026 05:50
signed_post passed its prefix through as given, so a prefix without a trailing
slash admitted sibling keys (root also matched root-evil/). _post_policy now
appends the slash, as the GCS store's does, and issue_upload_policy no longer
needs to.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@earakely-scale earakely-scale changed the title refactor(store): S3 signs upload policies through a private _post_policy, as GCS does fix(store): S3 upload policies are scoped to a directory and signed through a private _post_policy Oct 7, 2026
@earakely-scale
earakely-scale merged commit 0cb668c into main Oct 7, 2026
15 checks passed
@earakely-scale
earakely-scale deleted the edgararakelyan/s3-post-policy branch October 7, 2026 06:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant