mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-20 08:03:28 +00:00
* 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>
69 lines
2.4 KiB
Python
69 lines
2.4 KiB
Python
"""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"]
|