diff --git a/.github/workflows/ministack.yml b/.github/workflows/ministack.yml new file mode 100644 index 0000000000..3f5df29de3 --- /dev/null +++ b/.github/workflows/ministack.yml @@ -0,0 +1,129 @@ +name: "MiniStack Terraform lifecycle" + +on: + push: + branches: + - main + paths: + - ".github/workflows/ministack.yml" + - "tests/ministack/**" + - "*.tf" + - "policies/**" + - "examples/**" + - "modules/**" + pull_request: + paths: + - ".github/workflows/ministack.yml" + - "tests/ministack/**" + - "*.tf" + - "policies/**" + - "examples/**" + - "modules/**" + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + AWS_ACCESS_KEY_ID: "000000000000" + AWS_DEFAULT_REGION: eu-west-1 + AWS_EC2_METADATA_DISABLED: "true" + AWS_ENDPOINT_URL: http://ministack:4566 + AWS_REGION: eu-west-1 + AWS_SECRET_ACCESS_KEY: test-only + TF_IN_AUTOMATION: "true" + TF_INPUT: "false" + +jobs: + terraform_lifecycle: + name: Apply/destroy ${{ matrix.example }} against MiniStack + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + max-parallel: 4 + matrix: + example: + - base + - default + - ephemeral + - external-managed-ssm-secrets + - multi-runner + - permissions-boundary + - prebuilt + - termination-watcher + container: + image: hashicorp/terraform@sha256:1d10ec4073f4ddbdf34a28540a3b9250852ab500cb1c53f68c8bd17d82f474d8 # 1.14 + services: + ministack: + image: ghcr.io/ministackorg/ministack:1.5.0@sha256:ba48c20747780605a4287a950e7bb1758ddc3b55ec92409a0c47677cbe26bbb9 + env: + MINISTACK_ACCOUNT_ID: "000000000000" + MINISTACK_REGION: eu-west-1 + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Mark repository as safe + shell: sh + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + + - id: prepare + name: Prepare isolated fixture + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh prepare "$EXAMPLE" + + - id: fixture + name: Apply shared fixture + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh fixture-apply "$EXAMPLE" + + - id: setup + name: Apply permissions-boundary prerequisite + if: matrix.example == 'permissions-boundary' + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh setup-apply "$EXAMPLE" + + - id: init + name: Terraform init + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh init "$EXAMPLE" + + - id: apply + name: Terraform apply + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh apply "$EXAMPLE" + + - name: Terraform destroy + if: always() && steps.init.outcome == 'success' + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh destroy "$EXAMPLE" + + - name: Destroy permissions-boundary prerequisite + if: always() && matrix.example == 'permissions-boundary' && steps.setup.outcome != 'skipped' + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh setup-destroy "$EXAMPLE" + + - name: Destroy shared fixture + if: always() && steps.prepare.outcome == 'success' && steps.fixture.outcome != 'skipped' + env: + EXAMPLE: ${{ matrix.example }} + run: tests/ministack/run-example.sh fixture-destroy "$EXAMPLE" diff --git a/.gitignore b/.gitignore index 276fe10733..9bb0ac7d7e 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # lock files **/.terraform.lock.hcl !examples/**/.terraform.lock.hcl +!tests/ministack/setup/.terraform.lock.hcl # keys diff --git a/tests/ministack/README.md b/tests/ministack/README.md new file mode 100644 index 0000000000..1b9042a575 --- /dev/null +++ b/tests/ministack/README.md @@ -0,0 +1,30 @@ +# MiniStack example lifecycle tests + +The MiniStack workflow runs explicit `terraform apply` and `terraform destroy` +commands against the repository's runnable AWS examples. Every matrix entry gets +an isolated source tree, Terraform state, and MiniStack service. + +The fixture creates synthetic SSM values through MiniStack and an inert Lambda +archive under its ignored `.terraform/` directory. Test-only Terraform override +files route each example to that archive and a MiniStack AMI. They also disable +the `webhook-github-app` local-exec module, which would otherwise update a real +GitHub App. The production example configurations are not changed. + +| Example | Lifecycle coverage | +| --- | --- | +| `base` | VPC and Resource Groups | +| `default` | Full default runner stack | +| `ephemeral` | Ephemeral runner and job-retry stack | +| `external-managed-ssm-secrets` | Runner stack with fixture-owned external SSM parameters | +| `multi-runner` | All runner lanes: public/private SSM wiring for Linux x64/ARM64 and module-managed AMI parameters for three lanes | +| `permissions-boundary` | IAM setup, assumed-role runner stack, and reverse-order teardown | +| `prebuilt` | Prebuilt-runner stack using a MiniStack AMI | +| `termination-watcher` | Standalone termination watcher | + +Two examples are intentionally outside the matrix: + +- `dedicated-mac-hosts` requires the EC2 Dedicated Hosts and License Manager + APIs, which MiniStack v1.5.0 does not implement. +- `lambdas-download` has no AWS resources. Its apply operation downloads release + archives from GitHub, so it is not a MiniStack lifecycle test. The underlying + `download-lambda` module remains in the existing module validation matrix. diff --git a/tests/ministack/overrides/README.md b/tests/ministack/overrides/README.md new file mode 100644 index 0000000000..a51e9f4e43 --- /dev/null +++ b/tests/ministack/overrides/README.md @@ -0,0 +1,40 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.10.0 | +| [aws](#requirement\_aws) | = 6.35.1 | + +## Providers + +No providers. + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [runners](#module\_runners) | | n/a | +| [spot\_termination\_watchter](#module\_spot\_termination\_watchter) | | n/a | +| [webhook\_github\_app](#module\_webhook\_github\_app) | | n/a | + +## Resources + +No resources. + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [ami\_name\_filter](#input\_ami\_name\_filter) | n/a | `string` | `"amzn2-ami-hvm-2.0.20231116.0-x86_64-gp2"` | no | +| [aws\_region](#input\_aws\_region) | n/a | `string` | `"eu-west-1"` | no | +| [environment](#input\_environment) | n/a | `string` | `"ministack-prebuilt"` | no | +| [github\_app](#input\_github\_app) | n/a | `map` |
{
"id": "0",
"key_base64": "ministack-invalid-key"
}
| no | +| [github\_app\_ssm\_parameters](#input\_github\_app\_ssm\_parameters) | n/a | `map` |
{
"id": {
"arn": "arn:aws:ssm:eu-west-1:000000000000:parameter/ministack/terraform-aws-github-runner/github-app/id",
"name": "/ministack/terraform-aws-github-runner/github-app/id"
},
"key_base64": {
"arn": "arn:aws:ssm:eu-west-1:000000000000:parameter/ministack/terraform-aws-github-runner/github-app/key-base64",
"name": "/ministack/terraform-aws-github-runner/github-app/key-base64"
},
"webhook_secret": {
"arn": "arn:aws:ssm:eu-west-1:000000000000:parameter/ministack/terraform-aws-github-runner/github-app/webhook-secret",
"name": "/ministack/terraform-aws-github-runner/github-app/webhook-secret"
}
}
| no | +| [ministack\_lambda\_archive](#input\_ministack\_lambda\_archive) | Absolute path to the inert Lambda archive created by the MiniStack fixture. | `string` | n/a | yes | +| [prefix](#input\_prefix) | n/a | `string` | `"ministack-base"` | no | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/tests/ministack/overrides/base_override.tf b/tests/ministack/overrides/base_override.tf new file mode 100644 index 0000000000..7450840076 --- /dev/null +++ b/tests/ministack/overrides/base_override.tf @@ -0,0 +1,7 @@ +variable "prefix" { + default = "ministack-base" +} + +variable "aws_region" { + default = "eu-west-1" +} diff --git a/tests/ministack/overrides/common.tf b/tests/ministack/overrides/common.tf new file mode 100644 index 0000000000..8cec884357 --- /dev/null +++ b/tests/ministack/overrides/common.tf @@ -0,0 +1,19 @@ +variable "ministack_lambda_archive" { + description = "Absolute path to the inert Lambda archive created by the MiniStack fixture." + type = string + + validation { + condition = endswith(var.ministack_lambda_archive, "/tests/ministack/setup/.terraform/ministack/lambda.zip") + error_message = "The MiniStack Lambda archive must come from the isolated test fixture." + } +} + +locals { + ministack_ami = { + filter = { + name = ["amzn2-ami-hvm-2.0.20231116.0-x86_64-gp2"] + state = ["available"] + } + owners = ["self"] + } +} diff --git a/tests/ministack/overrides/default_override.tf b/tests/ministack/overrides/default_override.tf new file mode 100644 index 0000000000..654aa37161 --- /dev/null +++ b/tests/ministack/overrides/default_override.tf @@ -0,0 +1,29 @@ +variable "environment" { + default = "ministack-default" +} + +variable "github_app" { + default = { + id = "0" + key_base64 = "ministack-invalid-key" + } +} + +module "runners" { + ami = local.ministack_ami + ami_housekeeper_lambda_zip = var.ministack_lambda_archive + runner_binaries_syncer_lambda_zip = var.ministack_lambda_archive + runners_lambda_zip = var.ministack_lambda_archive + webhook_lambda_zip = var.ministack_lambda_archive + + instance_termination_watcher = { + enable = true + zip = var.ministack_lambda_archive + } +} + +# The production example updates GitHub through a local-exec provisioner. +# A zero count structurally prevents any external GitHub API call in this test. +module "webhook_github_app" { + count = 0 +} diff --git a/tests/ministack/overrides/ephemeral_override.tf b/tests/ministack/overrides/ephemeral_override.tf new file mode 100644 index 0000000000..ab85df74b1 --- /dev/null +++ b/tests/ministack/overrides/ephemeral_override.tf @@ -0,0 +1,23 @@ +variable "environment" { + default = "ministack-ephemeral" +} + +variable "github_app" { + default = { + id = "0" + key_base64 = "ministack-invalid-key" + } +} + +module "runners" { + ami = local.ministack_ami + runner_binaries_syncer_lambda_zip = var.ministack_lambda_archive + runners_lambda_zip = var.ministack_lambda_archive + webhook_lambda_zip = var.ministack_lambda_archive +} + +# The production example updates GitHub through a local-exec provisioner. +# A zero count structurally prevents any external GitHub API call in this test. +module "webhook_github_app" { + count = 0 +} diff --git a/tests/ministack/overrides/external-managed-ssm-secrets_override.tf b/tests/ministack/overrides/external-managed-ssm-secrets_override.tf new file mode 100644 index 0000000000..701b8b61b8 --- /dev/null +++ b/tests/ministack/overrides/external-managed-ssm-secrets_override.tf @@ -0,0 +1,27 @@ +variable "environment" { + default = "ministack-external-ssm" +} + +variable "github_app_ssm_parameters" { + default = { + id = { + arn = "arn:aws:ssm:eu-west-1:000000000000:parameter/ministack/terraform-aws-github-runner/github-app/id" + name = "/ministack/terraform-aws-github-runner/github-app/id" + } + key_base64 = { + arn = "arn:aws:ssm:eu-west-1:000000000000:parameter/ministack/terraform-aws-github-runner/github-app/key-base64" + name = "/ministack/terraform-aws-github-runner/github-app/key-base64" + } + webhook_secret = { + arn = "arn:aws:ssm:eu-west-1:000000000000:parameter/ministack/terraform-aws-github-runner/github-app/webhook-secret" + name = "/ministack/terraform-aws-github-runner/github-app/webhook-secret" + } + } +} + +module "runners" { + ami = local.ministack_ami + runner_binaries_syncer_lambda_zip = var.ministack_lambda_archive + runners_lambda_zip = var.ministack_lambda_archive + webhook_lambda_zip = var.ministack_lambda_archive +} diff --git a/tests/ministack/overrides/multi-runner_override.tf b/tests/ministack/overrides/multi-runner_override.tf new file mode 100644 index 0000000000..0516d6f33d --- /dev/null +++ b/tests/ministack/overrides/multi-runner_override.tf @@ -0,0 +1,39 @@ +variable "environment" { + default = "ministack" +} + +variable "github_app" { + default = { + id = "0" + key_base64 = "ministack-invalid-key" + } +} + +locals { + # The production example consumes this override after it is copied into the + # example root; it is intentionally unused in this standalone fixture folder. + # tflint-ignore: terraform_unused_declarations + multi_runner_config = { + for name, config in local.multi_runner_config_files : name => merge(config, { + runner_config = merge(config.runner_config, { + ami = contains(keys(config.runner_config), "ami") ? merge(local.ministack_ami, { + id_ssm_parameter_arn = lookup(local.ssm_ami_arns, name, null) + }) : null + subnet_ids = lookup(config.runner_config, "subnet_ids", null) != null ? [module.base.vpc.private_subnets[0]] : null + vpc_id = lookup(config.runner_config, "vpc_id", null) != null ? module.base.vpc.vpc_id : null + }) + }) + } +} + +module "runners" { + runner_binaries_syncer_lambda_zip = var.ministack_lambda_archive + runners_lambda_zip = var.ministack_lambda_archive + webhook_lambda_zip = var.ministack_lambda_archive +} + +# The production example updates GitHub through a local-exec provisioner. +# A zero count structurally prevents any external GitHub API call in this test. +module "webhook_github_app" { + count = 0 +} diff --git a/tests/ministack/overrides/permissions-boundary-provider_override.tf b/tests/ministack/overrides/permissions-boundary-provider_override.tf new file mode 100644 index 0000000000..1c1a2ea07d --- /dev/null +++ b/tests/ministack/overrides/permissions-boundary-provider_override.tf @@ -0,0 +1,14 @@ +provider "aws" { + alias = "terraform_role" + region = "eu-west-1" + + # These values are MiniStack test identifiers and cannot authenticate to AWS. + access_key = "000000000000" + secret_key = "ministack-test-only" + + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + skip_requesting_account_id = true + s3_use_path_style = true +} diff --git a/tests/ministack/overrides/permissions-boundary_override.tf b/tests/ministack/overrides/permissions-boundary_override.tf new file mode 100644 index 0000000000..b45b581f6b --- /dev/null +++ b/tests/ministack/overrides/permissions-boundary_override.tf @@ -0,0 +1,13 @@ +variable "github_app" { + default = { + id = "0" + key_base64 = "ministack-invalid-key" + } +} + +module "runners" { + ami = local.ministack_ami + runner_binaries_syncer_lambda_zip = var.ministack_lambda_archive + runners_lambda_zip = var.ministack_lambda_archive + webhook_lambda_zip = var.ministack_lambda_archive +} diff --git a/tests/ministack/overrides/prebuilt_override.tf b/tests/ministack/overrides/prebuilt_override.tf new file mode 100644 index 0000000000..32c35b7f4d --- /dev/null +++ b/tests/ministack/overrides/prebuilt_override.tf @@ -0,0 +1,26 @@ +variable "environment" { + default = "ministack-prebuilt" +} + +variable "github_app" { + default = { + id = "0" + key_base64 = "ministack-invalid-key" + } +} + +variable "ami_name_filter" { + default = "amzn2-ami-hvm-2.0.20231116.0-x86_64-gp2" +} + +module "runners" { + ami_housekeeper_lambda_zip = var.ministack_lambda_archive + runners_lambda_zip = var.ministack_lambda_archive + webhook_lambda_zip = var.ministack_lambda_archive +} + +# The production example updates GitHub through a local-exec provisioner. +# A zero count structurally prevents any external GitHub API call in this test. +module "webhook_github_app" { + count = 0 +} diff --git a/tests/ministack/overrides/provider.tf b/tests/ministack/overrides/provider.tf new file mode 100644 index 0000000000..0a33ab2dbd --- /dev/null +++ b/tests/ministack/overrides/provider.tf @@ -0,0 +1,16 @@ +# The permissions-boundary override merges an alias into this provider when +# TFLint evaluates this standalone fixture directory. +# tflint-ignore: terraform_unused_declarations +provider "aws" { + region = "eu-west-1" + + # These values are MiniStack test identifiers and cannot authenticate to AWS. + access_key = "000000000000" + secret_key = "ministack-test-only" + + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + skip_requesting_account_id = true + s3_use_path_style = true +} diff --git a/tests/ministack/overrides/termination-watcher_override.tf b/tests/ministack/overrides/termination-watcher_override.tf new file mode 100644 index 0000000000..b4f4a6833c --- /dev/null +++ b/tests/ministack/overrides/termination-watcher_override.tf @@ -0,0 +1,15 @@ +module "spot_termination_watchter" { + config = { + metrics = { + enable = true + metric = { + enable_spot_termination_warning = true + } + } + prefix = "global" + tag_filters = { + "ghr:Application" = "github-action-runner" + } + zip = var.ministack_lambda_archive + } +} diff --git a/tests/ministack/overrides/versions.tf b/tests/ministack/overrides/versions.tf new file mode 100644 index 0000000000..db7f916fb6 --- /dev/null +++ b/tests/ministack/overrides/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.10.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = "= 6.35.1" + } + } +} diff --git a/tests/ministack/run-example.sh b/tests/ministack/run-example.sh new file mode 100755 index 0000000000..21c66a0f15 --- /dev/null +++ b/tests/ministack/run-example.sh @@ -0,0 +1,106 @@ +#!/bin/sh + +set -eu + +action="${1:-}" +example="${2:-}" + +case "$example" in + base | default | ephemeral | external-managed-ssm-secrets | multi-runner | permissions-boundary | prebuilt | termination-watcher) ;; + *) + echo "Unsupported MiniStack example: $example" >&2 + exit 64 + ;; +esac + +case "$action" in + prepare | fixture-apply | setup-apply | init | apply | destroy | setup-destroy | fixture-destroy) ;; + *) + echo "Usage: $0 {prepare|fixture-apply|setup-apply|init|apply|destroy|setup-destroy|fixture-destroy} EXAMPLE" >&2 + exit 64 + ;; +esac + +script_dir=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd) +source_root="${GITHUB_WORKSPACE:-$(CDPATH='' cd -- "$script_dir/../.." && pwd)}" +temporary_root="${RUNNER_TEMP:-${TMPDIR:-/tmp}}" +worktree="$temporary_root/terraform-aws-github-runner-ministack-$example" +example_root="$worktree/examples/$example" +fixture_root="$worktree/tests/ministack/setup" +lambda_archive="$fixture_root/.terraform/ministack/lambda.zip" + +terraform_example() { + terraform -chdir="$example_root" "$@" -var="ministack_lambda_archive=$lambda_archive" +} + +case "$action" in + prepare) + if [ -e "$worktree" ]; then + echo "Refusing to overwrite existing MiniStack worktree: $worktree" >&2 + exit 73 + fi + + mkdir -p "$worktree" + git -C "$source_root" archive --format=tar "${MINISTACK_SOURCE_REF:-${GITHUB_SHA:-HEAD}}" | tar -xf - -C "$worktree" + + if [ ! -f "$example_root/main.tf" ]; then + echo "The isolated worktree does not contain examples/$example/main.tf" >&2 + exit 66 + fi + + cp "$worktree/tests/ministack/overrides/common.tf" "$example_root/ministack_common.tf" + cp "$worktree/tests/ministack/overrides/${example}_override.tf" "$example_root/ministack_example_override.tf" + cp "$worktree/tests/ministack/overrides/versions.tf" "$example_root/ministack_versions_override.tf" + + case "$example" in + base | termination-watcher) + cp "$worktree/tests/ministack/overrides/provider.tf" "$example_root/ministack_provider.tf" + ;; + permissions-boundary) + cp "$worktree/tests/ministack/overrides/provider.tf" "$example_root/ministack_provider.tf" + cp "$worktree/tests/ministack/overrides/permissions-boundary-provider_override.tf" "$example_root/ministack_permissions_provider_override.tf" + ;; + *) + cp "$worktree/tests/ministack/overrides/provider.tf" "$example_root/ministack_provider_override.tf" + ;; + esac + + ;; + fixture-apply) + terraform -chdir="$fixture_root" init -backend=false -input=false -lockfile=readonly + terraform -chdir="$fixture_root" apply -auto-approve -input=false + ;; + setup-apply) + if [ "$example" != "permissions-boundary" ]; then + exit 0 + fi + + # The isolated archive may update its lockfile for the Linux test platform. + terraform -chdir="$example_root/setup" init -backend=false -input=false + terraform -chdir="$example_root/setup" apply -auto-approve -input=false + ;; + init) + # The isolated archive may update its lockfile for the Linux test platform + # and the MiniStack-specific provider constraint. + terraform -chdir="$example_root" init -backend=false -input=false + ;; + apply) + terraform_example apply -auto-approve -input=false + ;; + destroy) + terraform -chdir="$example_root" init -backend=false -input=false + terraform_example destroy -auto-approve -input=false + ;; + setup-destroy) + if [ "$example" != "permissions-boundary" ]; then + exit 0 + fi + + terraform -chdir="$example_root/setup" init -backend=false -input=false + terraform -chdir="$example_root/setup" destroy -auto-approve -input=false + ;; + fixture-destroy) + terraform -chdir="$fixture_root" init -backend=false -input=false -lockfile=readonly + terraform -chdir="$fixture_root" destroy -auto-approve -input=false + ;; +esac diff --git a/tests/ministack/setup/.terraform.lock.hcl b/tests/ministack/setup/.terraform.lock.hcl new file mode 100644 index 0000000000..8917cfa897 --- /dev/null +++ b/tests/ministack/setup/.terraform.lock.hcl @@ -0,0 +1,48 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/archive" { + version = "2.8.0" + constraints = "~> 2.7" + hashes = [ + "h1:WB6H5ksIZiyq1lQlD/PWeh+tn4FLsbSjVnRW3+4xe2Y=", + "h1:jdmKm+xl6ZcQrijxapnZ94RVuz/G4vk7hsIa1N0VT5Q=", + "zh:0d14713fdc259fb377d0b899ad3c650a34194bd52194c863303ef22a65a580e2", + "zh:369b56040c7a8085d04e7e8ffac1e2b321a3170e502f788819bc34b868ec016f", + "zh:4d1a3b983ed6af5a52bfe12794674ae55cbadfa6021b37106ade68b433ad216a", + "zh:5c547549e26e083573c78a966ca68ce6d7df6bb8f3948f66a575f07da46b74ea", + "zh:6de093e62a975eb19a5e3017ce38e6e3cb639c17b79648d2000e0a8348f0e997", + "zh:7267936c2cdbc448efeb594d73e6b56a53d6a7ae14fe88cdd2a4133adc3302f0", + "zh:7482f023050ed426b4b45116e1761643bc33b1fd4ce4a6fab207ae2571f35940", + "zh:76bbd93b234e5a2927d98b511d86565700f549b570871a194c35f944b96cefb7", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:c6afc4bc1f002bac9c173007dd4da05fde788cd14c2916089f958c33fedb0dfa", + "zh:d3ba40bd806a3a08e9237dece679193c99afb2085de6b45d7f5d1f673cfcd368", + "zh:e1ad7ded53ecd6f0e5b473a3b44eae2b2e885653a56050ab583d387332be02e4", + "zh:e93e78575ce82be6084cc153c24ba8f385dc8d6880888ee66e918460c870953d", + ] +} + +provider "registry.terraform.io/hashicorp/aws" { + version = "6.35.1" + constraints = "6.35.1" + hashes = [ + "h1:0/uXxSpL98lpRqjRhjAvvWZVnJZnbOehfAlTrcPXURI=", + "h1:xD+5zPhF0ry3sutriARfFVIg5m38VwYt66RveI3aUyI=", + "zh:0a16d1b0ba9379e5c5295e6b3caa42f0b8ba6b9f0a7cc9dbe58c232cf995db2d", + "zh:4b2e69907a1a2c557e45ef590f9fd6187ab5bf90378346ba9f723535e49ce908", + "zh:56bdafda0d629e15dc3dd9275b54f1fb953e2e09a3bc1a34e027da9d03ea4893", + "zh:5b84e933989150249036f84faad221dce0daa9d3043ff24401547e18f00b121e", + "zh:70bac98c27a14cb2cedabd741a1f7f1bab074c127efdcf02b54dbcf0d03db3cc", + "zh:7184f48bd077eaf68e184fd44f97e2d971cb77c59a68aedb95a0f8dc01b134fe", + "zh:7367589ae8b584bfcd83c973f5003e15010a453349c017a0d2cca8772d4fcfd9", + "zh:7ec9699dee49dd31bbc2d0e50fa1fff451eee5c1d9fd59bca7412acb49ce6594", + "zh:92dd139b96977a64af0e976cd06e84921033678ab97550f1b687c0ea54a8e82c", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:9f2df575a5b010db60068668c48806595a3d617a2c0305035283fe8b72f07b19", + "zh:a4602b7602c75c8f726bdc7e706dc5c26736e47cc8381be01386aa8d8d998403", + "zh:bc25fefeeee10425df7aebfc21dc6532d19acdf03fa97b9e6d8c113adffd0a1d", + "zh:f445592040b5fc368a12e6edeffc951b2eb41e86413c4074638a13376e25a9cc", + "zh:ff43962a48bd8f85e17188736bbd3c145b6a1320bd8303221f6b4f9ec861e1e6", + ] +} diff --git a/tests/ministack/setup/README.md b/tests/ministack/setup/README.md new file mode 100644 index 0000000000..4c39a7450a --- /dev/null +++ b/tests/ministack/setup/README.md @@ -0,0 +1,41 @@ + +## Requirements + +| Name | Version | +|------|---------| +| [terraform](#requirement\_terraform) | >= 1.10.0 | +| [archive](#requirement\_archive) | ~> 2.7 | +| [aws](#requirement\_aws) | = 6.35.1 | + +## Providers + +| Name | Version | +|------|---------| +| [archive](#provider\_archive) | 2.8.0 | +| [aws](#provider\_aws) | 6.35.1 | + +## Modules + +No modules. + +## Resources + +| Name | Type | +|------|------| +| [aws_ssm_parameter.al2023_arm64](https://registry.terraform.io/providers/hashicorp/aws/6.35.1/docs/resources/ssm_parameter) | resource | +| [aws_ssm_parameter.al2023_x64](https://registry.terraform.io/providers/hashicorp/aws/6.35.1/docs/resources/ssm_parameter) | resource | +| [aws_ssm_parameter.github_app_id](https://registry.terraform.io/providers/hashicorp/aws/6.35.1/docs/resources/ssm_parameter) | resource | +| [aws_ssm_parameter.github_app_key](https://registry.terraform.io/providers/hashicorp/aws/6.35.1/docs/resources/ssm_parameter) | resource | +| [aws_ssm_parameter.github_app_webhook_secret](https://registry.terraform.io/providers/hashicorp/aws/6.35.1/docs/resources/ssm_parameter) | resource | +| [archive_file.lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source | + +## Inputs + +No inputs. + +## Outputs + +| Name | Description | +|------|-------------| +| [lambda\_archive](#output\_lambda\_archive) | Absolute path to the inert Lambda archive used by the example tests. | + \ No newline at end of file diff --git a/tests/ministack/setup/index.mjs b/tests/ministack/setup/index.mjs new file mode 100644 index 0000000000..57b6fbdf51 --- /dev/null +++ b/tests/ministack/setup/index.mjs @@ -0,0 +1,16 @@ +const response = async () => ({ statusCode: 200, body: "ministack" }); + +export { + response as adjustPool, + response as deregisterRetry, + response as directWebhook, + response as dispatchToRunners, + response as eventBridgeWebhook, + response as handler, + response as interruptionWarning, + response as jobRetryCheck, + response as scaleDownHandler, + response as scaleUpHandler, + response as ssmHousekeeper, + response as termination, +}; diff --git a/tests/ministack/setup/main.tf b/tests/ministack/setup/main.tf new file mode 100644 index 0000000000..208e29c66d --- /dev/null +++ b/tests/ministack/setup/main.tf @@ -0,0 +1,69 @@ +terraform { + required_version = ">= 1.10.0" + + required_providers { + archive = { + source = "hashicorp/archive" + version = "~> 2.7" + } + aws = { + source = "hashicorp/aws" + version = "= 6.35.1" + } + } +} + +provider "aws" { + region = "eu-west-1" + + # These values are MiniStack test identifiers and cannot authenticate to AWS. + access_key = "000000000000" + secret_key = "ministack-test-only" + + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + skip_requesting_account_id = true + s3_use_path_style = true +} + +data "archive_file" "lambda" { + type = "zip" + source_file = "${path.module}/index.mjs" + output_path = "${path.module}/.terraform/ministack/lambda.zip" +} + +resource "aws_ssm_parameter" "al2023_x64" { + name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64" + type = "String" + value = "ami-0a1b2c3d4e5f67890" +} + +resource "aws_ssm_parameter" "al2023_arm64" { + name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-arm64" + type = "String" + value = "ami-0a1b2c3d4e5f67890" +} + +resource "aws_ssm_parameter" "github_app_id" { + name = "/ministack/terraform-aws-github-runner/github-app/id" + type = "String" + value = "0" +} + +resource "aws_ssm_parameter" "github_app_key" { + name = "/ministack/terraform-aws-github-runner/github-app/key-base64" + type = "SecureString" + value = "ministack-invalid-github-app-key" +} + +resource "aws_ssm_parameter" "github_app_webhook_secret" { + name = "/ministack/terraform-aws-github-runner/github-app/webhook-secret" + type = "SecureString" + value = "ministack-test-only" +} + +output "lambda_archive" { + description = "Absolute path to the inert Lambda archive used by the example tests." + value = abspath(data.archive_file.lambda.output_path) +}