diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..64bd5cee --- /dev/null +++ b/.editorconfig @@ -0,0 +1,132 @@ +# Distributed via https://github.com/rebuy-de/terraform-cluster-config +# Modify only there, changes in project repos will be overwritten + +root = true + +[openapi-spec.yaml] +ij_formatter_enabled = false + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +max_line_length = 120 +tab_width = 4 +trim_trailing_whitespace = true +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = true +ij_smart_tabs = false +ij_visual_guides = +ij_wrap_on_typing = false + +[{*.htm,*.html,*.sht,*.shtm,*.shtml}] +ij_html_attribute_wrap = off +ij_html_do_not_indent_children_of_tags = +ij_html_keep_blank_lines = 1 +ij_html_text_wrap = off + +[{*.cjs,*.js}] +ij_javascript_do_while_brace_force = always +ij_javascript_for_brace_force = always +ij_javascript_if_brace_force = always +ij_javascript_keep_blank_lines_in_code = 1 +ij_javascript_use_double_quotes = false +ij_javascript_while_brace_force = always + +[{*.ats,*.cts,*.mts,*.ts}] +ij_typescript_do_while_brace_force = always +ij_typescript_for_brace_force = always +ij_typescript_if_brace_force = always +ij_typescript_import_prefer_absolute_path = true +ij_typescript_keep_blank_lines_in_code = 1 +ij_typescript_space_before_function_left_parenth = false +ij_typescript_use_double_quotes = false +ij_typescript_while_brace_force = always + +[*.coffee] +indent_size = 2 + +[*.java] +ij_continuation_indent_size = 4 +ij_java_blank_lines_around_field = 1 +ij_java_blank_lines_around_initializer = 0 +ij_java_class_brace_style = next_line +ij_java_class_count_to_use_import_on_demand = 99 +ij_java_do_while_brace_force = always +ij_java_doc_add_blank_line_after_param_comments = true +ij_java_doc_add_blank_line_after_return = true +ij_java_for_brace_force = always +ij_java_if_brace_force = always +ij_java_keep_blank_lines_before_right_brace = 0 +ij_java_keep_blank_lines_in_code = 1 +ij_java_keep_blank_lines_in_declarations = 0 +ij_java_keep_simple_classes_in_one_line = true +ij_java_keep_simple_lambdas_in_one_line = true +ij_java_method_brace_style = next_line +ij_java_names_count_to_use_import_on_demand = 99 +ij_java_new_line_after_lparen_in_record_header = true +ij_java_packages_to_use_import_on_demand = +ij_java_record_components_wrap = on_every_item +ij_java_rparen_on_new_line_in_record_header = true +ij_java_while_brace_force = always + +[{*.kt,*.kts}] +ij_continuation_indent_size = 4 +ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL +ij_kotlin_name_count_to_use_star_import = 2147483647 +ij_kotlin_name_count_to_use_star_import_for_members = 2147483647 +ij_kotlin_packages_to_use_import_on_demand = + +[{*.ctp,*.hphp,*.inc,*.module,*.php,*.php4,*.php5,*.phtml}] +ij_php_align_multiline_parameters = false +ij_php_blank_lines_around_field = 1 +ij_php_blank_lines_before_return_statement = 1 +ij_php_comma_after_last_array_element = true +ij_php_force_short_declaration_array_style = true +ij_php_keep_blank_lines_before_right_brace = 0 +ij_php_keep_blank_lines_in_code = 1 +ij_php_keep_blank_lines_in_declarations = 0 +ij_php_keep_rparen_and_lbrace_on_one_line = true +ij_php_lower_case_boolean_const = true +ij_php_lower_case_null_const = true +ij_php_method_parameters_new_line_after_left_paren = true +ij_php_method_parameters_right_paren_on_new_line = true +ij_php_phpdoc_blank_line_before_tags = true +ij_php_phpdoc_blank_lines_around_parameters = true +ij_php_space_after_type_cast = true +ij_php_space_before_short_closure_left_parenthesis = true + +[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.pom,*.rng,*.tld,*.wadl,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,phpunit.xml.dist}] +ij_xml_space_inside_empty_tag = true + +[{*.tf,*.tfvars,*.hcl}] +tab_width = 2 +ij_continuation_indent_size = 4 + +[*.less] +tab_width = 2 +ij_continuation_indent_size = 2 + +[*.sass] +tab_width = 2 +ij_continuation_indent_size = 2 + +[*.scala] +ij_scala_do_while_brace_force = always +ij_scala_for_brace_force = always +ij_scala_if_brace_force = always +ij_scala_keep_blank_lines_before_right_brace = 0 +ij_scala_keep_blank_lines_in_code = 0 +ij_scala_keep_blank_lines_in_declarations = 0 +ij_scala_multiline_string_closing_quotes_on_new_line = false + +[*.scss] +ij_continuation_indent_size = 4 + +[{*.yaml,*.yml}] +ij_yaml_spaces_within_braces = false +ij_yaml_spaces_within_brackets = false diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..91d476ed --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "gomod" + directory: "/" + schedule: + interval: "weekly" + day: "tuesday" + time: "10:00" + timezone: "Europe/Berlin" + groups: + golang: + patterns: + - "*" diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 00000000..4d213e6f --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,13 @@ +# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes#configuring-automatically-generated-release-notes + +changelog: + categories: + - title: Notable changes + labels: + - '*' + exclude: + labels: + - dependencies + - title: Dependency updates + labels: + - dependencies diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..7513d629 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,54 @@ +name: release + +on: + release: + types: [created] + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: main + - name: Update versions in readme + run: | + sed -r -i "s/aws-nuke:v[0-9]+\.[0-9]+\.[0-9]+/aws-nuke:${{ github.ref_name }}/" README.md + sed -r -i "s/aws-nuke-v[0-9]+\.[0-9]+\.[0-9]+/aws-nuke-${{ github.ref_name }}/" README.md + sed -r -i "s/\/v[0-9]+\.[0-9]+\.[0-9]+\//\/${{ github.ref_name }}\//" README.md + - uses: peter-evans/create-pull-request@v6 + name: Create Pull Request + with: + title: Update readme for ${{ github.ref_name }} release + commit-message: Update readme for ${{ github.ref_name }} release + body: Updating version references in the readme to ${{ github.ref_name }} + branch: update-readme-${{ github.ref_name }} + delete-branch: true + + release: + name: Publish binaries + runs-on: ubuntu-22.04 + steps: + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Build Project binaries + env: + CGO_ENABLED: 0 + run: | + make xc + - name: Upload binaries to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: dist/aws* + tag: ${{ github.ref }} + overwrite: true + file_glob: true \ No newline at end of file diff --git a/go.sum b/go.sum index aaa730b0..f36883fa 100644 --- a/go.sum +++ b/go.sum @@ -122,4 +122,4 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/need_refactor/bedrock-agentalias.go b/need_refactor/bedrock-agentalias.go new file mode 100644 index 00000000..63e0edba --- /dev/null +++ b/need_refactor/bedrock-agentalias.go @@ -0,0 +1,105 @@ +package resources + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/bedrockagent" + "github.com/rebuy-de/aws-nuke/v2/pkg/types" +) + +type BedrockAgentAlias struct { + svc *bedrockagent.BedrockAgent + AgentId *string + AgentAliasId *string + AgentAliasName *string +} + +func init() { + register("BedrockAgentAlias", ListBedrockAgentAliases) +} + +func ListBedrockAgentAliases(sess *session.Session) ([]Resource, error) { + svc := bedrockagent.New(sess) + resources := []Resource{} + + agentIds, err := ListBedrockAgentIds(svc) + if err != nil { + return nil, err + } + + for _, agentId := range agentIds { + params := &bedrockagent.ListAgentAliasesInput{ + MaxResults: aws.Int64(100), + AgentId: aws.String(agentId), + } + for { + output, err := svc.ListAgentAliases(params) + if err != nil { + return nil, err + } + + for _, agentAliasInfo := range output.AgentAliasSummaries { + resources = append(resources, &BedrockAgentAlias{ + svc: svc, + AgentId: aws.String(agentId), + AgentAliasName: agentAliasInfo.AgentAliasName, + AgentAliasId: agentAliasInfo.AgentAliasId, + }) + } + + if output.NextToken == nil { + break + } + params.NextToken = output.NextToken + } + + } + + return resources, nil +} + +func ListBedrockAgentIds(svc *bedrockagent.BedrockAgent) ([]string, error) { + + agentIds := []string{} + params := &bedrockagent.ListAgentsInput{ + MaxResults: aws.Int64(100), + } + for { + output, err := svc.ListAgents(params) + if err != nil { + return nil, err + } + + for _, agent := range output.AgentSummaries { + agentIds = append(agentIds, *agent.AgentId) + } + + if output.NextToken == nil { + break + } + params.NextToken = output.NextToken + } + + return agentIds, nil +} + +func (f *BedrockAgentAlias) Remove() error { + _, err := f.svc.DeleteAgentAlias(&bedrockagent.DeleteAgentAliasInput{ + AgentAliasId: f.AgentAliasId, + AgentId: f.AgentId, + }) + return err +} + +func (f *BedrockAgentAlias) Properties() types.Properties { + properties := types.NewProperties(). + Set("AgentId", f.AgentId). + Set("AgentAliasId", f.AgentAliasId). + Set("AgentAliasName", f.AgentAliasName) + + return properties +} + +func (f *BedrockAgentAlias) String() string { + return *f.AgentAliasName +} diff --git a/need_refactor/bedrock-flowalias.go b/need_refactor/bedrock-flowalias.go new file mode 100644 index 00000000..eca852ca --- /dev/null +++ b/need_refactor/bedrock-flowalias.go @@ -0,0 +1,115 @@ +package resources + +import ( + "fmt" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/bedrockagent" + "github.com/rebuy-de/aws-nuke/v2/pkg/types" +) + +type BedrockFlowAlias struct { + svc *bedrockagent.BedrockAgent + FlowId *string + FlowAliasId *string + FlowAliasName *string +} + +func init() { + register("BedrockFlowAlias", ListBedrockFlowAliases) +} + +func ListBedrockFlowAliases(sess *session.Session) ([]Resource, error) { + svc := bedrockagent.New(sess) + resources := []Resource{} + + flowIds, err := ListBedrockFlowIds(svc) + if err != nil { + return nil, err + } + + for _, flowId := range flowIds { + params := &bedrockagent.ListFlowAliasesInput{ + MaxResults: aws.Int64(100), + FlowIdentifier: aws.String(flowId), + } + for { + output, err := svc.ListFlowAliases(params) + if err != nil { + return nil, err + } + + for _, flowAliasInfo := range output.FlowAliasSummaries { + resources = append(resources, &BedrockFlowAlias{ + svc: svc, + FlowId: flowAliasInfo.FlowId, + FlowAliasId: flowAliasInfo.Id, + FlowAliasName: flowAliasInfo.Name, + }) + } + + if output.NextToken == nil { + break + } + params.NextToken = output.NextToken + } + + } + + return resources, nil +} + +func ListBedrockFlowIds(svc *bedrockagent.BedrockAgent) ([]string, error) { + + flowIds := []string{} + params := &bedrockagent.ListFlowsInput{ + MaxResults: aws.Int64(100), + } + for { + output, err := svc.ListFlows(params) + if err != nil { + return nil, err + } + + for _, flow := range output.FlowSummaries { + flowIds = append(flowIds, *flow.Id) + } + + if output.NextToken == nil { + break + } + params.NextToken = output.NextToken + } + + return flowIds, nil +} + +func (f *BedrockFlowAlias) Filter() error { + if strings.HasPrefix(*f.FlowAliasName, "TSTALIASID") { + return fmt.Errorf("cannot delete AWS managed Flow Alias") + } + return nil +} + +func (f *BedrockFlowAlias) Remove() error { + _, err := f.svc.DeleteFlowAlias(&bedrockagent.DeleteFlowAliasInput{ + AliasIdentifier: f.FlowAliasId, + FlowIdentifier: f.FlowId, + }) + return err +} + +func (f *BedrockFlowAlias) Properties() types.Properties { + properties := types.NewProperties(). + Set("FlowId", f.FlowId). + Set("FlowAliasId", f.FlowAliasId). + Set("FlowAliasName", f.FlowAliasName) + + return properties +} + +func (f *BedrockFlowAlias) String() string { + return *f.FlowAliasName +} diff --git a/need_refactor/kinesis-signaling-channels.go b/need_refactor/kinesis-signaling-channels.go new file mode 100644 index 00000000..d1830f06 --- /dev/null +++ b/need_refactor/kinesis-signaling-channels.go @@ -0,0 +1,60 @@ +package resources + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/kinesisvideo" +) + +type KinesisSignalingChannels struct { + svc *kinesisvideo.KinesisVideo + ChannelARN *string +} + +func init() { + register("KinesisSignalingChannels", ListKinesisSignalingChannels) +} + +func ListKinesisSignalingChannels(sess *session.Session) ([]Resource, error) { + svc := kinesisvideo.New(sess) + resources := []Resource{} + + params := &kinesisvideo.ListSignalingChannelsInput{ + MaxResults: aws.Int64(100), + } + + for { + output, err := svc.ListSignalingChannels(params) + if err != nil { + return nil, err + } + + for _, streamInfo := range output.ChannelInfoList { + resources = append(resources, &KinesisSignalingChannels{ + svc: svc, + ChannelARN: streamInfo.ChannelARN, + }) + } + + if output.NextToken == nil { + break + } + + params.NextToken = output.NextToken + } + + return resources, nil +} + +func (f *KinesisSignalingChannels) Remove() error { + + _, err := f.svc.DeleteSignalingChannel(&kinesisvideo.DeleteSignalingChannelInput{ + ChannelARN: f.ChannelARN, + }) + + return err +} + +func (f *KinesisSignalingChannels) String() string { + return *f.ChannelARN +} diff --git a/resources/ec2-tgw-attachments.go b/resources/ec2-tgw-attachments.go index 4a3d4796..01dda08f 100644 --- a/resources/ec2-tgw-attachments.go +++ b/resources/ec2-tgw-attachments.go @@ -69,6 +69,21 @@ func (e *EC2TGWAttachment) Remove(_ context.Context) error { // as part of TGW to delete VPN attachments. return fmt.Errorf("VPN attachment") } + + // Execute different API calls depending on the resource type. + if *e.tgwa.ResourceType == "peering" { + params := &ec2.DeleteTransitGatewayPeeringAttachmentInput{ + TransitGatewayAttachmentId: e.tgwa.TransitGatewayAttachmentId, + } + + _, err := e.svc.DeleteTransitGatewayPeeringAttachment(params) + if err != nil { + return err + } + + return nil + } + params := &ec2.DeleteTransitGatewayVpcAttachmentInput{ TransitGatewayAttachmentId: e.tgwa.TransitGatewayAttachmentId, } diff --git a/resources/ecs-services.go b/resources/ecs-services.go index d15ab5db..adeab72e 100644 --- a/resources/ecs-services.go +++ b/resources/ecs-services.go @@ -60,24 +60,19 @@ func (l *ECSServiceLister) List(_ context.Context, o interface{}) ([]resource.Re Cluster: clusterArn, MaxResults: aws.Int64(10), } - output, err := svc.ListServices(serviceParams) + err := svc.ListServicesPages(serviceParams, func(page *ecs.ListServicesOutput, lastPage bool) bool { + for _, serviceArn := range page.ServiceArns { + resources = append(resources, &ECSService{ + svc: svc, + serviceARN: serviceArn, + clusterARN: clusterArn, + }) + } + return true + }) if err != nil { return nil, err } - - for _, serviceArn := range output.ServiceArns { - resources = append(resources, &ECSService{ - svc: svc, - serviceARN: serviceArn, - clusterARN: clusterArn, - }) - } - - if output.NextToken == nil { - continue - } - - serviceParams.NextToken = output.NextToken } return resources, nil diff --git a/resources/waf-rules.go b/resources/waf-rules.go index 47d98cd3..e9903246 100644 --- a/resources/waf-rules.go +++ b/resources/waf-rules.go @@ -42,9 +42,12 @@ func (l *WAFRuleLister) List(_ context.Context, o interface{}) ([]resource.Resou } for _, rule := range resp.Rules { - ruleResp, _ := svc.GetRule(&waf.GetRuleInput{ + ruleResp, err := svc.GetRule(&waf.GetRuleInput{ RuleId: rule.RuleId, }) + if err != nil { + return nil, err + } resources = append(resources, &WAFRule{ svc: svc, ID: rule.RuleId, diff --git a/resources/wafregional-rules.go b/resources/wafregional-rules.go index b1cb87a9..1de5c1b1 100644 --- a/resources/wafregional-rules.go +++ b/resources/wafregional-rules.go @@ -43,9 +43,12 @@ func (l *WAFRegionalRuleLister) List(_ context.Context, o interface{}) ([]resour } for _, rule := range resp.Rules { - ruleResp, _ := svc.GetRule(&waf.GetRuleInput{ + ruleResp, err := svc.GetRule(&waf.GetRuleInput{ RuleId: rule.RuleId, }) + if err != nil { + return nil, err + } resources = append(resources, &WAFRegionalRule{ svc: svc, ID: rule.RuleId, diff --git a/tools/tools.go b/tools/tools.go new file mode 100644 index 00000000..356e8982 --- /dev/null +++ b/tools/tools.go @@ -0,0 +1,8 @@ +//go:build tools + +package main + +// https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module +import ( + _ "github.com/golang/mock/mockgen" +)