mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-20 00:03:21 +00:00
feat: route python S3 client settings through the S3 proxy (#11819)
* feat: route the python SDK's S3 client settings through the S3 proxy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: drop the boto3 config key and expose the proxied bucket to polars Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: update ee-repo-ref Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: proxy S3 settings only for server-signed tokens and keep tls verify Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: update ee-repo-ref Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * chore: update ee-repo-ref to cd3395013d8484cd3917cdb6ee7837b6ac91e577 This commit updates the EE repository reference after PR #889 was merged in windmill-ee-private. Previous ee-repo-ref: e90873bba9dde1e899741d111137f94dde2e5ff8 New ee-repo-ref: cd3395013d8484cd3917cdb6ee7837b6ac91e577 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
windmill-internal-app[bot]
parent
e7088e7f47
commit
de340eed6f
@@ -0,0 +1,68 @@
|
||||
"""The default S3 connection settings go through the S3 proxy only when the server can verify
|
||||
the token's SigV4 signature and serves the bucket-addressed routes; otherwise they keep the
|
||||
storage's own credentials."""
|
||||
|
||||
import pytest
|
||||
|
||||
from wmill.client import Windmill
|
||||
|
||||
JOB_TOKEN = "jwt_header.payload.signature"
|
||||
|
||||
|
||||
class _Response:
|
||||
def __init__(self, status_code, body):
|
||||
self.status_code = status_code
|
||||
self._body = body
|
||||
|
||||
def json(self):
|
||||
return self._body
|
||||
|
||||
|
||||
def _client(token, status_code=200, body=None):
|
||||
client = Windmill(base_url="https://wm.example", token=token, workspace="ws")
|
||||
calls = []
|
||||
|
||||
def get(endpoint, raise_for_status=True, **kwargs):
|
||||
calls.append(endpoint)
|
||||
return _Response(status_code, body if body is not None else {"bucket": "data"})
|
||||
|
||||
def post(endpoint, raise_for_status=True, **kwargs):
|
||||
calls.append(endpoint)
|
||||
resource = {"endPoint": "s3.example", "useSSL": True, "region": "eu-west-1"}
|
||||
return _Response(200, {**resource, "accessKey": "raw", "secretKey": "raw-secret"})
|
||||
|
||||
client.get = get
|
||||
client.post = post
|
||||
return client, calls
|
||||
|
||||
|
||||
def test_job_token_goes_through_the_proxy():
|
||||
client, _ = _client(JOB_TOKEN)
|
||||
settings = client.get_boto3_connection_settings()
|
||||
assert settings["endpoint_url"] == "https://wm.example/api/w/ws/s3_proxy/_wm_bucket_/_default_"
|
||||
assert settings["aws_access_key_id"] == "jwt_header.payload"
|
||||
assert settings["aws_secret_access_key"] == "signature"
|
||||
assert client.get_polars_connection_settings()["s3_bucket"] == "data"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"token,status_code,body",
|
||||
[
|
||||
("personaltokenwithoutdots", 200, None),
|
||||
("jwt_ext_header.payload.signature", 200, None),
|
||||
(JOB_TOKEN, 404, None),
|
||||
(JOB_TOKEN, 200, {"bucket": None}),
|
||||
],
|
||||
ids=["personal token", "external jwt", "older server", "non-S3 storage"],
|
||||
)
|
||||
def test_falls_back_to_the_storage_credentials(token, status_code, body):
|
||||
client, calls = _client(token, status_code, body)
|
||||
settings = client.get_boto3_connection_settings()
|
||||
assert settings["aws_access_key_id"] == "raw"
|
||||
assert calls[-1].endswith("/job_helpers/v2/s3_resource_info")
|
||||
|
||||
|
||||
def test_explicit_resource_path_never_asks_for_the_proxy():
|
||||
client, calls = _client(JOB_TOKEN)
|
||||
client.get_boto3_connection_settings("u/admin/s3")
|
||||
assert calls == ["/w/ws/job_helpers/v2/s3_resource_info"]
|
||||
Reference in New Issue
Block a user