Skip to content

Commit ffcf472

Browse files
authored
Merge branch 'main' into investigate-pubsub-conformance-test
2 parents 400af65 + e741a87 commit ffcf472

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+643
-392
lines changed

iam/iam-aws/src/main/java/com/salesforce/multicloudj/iam/aws/AwsIam.java

Lines changed: 35 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@
1212
import com.salesforce.multicloudj.common.provider.Provider;
1313
import com.salesforce.multicloudj.iam.driver.AbstractIam;
1414
import com.salesforce.multicloudj.iam.model.AttachInlinePolicyRequest;
15+
import com.salesforce.multicloudj.iam.model.CreateIdentityRequest;
1516
import com.salesforce.multicloudj.iam.model.CreateOptions;
17+
import com.salesforce.multicloudj.iam.model.DeleteIdentityRequest;
1618
import com.salesforce.multicloudj.iam.model.GetAttachedPoliciesRequest;
19+
import com.salesforce.multicloudj.iam.model.GetIdentityRequest;
1720
import com.salesforce.multicloudj.iam.model.GetInlinePolicyDetailsRequest;
21+
import com.salesforce.multicloudj.iam.model.RemovePolicyRequest;
1822
import com.salesforce.multicloudj.iam.model.PolicyDocument;
1923
import com.salesforce.multicloudj.iam.model.Statement;
2024
import com.salesforce.multicloudj.iam.model.TrustConfiguration;
@@ -155,25 +159,20 @@ public void close() throws Exception {
155159
/**
156160
* Create IAM Role with optional Trust Configuration and Create Options.
157161
*
158-
* @param identityName the IAM role name (e.g., "MyApplicationRole").
159-
* @param description optional description for the role.
160-
* @param tenantId the AWS Account ID.
161-
* @param region the AWS region for the IAM client.
162-
* @param trustConfig optional trust configuration.
163-
* @param options optional creation options for the role.
162+
* @param request the request containing identity name, description, tenant ID, region, trust config, and options.
164163
* @return the IAM role ARN.
165164
*/
166165
@Override
167-
protected String doCreateIdentity(String identityName, String description, String tenantId, String region, Optional<TrustConfiguration> trustConfig, Optional<CreateOptions> options) {
168-
String assumeRolePolicyDocument = buildAssumeRolePolicyDocument(tenantId, trustConfig);
166+
protected String doCreateIdentity(CreateIdentityRequest request) {
167+
String assumeRolePolicyDocument = buildAssumeRolePolicyDocument(request.getTenantId(), request.getTrustConfig());
169168

170169
CreateRoleRequest.Builder requestBuilder = CreateRoleRequest.builder()
171-
.roleName(identityName)
170+
.roleName(request.getIdentityName())
172171
.assumeRolePolicyDocument(assumeRolePolicyDocument)
173-
.description(StringUtils.defaultString(description));
172+
.description(StringUtils.defaultString(request.getDescription()));
174173

175-
if (options.isPresent()) {
176-
CreateOptions opts = options.get();
174+
if (request.getOptions().isPresent()) {
175+
CreateOptions opts = request.getOptions().get();
177176
if (StringUtils.isNotBlank(opts.getPath())) {
178177
requestBuilder.path(opts.getPath());
179178
}
@@ -190,11 +189,11 @@ protected String doCreateIdentity(String identityName, String description, Strin
190189
Role role = response.role();
191190
return role != null ? role.arn() : null;
192191
} catch (EntityAlreadyExistsException e) {
193-
GetRoleResponse getRoleResponse = this.iamClient.getRole(GetRoleRequest.builder().roleName(identityName).build());
192+
GetRoleResponse getRoleResponse = this.iamClient.getRole(GetRoleRequest.builder().roleName(request.getIdentityName()).build());
194193
Role existingRole = getRoleResponse.role();
195194

196195
if (existingRole != null) {
197-
updateRoleIfNeeded(existingRole, description, assumeRolePolicyDocument, options);
196+
updateRoleIfNeeded(existingRole, request.getDescription(), assumeRolePolicyDocument, request.getOptions());
198197
}
199198

200199
return existingRole != null ? existingRole.arn() : null;
@@ -313,10 +312,10 @@ private String buildAssumeRolePolicyDocument(String tenantId, Optional<TrustConf
313312

314313
Map<String, Object> principal = new LinkedHashMap<>();
315314
if (!awsPrincipals.isEmpty()) {
316-
principal.put("AWS", awsPrincipals.size() == 1 ? awsPrincipals.get(0) : awsPrincipals);
315+
principal.put("AWS", awsPrincipals);
317316
}
318317
if (!servicePrincipals.isEmpty()) {
319-
principal.put("Service", servicePrincipals.size() == 1 ? servicePrincipals.get(0) : servicePrincipals);
318+
principal.put("Service", servicePrincipals);
320319
}
321320
stmt.put("Principal", principal);
322321

@@ -334,9 +333,6 @@ private String buildAssumeRolePolicyDocument(String tenantId, Optional<TrustConf
334333

335334
@Override
336335
protected void doAttachInlinePolicy(AttachInlinePolicyRequest request) {
337-
if (StringUtils.isBlank(request.getIdentityName())) {
338-
throw new InvalidArgumentException("identityName is required for AWS IAM");
339-
}
340336
if (StringUtils.isBlank(request.getPolicyDocument().getName())) {
341337
throw new InvalidArgumentException("policy name is required for AWS IAM");
342338
}
@@ -356,7 +352,7 @@ protected void doAttachInlinePolicy(AttachInlinePolicyRequest request) {
356352
private static String buildInlinePolicyDocumentJson(PolicyDocument policyDocument) {
357353
String version = policyDocument.getVersion();
358354
if (StringUtils.isBlank(version)) {
359-
throw new InvalidArgumentException("Version is required for AWS inline policy document");
355+
version = POLICY_VERSION;
360356
}
361357
Map<String, Object> doc = new LinkedHashMap<>();
362358
doc.put("Version", version);
@@ -368,21 +364,19 @@ private static String buildInlinePolicyDocumentJson(PolicyDocument policyDocumen
368364

369365
List<String> actions = stmt.getActions();
370366
if (actions != null && !actions.isEmpty()) {
371-
awsStmt.put("Action", actions.size() == 1 ? actions.get(0) : actions);
367+
awsStmt.put("Action", actions);
372368
}
373369
if (StringUtils.isNotBlank(stmt.getSid())) {
374370
awsStmt.put("Sid", stmt.getSid());
375371
}
376372
if (stmt.getResources() != null && !stmt.getResources().isEmpty()) {
377-
awsStmt.put("Resource", stmt.getResources().size() == 1 ? stmt.getResources().get(0) : stmt.getResources());
378-
} else {
379-
awsStmt.put("Resource", "*");
373+
awsStmt.put("Resource", stmt.getResources());
380374
}
381375
if (stmt.getConditions() != null && !stmt.getConditions().isEmpty()) {
382376
awsStmt.put("Condition", stmt.getConditions());
383377
}
384378
if (stmt.getPrincipals() != null && !stmt.getPrincipals().isEmpty()) {
385-
awsStmt.put("Principal", stmt.getPrincipals().size() == 1 ? stmt.getPrincipals().get(0) : stmt.getPrincipals());
379+
awsStmt.put("Principal", stmt.getPrincipals());
386380
}
387381

388382
awsStatements.add(awsStmt);
@@ -439,51 +433,44 @@ protected List<String> doGetAttachedPolicies(GetAttachedPoliciesRequest request)
439433
/**
440434
* Removes an inline policy from an IAM role.
441435
*
442-
* @param identityName the IAM role name.
443-
* @param policyName the name of the inline policy to remove.
444-
* @param tenantId the AWS Account ID.
445-
* @param region the AWS region for the IAM client.
436+
* @param request the request containing identity name, policy name, tenant ID, and region.
446437
*/
447438
@Override
448-
protected void doRemovePolicy(String identityName, String policyName, String tenantId, String region) {
449-
DeleteRolePolicyRequest request = DeleteRolePolicyRequest.builder()
450-
.roleName(identityName)
451-
.policyName(policyName)
439+
protected void doRemovePolicy(RemovePolicyRequest request) {
440+
DeleteRolePolicyRequest deleteRequest = DeleteRolePolicyRequest.builder()
441+
.roleName(request.getIdentityName())
442+
.policyName(request.getPolicyName())
452443
.build();
453444

454-
this.iamClient.deleteRolePolicy(request);
445+
this.iamClient.deleteRolePolicy(deleteRequest);
455446
}
456447

457448

458449
/**
459450
* Delete IAM Role.
460451
*
461-
* @param identityName the IAM role name.
462-
* @param tenantId the AWS Account ID.
463-
* @param region the AWS region for the IAM client.
452+
* @param request the request containing identity name, tenant ID, and region.
464453
*/
465454
@Override
466-
protected void doDeleteIdentity(String identityName, String tenantId, String region) {
467-
DeleteRoleRequest request = DeleteRoleRequest.builder()
468-
.roleName(identityName)
455+
protected void doDeleteIdentity(DeleteIdentityRequest request) {
456+
DeleteRoleRequest deleteRoleRequest = DeleteRoleRequest.builder()
457+
.roleName(request.getIdentityName())
469458
.build();
470-
this.iamClient.deleteRole(request);
459+
this.iamClient.deleteRole(deleteRoleRequest);
471460
}
472461

473462
/**
474463
* Get IAM Role.
475464
*
476-
* @param identityName the IAM role name.
477-
* @param tenantId the AWS Account ID.
478-
* @param region the AWS region for the IAM client.
465+
* @param request the request containing identity name, tenant ID, and region.
479466
* @return the IAM role ARN.
480467
*/
481468
@Override
482-
protected String doGetIdentity(String identityName, String tenantId, String region) {
483-
GetRoleRequest request = GetRoleRequest.builder()
484-
.roleName(identityName)
469+
protected String doGetIdentity(GetIdentityRequest request) {
470+
GetRoleRequest getRoleRequest = GetRoleRequest.builder()
471+
.roleName(request.getIdentityName())
485472
.build();
486-
GetRoleResponse response = this.iamClient.getRole(request);
473+
GetRoleResponse response = this.iamClient.getRole(getRoleRequest);
487474
Role role = response.role();
488475
return role != null ? role.arn() : null;
489476
}

iam/iam-aws/src/test/java/com/salesforce/multicloudj/iam/aws/AwsIamIT.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,14 @@ public String getTestRoleName() {
127127
return "testSa"; // IAM role name for attach/getInlinePolicyDetails.
128128
}
129129

130+
/** Dummy S3 resource ARN for the test inline policy (valid format; used in record/replay IT). */
131+
private static final String TEST_POLICY_RESOURCE = "arn:aws:s3:::multicloudj-iam-it-test-bucket/*";
132+
133+
@Override
134+
public String getTestPolicyResource() {
135+
return TEST_POLICY_RESOURCE;
136+
}
137+
130138
@Override
131139
public void close() {
132140
if (client != null) {

iam/iam-aws/src/test/java/com/salesforce/multicloudj/iam/aws/AwsIamTest.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ void testCreateIdentityWithServicePrincipalInTrustConfig() throws Exception {
138138

139139
JsonNode service = doc.at("/Statement/0/Principal/Service");
140140
assertFalse(service.isMissingNode(), "Service principal should not be missing");
141-
assertEquals("ec2.amazonaws.com", service.asText());
141+
assertEquals("ec2.amazonaws.com", service.isArray() ? service.get(0).asText() : service.asText());
142142
}
143143

144144
@Test
@@ -173,8 +173,9 @@ void testCreateIdentityWithoutTrustConfigDefaultsToSameAccountRoot() throws Exce
173173
assertFalse(stmt.isMissingNode(), "Statement should not be missing");
174174
assertEquals("Allow", stmt.at("/Effect").asText());
175175
assertEquals("sts:AssumeRole", stmt.at("/Action").asText());
176+
JsonNode awsPrincipal = stmt.at("/Principal/AWS");
176177
assertEquals("arn:aws:iam::" + TEST_TENANT_ID + ":root",
177-
stmt.at("/Principal/AWS").asText());
178+
awsPrincipal.isArray() ? awsPrincipal.get(0).asText() : awsPrincipal.asText());
178179
}
179180

180181
@Test
@@ -457,7 +458,7 @@ void testCreateIdentityAlreadyExistsUpdatesTrustPolicyWhenDifferent() throws Exc
457458

458459
JsonNode updatedPolicy = OBJECT_MAPPER.readTree(updatePolicyCaptor.getValue().policyDocument());
459460
JsonNode principal = updatedPolicy.at("/Statement/0/Principal/AWS");
460-
assertEquals("arn:aws:iam::999999999999:root", principal.asText());
461+
assertEquals("arn:aws:iam::999999999999:root", principal.isArray() ? principal.get(0).asText() : principal.asText());
461462
}
462463

463464
@Test
@@ -549,8 +550,8 @@ void testCreateIdentityAlreadyExistsUpdatesMultipleAttributesWhenDifferent() thr
549550

550551
private String buildDefaultAssumeRolePolicy() {
551552
return "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\"," +
552-
"\"Action\":\"sts:AssumeRole\",\"Principal\":{\"AWS\":\"arn:aws:iam::" +
553-
TEST_TENANT_ID + ":root\"}}]}";
553+
"\"Action\":\"sts:AssumeRole\",\"Principal\":{\"AWS\":[\"arn:aws:iam::" +
554+
TEST_TENANT_ID + ":root\"]}}]}";
554555
}
555556

556557
@Test

iam/iam-aws/src/test/resources/mappings/post-a7redz3j0q.json renamed to iam/iam-aws/src/test/resources/mappings/post-3uk1re9u8b.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
{
2-
"id" : "a4a68dd6-d272-41dc-b5d0-e9ce8285fe5d",
2+
"id" : "444eb433-71e4-442e-8eca-93cbb80210ad",
33
"name" : "",
44
"request" : {
55
"url" : "/",
66
"method" : "POST",
77
"bodyPatterns" : [ {
8-
"equalTo" : "Action=PutRolePolicy&Version=2010-05-08&RoleName=testSa&PolicyName=TestPolicy&PolicyDocument=%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%22iam%3AGetRole%22%2C%22Resource%22%3A%22*%22%7D%5D%7D",
8+
"equalTo" : "Action=PutRolePolicy&Version=2010-05-08&RoleName=testSa&PolicyName=TestPolicy&PolicyDocument=%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%5B%22s3%3AGetObject%22%2C%22s3%3APutObject%22%5D%2C%22Resource%22%3A%5B%22arn%3Aaws%3As3%3A%3A%3Amulticloudj-iam-it-test-bucket%2F*%22%5D%7D%5D%7D",
99
"caseInsensitive" : false
1010
} ]
1111
},
1212
"response" : {
1313
"status" : 200,
14-
"body" : "<PutRolePolicyResponse xmlns=\"https://iam.amazonaws.com/doc/2010-05-08/\">\n <ResponseMetadata>\n <RequestId>04339358-c312-437d-97f9-a42a385438db</RequestId>\n </ResponseMetadata>\n</PutRolePolicyResponse>\n",
14+
"body" : "<PutRolePolicyResponse xmlns=\"https://iam.amazonaws.com/doc/2010-05-08/\">\n <ResponseMetadata>\n <RequestId>58100288-efa5-4fc6-a2df-78c9216d7e23</RequestId>\n </ResponseMetadata>\n</PutRolePolicyResponse>\n",
1515
"headers" : {
16-
"x-amzn-RequestId" : "04339358-c312-437d-97f9-a42a385438db",
17-
"Date" : "Mon, 02 Feb 2026 20:44:18 GMT",
16+
"x-amzn-RequestId" : "58100288-efa5-4fc6-a2df-78c9216d7e23",
17+
"Date" : "Thu, 26 Feb 2026 22:33:58 GMT",
1818
"Content-Type" : "text/xml"
1919
}
2020
},
21-
"uuid" : "a4a68dd6-d272-41dc-b5d0-e9ce8285fe5d",
21+
"uuid" : "444eb433-71e4-442e-8eca-93cbb80210ad",
2222
"persistent" : true,
23-
"insertionIndex" : 33
23+
"insertionIndex" : 31
2424
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"id" : "0a380abe-17a2-4d3c-a911-4ff5cd11c0ac",
3+
"name" : "",
4+
"request" : {
5+
"url" : "/",
6+
"method" : "POST",
7+
"bodyPatterns" : [ {
8+
"equalTo" : "Action=CreateRole&Version=2010-05-08&RoleName=MultiCloudJTestRoleOptions&AssumeRolePolicyDocument=%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%22sts%3AAssumeRole%22%2C%22Principal%22%3A%7B%22AWS%22%3A%5B%22arn%3Aaws%3Aiam%3A%3A654654370895%3Aroot%22%5D%7D%7D%5D%7D&Description=Test+identity+with+options",
9+
"caseInsensitive" : false
10+
} ]
11+
},
12+
"response" : {
13+
"status" : 200,
14+
"body" : "<CreateRoleResponse xmlns=\"https://iam.amazonaws.com/doc/2010-05-08/\">\n <CreateRoleResult>\n <Role>\n <Path>/</Path>\n <AssumeRolePolicyDocument>%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%22sts%3AAssumeRole%22%2C%22Principal%22%3A%7B%22AWS%22%3A%5B%22arn%3Aaws%3Aiam%3A%3A654654370895%3Aroot%22%5D%7D%7D%5D%7D</AssumeRolePolicyDocument>\n <RoleId>AROAZQ3DQ6RH33DRLNZ2I</RoleId>\n <RoleName>MultiCloudJTestRoleOptions</RoleName>\n <Arn>arn:aws:iam::654654370895:role/MultiCloudJTestRoleOptions</Arn>\n <CreateDate>2026-02-26T22:33:39Z</CreateDate>\n </Role>\n </CreateRoleResult>\n <ResponseMetadata>\n <RequestId>d91d3643-48c1-4169-867c-2a788b3548a8</RequestId>\n </ResponseMetadata>\n</CreateRoleResponse>\n",
15+
"headers" : {
16+
"x-amzn-RequestId" : "d91d3643-48c1-4169-867c-2a788b3548a8",
17+
"Date" : "Thu, 26 Feb 2026 22:33:39 GMT",
18+
"Content-Type" : "text/xml"
19+
}
20+
},
21+
"uuid" : "0a380abe-17a2-4d3c-a911-4ff5cd11c0ac",
22+
"persistent" : true,
23+
"insertionIndex" : 14
24+
}

iam/iam-aws/src/test/resources/mappings/post-hpvfnilooi.json renamed to iam/iam-aws/src/test/resources/mappings/post-bdn3i0sqqv.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"id" : "6ecad65a-167f-4030-8e43-ea2acf576811",
2+
"id" : "bb996a64-e3ba-42db-866d-7a0bf4938d1e",
33
"name" : "",
44
"request" : {
55
"url" : "/",
@@ -11,14 +11,14 @@
1111
},
1212
"response" : {
1313
"status" : 200,
14-
"body" : "<GetRoleResponse xmlns=\"https://iam.amazonaws.com/doc/2010-05-08/\">\n <GetRoleResult>\n <Role>\n <Path>/</Path>\n <AssumeRolePolicyDocument>%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22AWS%22%3A%22arn%3Aaws%3Aiam%3A%3A654654370895%3Aroot%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D</AssumeRolePolicyDocument>\n <MaxSessionDuration>3600</MaxSessionDuration>\n <RoleId>AROAZQ3DQ6RH4Y2AB3YKQ</RoleId>\n <RoleLastUsed/>\n <RoleName>MultiCloudJTestRoleLifeCycle</RoleName>\n <Description>Test identity for lifecycle test</Description>\n <Arn>arn:aws:iam::654654370895:role/MultiCloudJTestRoleLifeCycle</Arn>\n <CreateDate>2026-01-06T09:25:34Z</CreateDate>\n </Role>\n </GetRoleResult>\n <ResponseMetadata>\n <RequestId>5b842721-6b57-43ca-aa63-39eadc66e18d</RequestId>\n </ResponseMetadata>\n</GetRoleResponse>\n",
14+
"body" : "<GetRoleResponse xmlns=\"https://iam.amazonaws.com/doc/2010-05-08/\">\n <GetRoleResult>\n <Role>\n <Path>/</Path>\n <AssumeRolePolicyDocument>%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Principal%22%3A%7B%22AWS%22%3A%22arn%3Aaws%3Aiam%3A%3A654654370895%3Aroot%22%7D%2C%22Action%22%3A%22sts%3AAssumeRole%22%7D%5D%7D</AssumeRolePolicyDocument>\n <MaxSessionDuration>3600</MaxSessionDuration>\n <RoleId>AROAZQ3DQ6RHW3D5YSFCM</RoleId>\n <RoleLastUsed/>\n <RoleName>MultiCloudJTestRoleLifeCycle</RoleName>\n <Description>Test identity for lifecycle test</Description>\n <Arn>arn:aws:iam::654654370895:role/MultiCloudJTestRoleLifeCycle</Arn>\n <CreateDate>2026-02-26T22:33:33Z</CreateDate>\n </Role>\n </GetRoleResult>\n <ResponseMetadata>\n <RequestId>0e978bb1-e425-4f22-837b-b05eeb6da0db</RequestId>\n </ResponseMetadata>\n</GetRoleResponse>\n",
1515
"headers" : {
16-
"x-amzn-RequestId" : "5b842721-6b57-43ca-aa63-39eadc66e18d",
17-
"Date" : "Tue, 06 Jan 2026 09:25:36 GMT",
16+
"x-amzn-RequestId" : "0e978bb1-e425-4f22-837b-b05eeb6da0db",
17+
"Date" : "Thu, 26 Feb 2026 22:33:36 GMT",
1818
"Content-Type" : "text/xml"
1919
}
2020
},
21-
"uuid" : "6ecad65a-167f-4030-8e43-ea2acf576811",
21+
"uuid" : "bb996a64-e3ba-42db-866d-7a0bf4938d1e",
2222
"persistent" : true,
23-
"insertionIndex" : 6
23+
"insertionIndex" : 8
2424
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"id" : "40a6ca24-a9bb-448b-92e9-9561c250a2be",
3+
"name" : "",
4+
"request" : {
5+
"url" : "/",
6+
"method" : "POST",
7+
"bodyPatterns" : [ {
8+
"equalTo" : "Action=GetRolePolicy&Version=2010-05-08&RoleName=testSa&PolicyName=TestPolicy",
9+
"caseInsensitive" : false
10+
} ]
11+
},
12+
"response" : {
13+
"status" : 200,
14+
"body" : "<GetRolePolicyResponse xmlns=\"https://iam.amazonaws.com/doc/2010-05-08/\">\n <GetRolePolicyResult>\n <PolicyDocument>%7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22Effect%22%3A%22Allow%22%2C%22Action%22%3A%5B%22s3%3AGetObject%22%2C%22s3%3APutObject%22%5D%2C%22Resource%22%3A%5B%22arn%3Aaws%3As3%3A%3A%3Amulticloudj-iam-it-test-bucket%2F%2A%22%5D%7D%5D%7D</PolicyDocument>\n <PolicyName>TestPolicy</PolicyName>\n <RoleName>testSa</RoleName>\n </GetRolePolicyResult>\n <ResponseMetadata>\n <RequestId>e3784cee-baad-4ae1-a534-6d6b3bd10fc2</RequestId>\n </ResponseMetadata>\n</GetRolePolicyResponse>\n",
15+
"headers" : {
16+
"x-amzn-RequestId" : "e3784cee-baad-4ae1-a534-6d6b3bd10fc2",
17+
"Date" : "Thu, 26 Feb 2026 22:33:28 GMT",
18+
"Content-Type" : "text/xml"
19+
}
20+
},
21+
"uuid" : "40a6ca24-a9bb-448b-92e9-9561c250a2be",
22+
"persistent" : true,
23+
"insertionIndex" : 1
24+
}

0 commit comments

Comments
 (0)