| 1 | // Copyright (c) 2019-2026 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | module s3 |
| 5 | |
| 6 | fn test_credentials_validate_rejects_crlf_injection() { |
| 7 | c := Credentials{ |
| 8 | access_key_id: 'KEY' |
| 9 | secret_access_key: 'secret\r\nInjected: header' |
| 10 | } |
| 11 | if _ := c.validate() { |
| 12 | assert false, 'should have rejected CRLF' |
| 13 | } |
| 14 | } |
| 15 | |
| 16 | fn test_credentials_from_env_returns_empty_when_unset() { |
| 17 | // Cannot safely set env vars from a test without polluting the parent |
| 18 | // shell, so just verify the call returns a value of the right shape. |
| 19 | c := Credentials.from_env() |
| 20 | _ = c |
| 21 | } |
| 22 | |
| 23 | fn test_endpoint_scheme_is_derived_when_explicit() { |
| 24 | c1 := Credentials{ |
| 25 | access_key_id: 'K' |
| 26 | secret_access_key: 'S' |
| 27 | endpoint: 'https://s3.example.com' |
| 28 | } |
| 29 | assert c1.scheme() == 'https' |
| 30 | c2 := Credentials{ |
| 31 | access_key_id: 'K' |
| 32 | secret_access_key: 'S' |
| 33 | endpoint: 'http://localhost:9000' |
| 34 | } |
| 35 | assert c2.scheme() == 'http', 'http:// endpoint must yield http even when insecure_http is unset' |
| 36 | c3 := Credentials{ |
| 37 | access_key_id: 'K' |
| 38 | secret_access_key: 'S' |
| 39 | endpoint: 'http://localhost:9000' |
| 40 | insecure_http: true |
| 41 | } |
| 42 | assert c3.scheme() == 'http' |
| 43 | // Bare host: defaults to https unless insecure_http is set. |
| 44 | c4 := Credentials{ |
| 45 | access_key_id: 'K' |
| 46 | secret_access_key: 'S' |
| 47 | endpoint: 'localhost:9000' |
| 48 | } |
| 49 | assert c4.scheme() == 'https' |
| 50 | c5 := Credentials{ |
| 51 | access_key_id: 'K' |
| 52 | secret_access_key: 'S' |
| 53 | endpoint: 'localhost:9000' |
| 54 | insecure_http: true |
| 55 | } |
| 56 | assert c5.scheme() == 'http' |
| 57 | } |
| 58 | |
| 59 | fn test_endpoint_host_only_strips_scheme_and_path() { |
| 60 | c := Credentials{ |
| 61 | access_key_id: 'K' |
| 62 | secret_access_key: 'S' |
| 63 | endpoint: 'https://proxy.example.com:8443/s3' |
| 64 | } |
| 65 | assert c.host_only() == 'proxy.example.com:8443' |
| 66 | assert c.extra_path() == '/s3' |
| 67 | } |
| 68 | |
| 69 | fn test_guess_region_paths() { |
| 70 | assert guess_region('') == 'us-east-1' |
| 71 | assert guess_region('https://s3.eu-west-3.amazonaws.com') == 'eu-west-3' |
| 72 | assert guess_region('https://my-acct.r2.cloudflarestorage.com') == 'auto' |
| 73 | assert guess_region('https://s3.example.com') == 'auto' |
| 74 | // AWS global endpoints sign with us-east-1, not 'auto'. |
| 75 | assert guess_region('https://s3.amazonaws.com') == 'us-east-1' |
| 76 | assert guess_region('s3.amazonaws.com') == 'us-east-1' |
| 77 | assert guess_region('https://s3-external-1.amazonaws.com') == 'us-east-1' |
| 78 | } |
| 79 | |
| 80 | fn test_credentials_merge_overrides_only_non_empty() { |
| 81 | base := Credentials{ |
| 82 | access_key_id: 'BASE' |
| 83 | secret_access_key: 'basesecret' |
| 84 | region: 'eu-west-1' |
| 85 | bucket: 'b1' |
| 86 | } |
| 87 | other := Credentials{ |
| 88 | bucket: 'b2' |
| 89 | } |
| 90 | got := base.merge(other) |
| 91 | assert got.access_key_id == 'BASE' |
| 92 | assert got.region == 'eu-west-1' |
| 93 | assert got.bucket == 'b2' |
| 94 | } |
| 95 | |
| 96 | fn test_resolved_region_prefers_explicit() { |
| 97 | c := Credentials{ |
| 98 | access_key_id: 'K' |
| 99 | secret_access_key: 'S' |
| 100 | region: 'eu-central-1' |
| 101 | endpoint: 'https://s3.us-west-2.amazonaws.com' |
| 102 | } |
| 103 | assert c.resolved_region() == 'eu-central-1' |
| 104 | } |
| 105 | |