├── .github
├── e2eapply.tape
├── e2eplan.tape
└── workflows
│ ├── release.yml
│ └── tests.yml
├── .gitignore
├── .goreleaser.yaml
├── .terraform.lock.hcl
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── assets
├── banner_dark.svg
├── banner_light.svg
├── blastRadiusItems.png
├── chainLink.png
├── change.png
├── change.svg
├── changed.png
├── changed.svg
├── created.png
├── created.svg
├── deleted.png
├── deleted.svg
├── edge.png
├── edge.svg
├── high.png
├── high.svg
├── item.png
├── item.svg
├── link.svg
├── logo.png
├── low.png
├── low.svg
├── medium.png
├── medium.svg
├── open_in_overmind.svg
├── replaced.png
├── replaced.svg
├── risks.png
├── risks.svg
├── unchanged.svg
└── unmapped.svg
├── auth
├── auth.go
├── auth_client.go
├── auth_test.go
├── middleware.go
├── middleware_test.go
├── nats.go
├── nats_test.go
└── tracing.go
├── aws-source
├── .deadcode-ignore
├── acceptance
│ └── nats-server.conf
├── adapterhelpers
│ ├── always_get_source.go
│ ├── always_get_source_test.go
│ ├── describe_source.go
│ ├── describe_source_test.go
│ ├── get_list_adapter_v2.go
│ ├── get_list_adapter_v2_test.go
│ ├── get_list_source.go
│ ├── get_list_source_test.go
│ ├── shared_tests.go
│ ├── sources.go
│ ├── util.go
│ └── util_test.go
├── adapters
│ ├── apigateway-api-key.go
│ ├── apigateway-api-key_test.go
│ ├── apigateway-authorizer.go
│ ├── apigateway-authorizer_test.go
│ ├── apigateway-deployment.go
│ ├── apigateway-deployment_test.go
│ ├── apigateway-domain-name.go
│ ├── apigateway-domain-name_test.go
│ ├── apigateway-integration.go
│ ├── apigateway-integration_test.go
│ ├── apigateway-method-response.go
│ ├── apigateway-method-response_test.go
│ ├── apigateway-method.go
│ ├── apigateway-method_test.go
│ ├── apigateway-model.go
│ ├── apigateway-model_test.go
│ ├── apigateway-resource.go
│ ├── apigateway-resource_test.go
│ ├── apigateway-rest-api.go
│ ├── apigateway-rest-api_test.go
│ ├── apigateway-stage.go
│ ├── apigateway-stage_test.go
│ ├── autoscaling-auto-scaling-group.go
│ ├── autoscaling-auto-scaling-group_test.go
│ ├── cloudfront-cache-policy.go
│ ├── cloudfront-cache-policy_test.go
│ ├── cloudfront-continuous-deployment-policy.go
│ ├── cloudfront-continuous-deployment-policy_test.go
│ ├── cloudfront-distribution.go
│ ├── cloudfront-distribution_test.go
│ ├── cloudfront-function.go
│ ├── cloudfront-function_test.go
│ ├── cloudfront-key-group.go
│ ├── cloudfront-key-group_test.go
│ ├── cloudfront-origin-access-control.go
│ ├── cloudfront-origin-access-control_test.go
│ ├── cloudfront-origin-request-policy.go
│ ├── cloudfront-origin-request-policy_test.go
│ ├── cloudfront-realtime-log-config.go
│ ├── cloudfront-realtime-log-config_test.go
│ ├── cloudfront-response-headers-policy.go
│ ├── cloudfront-response-headers-policy_test.go
│ ├── cloudfront-streaming-distribution.go
│ ├── cloudfront-streaming-distribution_test.go
│ ├── cloudfront.go
│ ├── cloudfront_test.go
│ ├── cloudwatch-alarm.go
│ ├── cloudwatch-alarm_test.go
│ ├── cloudwatch_metric_links.go
│ ├── cloudwatch_metric_links_test.go
│ ├── directconnect-connection.go
│ ├── directconnect-connection_test.go
│ ├── directconnect-customer-metadata.go
│ ├── directconnect-customer-metadata_test.go
│ ├── directconnect-direct-connect-gateway-association-proposal.go
│ ├── directconnect-direct-connect-gateway-association-proposal_test.go
│ ├── directconnect-direct-connect-gateway-association.go
│ ├── directconnect-direct-connect-gateway-association_test.go
│ ├── directconnect-direct-connect-gateway-attachment.go
│ ├── directconnect-direct-connect-gateway-attachment_test.go
│ ├── directconnect-direct-connect-gateway.go
│ ├── directconnect-direct-connect-gateway_test.go
│ ├── directconnect-hosted-connection.go
│ ├── directconnect-hosted-connection_test.go
│ ├── directconnect-interconnect.go
│ ├── directconnect-interconnect_test.go
│ ├── directconnect-lag.go
│ ├── directconnect-lag_test.go
│ ├── directconnect-location.go
│ ├── directconnect-location_test.go
│ ├── directconnect-router-configuration.go
│ ├── directconnect-router-configuration_test.go
│ ├── directconnect-virtual-gateway.go
│ ├── directconnect-virtual-gateway_test.go
│ ├── directconnect-virtual-interface.go
│ ├── directconnect-virtual-interface_test.go
│ ├── directconnect.go
│ ├── directconnect_test.go
│ ├── dynamodb-backup.go
│ ├── dynamodb-backup_test.go
│ ├── dynamodb-table.go
│ ├── dynamodb-table_test.go
│ ├── dynamodb.go
│ ├── dynamodb_test.go
│ ├── ec2-address.go
│ ├── ec2-address_test.go
│ ├── ec2-capacity-reservation-fleet.go
│ ├── ec2-capacity-reservation-fleet_test.go
│ ├── ec2-capacity-reservation.go
│ ├── ec2-capacity-reservation_test.go
│ ├── ec2-egress-only-internet-gateway.go
│ ├── ec2-egress-only-internet-gateway_test.go
│ ├── ec2-iam-instance-profile-association.go
│ ├── ec2-iam-instance-profile-association_test.go
│ ├── ec2-image.go
│ ├── ec2-image_test.go
│ ├── ec2-instance-event-window.go
│ ├── ec2-instance-event-window_test.go
│ ├── ec2-instance-status.go
│ ├── ec2-instance-status_test.go
│ ├── ec2-instance.go
│ ├── ec2-instance_test.go
│ ├── ec2-internet-gateway.go
│ ├── ec2-internet-gateway_test.go
│ ├── ec2-key-pair.go
│ ├── ec2-key-pair_test.go
│ ├── ec2-launch-template-version.go
│ ├── ec2-launch-template-version_test.go
│ ├── ec2-launch-template.go
│ ├── ec2-launch-template_test.go
│ ├── ec2-nat-gateway.go
│ ├── ec2-nat-gateway_test.go
│ ├── ec2-network-acl.go
│ ├── ec2-network-acl_test.go
│ ├── ec2-network-interface-permission.go
│ ├── ec2-network-interface-permission_test.go
│ ├── ec2-network-interface.go
│ ├── ec2-network-interface_test.go
│ ├── ec2-placement-group.go
│ ├── ec2-placement-group_test.go
│ ├── ec2-reserved-instance.go
│ ├── ec2-reserved-instance_test.go
│ ├── ec2-route-table.go
│ ├── ec2-route-table_test.go
│ ├── ec2-security-group-rule.go
│ ├── ec2-security-group-rule_test.go
│ ├── ec2-security-group.go
│ ├── ec2-security-group_test.go
│ ├── ec2-snapshot.go
│ ├── ec2-snapshot_test.go
│ ├── ec2-subnet.go
│ ├── ec2-subnet_test.go
│ ├── ec2-volume-status.go
│ ├── ec2-volume-status_test.go
│ ├── ec2-volume.go
│ ├── ec2-volume_test.go
│ ├── ec2-vpc-endpoint.go
│ ├── ec2-vpc-endpoint_test.go
│ ├── ec2-vpc-peering-connection.go
│ ├── ec2-vpc-peering-connection_test.go
│ ├── ec2-vpc.go
│ ├── ec2-vpc_test.go
│ ├── ec2.go
│ ├── ec2_test.go
│ ├── ecs-capacity-provider.go
│ ├── ecs-capacity-provider_test.go
│ ├── ecs-cluster.go
│ ├── ecs-cluster_test.go
│ ├── ecs-container-instance.go
│ ├── ecs-container-instance_test.go
│ ├── ecs-service.go
│ ├── ecs-service_test.go
│ ├── ecs-task-definition.go
│ ├── ecs-task-definition_test.go
│ ├── ecs-task.go
│ ├── ecs-task_test.go
│ ├── ecs.go
│ ├── ecs_test.go
│ ├── efs-access-point.go
│ ├── efs-access-point_test.go
│ ├── efs-backup-policy.go
│ ├── efs-backup-policy_test.go
│ ├── efs-file-system.go
│ ├── efs-file-system_test.go
│ ├── efs-mount-target.go
│ ├── efs-mount-target_test.go
│ ├── efs-replication-configuration.go
│ ├── efs-replication-configuration_test.go
│ ├── efs.go
│ ├── efs_test.go
│ ├── eks-addon.go
│ ├── eks-addon_test.go
│ ├── eks-cluster.go
│ ├── eks-cluster_test.go
│ ├── eks-fargate-profile.go
│ ├── eks-fargate-profile_test.go
│ ├── eks-nodegroup.go
│ ├── eks-nodegroup_test.go
│ ├── eks.go
│ ├── eks_test.go
│ ├── elb-instance-health.go
│ ├── elb-instance-health_test.go
│ ├── elb-load-balancer.go
│ ├── elb-load-balancer_test.go
│ ├── elbv2-listener.go
│ ├── elbv2-listener_test.go
│ ├── elbv2-load-balancer.go
│ ├── elbv2-load-balancer_test.go
│ ├── elbv2-rule.go
│ ├── elbv2-rule_test.go
│ ├── elbv2-target-group.go
│ ├── elbv2-target-group_test.go
│ ├── elbv2-target-health.go
│ ├── elbv2-target-health_test.go
│ ├── elbv2.go
│ ├── elbv2_test.go
│ ├── iam-group.go
│ ├── iam-group_test.go
│ ├── iam-instance-profile.go
│ ├── iam-instance-profile_test.go
│ ├── iam-policy.go
│ ├── iam-policy_test.go
│ ├── iam-role.go
│ ├── iam-role_test.go
│ ├── iam-user.go
│ ├── iam-user_test.go
│ ├── iam.go
│ ├── iam_test.go
│ ├── integration
│ │ ├── apigateway
│ │ │ ├── apigateway_test.go
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── find.go
│ │ │ ├── main_test.go
│ │ │ ├── setup.go
│ │ │ ├── teardown.go
│ │ │ └── util.go
│ │ ├── ec2
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── find.go
│ │ │ ├── instance_test.go
│ │ │ ├── main_test.go
│ │ │ ├── setup.go
│ │ │ ├── teardown.go
│ │ │ └── util.go
│ │ ├── errors.go
│ │ ├── kms
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── find.go
│ │ │ ├── kms_test.go
│ │ │ ├── main_test.go
│ │ │ ├── setup.go
│ │ │ ├── teardown.go
│ │ │ └── util.go
│ │ ├── networkmanager
│ │ │ ├── create.go
│ │ │ ├── delete.go
│ │ │ ├── find.go
│ │ │ ├── main_test.go
│ │ │ ├── networkmanager_test.go
│ │ │ ├── setup.go
│ │ │ ├── tags.go
│ │ │ └── teardown.go
│ │ ├── ssm
│ │ │ └── main_test.go
│ │ ├── util.go
│ │ └── util_test.go
│ ├── kms-alias.go
│ ├── kms-alias_test.go
│ ├── kms-custom-key-store.go
│ ├── kms-custom-key-store_test.go
│ ├── kms-grant.go
│ ├── kms-grant_test.go
│ ├── kms-key-policy.go
│ ├── kms-key-policy_test.go
│ ├── kms-key.go
│ ├── kms-key_test.go
│ ├── kms.go
│ ├── lambda-function.go
│ ├── lambda-function_test.go
│ ├── lambda-layer-version.go
│ ├── lambda-layer-version_test.go
│ ├── lambda-layer.go
│ ├── lambda-layer_test.go
│ ├── lambda.go
│ ├── lambda_test.go
│ ├── main.go
│ ├── network-firewall-firewall-policy.go
│ ├── network-firewall-firewall-policy_test.go
│ ├── network-firewall-firewall.go
│ ├── network-firewall-firewall_test.go
│ ├── network-firewall-rule-group.go
│ ├── network-firewall-rule-group_test.go
│ ├── network-firewall-tls-inspection-configuration.go
│ ├── network-firewall-tls-inspection-configuration_test.go
│ ├── networkfirewall.go
│ ├── networkfirewall_test.go
│ ├── networkmanager-connect-attachment.go
│ ├── networkmanager-connect-attachment_test.go
│ ├── networkmanager-connect-peer-association.go
│ ├── networkmanager-connect-peer-association_test.go
│ ├── networkmanager-connect-peer.go
│ ├── networkmanager-connect-peer_test.go
│ ├── networkmanager-connection.go
│ ├── networkmanager-connection_test.go
│ ├── networkmanager-core-network-policy.go
│ ├── networkmanager-core-network-policy_test.go
│ ├── networkmanager-core-network.go
│ ├── networkmanager-core-network_test.go
│ ├── networkmanager-device.go
│ ├── networkmanager-device_test.go
│ ├── networkmanager-global-network.go
│ ├── networkmanager-global-network_test.go
│ ├── networkmanager-link-association.go
│ ├── networkmanager-link-association_test.go
│ ├── networkmanager-link.go
│ ├── networkmanager-link_test.go
│ ├── networkmanager-network-resource-relationship.go
│ ├── networkmanager-network-resource-relationship_test.go
│ ├── networkmanager-site-to-site-vpn-attachment.go
│ ├── networkmanager-site-to-site-vpn-attachment_test.go
│ ├── networkmanager-site.go
│ ├── networkmanager-site_test.go
│ ├── networkmanager-transit-gateway-connect-peer-association.go
│ ├── networkmanager-transit-gateway-connect-peer-association_test.go
│ ├── networkmanager-transit-gateway-peering.go
│ ├── networkmanager-transit-gateway-peering_test.go
│ ├── networkmanager-transit-gateway-registration.go
│ ├── networkmanager-transit-gateway-registration_test.go
│ ├── networkmanager-transit-gateway-route-table-attachment.go
│ ├── networkmanager-transit-gateway-route-table-attachment_test.go
│ ├── networkmanager-vpc-attachment.go
│ ├── networkmanager-vpc-attachment_test.go
│ ├── networkmanager.go
│ ├── networkmanager_test.go
│ ├── rds-db-cluster-parameter-group.go
│ ├── rds-db-cluster-parameter-group_test.go
│ ├── rds-db-cluster.go
│ ├── rds-db-cluster_test.go
│ ├── rds-db-instance.go
│ ├── rds-db-instance_test.go
│ ├── rds-db-parameter-group.go
│ ├── rds-db-parameter-group_test.go
│ ├── rds-db-subnet-group.go
│ ├── rds-db-subnet-group_test.go
│ ├── rds-option-group.go
│ ├── rds-option-group_test.go
│ ├── rds.go
│ ├── rds_test.go
│ ├── route53-health-check.go
│ ├── route53-health-check_test.go
│ ├── route53-hosted-zone.go
│ ├── route53-hosted-zone_test.go
│ ├── route53-resource-record-set.go
│ ├── route53-resource-record-set_test.go
│ ├── route53.go
│ ├── route53_test.go
│ ├── s3.go
│ ├── s3_test.go
│ ├── sns-data-protection-policy.go
│ ├── sns-data-protection-policy_test.go
│ ├── sns-endpoint.go
│ ├── sns-endpoint_test.go
│ ├── sns-platform-application.go
│ ├── sns-platform-application_test.go
│ ├── sns-subscription.go
│ ├── sns-subscription_test.go
│ ├── sns-topic.go
│ ├── sns-topic_test.go
│ ├── sns.go
│ ├── sqs-queue.go
│ ├── sqs-queue_test.go
│ ├── sqs.go
│ ├── ssm-parameter.go
│ ├── ssm-parameter_test.go
│ └── tracing.go
├── build
│ └── package
│ │ └── Dockerfile
├── cmd
│ └── root.go
├── docker-compose.yml
├── main.go
└── proc
│ └── proc.go
├── cmd
├── auth_client.go
├── bookmarks.go
├── bookmarks_create_bookmark.go
├── bookmarks_get_affected_bookmarks.go
├── bookmarks_get_bookmark.go
├── changes.go
├── changes_end_change.go
├── changes_get_change.go
├── changes_list_changes.go
├── changes_start_change.go
├── changes_submit_plan.go
├── changes_submit_plan_test.go
├── explore.go
├── flags.go
├── integrations.go
├── integrations_tfc.go
├── invites.go
├── invites_crud.go
├── logging.go
├── pterm.go
├── repo.go
├── repo_test.go
├── request.go
├── request_load.go
├── request_query.go
├── root.go
├── root_test.go
├── snapshots.go
├── snapshots_get_snapshot.go
├── terraform.go
├── terraform_apply.go
├── terraform_plan.go
├── theme.go
├── theme_darwin.go
├── theme_linux.go
├── theme_test.go
└── theme_windows.go
├── demos
└── plan.tape
├── discovery
├── adapter.go
├── adapter_test.go
├── adapterhost.go
├── adapterhost_test.go
├── cmd.go
├── cmd_test.go
├── engine.go
├── engine_test.go
├── enginerequests.go
├── enginerequests_test.go
├── getfindmutex.go
├── getfindmutex_test.go
├── heartbeat.go
├── heartbeat_test.go
├── item_tests.go
├── logs.go
├── logs_test.go
├── main_test.go
├── nats_shared_test.go
├── nats_watcher.go
├── nats_watcher_test.go
├── nil_publisher.go
├── performance_test.go
├── querytracker.go
├── querytracker_test.go
├── shared_test.go
└── tracing.go
├── examples
└── create-bookmark.json
├── go.mod
├── go.sum
├── gon-amd64.json
├── gon-arm64.json
├── k8s-source
├── acceptance
│ └── nats-server.conf
├── adapters
│ ├── clusterrole.go
│ ├── clusterrole_test.go
│ ├── clusterrolebinding.go
│ ├── clusterrolebinding_test.go
│ ├── configmap.go
│ ├── configmap_test.go
│ ├── cronjob.go
│ ├── cronjob_test.go
│ ├── daemonset.go
│ ├── daemonset_test.go
│ ├── deployment.go
│ ├── deployment_test.go
│ ├── endpoints.go
│ ├── endpoints_test.go
│ ├── endpointslice.go
│ ├── endpointslice_test.go
│ ├── generic_source.go
│ ├── generic_source_test.go
│ ├── horizontalpodautoscaler.go
│ ├── horizontalpodautoscaler_test.go
│ ├── ingress.go
│ ├── ingress_test.go
│ ├── job.go
│ ├── job_test.go
│ ├── limitrange.go
│ ├── limitrange_test.go
│ ├── main.go
│ ├── networkpolicy.go
│ ├── networkpolicy_test.go
│ ├── node.go
│ ├── node_test.go
│ ├── persistentvolume.go
│ ├── persistentvolume_test.go
│ ├── persistentvolumeclaim.go
│ ├── persistentvolumeclaim_test.go
│ ├── poddisruptionbudget.go
│ ├── poddisruptionbudget_test.go
│ ├── pods.go
│ ├── pods_test.go
│ ├── priorityclass.go
│ ├── priorityclass_test.go
│ ├── replicaset.go
│ ├── replicaset_test.go
│ ├── replicationcontroller.go
│ ├── replicationcontroller_test.go
│ ├── resourcequota.go
│ ├── resourcequota_test.go
│ ├── role.go
│ ├── role_test.go
│ ├── rolebinding.go
│ ├── rolebinding_test.go
│ ├── secret.go
│ ├── secret_test.go
│ ├── service.go
│ ├── service_test.go
│ ├── serviceaccount.go
│ ├── serviceaccount_test.go
│ ├── shared_test.go
│ ├── shared_util.go
│ ├── shared_util_test.go
│ ├── statefulset.go
│ ├── statefulset_test.go
│ ├── storageclass.go
│ ├── storageclass_test.go
│ ├── volumeattachment.go
│ └── volumeattachment_test.go
├── build
│ └── package
│ │ └── Dockerfile
├── cmd
│ └── root.go
├── config.json
├── cr.sh
├── deployments
│ └── overmind-kube-source
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── README.md
│ │ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── clusterrole.yaml
│ │ ├── clusterrolebinding.yaml
│ │ ├── configmap.yaml
│ │ ├── deployment.yaml
│ │ ├── hpa.yaml
│ │ ├── secret.yaml
│ │ └── serviceaccount.yaml
│ │ └── values.yaml
└── main.go
├── lostpixel.config.ts
├── main.go
├── main.tf
├── package.json
├── sdp-go
├── .gitignore
├── account.go
├── account.pb.go
├── apikey.go
├── apikeys.pb.go
├── auth0support.pb.go
├── bookmarks.go
├── bookmarks.pb.go
├── changes.go
├── changes.pb.go
├── changes_test.go
├── changetimeline.go
├── cli.pb.go
├── compare.go
├── config.pb.go
├── connection.go
├── connection_test.go
├── encoder_test.go
├── errors.go
├── gateway.go
├── gateway.pb.go
├── gateway_test.go
├── genhandler.go
├── graph
│ ├── main.go
│ └── main_test.go
├── handler_cancelquery.go
├── handler_gatewayresponse.go
├── handler_natsgetlogrecordsrequest.go
├── handler_natsgetlogrecordsresponse.go
├── handler_query.go
├── handler_queryresponse.go
├── instance_detect.go
├── invites.pb.go
├── items.go
├── items.pb.go
├── items_test.go
├── link_extract.go
├── link_extract_test.go
├── logs.go
├── logs.pb.go
├── logs_test.go
├── progress.go
├── progress_test.go
├── responses.go
├── responses.pb.go
├── revlink.pb.go
├── sdpconnect
│ ├── account.connect.go
│ ├── apikeys.connect.go
│ ├── auth0support.connect.go
│ ├── bookmarks.connect.go
│ ├── changes.connect.go
│ ├── cli.connect.go
│ ├── config.connect.go
│ ├── invites.connect.go
│ ├── logs.connect.go
│ ├── revlink.connect.go
│ └── snapshots.connect.go
├── sdpws
│ ├── client.go
│ ├── client_test.go
│ ├── messagehandler.go
│ └── utils.go
├── snapshots.go
├── snapshots.pb.go
├── test_utils.go
├── test_utils_test.go
├── tracing.go
├── tracing
│ └── main.go
├── tracing_test.go
├── util.go
├── util.pb.go
├── util_test.go
├── validation.go
└── validation_test.go
├── sdpcache
├── cache.go
├── cache_benchmark_test.go
├── cache_test.go
└── item_generator_test.go
├── sources
├── aws
│ ├── apigateway-api-key.go
│ ├── apigateway-stage.go
│ ├── base.go
│ ├── errors.go
│ ├── shared
│ │ └── models.go
│ └── validation_test.go
├── example
│ ├── base.go
│ ├── custom_searchable_listable.go
│ ├── errors.go
│ ├── metadata_test.go
│ ├── mocks
│ │ └── mock_external_api_client.go
│ ├── shared
│ │ └── models.go
│ ├── standard_searchable_listable.go
│ ├── standard_searchable_listable_test.go
│ └── validation_test.go
├── gcp
│ ├── README.md
│ ├── adapters
│ │ ├── adapters.go
│ │ ├── compute-accelerator-type.go
│ │ ├── compute-address.go
│ │ ├── compute-address_test.go
│ │ ├── compute-autoscaler.go
│ │ ├── compute-autoscaler_test.go
│ │ ├── compute-backend-service.go
│ │ ├── compute-backend-service_test.go
│ │ ├── compute-forwarding-rule.go
│ │ ├── compute-forwarding-rule_test.go
│ │ ├── compute-healthcheck.go
│ │ ├── compute-healthcheck_test.go
│ │ ├── compute-image.go
│ │ ├── compute-image_test.go
│ │ ├── compute-instance-group-manager.go
│ │ ├── compute-instance-group-manager_test.go
│ │ ├── compute-instance-group.go
│ │ ├── compute-instance-group_test.go
│ │ ├── compute-instance.go
│ │ ├── compute-instance_test.go
│ │ ├── compute-instant-snapshot.go
│ │ ├── compute-instant-snapshot_test.go
│ │ ├── compute-machine-type.go
│ │ ├── compute-node-group.go
│ │ ├── compute-node-group_test.go
│ │ ├── compute-node-template.go
│ │ ├── compute-node-template_test.go
│ │ ├── compute-region-commitment.go
│ │ ├── compute-reservation.go
│ │ ├── compute-reservation_test.go
│ │ ├── compute-resource-policy.go
│ │ ├── compute-security-policy.go
│ │ ├── compute-security-policy_test.go
│ │ ├── container-cluster.go
│ │ ├── network-security-client-tls-policy.go
│ │ ├── network-services-service-binding.go
│ │ └── network-services-service-lb-policy.go
│ ├── cmd
│ │ └── root.go
│ ├── integration-tests
│ │ ├── compute-address_test.go
│ │ ├── compute-autoscaler_test.go
│ │ ├── compute-forwarding-rule_test.go
│ │ ├── compute-healthcheck_test.go
│ │ ├── compute-image_test.go
│ │ ├── compute-instance-group-manager_test.go
│ │ ├── compute-instance-group_test.go
│ │ ├── compute-instance_test.go
│ │ ├── compute-instant-snapshot_test.go
│ │ ├── compute-node-group_test.go
│ │ ├── compute-reservation_test.go
│ │ └── main_test.go
│ ├── main.go
│ ├── proc
│ │ ├── proc.go
│ │ └── proc_test.go
│ └── shared
│ │ ├── base.go
│ │ ├── compute-clients.go
│ │ ├── errors.go
│ │ ├── mocks
│ │ └── mock_compute_instance_client.go
│ │ ├── models.go
│ │ ├── network-security-clients.go
│ │ ├── utils.go
│ │ └── utils_test.go
├── shared
│ ├── base.go
│ ├── shared.go
│ ├── testing.go
│ ├── util.go
│ └── util_test.go
├── stdlib
│ ├── items.go
│ └── shared
│ │ └── models.go
├── transformer.go
└── transformer_test.go
├── stdlib-source
├── adapters
│ ├── certificate.go
│ ├── certificate_test.go
│ ├── dns.go
│ ├── dns_test.go
│ ├── http.go
│ ├── http_test.go
│ ├── ip.go
│ ├── ip_cache.go
│ ├── ip_cache_test.go
│ ├── ip_test.go
│ ├── main.go
│ ├── main_test.go
│ ├── rdap-asn.go
│ ├── rdap-asn_test.go
│ ├── rdap-domain.go
│ ├── rdap-domain_test.go
│ ├── rdap-entity.go
│ ├── rdap-entity_test.go
│ ├── rdap-ip-network.go
│ ├── rdap-ip-network_test.go
│ ├── rdap-nameserver.go
│ ├── rdap-nameserver_test.go
│ └── test
│ │ ├── data.go
│ │ ├── testdog.go
│ │ ├── testfood.go
│ │ ├── testgroup.go
│ │ ├── testhobby.go
│ │ ├── testlocation.go
│ │ ├── testperson.go
│ │ └── testregion.go
├── build
│ └── package
│ │ └── Dockerfile
├── cmd
│ └── root.go
└── main.go
├── tfutils
├── aws_config.go
├── aws_config_test.go
├── plan.go
├── plan_mapper.go
├── plan_mapper_test.go
└── testdata
│ ├── config_from_provider
│ ├── ca-bundle.crt
│ └── test.tf
│ ├── invalid_vars.tfvars
│ ├── plan.json
│ ├── providers.tf
│ ├── state.json
│ ├── subfolder
│ └── more_providers.tf
│ ├── test_vars.tfvars
│ └── tfvars.json
└── tracing
├── deferlog.go
├── main.go
└── main_test.go
/.github/e2eapply.tape:
--------------------------------------------------------------------------------
1 | Output e2e/apply.mp4
2 |
3 | Set Width 1920
4 | Set Height 1080
5 |
6 | Set FontSize 12
7 | Set CursorBlink false
8 |
9 | Hide
10 | Type "export PATH=$PWD:$PATH"
11 | Enter
12 | Type "clear"
13 | Enter
14 | Show
15 |
16 | Type@1ms "overmind terraform apply -- tfplan"
17 | Enter
18 | Sleep 70
19 | Screenshot e2e/apply.png
20 |
--------------------------------------------------------------------------------
/.github/e2eplan.tape:
--------------------------------------------------------------------------------
1 | Output e2e/plan.mp4
2 |
3 | Set Width 1920
4 | Set Height 1080
5 |
6 | Set FontSize 12
7 | Set CursorBlink false
8 |
9 | Hide
10 | Type "export PATH=$PWD:$PATH"
11 | Enter
12 | Type "clear"
13 | Enter
14 | Show
15 |
16 | Type@1ms "overmind terraform plan -- -out tfplan"
17 | Enter
18 | Sleep 2
19 | Enter
20 | Sleep 80
21 | Screenshot e2e/plan.png
22 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Run Tests
2 | on: push
3 | jobs:
4 | test:
5 | name: Run Tests
6 | runs-on: depot-ubuntu-22.04-4
7 |
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v4
11 | with:
12 | fetch-depth: 0
13 |
14 | - name: Set up Go
15 | uses: actions/setup-go@v5
16 | with:
17 | go-version: 1.x
18 | check-latest: true
19 | cache: true
20 |
21 | - name: Go Test
22 | run: |
23 | go run main.go --version
24 | go test -race -v -timeout 5m github.com/overmindtech/cli github.com/overmindtech/cli/tfutils
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # If you prefer the allow list template instead of the deny list, see community template:
2 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3 | #
4 | # Binaries for programs and plugins
5 | *.exe
6 | *.exe~
7 | *.dll
8 | *.so
9 | *.dylib
10 |
11 | # Test binary, built with `go test -c`
12 | *.test
13 | gon
14 |
15 | # Output of the go coverage tool, specifically when used with LiteIDE
16 | *.out
17 |
18 | # Dependency directories (remove the comment below to include it)
19 | # vendor/
20 |
21 | # Go workspace file
22 | go.work
23 |
24 | dist/
25 | output
26 | .DS_Store
27 | .terraform
28 | overmind.plan
29 | terraform.tfstate
30 | terraform.tfstate.backup
31 | /tmp/
32 | /node_modules
33 | __debug_bin*
34 |
35 | # ignore local terraform files
36 | tfplan.json*
37 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Releasing a new cli version
2 |
3 | - Make sure that main is green before proceeding! Then in the CLI directory, update to latest.
4 |
5 | ```shell
6 | git fetch --all
7 | git rebase origin/main
8 | ```
9 |
10 | - Compare the changes from the last release to what is in main. For [example](https://github.com/overmindtech/cli/compare/v1.3.2...main). Following [semver](https://semver.org/) choose your new version. And use it to tag a version, and push it.
11 |
12 | ```shell
13 | git tag -s v0.0.0
14 | git push origin tag v0.0.0
15 | ```
16 |
17 | - Github actions will then run, assuming everything goes green. It will create a new [pull request in overmind/homebrew-overmind](https://github.com/overmindtech/homebrew-overmind/pulls).
18 | - **DO NOT MERGE THE PR YET** If this PR is green the PR it will require the 'pr-pull' label to be added. It will trigger another github action / check to run. This will automerge the PR and the release is complete.
19 |
--------------------------------------------------------------------------------
/assets/blastRadiusItems.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/blastRadiusItems.png
--------------------------------------------------------------------------------
/assets/chainLink.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/chainLink.png
--------------------------------------------------------------------------------
/assets/change.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/change.png
--------------------------------------------------------------------------------
/assets/change.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/assets/changed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/changed.png
--------------------------------------------------------------------------------
/assets/changed.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/created.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/created.png
--------------------------------------------------------------------------------
/assets/created.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/deleted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/deleted.png
--------------------------------------------------------------------------------
/assets/deleted.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/edge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/edge.png
--------------------------------------------------------------------------------
/assets/high.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/high.png
--------------------------------------------------------------------------------
/assets/high.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/item.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/item.png
--------------------------------------------------------------------------------
/assets/item.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/logo.png
--------------------------------------------------------------------------------
/assets/low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/low.png
--------------------------------------------------------------------------------
/assets/low.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/medium.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/medium.png
--------------------------------------------------------------------------------
/assets/medium.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/assets/replaced.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/replaced.png
--------------------------------------------------------------------------------
/assets/replaced.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/risks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/overmindtech/cli/55bfbc5cc407d95db54c909903f0223fb51171ec/assets/risks.png
--------------------------------------------------------------------------------
/assets/risks.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/unchanged.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/assets/unmapped.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/auth/tracing.go:
--------------------------------------------------------------------------------
1 | package auth
2 |
3 | import (
4 | "go.opentelemetry.io/otel"
5 | semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
6 | "go.opentelemetry.io/otel/trace"
7 | )
8 |
9 | const (
10 | instrumentationName = "github.com/overmindtech/cli/auth"
11 | instrumentationVersion = "0.0.1"
12 | )
13 |
14 | var tracer = otel.GetTracerProvider().Tracer(
15 | instrumentationName,
16 | trace.WithInstrumentationVersion(instrumentationVersion),
17 | trace.WithSchemaURL(semconv.SchemaURL),
18 | )
19 |
--------------------------------------------------------------------------------
/aws-source/.deadcode-ignore:
--------------------------------------------------------------------------------
1 | adapterhelpers/shared_tests.go:19:6: unreachable func: PtrInt32
2 | adapterhelpers/shared_tests.go:27:6: unreachable func: PtrFloat32
3 | adapterhelpers/shared_tests.go:31:6: unreachable func: PtrFloat64
4 | adapterhelpers/shared_tests.go:35:6: unreachable func: PtrTime
5 | adapterhelpers/shared_tests.go:39:6: unreachable func: PtrBool
6 | adapterhelpers/shared_tests.go:73:21: unreachable func: VPCConfig.Cleanup
7 | adapterhelpers/shared_tests.go:77:21: unreachable func: VPCConfig.RunCleanup
8 | adapterhelpers/shared_tests.go:88:21: unreachable func: VPCConfig.Fetch
9 | adapterhelpers/shared_tests.go:121:21: unreachable func: VPCConfig.CreateGateway
10 | adapterhelpers/shared_tests.go:198:6: unreachable func: retry
11 | adapterhelpers/shared_tests.go:221:21: unreachable func: QueryTests.Execute
12 | adapterhelpers/shared_tests.go:238:6: unreachable func: lirMatches
13 | adapterhelpers/shared_tests.go:246:6: unreachable func: CheckQuery
14 | adapterhelpers/util.go:180:18: unreachable func: E2ETest.Run
15 | adapterhelpers/util.go:326:6: unreachable func: GetAutoConfig
16 | adapters/rds.go:25:24: unreachable func: mockRdsClient.DescribeDBClusterParameterGroups
17 | adapters/rds.go:29:24: unreachable func: mockRdsClient.DescribeDBClusterParameters
18 | adapters/rds.go:33:24: unreachable func: mockRdsClient.ListTagsForResource
19 | adapters/rds.go:44:24: unreachable func: mockRdsClient.DescribeDBClusters
20 | adapters/rds.go:48:24: unreachable func: mockRdsClient.DescribeDBInstances
21 | adapters/rds.go:52:24: unreachable func: mockRdsClient.DescribeDBSubnetGroups
22 | adapters/rds.go:56:24: unreachable func: mockRdsClient.DescribeOptionGroups
23 | adapters/rds.go:60:24: unreachable func: mockRdsClient.DescribeDBParameterGroups
24 | adapters/rds.go:64:24: unreachable func: mockRdsClient.DescribeDBParameters
25 |
--------------------------------------------------------------------------------
/aws-source/acceptance/nats-server.conf:
--------------------------------------------------------------------------------
1 | # Client port of 4222 on all interfaces
2 | port: 4222
3 |
4 | # HTTP monitoring port
5 | monitor_port: 8222
6 |
7 | # This is for clustering multiple servers together.
8 | cluster {
9 | # It is recommended to set a cluster name
10 | name: "my_cluster"
11 |
12 | # Route connections to be received on any interface on port 6222
13 | port: 6222
14 |
15 | # Routes are protected, so need to use them with --routes flag
16 | # e.g. --routes=nats-route://ruser:T0pS3cr3t@otherdockerhost:6222
17 | authorization {
18 | user: ruser
19 | timeout: 0.75
20 | }
21 |
22 | # Routes are actively solicited and connected to from this server.
23 | # This Docker image has none by default, but you can pass a
24 | # flag to the nats-server docker image to create one to an existing server.
25 | routes = []
26 | }
27 |
28 | websocket {
29 | port: 4433
30 | no_tls: true
31 | }
32 |
--------------------------------------------------------------------------------
/aws-source/adapters/apigateway-api-key_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/aws"
8 | "github.com/aws/aws-sdk-go-v2/service/apigateway"
9 | "github.com/aws/aws-sdk-go-v2/service/apigateway/types"
10 |
11 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
12 | "github.com/overmindtech/cli/sdp-go"
13 | )
14 |
15 | func TestApiKeyOutputMapper(t *testing.T) {
16 | awsItem := &types.ApiKey{
17 | Id: aws.String("api-key-id"),
18 | Name: aws.String("api-key-name"),
19 | Enabled: true,
20 | CreatedDate: aws.Time(time.Now()),
21 | LastUpdatedDate: aws.Time(time.Now()),
22 | StageKeys: []string{"rest-api-id/stage"},
23 | Tags: map[string]string{"key": "value"},
24 | }
25 |
26 | item, err := apiKeyOutputMapper("scope", awsItem)
27 | if err != nil {
28 | t.Fatalf("unexpected error: %v", err)
29 | }
30 |
31 | if err := item.Validate(); err != nil {
32 | t.Error(err)
33 | }
34 |
35 | tests := adapterhelpers.QueryTests{
36 | {
37 | ExpectedType: "apigateway-rest-api",
38 | ExpectedMethod: sdp.QueryMethod_GET,
39 | ExpectedQuery: "rest-api-id",
40 | ExpectedScope: "scope",
41 | },
42 | }
43 |
44 | tests.Execute(t, item)
45 | }
46 |
47 | func TestNewAPIGatewayApiKeyAdapter(t *testing.T) {
48 | config, account, region := adapterhelpers.GetAutoConfig(t)
49 |
50 | client := apigateway.NewFromConfig(config)
51 |
52 | adapter := NewAPIGatewayApiKeyAdapter(client, account, region)
53 |
54 | test := adapterhelpers.E2ETest{
55 | Adapter: adapter,
56 | Timeout: 10 * time.Second,
57 | SkipList: true,
58 | }
59 |
60 | test.Run(t)
61 | }
62 |
--------------------------------------------------------------------------------
/aws-source/adapters/apigateway-deployment_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/aws"
8 | "github.com/aws/aws-sdk-go-v2/service/apigateway"
9 | "github.com/aws/aws-sdk-go-v2/service/apigateway/types"
10 |
11 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
12 | "github.com/overmindtech/cli/sdp-go"
13 | )
14 |
15 | func TestDeploymentOutputMapper(t *testing.T) {
16 | awsItem := &types.Deployment{
17 | Id: aws.String("deployment-id"),
18 | CreatedDate: aws.Time(time.Now()),
19 | Description: aws.String("deployment-description"),
20 | ApiSummary: map[string]map[string]types.MethodSnapshot{},
21 | }
22 |
23 | item, err := deploymentOutputMapper("rest-api-id", "scope", awsItem)
24 | if err != nil {
25 | t.Fatalf("unexpected error: %v", err)
26 | }
27 |
28 | if err := item.Validate(); err != nil {
29 | t.Error(err)
30 | }
31 |
32 | tests := adapterhelpers.QueryTests{
33 | {
34 | ExpectedType: "apigateway-rest-api",
35 | ExpectedMethod: sdp.QueryMethod_GET,
36 | ExpectedQuery: "rest-api-id",
37 | ExpectedScope: "scope",
38 | },
39 | {
40 | ExpectedType: "apigateway-stage",
41 | ExpectedMethod: sdp.QueryMethod_SEARCH,
42 | ExpectedQuery: "rest-api-id/deployment-id",
43 | ExpectedScope: "scope",
44 | },
45 | }
46 |
47 | tests.Execute(t, item)
48 | }
49 |
50 | func TestNewAPIGatewayDeploymentAdapter(t *testing.T) {
51 | config, account, region := adapterhelpers.GetAutoConfig(t)
52 |
53 | client := apigateway.NewFromConfig(config)
54 |
55 | adapter := NewAPIGatewayDeploymentAdapter(client, account, region)
56 |
57 | test := adapterhelpers.E2ETest{
58 | Adapter: adapter,
59 | Timeout: 10 * time.Second,
60 | SkipList: true,
61 | }
62 |
63 | test.Run(t)
64 | }
65 |
--------------------------------------------------------------------------------
/aws-source/adapters/apigateway-model_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/aws"
8 | "github.com/aws/aws-sdk-go-v2/service/apigateway"
9 | "github.com/aws/aws-sdk-go-v2/service/apigateway/types"
10 |
11 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
12 | "github.com/overmindtech/cli/sdp-go"
13 | )
14 |
15 | func TestModelOutputMapper(t *testing.T) {
16 | awsItem := &types.Model{
17 | Id: aws.String("model-id"),
18 | Name: aws.String("model-name"),
19 | Description: aws.String("description"),
20 | Schema: aws.String("{\"type\": \"object\"}"),
21 | ContentType: aws.String("application/json"),
22 | }
23 |
24 | item, err := modelOutputMapper("rest-api-id/model-name", "scope", awsItem)
25 | if err != nil {
26 | t.Fatalf("unexpected error: %v", err)
27 | }
28 |
29 | if err := item.Validate(); err != nil {
30 | t.Error(err)
31 | }
32 |
33 | tests := adapterhelpers.QueryTests{
34 | {
35 | ExpectedType: "apigateway-rest-api",
36 | ExpectedMethod: sdp.QueryMethod_GET,
37 | ExpectedQuery: "rest-api-id",
38 | ExpectedScope: "scope",
39 | },
40 | }
41 |
42 | tests.Execute(t, item)
43 | }
44 |
45 | func TestNewAPIGatewayModelAdapter(t *testing.T) {
46 | config, account, region := adapterhelpers.GetAutoConfig(t)
47 |
48 | client := apigateway.NewFromConfig(config)
49 |
50 | adapter := NewAPIGatewayModelAdapter(client, account, region)
51 |
52 | test := adapterhelpers.E2ETest{
53 | Adapter: adapter,
54 | Timeout: 10 * time.Second,
55 | SkipList: true,
56 | }
57 |
58 | test.Run(t)
59 | }
60 |
--------------------------------------------------------------------------------
/aws-source/adapters/cloudfront-function_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | )
10 |
11 | func TestFunctionItemMapper(t *testing.T) {
12 | summary := types.FunctionSummary{
13 | FunctionConfig: &types.FunctionConfig{
14 | Comment: adapterhelpers.PtrString("test-comment"),
15 | Runtime: types.FunctionRuntimeCloudfrontJs20,
16 | },
17 | FunctionMetadata: &types.FunctionMetadata{
18 | FunctionARN: adapterhelpers.PtrString("arn:aws:cloudfront::123456789012:function/test-function"),
19 | LastModifiedTime: adapterhelpers.PtrTime(time.Now()),
20 | CreatedTime: adapterhelpers.PtrTime(time.Now()),
21 | Stage: types.FunctionStageLive,
22 | },
23 | Name: adapterhelpers.PtrString("test-function"),
24 | Status: adapterhelpers.PtrString("test-status"),
25 | }
26 |
27 | item, err := functionItemMapper("", "test", &summary)
28 |
29 | if err != nil {
30 | t.Fatal(err)
31 | }
32 |
33 | if err = item.Validate(); err != nil {
34 | t.Error(err)
35 | }
36 | }
37 |
38 | func TestNewCloudfrontCloudfrontFunctionAdapter(t *testing.T) {
39 | client, account, _ := CloudfrontGetAutoConfig(t)
40 |
41 | adapter := NewCloudfrontCloudfrontFunctionAdapter(client, account)
42 |
43 | test := adapterhelpers.E2ETest{
44 | Adapter: adapter,
45 | Timeout: 10 * time.Second,
46 | }
47 |
48 | test.Run(t)
49 | }
50 |
--------------------------------------------------------------------------------
/aws-source/adapters/cloudfront-key-group_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | )
10 |
11 | func TestKeyGroupItemMapper(t *testing.T) {
12 | group := types.KeyGroup{
13 | Id: adapterhelpers.PtrString("test-id"),
14 | KeyGroupConfig: &types.KeyGroupConfig{
15 | Items: []string{
16 | "some-identity",
17 | },
18 | Name: adapterhelpers.PtrString("test-name"),
19 | Comment: adapterhelpers.PtrString("test-comment"),
20 | },
21 | LastModifiedTime: adapterhelpers.PtrTime(time.Now()),
22 | }
23 |
24 | item, err := KeyGroupItemMapper("", "test", &group)
25 |
26 | if err != nil {
27 | t.Fatal(err)
28 | }
29 |
30 | if err = item.Validate(); err != nil {
31 | t.Error(err)
32 | }
33 | }
34 |
35 | func TestNewCloudfrontKeyGroupAdapter(t *testing.T) {
36 | client, account, _ := CloudfrontGetAutoConfig(t)
37 |
38 | adapter := NewCloudfrontKeyGroupAdapter(client, account)
39 |
40 | test := adapterhelpers.E2ETest{
41 | Adapter: adapter,
42 | Timeout: 10 * time.Second,
43 | }
44 |
45 | test.Run(t)
46 | }
47 |
--------------------------------------------------------------------------------
/aws-source/adapters/cloudfront-origin-access-control_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | )
10 |
11 | func TestOriginAccessControlItemMapper(t *testing.T) {
12 | x := types.OriginAccessControl{
13 | Id: adapterhelpers.PtrString("test"),
14 | OriginAccessControlConfig: &types.OriginAccessControlConfig{
15 | Name: adapterhelpers.PtrString("example-name"),
16 | OriginAccessControlOriginType: types.OriginAccessControlOriginTypesS3,
17 | SigningBehavior: types.OriginAccessControlSigningBehaviorsAlways,
18 | SigningProtocol: types.OriginAccessControlSigningProtocolsSigv4,
19 | Description: adapterhelpers.PtrString("example-description"),
20 | },
21 | }
22 |
23 | item, err := originAccessControlItemMapper("", "test", &x)
24 |
25 | if err != nil {
26 | t.Fatal(err)
27 | }
28 |
29 | if err = item.Validate(); err != nil {
30 | t.Error(err)
31 | }
32 | }
33 |
34 | func TestNewCloudfrontOriginAccessControlAdapter(t *testing.T) {
35 | client, account, _ := CloudfrontGetAutoConfig(t)
36 |
37 | adapter := NewCloudfrontOriginAccessControlAdapter(client, account)
38 |
39 | test := adapterhelpers.E2ETest{
40 | Adapter: adapter,
41 | Timeout: 10 * time.Second,
42 | }
43 |
44 | test.Run(t)
45 | }
46 |
--------------------------------------------------------------------------------
/aws-source/adapters/cloudfront.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/cloudfront"
7 | "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
8 | )
9 |
10 | // Converts a CloudFront Tags object to a map
11 | func cloudfrontTagsToMap(tags *types.Tags) map[string]string {
12 | if tags == nil {
13 | return nil
14 | }
15 |
16 | tagMap := make(map[string]string)
17 |
18 | for _, tag := range tags.Items {
19 | if tag.Key != nil && tag.Value != nil {
20 | tagMap[*tag.Key] = *tag.Value
21 | }
22 | }
23 |
24 | return tagMap
25 | }
26 |
27 | type CloudFrontClient interface {
28 | GetCachePolicy(ctx context.Context, params *cloudfront.GetCachePolicyInput, optFns ...func(*cloudfront.Options)) (*cloudfront.GetCachePolicyOutput, error)
29 | ListCachePolicies(ctx context.Context, params *cloudfront.ListCachePoliciesInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListCachePoliciesOutput, error)
30 |
31 | GetDistribution(ctx context.Context, params *cloudfront.GetDistributionInput, optFns ...func(*cloudfront.Options)) (*cloudfront.GetDistributionOutput, error)
32 | ListDistributions(ctx context.Context, params *cloudfront.ListDistributionsInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListDistributionsOutput, error)
33 |
34 | GetStreamingDistribution(ctx context.Context, params *cloudfront.GetStreamingDistributionInput, optFns ...func(*cloudfront.Options)) (*cloudfront.GetStreamingDistributionOutput, error)
35 | ListStreamingDistributions(ctx context.Context, params *cloudfront.ListStreamingDistributionsInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListStreamingDistributionsOutput, error)
36 |
37 | ListTagsForResource(ctx context.Context, params *cloudfront.ListTagsForResourceInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListTagsForResourceOutput, error)
38 | }
39 |
--------------------------------------------------------------------------------
/aws-source/adapters/cloudfront_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/cloudfront"
8 | "github.com/aws/aws-sdk-go-v2/service/cloudfront/types"
9 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
10 | )
11 |
12 | func (c TestCloudFrontClient) ListTagsForResource(ctx context.Context, params *cloudfront.ListTagsForResourceInput, optFns ...func(*cloudfront.Options)) (*cloudfront.ListTagsForResourceOutput, error) {
13 | return &cloudfront.ListTagsForResourceOutput{
14 | Tags: &types.Tags{
15 | Items: []types.Tag{
16 | {
17 | Key: adapterhelpers.PtrString("foo"),
18 | Value: adapterhelpers.PtrString("bar"),
19 | },
20 | },
21 | },
22 | }, nil
23 | }
24 |
25 | type TestCloudFrontClient struct{}
26 |
27 | func CloudfrontGetAutoConfig(t *testing.T) (*cloudfront.Client, string, string) {
28 | config, account, region := adapterhelpers.GetAutoConfig(t)
29 | client := cloudfront.NewFromConfig(config)
30 |
31 | return client, account, region
32 | }
33 |
--------------------------------------------------------------------------------
/aws-source/adapters/directconnect-customer-metadata_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 | "time"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/directconnect"
9 | "github.com/aws/aws-sdk-go-v2/service/directconnect/types"
10 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
11 | )
12 |
13 | func TestCustomerMetadataOutputMapper(t *testing.T) {
14 | output := &directconnect.DescribeCustomerMetadataOutput{
15 | Agreements: []types.CustomerAgreement{
16 | {
17 | AgreementName: adapterhelpers.PtrString("example-customer-agreement"),
18 | Status: adapterhelpers.PtrString("signed"),
19 | },
20 | },
21 | }
22 |
23 | items, err := customerMetadataOutputMapper(context.Background(), nil, "foo", nil, output)
24 | if err != nil {
25 | t.Fatal(err)
26 | }
27 |
28 | for _, item := range items {
29 | if err := item.Validate(); err != nil {
30 | t.Error(err)
31 | }
32 | }
33 |
34 | if len(items) != 1 {
35 | t.Fatalf("expected 1 item, got %v", len(items))
36 | }
37 | }
38 |
39 | func TestNewDirectConnectCustomerMetadataAdapter(t *testing.T) {
40 | client, account, region := directconnectGetAutoConfig(t)
41 |
42 | adapter := NewDirectConnectCustomerMetadataAdapter(client, account, region)
43 |
44 | test := adapterhelpers.E2ETest{
45 | Adapter: adapter,
46 | Timeout: 10 * time.Second,
47 | }
48 |
49 | test.Run(t)
50 | }
51 |
--------------------------------------------------------------------------------
/aws-source/adapters/directconnect-location_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 | "time"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/directconnect"
9 | "github.com/aws/aws-sdk-go-v2/service/directconnect/types"
10 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
11 | )
12 |
13 | func TestLocationOutputMapper(t *testing.T) {
14 | output := &directconnect.DescribeLocationsOutput{
15 | Locations: []types.Location{
16 | {
17 | AvailableMacSecPortSpeeds: []string{"1 Gbps", "10 Gbps"},
18 | AvailablePortSpeeds: []string{"50 Mbps", "100 Mbps", "1 Gbps", "10 Gbps"},
19 | AvailableProviders: []string{"ProviderA", "ProviderB", "ProviderC"},
20 | LocationName: adapterhelpers.PtrString("NAP do Brasil, Barueri, Sao Paulo"),
21 | LocationCode: adapterhelpers.PtrString("TNDB"),
22 | Region: adapterhelpers.PtrString("us-east-1"),
23 | },
24 | },
25 | }
26 |
27 | items, err := locationOutputMapper(context.Background(), nil, "foo", nil, output)
28 | if err != nil {
29 | t.Fatal(err)
30 | }
31 |
32 | for _, item := range items {
33 | if err := item.Validate(); err != nil {
34 | t.Error(err)
35 | }
36 | }
37 |
38 | if len(items) != 1 {
39 | t.Fatalf("expected 1 item, got %v", len(items))
40 | }
41 | }
42 |
43 | func TestNewDirectConnectLocationAdapter(t *testing.T) {
44 | client, account, region := directconnectGetAutoConfig(t)
45 |
46 | adapter := NewDirectConnectLocationAdapter(client, account, region)
47 |
48 | test := adapterhelpers.E2ETest{
49 | Adapter: adapter,
50 | Timeout: 10 * time.Second,
51 | }
52 |
53 | test.Run(t)
54 | }
55 |
--------------------------------------------------------------------------------
/aws-source/adapters/directconnect-virtual-gateway_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 | "time"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/directconnect"
9 | "github.com/aws/aws-sdk-go-v2/service/directconnect/types"
10 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
11 | )
12 |
13 | func TestVirtualGatewayOutputMapper(t *testing.T) {
14 | output := &directconnect.DescribeVirtualGatewaysOutput{
15 | VirtualGateways: []types.VirtualGateway{
16 | {
17 | VirtualGatewayId: adapterhelpers.PtrString("cf68415c-f4ae-48f2-87a7-3b52cexample"),
18 | VirtualGatewayState: adapterhelpers.PtrString("available"),
19 | },
20 | },
21 | }
22 |
23 | items, err := virtualGatewayOutputMapper(context.Background(), nil, "foo", nil, output)
24 | if err != nil {
25 | t.Fatal(err)
26 | }
27 |
28 | for _, item := range items {
29 | if err := item.Validate(); err != nil {
30 | t.Error(err)
31 | }
32 | }
33 |
34 | if len(items) != 1 {
35 | t.Fatalf("expected 1 item, got %v", len(items))
36 | }
37 | }
38 |
39 | func TestNewDirectConnectVirtualGatewayAdapter(t *testing.T) {
40 | client, account, region := directconnectGetAutoConfig(t)
41 |
42 | adapter := NewDirectConnectVirtualGatewayAdapter(client, account, region)
43 |
44 | test := adapterhelpers.E2ETest{
45 | Adapter: adapter,
46 | Timeout: 10 * time.Second,
47 | }
48 |
49 | test.Run(t)
50 | }
51 |
--------------------------------------------------------------------------------
/aws-source/adapters/directconnect.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/directconnect"
7 | "github.com/aws/aws-sdk-go-v2/service/directconnect/types"
8 | )
9 |
10 | // Converts a slice of tags to a map
11 | func directconnectTagsToMap(tags []types.Tag) map[string]string {
12 | tagsMap := make(map[string]string)
13 |
14 | for _, tag := range tags {
15 | if tag.Key != nil && tag.Value != nil {
16 | tagsMap[*tag.Key] = *tag.Value
17 | }
18 | }
19 |
20 | return tagsMap
21 | }
22 |
23 | func arnToTags(ctx context.Context, cli *directconnect.Client, resourceARNs []string) (map[string][]types.Tag, error) {
24 | if cli == nil {
25 | return nil, nil
26 | }
27 |
28 | tagsOutput, err := cli.DescribeTags(ctx, &directconnect.DescribeTagsInput{
29 | ResourceArns: resourceARNs,
30 | })
31 | if err != nil {
32 | return nil, err
33 | }
34 |
35 | tags := make(map[string][]types.Tag, len(tagsOutput.ResourceTags))
36 | for _, tag := range tagsOutput.ResourceTags {
37 | tags[*tag.ResourceArn] = tag.Tags
38 | }
39 |
40 | return tags, nil
41 | }
42 |
--------------------------------------------------------------------------------
/aws-source/adapters/directconnect_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/directconnect"
7 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
8 | )
9 |
10 | func directconnectGetAutoConfig(t *testing.T) (*directconnect.Client, string, string) {
11 | config, account, region := adapterhelpers.GetAutoConfig(t)
12 | client := directconnect.NewFromConfig(config)
13 |
14 | return client, account, region
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/dynamodb.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/dynamodb"
7 | )
8 |
9 | type Client interface {
10 | DescribeKinesisStreamingDestination(ctx context.Context, params *dynamodb.DescribeKinesisStreamingDestinationInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeKinesisStreamingDestinationOutput, error)
11 | DescribeBackup(ctx context.Context, params *dynamodb.DescribeBackupInput, optFns ...func(*dynamodb.Options)) (*dynamodb.DescribeBackupOutput, error)
12 | ListBackups(ctx context.Context, params *dynamodb.ListBackupsInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListBackupsOutput, error)
13 | ListTagsOfResource(ctx context.Context, params *dynamodb.ListTagsOfResourceInput, optFns ...func(*dynamodb.Options)) (*dynamodb.ListTagsOfResourceOutput, error)
14 |
15 | dynamodb.DescribeTableAPIClient
16 | dynamodb.ListTablesAPIClient
17 | }
18 |
--------------------------------------------------------------------------------
/aws-source/adapters/dynamodb_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | type DynamoDBTestClient struct{}
4 |
--------------------------------------------------------------------------------
/aws-source/adapters/ec2.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import "github.com/aws/aws-sdk-go-v2/service/ec2/types"
4 |
5 | // Converts a slice of tags to a map
6 | func ec2TagsToMap(tags []types.Tag) map[string]string {
7 | tagsMap := make(map[string]string)
8 |
9 | for _, tag := range tags {
10 | if tag.Key != nil && tag.Value != nil {
11 | tagsMap[*tag.Key] = *tag.Value
12 | }
13 | }
14 |
15 | return tagsMap
16 | }
17 |
--------------------------------------------------------------------------------
/aws-source/adapters/ec2_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/ec2"
7 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
8 | )
9 |
10 | func ec2GetAutoConfig(t *testing.T) (*ec2.Client, string, string) {
11 | config, account, region := adapterhelpers.GetAutoConfig(t)
12 | client := ec2.NewFromConfig(config)
13 |
14 | return client, account, region
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/ecs.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/ecs"
7 | "github.com/aws/aws-sdk-go-v2/service/ecs/types"
8 | )
9 |
10 | type ECSClient interface {
11 | DescribeClusters(ctx context.Context, params *ecs.DescribeClustersInput, optFns ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error)
12 | DescribeCapacityProviders(ctx context.Context, params *ecs.DescribeCapacityProvidersInput, optFns ...func(*ecs.Options)) (*ecs.DescribeCapacityProvidersOutput, error)
13 | DescribeContainerInstances(ctx context.Context, params *ecs.DescribeContainerInstancesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeContainerInstancesOutput, error)
14 | DescribeServices(ctx context.Context, params *ecs.DescribeServicesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error)
15 | DescribeTaskDefinition(ctx context.Context, params *ecs.DescribeTaskDefinitionInput, optFns ...func(*ecs.Options)) (*ecs.DescribeTaskDefinitionOutput, error)
16 | DescribeTasks(ctx context.Context, params *ecs.DescribeTasksInput, optFns ...func(*ecs.Options)) (*ecs.DescribeTasksOutput, error)
17 |
18 | ecs.ListClustersAPIClient
19 | ecs.ListContainerInstancesAPIClient
20 | ecs.ListServicesAPIClient
21 | ecs.ListTaskDefinitionsAPIClient
22 | ecs.ListTasksAPIClient
23 | }
24 |
25 | // convertTags converts slice of ecs tags to a map
26 | func ecsTagsToMap(tags []types.Tag) map[string]string {
27 | tagsMap := make(map[string]string)
28 |
29 | for _, tag := range tags {
30 | if tag.Key != nil && tag.Value != nil {
31 | tagsMap[*tag.Key] = *tag.Value
32 | }
33 | }
34 |
35 | return tagsMap
36 | }
37 |
--------------------------------------------------------------------------------
/aws-source/adapters/ecs_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/ecs"
7 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
8 | )
9 |
10 | type ecsTestClient struct{}
11 |
12 | func ecsGetAutoConfig(t *testing.T) (*ecs.Client, string, string) {
13 | config, account, region := adapterhelpers.GetAutoConfig(t)
14 | client := ecs.NewFromConfig(config)
15 |
16 | return client, account, region
17 | }
18 |
--------------------------------------------------------------------------------
/aws-source/adapters/efs-backup-policy_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/efs"
8 | "github.com/aws/aws-sdk-go-v2/service/efs/types"
9 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
10 | )
11 |
12 | func TestBackupPolicyOutputMapper(t *testing.T) {
13 | output := &efs.DescribeBackupPolicyOutput{
14 | BackupPolicy: &types.BackupPolicy{
15 | Status: types.StatusEnabled,
16 | },
17 | }
18 |
19 | items, err := BackupPolicyOutputMapper(context.Background(), nil, "foo", &efs.DescribeBackupPolicyInput{
20 | FileSystemId: adapterhelpers.PtrString("fs-1234"),
21 | }, output)
22 |
23 | if err != nil {
24 | t.Fatal(err)
25 | }
26 |
27 | for _, item := range items {
28 | if err := item.Validate(); err != nil {
29 | t.Error(err)
30 | }
31 | }
32 |
33 | if len(items) != 1 {
34 | t.Fatalf("expected 1 item, got %v", len(items))
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/aws-source/adapters/efs.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/aws/aws-sdk-go-v2/service/efs/types"
5 | "github.com/overmindtech/cli/sdp-go"
6 | )
7 |
8 | // lifeCycleStateToHealth Converts a lifecycle state to a health state
9 | func lifeCycleStateToHealth(state types.LifeCycleState) *sdp.Health {
10 | switch state {
11 | case types.LifeCycleStateCreating:
12 | return sdp.Health_HEALTH_PENDING.Enum()
13 | case types.LifeCycleStateAvailable:
14 | return sdp.Health_HEALTH_OK.Enum()
15 | case types.LifeCycleStateUpdating:
16 | return sdp.Health_HEALTH_PENDING.Enum()
17 | case types.LifeCycleStateDeleting:
18 | return sdp.Health_HEALTH_PENDING.Enum()
19 | case types.LifeCycleStateDeleted:
20 | return sdp.Health_HEALTH_WARNING.Enum()
21 | case types.LifeCycleStateError:
22 | return sdp.Health_HEALTH_ERROR.Enum()
23 | }
24 |
25 | return nil
26 | }
27 |
28 | // Converts a slice of tags to a map
29 | func efsTagsToMap(tags []types.Tag) map[string]string {
30 | tagsMap := make(map[string]string)
31 |
32 | for _, tag := range tags {
33 | if tag.Key != nil && tag.Value != nil {
34 | tagsMap[*tag.Key] = *tag.Value
35 | }
36 | }
37 |
38 | return tagsMap
39 | }
40 |
--------------------------------------------------------------------------------
/aws-source/adapters/efs_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/efs"
7 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
8 | )
9 |
10 | func efsGetAutoConfig(t *testing.T) (*efs.Client, string, string) {
11 | config, account, region := adapterhelpers.GetAutoConfig(t)
12 | client := efs.NewFromConfig(config)
13 |
14 | return client, account, region
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/eks.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/eks"
7 | )
8 |
9 | type EKSClient interface {
10 | ListClusters(context.Context, *eks.ListClustersInput, ...func(*eks.Options)) (*eks.ListClustersOutput, error)
11 | DescribeCluster(ctx context.Context, params *eks.DescribeClusterInput, optFns ...func(*eks.Options)) (*eks.DescribeClusterOutput, error)
12 | ListAddons(context.Context, *eks.ListAddonsInput, ...func(*eks.Options)) (*eks.ListAddonsOutput, error)
13 | DescribeAddon(ctx context.Context, params *eks.DescribeAddonInput, optFns ...func(*eks.Options)) (*eks.DescribeAddonOutput, error)
14 | ListFargateProfiles(ctx context.Context, params *eks.ListFargateProfilesInput, optFns ...func(*eks.Options)) (*eks.ListFargateProfilesOutput, error)
15 | DescribeFargateProfile(ctx context.Context, params *eks.DescribeFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DescribeFargateProfileOutput, error)
16 | ListIdentityProviderConfigs(ctx context.Context, params *eks.ListIdentityProviderConfigsInput, optFns ...func(*eks.Options)) (*eks.ListIdentityProviderConfigsOutput, error)
17 | DescribeIdentityProviderConfig(ctx context.Context, params *eks.DescribeIdentityProviderConfigInput, optFns ...func(*eks.Options)) (*eks.DescribeIdentityProviderConfigOutput, error)
18 | ListNodegroups(ctx context.Context, params *eks.ListNodegroupsInput, optFns ...func(*eks.Options)) (*eks.ListNodegroupsOutput, error)
19 | DescribeNodegroup(ctx context.Context, params *eks.DescribeNodegroupInput, optFns ...func(*eks.Options)) (*eks.DescribeNodegroupOutput, error)
20 | }
21 |
--------------------------------------------------------------------------------
/aws-source/adapters/elb-instance-health_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | elb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing"
8 | "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types"
9 |
10 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
11 | "github.com/overmindtech/cli/sdp-go"
12 | )
13 |
14 | func TestInstanceHealthOutputMapper(t *testing.T) {
15 |
16 | output := elb.DescribeInstanceHealthOutput{
17 | InstanceStates: []types.InstanceState{
18 | {
19 | InstanceId: adapterhelpers.PtrString("i-0337802d908b4a81e"), // link
20 | State: adapterhelpers.PtrString("InService"),
21 | ReasonCode: adapterhelpers.PtrString("N/A"),
22 | Description: adapterhelpers.PtrString("N/A"),
23 | },
24 | },
25 | }
26 |
27 | items, err := instanceHealthOutputMapper(context.Background(), nil, "foo", nil, &output)
28 |
29 | if err != nil {
30 | t.Error(err)
31 | }
32 |
33 | for _, item := range items {
34 | if err := item.Validate(); err != nil {
35 | t.Error(err)
36 | }
37 | }
38 |
39 | if len(items) != 1 {
40 | t.Fatalf("expected 1 item, got %v", len(items))
41 | }
42 |
43 | item := items[0]
44 |
45 | // It doesn't really make sense to test anything other than the linked items
46 | // since the attributes are converted automatically
47 | tests := adapterhelpers.QueryTests{
48 | {
49 | ExpectedType: "ec2-instance",
50 | ExpectedMethod: sdp.QueryMethod_GET,
51 | ExpectedQuery: "i-0337802d908b4a81e",
52 | ExpectedScope: "foo",
53 | },
54 | }
55 |
56 | tests.Execute(t, item)
57 | }
58 |
--------------------------------------------------------------------------------
/aws-source/adapters/iam-group_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/aws"
8 | "github.com/aws/aws-sdk-go-v2/service/iam"
9 | "github.com/aws/aws-sdk-go-v2/service/iam/types"
10 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
11 | )
12 |
13 | func TestGroupItemMapper(t *testing.T) {
14 | zone := types.Group{
15 | Path: adapterhelpers.PtrString("/"),
16 | GroupName: adapterhelpers.PtrString("power-users"),
17 | GroupId: adapterhelpers.PtrString("AGPA3VLV2U27T6SSLJMDS"),
18 | Arn: adapterhelpers.PtrString("arn:aws:iam::801795385023:group/power-users"),
19 | CreateDate: adapterhelpers.PtrTime(time.Now()),
20 | }
21 |
22 | item, err := groupItemMapper(nil, "foo", &zone)
23 |
24 | if err != nil {
25 | t.Error(err)
26 | }
27 |
28 | if err = item.Validate(); err != nil {
29 | t.Error(err)
30 | }
31 |
32 | }
33 |
34 | func TestNewIAMGroupAdapter(t *testing.T) {
35 | config, account, _ := adapterhelpers.GetAutoConfig(t)
36 | client := iam.NewFromConfig(config, func(o *iam.Options) {
37 | o.RetryMode = aws.RetryModeAdaptive
38 | o.RetryMaxAttempts = 10
39 | })
40 |
41 | adapter := NewIAMGroupAdapter(client, account)
42 |
43 | test := adapterhelpers.E2ETest{
44 | Adapter: adapter,
45 | Timeout: 30 * time.Second,
46 | }
47 |
48 | test.Run(t)
49 | }
50 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/apigateway/delete.go:
--------------------------------------------------------------------------------
1 | package apigateway
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/apigateway"
7 |
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | )
10 |
11 | func deleteRestAPI(ctx context.Context, client *apigateway.Client, restAPIID string) error {
12 | _, err := client.DeleteRestApi(ctx, &apigateway.DeleteRestApiInput{
13 | RestApiId: adapterhelpers.PtrString(restAPIID),
14 | })
15 |
16 | return err
17 | }
18 |
19 | func deleteAPIKeyByName(ctx context.Context, client *apigateway.Client, id *string) error {
20 | _, err := client.DeleteApiKey(ctx, &apigateway.DeleteApiKeyInput{
21 | ApiKey: id,
22 | })
23 | if err != nil {
24 | return err
25 | }
26 |
27 | return nil
28 | }
29 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/apigateway/teardown.go:
--------------------------------------------------------------------------------
1 | package apigateway
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "log/slog"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/apigateway"
9 |
10 | "github.com/overmindtech/cli/aws-source/adapters/integration"
11 | )
12 |
13 | func teardown(ctx context.Context, logger *slog.Logger, client *apigateway.Client) error {
14 | restAPIID, err := findRestAPIsByTags(ctx, client)
15 | if err != nil {
16 | if nf := integration.NewNotFoundError(restAPISrc); errors.As(err, &nf) {
17 | logger.WarnContext(ctx, "Rest API not found")
18 | } else {
19 | return err
20 | }
21 | } else {
22 | err = deleteRestAPI(ctx, client, *restAPIID)
23 | if err != nil {
24 | return err
25 | }
26 | }
27 |
28 | keyName := integration.ResourceName(integration.APIGateway, apiKeySrc, integration.TestID())
29 | apiKeyID, err := findAPIKeyByName(ctx, client, keyName)
30 | if err != nil {
31 | if nf := integration.NewNotFoundError(apiKeySrc); errors.As(err, &nf) {
32 | logger.WarnContext(ctx, "API Key not found", "name", keyName)
33 | return nil
34 | } else {
35 | return err
36 | }
37 | } else {
38 | err = deleteAPIKeyByName(ctx, client, apiKeyID)
39 | if err != nil {
40 | return err
41 | }
42 | }
43 |
44 | return nil
45 | }
46 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/apigateway/util.go:
--------------------------------------------------------------------------------
1 | package apigateway
2 |
3 | import (
4 | "github.com/overmindtech/cli/aws-source/adapters/integration"
5 | )
6 |
7 | func resourceTags(resourceName, testID string, nameAdditionalAttr ...string) map[string]string {
8 | return map[string]string{
9 | integration.TagTestKey: integration.TagTestValue,
10 | integration.TagTestTypeKey: integration.TestName(integration.APIGateway),
11 | integration.TagTestIDKey: testID,
12 | integration.TagResourceIDKey: integration.ResourceName(integration.APIGateway, resourceName, nameAdditionalAttr...),
13 | }
14 | }
15 |
16 | func hasTags(tags map[string]string, requiredTags map[string]string) bool {
17 | for k, v := range requiredTags {
18 | if tags[k] != v {
19 | return false
20 | }
21 | }
22 |
23 | return true
24 | }
25 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/ec2/delete.go:
--------------------------------------------------------------------------------
1 | package ec2
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/ec2"
7 | )
8 |
9 | func deleteInstance(ctx context.Context, client *ec2.Client, instanceID string) error {
10 | input := &ec2.TerminateInstancesInput{
11 | InstanceIds: []string{instanceID},
12 | }
13 |
14 | _, err := client.TerminateInstances(ctx, input)
15 | return err
16 | }
17 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/ec2/find.go:
--------------------------------------------------------------------------------
1 | package ec2
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/ec2"
7 | "github.com/aws/aws-sdk-go-v2/service/ec2/types"
8 | "github.com/overmindtech/cli/aws-source/adapters/integration"
9 | )
10 |
11 | // findActiveInstanceIDByTags finds an instance by tags
12 | // additionalAttr is a variadic parameter that allows to specify additional attributes to search for
13 | // it ignores terminated instances
14 | func findActiveInstanceIDByTags(ctx context.Context, client *ec2.Client, additionalAttr ...string) (*string, error) {
15 | result, err := client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{})
16 | if err != nil {
17 | return nil, err
18 | }
19 |
20 | for _, reservation := range result.Reservations {
21 | for _, instance := range reservation.Instances {
22 | // ignore terminated or shutting down instances
23 | if instance.State.Name == types.InstanceStateNameTerminated ||
24 | instance.State.Name == types.InstanceStateNameShuttingDown {
25 | // ignore terminated instances
26 | continue
27 | }
28 |
29 | if hasTags(instance.Tags, resourceTags(instanceSrc, integration.TestID(), additionalAttr...)) {
30 | return instance.InstanceId, nil
31 | }
32 | }
33 | }
34 |
35 | return nil, integration.NewNotFoundError(integration.ResourceName(integration.EC2, instanceSrc, additionalAttr...))
36 | }
37 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/ec2/main_test.go:
--------------------------------------------------------------------------------
1 | package ec2
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log/slog"
7 | "os"
8 | "testing"
9 |
10 | awsec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
11 | "github.com/overmindtech/cli/aws-source/adapters/integration"
12 | )
13 |
14 | func TestMain(m *testing.M) {
15 | if integration.ShouldRunIntegrationTests() {
16 | fmt.Println("Running integration tests")
17 | os.Exit(m.Run())
18 | } else {
19 | fmt.Println("Skipping integration tests, set RUN_INTEGRATION_TESTS=true to run them")
20 | os.Exit(0)
21 | }
22 | }
23 |
24 | func TestIntegrationEC2(t *testing.T) {
25 | t.Run("Setup", Setup)
26 | t.Run("EC2", EC2)
27 | t.Run("Teardown", Teardown)
28 | }
29 |
30 | func Setup(t *testing.T) {
31 | ctx := context.Background()
32 | logger := slog.Default()
33 |
34 | var err error
35 | testClient, err := ec2Client(ctx)
36 | if err != nil {
37 | t.Fatalf("Failed to create EC2 client: %v", err)
38 | }
39 |
40 | if err := setup(ctx, logger, testClient); err != nil {
41 | t.Fatalf("Failed to setup EC2 integration tests: %v", err)
42 | }
43 | }
44 |
45 | func Teardown(t *testing.T) {
46 | ctx := context.Background()
47 | logger := slog.Default()
48 |
49 | var err error
50 | testClient, err := ec2Client(ctx)
51 | if err != nil {
52 | t.Fatalf("Failed to create EC2 client: %v", err)
53 | }
54 |
55 | if err := teardown(ctx, logger, testClient); err != nil {
56 | t.Fatalf("Failed to teardown EC2 integration tests: %v", err)
57 | }
58 | }
59 |
60 | func ec2Client(ctx context.Context) (*awsec2.Client, error) {
61 | testAWSConfig, err := integration.AWSSettings(ctx)
62 | if err != nil {
63 | return nil, fmt.Errorf("failed to get AWS settings: %w", err)
64 | }
65 |
66 | return awsec2.NewFromConfig(testAWSConfig.Config), nil
67 | }
68 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/ec2/setup.go:
--------------------------------------------------------------------------------
1 | package ec2
2 |
3 | import (
4 | "context"
5 | "log/slog"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/ec2"
8 | "github.com/overmindtech/cli/aws-source/adapters/integration"
9 | )
10 |
11 | const instanceSrc = "instance"
12 |
13 | func setup(ctx context.Context, logger *slog.Logger, client *ec2.Client) error {
14 | // Create EC2 instance
15 | return createEC2Instance(ctx, logger, client, integration.TestID())
16 | }
17 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/ec2/teardown.go:
--------------------------------------------------------------------------------
1 | package ec2
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "log/slog"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/ec2"
9 | "github.com/overmindtech/cli/aws-source/adapters/integration"
10 | )
11 |
12 | func teardown(ctx context.Context, logger *slog.Logger, client *ec2.Client) error {
13 | instanceID, err := findActiveInstanceIDByTags(ctx, client)
14 | if err != nil {
15 | nf := integration.NewNotFoundError(instanceSrc)
16 | if errors.As(err, &nf) {
17 | logger.WarnContext(ctx, "Instance not found")
18 | return nil
19 | } else {
20 | return err
21 | }
22 | }
23 |
24 | return deleteInstance(ctx, client, *instanceID)
25 | }
26 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/ec2/util.go:
--------------------------------------------------------------------------------
1 | package ec2
2 |
3 | import (
4 | "github.com/aws/aws-sdk-go-v2/aws"
5 | "github.com/aws/aws-sdk-go-v2/service/ec2/types"
6 | "github.com/overmindtech/cli/aws-source/adapters/integration"
7 | )
8 |
9 | func resourceTags(resourceName, testID string, nameAdditionalAttr ...string) []types.Tag {
10 | return []types.Tag{
11 | {
12 | Key: aws.String(integration.TagTestKey),
13 | Value: aws.String(integration.TagTestValue),
14 | },
15 | {
16 | Key: aws.String(integration.TagTestTypeKey),
17 | Value: aws.String(integration.TestName(integration.EC2)),
18 | },
19 | {
20 | Key: aws.String(integration.TagTestIDKey),
21 | Value: aws.String(testID),
22 | },
23 | {
24 | Key: aws.String(integration.TagResourceIDKey),
25 | Value: aws.String(integration.ResourceName(integration.EC2, resourceName, nameAdditionalAttr...)),
26 | },
27 | }
28 | }
29 |
30 | func hasTags(tags []types.Tag, requiredTags []types.Tag) bool {
31 | rT := make(map[string]string)
32 | for _, t := range requiredTags {
33 | rT[*t.Key] = *t.Value
34 | }
35 |
36 | oT := make(map[string]string)
37 | for _, t := range tags {
38 | oT[*t.Key] = *t.Value
39 | }
40 |
41 | for k, v := range rT {
42 | if oT[k] != v {
43 | return false
44 | }
45 | }
46 |
47 | return true
48 | }
49 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/errors.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import "fmt"
4 |
5 | type NotFoundError struct {
6 | ResourceName string
7 | }
8 |
9 | func (e NotFoundError) Error() string {
10 | return fmt.Sprintf("Resource not found: %s", e.ResourceName)
11 | }
12 |
13 | func NewNotFoundError(resourceName string) NotFoundError {
14 | return NotFoundError{ResourceName: resourceName}
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/kms/delete.go:
--------------------------------------------------------------------------------
1 | package kms
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/kms"
7 | )
8 |
9 | func deleteKey(ctx context.Context, client *kms.Client, keyID string) error {
10 | seven := int32(7)
11 | _, err := client.ScheduleKeyDeletion(ctx, &kms.ScheduleKeyDeletionInput{
12 | KeyId: &keyID,
13 | PendingWindowInDays: &seven, // it can be minimum 7 days
14 | })
15 | return err
16 | }
17 |
18 | func deleteAlias(ctx context.Context, client *kms.Client, aliasName string) error {
19 | _, err := client.DeleteAlias(ctx, &kms.DeleteAliasInput{
20 | AliasName: &aliasName,
21 | })
22 | return err
23 | }
24 |
25 | func deleteGrant(ctx context.Context, client *kms.Client, keyID, grantID string) error {
26 | _, err := client.RevokeGrant(ctx, &kms.RevokeGrantInput{
27 | KeyId: &keyID,
28 | GrantId: &grantID,
29 | })
30 | return err
31 | }
32 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/kms/main_test.go:
--------------------------------------------------------------------------------
1 | package kms
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log/slog"
7 | "os"
8 | "testing"
9 |
10 | awskms "github.com/aws/aws-sdk-go-v2/service/kms"
11 | "github.com/overmindtech/cli/aws-source/adapters/integration"
12 | )
13 |
14 | func TestMain(m *testing.M) {
15 | if integration.ShouldRunIntegrationTests() {
16 | fmt.Println("Running integration tests")
17 | os.Exit(m.Run())
18 | } else {
19 | fmt.Println("Skipping integration tests, set RUN_INTEGRATION_TESTS=true to run them")
20 | os.Exit(0)
21 | }
22 | }
23 |
24 | func TestIntegrationKMS(t *testing.T) {
25 | t.Run("Setup", Setup)
26 | t.Run("KMS", KMS)
27 | t.Run("Teardown", Teardown)
28 | }
29 |
30 | func Setup(t *testing.T) {
31 | ctx := context.Background()
32 | logger := slog.Default()
33 |
34 | var err error
35 | testClient, err := kmsClient(ctx)
36 | if err != nil {
37 | t.Fatalf("Failed to create KMS client: %v", err)
38 | }
39 |
40 | if err := setup(ctx, logger, testClient); err != nil {
41 | t.Fatalf("Failed to setup KMS integration tests: %v", err)
42 | }
43 | }
44 |
45 | func Teardown(t *testing.T) {
46 | ctx := context.Background()
47 | logger := slog.Default()
48 |
49 | var err error
50 | testClient, err := kmsClient(ctx)
51 | if err != nil {
52 | t.Fatalf("Failed to create KMS client: %v", err)
53 | }
54 |
55 | if err := teardown(ctx, logger, testClient); err != nil {
56 | t.Fatalf("Failed to teardown KMS integration tests: %v", err)
57 | }
58 | }
59 |
60 | func kmsClient(ctx context.Context) (*awskms.Client, error) {
61 | testAWSConfig, err := integration.AWSSettings(ctx)
62 | if err != nil {
63 | return nil, fmt.Errorf("failed to get AWS settings: %w", err)
64 | }
65 |
66 | return awskms.NewFromConfig(testAWSConfig.Config), nil
67 | }
68 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/kms/setup.go:
--------------------------------------------------------------------------------
1 | package kms
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "log/slog"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/kms"
9 | "github.com/overmindtech/cli/aws-source/adapters/integration"
10 | )
11 |
12 | const (
13 | keySrc = "key"
14 | aliasSrc = "alias"
15 | grantSrc = "grant"
16 | keyPolicySrc = "key-policy"
17 | )
18 |
19 | func setup(ctx context.Context, logger *slog.Logger, client *kms.Client) error {
20 | testID := integration.TestID()
21 |
22 | // Create KMS key
23 | keyID, err := createKey(ctx, logger, client, testID)
24 | if err != nil {
25 | return err
26 | }
27 |
28 | // Create KMS alias
29 | err = createAlias(ctx, logger, client, *keyID)
30 | if err != nil {
31 | return err
32 | }
33 |
34 | principal, err := integration.GetCallerIdentityARN(ctx)
35 | if err != nil {
36 | return fmt.Errorf("failed to get caller identity: %w", err)
37 | }
38 |
39 | // Create KMS grant
40 | err = createGrant(ctx, logger, client, *keyID, *principal)
41 | if err != nil {
42 | return err
43 | }
44 |
45 | // Create KMS key policy
46 | return putKeyPolicy(ctx, logger, client, *keyID, *principal)
47 | }
48 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/kms/teardown.go:
--------------------------------------------------------------------------------
1 | package kms
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "fmt"
7 | "log/slog"
8 |
9 | "github.com/aws/aws-sdk-go-v2/service/kms"
10 | "github.com/overmindtech/cli/aws-source/adapters/integration"
11 | )
12 |
13 | func teardown(ctx context.Context, logger *slog.Logger, client *kms.Client) error {
14 | keyID, err := findActiveKeyIDByTags(ctx, client)
15 | if err != nil {
16 | if nf := integration.NewNotFoundError(keySrc); errors.As(err, &nf) {
17 | logger.WarnContext(ctx, "Key not found")
18 | return nil
19 | } else {
20 | return err
21 | }
22 | }
23 |
24 | principal, err := integration.GetCallerIdentityARN(ctx)
25 | if err != nil {
26 | return fmt.Errorf("failed to get caller identity: %w", err)
27 | }
28 |
29 | grantID, err := findGrant(ctx, client, *keyID, *principal)
30 | if err != nil {
31 | if nf := integration.NewNotFoundError(grantSrc); errors.As(err, &nf) {
32 | logger.WarnContext(ctx, "Grant not found")
33 | } else {
34 | return err
35 | }
36 | }
37 |
38 | err = deleteGrant(ctx, client, *keyID, *grantID)
39 | if err != nil {
40 | return err
41 | }
42 |
43 | aliasNames, err := findAliasesByTargetKey(ctx, client, *keyID)
44 | if err != nil {
45 | if nf := integration.NewNotFoundError(aliasSrc); errors.As(err, &nf) {
46 | logger.WarnContext(ctx, "Alias not found")
47 | } else {
48 | return err
49 | }
50 | }
51 |
52 | for _, aliasName := range aliasNames {
53 | err = deleteAlias(ctx, client, aliasName)
54 | if err != nil {
55 | return err
56 | }
57 | }
58 |
59 | return deleteKey(ctx, client, *keyID)
60 | }
61 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/kms/util.go:
--------------------------------------------------------------------------------
1 | package kms
2 |
3 | import (
4 | "github.com/aws/aws-sdk-go-v2/aws"
5 | "github.com/aws/aws-sdk-go-v2/service/kms/types"
6 | "github.com/overmindtech/cli/aws-source/adapters/integration"
7 | )
8 |
9 | func resourceTags(resourceName, testID string, nameAdditionalAttr ...string) []types.Tag {
10 | return []types.Tag{
11 | {
12 | TagKey: aws.String(integration.TagTestKey),
13 | TagValue: aws.String(integration.TagTestValue),
14 | },
15 | {
16 | TagKey: aws.String(integration.TagTestTypeKey),
17 | TagValue: aws.String(integration.TestName(integration.KMS)),
18 | },
19 | {
20 | TagKey: aws.String(integration.TagTestIDKey),
21 | TagValue: aws.String(testID),
22 | },
23 | {
24 | TagKey: aws.String(integration.TagResourceIDKey),
25 | TagValue: aws.String(integration.ResourceName(integration.KMS, resourceName, nameAdditionalAttr...)),
26 | },
27 | }
28 | }
29 |
30 | func hasTags(tags []types.Tag, requiredTags []types.Tag) bool {
31 | rT := make(map[string]string)
32 | for _, t := range requiredTags {
33 | rT[*t.TagKey] = *t.TagValue
34 | }
35 |
36 | oT := make(map[string]string)
37 | for _, t := range tags {
38 | oT[*t.TagKey] = *t.TagValue
39 | }
40 |
41 | for k, v := range rT {
42 | if oT[k] != v {
43 | return false
44 | }
45 | }
46 |
47 | return true
48 | }
49 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/networkmanager/tags.go:
--------------------------------------------------------------------------------
1 | package networkmanager
2 |
3 | import (
4 | "github.com/aws/aws-sdk-go-v2/aws"
5 | "github.com/aws/aws-sdk-go-v2/service/networkmanager/types"
6 | "github.com/overmindtech/cli/aws-source/adapters/integration"
7 | )
8 |
9 | func resourceTags(resourceName, testID string, additionalAttr ...string) []types.Tag {
10 | return []types.Tag{
11 | {
12 | Key: aws.String(integration.TagTestKey),
13 | Value: aws.String(integration.TagTestValue),
14 | },
15 | {
16 | Key: aws.String(integration.TagTestTypeKey),
17 | Value: aws.String(integration.TestName(integration.NetworkManager)),
18 | },
19 | {
20 | Key: aws.String(integration.TagTestIDKey),
21 | Value: aws.String(testID),
22 | },
23 | {
24 | Key: aws.String(integration.TagResourceIDKey),
25 | Value: aws.String(integration.ResourceName(integration.NetworkManager, resourceName, additionalAttr...)),
26 | },
27 | }
28 | }
29 |
30 | func hasTags(tags []types.Tag, requiredTags []types.Tag) bool {
31 | rT := make(map[string]string)
32 | for _, t := range requiredTags {
33 | rT[*t.Key] = *t.Value
34 | }
35 |
36 | oT := make(map[string]string)
37 | for _, t := range tags {
38 | oT[*t.Key] = *t.Value
39 | }
40 |
41 | for k, v := range rT {
42 | if oT[k] != v {
43 | return false
44 | }
45 | }
46 |
47 | return true
48 | }
49 |
--------------------------------------------------------------------------------
/aws-source/adapters/integration/util_test.go:
--------------------------------------------------------------------------------
1 | package integration
2 |
3 | import (
4 | "os"
5 | "testing"
6 | )
7 |
8 | func Test_testID(t *testing.T) {
9 | t.Run("test id is given via env var", func(t *testing.T) {
10 | err := os.Setenv("INTEGRATION_TEST_ID", "test-id")
11 | if err != nil {
12 | t.Error(err)
13 | }
14 | defer func() {
15 | err := os.Unsetenv("INTEGRATION_TEST_ID")
16 | if err != nil {
17 | t.Error(err)
18 | }
19 | }()
20 |
21 | if got := TestID(); got != "test-id" {
22 | t.Errorf("TestID() = %v, want %v", got, "test-id")
23 | }
24 | })
25 |
26 | t.Run("test id is not given via env var - defaults to host name", func(t *testing.T) {
27 | err := os.Unsetenv("INTEGRATION_TEST_ID")
28 | if err != nil {
29 | t.Error(err)
30 | }
31 |
32 | if got := TestID(); got == "" {
33 | t.Errorf("TestID() = %v, want not empty", got)
34 | }
35 | })
36 | }
37 |
--------------------------------------------------------------------------------
/aws-source/adapters/kms-alias_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 | "time"
7 |
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | "github.com/overmindtech/cli/sdp-go"
10 |
11 | "github.com/aws/aws-sdk-go-v2/service/kms"
12 | "github.com/aws/aws-sdk-go-v2/service/kms/types"
13 | )
14 |
15 | func TestAliasOutputMapper(t *testing.T) {
16 | output := &kms.ListAliasesOutput{
17 | Aliases: []types.AliasListEntry{
18 | {
19 | AliasName: adapterhelpers.PtrString("alias/test-key"),
20 | TargetKeyId: adapterhelpers.PtrString("cf68415c-f4ae-48f2-87a7-3b52ce"),
21 | AliasArn: adapterhelpers.PtrString("arn:aws:kms:us-west-2:123456789012:alias/test-key"),
22 | CreationDate: adapterhelpers.PtrTime(time.Now()),
23 | LastUpdatedDate: adapterhelpers.PtrTime(time.Now()),
24 | },
25 | },
26 | }
27 |
28 | items, err := aliasOutputMapper(context.Background(), nil, "foo", nil, output)
29 | if err != nil {
30 | t.Fatal(err)
31 | }
32 |
33 | for _, item := range items {
34 | if err := item.Validate(); err != nil {
35 | t.Error(err)
36 | }
37 | }
38 |
39 | if len(items) != 1 {
40 | t.Fatalf("expected 1 item, got %v", len(items))
41 | }
42 |
43 | item := items[0]
44 |
45 | tests := adapterhelpers.QueryTests{
46 | {
47 | ExpectedType: "kms-key",
48 | ExpectedMethod: sdp.QueryMethod_GET,
49 | ExpectedQuery: "cf68415c-f4ae-48f2-87a7-3b52ce",
50 | ExpectedScope: "foo",
51 | },
52 | }
53 |
54 | tests.Execute(t, item)
55 | }
56 |
57 | func TestNewKMSAliasAdapter(t *testing.T) {
58 | config, account, region := adapterhelpers.GetAutoConfig(t)
59 | client := kms.NewFromConfig(config)
60 |
61 | adapter := NewKMSAliasAdapter(client, account, region)
62 |
63 | test := adapterhelpers.E2ETest{
64 | Adapter: adapter,
65 | Timeout: 10 * time.Second,
66 | }
67 |
68 | test.Run(t)
69 | }
70 |
--------------------------------------------------------------------------------
/aws-source/adapters/kms.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/kms"
7 | "github.com/aws/aws-sdk-go-v2/service/kms/types"
8 | )
9 |
10 | func kmsTags(ctx context.Context, cli kmsClient, keyID string) (map[string]string, error) {
11 | if cli == nil {
12 | return nil, nil
13 | }
14 |
15 | output, err := cli.ListResourceTags(ctx, &kms.ListResourceTagsInput{
16 | KeyId: &keyID,
17 | })
18 | if err != nil {
19 | return nil, err
20 | }
21 |
22 | return kmsTagsToMap(output.Tags), nil
23 | }
24 |
25 | func kmsTagsToMap(tags []types.Tag) map[string]string {
26 | tagsMap := make(map[string]string)
27 |
28 | for _, tag := range tags {
29 | if tag.TagKey != nil && tag.TagValue != nil {
30 | tagsMap[*tag.TagKey] = *tag.TagValue
31 | }
32 | }
33 |
34 | return tagsMap
35 | }
36 |
--------------------------------------------------------------------------------
/aws-source/adapters/lambda-layer_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/lambda/types"
8 |
9 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
10 | "github.com/overmindtech/cli/sdp-go"
11 | )
12 |
13 | func TestLayerItemMapper(t *testing.T) {
14 | layer := types.LayersListItem{
15 | LatestMatchingVersion: &types.LayerVersionsListItem{
16 | CompatibleArchitectures: []types.Architecture{
17 | types.ArchitectureArm64,
18 | types.ArchitectureX8664,
19 | },
20 | CompatibleRuntimes: []types.Runtime{
21 | types.RuntimeJava11,
22 | },
23 | CreatedDate: adapterhelpers.PtrString("2018-11-27T15:10:45.123+0000"),
24 | Description: adapterhelpers.PtrString("description"),
25 | LayerVersionArn: adapterhelpers.PtrString("arn:aws:service:region:account:type/id"),
26 | LicenseInfo: adapterhelpers.PtrString("info"),
27 | Version: 10,
28 | },
29 | LayerArn: adapterhelpers.PtrString("arn:aws:service:region:account:type/id"),
30 | LayerName: adapterhelpers.PtrString("name"),
31 | }
32 |
33 | item, err := layerItemMapper("", "foo", &layer)
34 |
35 | if err != nil {
36 | t.Error(err)
37 | }
38 |
39 | if err = item.Validate(); err != nil {
40 | t.Error(err)
41 | }
42 |
43 | tests := adapterhelpers.QueryTests{
44 | {
45 | ExpectedType: "lambda-layer-version",
46 | ExpectedMethod: sdp.QueryMethod_GET,
47 | ExpectedQuery: "name:10",
48 | ExpectedScope: "foo",
49 | },
50 | }
51 |
52 | tests.Execute(t, item)
53 | }
54 |
55 | func TestNewLambdaLayerAdapter(t *testing.T) {
56 | client, account, region := lambdaGetAutoConfig(t)
57 |
58 | adapter := NewLambdaLayerAdapter(client, account, region)
59 |
60 | test := adapterhelpers.E2ETest{
61 | Adapter: adapter,
62 | Timeout: 10 * time.Second,
63 | SkipGet: true,
64 | }
65 |
66 | test.Run(t)
67 | }
68 |
--------------------------------------------------------------------------------
/aws-source/adapters/lambda.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/lambda"
7 | )
8 |
9 | // LambdaClient Represents the client we need to talk to Lambda, usually this is
10 | // *lambda.Client
11 | type LambdaClient interface {
12 | GetFunction(ctx context.Context, params *lambda.GetFunctionInput, optFns ...func(*lambda.Options)) (*lambda.GetFunctionOutput, error)
13 | GetLayerVersion(ctx context.Context, params *lambda.GetLayerVersionInput, optFns ...func(*lambda.Options)) (*lambda.GetLayerVersionOutput, error)
14 | GetPolicy(ctx context.Context, params *lambda.GetPolicyInput, optFns ...func(*lambda.Options)) (*lambda.GetPolicyOutput, error)
15 |
16 | lambda.ListFunctionEventInvokeConfigsAPIClient
17 | lambda.ListFunctionUrlConfigsAPIClient
18 | lambda.ListFunctionsAPIClient
19 | lambda.ListLayerVersionsAPIClient
20 | }
21 |
22 | // This is derived from the AWS example:
23 | // https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/gov2/iam/actions/policies.go#L21C1-L32C2
24 | // and represents the structure of an IAM policy document
25 | type PolicyDocument struct {
26 | Version string `json:""`
27 | Statement []PolicyStatement `json:""`
28 | }
29 |
30 | // PolicyStatement defines a statement in a policy document.
31 | type PolicyStatement struct {
32 | Action string
33 | Principal Principal `json:",omitempty"`
34 | Condition Condition `json:",omitempty"`
35 | }
36 |
37 | type Principal struct {
38 | Service string `json:",omitempty"`
39 | }
40 |
41 | type Condition struct {
42 | ArnLike ArnLikeCondition `json:",omitempty"`
43 | StringEquals StringEqualsCondition `json:",omitempty"`
44 | }
45 |
46 | type StringEqualsCondition struct {
47 | AWSSourceAccount string `json:"AWS:SourceAccount,omitempty"`
48 | }
49 |
50 | type ArnLikeCondition struct {
51 | AWSSourceArn string `json:"AWS:SourceArn,omitempty"`
52 | }
53 |
--------------------------------------------------------------------------------
/aws-source/adapters/main.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/sdp-go"
5 | )
6 |
7 | var Metadata = sdp.AdapterMetadataList{}
8 |
--------------------------------------------------------------------------------
/aws-source/adapters/networkfirewall_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | type testNetworkFirewallClient struct{}
4 |
--------------------------------------------------------------------------------
/aws-source/adapters/networkmanager-connect-attachment_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/networkmanager/types"
7 |
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | "github.com/overmindtech/cli/sdp-go"
10 | )
11 |
12 | func TestConnectAttachmentItemMapper(t *testing.T) {
13 |
14 | scope := "123456789012.eu-west-2"
15 | item, err := connectAttachmentItemMapper("", scope, &types.ConnectAttachment{
16 | Attachment: &types.Attachment{
17 | AttachmentId: adapterhelpers.PtrString("att-1"),
18 | CoreNetworkId: adapterhelpers.PtrString("cn-1"),
19 | CoreNetworkArn: adapterhelpers.PtrString("arn:aws:networkmanager:eu-west-2:123456789012:core-network/cn-1"),
20 | },
21 | })
22 | if err != nil {
23 | t.Error(err)
24 | }
25 |
26 | // Ensure unique attribute
27 | err = item.Validate()
28 | if err != nil {
29 | t.Error(err)
30 | }
31 |
32 | if item.UniqueAttributeValue() != "att-1" {
33 | t.Fatalf("expected att-1, got %v", item.UniqueAttributeValue())
34 | }
35 |
36 | tests := adapterhelpers.QueryTests{
37 | {
38 | ExpectedType: "networkmanager-core-network",
39 | ExpectedMethod: sdp.QueryMethod_GET,
40 | ExpectedQuery: "cn-1",
41 | ExpectedScope: scope,
42 | },
43 | {
44 | ExpectedType: "networkmanager-core-network",
45 | ExpectedMethod: sdp.QueryMethod_SEARCH,
46 | ExpectedQuery: "arn:aws:networkmanager:eu-west-2:123456789012:core-network/cn-1",
47 | ExpectedScope: "123456789012.eu-west-2",
48 | },
49 | }
50 |
51 | tests.Execute(t, item)
52 | }
53 |
--------------------------------------------------------------------------------
/aws-source/adapters/networkmanager-core-network-policy_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/networkmanager/types"
7 |
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | "github.com/overmindtech/cli/sdp-go"
10 | )
11 |
12 | func TestCoreNetworkPolicyItemMapper(t *testing.T) {
13 |
14 | scope := "123456789012.eu-west-2"
15 | item, err := coreNetworkPolicyItemMapper("", scope, &types.CoreNetworkPolicy{
16 | CoreNetworkId: adapterhelpers.PtrString("cn-1"),
17 | PolicyVersionId: adapterhelpers.PtrInt32(1),
18 | })
19 | if err != nil {
20 | t.Error(err)
21 | }
22 |
23 | // Ensure unique attribute
24 | err = item.Validate()
25 | if err != nil {
26 | t.Error(err)
27 | }
28 |
29 | if item.UniqueAttributeValue() != "cn-1" {
30 | t.Fatalf("expected cn-1, got %v", item.UniqueAttributeValue())
31 | }
32 |
33 | tests := adapterhelpers.QueryTests{
34 | {
35 | ExpectedType: "networkmanager-core-network",
36 | ExpectedMethod: sdp.QueryMethod_GET,
37 | ExpectedQuery: "cn-1",
38 | ExpectedScope: scope,
39 | },
40 | }
41 |
42 | tests.Execute(t, item)
43 | }
44 |
--------------------------------------------------------------------------------
/aws-source/adapters/networkmanager-vpc-attachment_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/networkmanager/types"
7 |
8 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
9 | "github.com/overmindtech/cli/sdp-go"
10 | )
11 |
12 | func TestVPCAttachmentItemMapper(t *testing.T) {
13 | input := types.VpcAttachment{
14 | Attachment: &types.Attachment{
15 | AttachmentId: adapterhelpers.PtrString("attachment1"),
16 | CoreNetworkId: adapterhelpers.PtrString("corenetwork1"),
17 | },
18 | }
19 | scope := "123456789012.eu-west-2"
20 | item, err := vpcAttachmentItemMapper("", scope, &input)
21 |
22 | if err != nil {
23 | t.Error(err)
24 | }
25 | if err := item.Validate(); err != nil {
26 | t.Error(err)
27 | }
28 |
29 | // Ensure unique attribute
30 | if item.UniqueAttributeValue() != "attachment1" {
31 | t.Fatalf("expected %v, got %v", "attachment1", item.UniqueAttributeValue())
32 | }
33 |
34 | tests := adapterhelpers.QueryTests{
35 | {
36 | ExpectedType: "networkmanager-core-network",
37 | ExpectedMethod: sdp.QueryMethod_GET,
38 | ExpectedQuery: "corenetwork1",
39 | ExpectedScope: scope,
40 | },
41 | }
42 |
43 | tests.Execute(t, item)
44 | }
45 |
--------------------------------------------------------------------------------
/aws-source/adapters/networkmanager.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/networkmanager"
7 | "github.com/aws/aws-sdk-go-v2/service/networkmanager/types"
8 | )
9 |
10 | type NetworkManagerClient interface {
11 | networkmanager.ListConnectPeersAPIClient
12 | networkmanager.ListCoreNetworksAPIClient
13 |
14 | GetConnectPeer(ctx context.Context, params *networkmanager.GetConnectPeerInput, optFns ...func(*networkmanager.Options)) (*networkmanager.GetConnectPeerOutput, error)
15 | GetCoreNetwork(ctx context.Context, params *networkmanager.GetCoreNetworkInput, optFns ...func(*networkmanager.Options)) (*networkmanager.GetCoreNetworkOutput, error)
16 | }
17 |
18 | // convertTags converts slice of ecs tags to a map
19 | func networkmanagerTagsToMap(tags []types.Tag) map[string]string {
20 | tagsMap := make(map[string]string)
21 |
22 | for _, tag := range tags {
23 | if tag.Key != nil && tag.Value != nil {
24 | tagsMap[*tag.Key] = *tag.Value
25 | }
26 | }
27 |
28 | return tagsMap
29 | }
30 |
--------------------------------------------------------------------------------
/aws-source/adapters/networkmanager_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | type NetworkManagerTestClient struct{}
4 |
--------------------------------------------------------------------------------
/aws-source/adapters/rds-option-group_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/rds"
8 | "github.com/aws/aws-sdk-go-v2/service/rds/types"
9 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
10 | )
11 |
12 | func TestOptionGroupOutputMapper(t *testing.T) {
13 | output := rds.DescribeOptionGroupsOutput{
14 | OptionGroupsList: []types.OptionGroup{
15 | {
16 | OptionGroupName: adapterhelpers.PtrString("default:aurora-mysql-8-0"),
17 | OptionGroupDescription: adapterhelpers.PtrString("Default option group for aurora-mysql 8.0"),
18 | EngineName: adapterhelpers.PtrString("aurora-mysql"),
19 | MajorEngineVersion: adapterhelpers.PtrString("8.0"),
20 | Options: []types.Option{},
21 | AllowsVpcAndNonVpcInstanceMemberships: adapterhelpers.PtrBool(true),
22 | OptionGroupArn: adapterhelpers.PtrString("arn:aws:rds:eu-west-2:052392120703:og:default:aurora-mysql-8-0"),
23 | },
24 | },
25 | }
26 |
27 | items, err := optionGroupOutputMapper(context.Background(), mockRdsClient{}, "foo", nil, &output)
28 |
29 | if err != nil {
30 | t.Fatal(err)
31 | }
32 |
33 | if len(items) != 1 {
34 | t.Fatalf("got %v items, expected 1", len(items))
35 | }
36 |
37 | item := items[0]
38 |
39 | if err = item.Validate(); err != nil {
40 | t.Error(err)
41 | }
42 |
43 | if item.GetTags()["key"] != "value" {
44 | t.Errorf("expected key to be value, got %v", item.GetTags()["key"])
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/aws-source/adapters/rds_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/rds"
7 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
8 | )
9 |
10 | func rdsGetAutoConfig(t *testing.T) (*rds.Client, string, string) {
11 | config, account, region := adapterhelpers.GetAutoConfig(t)
12 | client := rds.NewFromConfig(config)
13 |
14 | return client, account, region
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/route53-hosted-zone_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | "time"
6 |
7 | "github.com/aws/aws-sdk-go-v2/service/route53/types"
8 |
9 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
10 | "github.com/overmindtech/cli/sdp-go"
11 | )
12 |
13 | func TestHostedZoneItemMapper(t *testing.T) {
14 | zone := types.HostedZone{
15 | Id: adapterhelpers.PtrString("/hostedzone/Z08416862SZP5DJXIDB29"),
16 | Name: adapterhelpers.PtrString("overmind-demo.com."),
17 | CallerReference: adapterhelpers.PtrString("RISWorkflow-RD:144d3779-1574-42bf-9e75-f309838ea0a1"),
18 | Config: &types.HostedZoneConfig{
19 | Comment: adapterhelpers.PtrString("HostedZone created by Route53 Registrar"),
20 | PrivateZone: false,
21 | },
22 | ResourceRecordSetCount: adapterhelpers.PtrInt64(3),
23 | LinkedService: &types.LinkedService{
24 | Description: adapterhelpers.PtrString("service description"),
25 | ServicePrincipal: adapterhelpers.PtrString("principal"),
26 | },
27 | }
28 |
29 | item, err := hostedZoneItemMapper("", "foo", &zone)
30 |
31 | if err != nil {
32 | t.Error(err)
33 | }
34 |
35 | if err = item.Validate(); err != nil {
36 | t.Error(err)
37 | }
38 |
39 | tests := adapterhelpers.QueryTests{
40 | {
41 | ExpectedType: "route53-resource-record-set",
42 | ExpectedMethod: sdp.QueryMethod_SEARCH,
43 | ExpectedQuery: "/hostedzone/Z08416862SZP5DJXIDB29",
44 | ExpectedScope: "foo",
45 | },
46 | }
47 |
48 | tests.Execute(t, item)
49 | }
50 |
51 | func TestNewRoute53HostedZoneAdapter(t *testing.T) {
52 | client, account, region := route53GetAutoConfig(t)
53 |
54 | adapter := NewRoute53HostedZoneAdapter(client, account, region)
55 |
56 | test := adapterhelpers.E2ETest{
57 | Adapter: adapter,
58 | Timeout: 10 * time.Second,
59 | }
60 |
61 | test.Run(t)
62 | }
63 |
--------------------------------------------------------------------------------
/aws-source/adapters/route53.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import "github.com/aws/aws-sdk-go-v2/service/route53/types"
4 |
5 | func route53TagsToMap(tags []types.Tag) map[string]string {
6 | m := make(map[string]string)
7 |
8 | for _, tag := range tags {
9 | if tag.Key != nil && tag.Value != nil {
10 | m[*tag.Key] = *tag.Value
11 | }
12 | }
13 |
14 | return m
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/route53_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/route53"
7 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
8 | )
9 |
10 | func route53GetAutoConfig(t *testing.T) (*route53.Client, string, string) {
11 | config, account, region := adapterhelpers.GetAutoConfig(t)
12 | client := route53.NewFromConfig(config)
13 |
14 | return client, account, region
15 | }
16 |
--------------------------------------------------------------------------------
/aws-source/adapters/sns-data-protection-policy_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 | "time"
7 |
8 | "github.com/aws/aws-sdk-go-v2/service/sns"
9 | "github.com/overmindtech/cli/aws-source/adapterhelpers"
10 | )
11 |
12 | type mockDataProtectionPolicyClient struct{}
13 |
14 | func (m mockDataProtectionPolicyClient) GetDataProtectionPolicy(ctx context.Context, params *sns.GetDataProtectionPolicyInput, optFns ...func(*sns.Options)) (*sns.GetDataProtectionPolicyOutput, error) {
15 | return &sns.GetDataProtectionPolicyOutput{
16 | DataProtectionPolicy: adapterhelpers.PtrString("{\"Name\":\"data_protection_policy\",\"Description\":\"Example data protection policy\",\"Version\":\"2021-06-01\",\"Statement\":[{\"DataDirection\":\"Inbound\",\"Principal\":[\"*\"],\"DataIdentifier\":[\"arn:aws:dataprotection::aws:data-identifier/CreditCardNumber\"],\"Operation\":{\"Deny\":{}}}]}"),
17 | }, nil
18 | }
19 |
20 | func TestGetDataProtectionPolicyFunc(t *testing.T) {
21 | ctx := context.Background()
22 | cli := &mockDataProtectionPolicyClient{}
23 |
24 | item, err := getDataProtectionPolicyFunc(ctx, cli, "scope", &sns.GetDataProtectionPolicyInput{
25 | ResourceArn: adapterhelpers.PtrString("arn:aws:sns:us-east-1:123456789012:mytopic"),
26 | })
27 | if err != nil {
28 | t.Fatal(err)
29 | }
30 |
31 | if err = item.Validate(); err != nil {
32 | t.Fatal(err)
33 | }
34 | }
35 |
36 | func TestNewSNSDataProtectionPolicyAdapter(t *testing.T) {
37 | config, account, region := adapterhelpers.GetAutoConfig(t)
38 | client := sns.NewFromConfig(config)
39 |
40 | adapter := NewSNSDataProtectionPolicyAdapter(client, account, region)
41 |
42 | test := adapterhelpers.E2ETest{
43 | Adapter: adapter,
44 | Timeout: 10 * time.Second,
45 | SkipList: true,
46 | SkipGet: true,
47 | }
48 |
49 | test.Run(t)
50 | }
51 |
--------------------------------------------------------------------------------
/aws-source/adapters/sns.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/sns"
7 | "github.com/aws/aws-sdk-go-v2/service/sns/types"
8 | )
9 |
10 | type tagLister interface {
11 | ListTagsForResource(ctx context.Context, params *sns.ListTagsForResourceInput, optFns ...func(*sns.Options)) (*sns.ListTagsForResourceOutput, error)
12 | }
13 |
14 | // tagsByResourceARN returns the tags for a given resource ARN
15 | func tagsByResourceARN(ctx context.Context, cli tagLister, resourceARN string) ([]types.Tag, error) {
16 | if cli == nil {
17 | return nil, nil
18 | }
19 |
20 | output, err := cli.ListTagsForResource(ctx, &sns.ListTagsForResourceInput{
21 | ResourceArn: &resourceARN,
22 | })
23 | if err != nil {
24 | return nil, err
25 | }
26 |
27 | if output != nil && output.Tags != nil {
28 | return output.Tags, nil
29 | }
30 |
31 | return nil, nil
32 | }
33 |
34 | // tagsToMap converts a slice of tags to a map
35 | func tagsToMap(tags []types.Tag) map[string]string {
36 | tagsMap := make(map[string]string)
37 |
38 | for _, tag := range tags {
39 | if tag.Key != nil && tag.Value != nil {
40 | tagsMap[*tag.Key] = *tag.Value
41 | }
42 | }
43 |
44 | return tagsMap
45 | }
46 |
--------------------------------------------------------------------------------
/aws-source/adapters/sqs.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/aws/aws-sdk-go-v2/service/sqs"
7 | )
8 |
9 | func tags(ctx context.Context, cli sqsClient, queURL string) (map[string]string, error) {
10 | if cli == nil {
11 | return nil, nil
12 | }
13 |
14 | output, err := cli.ListQueueTags(ctx, &sqs.ListQueueTagsInput{
15 | QueueUrl: &queURL,
16 | })
17 | if err != nil {
18 | return nil, err
19 | }
20 |
21 | return output.Tags, nil
22 | }
23 |
--------------------------------------------------------------------------------
/aws-source/adapters/tracing.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "go.opentelemetry.io/otel"
5 | semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
6 | "go.opentelemetry.io/otel/trace"
7 | )
8 |
9 | const (
10 | instrumentationName = "github.com/overmindtech/cli/aws-source/adapters"
11 | instrumentationVersion = "0.0.1"
12 | )
13 |
14 | var tracer = otel.GetTracerProvider().Tracer(
15 | instrumentationName,
16 | trace.WithInstrumentationVersion(instrumentationVersion),
17 | trace.WithSchemaURL(semconv.SchemaURL),
18 | )
19 |
--------------------------------------------------------------------------------
/aws-source/build/package/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build the source binary
2 | FROM golang:1.24-alpine AS builder
3 | ARG TARGETOS
4 | ARG TARGETARCH
5 | ARG BUILD_VERSION
6 | ARG BUILD_COMMIT
7 |
8 | # required for generating the version descriptor
9 | RUN apk add --no-cache git
10 |
11 | WORKDIR /workspace
12 |
13 | # Copy the go source
14 | COPY . .
15 |
16 | # Build
17 | RUN --mount=type=cache,target=/go/pkg \
18 | --mount=type=cache,target=/root/.cache/go-build \
19 | GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/tracing.commit=${BUILD_COMMIT}" -o source aws-source/main.go
20 |
21 | FROM alpine:3.21
22 | WORKDIR /
23 | COPY --from=builder /workspace/source .
24 | USER 65534:65534
25 |
26 | ENTRYPOINT ["/source"]
27 |
--------------------------------------------------------------------------------
/aws-source/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 | services:
3 | nats:
4 | image: nats
5 | command: "-c /etc/nats/nats.conf -DV" #-c /etc/nats/nats.conf --cluster nats://0.0.0.0:6222 --routes=nats://ruser:T0pS3cr3t@nats:6222
6 | ports:
7 | - "4222:4222"
8 | - "8222:8222"
9 | - "6222:6222"
10 | - "4433:4433"
11 | volumes:
12 | - ./acceptance/nats-server.conf:/etc/nats/nats.conf
13 | # nats-1:
14 | # image: nats
15 | # command: "-c nats-server.conf --routes=nats-route://ruser:T0pS3cr3t@nats:6222 -DV"
16 | #link:
17 | # # Will build from a local copy
18 | # build: ../redacted_link
19 | # environment:
20 | # - REDACTED_NATS_URLS=nats
21 | # - REDACTED_VERBOSITY=debug
22 |
23 | networks:
24 | default:
25 | external:
26 | name: nats
27 |
--------------------------------------------------------------------------------
/aws-source/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2021 {AUTHOR}
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package main
17 |
18 | import (
19 | "github.com/overmindtech/cli/aws-source/cmd"
20 | _ "go.uber.org/automaxprocs"
21 | )
22 |
23 | func main() {
24 | cmd.Execute()
25 | }
26 |
--------------------------------------------------------------------------------
/cmd/bookmarks.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2024 NAME HERE
3 | */
4 | package cmd
5 |
6 | import (
7 | "github.com/spf13/cobra"
8 | )
9 |
10 | // bookmarksCmd represents the bookmarks command
11 | var bookmarksCmd = &cobra.Command{
12 | Use: "bookmarks",
13 | GroupID: "api",
14 | Short: "Interact with the bookmarks that were created in the Explore view",
15 | Long: `A bookmark in Overmind is a set of queries that are stored together and can be
16 | executed as a single block.`,
17 | Run: func(cmd *cobra.Command, args []string) {
18 | _ = cmd.Help()
19 | },
20 | }
21 |
22 | func init() {
23 | rootCmd.AddCommand(bookmarksCmd)
24 |
25 | addAPIFlags(bookmarksCmd)
26 |
27 | // Here you will define your flags and configuration settings.
28 |
29 | // Cobra supports Persistent Flags which will work for this command
30 | // and all subcommands, e.g.:
31 | // bookmarksCmd.PersistentFlags().String("foo", "", "A help for foo")
32 |
33 | // Cobra supports local flags which will only run when this command
34 | // is called directly, e.g.:
35 | // bookmarksCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
36 | }
37 |
--------------------------------------------------------------------------------
/cmd/changes.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | // changesCmd represents the changes command
8 | var changesCmd = &cobra.Command{
9 | Use: "changes",
10 | GroupID: "api",
11 | Short: "Create, update and delete changes in Overmind",
12 | Long: `Manage changes that are being tracked using Overmind. NOTE: It is probably
13 | easier to use our IaC wrappers such as 'overmind terraform plan' rather than
14 | using these commands directly, but they are provided for flexibility.`,
15 | Run: func(cmd *cobra.Command, args []string) {
16 | _ = cmd.Help()
17 | },
18 | }
19 |
20 | func init() {
21 | rootCmd.AddCommand(changesCmd)
22 |
23 | addAPIFlags(changesCmd)
24 |
25 | // Here you will define your flags and configuration settings.
26 |
27 | // Cobra supports Persistent Flags which will work for this command
28 | // and all subcommands, e.g.:
29 | // changesCmd.PersistentFlags().String("foo", "", "A help for foo")
30 |
31 | // Cobra supports local flags which will only run when this command
32 | // is called directly, e.g.:
33 | // changesCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
34 | }
35 |
--------------------------------------------------------------------------------
/cmd/integrations.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | // integrationsCmd represents the integrations command
8 | var integrationsCmd = &cobra.Command{
9 | Use: "integrations",
10 | GroupID: "api",
11 | Short: "Manage integrations with Overmind",
12 | Long: `Manage integrations with Overmind. These integrations allow you to
13 | integrate Overmind with other tools and services.`,
14 | Run: func(cmd *cobra.Command, args []string) {
15 | _ = cmd.Help()
16 | },
17 | }
18 |
19 | func init() {
20 | rootCmd.AddCommand(integrationsCmd)
21 |
22 | addAPIFlags(integrationsCmd)
23 |
24 | // Here you will define your flags and configuration settings.
25 |
26 | // Cobra supports Persistent Flags which will work for this command
27 | // and all subcommands, e.g.:
28 | // integrationsCmd.PersistentFlags().String("foo", "", "A help for foo")
29 |
30 | // Cobra supports local flags which will only run when this command
31 | // is called directly, e.g.:
32 | // integrationsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
33 | }
34 |
--------------------------------------------------------------------------------
/cmd/invites.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | // invitesCmd represents the invites command
8 | var invitesCmd = &cobra.Command{
9 | Use: "invites",
10 | GroupID: "api",
11 | Short: "Manage invites for your team to Overmind",
12 | Long: `Create and revoke Overmind invitations`,
13 | Run: func(cmd *cobra.Command, args []string) {
14 | _ = cmd.Help()
15 | },
16 | }
17 |
18 | func init() {
19 | rootCmd.AddCommand(invitesCmd)
20 |
21 | addAPIFlags(invitesCmd)
22 | // Here you will define your flags and configuration settings.
23 |
24 | // Cobra supports Persistent Flags which will work for this command
25 | // and all subcommands, e.g.:
26 | // invitesCmd.PersistentFlags().String("foo", "", "A help for foo")
27 |
28 | // Cobra supports local flags which will only run when this command
29 | // is called directly, e.g.:
30 | // invitesCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
31 | }
32 |
--------------------------------------------------------------------------------
/cmd/logging.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/ttacon/chalk"
5 | )
6 |
7 | var (
8 | // Styles
9 | Underline = TextStyle{chalk.Underline}
10 | Bold = TextStyle{chalk.Bold}
11 |
12 | // Colors
13 | Black = Color{chalk.Black}
14 | Red = Color{chalk.Red}
15 | Green = Color{chalk.Green}
16 | Yellow = Color{chalk.Yellow}
17 | Blue = Color{chalk.Blue}
18 | Magenta = Color{chalk.Magenta}
19 | Cyan = Color{chalk.Cyan}
20 | White = Color{chalk.White}
21 | )
22 |
23 | // A type that wraps chalk.TextStyle but adds detections for if we're in a TTY
24 | type TextStyle struct {
25 | underlying chalk.TextStyle
26 | }
27 |
28 | // A type that wraps chalk.Color but adds detections for if we're in a TTY
29 | type Color struct {
30 | underlying chalk.Color
31 | }
32 |
--------------------------------------------------------------------------------
/cmd/snapshots.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "github.com/spf13/cobra"
5 | )
6 |
7 | // snapshotsCmd represents the snapshots command
8 | var snapshotsCmd = &cobra.Command{
9 | Use: "snapshots",
10 | GroupID: "api",
11 | Short: "Create, view and delete snapshots if your infrastructure",
12 | Long: `Overmind automatically creates snapshots are part of the change lifecycle,
13 | however you can use these commands to interact directly with the API if
14 | required.`,
15 | Run: func(cmd *cobra.Command, args []string) {
16 | _ = cmd.Help()
17 | },
18 | }
19 |
20 | func init() {
21 | rootCmd.AddCommand(snapshotsCmd)
22 |
23 | addAPIFlags(snapshotsCmd)
24 |
25 | // Here you will define your flags and configuration settings.
26 |
27 | // Cobra supports Persistent Flags which will work for this command
28 | // and all subcommands, e.g.:
29 | // snapshotsCmd.PersistentFlags().String("foo", "", "A help for foo")
30 |
31 | // Cobra supports local flags which will only run when this command
32 | // is called directly, e.g.:
33 | // snapshotsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
34 | }
35 |
--------------------------------------------------------------------------------
/cmd/theme_darwin.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | // IsConhost returns true if the current terminal is conhost. This indicates
4 | // that it can't deal with multi-byte characters and requires special treatment.
5 | // See https://github.com/overmindtech/cli/issues/388 for detailed analysis.
6 | func IsConhost() bool {
7 | return false
8 | }
9 |
--------------------------------------------------------------------------------
/cmd/theme_linux.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import (
4 | "bytes"
5 | "os"
6 | "sync"
7 | )
8 |
9 | var isWslCache int // 0 = unset; 1 = WSL; 2 = not WSL
10 | var isWslCacheMu sync.RWMutex
11 |
12 | // IsConhost returns true if the current terminal is conhost. This indicates
13 | // that it can't deal with multi-byte characters and requires special treatment.
14 | // See https://github.com/overmindtech/cli/issues/388 for detailed analysis.
15 | func IsConhost() bool {
16 | // shortcut this if we (probably) run in Windows Terminal (through WSL) or
17 | // on something that smells like a regular Linux terminal
18 | if os.Getenv("WT_SESSION") != "" {
19 | return false
20 | }
21 |
22 | isWslCacheMu.RLock()
23 | w := isWslCache
24 | isWslCacheMu.RUnlock()
25 |
26 | switch w {
27 | case 1:
28 | return true
29 | case 2:
30 | return false
31 | }
32 |
33 | // isWslCache has not yet been initialised, so we need to check if we are in WSL
34 | // since we don't know if we are in WSL, we need to check now
35 | isWslCacheMu.Lock()
36 | defer isWslCacheMu.Unlock()
37 | if w != 0 {
38 | // someone else raced the lock and has already decided
39 | return isWslCache == 1
40 | }
41 |
42 | // check if we run in WSL
43 | ver, err := os.ReadFile("/proc/version")
44 | if err == nil && bytes.Contains(ver, []byte("Microsoft")) {
45 | isWslCache = 1
46 | return true
47 | }
48 |
49 | // we can't access /proc/version or it does not contain Microsoft, we are _probably_ not in WSL
50 | isWslCache = 2
51 | return false
52 | }
53 |
--------------------------------------------------------------------------------
/cmd/theme_windows.go:
--------------------------------------------------------------------------------
1 | package cmd
2 |
3 | import "os"
4 |
5 | // IsConhost returns true if the current terminal is conhost. This indicates
6 | // that it can't deal with multi-byte characters and requires special treatment.
7 | // See https://github.com/overmindtech/cli/issues/388 for detailed analysis.
8 | func IsConhost() bool {
9 | return os.Getenv("WT_SESSION") == ""
10 | }
11 |
--------------------------------------------------------------------------------
/demos/plan.tape:
--------------------------------------------------------------------------------
1 | Output demos/plan.gif
2 | # Output demos/plan.mp4
3 |
4 | Set Margin 20
5 | Set MarginFill "#7a70eb" # use Dark.BgMain
6 | Set BorderRadius 10
7 |
8 | Set Width 1200
9 | Set Height 900
10 |
11 | Set FontSize 15
12 |
13 | Hide
14 | Type "cd tmp"
15 | Enter
16 | Type "export PATH=$PWD:$PATH"
17 | Enter
18 | Type "clear"
19 | Enter
20 | Show
21 |
22 | Type@10ms "overmind terraform plan"
23 | Enter
24 | Sleep 2
25 | Down
26 | Sleep 500ms
27 | Down
28 | Sleep 1
29 | Enter
30 | Type "sso-dogfood"
31 | Sleep 1
32 | Enter
33 | Sleep 60
34 | Sleep 20
35 |
36 | # Ctrl+c
37 | # Sleep 10
38 |
--------------------------------------------------------------------------------
/discovery/main_test.go:
--------------------------------------------------------------------------------
1 | package discovery
2 |
3 | import (
4 | "context"
5 | "log"
6 | "os"
7 | "testing"
8 |
9 | "github.com/overmindtech/cli/tracing"
10 | )
11 |
12 | func TestMain(m *testing.M) {
13 | exitCode := func() int {
14 | defer tracing.ShutdownTracer(context.Background())
15 |
16 | if err := tracing.InitTracerWithUpstreams("discovery-tests", os.Getenv("HONEYCOMB_API_KEY"), ""); err != nil {
17 | log.Fatal(err)
18 | }
19 |
20 | return m.Run()
21 | }()
22 |
23 | os.Exit(exitCode)
24 | }
25 |
--------------------------------------------------------------------------------
/discovery/nats_shared_test.go:
--------------------------------------------------------------------------------
1 | package discovery
2 |
3 | import (
4 | "fmt"
5 | "net"
6 | "net/url"
7 | "testing"
8 | "time"
9 | )
10 |
11 | var NatsTestURLs = []string{
12 | "nats://nats:4222",
13 | "nats://localhost:4222",
14 | }
15 |
16 | var NatsAuthTestURLs = []string{
17 | "nats://nats-auth:4222",
18 | "nats://localhost:4223",
19 | }
20 |
21 | var tokenExchangeURLs = []string{
22 | "http://api-server:8080/api",
23 | "http://localhost:8080/api",
24 | }
25 |
26 | // SkipWithoutNats Skips a test if NATS is not available
27 | func SkipWithoutNats(t *testing.T) {
28 | var err error
29 |
30 | for _, url := range NatsTestURLs {
31 | err = testURL(url)
32 |
33 | if err == nil {
34 | return
35 | }
36 | }
37 |
38 | if err != nil {
39 | t.Error(err)
40 | t.Skip("NATS not available")
41 | }
42 | }
43 |
44 | // SkipWithoutNatsAuth Skips a test if authenticated NATS is not available
45 | func SkipWithoutNatsAuth(t *testing.T) {
46 | var err error
47 |
48 | for _, url := range NatsAuthTestURLs {
49 | err = testURL(url)
50 |
51 | if err == nil {
52 | return
53 | }
54 | }
55 |
56 | if err != nil {
57 | t.Error(err)
58 | t.Skip("NATS not available")
59 | }
60 | }
61 |
62 | func GetWorkingTokenExchange() (string, error) {
63 | var err error
64 |
65 | for _, url := range tokenExchangeURLs {
66 | if err = testURL(url); err == nil {
67 | return url, nil
68 | }
69 | }
70 |
71 | return "", fmt.Errorf("no working token exchanges found: %w", err)
72 | }
73 |
74 | func testURL(testURL string) error {
75 | url, err := url.Parse(testURL)
76 |
77 | if err != nil {
78 | return fmt.Errorf("could not parse NATS URL: %v. Error: %w", testURL, err)
79 | }
80 |
81 | conn, err := net.DialTimeout("tcp", net.JoinHostPort(url.Hostname(), url.Port()), time.Second)
82 |
83 | if err == nil {
84 | conn.Close()
85 | return nil
86 | }
87 |
88 | return err
89 | }
90 |
--------------------------------------------------------------------------------
/discovery/tracing.go:
--------------------------------------------------------------------------------
1 | package discovery
2 |
3 | import (
4 | "go.opentelemetry.io/otel"
5 | semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
6 | "go.opentelemetry.io/otel/trace"
7 | )
8 |
9 | const (
10 | instrumentationName = "github.com/overmindtech/cli/discovery/discovery"
11 | instrumentationVersion = "0.0.1"
12 | )
13 |
14 | var (
15 | tracer = otel.GetTracerProvider().Tracer(
16 | instrumentationName,
17 | trace.WithInstrumentationVersion(instrumentationVersion),
18 | trace.WithSchemaURL(semconv.SchemaURL),
19 | )
20 | )
21 |
--------------------------------------------------------------------------------
/examples/create-bookmark.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Changing items for 'CN=GTS Root R1,O=Google Trust Services'",
3 | "description": "This bookmark contains the items that are changing as part of the 'CN=GTS Root R1,O=Google Trust Services' change. Generated using UpdateChangingItems",
4 | "queries": [
5 | {
6 | "type": "certificate",
7 | "query": "CN=GTS Root R1,O=Google Trust Services",
8 | "scope": "global"
9 | }
10 | ]
11 | }
--------------------------------------------------------------------------------
/gon-amd64.json:
--------------------------------------------------------------------------------
1 | {
2 | "source": ["./dist/overmind-macos_darwin_amd64_v1/overmind"],
3 | "bundle_id": "tech.overmind.cli",
4 | "apple_id": {
5 | "username": "dylanratcliffe@outlook.com",
6 | "provider": "248Q4U4VT7"
7 | },
8 | "sign": {
9 | "application_identity": "CE61C10EED69BFB4B25EB349AD15B29D75A809B9"
10 | },
11 | "dmg" :{
12 | "output_path": "dist/overmind-cli-amd64.dmg",
13 | "volume_name": "Overmind"
14 | }
15 | }
--------------------------------------------------------------------------------
/gon-arm64.json:
--------------------------------------------------------------------------------
1 | {
2 | "source": ["./dist/overmind-macos_darwin_arm64/overmind"],
3 | "bundle_id": "tech.overmind.cli",
4 | "apple_id": {
5 | "username": "dylanratcliffe@outlook.com",
6 | "provider": "248Q4U4VT7"
7 | },
8 | "sign": {
9 | "application_identity": "CE61C10EED69BFB4B25EB349AD15B29D75A809B9"
10 | },
11 | "dmg" :{
12 | "output_path": "dist/overmind-cli-arm64.dmg",
13 | "volume_name": "Overmind"
14 | }
15 | }
--------------------------------------------------------------------------------
/k8s-source/acceptance/nats-server.conf:
--------------------------------------------------------------------------------
1 | # Client port of 4222 on all interfaces
2 | port: 4222
3 |
4 | # HTTP monitoring port
5 | monitor_port: 8222
6 |
7 | # This is for clustering multiple servers together.
8 | cluster {
9 | # It is recommended to set a cluster name
10 | name: "my_cluster"
11 |
12 | # Route connections to be received on any interface on port 6222
13 | port: 6222
14 |
15 | # Routes are protected, so need to use them with --routes flag
16 | # e.g. --routes=nats-route://ruser:T0pS3cr3t@otherdockerhost:6222
17 | authorization {
18 | user: ruser
19 | password: T0pS3cr3t
20 | timeout: 0.75
21 | }
22 |
23 | # Routes are actively solicited and connected to from this server.
24 | # This Docker image has none by default, but you can pass a
25 | # flag to the nats-server docker image to create one to an existing server.
26 | routes = []
27 | }
28 |
29 | websocket {
30 | port: 4433
31 | no_tls: true
32 | }
--------------------------------------------------------------------------------
/k8s-source/adapters/clusterrole.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/rbac/v1"
7 |
8 | "k8s.io/client-go/kubernetes"
9 | )
10 |
11 | func newClusterRoleAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
12 | return &KubeTypeAdapter[*v1.ClusterRole, *v1.ClusterRoleList]{
13 | ClusterName: cluster,
14 | Namespaces: namespaces,
15 | TypeName: "ClusterRole",
16 | ClusterInterfaceBuilder: func() ItemInterface[*v1.ClusterRole, *v1.ClusterRoleList] {
17 | return cs.RbacV1().ClusterRoles()
18 | },
19 | ListExtractor: func(list *v1.ClusterRoleList) ([]*v1.ClusterRole, error) {
20 | bindings := make([]*v1.ClusterRole, len(list.Items))
21 |
22 | for i := range list.Items {
23 | bindings[i] = &list.Items[i]
24 | }
25 |
26 | return bindings, nil
27 | },
28 | AdapterMetadata: clusterRoleAdapterMetadata,
29 | }
30 | }
31 |
32 | var clusterRoleAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
33 | Type: "ClusterRole",
34 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY,
35 | DescriptiveName: "Cluster Role",
36 | SupportedQueryMethods: DefaultSupportedQueryMethods("Cluster Role"),
37 | TerraformMappings: []*sdp.TerraformMapping{
38 | {
39 | TerraformMethod: sdp.QueryMethod_GET,
40 | TerraformQueryMap: "kubernetes_cluster_role_v1.metadata[0].name",
41 | },
42 | },
43 | })
44 |
45 | func init() {
46 | registerAdapterLoader(newClusterRoleAdapter)
47 | }
48 |
--------------------------------------------------------------------------------
/k8s-source/adapters/clusterrole_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var clusterRoleYAML = `
8 | apiVersion: rbac.authorization.k8s.io/v1
9 | kind: ClusterRole
10 | metadata:
11 | name: read-only
12 | rules:
13 | - apiGroups: [""]
14 | resources: ["*"]
15 | verbs: ["get", "list", "watch"]
16 |
17 | `
18 |
19 | func TestClusterRoleAdapter(t *testing.T) {
20 | adapter := newClusterRoleAdapter(CurrentCluster.ClientSet, CurrentCluster.Name, []string{})
21 |
22 | st := AdapterTests{
23 | Adapter: adapter,
24 | GetQuery: "read-only",
25 | GetScope: CurrentCluster.Name,
26 | SetupYAML: clusterRoleYAML,
27 | GetQueryTests: QueryTests{},
28 | }
29 |
30 | st.Execute(t)
31 | }
32 |
--------------------------------------------------------------------------------
/k8s-source/adapters/clusterrolebinding_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | )
8 |
9 | var clusterRoleBindingYAML = `
10 | apiVersion: rbac.authorization.k8s.io/v1
11 | kind: ClusterRoleBinding
12 | metadata:
13 | name: admin-binding
14 | subjects:
15 | - kind: Group
16 | name: system:serviceaccounts:default
17 | apiGroup: rbac.authorization.k8s.io
18 | roleRef:
19 | kind: ClusterRole
20 | name: admin
21 | apiGroup: rbac.authorization.k8s.io
22 | `
23 |
24 | func TestClusterRoleBindingAdapter(t *testing.T) {
25 | adapter := newClusterRoleBindingAdapter(CurrentCluster.ClientSet, CurrentCluster.Name, []string{})
26 |
27 | st := AdapterTests{
28 | Adapter: adapter,
29 | GetQuery: "admin-binding",
30 | GetScope: CurrentCluster.Name,
31 | SetupYAML: clusterRoleBindingYAML,
32 | GetQueryTests: QueryTests{
33 | {
34 | ExpectedType: "ClusterRole",
35 | ExpectedMethod: sdp.QueryMethod_GET,
36 | ExpectedQuery: "admin",
37 | ExpectedScope: CurrentCluster.Name,
38 | },
39 | {
40 | ExpectedType: "Group",
41 | ExpectedMethod: sdp.QueryMethod_GET,
42 | ExpectedQuery: "system:serviceaccounts:default",
43 | ExpectedScope: CurrentCluster.Name,
44 | },
45 | },
46 | }
47 |
48 | st.Execute(t)
49 | }
50 |
--------------------------------------------------------------------------------
/k8s-source/adapters/configmap.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/kubernetes"
8 | )
9 |
10 | func newConfigMapAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
11 | return &KubeTypeAdapter[*v1.ConfigMap, *v1.ConfigMapList]{
12 | ClusterName: cluster,
13 | Namespaces: namespaces,
14 | TypeName: "ConfigMap",
15 | AutoQueryExtract: true,
16 | NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.ConfigMap, *v1.ConfigMapList] {
17 | return cs.CoreV1().ConfigMaps(namespace)
18 | },
19 | ListExtractor: func(list *v1.ConfigMapList) ([]*v1.ConfigMap, error) {
20 | bindings := make([]*v1.ConfigMap, len(list.Items))
21 |
22 | for i := range list.Items {
23 | bindings[i] = &list.Items[i]
24 | }
25 |
26 | return bindings, nil
27 | },
28 | AdapterMetadata: configMapAdapterMetadata,
29 | }
30 | }
31 |
32 | var configMapAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
33 | Type: "ConfigMap",
34 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION,
35 | DescriptiveName: "Config Map",
36 | SupportedQueryMethods: DefaultSupportedQueryMethods("Config Map"),
37 | TerraformMappings: []*sdp.TerraformMapping{
38 | {
39 | TerraformMethod: sdp.QueryMethod_GET,
40 | TerraformQueryMap: "kubernetes_config_map_v1.metadata[0].name",
41 | },
42 | {
43 | TerraformMethod: sdp.QueryMethod_GET,
44 | TerraformQueryMap: "kubernetes_config_map.metadata[0].name",
45 | },
46 | },
47 | })
48 |
49 | func init() {
50 | registerAdapterLoader(newConfigMapAdapter)
51 | }
52 |
--------------------------------------------------------------------------------
/k8s-source/adapters/configmap_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import "testing"
4 |
5 | var configMapYAML = `
6 | apiVersion: v1
7 | kind: ConfigMap
8 | metadata:
9 | name: my-configmap
10 | data:
11 | DATABASE_URL: "postgres://myuser:mypassword@mydbhost:5432/mydatabase"
12 | APP_SECRET_KEY: "mysecretkey123"
13 | `
14 |
15 | func TestConfigMapAdapter(t *testing.T) {
16 | sd := ScopeDetails{
17 | ClusterName: CurrentCluster.Name,
18 | Namespace: "default",
19 | }
20 |
21 | adapter := newConfigMapAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
22 |
23 | st := AdapterTests{
24 | Adapter: adapter,
25 | GetQuery: "my-configmap",
26 | GetScope: sd.String(),
27 | SetupYAML: configMapYAML,
28 | GetQueryTests: QueryTests{},
29 | }
30 |
31 | st.Execute(t)
32 | }
33 |
--------------------------------------------------------------------------------
/k8s-source/adapters/cronjob.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/batch/v1"
7 |
8 | "k8s.io/client-go/kubernetes"
9 | )
10 |
11 | func newCronJobAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
12 | return &KubeTypeAdapter[*v1.CronJob, *v1.CronJobList]{
13 | ClusterName: cluster,
14 | Namespaces: namespaces,
15 | TypeName: "CronJob",
16 | AutoQueryExtract: true,
17 | NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.CronJob, *v1.CronJobList] {
18 | return cs.BatchV1().CronJobs(namespace)
19 | },
20 | ListExtractor: func(list *v1.CronJobList) ([]*v1.CronJob, error) {
21 | bindings := make([]*v1.CronJob, len(list.Items))
22 |
23 | for i := range list.Items {
24 | bindings[i] = &list.Items[i]
25 | }
26 |
27 | return bindings, nil
28 | },
29 | // Cronjobs don't need linked items as the jobs they produce are linked
30 | // automatically
31 | AdapterMetadata: cronJobAdapterMetadata,
32 | }
33 | }
34 |
35 | var cronJobAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
36 | Type: "CronJob",
37 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION,
38 | DescriptiveName: "Cron Job",
39 | SupportedQueryMethods: DefaultSupportedQueryMethods("Cron Job"),
40 | TerraformMappings: []*sdp.TerraformMapping{
41 | {
42 | TerraformMethod: sdp.QueryMethod_GET,
43 | TerraformQueryMap: "kubernetes_cron_job_v1.metadata[0].name",
44 | },
45 | {
46 | TerraformMethod: sdp.QueryMethod_GET,
47 | TerraformQueryMap: "kubernetes_cron_job.metadata[0].name",
48 | },
49 | },
50 | })
51 |
52 | func init() {
53 | registerAdapterLoader(newCronJobAdapter)
54 | }
55 |
--------------------------------------------------------------------------------
/k8s-source/adapters/daemonset.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/apps/v1"
7 |
8 | "k8s.io/client-go/kubernetes"
9 | )
10 |
11 | func newDaemonSetAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
12 | return &KubeTypeAdapter[*v1.DaemonSet, *v1.DaemonSetList]{
13 | ClusterName: cluster,
14 | Namespaces: namespaces,
15 | TypeName: "DaemonSet",
16 | AutoQueryExtract: true,
17 | NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.DaemonSet, *v1.DaemonSetList] {
18 | return cs.AppsV1().DaemonSets(namespace)
19 | },
20 | ListExtractor: func(list *v1.DaemonSetList) ([]*v1.DaemonSet, error) {
21 | extracted := make([]*v1.DaemonSet, len(list.Items))
22 |
23 | for i := range list.Items {
24 | extracted[i] = &list.Items[i]
25 | }
26 |
27 | return extracted, nil
28 | },
29 | // Pods are linked automatically
30 | AdapterMetadata: daemonSetAdapterMetadata,
31 | }
32 | }
33 |
34 | var daemonSetAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
35 | Type: "DaemonSet",
36 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_COMPUTE_APPLICATION,
37 | DescriptiveName: "Daemon Set",
38 | SupportedQueryMethods: DefaultSupportedQueryMethods("Daemon Set"),
39 | TerraformMappings: []*sdp.TerraformMapping{
40 | {
41 | TerraformMethod: sdp.QueryMethod_GET,
42 | TerraformQueryMap: "kubernetes_daemon_set_v1.metadata[0].name",
43 | },
44 | {
45 | TerraformMethod: sdp.QueryMethod_GET,
46 | TerraformQueryMap: "kubernetes_daemonset.metadata[0].name",
47 | },
48 | },
49 | })
50 |
51 | func init() {
52 | registerAdapterLoader(newDaemonSetAdapter)
53 | }
54 |
--------------------------------------------------------------------------------
/k8s-source/adapters/daemonset_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var daemonSetYAML = `
8 | apiVersion: apps/v1
9 | kind: DaemonSet
10 | metadata:
11 | name: my-daemonset
12 | spec:
13 | selector:
14 | matchLabels:
15 | app: my-app
16 | template:
17 | metadata:
18 | labels:
19 | app: my-app
20 | spec:
21 | containers:
22 | - name: my-container
23 | image: nginx:latest
24 | ports:
25 | - containerPort: 80
26 |
27 | `
28 |
29 | func TestDaemonSetSource(t *testing.T) {
30 | sd := ScopeDetails{
31 | ClusterName: CurrentCluster.Name,
32 | Namespace: "default",
33 | }
34 |
35 | adapter := newDaemonSetAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
36 |
37 | st := AdapterTests{
38 | Adapter: adapter,
39 | GetQuery: "my-daemonset",
40 | GetScope: sd.String(),
41 | SetupYAML: daemonSetYAML,
42 | }
43 |
44 | st.Execute(t)
45 | }
46 |
--------------------------------------------------------------------------------
/k8s-source/adapters/deployment_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | var deploymentYAML = `
11 | apiVersion: apps/v1
12 | kind: Deployment
13 | metadata:
14 | name: my-deployment
15 | spec:
16 | replicas: 1
17 | selector:
18 | matchLabels:
19 | app: my-deployment
20 | template:
21 | metadata:
22 | labels:
23 | app: my-deployment
24 | spec:
25 | containers:
26 | - name: my-container
27 | image: nginx:latest
28 | ports:
29 | - containerPort: 80
30 | `
31 |
32 | func TestDeploymentSource(t *testing.T) {
33 | sd := ScopeDetails{
34 | ClusterName: CurrentCluster.Name,
35 | Namespace: "default",
36 | }
37 |
38 | adapter := newDeploymentAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
39 |
40 | st := AdapterTests{
41 | Adapter: adapter,
42 | GetQuery: "my-deployment",
43 | GetScope: sd.String(),
44 | SetupYAML: deploymentYAML,
45 | Wait: func(item *sdp.Item) bool {
46 | return item.GetHealth() == sdp.Health_HEALTH_OK
47 | },
48 | GetQueryTests: QueryTests{
49 | {
50 | ExpectedType: "ReplicaSet",
51 | ExpectedMethod: sdp.QueryMethod_GET,
52 | ExpectedScope: "local-tests.default",
53 | ExpectedQueryMatches: regexp.MustCompile("my-deployment"),
54 | },
55 | },
56 | }
57 |
58 | st.Execute(t)
59 | }
60 |
--------------------------------------------------------------------------------
/k8s-source/adapters/horizontalpodautoscaler_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | )
8 |
9 | var horizontalPodAutoscalerYAML = `
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | metadata:
13 | name: hpa-deployment
14 | spec:
15 | replicas: 1
16 | selector:
17 | matchLabels:
18 | app: hpa-app
19 | template:
20 | metadata:
21 | labels:
22 | app: hpa-app
23 | spec:
24 | containers:
25 | - name: hpa-container
26 | image: nginx:latest
27 | ports:
28 | - containerPort: 80
29 | ---
30 | apiVersion: autoscaling/v2
31 | kind: HorizontalPodAutoscaler
32 | metadata:
33 | name: my-hpa
34 | spec:
35 | scaleTargetRef:
36 | apiVersion: apps/v1
37 | kind: Deployment
38 | name: hpa-deployment
39 | minReplicas: 1
40 | maxReplicas: 10
41 | metrics:
42 | - type: Resource
43 | resource:
44 | name: cpu
45 | target:
46 | type: Utilization
47 | averageUtilization: 50
48 | `
49 |
50 | func TestHorizontalPodAutoscalerAdapter(t *testing.T) {
51 | sd := ScopeDetails{
52 | ClusterName: CurrentCluster.Name,
53 | Namespace: "default",
54 | }
55 |
56 | adapter := newHorizontalPodAutoscalerAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
57 |
58 | st := AdapterTests{
59 | Adapter: adapter,
60 | GetQuery: "my-hpa",
61 | GetScope: sd.String(),
62 | SetupYAML: horizontalPodAutoscalerYAML,
63 | GetQueryTests: QueryTests{
64 | {
65 | ExpectedType: "Deployment",
66 | ExpectedMethod: sdp.QueryMethod_GET,
67 | ExpectedScope: sd.String(),
68 | ExpectedQuery: "hpa-deployment",
69 | },
70 | },
71 | }
72 |
73 | st.Execute(t)
74 | }
75 |
--------------------------------------------------------------------------------
/k8s-source/adapters/job_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | var jobYAML = `
11 | apiVersion: batch/v1
12 | kind: Job
13 | metadata:
14 | name: my-job
15 | spec:
16 | template:
17 | spec:
18 | containers:
19 | - name: my-container
20 | image: nginx
21 | command: ["/bin/sh", "-c"]
22 | args:
23 | - echo "Hello, world!"; sleep 5
24 | restartPolicy: OnFailure
25 | backoffLimit: 4
26 | ---
27 | apiVersion: batch/v1
28 | kind: Job
29 | metadata:
30 | name: my-job2
31 | spec:
32 | template:
33 | spec:
34 | containers:
35 | - name: my-container
36 | image: nginx
37 | command: ["/bin/sh", "-c"]
38 | args:
39 | - echo "Hello, world!"; sleep 5
40 | restartPolicy: OnFailure
41 | backoffLimit: 4
42 | `
43 |
44 | func TestJobAdapter(t *testing.T) {
45 | sd := ScopeDetails{
46 | ClusterName: CurrentCluster.Name,
47 | Namespace: "default",
48 | }
49 |
50 | adapter := newJobAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
51 |
52 | st := AdapterTests{
53 | Adapter: adapter,
54 | GetQuery: "my-job",
55 | GetScope: sd.String(),
56 | SetupYAML: jobYAML,
57 | GetQueryTests: QueryTests{
58 | {
59 | ExpectedQueryMatches: regexp.MustCompile("controller-uid="),
60 | ExpectedType: "Pod",
61 | ExpectedMethod: sdp.QueryMethod_SEARCH,
62 | ExpectedScope: sd.String(),
63 | },
64 | },
65 | }
66 |
67 | st.Execute(t)
68 | }
69 |
--------------------------------------------------------------------------------
/k8s-source/adapters/limitrange.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/kubernetes"
8 | )
9 |
10 | func newLimitRangeAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
11 | return &KubeTypeAdapter[*v1.LimitRange, *v1.LimitRangeList]{
12 | ClusterName: cluster,
13 | Namespaces: namespaces,
14 | TypeName: "LimitRange",
15 | NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.LimitRange, *v1.LimitRangeList] {
16 | return cs.CoreV1().LimitRanges(namespace)
17 | },
18 | ListExtractor: func(list *v1.LimitRangeList) ([]*v1.LimitRange, error) {
19 | extracted := make([]*v1.LimitRange, len(list.Items))
20 |
21 | for i := range list.Items {
22 | extracted[i] = &list.Items[i]
23 | }
24 |
25 | return extracted, nil
26 | },
27 | AdapterMetadata: limitRangeAdapterMetadata,
28 | }
29 | }
30 |
31 | var limitRangeAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
32 | Type: "LimitRange",
33 | DescriptiveName: "Limit Range",
34 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION,
35 | SupportedQueryMethods: DefaultSupportedQueryMethods("Limit Range"),
36 | TerraformMappings: []*sdp.TerraformMapping{
37 | {
38 | TerraformMethod: sdp.QueryMethod_GET,
39 | TerraformQueryMap: "kubernetes_limit_range_v1.metadata[0].name",
40 | },
41 | {
42 | TerraformMethod: sdp.QueryMethod_GET,
43 | TerraformQueryMap: "kubernetes_limit_range.metadata[0].name",
44 | },
45 | },
46 | })
47 |
48 | func init() {
49 | registerAdapterLoader(newLimitRangeAdapter)
50 | }
51 |
--------------------------------------------------------------------------------
/k8s-source/adapters/limitrange_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var limitRangeYAML = `
8 | apiVersion: v1
9 | kind: LimitRange
10 | metadata:
11 | name: example-limit-range
12 | spec:
13 | limits:
14 | - type: Pod
15 | max:
16 | memory: 200Mi
17 | min:
18 | cpu: 50m
19 | - type: Container
20 | max:
21 | memory: 150Mi
22 | cpu: 100m
23 | min:
24 | memory: 50Mi
25 | cpu: 50m
26 | default:
27 | memory: 100Mi
28 | cpu: 50m
29 | defaultRequest:
30 | memory: 80Mi
31 | cpu: 50m
32 | `
33 |
34 | func TestLimitRangeAdapter(t *testing.T) {
35 | sd := ScopeDetails{
36 | ClusterName: CurrentCluster.Name,
37 | Namespace: "default",
38 | }
39 |
40 | adapter := newLimitRangeAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
41 |
42 | st := AdapterTests{
43 | Adapter: adapter,
44 | GetQuery: "example-limit-range",
45 | GetScope: sd.String(),
46 | SetupYAML: limitRangeYAML,
47 | GetQueryTests: QueryTests{},
48 | }
49 |
50 | st.Execute(t)
51 | }
52 |
--------------------------------------------------------------------------------
/k8s-source/adapters/main.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "k8s.io/client-go/kubernetes"
6 | )
7 |
8 | type AdapterLoader func(clientSet *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter
9 |
10 | var adapterLoaders []AdapterLoader
11 |
12 | func registerAdapterLoader(loader AdapterLoader) {
13 | adapterLoaders = append(adapterLoaders, loader)
14 | }
15 |
16 | func LoadAllAdapters(cs *kubernetes.Clientset, cluster string, namespaces []string) []discovery.Adapter {
17 | adapters := make([]discovery.Adapter, len(adapterLoaders))
18 |
19 | for i, loader := range adapterLoaders {
20 | adapters[i] = loader(cs, cluster, namespaces)
21 | }
22 |
23 | return adapters
24 | }
25 |
--------------------------------------------------------------------------------
/k8s-source/adapters/networkpolicy_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | var NetworkPolicyYAML = `
11 | apiVersion: networking.k8s.io/v1
12 | kind: NetworkPolicy
13 | metadata:
14 | name: allow-nginx
15 | spec:
16 | podSelector:
17 | matchLabels:
18 | app: nginx
19 | policyTypes:
20 | - Ingress
21 | ingress:
22 | - from:
23 | - podSelector:
24 | matchLabels:
25 | app: frontend
26 | ports:
27 | - protocol: TCP
28 | port: 80
29 | `
30 |
31 | func TestNetworkPolicyAdapter(t *testing.T) {
32 | sd := ScopeDetails{
33 | ClusterName: CurrentCluster.Name,
34 | Namespace: "default",
35 | }
36 |
37 | adapter := newNetworkPolicyAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
38 |
39 | st := AdapterTests{
40 | Adapter: adapter,
41 | GetQuery: "allow-nginx",
42 | GetScope: sd.String(),
43 | SetupYAML: NetworkPolicyYAML,
44 | GetQueryTests: QueryTests{
45 | {
46 | ExpectedQueryMatches: regexp.MustCompile("nginx"),
47 | ExpectedType: "Pod",
48 | ExpectedMethod: sdp.QueryMethod_SEARCH,
49 | ExpectedScope: sd.String(),
50 | },
51 | },
52 | }
53 |
54 | st.Execute(t)
55 | }
56 |
--------------------------------------------------------------------------------
/k8s-source/adapters/node_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | func TestNodeAdapter(t *testing.T) {
11 | sd := ScopeDetails{
12 | ClusterName: CurrentCluster.Name,
13 | Namespace: "default",
14 | }
15 |
16 | adapter := newNodeAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
17 |
18 | st := AdapterTests{
19 | Adapter: adapter,
20 | GetQuery: "local-tests-control-plane",
21 | GetScope: sd.String(),
22 | GetQueryTests: QueryTests{
23 | {
24 | ExpectedType: "ip",
25 | ExpectedMethod: sdp.QueryMethod_GET,
26 | ExpectedScope: "global",
27 | ExpectedQueryMatches: regexp.MustCompile(`172\.`),
28 | },
29 | },
30 | }
31 |
32 | st.Execute(t)
33 | }
34 |
--------------------------------------------------------------------------------
/k8s-source/adapters/persistentvolume_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var persistentVolumeYAML = `
8 | ---
9 | apiVersion: v1
10 | kind: PersistentVolume
11 | metadata:
12 | name: pv-test-pv
13 | spec:
14 | capacity:
15 | storage: 1Gi
16 | accessModes:
17 | - ReadWriteOnce
18 | hostPath:
19 | path: /tmp/pv-test-pv
20 | `
21 |
22 | func TestPersistentVolumeAdapter(t *testing.T) {
23 | sd := ScopeDetails{
24 | ClusterName: CurrentCluster.Name,
25 | Namespace: "",
26 | }
27 |
28 | adapter := newPersistentVolumeAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
29 |
30 | st := AdapterTests{
31 | Adapter: adapter,
32 | GetQuery: "pv-test-pv",
33 | GetScope: sd.String(),
34 | SetupYAML: persistentVolumeYAML,
35 | GetQueryTests: QueryTests{},
36 | }
37 |
38 | st.Execute(t)
39 | }
40 |
--------------------------------------------------------------------------------
/k8s-source/adapters/poddisruptionbudget_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | var PodDisruptionBudgetYAML = `
11 | apiVersion: policy/v1
12 | kind: PodDisruptionBudget
13 | metadata:
14 | name: example-pdb
15 | spec:
16 | minAvailable: 2
17 | selector:
18 | matchLabels:
19 | app: example-app
20 | `
21 |
22 | func TestPodDisruptionBudgetAdapter(t *testing.T) {
23 | sd := ScopeDetails{
24 | ClusterName: CurrentCluster.Name,
25 | Namespace: "default",
26 | }
27 |
28 | adapter := newPodDisruptionBudgetAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
29 |
30 | st := AdapterTests{
31 | Adapter: adapter,
32 | GetQuery: "example-pdb",
33 | GetScope: sd.String(),
34 | SetupYAML: PodDisruptionBudgetYAML,
35 | GetQueryTests: QueryTests{
36 | {
37 | ExpectedQueryMatches: regexp.MustCompile("app=example-app"),
38 | ExpectedType: "Pod",
39 | ExpectedMethod: sdp.QueryMethod_SEARCH,
40 | ExpectedScope: sd.String(),
41 | },
42 | },
43 | }
44 |
45 | st.Execute(t)
46 | }
47 |
--------------------------------------------------------------------------------
/k8s-source/adapters/priorityclass.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/scheduling/v1"
7 |
8 | "k8s.io/client-go/kubernetes"
9 | )
10 |
11 | func newPriorityClassAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
12 | return &KubeTypeAdapter[*v1.PriorityClass, *v1.PriorityClassList]{
13 | ClusterName: cluster,
14 | Namespaces: namespaces,
15 | TypeName: "PriorityClass",
16 | ClusterInterfaceBuilder: func() ItemInterface[*v1.PriorityClass, *v1.PriorityClassList] {
17 | return cs.SchedulingV1().PriorityClasses()
18 | },
19 | ListExtractor: func(list *v1.PriorityClassList) ([]*v1.PriorityClass, error) {
20 | extracted := make([]*v1.PriorityClass, len(list.Items))
21 |
22 | for i := range list.Items {
23 | extracted[i] = &list.Items[i]
24 | }
25 |
26 | return extracted, nil
27 | },
28 | AdapterMetadata: priorityClassAdapterMetadata,
29 | }
30 | }
31 |
32 | var priorityClassAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
33 | Type: "PriorityClass",
34 | DescriptiveName: "Priority Class",
35 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION,
36 | SupportedQueryMethods: DefaultSupportedQueryMethods("Priority Class"),
37 | TerraformMappings: []*sdp.TerraformMapping{
38 | {
39 | TerraformMethod: sdp.QueryMethod_GET,
40 | TerraformQueryMap: "kubernetes_priority_class_v1.metadata[0].name",
41 | },
42 | {
43 | TerraformMethod: sdp.QueryMethod_GET,
44 | TerraformQueryMap: "kubernetes_priority_class.metadata[0].name",
45 | },
46 | },
47 | })
48 |
49 | func init() {
50 | registerAdapterLoader(newPriorityClassAdapter)
51 | }
52 |
--------------------------------------------------------------------------------
/k8s-source/adapters/priorityclass_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var priorityClassYAML = `
8 | apiVersion: scheduling.k8s.io/v1
9 | kind: PriorityClass
10 | metadata:
11 | name: ultra-mega-priority
12 | value: 1000000
13 | globalDefault: false
14 | description: "This priority class should be used for ultra-mega-priority workloads"
15 | `
16 |
17 | func TestPriorityClassAdapter(t *testing.T) {
18 | sd := ScopeDetails{
19 | ClusterName: CurrentCluster.Name,
20 | Namespace: "default",
21 | }
22 |
23 | adapter := newPriorityClassAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
24 |
25 | st := AdapterTests{
26 | Adapter: adapter,
27 | GetQuery: "ultra-mega-priority",
28 | GetScope: sd.String(),
29 | SetupYAML: priorityClassYAML,
30 | GetQueryTests: QueryTests{},
31 | }
32 |
33 | st.Execute(t)
34 | }
35 |
--------------------------------------------------------------------------------
/k8s-source/adapters/replicaset_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | var replicaSetYAML = `
11 | apiVersion: apps/v1
12 | kind: ReplicaSet
13 | metadata:
14 | name: replica-set-test
15 | spec:
16 | replicas: 1
17 | selector:
18 | matchLabels:
19 | app: replica-set-test
20 | template:
21 | metadata:
22 | labels:
23 | app: replica-set-test
24 | spec:
25 | containers:
26 | - name: replica-set-test
27 | image: nginx:latest
28 | ports:
29 | - containerPort: 80
30 |
31 | `
32 |
33 | func TestReplicaSetAdapter(t *testing.T) {
34 | sd := ScopeDetails{
35 | ClusterName: CurrentCluster.Name,
36 | Namespace: "default",
37 | }
38 |
39 | adapter := newReplicaSetAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
40 |
41 | st := AdapterTests{
42 | Adapter: adapter,
43 | GetQuery: "replica-set-test",
44 | GetScope: sd.String(),
45 | SetupYAML: replicaSetYAML,
46 | GetQueryTests: QueryTests{
47 | {
48 | ExpectedQueryMatches: regexp.MustCompile("app=replica-set-test"),
49 | ExpectedType: "Pod",
50 | ExpectedMethod: sdp.QueryMethod_SEARCH,
51 | ExpectedScope: sd.String(),
52 | },
53 | },
54 | }
55 |
56 | st.Execute(t)
57 | }
58 |
--------------------------------------------------------------------------------
/k8s-source/adapters/replicationcontroller_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "regexp"
5 | "testing"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | var replicationControllerYAML = `
11 | apiVersion: v1
12 | kind: ReplicationController
13 | metadata:
14 | name: replication-controller-test
15 | spec:
16 | replicas: 1
17 | selector:
18 | app: replication-controller-test
19 | template:
20 | metadata:
21 | labels:
22 | app: replication-controller-test
23 | spec:
24 | containers:
25 | - name: nginx
26 | image: nginx:latest
27 | ports:
28 | - containerPort: 80
29 |
30 | `
31 |
32 | func TestReplicationControllerAdapter(t *testing.T) {
33 | sd := ScopeDetails{
34 | ClusterName: CurrentCluster.Name,
35 | Namespace: "default",
36 | }
37 |
38 | adapter := newReplicationControllerAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
39 |
40 | st := AdapterTests{
41 | Adapter: adapter,
42 | GetQuery: "replication-controller-test",
43 | GetScope: sd.String(),
44 | SetupYAML: replicationControllerYAML,
45 | GetQueryTests: QueryTests{
46 | {
47 | ExpectedQueryMatches: regexp.MustCompile("app=replication-controller-test"),
48 | ExpectedType: "Pod",
49 | ExpectedMethod: sdp.QueryMethod_SEARCH,
50 | ExpectedScope: sd.String(),
51 | },
52 | },
53 | }
54 |
55 | st.Execute(t)
56 | }
57 |
--------------------------------------------------------------------------------
/k8s-source/adapters/resourcequota.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/kubernetes"
8 | )
9 |
10 | func newResourceQuotaAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
11 | return &KubeTypeAdapter[*v1.ResourceQuota, *v1.ResourceQuotaList]{
12 | ClusterName: cluster,
13 | Namespaces: namespaces,
14 | TypeName: "ResourceQuota",
15 | NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.ResourceQuota, *v1.ResourceQuotaList] {
16 | return cs.CoreV1().ResourceQuotas(namespace)
17 | },
18 | ListExtractor: func(list *v1.ResourceQuotaList) ([]*v1.ResourceQuota, error) {
19 | extracted := make([]*v1.ResourceQuota, len(list.Items))
20 |
21 | for i := range list.Items {
22 | extracted[i] = &list.Items[i]
23 | }
24 |
25 | return extracted, nil
26 | },
27 | AdapterMetadata: resourceQuotaAdapterMetadata,
28 | }
29 | }
30 |
31 | var resourceQuotaAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
32 | Type: "ResourceQuota",
33 | DescriptiveName: "Resource Quota",
34 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_CONFIGURATION,
35 | SupportedQueryMethods: DefaultSupportedQueryMethods("Resource Quota"),
36 | TerraformMappings: []*sdp.TerraformMapping{
37 | {
38 | TerraformMethod: sdp.QueryMethod_GET,
39 | TerraformQueryMap: "kubernetes_resource_quota_v1.metadata[0].name",
40 | },
41 | {
42 | TerraformMethod: sdp.QueryMethod_GET,
43 | TerraformQueryMap: "kubernetes_resource_quota.metadata[0].name",
44 | },
45 | },
46 | })
47 |
48 | func init() {
49 | registerAdapterLoader(newResourceQuotaAdapter)
50 | }
51 |
--------------------------------------------------------------------------------
/k8s-source/adapters/resourcequota_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var resourceQuotaYAML = `
8 | apiVersion: v1
9 | kind: ResourceQuota
10 | metadata:
11 | name: quota-example
12 | spec:
13 | hard:
14 | pods: "10"
15 | requests.cpu: "2"
16 | requests.memory: 2Gi
17 | limits.cpu: "4"
18 | limits.memory: 4Gi
19 | `
20 |
21 | func TestResourceQuotaAdapter(t *testing.T) {
22 | sd := ScopeDetails{
23 | ClusterName: CurrentCluster.Name,
24 | Namespace: "default",
25 | }
26 |
27 | adapter := newResourceQuotaAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
28 |
29 | st := AdapterTests{
30 | Adapter: adapter,
31 | GetQuery: "quota-example",
32 | GetScope: sd.String(),
33 | SetupYAML: resourceQuotaYAML,
34 | }
35 |
36 | st.Execute(t)
37 | }
38 |
--------------------------------------------------------------------------------
/k8s-source/adapters/role.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/rbac/v1"
7 |
8 | "k8s.io/client-go/kubernetes"
9 | )
10 |
11 | func newRoleAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
12 | return &KubeTypeAdapter[*v1.Role, *v1.RoleList]{
13 | ClusterName: cluster,
14 | Namespaces: namespaces,
15 | TypeName: "Role",
16 | NamespacedInterfaceBuilder: func(namespace string) ItemInterface[*v1.Role, *v1.RoleList] {
17 | return cs.RbacV1().Roles(namespace)
18 | },
19 | ListExtractor: func(list *v1.RoleList) ([]*v1.Role, error) {
20 | extracted := make([]*v1.Role, len(list.Items))
21 |
22 | for i := range list.Items {
23 | extracted[i] = &list.Items[i]
24 | }
25 |
26 | return extracted, nil
27 | },
28 | AdapterMetadata: roleAdapterMetadata,
29 | }
30 | }
31 |
32 | var roleAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
33 | Type: "Role",
34 | DescriptiveName: "Role",
35 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_SECURITY,
36 | SupportedQueryMethods: DefaultSupportedQueryMethods("Role"),
37 | TerraformMappings: []*sdp.TerraformMapping{
38 | {
39 | TerraformMethod: sdp.QueryMethod_GET,
40 | TerraformQueryMap: "kubernetes_role_v1.metadata[0].name",
41 | },
42 | {
43 | TerraformMethod: sdp.QueryMethod_GET,
44 | TerraformQueryMap: "kubernetes_role.metadata[0].name",
45 | },
46 | },
47 | })
48 |
49 | func init() {
50 | registerAdapterLoader(newRoleAdapter)
51 | }
52 |
--------------------------------------------------------------------------------
/k8s-source/adapters/role_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var RoleYAML = `
8 | apiVersion: rbac.authorization.k8s.io/v1
9 | kind: Role
10 | metadata:
11 | name: role-test-role
12 | rules:
13 | - apiGroups:
14 | - ""
15 | - "apps"
16 | - "batch"
17 | - "extensions"
18 | resources:
19 | - pods
20 | - deployments
21 | - jobs
22 | - cronjobs
23 | - configmaps
24 | - secrets
25 | verbs:
26 | - get
27 | - list
28 | - watch
29 | - create
30 | - update
31 | - delete
32 | `
33 |
34 | func TestRoleAdapter(t *testing.T) {
35 | sd := ScopeDetails{
36 | ClusterName: CurrentCluster.Name,
37 | Namespace: "default",
38 | }
39 |
40 | adapter := newRoleAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
41 |
42 | st := AdapterTests{
43 | Adapter: adapter,
44 | GetQuery: "role-test-role",
45 | GetScope: sd.String(),
46 | SetupYAML: RoleYAML,
47 | }
48 |
49 | st.Execute(t)
50 | }
51 |
--------------------------------------------------------------------------------
/k8s-source/adapters/secret_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var secretYAML = `
8 | apiVersion: v1
9 | kind: Secret
10 | metadata:
11 | name: secret-test-secret
12 | type: Opaque
13 | data:
14 | username: dXNlcm5hbWUx # base64-encoded "username1"
15 | password: cGFzc3dvcmQx # base64-encoded "password1"
16 |
17 | `
18 |
19 | func TestSecretAdapter(t *testing.T) {
20 | sd := ScopeDetails{
21 | ClusterName: CurrentCluster.Name,
22 | Namespace: "default",
23 | }
24 |
25 | adapter := newSecretAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
26 |
27 | st := AdapterTests{
28 | Adapter: adapter,
29 | GetQuery: "secret-test-secret",
30 | GetScope: sd.String(),
31 | SetupYAML: secretYAML,
32 | }
33 |
34 | st.Execute(t)
35 | }
36 |
--------------------------------------------------------------------------------
/k8s-source/adapters/serviceaccount_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | )
8 |
9 | var serviceAccountYAML = `
10 | apiVersion: v1
11 | kind: Secret
12 | metadata:
13 | name: service-account-secret
14 | type: Opaque
15 | data:
16 | username: Zm9vCg==
17 | password: Zm9vCg==
18 | ---
19 | apiVersion: v1
20 | kind: Secret
21 | metadata:
22 | name: service-account-secret-pull
23 | type: kubernetes.io/dockerconfigjson
24 | data:
25 | .dockerconfigjson: eyJhdXRocyI6eyJnaGNyLmlvIjp7InVzZXJuYW1lIjoiaHVudGVyIiwicGFzc3dvcmQiOiJodW50ZXIyIiwiZW1haWwiOiJmb29AYmFyLmNvbSIsImF1dGgiOiJhSFZ1ZEdWeU9taDFiblJsY2pJPSJ9fX0=
26 | ---
27 | apiVersion: v1
28 | kind: ServiceAccount
29 | metadata:
30 | name: test-service-account
31 | secrets:
32 | - name: service-account-secret
33 | imagePullSecrets:
34 | - name: service-account-secret-pull
35 | `
36 |
37 | func TestServiceAccountAdapter(t *testing.T) {
38 | sd := ScopeDetails{
39 | ClusterName: CurrentCluster.Name,
40 | Namespace: "default",
41 | }
42 |
43 | adapter := newServiceAccountAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
44 |
45 | st := AdapterTests{
46 | Adapter: adapter,
47 | GetQuery: "test-service-account",
48 | GetScope: sd.String(),
49 | SetupYAML: serviceAccountYAML,
50 | GetQueryTests: QueryTests{
51 | {
52 | ExpectedType: "Secret",
53 | ExpectedMethod: sdp.QueryMethod_GET,
54 | ExpectedQuery: "service-account-secret",
55 | ExpectedScope: sd.String(),
56 | },
57 | {
58 | ExpectedType: "Secret",
59 | ExpectedMethod: sdp.QueryMethod_GET,
60 | ExpectedQuery: "service-account-secret-pull",
61 | ExpectedScope: sd.String(),
62 | },
63 | },
64 | }
65 |
66 | st.Execute(t)
67 | }
68 |
--------------------------------------------------------------------------------
/k8s-source/adapters/storageclass.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "github.com/overmindtech/cli/discovery"
5 | "github.com/overmindtech/cli/sdp-go"
6 | v1 "k8s.io/api/storage/v1"
7 |
8 | "k8s.io/client-go/kubernetes"
9 | )
10 |
11 | func newStorageClassAdapter(cs *kubernetes.Clientset, cluster string, namespaces []string) discovery.ListableAdapter {
12 | return &KubeTypeAdapter[*v1.StorageClass, *v1.StorageClassList]{
13 | ClusterName: cluster,
14 | Namespaces: namespaces,
15 | TypeName: "StorageClass",
16 | ClusterInterfaceBuilder: func() ItemInterface[*v1.StorageClass, *v1.StorageClassList] {
17 | return cs.StorageV1().StorageClasses()
18 | },
19 | ListExtractor: func(list *v1.StorageClassList) ([]*v1.StorageClass, error) {
20 | extracted := make([]*v1.StorageClass, len(list.Items))
21 |
22 | for i := range list.Items {
23 | extracted[i] = &list.Items[i]
24 | }
25 |
26 | return extracted, nil
27 | },
28 | AdapterMetadata: storageClassAdapterMetadata,
29 | }
30 | }
31 |
32 | var storageClassAdapterMetadata = Metadata.Register(&sdp.AdapterMetadata{
33 | Type: "StorageClass",
34 | DescriptiveName: "Storage Class",
35 | Category: sdp.AdapterCategory_ADAPTER_CATEGORY_STORAGE,
36 | SupportedQueryMethods: DefaultSupportedQueryMethods("Storage Class"),
37 | TerraformMappings: []*sdp.TerraformMapping{
38 | {
39 | TerraformMethod: sdp.QueryMethod_GET,
40 | TerraformQueryMap: "kubernetes_storage_class.metadata[0].name",
41 | },
42 | {
43 | TerraformMethod: sdp.QueryMethod_GET,
44 | TerraformQueryMap: "kubernetes_storage_class_v1.metadata[0].name",
45 | },
46 | },
47 | })
48 |
49 | func init() {
50 | registerAdapterLoader(newStorageClassAdapter)
51 | }
52 |
--------------------------------------------------------------------------------
/k8s-source/adapters/storageclass_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | var storageClassYAML = `
8 | apiVersion: storage.k8s.io/v1
9 | kind: StorageClass
10 | metadata:
11 | name: storage-class-test
12 | provisioner: kubernetes.io/aws-ebs
13 | parameters:
14 | type: gp2
15 |
16 | `
17 |
18 | func TestStorageClassAdapter(t *testing.T) {
19 | sd := ScopeDetails{
20 | ClusterName: CurrentCluster.Name,
21 | Namespace: "default",
22 | }
23 |
24 | adapter := newStorageClassAdapter(CurrentCluster.ClientSet, sd.ClusterName, []string{sd.Namespace})
25 |
26 | st := AdapterTests{
27 | Adapter: adapter,
28 | GetQuery: "storage-class-test",
29 | GetScope: sd.String(),
30 | SetupYAML: storageClassYAML,
31 | }
32 |
33 | st.Execute(t)
34 | }
35 |
--------------------------------------------------------------------------------
/k8s-source/build/package/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build the source binary
2 | FROM golang:1.24-alpine AS builder
3 | ARG TARGETOS
4 | ARG TARGETARCH
5 | ARG BUILD_VERSION
6 | ARG BUILD_COMMIT
7 |
8 | # required for accessing the private dependencies and generating version descriptor
9 | RUN apk add --no-cache git curl
10 |
11 | WORKDIR /workspace
12 |
13 | # Copy the go source
14 | COPY . .
15 |
16 | # Build
17 | RUN --mount=type=cache,target=/go/pkg \
18 | --mount=type=cache,target=/root/.cache/go-build \
19 | GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/tracing.commit=${BUILD_COMMIT}" -o source k8s-source/main.go
20 |
21 | FROM alpine:3.21
22 | WORKDIR /
23 | COPY --from=builder /workspace/source .
24 | USER 65534:65534
25 |
26 | ENTRYPOINT ["/source"]
27 |
--------------------------------------------------------------------------------
/k8s-source/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "auths": {
3 | "ghcr.io": {},
4 | },
5 | "credsStore": "desktop"
6 | }
7 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | name: overmind-kube-source
3 | description: A source that allows Overmind to read from the current Kubernetes cluster
4 |
5 | # A chart can be either an 'application' or a 'library' chart.
6 | #
7 | # Application charts are a collection of templates that can be packaged into versioned archives
8 | # to be deployed.
9 | #
10 | # Library charts provide useful utilities or functions for the chart developer. They're included as
11 | # a dependency of application charts to inject those utilities and functions into the rendering
12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed.
13 | type: application
14 |
15 | # This is the chart version. This version number should be incremented each time you make changes
16 | # to the chart and its templates, including the app version.
17 | # Versions are expected to follow Semantic Versioning (https://semver.org/)
18 | #
19 | # This is set during CI
20 | version: 0.0.0
21 |
22 | # This is the version number of the application being deployed. This version number should be
23 | # incremented each time you make changes to the application. Versions are not expected to
24 | # follow Semantic Versioning. They should reflect the version the application is using.
25 | # It is recommended to use it with quotes.
26 | #
27 | # This is set during CI
28 | appVersion: "0.0.0"
29 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/README.md:
--------------------------------------------------------------------------------
1 | # K8s Source Helm Chart
2 |
3 | ## Developing
4 |
5 | Installing into a local cluster:
6 |
7 | ```shell
8 | helm install k8s-source deployments/overmind-kube-source --set source.natsJWT=REPLACEME,source.natsNKeySeed=REPLACEME
9 | ```
10 |
11 | Removing the chart:
12 |
13 | ```shell
14 | helm uninstall k8s-source
15 | ```
16 |
17 | ## Releasing
18 |
19 | These charts are automatically released and pushed to Cloudsmith when the monorepo is tagged with a version in the following format `k8s-source/v1.2.3`. This will cause the docker container to be built, tagged with `1.2.3`, pushed, and a new corresponding helm chart released. See `.github/workflows/k8s-source-release.yml` for more details
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/NOTES.txt:
--------------------------------------------------------------------------------
1 | The overmind source has now been installed ✅
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/clusterrole.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRole
3 | metadata:
4 | name: {{ include "overmind-kube-source.clusterRoleName" . }}
5 | rules:
6 | - apiGroups: ["*"]
7 | resources: ["*"]
8 | verbs: ["get", "list", "watch"]
9 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/clusterrolebinding.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: rbac.authorization.k8s.io/v1
2 | kind: ClusterRoleBinding
3 | metadata:
4 | name: {{ include "overmind-kube-source.clusterRoleBindingName" . }}
5 | subjects:
6 | - kind: ServiceAccount
7 | name: {{ include "overmind-kube-source.serviceAccountName" . }}
8 | namespace: {{ .Release.Namespace }}
9 | roleRef:
10 | kind: ClusterRole
11 | name: {{ include "overmind-kube-source.clusterRoleName" . }}
12 | apiGroup: rbac.authorization.k8s.io
13 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | # ConfigMap definition
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: {{ include "overmind-kube-source.fullname" . }}-config
7 | data:
8 | LOG: {{ .Values.source.log }}
9 | MAX_PARALLEL: {{ .Values.source.maxParallel | quote }}
10 | SOURCE_NAME: {{ .Chart.Name }}
11 | RATE_LIMIT_QPS: {{ .Values.source.rateLimitQPS | quote }}
12 | RATE_LIMIT_BURST: {{ .Values.source.rateLimitBurst | quote }}
13 | {{- if .Values.source.clusterName }}
14 | CLUSTER_NAME: {{ .Values.source.clusterName | quote }}
15 | {{- end }}
16 | {{- if .Values.source.app }}
17 | APP: {{ .Values.source.app | quote }}
18 | {{- end }}
19 | {{- if .Values.source.honeycombApiKey }}
20 | HONEYCOMB_API_KEY: {{ .Values.source.honeycombApiKey | quote }}
21 | {{- end }}
22 | ---
23 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/hpa.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.autoscaling.enabled }}
2 | apiVersion: autoscaling/v2
3 | kind: HorizontalPodAutoscaler
4 | metadata:
5 | name: {{ include "overmind-kube-source.fullname" . }}
6 | labels:
7 | {{- include "overmind-kube-source.labels" . | nindent 4 }}
8 | spec:
9 | scaleTargetRef:
10 | apiVersion: apps/v1
11 | kind: Deployment
12 | name: {{ include "overmind-kube-source.fullname" . }}
13 | minReplicas: {{ .Values.autoscaling.minReplicas }}
14 | maxReplicas: {{ .Values.autoscaling.maxReplicas }}
15 | metrics:
16 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
17 | - type: Resource
18 | resource:
19 | name: cpu
20 | target:
21 | type: Utilization
22 | averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
23 | {{- end }}
24 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
25 | - type: Resource
26 | resource:
27 | name: memory
28 | target:
29 | type: Utilization
30 | averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
31 | {{- end }}
32 | {{- end }}
33 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/secret.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.source.apiKey.value }}
2 | apiVersion: v1
3 | kind: Secret
4 | metadata:
5 | name: {{ include "overmind-kube-source.fullname" . }}-secrets
6 | type: Opaque
7 | data:
8 | API_KEY: {{ .Values.source.apiKey.value | b64enc }}
9 | {{- end }}
10 |
--------------------------------------------------------------------------------
/k8s-source/deployments/overmind-kube-source/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ServiceAccount
3 | metadata:
4 | name: {{ include "overmind-kube-source.serviceAccountName" . }}
5 | labels:
6 | {{- include "overmind-kube-source.labels" . | nindent 4 }}
7 | {{- with .Values.serviceAccount.annotations }}
8 | annotations:
9 | {{- toYaml . | nindent 4 }}
10 | {{- end }}
11 |
--------------------------------------------------------------------------------
/k8s-source/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2021 Dylan Ratcliffe
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package main
17 |
18 | import (
19 | "github.com/overmindtech/cli/k8s-source/cmd"
20 | _ "go.uber.org/automaxprocs"
21 | )
22 |
23 | func main() {
24 | cmd.Execute()
25 | }
26 |
--------------------------------------------------------------------------------
/lostpixel.config.ts:
--------------------------------------------------------------------------------
1 | import { CustomProjectConfig } from 'lost-pixel';
2 |
3 | export const config: CustomProjectConfig = {
4 | customShots: {
5 | currentShotsPath: "./e2e",
6 | },
7 |
8 | // Lost Pixel Platform (to use in Platform mode, comment out the OSS mode and uncomment this part )
9 | lostPixelProjectId: 'cm67zty5r073v6ql0ii68nq5f',
10 | apiKey: process.env.LOST_PIXEL_API_KEY,
11 | };
12 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/charmbracelet/lipgloss"
5 | "github.com/muesli/termenv"
6 | "github.com/overmindtech/cli/cmd"
7 | )
8 |
9 | func main() {
10 | // work around lipgloss/termenv integration bug.
11 | // See https://github.com/charmbracelet/lipgloss/issues/73#issuecomment-1144921037
12 | lipgloss.SetHasDarkBackground(termenv.HasDarkBackground())
13 |
14 | cmd.Execute()
15 | }
16 |
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | # This is a very simple example to deploy a few cheap resources into AWS to test the new `terraform plan` and `terraform apply` subcommands.
2 |
3 | terraform {
4 | required_version = ">= 1.5.0"
5 |
6 | required_providers {
7 | aws = {
8 | source = "hashicorp/aws"
9 | version = ">= 4.56"
10 | }
11 | }
12 | }
13 |
14 | provider "aws" {}
15 | provider "aws" {
16 | alias = "aliased"
17 | region = "us-east-1"
18 | }
19 |
20 | variable "bucket_postfix" {
21 | type = string
22 | description = "The prefix to apply to the bucket name."
23 | default = "test"
24 | }
25 |
26 | module "bucket" {
27 | source = "terraform-aws-modules/s3-bucket/aws"
28 | version = "~> 4.0"
29 |
30 | bucket_prefix = "cli-test${var.bucket_postfix}"
31 |
32 | control_object_ownership = true
33 | object_ownership = "BucketOwnerEnforced"
34 | block_public_policy = true
35 | block_public_acls = true
36 | ignore_public_acls = true
37 | restrict_public_buckets = true
38 | }
39 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cli",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "lost-pixel": "lost-pixel",
8 | "lost-pixel:update": "lost-pixel update"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "@types/node": "^22.0.0",
15 | "lost-pixel": "^3.17.0"
16 | },
17 | "engines": {
18 | "node": "^22.0.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/sdp-go/.gitignore:
--------------------------------------------------------------------------------
1 | vendor
2 | .DS_Store
3 |
--------------------------------------------------------------------------------
/sdp-go/account.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | import "github.com/google/uuid"
4 |
5 | func (a *SourceMetadata) GetUUIDParsed() *uuid.UUID {
6 | u, err := uuid.FromBytes(a.GetUUID())
7 | if err != nil {
8 | return nil
9 | }
10 | return &u
11 | }
12 |
13 | func (a *SourceHealth) GetUUIDParsed() *uuid.UUID {
14 | u, err := uuid.FromBytes(a.GetUUID())
15 | if err != nil {
16 | return nil
17 | }
18 | return &u
19 | }
20 |
--------------------------------------------------------------------------------
/sdp-go/apikey.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | import "github.com/google/uuid"
4 |
5 | func (a *APIKeyMetadata) GetUUIDParsed() *uuid.UUID {
6 | u, err := uuid.FromBytes(a.GetUuid())
7 | if err != nil {
8 | return nil
9 | }
10 | return &u
11 | }
12 |
--------------------------------------------------------------------------------
/sdp-go/bookmarks.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | func (b *Bookmark) ToMap() map[string]any {
4 | return map[string]any{
5 | "metadata": b.GetMetadata().ToMap(),
6 | "properties": b.GetProperties().ToMap(),
7 | }
8 | }
9 |
10 | func (bm *BookmarkMetadata) ToMap() map[string]any {
11 | return map[string]any{
12 | "UUID": stringFromUuidBytes(bm.GetUUID()),
13 | "created": bm.GetCreated().AsTime(),
14 | }
15 | }
16 |
17 | func (bp *BookmarkProperties) ToMap() map[string]any {
18 | return map[string]any{
19 | "name": bp.GetName(),
20 | "description": bp.GetDescription(),
21 | "queries": bp.GetQueries(),
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sdp-go/changetimeline.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | type ChangeTimelineEntryV2Name string
4 |
5 | // If you add/delete/move an entry here, make sure to update/check the following:
6 | // - the PopulateChangeTimelineV2 function
7 | // - GetChangeTimelineV2 in api-server/server/changesservice.go
8 | // - resetChangeAnalysisTables in api-server/server/changeanalysis/shared.go
9 | // - the cli tool if we are waiting for a change analysis to finish
10 | const (
11 | ChangeTimelineEntryV2NameChangeCreated ChangeTimelineEntryV2Name = "Change Created"
12 | ChangeTimelineEntryV2NameMappedResources ChangeTimelineEntryV2Name = "Mapped Resources"
13 | ChangeTimelineEntryV2NameCalculatedBlastRadius ChangeTimelineEntryV2Name = "Calculated Blast Radius"
14 | ChangeTimelineEntryV2NameCalculatedRisks ChangeTimelineEntryV2Name = "Calculated Risks"
15 | ChangeTimelineEntryV2NameAutoTagging ChangeTimelineEntryV2Name = "Auto Tagging"
16 | ChangeTimelineEntryV2NameChangeStarted ChangeTimelineEntryV2Name = "Change Started"
17 | ChangeTimelineEntryV2NameChangeFinished ChangeTimelineEntryV2Name = "Change Finished"
18 | )
19 |
--------------------------------------------------------------------------------
/sdp-go/compare.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | import "fmt"
4 |
5 | // Comparer is an object that can be compared for the purposes of sorting.
6 | // Basically anything that implements this interface is sortable
7 | type Comparer interface {
8 | Compare(b *Item) int
9 | }
10 |
11 | // Compare compares two Items for the purposes of sorting. This sorts based on
12 | // the string conversion of the Type, followed by the UniqueAttribute
13 | func (i *Item) Compare(r *Item) (int, error) {
14 | // Convert to strings
15 | right := fmt.Sprintf("%v: %v", r.GetType(), r.UniqueAttributeValue())
16 | left := fmt.Sprintf("%v: %v", i.GetType(), i.UniqueAttributeValue())
17 |
18 | // Compare the strings and return the value
19 | switch {
20 | case left > right:
21 | return 1, nil
22 | case left < right:
23 | return -1, nil
24 | default:
25 | return 0, nil
26 | }
27 | }
28 |
29 | // CompareError is returned when two Items cannot be compared because their
30 | // UniqueAttributeValue() is not sortable
31 | type CompareError Item
32 |
33 | // Error returns the string when the error is handled
34 | func (c *CompareError) Error() string {
35 | return (fmt.Sprintf(
36 | "Item %v unique attribute: %v of type %v does not implement interface fmt.Stringer. Cannot sort.",
37 | c.Type,
38 | c.UniqueAttribute,
39 | c.Type,
40 | ))
41 | }
42 |
--------------------------------------------------------------------------------
/sdp-go/connection_test.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | import (
4 | "context"
5 | "testing"
6 | )
7 |
8 | // This is an example of a Query with a timeout. This attribute was removed and
9 | // replaced with a `reserved` field. Therefore it is being used to test how we
10 | // handle older messages
11 | var exampleRemovedAttribute = []byte{
12 | 0xa, 0x3, 0x66, 0x6f, 0x6f, 0x1a, 0x3, 0x66, 0x6f, 0x6f, 0x22, 0x4, 0x8,
13 | 0xa, 0x10, 0x1, 0x2a, 0x3, 0x66, 0x6f, 0x6f, 0x30, 0x1, 0x3a, 0x10, 0x4e,
14 | 0x43, 0x68, 0xd9, 0x17, 0xd4, 0x4d, 0x83, 0xa9, 0xe6, 0xf5, 0x3a, 0xec,
15 | 0xc7, 0xe7, 0xf0, 0x42, 0x2, 0x8, 0xa,
16 | }
17 |
18 | func TestUnmarshal(t *testing.T) {
19 | ctx := context.Background()
20 | query := new(Query)
21 |
22 | err := Unmarshal(ctx, exampleRemovedAttribute, query)
23 |
24 | if err != nil {
25 | t.Error(err)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sdp-go/errors.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 |
7 | "github.com/google/uuid"
8 | )
9 |
10 | const ErrorTemplate string = `%v
11 |
12 | ErrorType: %v
13 | Scope: %v
14 | SourceName: %v
15 | ItemType: %v
16 | ResponderName: %v`
17 |
18 | // assert interface
19 | var _ error = (*QueryError)(nil)
20 |
21 | func (e *QueryError) GetUUIDParsed() *uuid.UUID {
22 | u, err := uuid.FromBytes(e.GetUUID())
23 | if err != nil {
24 | return nil
25 | }
26 | return &u
27 | }
28 |
29 | // Ensure that the QueryError is seen as a valid error in golang
30 | func (e *QueryError) Error() string {
31 | return fmt.Sprintf(
32 | ErrorTemplate,
33 | e.GetErrorString(),
34 | e.GetErrorType().String(),
35 | e.GetScope(),
36 | e.GetSourceName(),
37 | e.GetItemType(),
38 | e.GetResponderName(),
39 | )
40 | }
41 |
42 | // NewQueryError converts a regular error to a QueryError of type
43 | // OTHER. If the input error is already a QueryError then it is preserved
44 | func NewQueryError(err error) *QueryError {
45 | var sdpErr *QueryError
46 | if errors.As(err, &sdpErr) {
47 | return sdpErr
48 | }
49 |
50 | return &QueryError{
51 | ErrorType: QueryError_OTHER,
52 | ErrorString: err.Error(),
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/sdp-go/handler_cancelquery.go:
--------------------------------------------------------------------------------
1 | // Code generated by "genhandler CancelQuery"; DO NOT EDIT
2 |
3 | package sdp
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/nats-io/nats.go"
9 | "github.com/overmindtech/cli/tracing"
10 | "go.opentelemetry.io/otel/trace"
11 | )
12 |
13 | func NewCancelQueryHandler(spanName string, h func(ctx context.Context, i *CancelQuery), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
14 | return NewOtelExtractingHandler(
15 | spanName,
16 | func(ctx context.Context, m *nats.Msg) {
17 | var i CancelQuery
18 | err := Unmarshal(ctx, m.Data, &i)
19 | if err != nil {
20 | return
21 | }
22 | h(ctx, &i)
23 | },
24 | tracing.Tracer(),
25 | )
26 | }
27 |
28 | func NewRawCancelQueryHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *CancelQuery), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
29 | return NewOtelExtractingHandler(
30 | spanName,
31 | func(ctx context.Context, m *nats.Msg) {
32 | var i CancelQuery
33 | err := Unmarshal(ctx, m.Data, &i)
34 | if err != nil {
35 | return
36 | }
37 | h(ctx, m, &i)
38 | },
39 | tracing.Tracer(),
40 | )
41 | }
42 |
43 | func NewAsyncRawCancelQueryHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *CancelQuery), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
44 | return NewAsyncOtelExtractingHandler(
45 | spanName,
46 | func(ctx context.Context, m *nats.Msg) {
47 | var i CancelQuery
48 | err := Unmarshal(ctx, m.Data, &i)
49 | if err != nil {
50 | return
51 | }
52 | h(ctx, m, &i)
53 | },
54 | tracing.Tracer(),
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/sdp-go/handler_gatewayresponse.go:
--------------------------------------------------------------------------------
1 | // Code generated by "genhandler GatewayResponse"; DO NOT EDIT
2 |
3 | package sdp
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/nats-io/nats.go"
9 | "github.com/overmindtech/cli/tracing"
10 | "go.opentelemetry.io/otel/trace"
11 | )
12 |
13 | func NewGatewayResponseHandler(spanName string, h func(ctx context.Context, i *GatewayResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
14 | return NewOtelExtractingHandler(
15 | spanName,
16 | func(ctx context.Context, m *nats.Msg) {
17 | var i GatewayResponse
18 | err := Unmarshal(ctx, m.Data, &i)
19 | if err != nil {
20 | return
21 | }
22 | h(ctx, &i)
23 | },
24 | tracing.Tracer(),
25 | )
26 | }
27 |
28 | func NewRawGatewayResponseHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *GatewayResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
29 | return NewOtelExtractingHandler(
30 | spanName,
31 | func(ctx context.Context, m *nats.Msg) {
32 | var i GatewayResponse
33 | err := Unmarshal(ctx, m.Data, &i)
34 | if err != nil {
35 | return
36 | }
37 | h(ctx, m, &i)
38 | },
39 | tracing.Tracer(),
40 | )
41 | }
42 |
43 | func NewAsyncRawGatewayResponseHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *GatewayResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
44 | return NewAsyncOtelExtractingHandler(
45 | spanName,
46 | func(ctx context.Context, m *nats.Msg) {
47 | var i GatewayResponse
48 | err := Unmarshal(ctx, m.Data, &i)
49 | if err != nil {
50 | return
51 | }
52 | h(ctx, m, &i)
53 | },
54 | tracing.Tracer(),
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/sdp-go/handler_natsgetlogrecordsrequest.go:
--------------------------------------------------------------------------------
1 | // Code generated by "genhandler NATSGetLogRecordsRequest"; DO NOT EDIT
2 |
3 | package sdp
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/nats-io/nats.go"
9 | "github.com/overmindtech/cli/tracing"
10 | "go.opentelemetry.io/otel/trace"
11 | )
12 |
13 | func NewNATSGetLogRecordsRequestHandler(spanName string, h func(ctx context.Context, i *NATSGetLogRecordsRequest), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
14 | return NewOtelExtractingHandler(
15 | spanName,
16 | func(ctx context.Context, m *nats.Msg) {
17 | var i NATSGetLogRecordsRequest
18 | err := Unmarshal(ctx, m.Data, &i)
19 | if err != nil {
20 | return
21 | }
22 | h(ctx, &i)
23 | },
24 | tracing.Tracer(),
25 | )
26 | }
27 |
28 | func NewRawNATSGetLogRecordsRequestHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *NATSGetLogRecordsRequest), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
29 | return NewOtelExtractingHandler(
30 | spanName,
31 | func(ctx context.Context, m *nats.Msg) {
32 | var i NATSGetLogRecordsRequest
33 | err := Unmarshal(ctx, m.Data, &i)
34 | if err != nil {
35 | return
36 | }
37 | h(ctx, m, &i)
38 | },
39 | tracing.Tracer(),
40 | )
41 | }
42 |
43 | func NewAsyncRawNATSGetLogRecordsRequestHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *NATSGetLogRecordsRequest), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
44 | return NewAsyncOtelExtractingHandler(
45 | spanName,
46 | func(ctx context.Context, m *nats.Msg) {
47 | var i NATSGetLogRecordsRequest
48 | err := Unmarshal(ctx, m.Data, &i)
49 | if err != nil {
50 | return
51 | }
52 | h(ctx, m, &i)
53 | },
54 | tracing.Tracer(),
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/sdp-go/handler_natsgetlogrecordsresponse.go:
--------------------------------------------------------------------------------
1 | // Code generated by "genhandler NATSGetLogRecordsResponse"; DO NOT EDIT
2 |
3 | package sdp
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/nats-io/nats.go"
9 | "github.com/overmindtech/cli/tracing"
10 | "go.opentelemetry.io/otel/trace"
11 | )
12 |
13 | func NewNATSGetLogRecordsResponseHandler(spanName string, h func(ctx context.Context, i *NATSGetLogRecordsResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
14 | return NewOtelExtractingHandler(
15 | spanName,
16 | func(ctx context.Context, m *nats.Msg) {
17 | var i NATSGetLogRecordsResponse
18 | err := Unmarshal(ctx, m.Data, &i)
19 | if err != nil {
20 | return
21 | }
22 | h(ctx, &i)
23 | },
24 | tracing.Tracer(),
25 | )
26 | }
27 |
28 | func NewRawNATSGetLogRecordsResponseHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *NATSGetLogRecordsResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
29 | return NewOtelExtractingHandler(
30 | spanName,
31 | func(ctx context.Context, m *nats.Msg) {
32 | var i NATSGetLogRecordsResponse
33 | err := Unmarshal(ctx, m.Data, &i)
34 | if err != nil {
35 | return
36 | }
37 | h(ctx, m, &i)
38 | },
39 | tracing.Tracer(),
40 | )
41 | }
42 |
43 | func NewAsyncRawNATSGetLogRecordsResponseHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *NATSGetLogRecordsResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
44 | return NewAsyncOtelExtractingHandler(
45 | spanName,
46 | func(ctx context.Context, m *nats.Msg) {
47 | var i NATSGetLogRecordsResponse
48 | err := Unmarshal(ctx, m.Data, &i)
49 | if err != nil {
50 | return
51 | }
52 | h(ctx, m, &i)
53 | },
54 | tracing.Tracer(),
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/sdp-go/handler_query.go:
--------------------------------------------------------------------------------
1 | // Code generated by "genhandler Query"; DO NOT EDIT
2 |
3 | package sdp
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/nats-io/nats.go"
9 | "github.com/overmindtech/cli/tracing"
10 | "go.opentelemetry.io/otel/trace"
11 | )
12 |
13 | func NewQueryHandler(spanName string, h func(ctx context.Context, i *Query), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
14 | return NewOtelExtractingHandler(
15 | spanName,
16 | func(ctx context.Context, m *nats.Msg) {
17 | var i Query
18 | err := Unmarshal(ctx, m.Data, &i)
19 | if err != nil {
20 | return
21 | }
22 | h(ctx, &i)
23 | },
24 | tracing.Tracer(),
25 | )
26 | }
27 |
28 | func NewRawQueryHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *Query), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
29 | return NewOtelExtractingHandler(
30 | spanName,
31 | func(ctx context.Context, m *nats.Msg) {
32 | var i Query
33 | err := Unmarshal(ctx, m.Data, &i)
34 | if err != nil {
35 | return
36 | }
37 | h(ctx, m, &i)
38 | },
39 | tracing.Tracer(),
40 | )
41 | }
42 |
43 | func NewAsyncRawQueryHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *Query), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
44 | return NewAsyncOtelExtractingHandler(
45 | spanName,
46 | func(ctx context.Context, m *nats.Msg) {
47 | var i Query
48 | err := Unmarshal(ctx, m.Data, &i)
49 | if err != nil {
50 | return
51 | }
52 | h(ctx, m, &i)
53 | },
54 | tracing.Tracer(),
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/sdp-go/handler_queryresponse.go:
--------------------------------------------------------------------------------
1 | // Code generated by "genhandler QueryResponse"; DO NOT EDIT
2 |
3 | package sdp
4 |
5 | import (
6 | "context"
7 |
8 | "github.com/nats-io/nats.go"
9 | "github.com/overmindtech/cli/tracing"
10 | "go.opentelemetry.io/otel/trace"
11 | )
12 |
13 | func NewQueryResponseHandler(spanName string, h func(ctx context.Context, i *QueryResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
14 | return NewOtelExtractingHandler(
15 | spanName,
16 | func(ctx context.Context, m *nats.Msg) {
17 | var i QueryResponse
18 | err := Unmarshal(ctx, m.Data, &i)
19 | if err != nil {
20 | return
21 | }
22 | h(ctx, &i)
23 | },
24 | tracing.Tracer(),
25 | )
26 | }
27 |
28 | func NewRawQueryResponseHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *QueryResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
29 | return NewOtelExtractingHandler(
30 | spanName,
31 | func(ctx context.Context, m *nats.Msg) {
32 | var i QueryResponse
33 | err := Unmarshal(ctx, m.Data, &i)
34 | if err != nil {
35 | return
36 | }
37 | h(ctx, m, &i)
38 | },
39 | tracing.Tracer(),
40 | )
41 | }
42 |
43 | func NewAsyncRawQueryResponseHandler(spanName string, h func(ctx context.Context, m *nats.Msg, i *QueryResponse), spanOpts ...trace.SpanStartOption) nats.MsgHandler {
44 | return NewAsyncOtelExtractingHandler(
45 | spanName,
46 | func(ctx context.Context, m *nats.Msg) {
47 | var i QueryResponse
48 | err := Unmarshal(ctx, m.Data, &i)
49 | if err != nil {
50 | return
51 | }
52 | h(ctx, m, &i)
53 | },
54 | tracing.Tracer(),
55 | )
56 | }
57 |
--------------------------------------------------------------------------------
/sdp-go/responses.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | // TODO: instead of translating, unify this
4 | func (r *Response) ToQueryStatus() *QueryStatus {
5 | return &QueryStatus{
6 | UUID: r.GetUUID(),
7 | Status: r.GetState().ToQueryStatus(),
8 | }
9 | }
10 |
11 | // TODO: instead of translating, unify this
12 | func (r ResponderState) ToQueryStatus() QueryStatus_Status {
13 | switch r {
14 | case ResponderState_WORKING:
15 | return QueryStatus_STARTED
16 | case ResponderState_COMPLETE:
17 | return QueryStatus_FINISHED
18 | case ResponderState_ERROR:
19 | return QueryStatus_ERRORED
20 | case ResponderState_CANCELLED:
21 | return QueryStatus_CANCELLED
22 | case ResponderState_STALLED:
23 | return QueryStatus_ERRORED
24 | default:
25 | return QueryStatus_UNSPECIFIED
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sdp-go/snapshots.go:
--------------------------------------------------------------------------------
1 | package sdp
2 |
3 | func (s *Snapshot) ToMap() map[string]any {
4 | return map[string]any{
5 | "metadata": s.GetMetadata().ToMap(),
6 | "properties": s.GetProperties().ToMap(),
7 | }
8 | }
9 |
10 | func (sm *SnapshotMetadata) ToMap() map[string]any {
11 | return map[string]any{
12 | "UUID": stringFromUuidBytes(sm.GetUUID()),
13 | "created": sm.GetCreated().AsTime(),
14 | }
15 | }
16 |
17 | func (sp *SnapshotProperties) ToMap() map[string]any {
18 | return map[string]any{
19 | "name": sp.GetName(),
20 | "description": sp.GetDescription(),
21 | "queries": sp.GetQueries(),
22 | "Items": sp.GetItems(),
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sdp-go/tracing/main.go:
--------------------------------------------------------------------------------
1 | package tracing
2 |
3 | import (
4 | _ "embed"
5 |
6 | "go.opentelemetry.io/otel"
7 | semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
8 | "go.opentelemetry.io/otel/trace"
9 | )
10 |
11 | const instrumentationName = "github.com/overmindtech/cli/sdp-go"
12 |
13 | var (
14 | tracer = otel.GetTracerProvider().Tracer(
15 | instrumentationName,
16 | trace.WithSchemaURL(semconv.SchemaURL),
17 | )
18 | )
19 |
20 | func Tracer() trace.Tracer {
21 | return tracer
22 | }
23 |
--------------------------------------------------------------------------------
/sources/aws/base.go:
--------------------------------------------------------------------------------
1 | package aws
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | "github.com/overmindtech/cli/sources/shared"
8 | )
9 |
10 | type Base struct {
11 | accountID string
12 | region string
13 |
14 | *shared.Base
15 | }
16 |
17 | func NewBase(
18 | accountID string,
19 | region string,
20 | category sdp.AdapterCategory,
21 | item shared.ItemType,
22 | ) *Base {
23 | return &Base{
24 | accountID: accountID,
25 | region: region,
26 | Base: shared.NewBase(
27 | category,
28 | item,
29 | []string{fmt.Sprintf("%s.%s", accountID, region)},
30 | ),
31 | }
32 | }
33 |
34 | func (m *Base) AccountID() string {
35 | return m.accountID
36 | }
37 |
38 | func (m *Base) Region() string {
39 | return m.region
40 | }
41 |
--------------------------------------------------------------------------------
/sources/aws/errors.go:
--------------------------------------------------------------------------------
1 | package aws
2 |
3 | import (
4 | "errors"
5 | "slices"
6 |
7 | awsHttp "github.com/aws/smithy-go/transport/http"
8 |
9 | "github.com/overmindtech/cli/sdp-go"
10 | )
11 |
12 | // queryError takes an error and returns a sdp.QueryError.
13 | func queryError(err error) *sdp.QueryError {
14 | var responseErr *awsHttp.ResponseError
15 | if errors.As(err, &responseErr) {
16 | // If the input is bad, access is denied, or the thing wasn't found then
17 | // we should assume that it is not exist for this adapter
18 | if slices.Contains([]int{400, 403, 404}, responseErr.HTTPStatusCode()) {
19 | return &sdp.QueryError{
20 | ErrorType: sdp.QueryError_NOTFOUND,
21 | ErrorString: err.Error(),
22 | }
23 | }
24 | }
25 |
26 | return &sdp.QueryError{
27 | ErrorType: sdp.QueryError_OTHER,
28 | ErrorString: err.Error(),
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/sources/aws/shared/models.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "github.com/overmindtech/cli/sources/shared"
5 | )
6 |
7 | const (
8 | AWS shared.Source = "aws"
9 | )
10 |
11 | // APIs
12 | const (
13 | APIGateway shared.API = "api-gateway"
14 | WAFv2 shared.API = "wafv2"
15 | )
16 |
17 | // Resources
18 | const (
19 | APIKey shared.Resource = "api-key"
20 | Stage shared.Resource = "stage"
21 | RESTAPI shared.Resource = "rest-api"
22 | Deployment shared.Resource = "deployment"
23 | WebACL shared.Resource = "web-acl"
24 | )
25 |
--------------------------------------------------------------------------------
/sources/aws/validation_test.go:
--------------------------------------------------------------------------------
1 | package aws
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | "strings"
7 | "testing"
8 |
9 | "github.com/overmindtech/cli/discovery"
10 | "github.com/overmindtech/cli/sources"
11 | )
12 |
13 | type Validate interface {
14 | Validate() error
15 | }
16 |
17 | func TestAdaptersValidation(t *testing.T) {
18 | accountID := "123456789012"
19 | region := "us-east-1"
20 |
21 | var adapters []discovery.Adapter
22 | adapters = append(adapters,
23 | sources.WrapperToAdapter(NewAPIGatewayStage(nil, accountID, region)),
24 | sources.WrapperToAdapter(NewApiGatewayAPIKey(nil, accountID, region)),
25 | )
26 |
27 | for _, adapter := range adapters {
28 | t.Run(adapter.Name(), func(t *testing.T) {
29 | // Test the adapter
30 | a, ok := adapter.(Validate)
31 | if !ok {
32 | t.Fatalf("Adapter %s does not implement Validate", adapter.Name())
33 | }
34 |
35 | if err := a.Validate(); err != nil {
36 | t.Fatalf("Adapter %s failed validation: %v", adapter.Name(), err)
37 | }
38 |
39 | if strings.EqualFold(os.Getenv("LOG_LEVEL"), "debug") {
40 | // Pretty print the adapter metadata via json
41 | jsonData, err := json.MarshalIndent(adapter.Metadata(), "", " ")
42 | if err != nil {
43 | t.Fatalf("Failed to marshal adapter metadata: %v", err)
44 | }
45 | t.Logf("Adapter %s metadata: %s", adapter.Name(), string(jsonData))
46 | }
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/sources/example/base.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | "github.com/overmindtech/cli/sources/shared"
8 | )
9 |
10 | // Base customizes the sources.Base struct
11 | // It adds the project ID and zone to the base struct
12 | // and makes them available to concrete wrapper implementations.
13 | type Base struct {
14 | projectID string
15 | zone string
16 |
17 | *shared.Base
18 | }
19 |
20 | // NewBase creates a new Base struct
21 | func NewBase(
22 | projectID string,
23 | zone string,
24 | category sdp.AdapterCategory,
25 | item shared.ItemType,
26 | ) *Base {
27 | return &Base{
28 | projectID: projectID,
29 | zone: zone,
30 | Base: shared.NewBase(
31 | category,
32 | item,
33 | []string{fmt.Sprintf("%s.%s", projectID, zone)},
34 | ),
35 | }
36 | }
37 |
38 | // ProjectID returns the project ID
39 | func (m *Base) ProjectID() string {
40 | return m.projectID
41 | }
42 |
43 | // Zone returns the zone
44 | func (m *Base) Zone() string {
45 | return m.zone
46 | }
47 |
--------------------------------------------------------------------------------
/sources/example/errors.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "errors"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | )
8 |
9 | // queryError is a helper function to convert errors into sdp.QueryError
10 | func queryError(err error) *sdp.QueryError {
11 | if errors.As(err, new(NotFoundError)) {
12 | return &sdp.QueryError{
13 | ErrorType: sdp.QueryError_NOTFOUND,
14 | ErrorString: err.Error(),
15 | }
16 | }
17 |
18 | return &sdp.QueryError{
19 | ErrorType: sdp.QueryError_OTHER,
20 | ErrorString: err.Error(),
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sources/example/shared/models.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "github.com/overmindtech/cli/sources/shared"
5 | )
6 |
7 | const (
8 | Source shared.Source = "GCP"
9 | )
10 |
11 | // APIs
12 | const (
13 | Compute shared.API = "compute"
14 | )
15 |
16 | // Resources
17 | const (
18 | Instance shared.Resource = "instance"
19 | Disk shared.Resource = "disk"
20 | Status shared.Resource = "status"
21 | )
22 |
--------------------------------------------------------------------------------
/sources/example/validation_test.go:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import (
4 | "encoding/json"
5 | "os"
6 | "strings"
7 | "testing"
8 |
9 | "github.com/overmindtech/cli/discovery"
10 | "github.com/overmindtech/cli/sources"
11 | )
12 |
13 | type Validate interface {
14 | Validate() error
15 | }
16 |
17 | func TestAdaptersValidation(t *testing.T) {
18 | projectID := "123456789012"
19 | zone := "us-east-1"
20 |
21 | var adapters []discovery.Adapter
22 | adapters = append(adapters,
23 | sources.WrapperToAdapter(NewStandardSearchableListable(nil, projectID, zone)),
24 | sources.WrapperToAdapter(NewCustomSearchableListable(nil, projectID, zone)),
25 | )
26 |
27 | for _, adapter := range adapters {
28 | t.Run(adapter.Name(), func(t *testing.T) {
29 | // Test the adapter
30 | a, ok := adapter.(Validate)
31 | if !ok {
32 | t.Fatalf("Adapter %s does not implement Validate", adapter.Name())
33 | }
34 |
35 | if err := a.Validate(); err != nil {
36 | t.Fatalf("Adapter %s failed validation: %v", adapter.Name(), err)
37 | }
38 |
39 | if strings.EqualFold(os.Getenv("LOG_LEVEL"), "debug") {
40 | // Pretty print the adapter metadata via json
41 | jsonData, err := json.MarshalIndent(adapter.Metadata(), "", " ")
42 | if err != nil {
43 | t.Fatalf("Failed to marshal adapter metadata: %v", err)
44 | }
45 | t.Logf("Adapter %s metadata: %s", adapter.Name(), string(jsonData))
46 | }
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/sources/gcp/adapters/compute-accelerator-type.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
5 | "github.com/overmindtech/cli/sources/shared"
6 | )
7 |
8 | var ComputeAcceleratorType = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.AcceleratorType)
9 |
--------------------------------------------------------------------------------
/sources/gcp/adapters/compute-machine-type.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
5 | "github.com/overmindtech/cli/sources/shared"
6 | )
7 |
8 | var ComputeMachineType = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.MachineType)
9 |
--------------------------------------------------------------------------------
/sources/gcp/adapters/compute-region-commitment.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
5 | "github.com/overmindtech/cli/sources/shared"
6 | )
7 |
8 | var ComputeRegionCommitment = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.RegionCommitment)
9 |
--------------------------------------------------------------------------------
/sources/gcp/adapters/compute-resource-policy.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
5 | "github.com/overmindtech/cli/sources/shared"
6 | )
7 |
8 | var ComputeResourcePolicy = shared.NewItemType(gcpshared.GCP, gcpshared.Compute, gcpshared.ResourcePolicy)
9 |
--------------------------------------------------------------------------------
/sources/gcp/adapters/network-services-service-binding.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
5 | "github.com/overmindtech/cli/sources/shared"
6 | )
7 |
8 | var NetworkServicesServiceBinding = shared.NewItemType(gcpshared.GCP, gcpshared.NetworkServices, gcpshared.ServiceBinding)
9 |
--------------------------------------------------------------------------------
/sources/gcp/adapters/network-services-service-lb-policy.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | gcpshared "github.com/overmindtech/cli/sources/gcp/shared"
5 | "github.com/overmindtech/cli/sources/shared"
6 | )
7 |
8 | var NetworkServicesServiceLbPolicy = shared.NewItemType(gcpshared.GCP, gcpshared.NetworkServices, gcpshared.ServiceLbPolicy)
9 |
--------------------------------------------------------------------------------
/sources/gcp/integration-tests/main_test.go:
--------------------------------------------------------------------------------
1 | package integrationtests
2 |
3 | import (
4 | "fmt"
5 | "os"
6 | "strconv"
7 | "testing"
8 | )
9 |
10 | func TestMain(m *testing.M) {
11 | if shouldRunIntegrationTests() {
12 | fmt.Println("Running integration tests")
13 | os.Exit(m.Run())
14 | } else {
15 | fmt.Println("Skipping integration tests, set RUN_GCP_INTEGRATION_TESTS=true to run them")
16 | os.Exit(0)
17 | }
18 | }
19 |
20 | func shouldRunIntegrationTests() bool {
21 | run, found := os.LookupEnv("RUN_GCP_INTEGRATION_TESTS")
22 |
23 | if !found {
24 | return false
25 | }
26 |
27 | shouldRun, err := strconv.ParseBool(run)
28 | if err != nil {
29 | return false
30 | }
31 |
32 | return shouldRun
33 | }
34 |
--------------------------------------------------------------------------------
/sources/gcp/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | _ "go.uber.org/automaxprocs"
5 |
6 | "github.com/overmindtech/cli/sources/gcp/cmd"
7 | )
8 |
9 | func main() {
10 | cmd.Execute()
11 | }
12 |
--------------------------------------------------------------------------------
/sources/gcp/proc/proc_test.go:
--------------------------------------------------------------------------------
1 | package proc
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestZoneToRegion(t *testing.T) {
8 | tests := []struct {
9 | name string
10 | zone string
11 | expected string
12 | }{
13 | {
14 | name: "Valid zone with region us-central1-a",
15 | zone: "us-central1-a",
16 | expected: "us-central1",
17 | },
18 | {
19 | name: "Valid zone with region europe-west1-b",
20 | zone: "europe-west1-b",
21 | expected: "europe-west1",
22 | },
23 | {
24 | name: "Empty zone",
25 | zone: "",
26 | expected: "",
27 | },
28 | {
29 | name: "Zone with no dash",
30 | zone: "uscentral1",
31 | expected: "",
32 | },
33 | }
34 |
35 | for _, tt := range tests {
36 | t.Run(tt.name, func(t *testing.T) {
37 | result := zoneToRegion(tt.zone)
38 | if result != tt.expected {
39 | t.Errorf("zoneToRegion(%q) = %q; expected %q", tt.zone, result, tt.expected)
40 | }
41 | })
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sources/gcp/shared/errors.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "google.golang.org/grpc/codes"
5 | "google.golang.org/grpc/status"
6 |
7 | "github.com/overmindtech/cli/sdp-go"
8 | )
9 |
10 | // QueryError is a helper function to convert errors into sdp.QueryError
11 | func QueryError(err error) *sdp.QueryError {
12 | // Check if the error is a gRPC `not_found` error
13 | if s, ok := status.FromError(err); ok && s.Code() == codes.NotFound {
14 | return &sdp.QueryError{
15 | ErrorType: sdp.QueryError_NOTFOUND,
16 | ErrorString: err.Error(),
17 | }
18 | }
19 |
20 | return &sdp.QueryError{
21 | ErrorType: sdp.QueryError_OTHER,
22 | ErrorString: err.Error(),
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/sources/gcp/shared/network-security-clients.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "context"
5 |
6 | "cloud.google.com/go/networksecurity/apiv1beta1"
7 | "cloud.google.com/go/networksecurity/apiv1beta1/networksecuritypb"
8 | "github.com/googleapis/gax-go/v2"
9 | )
10 |
11 | type NetworkSecurityClientTlsPolicyClient interface {
12 | Get(ctx context.Context, req *networksecuritypb.GetClientTlsPolicyRequest, opts ...gax.CallOption) (*networksecuritypb.ClientTlsPolicy, error)
13 | List(ctx context.Context, req *networksecuritypb.ListClientTlsPoliciesRequest, opts ...gax.CallOption) NetworkSecurityClientTlsPolicyIterator
14 | }
15 |
16 | type NetworkSecurityClientTlsPolicyIterator interface {
17 | Next() (*networksecuritypb.ClientTlsPolicy, error)
18 | }
19 |
20 | type networkSecurityClientTlsPolicyClient struct {
21 | client *networksecurity.Client
22 | }
23 |
24 | func (c networkSecurityClientTlsPolicyClient) Get(ctx context.Context, req *networksecuritypb.GetClientTlsPolicyRequest, opts ...gax.CallOption) (*networksecuritypb.ClientTlsPolicy, error) {
25 | return c.client.GetClientTlsPolicy(ctx, req, opts...)
26 | }
27 |
28 | func (c networkSecurityClientTlsPolicyClient) List(ctx context.Context, req *networksecuritypb.ListClientTlsPoliciesRequest, opts ...gax.CallOption) NetworkSecurityClientTlsPolicyIterator {
29 | return c.client.ListClientTlsPolicies(ctx, req, opts...)
30 | }
31 |
32 | // NewNetworkSecurityClientTlsPolicyClient creates a new NetworkSecurityClientTlsPolicyClient
33 | func NewNetworkSecurityClientTlsPolicyClient(client *networksecurity.Client) NetworkSecurityClientTlsPolicyClient {
34 | return &networkSecurityClientTlsPolicyClient{
35 | client: client,
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/sources/shared/util.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "strings"
5 |
6 | "github.com/overmindtech/cli/sdp-go"
7 | )
8 |
9 | // ToAttributesWithExclude converts an interface to SDP attributes using the `sdp.ToAttributesSorted`
10 | // function, and also allows the user to exclude certain top-level fields from
11 | // the resulting attributes
12 | func ToAttributesWithExclude(i interface{}, exclusions ...string) (*sdp.ItemAttributes, error) {
13 | attrs, err := sdp.ToAttributesViaJson(i)
14 | if err != nil {
15 | return nil, err
16 | }
17 |
18 | for _, exclusion := range exclusions {
19 | if s := attrs.GetAttrStruct(); s != nil {
20 | delete(s.GetFields(), exclusion)
21 | }
22 | }
23 |
24 | return attrs, nil
25 | }
26 |
27 | // CompositeLookupKey creates a composite lookup key from multiple query parts.
28 | func CompositeLookupKey(queryParts ...string) string {
29 | // Join the query parts with the default separator "|"
30 | return strings.Join(queryParts, QuerySeparator)
31 | }
32 |
--------------------------------------------------------------------------------
/sources/shared/util_test.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestCompositeLookupKey(t *testing.T) {
8 | tests := []struct {
9 | name string
10 | queryParts []string
11 | expected string
12 | }{
13 | {
14 | name: "Single query part",
15 | queryParts: []string{"part1"},
16 | expected: "part1",
17 | },
18 | {
19 | name: "Multiple query parts",
20 | queryParts: []string{"part1", "part2", "part3"},
21 | expected: "part1|part2|part3",
22 | },
23 | {
24 | name: "Empty query parts",
25 | queryParts: []string{},
26 | expected: "",
27 | },
28 | {
29 | name: "Query parts with empty strings",
30 | queryParts: []string{"part1", "", "part3"},
31 | expected: "part1||part3",
32 | },
33 | }
34 |
35 | for _, tt := range tests {
36 | t.Run(tt.name, func(t *testing.T) {
37 | result := CompositeLookupKey(tt.queryParts...)
38 | if result != tt.expected {
39 | t.Errorf("CompositeLookupKey(%v) = %q; want %q", tt.queryParts, result, tt.expected)
40 | }
41 | })
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sources/stdlib/items.go:
--------------------------------------------------------------------------------
1 | package stdlib
2 |
3 | import (
4 | "github.com/overmindtech/cli/sources/shared"
5 | stdlibshared "github.com/overmindtech/cli/sources/stdlib/shared"
6 | )
7 |
8 | var (
9 | NetworkIP = shared.NewItemType(stdlibshared.Stdlib, stdlibshared.Network, stdlibshared.IP)
10 | )
11 |
--------------------------------------------------------------------------------
/sources/stdlib/shared/models.go:
--------------------------------------------------------------------------------
1 | package shared
2 |
3 | import "github.com/overmindtech/cli/sources/shared"
4 |
5 | const (
6 | Stdlib shared.Source = "Stdlib"
7 | )
8 |
9 | const (
10 | Network shared.API = "network"
11 | )
12 |
13 | const (
14 | IP shared.Resource = "ip"
15 | )
16 |
--------------------------------------------------------------------------------
/sources/transformer_test.go:
--------------------------------------------------------------------------------
1 | package sources
2 |
3 | import (
4 | "testing"
5 |
6 | aws "github.com/overmindtech/cli/sources/aws/shared"
7 | gcp "github.com/overmindtech/cli/sources/gcp/shared"
8 | "github.com/overmindtech/cli/sources/shared"
9 | )
10 |
11 | func TestItemTypeReadableFormat(t *testing.T) {
12 | tests := []struct {
13 | name string
14 | input shared.ItemType
15 | expected string
16 | }{
17 | {
18 | name: "Three parts input",
19 | input: shared.NewItemType(gcp.GCP, gcp.Compute, gcp.Instance),
20 | expected: "GCP Compute Instance",
21 | },
22 | {
23 | name: "Three parts input",
24 | input: shared.NewItemType(aws.AWS, aws.APIGateway, aws.RESTAPI),
25 | expected: "AWS Api Gateway Rest Api",
26 | // Note that this is only testing the fallback rendering,
27 | // adapter implementors will have to supply a custom descriptive name,
28 | // like "Amazon API Gateway REST API" in the `AdapterMetadata`.
29 | },
30 | }
31 |
32 | for _, tt := range tests {
33 | t.Run(tt.name, func(t *testing.T) {
34 | actual := tt.input.Readable()
35 | if actual != tt.expected {
36 | t.Errorf("readableFormat(%q) = %q; expected %q", tt.input, actual, tt.expected)
37 | }
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/stdlib-source/adapters/main_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "net/http"
5 | "testing"
6 |
7 | "github.com/openrdap/rdap"
8 | "github.com/openrdap/rdap/bootstrap"
9 | )
10 |
11 | func testRdapClient(t *testing.T) *rdap.Client {
12 | return &rdap.Client{
13 | HTTP: http.DefaultClient,
14 | Bootstrap: &bootstrap.Client{
15 | Verbose: func(text string) {
16 | t.Log(text)
17 | },
18 | },
19 | Verbose: func(text string) {
20 | t.Log(text)
21 | },
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/stdlib-source/adapters/rdap-asn_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/openrdap/rdap"
8 | "github.com/overmindtech/cli/sdpcache"
9 | )
10 |
11 | func TestASNAdapterGet(t *testing.T) {
12 | t.Parallel()
13 |
14 | src := &RdapASNAdapter{
15 | ClientFac: func() *rdap.Client { return testRdapClient(t) },
16 | Cache: sdpcache.NewCache(),
17 | }
18 |
19 | item, err := src.Get(context.Background(), "global", "AS15169", false)
20 |
21 | if err != nil {
22 | t.Fatal(err)
23 | }
24 |
25 | err = item.Validate()
26 |
27 | if err != nil {
28 | t.Error(err)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/stdlib-source/adapters/rdap-domain_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/openrdap/rdap"
8 | "github.com/overmindtech/cli/sdpcache"
9 | )
10 |
11 | func TestDomainAdapterGet(t *testing.T) {
12 | t.Parallel()
13 |
14 | src := &RdapDomainAdapter{
15 | ClientFac: func() *rdap.Client { return testRdapClient(t) },
16 | Cache: sdpcache.NewCache(),
17 | }
18 |
19 | t.Run("without a dot", func(t *testing.T) {
20 | items, err := src.Search(context.Background(), "global", "reddit.map.fastly.net", false)
21 |
22 | if err != nil {
23 | t.Fatal(err)
24 | }
25 |
26 | if len(items) != 1 {
27 | t.Fatal("Expected 1 item")
28 | }
29 |
30 | item := items[0]
31 |
32 | err = item.Validate()
33 |
34 | if err != nil {
35 | t.Error(err)
36 | }
37 | })
38 |
39 | t.Run("with a dot", func(t *testing.T) {
40 | items, err := src.Search(context.Background(), "global", "reddit.map.fastly.net.", false)
41 |
42 | if err != nil {
43 | t.Fatal(err)
44 | }
45 |
46 | if len(items) != 1 {
47 | t.Fatal("Expected 1 item")
48 | }
49 |
50 | item := items[0]
51 |
52 | err = item.Validate()
53 |
54 | if err != nil {
55 | t.Error(err)
56 | }
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/stdlib-source/adapters/rdap-entity_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "errors"
6 | "testing"
7 |
8 | "github.com/openrdap/rdap"
9 | "github.com/overmindtech/cli/sdp-go"
10 | "github.com/overmindtech/cli/sdpcache"
11 | )
12 |
13 | func TestEntityAdapterSearch(t *testing.T) {
14 | t.Parallel()
15 |
16 | realUrls := []string{
17 | "https://rdap.apnic.net/entity/AIC3-AP",
18 | "https://rdap.apnic.net/entity/IRT-APNICRANDNET-AU",
19 | "https://rdap.arin.net/registry/entity/HPINC-Z",
20 | }
21 |
22 | src := &RdapEntityAdapter{
23 | ClientFac: func() *rdap.Client { return testRdapClient(t) },
24 | Cache: sdpcache.NewCache(),
25 | }
26 |
27 | for _, realUrl := range realUrls {
28 | t.Run(realUrl, func(t *testing.T) {
29 | items, err := src.Search(context.Background(), "global", realUrl, false)
30 |
31 | if err != nil {
32 | t.Fatal(err)
33 | }
34 |
35 | if len(items) != 1 {
36 | t.Fatalf("Expected 1 item, got %v", len(items))
37 | }
38 |
39 | item := items[0]
40 |
41 | err = item.Validate()
42 |
43 | if err != nil {
44 | t.Error(err)
45 | }
46 | })
47 | }
48 |
49 | t.Run("not found", func(t *testing.T) {
50 | _, err := src.Search(context.Background(), "global", "https://rdap.apnic.net/entity/NOTFOUND", false)
51 |
52 | if err == nil {
53 | t.Fatal("Expected error")
54 | }
55 |
56 | var sdpError *sdp.QueryError
57 |
58 | if ok := errors.As(err, &sdpError); ok {
59 | if sdpError.GetErrorType() != sdp.QueryError_NOTFOUND {
60 | t.Errorf("Expected QueryError_NOTFOUND, got %v", sdpError.GetErrorType())
61 | }
62 | } else {
63 | t.Fatalf("Expected QueryError, got %T", err)
64 | }
65 | })
66 | }
67 |
--------------------------------------------------------------------------------
/stdlib-source/adapters/rdap-nameserver_test.go:
--------------------------------------------------------------------------------
1 | package adapters
2 |
3 | import (
4 | "context"
5 | "testing"
6 |
7 | "github.com/openrdap/rdap"
8 | "github.com/overmindtech/cli/sdpcache"
9 | )
10 |
11 | func TestNameserverAdapterSearch(t *testing.T) {
12 | t.Parallel()
13 |
14 | src := &RdapNameserverAdapter{
15 | ClientFac: func() *rdap.Client { return testRdapClient(t) },
16 | Cache: sdpcache.NewCache(),
17 | }
18 |
19 | items, err := src.Search(context.Background(), "global", "https://rdap.verisign.com/com/v1/nameserver/NS4.GOOGLE.COM", false)
20 |
21 | if err != nil {
22 | t.Fatal(err)
23 | }
24 |
25 | if len(items) != 1 {
26 | t.Fatal("Expected 1 item")
27 | }
28 |
29 | item := items[0]
30 |
31 | err = item.Validate()
32 |
33 | if err != nil {
34 | t.Error(err)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/stdlib-source/build/package/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build the source binary
2 | FROM golang:1.24-alpine AS builder
3 | ARG TARGETOS
4 | ARG TARGETARCH
5 | ARG BUILD_VERSION
6 | ARG BUILD_COMMIT
7 |
8 | # required for accessing the private dependencies and generating version descriptor
9 | RUN apk add --no-cache git curl
10 |
11 | WORKDIR /workspace
12 |
13 | # Copy the go source
14 | COPY . .
15 |
16 | # Build
17 | RUN --mount=type=cache,target=/go/pkg \
18 | --mount=type=cache,target=/root/.cache/go-build \
19 | GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -trimpath -ldflags="-s -w -X github.com/overmindtech/cli/tracing.version=${BUILD_VERSION} -X github.com/overmindtech/cli/tracing.commit=${BUILD_COMMIT}" -o source stdlib-source/main.go
20 |
21 | FROM alpine:3.21
22 | WORKDIR /
23 | COPY --from=builder /workspace/source .
24 | USER 65534:65534
25 |
26 | ENTRYPOINT ["/source"]
27 |
--------------------------------------------------------------------------------
/stdlib-source/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2021 {AUTHOR}
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | package main
17 |
18 | import (
19 | "github.com/overmindtech/cli/stdlib-source/cmd"
20 | _ "go.uber.org/automaxprocs"
21 | )
22 |
23 | func main() {
24 | cmd.Execute()
25 | }
26 |
--------------------------------------------------------------------------------
/tfutils/testdata/invalid_vars.tfvars:
--------------------------------------------------------------------------------
1 | this is not valid hcl
2 |
3 | And therefore shouldn't parse
--------------------------------------------------------------------------------
/tfutils/testdata/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "format_version": "1.0",
3 | "terraform_version": "1.5.7",
4 | "values": {
5 | "outputs": {},
6 | "root_module": {
7 | "resources": [],
8 | "child_modules": []
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/tfutils/testdata/subfolder/more_providers.tf:
--------------------------------------------------------------------------------
1 | provider "aws" {
2 | alias = "subdir"
3 | region = "us-west-2"
4 | access_key = "my-access-key"
5 | secret_key = "my-secret-key"
6 | }
--------------------------------------------------------------------------------
/tfutils/testdata/test_vars.tfvars:
--------------------------------------------------------------------------------
1 | # String variable
2 | simple_string="example_string"
3 |
4 | # Number variable
5 | example_number = 42
6 |
7 | # Boolean variable
8 | example_boolean = true
9 |
10 | # List of strings
11 | example_list = ["item1", "item2", "item3"]
12 |
13 | # Map of strings
14 | example_map = {
15 | key1 = "value1"
16 | key2 = "value2"
17 | }
18 |
19 | # Complex map (nested maps)
20 | complex_map = {
21 | nested_map1 = {
22 | nested_key1 = "nested_value1"
23 | nested_key2 = "nested_value2"
24 | }
25 | nested_map2 = {
26 | nested_key1 = "nested_value3"
27 | nested_key2 = "nested_value4"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tfutils/testdata/tfvars.json:
--------------------------------------------------------------------------------
1 | {
2 | "string": "example_string",
3 | "list": ["item1", "item2"]
4 | }
5 |
--------------------------------------------------------------------------------
/tracing/deferlog.go:
--------------------------------------------------------------------------------
1 | package tracing
2 |
3 | import (
4 | "context"
5 | "fmt"
6 | "os"
7 | "runtime/debug"
8 |
9 | "github.com/getsentry/sentry-go"
10 | log "github.com/sirupsen/logrus"
11 | "go.opentelemetry.io/otel/attribute"
12 | "go.opentelemetry.io/otel/trace"
13 | )
14 |
15 | // LogRecoverToReturn Recovers from a panic, logs and forwards it sentry and otel, then returns
16 | // Does nothing when there is no panic.
17 | func LogRecoverToReturn(ctx context.Context, loc string) {
18 | err := recover()
19 | if err == nil {
20 | return
21 | }
22 |
23 | stack := string(debug.Stack())
24 | HandleError(ctx, loc, err, stack)
25 | }
26 |
27 | // LogRecoverToExit Recovers from a panic, logs and forwards it sentry and otel, then exits
28 | // Does nothing when there is no panic.
29 | func LogRecoverToExit(ctx context.Context, loc string) {
30 | err := recover()
31 | if err == nil {
32 | return
33 | }
34 |
35 | stack := string(debug.Stack())
36 | HandleError(ctx, loc, err, stack)
37 |
38 | // ensure that errors still get sent out
39 | ShutdownTracer(ctx)
40 |
41 | os.Exit(1)
42 | }
43 |
44 | func HandleError(ctx context.Context, loc string, err interface{}, stack string) {
45 | msg := fmt.Sprintf("unhandled panic in %v, exiting: %v", loc, err)
46 |
47 | hub := sentry.CurrentHub()
48 | if hub != nil {
49 | hub.Recover(err)
50 | }
51 |
52 | // always log to stderr (no WithContext!)
53 | log.WithFields(log.Fields{"loc": loc, "stack": stack}).Error(msg)
54 |
55 | // if we have a context, try attaching additional info to the span
56 | if ctx != nil {
57 | log.WithContext(ctx).WithFields(log.Fields{"loc": loc, "stack": stack}).Error(msg)
58 | span := trace.SpanFromContext(ctx)
59 | span.SetAttributes(attribute.String("ovm.panic.loc", loc))
60 | span.SetAttributes(attribute.String("ovm.panic.stack", stack))
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/tracing/main_test.go:
--------------------------------------------------------------------------------
1 | package tracing
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 | func TestTracingResource(t *testing.T) {
8 | resource := tracingResource("test-component")
9 | if resource == nil {
10 | t.Error("Could not initialize tracing resource. Check the log!")
11 | }
12 | }
13 |
--------------------------------------------------------------------------------