2026-05-11 22:37:05 -07:00
// Copyright IBM Corp. 2021, 2026
2023-01-03 22:03:42 +00:00
// SPDX-License-Identifier: MPL-2.0
2023-03-20 11:02:17 -07:00
package testing
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
// This file contains the TestHostPlugin orchestrator. It deploys the Terraform
// workspace, collects outputs, and calls the per-credential-type helper
// functions defined in e2e_host_static_test.go and e2e_host_assumerole_test.go.
2021-10-06 12:47:05 -07:00
import (
"context"
"os"
"testing"
2026-10-12 10:27:59 -07:00
"repo.anhonesthost.net/CyberCoveLLC/threshold-plugin-aws/plugin/service/host"
2021-10-06 12:47:05 -07:00
"github.com/stretchr/testify/require"
2026-09-24 14:07:28 -05:00
)
const (
envTargetAccessKeyId = "TARGET_AWS_ACCESS_KEY_ID"
envTargetSecretAccessKey = "TARGET_AWS_SECRET_ACCESS_KEY"
envTargetSessionToken = "TARGET_AWS_SESSION_TOKEN"
envTargetRegion = "TARGET_AWS_REGION"
2021-10-06 12:47:05 -07:00
)
2023-07-18 16:33:24 -07:00
const expectedEc2InstanceCount = 5
2021-10-06 12:47:05 -07:00
2023-07-18 16:33:24 -07:00
func TestHostPlugin ( t * testing . T ) {
2021-10-06 12:47:05 -07:00
region := os . Getenv ( "AWS_REGION" )
if region == "" {
t . Skip ( "set AWS_REGION to use this test" )
}
if envAccessKeyId := os . Getenv ( "AWS_ACCESS_KEY_ID" ); envAccessKeyId == "" {
t . Skip ( "set AWS_ACCESS_KEY_ID to use this test" )
}
if envSecretAccessKey := os . Getenv ( "AWS_SECRET_ACCESS_KEY" ); envSecretAccessKey == "" {
t . Skip ( "set AWS_SECRET_ACCESS_KEY to use this test" )
}
require := require . New ( t )
2026-09-24 14:07:28 -05:00
// Collect cross-account credentials up front so they can be passed as
// Terraform variables. The cross-account section is skipped (not failed)
// when these are absent, but we need the values available before Deploy.
targetAccessKeyId := os . Getenv ( envTargetAccessKeyId )
targetSecretAccessKey := os . Getenv ( envTargetSecretAccessKey )
targetSessionToken := os . Getenv ( envTargetSessionToken )
targetRegion := os . Getenv ( envTargetRegion )
if targetRegion == "" {
targetRegion = region
}
tfVars := map [ string ] string {}
if targetAccessKeyId != "" && targetSecretAccessKey != "" {
tfVars [ "target_access_key_id" ] = targetAccessKeyId
tfVars [ "target_secret_access_key" ] = targetSecretAccessKey
tfVars [ "target_region" ] = targetRegion
if targetSessionToken != "" {
tfVars [ "target_session_token" ] = targetSessionToken
}
}
tf , err := NewTestTerraformer ( "testdata/host" , tfVars )
2021-10-06 12:47:05 -07:00
require . NoError ( err )
require . NotNil ( tf )
t . Log ( "===== deploying test Terraform workspace =====" )
err = tf . Deploy ()
require . NoError ( err )
defer func () {
t . Log ( "===== destroying test Terraform workspace =====" )
if err := tf . Destroy (); err != nil {
t . Logf ( "WARNING: could not run Terraform destroy: %s" , err )
}
}()
iamUserNames , err := tf . GetOutputSlice ( "iam_user_names" )
require . NoError ( err )
require . Len ( iamUserNames , expectedIamUserCount )
iamUserArns , err := tf . GetOutputSlice ( "iam_user_arns" )
require . NoError ( err )
require . Len ( iamUserArns , expectedIamUserCount )
iamAccessKeyIds , err := tf . GetOutputSlice ( "iam_access_key_ids" )
require . NoError ( err )
require . Len ( iamAccessKeyIds , expectedIamUserCount )
iamSecretAccessKeys , err := tf . GetOutputSlice ( "iam_secret_access_keys" )
require . NoError ( err )
require . Len ( iamSecretAccessKeys , expectedIamUserCount )
ec2InstanceIds , err := tf . GetOutputSlice ( "instance_ids" )
require . NoError ( err )
require . Len ( ec2InstanceIds , expectedEc2InstanceCount )
ec2InstanceAddrs , err := tf . GetOutputMap ( "instance_addrs" )
require . NoError ( err )
require . Len ( ec2InstanceAddrs , expectedEc2InstanceCount )
ec2InstanceTags , err := tf . GetOutputMap ( "instance_tags" )
require . NoError ( err )
require . Len ( ec2InstanceTags , expectedEc2InstanceCount )
2026-05-14 10:59:38 -07:00
rawExpectedTags , err := tf . GetOutputSlice ( "instance_tag_keys" )
require . NoError ( err )
require . Len ( rawExpectedTags , 3 )
expectedTags := make ([] string , 0 , len ( rawExpectedTags ))
for _ , rawExpectedTag := range rawExpectedTags {
expectedTags = append ( expectedTags , rawExpectedTag .( string ))
}
2021-10-06 12:47:05 -07:00
// Start the workflow now. Set up the host catalog. Note that this
// will cause the state to go out of drift above in the sense that
// the access key ID/secret access key will no longer be valid. We
// will assert this through the returned state.
2023-03-20 11:02:17 -07:00
p := new ( host . HostPlugin )
2021-10-06 12:47:05 -07:00
ctx := context . Background ()
// ********************
// * OnCreateCatalog
// ********************
//
// Test non-rotation (using primary user).
keyid , secret := testPluginOnCreateCatalog ( ctx , t , p , region , iamAccessKeyIds [ 0 ].( string ), iamSecretAccessKeys [ 0 ].( string ), false )
// Test rotation next.
keyid , secret = testPluginOnCreateCatalog ( ctx , t , p , region , keyid , secret , true )
// ********************
// * OnUpdateCatalog
// ********************
//
// Test no-op non-rotation.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , "" , "" , false , false )
// Switch to rotation.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , "" , "" , false , true )
// Test no-op with rotation.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , "" , "" , true , true )
// Switch credentials to next user. Don't rotate.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , iamAccessKeyIds [ 1 ].( string ), iamSecretAccessKeys [ 1 ].( string ), true , false )
// Switch credentials to next user. Add rotation.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , iamAccessKeyIds [ 2 ].( string ), iamSecretAccessKeys [ 2 ].( string ), false , true )
// Switch to next user, with rotation disabled.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , iamAccessKeyIds [ 3 ].( string ), iamSecretAccessKeys [ 3 ].( string ), true , false )
// Last case - switch to another user and keep rotation off.
keyid , secret = testPluginOnUpdateCatalog ( ctx , t , p , region , keyid , secret , iamAccessKeyIds [ 4 ].( string ), iamSecretAccessKeys [ 4 ].( string ), false , false )
// ********************
// * OnDeleteCatalog
// ********************
//
// Test non-rotated.
testPluginOnDeleteCatalog ( ctx , t , p , region , keyid , secret , false )
// Test as if we had rotated these credentials (note that this
// makes this test set unusable).
testPluginOnDeleteCatalog ( ctx , t , p , region , keyid , secret , true )
// ********************
// * Host set stuff
// ********************
// Reassign the keyid and secret first.
keyid , secret = iamAccessKeyIds [ 5 ].( string ), iamSecretAccessKeys [ 5 ].( string )
// Process the collection of instances and index by expected tag names.
2026-09-24 14:07:28 -05:00
expectedTagInstancesMap := buildExpectedTagInstancesMap ( ec2InstanceTags , expectedTags )
requireTagInstancesMatchProvisioned ( t , ec2InstanceIds , expectedTagInstancesMap )
2021-10-06 12:47:05 -07:00
cases := [][] string {
2026-05-14 10:59:38 -07:00
{ expectedTags [ 0 ]},
{ expectedTags [ 1 ]},
{ expectedTags [ 2 ]},
{ expectedTags [ 0 ], expectedTags [ 1 ]},
{ expectedTags [ 0 ], expectedTags [ 2 ]},
{ expectedTags [ 1 ], expectedTags [ 2 ]},
{ expectedTags [ 0 ], expectedTags [ 1 ], expectedTags [ 2 ]},
2021-10-06 12:47:05 -07:00
}
for _ , tc := range cases {
// Test create/update in one step
testPluginOnCreateUpdateSet ( ctx , t , p , region , keyid , secret , tc )
// Test ListHosts
testPluginListHosts ( ctx , t , p , region , keyid , secret , tc , expectedTagInstancesMap )
// TODO: add OnDeleteSet if it needs to be implemented
}
2026-05-27 13:12:34 -07:00
// finally lets test instance_addresses_only catalog attribute correctly syncs only instance addresses
testInstanceAddressesOnlyListHosts ( ctx , t , p , tf , region , keyid , secret )
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
// ********************
// * AssumeRole - Happy Path & Error Cases
// ********************
assumeRoleArn , err := tf . GetOutputString ( "assume_role_arn" )
2021-10-06 12:47:05 -07:00
require . NoError ( err )
2026-09-24 14:07:28 -05:00
noTrustRoleArn , err := tf . GetOutputString ( "assume_role_no_trust_arn" )
require . NoError ( err )
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
missingPermRoleArn , err := tf . GetOutputString ( "assume_role_no_ec2_permission_arn" )
require . NoError ( err )
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
testOnCreateCatalogCases ( ctx , t , p , [] onCreateCatalogCase {
{ name : "assume role happy path" , catalogAttrs : roleArnAttrs ( region , assumeRoleArn )},
{ name : "assume role no trust" , catalogAttrs : roleArnAttrs ( region , noTrustRoleArn ), wantErr : "AccessDenied" },
{ name : "assume role missing ec2 permission" , catalogAttrs : roleArnAttrs ( region , missingPermRoleArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testOnUpdateCatalogCases ( ctx , t , p , [] onUpdateCatalogCase {
{ name : "assume role happy path" , catalogAttrs : roleArnAttrs ( region , assumeRoleArn )},
{ name : "assume role no trust" , catalogAttrs : roleArnAttrs ( region , noTrustRoleArn ), wantErr : "AccessDenied" },
{ name : "assume role missing ec2 permission" , currentAttrs : roleArnAttrs ( region , assumeRoleArn ), newAttrs : roleArnAttrs ( region , missingPermRoleArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testOnCreateSetCases ( ctx , t , p , [] onSetCase {
{ name : "assume role happy path" , catalogAttrs : roleArnAttrs ( region , assumeRoleArn ), tags : cases [ 0 ]},
{ name : "assume role no trust" , catalogAttrs : roleArnAttrs ( region , noTrustRoleArn ), wantErr : "AccessDenied" },
{ name : "assume role missing ec2 permission" , catalogAttrs : roleArnAttrs ( region , missingPermRoleArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testOnUpdateSetCases ( ctx , t , p , [] onSetCase {
{ name : "assume role happy path" , catalogAttrs : roleArnAttrs ( region , assumeRoleArn ), tags : cases [ 0 ]},
{ name : "assume role no trust" , catalogAttrs : roleArnAttrs ( region , noTrustRoleArn ), wantErr : "AccessDenied" },
{ name : "assume role missing ec2 permission" , catalogAttrs : roleArnAttrs ( region , missingPermRoleArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testListHostsCases ( ctx , t , p , [] listHostsCase {
{ name : "assume role happy path" , catalogAttrs : roleArnAttrs ( region , assumeRoleArn ), tags : cases [ 0 ], expected : expectedTagInstancesMap },
{ name : "assume role no trust" , catalogAttrs : roleArnAttrs ( region , noTrustRoleArn ), tags : cases [ 0 ], wantErr : "AccessDenied" },
{ name : "assume role missing ec2 permission" , catalogAttrs : roleArnAttrs ( region , missingPermRoleArn ), tags : cases [ 0 ], wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
// ********************
// * Cross-Role AssumeRole - Happy Path & Error Cases
// ********************
// These tests exercise the two-hop role chain within a single AWS account.
// The principal role has no ec2:DescribeInstances; the target role
// (assume_role) does. The plugin must assume the principal first, then use
// those credentials to assume the target role before calling DescribeInstances.
// This validates the plugin's chained credential logic without requiring a
// second AWS account.
crossRolePrincipalArn , err := tf . GetOutputString ( "cross_role_principal_arn" )
2021-10-06 12:47:05 -07:00
require . NoError ( err )
2026-09-24 14:07:28 -05:00
crossRolePrincipalNoTrustArn , err := tf . GetOutputString ( "cross_role_principal_no_trust_arn" )
2021-10-06 12:47:05 -07:00
require . NoError ( err )
2026-09-24 14:07:28 -05:00
crossRoleTargetNoTrustArn , err := tf . GetOutputString ( "cross_role_target_no_trust_arn" )
2021-10-06 12:47:05 -07:00
require . NoError ( err )
2026-09-24 14:07:28 -05:00
crossRoleTargetNoEc2PermissionArn , err := tf . GetOutputString ( "cross_role_target_no_ec2_permission_arn" )
require . NoError ( err )
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
// assume_role_arn is reused as the cross-role target — it has ec2:DescribeInstances
// and its trust policy allows the cross-role principal to assume it.
testOnCreateCatalogCases ( ctx , t , p , [] onCreateCatalogCase {
{ name : "cross-role happy path" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , assumeRoleArn )},
{ name : "cross-role principal no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalNoTrustArn , assumeRoleArn ), wantErr : "AccessDenied" },
{ name : "cross-role target no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-role target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testOnUpdateCatalogCases ( ctx , t , p , [] onUpdateCatalogCase {
{ name : "cross-role happy path" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , assumeRoleArn )},
{ name : "cross-role principal no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalNoTrustArn , assumeRoleArn ), wantErr : "AccessDenied" },
{ name : "cross-role target no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-role target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testOnCreateSetCases ( ctx , t , p , [] onSetCase {
{ name : "cross-role happy path" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , assumeRoleArn ), tags : cases [ 0 ]},
{ name : "cross-role principal no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalNoTrustArn , assumeRoleArn ), wantErr : "AccessDenied" },
{ name : "cross-role target no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-role target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testOnUpdateSetCases ( ctx , t , p , [] onSetCase {
{ name : "cross-role happy path" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , assumeRoleArn ), tags : cases [ 0 ]},
{ name : "cross-role principal no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalNoTrustArn , assumeRoleArn ), wantErr : "AccessDenied" },
{ name : "cross-role target no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-role target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
testListHostsCases ( ctx , t , p , [] listHostsCase {
{ name : "cross-role happy path" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , assumeRoleArn ), tags : cases [ 0 ], expected : expectedTagInstancesMap },
{ name : "cross-role principal no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalNoTrustArn , assumeRoleArn ), tags : cases [ 0 ], wantErr : "AccessDenied" },
{ name : "cross-role target no trust" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoTrustArn ), tags : cases [ 0 ], wantErr : "AccessDenied" },
{ name : "cross-role target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( region , crossRolePrincipalArn , crossRoleTargetNoEc2PermissionArn ), tags : cases [ 0 ], wantErr : "UnauthorizedOperation" },
2021-10-06 12:47:05 -07:00
})
2026-09-24 14:07:28 -05:00
// ********************
// * Cross-Account AssumeRole - Happy Path & Error Cases
// ********************
// These tests require credentials for a second AWS account supplied via
// TARGET_AWS_ACCESS_KEY_ID, TARGET_AWS_SECRET_ACCESS_KEY, and (for
// temporary credentials) TARGET_AWS_SESSION_TOKEN. They are skipped
// (not failed) when the access key ID or secret access key are absent.
if targetAccessKeyId == "" || targetSecretAccessKey == "" {
t . Log ( "skipping cross-account tests: set TARGET_AWS_ACCESS_KEY_ID and TARGET_AWS_SECRET_ACCESS_KEY to enable" )
} else {
crossAccountPrincipalArn , err := tf . GetOutputString ( "cross_account_principal_arn" )
require . NoError ( err )
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
crossAccountPrincipalNoTrustArn , err := tf . GetOutputString ( "cross_account_principal_no_trust_arn" )
require . NoError ( err )
2021-10-06 12:47:05 -07:00
2026-09-24 14:07:28 -05:00
crossAccountTargetArn , err := tf . GetOutputString ( "cross_account_target_arn" )
require . NoError ( err )
2026-05-27 13:12:34 -07:00
2026-09-24 14:07:28 -05:00
crossAccountTargetNoTrustArn , err := tf . GetOutputString ( "cross_account_target_no_trust_arn" )
require . NoError ( err )
2026-05-27 13:12:34 -07:00
2026-09-24 14:07:28 -05:00
crossAccountTargetNoEc2PermissionArn , err := tf . GetOutputString ( "cross_account_target_no_ec2_permission_arn" )
require . NoError ( err )
2026-05-27 13:12:34 -07:00
2026-09-24 14:07:28 -05:00
targetEc2InstanceIds , err := tf . GetOutputSlice ( "target_instance_ids" )
require . NoError ( err )
require . Len ( targetEc2InstanceIds , expectedEc2InstanceCount )
targetEc2InstanceTags , err := tf . GetOutputMap ( "target_instance_tags" )
require . NoError ( err )
expectedTargetTagInstancesMap := buildExpectedTagInstancesMap ( targetEc2InstanceTags , expectedTags )
requireTagInstancesMatchProvisioned ( t , targetEc2InstanceIds , expectedTargetTagInstancesMap )
testOnCreateCatalogCases ( ctx , t , p , [] onCreateCatalogCase {
{ name : "cross-account happy path" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetArn )},
{ name : "cross-account principal no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalNoTrustArn , crossAccountTargetArn ), wantErr : "AccessDenied" },
{ name : "cross-account target no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-account target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
})
testOnUpdateCatalogCases ( ctx , t , p , [] onUpdateCatalogCase {
{ name : "cross-account happy path" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetArn )},
{ name : "cross-account principal no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalNoTrustArn , crossAccountTargetArn ), wantErr : "AccessDenied" },
{ name : "cross-account target no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-account target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
})
testOnCreateSetCases ( ctx , t , p , [] onSetCase {
{ name : "cross-account happy path" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetArn ), tags : cases [ 0 ]},
{ name : "cross-account principal no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalNoTrustArn , crossAccountTargetArn ), wantErr : "AccessDenied" },
{ name : "cross-account target no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-account target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
})
testOnUpdateSetCases ( ctx , t , p , [] onSetCase {
{ name : "cross-account happy path" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetArn ), tags : cases [ 0 ]},
{ name : "cross-account principal no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalNoTrustArn , crossAccountTargetArn ), wantErr : "AccessDenied" },
{ name : "cross-account target no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoTrustArn ), wantErr : "AccessDenied" },
{ name : "cross-account target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoEc2PermissionArn ), wantErr : "UnauthorizedOperation" },
})
testListHostsCases ( ctx , t , p , [] listHostsCase {
{ name : "cross-account happy path" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetArn ), tags : cases [ 0 ], expected : expectedTargetTagInstancesMap },
{ name : "cross-account principal no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalNoTrustArn , crossAccountTargetArn ), tags : cases [ 0 ], wantErr : "AccessDenied" },
{ name : "cross-account target no trust" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoTrustArn ), tags : cases [ 0 ], wantErr : "AccessDenied" },
{ name : "cross-account target missing ec2 permission" , catalogAttrs : crossRoleAttrs ( targetRegion , crossAccountPrincipalArn , crossAccountTargetNoEc2PermissionArn ), tags : cases [ 0 ], wantErr : "UnauthorizedOperation" },
2026-05-27 13:12:34 -07:00
})
}
}