Repository: goda6565/lambda-bot
Pull request #16: 新規: 開発環境用のTerraform設定を追加し、API Gateway、ECR、Lambda、Secrets Managerのモジュー…
Author: login: goda6565
Created: 2025-05-24T12:35:46Z | Merged: 2025-05-24T12:37:51Z



Diff:
diff --git a/.github/workflows/terraform-job.yaml b/.github/workflows/terraform-job.yaml
index 7a2df32..5a80bef 100644
--- a/.github/workflows/terraform-job.yaml
+++ b/.github/workflows/terraform-job.yaml
@@ -28,7 +28,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        directory: ["terraform/shared", "terraform/envs/prod"]
+        directory: ["terraform/shared", "terraform/envs/prod", "terraform/envs/dev"]
       fail-fast: false
     defaults:
       run:
diff --git a/terraform/envs/dev/.terraform.lock.hcl b/terraform/envs/dev/.terraform.lock.hcl
new file mode 100644
index 0000000..524751d
--- /dev/null
+++ b/terraform/envs/dev/.terraform.lock.hcl
@@ -0,0 +1,25 @@
+# This file is maintained automatically by "terraform init".
+# Manual edits may be lost in future updates.
+
+provider "registry.terraform.io/hashicorp/aws" {
+  version     = "5.98.0"
+  constraints = "~> 5.98.0"
+  hashes = [
+    "h1:neMFK/kP1KT6cTGID+Tkkt8L7PsN9XqwrPDGXVw3WVY=",
+    "zh:23377bd90204b6203b904f48f53edcae3294eb072d8fc18a4531c0cde531a3a1",
+    "zh:2e55a6ea14cc43b08cf82d43063e96c5c2f58ee953c2628523d0ee918fe3b609",
+    "zh:4885a817c16fdaaeddc5031edc9594c1f300db0e5b23be7cd76a473e7dcc7b4f",
+    "zh:6ca7177ad4e5c9d93dee4be1ac0792b37107df04657fddfe0c976f36abdd18b5",
+    "zh:78bf8eb0a67bae5dede09666676c7a38c9fb8d1b80a90ba06cf36ae268257d6f",
+    "zh:874b5a99457a3f88e2915df8773120846b63d820868a8f43082193f3dc84adcb",
+    "zh:95e1e4cf587cde4537ac9dfee9e94270652c812ab31fce3a431778c053abf354",
+    "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
+    "zh:a75145b58b241d64570803e6565c72467cd664633df32678755b51871f553e50",
+    "zh:aa31b13d0b0e8432940d6892a48b6268721fa54a02ed62ee42745186ee32f58d",
+    "zh:ae4565770f76672ce8e96528cbb66afdade1f91383123c079c7fdeafcb3d2877",
+    "zh:b99f042c45bf6aa69dd73f3f6d9cbe0b495b30442c526e0b3810089c059ba724",
+    "zh:bbb38e86d926ef101cefafe8fe090c57f2b1356eac9fc5ec81af310c50375897",
+    "zh:d03c89988ba4a0bd3cfc8659f951183ae7027aa8018a7ca1e53a300944af59cb",
+    "zh:d179ef28843fe663fc63169291a211898199009f0d3f63f0a6f65349e77727ec",
+  ]
+}
diff --git a/terraform/envs/dev/api_gateway.tf b/terraform/envs/dev/api_gateway.tf
new file mode 100644
index 0000000..5388979
--- /dev/null
+++ b/terraform/envs/dev/api_gateway.tf
@@ -0,0 +1,7 @@
+module "api_gateway" {
+  source                  = "../../modules/api_gateway"
+  env                     = var.env
+  lambda_function_name    = var.lambda_function_name
+  lambda_alias_name       = module.lambda.aws_lambda_alias_name
+  lambda_alias_invoke_arn = module.lambda.aws_lambda_alias_invoke_arn
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/ecr.tf b/terraform/envs/dev/ecr.tf
new file mode 100644
index 0000000..6d3e1ec
--- /dev/null
+++ b/terraform/envs/dev/ecr.tf
@@ -0,0 +1,4 @@
+module "ecr" {
+  source              = "../../modules/ecr"
+  ecr_repository_name = "${var.lambda_function_name}-${var.env}"
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/lambda.tf b/terraform/envs/dev/lambda.tf
new file mode 100644
index 0000000..088c3a9
--- /dev/null
+++ b/terraform/envs/dev/lambda.tf
@@ -0,0 +1,12 @@
+module "lambda" {
+  source               = "../../modules/lambda"
+  env                  = var.env
+  lambda_function_name = var.lambda_function_name
+  lambda_environment = {
+    ENV = var.env
+  }
+  secret_manager_secrets_arns = [
+    module.slack_bot_token.secrets_manager_secrets_arn,
+    module.slack_signing_secret.secrets_manager_secrets_arn,
+  ]
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/outputs.tf b/terraform/envs/dev/outputs.tf
new file mode 100644
index 0000000..7469cf1
--- /dev/null
+++ b/terraform/envs/dev/outputs.tf
@@ -0,0 +1,3 @@
+output "api_gateway_invoke_url" {
+  value = module.api_gateway.api_gateway_invoke_url
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/provider.tf b/terraform/envs/dev/provider.tf
new file mode 100644
index 0000000..5ff54f0
--- /dev/null
+++ b/terraform/envs/dev/provider.tf
@@ -0,0 +1,3 @@
+provider "aws" {
+  region = var.region
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/secrets_manager.tf b/terraform/envs/dev/secrets_manager.tf
new file mode 100644
index 0000000..fc28ca5
--- /dev/null
+++ b/terraform/envs/dev/secrets_manager.tf
@@ -0,0 +1,11 @@
+module "slack_bot_token" {
+  source = "../../modules/secretsmanager"
+
+  secret_manager_secrets_name = "slack-bot-token-dev"
+}
+
+module "slack_signing_secret" {
+  source = "../../modules/secretsmanager"
+
+  secret_manager_secrets_name = "slack-signing-secret-dev"
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/terraform.tf b/terraform/envs/dev/terraform.tf
new file mode 100644
index 0000000..704bb3b
--- /dev/null
+++ b/terraform/envs/dev/terraform.tf
@@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 5.98.0"
+    }
+  }
+  required_version = ">= 1.12.0"
+  backend "s3" {
+    bucket = "lambda-bot-tfstate-backend"
+    key    = "dev"
+    region = "ap-northeast-1"
+  }
+}
\ No newline at end of file
diff --git a/terraform/envs/dev/variables.tf b/terraform/envs/dev/variables.tf
new file mode 100644
index 0000000..c7f6882
--- /dev/null
+++ b/terraform/envs/dev/variables.tf
@@ -0,0 +1,17 @@
+variable "region" {
+  description = "AWS region"
+  type        = string
+  default     = "ap-northeast-1"
+}
+
+variable "lambda_function_name" {
+  description = "The name of the lambda function"
+  type        = string
+  default     = "lambda-bot"
+}
+
+variable "env" {
+  description = "The environment of the lambda function"
+  type        = string
+  default     = "dev"
+}
\ No newline at end of file


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

Adds Terraform configuration for the dev environment, provisioning API Gateway, ECR, Lambda, and Secrets Manager, and updates the CI workflow to include `terraform/envs/dev`.

- Introduce dev-specific variables, provider, and backend configuration  
- Define modules for Slack secrets, ECR repo, Lambda function, and API Gateway  
- Expose API Gateway invoke URL in outputs and add `dev` to the GitHub Actions Terraform matrix

### Reviewed Changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

<details>
<summary>Show a summary per file</summary>

| File                                    | Description                                                 |
|-----------------------------------------|-------------------------------------------------------------|
| terraform/envs/dev/variables.tf         | Added region, lambda_function_name, and env variables       |
| terraform/envs/dev/terraform.tf         | Configured required providers and S3 backend for dev        |
| terraform/envs/dev/secrets_manager.tf   | Added modules for Slack bot token and signing secret        |
| terraform/envs/dev/provider.tf          | Set AWS provider region using `var.region`                  |
| terraform/envs/dev/outputs.tf           | Added `api_gateway_invoke_url` output                       |
| terraform/envs/dev/lambda.tf            | Configured the Lambda module with environment and secrets   |
| terraform/envs/dev/ecr.tf               | Configured the ECR module with repo name interpolation      |
| terraform/envs/dev/api_gateway.tf       | Configured the API Gateway module with Lambda alias details |
| .github/workflows/terraform-job.yaml     | Updated CI matrix to include the dev environment            |
</details>


<details>
<summary>Files not reviewed (1)</summary>

* **terraform/envs/dev/.terraform.lock.hcl**: Language not supported
</details>

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**terraform/envs/dev/variables.tf:13**
* [nitpick] Consider renaming this variable from `env` to `environment` or `env_name` to improve clarity and avoid potential naming conflicts.
```
variable "env" {
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-05-24T12:36:52Z

Review comments:
diff_hunk: @@ -0,0 +1,3 @@
+output "api_gateway_invoke_url" {
+  value = module.api_gateway.api_gateway_invoke_url
path: terraform/envs/dev/outputs.tf
user: login: Copilot
body: Add a `description` attribute to this output block to document its purpose for consumers.
```suggestion
  description = "The invoke URL for the API Gateway, used to access the deployed API."
  value       = module.api_gateway.api_gateway_invoke_url
```
created_at: 2025-05-24T12:36:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,4 @@
+module "ecr" {
+  source              = "../../modules/ecr"
+  ecr_repository_name = "${var.lambda_function_name}-${var.env}"
path: terraform/envs/dev/ecr.tf
user: login: Copilot
body: [nitpick] Use Terraform 0.12+ native string functions like `format("%s-%s", var.lambda_function_name, var.env)` for readability.
```suggestion
  ecr_repository_name = format("%s-%s", var.lambda_function_name, var.env)
```
created_at: 2025-05-24T12:36:51Z
author_association: NONE
diff_hunk: @@ -0,0 +1,14 @@
+terraform {
+  required_providers {
+    aws = {
+      source  = "hashicorp/aws"
+      version = "~> 5.98.0"
+    }
+  }
+  required_version = ">= 1.12.0"
+  backend "s3" {
+    bucket = "lambda-bot-tfstate-backend"
+    key    = "dev"
+    region = "ap-northeast-1"
path: terraform/envs/dev/terraform.tf
user: login: Copilot
body: [nitpick] The backend region is hard-coded here, duplicating `var.region` default; consider centralizing region configuration to prevent drift.
```suggestion
    region = var.region
```
created_at: 2025-05-24T12:36:52Z
author_association: NONE

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-24T12:36:16Z
body: 
## Plan Result (shared)

[CI link](https://github.com/goda6565/lambda-bot/actions/runs/15227104713)


<pre><code>No changes. Your infrastructure matches the configuration.</code></pre>






## :warning: Errors

* add a label shared/no-changes: POST https://api.github.com/repos/goda6565/lambda-bot/issues/16/labels: 403 You do not have permission to create labels on this repository. [{Resource:Repository Field:label Code:unauthorized Message:}]
<!-- github-comment: {"Command":"plan","JobName":"terraform","PRNumber":16,"Program":"tfcmt","SHA1":"3d41e86ac4790206bef543fb2b055547af727660","Target":"shared","Vars":{},"WorkflowName":"Terraform Multi-Env CI"} -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-24T12:36:16Z
body: 
## Plan Result (dev)

[CI link](https://github.com/goda6565/lambda-bot/actions/runs/15227104713)


<pre><code>Plan: 17 to add, 0 to change, 0 to destroy.</code></pre>

* Create
  * module.api_gateway.aws_apigatewayv2_api.lambda_api
  * module.api_gateway.aws_apigatewayv2_integration.lambda_integration
  * module.api_gateway.aws_apigatewayv2_route.lambda_function_route
  * module.api_gateway.aws_apigatewayv2_stage.lambda_function_invoke_stage
  * module.api_gateway.aws_cloudwatch_log_group.api_gateway
  * module.api_gateway.aws_lambda_permission.allow_apigateway
  * module.ecr.aws_ecr_repository.ecr_repository
  * module.lambda.aws_cloudwatch_log_group.lambda
  * module.lambda.aws_iam_role.lambda_role
  * module.lambda.aws_iam_role_policy.lambda_secret_manager_policy
  * module.lambda.aws_iam_role_policy_attachment.lambda_role_policy_attachment
  * module.lambda.aws_lambda_alias.lambda
  * module.lambda.aws_lambda_function.lambda
  * module.slack_bot_token.aws_secretsmanager_secret.secretsmanager_secret
  * module.slack_bot_token.aws_secretsmanager_secret_version.secretmanager_secret_version
  * module.slack_signing_secret.aws_secretsmanager_secret.secretsmanager_secret
  * module.slack_signing_secret.aws_secretsmanager_secret_version.secretmanager_secret_version


<details><summary>Change Result (Click me)</summary>

```hcl

  # module.api_gateway.aws_apigatewayv2_api.lambda_api will be created
  + resource "aws_apigatewayv2_api" "lambda_api" {
      + api_endpoint                 = (known after apply)
      + api_key_selection_expression = "$request.header.x-api-key"
      + arn                          = (known after apply)
      + execution_arn                = (known after apply)
      + id                           = (known after apply)
      + ip_address_type              = (known after apply)
      + name                         = "lambda-bot-dev-api"
      + protocol_type                = "HTTP"
      + route_selection_expression   = "$request.method $request.path"
      + tags_all                     = (known after apply)
    }

  # module.api_gateway.aws_apigatewayv2_integration.lambda_integration will be created
  + resource "aws_apigatewayv2_integration" "lambda_integration" {
      + api_id                                    = (known after apply)
      + connection_type                           = "INTERNET"
      + id                                        = (known after apply)
      + integration_method                        = "POST"
      + integration_response_selection_expression = (known after apply)
      + integration_type                          = "AWS_PROXY"
      + integration_uri                           = (known after apply)
      + payload_format_version                    = "2.0"
      + timeout_milliseconds                      = 30000
    }

  # module.api_gateway.aws_apigatewayv2_route.lambda_function_route will be created
  + resource "aws_apigatewayv2_route" "lambda_function_route" {
      + api_id             = (known after apply)
      + api_key_required   = false
      + authorization_type = "NONE"
      + id                 = (known after apply)
      + route_key          = "POST /invoke"
      + target             = (known after apply)
    }

  # module.api_gateway.aws_apigatewayv2_stage.lambda_function_invoke_stage will be created
  + resource "aws_apigatewayv2_stage" "lambda_function_invoke_stage" {
      + api_id        = (known after apply)
      + arn           = (known after apply)
      + auto_deploy   = true
      + deployment_id = (known after apply)
      + execution_arn = (known after apply)
      + id            = (known after apply)
      + invoke_url    = (known after apply)
      + name          = "$default"
      + tags_all      = (known after apply)

      + access_log_settings {
          + destination_arn = (known after apply)
          + format          = jsonencode(
                {
                  + httpMethod   = "$context.httpMethod"
                  + ip           = "$context.identity.sourceIp"
                  + protocol     = "$context.protocol"
                  + requestId    = "$context.requestId"
                  + requestTime  = "$context.requestTime"
                  + responseTime = "$context.responseLatency"
                  + routeKey     = "$context.routeKey"
                  + status       = "$context.status"
                }
            )
        }
    }

  # module.api_gateway.aws_cloudwatch_log_group.api_gateway will be created
  + resource "aws_cloudwatch_log_group" "api_gateway" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + log_group_class   = (known after apply)
      + name              = "/aws/lambda/lambda-bot-dev-api-gateway"
      + name_prefix       = (known after apply)
      + retention_in_days = 30
      + skip_destroy      = false
      + tags              = {
          + "Name" = "/aws/lambda/lambda-bot-dev-api-gateway"
        }
      + tags_all          = {
          + "Name" = "/aws/lambda/lambda-bot-dev-api-gateway"
        }
    }

  # module.api_gateway.aws_lambda_permission.allow_apigateway will be created
  + resource "aws_lambda_permission" "allow_apigateway" {
      + action              = "lambda:InvokeFunction"
      + function_name       = "lambda-bot-dev"
      + id                  = (known after apply)
      + principal           = "apigateway.amazonaws.com"
      + qualifier           = "dev"
      + source_arn          = (known after apply)
      + statement_id        = "AllowInvokeFromApiGateway"
      + statement_id_prefix = (known after apply)
    }

  # module.ecr.aws_ecr_repository.ecr_repository will be created
  + resource "aws_ecr_repository" "ecr_repository" {
      + arn                  = (known after apply)
      + id                   = (known after apply)
      + image_tag_mutability = "IMMUTABLE"
      + name                 = "lambda-bot-dev"
      + registry_id          = (known after apply)
      + repository_url       = (known after apply)
      + tags                 = {
          + "Name" = "lambda-bot-dev"
        }
      + tags_all             = {
          + "Name" = "lambda-bot-dev"
        }

      + image_scanning_configuration {
          + scan_on_push = true
        }
    }

  # module.lambda.data.aws_iam_policy_document.lambda_secret_manager_policy_document will be read during apply
  # (config refers to values not yet known)
 <= data "aws_iam_policy_document" "lambda_secret_manager_policy_document" {
      + id            = (known after apply)
      + json          = (known after apply)
      + minified_json = (known after apply)

      + statement {
          + actions   = [
              + "secretsmanager:GetSecretValue",
            ]
          + effect    = "Allow"
          + resources = [
              + (known after apply),
              + (known after apply),
            ]
        }
    }

  # module.lambda.aws_cloudwatch_log_group.lambda will be created
  + resource "aws_cloudwatch_log_group" "lambda" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + log_group_class   = (known after apply)
      + name              = "/aws/lambda/lambda-bot-dev"
      + name_prefix       = (known after apply)
      + retention_in_days = 30
      + skip_destroy      = false
      + tags              = {
          + "Name" = "/aws/lambda/lambda-bot-dev"
        }
      + tags_all          = {
          + "Name" = "/aws/lambda/lambda-bot-dev"
        }
    }

  # module.lambda.aws_iam_role.lambda_role will be created
  + resource "aws_iam_role" "lambda_role" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "lambda.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "lambda-bot-dev-role"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)

      + inline_policy (known after apply)
    }

  # module.lambda.aws_iam_role_policy.lambda_secret_manager_policy will be created
  + resource "aws_iam_role_policy" "lambda_secret_manager_policy" {
      + id          = (known after apply)
      + name        = "lambda-bot-dev-secret-manager-policy"
      + name_prefix = (known after apply)
      + policy      = (known after apply)
      + role        = (known after apply)
    }

  # module.lambda.aws_iam_role_policy_attachment.lambda_role_policy_attachment will be created
  + resource "aws_iam_role_policy_attachment" "lambda_role_policy_attachment" {
      + id         = (known after apply)
      + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      + role       = "lambda-bot-dev-role"
    }

  # module.lambda.aws_lambda_alias.lambda will be created
  + resource "aws_lambda_alias" "lambda" {
      + arn              = (known after apply)
      + function_name    = "lambda-bot-dev"
      + function_version = (known after apply)
      + id               = (known after apply)
      + invoke_arn       = (known after apply)
      + name             = "dev"
    }

  # module.lambda.aws_lambda_function.lambda will be created
  + resource "aws_lambda_function" "lambda" {
      + architectures                  = [
          + "arm64",
        ]
      + arn                            = (known after apply)
      + code_sha256                    = (known after apply)
      + function_name                  = "lambda-bot-dev"
      + id                             = (known after apply)
      + image_uri                      = "061051222129.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-bot-prod:latest"
      + invoke_arn                     = (known after apply)
      + last_modified                  = (known after apply)
      + memory_size                    = 128
      + package_type                   = "Image"
      + publish                        = true
      + qualified_arn                  = (known after apply)
      + qualified_invoke_arn           = (known after apply)
      + reserved_concurrent_executions = -1
      + role                           = (known after apply)
      + signing_job_arn                = (known after apply)
      + signing_profile_version_arn    = (known after apply)
      + skip_destroy                   = false
      + source_code_hash               = (known after apply)
      + source_code_size               = (known after apply)
      + tags                           = {
          + "Name" = "lambda-bot-dev"
        }
      + tags_all                       = {
          + "Name" = "lambda-bot-dev"
        }
      + timeout                        = 300
      + version                        = (known after apply)

      + environment {
          + variables = {
              + "ENV" = "dev"
            }
        }

      + ephemeral_storage (known after apply)

      + logging_config (known after apply)

      + tracing_config {
          + mode = "Active"
        }
    }

  # module.slack_bot_token.aws_secretsmanager_secret.secretsmanager_secret will be created
  + resource "aws_secretsmanager_secret" "secretsmanager_secret" {
      + arn                            = (known after apply)
      + force_overwrite_replica_secret = false
      + id                             = (known after apply)
      + name                           = "slack-bot-token-dev"
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + tags_all                       = (known after apply)

      + replica (known after apply)
    }

  # module.slack_bot_token.aws_secretsmanager_secret_version.secretmanager_secret_version will be created
  + resource "aws_secretsmanager_secret_version" "secretmanager_secret_version" {
      + arn                  = (known after apply)
      + has_secret_string_wo = (known after apply)
      + id                   = (known after apply)
      + secret_id            = (known after apply)
      + secret_string        = (sensitive value)
      + secret_string_wo     = (write-only attribute)
      + version_id           = (known after apply)
      + version_stages       = (known after apply)
    }

  # module.slack_signing_secret.aws_secretsmanager_secret.secretsmanager_secret will be created
  + resource "aws_secretsmanager_secret" "secretsmanager_secret" {
      + arn                            = (known after apply)
      + force_overwrite_replica_secret = false
      + id                             = (known after apply)
      + name                           = "slack-signing-secret-dev"
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + tags_all                       = (known after apply)

      + replica (known after apply)
    }

  # module.slack_signing_secret.aws_secretsmanager_secret_version.secretmanager_secret_version will be created
  + resource "aws_secretsmanager_secret_version" "secretmanager_secret_version" {
      + arn                  = (known after apply)
      + has_secret_string_wo = (known after apply)
      + id                   = (known after apply)
      + secret_id            = (known after apply)
      + secret_string        = (sensitive value)
      + secret_string_wo     = (write-only attribute)
      + version_id           = (known after apply)
      + version_stages       = (known after apply)
    }

Plan: 17 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + api_gateway_invoke_url = (known after apply)
```

</details>




## :warning: Errors

* add a label dev/add-or-update: POST https://api.github.com/repos/goda6565/lambda-bot/issues/16/labels: 403 You do not have permission to create labels on this repository. [{Resource:Repository Field:label Code:unauthorized Message:}]
<!-- github-comment: {"Command":"plan","JobName":"terraform","PRNumber":16,"Program":"tfcmt","SHA1":"3d41e86ac4790206bef543fb2b055547af727660","Target":"dev","Vars":{},"WorkflowName":"Terraform Multi-Env CI"} -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-24T12:36:19Z
body: 
## Plan Result (prod)

[CI link](https://github.com/goda6565/lambda-bot/actions/runs/15227104713)


<pre><code>No changes. Your infrastructure matches the configuration.</code></pre>






## :warning: Errors

* add a label prod/no-changes: POST https://api.github.com/repos/goda6565/lambda-bot/issues/16/labels: 403 You do not have permission to create labels on this repository. [{Resource:Repository Field:label Code:unauthorized Message:}]
<!-- github-comment: {"Command":"plan","JobName":"terraform","PRNumber":16,"Program":"tfcmt","SHA1":"3d41e86ac4790206bef543fb2b055547af727660","Target":"prod","Vars":{},"WorkflowName":"Terraform Multi-Env CI"} -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-24T12:38:22Z
body: 
## :white_check_mark: Apply Succeeded

[CI link](https://github.com/goda6565/lambda-bot/actions/runs/15227120744)



<pre><code>Apply complete! Resources: 0 added, 0 changed, 0 destroyed.</code></pre>

<details><summary>Details (Click me)</summary>

```hcl
module.bootstrap.aws_iam_openid_connect_provider.github_actions_oidc_provider: Refreshing state... [id=arn:aws:iam::061051222129:oidc-provider/token.actions.githubusercontent.com]
module.bootstrap.data.aws_iam_policy_document.github_actions_oidc_policy_document: Reading...
module.bootstrap.data.aws_iam_policy_document.github_actions_oidc_policy_document: Read complete after 0s [id=3042905044]
module.bootstrap.aws_iam_role.github_actions_oidc_role: Refreshing state... [id=github-actions-oidc-role]
module.bootstrap.aws_iam_role_policy_attachment.github_actions_oidc_role_policy_attachment: Refreshing state... [id=github-actions-oidc-role-20250523145820783500000001]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

github_actions_oidc_role_arn = "arn:aws:iam::061051222129:role/github-actions-oidc-role"

```

</details>

<!-- github-comment: {"Command":"apply","JobName":"terraform","PRNumber":16,"Program":"tfcmt","SHA1":"2406c8c4bb11402e429365bb25a1adb405e56cea","Vars":{},"WorkflowName":"Terraform Multi-Env CI"} -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-24T12:38:25Z
body: 
## :white_check_mark: Apply Succeeded

[CI link](https://github.com/goda6565/lambda-bot/actions/runs/15227120744)



<pre><code>Apply complete! Resources: 0 added, 0 changed, 0 destroyed.</code></pre>

<details><summary>Details (Click me)</summary>

```hcl
module.lambda.data.aws_iam_policy_document.lambda_policy_document: Reading...
module.lambda.aws_cloudwatch_log_group.lambda: Refreshing state... [id=/aws/lambda/lambda-bot-prod]
module.ecr.aws_ecr_repository.ecr_repository: Refreshing state... [id=lambda-bot-prod]
module.slack_signing_secret.aws_secretsmanager_secret.secretsmanager_secret: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-signing-secret-prod-6mlJo8]
module.api_gateway.aws_apigatewayv2_api.lambda_api: Refreshing state... [id=0pdgg6nqu1]
module.api_gateway.aws_cloudwatch_log_group.api_gateway: Refreshing state... [id=/aws/lambda/lambda-bot-prod-api-gateway]
module.slack_bot_token.aws_secretsmanager_secret.secretsmanager_secret: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-bot-token-prod-UoovR7]
module.lambda.data.aws_iam_policy_document.lambda_policy_document: Read complete after 0s [id=2690255455]
module.lambda.aws_iam_role.lambda_role: Refreshing state... [id=lambda-bot-prod-role]
module.lambda.aws_iam_role_policy_attachment.lambda_role_policy_attachment: Refreshing state... [id=lambda-bot-prod-role-20250524055713202500000001]
module.slack_bot_token.aws_secretsmanager_secret_version.secretmanager_secret_version: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-bot-token-prod-UoovR7|terraform-20250524091635592400000003]
module.slack_signing_secret.aws_secretsmanager_secret_version.secretmanager_secret_version: Refreshing state... [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-signing-secret-prod-6mlJo8|terraform-20250524091635604300000004]
module.lambda.data.aws_iam_policy_document.lambda_secret_manager_policy_document: Reading...
module.lambda.data.aws_iam_policy_document.lambda_secret_manager_policy_document: Read complete after 0s [id=1851053628]
module.lambda.aws_iam_role_policy.lambda_secret_manager_policy: Refreshing state... [id=lambda-bot-prod-role:lambda-bot-prod-secret-manager-policy]
module.api_gateway.aws_apigatewayv2_stage.lambda_function_invoke_stage: Refreshing state... [id=$default]
module.lambda.aws_lambda_function.lambda: Refreshing state... [id=lambda-bot-prod]
module.lambda.aws_lambda_alias.lambda: Refreshing state... [id=arn:aws:lambda:ap-northeast-1:061051222129:function:lambda-bot-prod:prod]
module.api_gateway.aws_lambda_permission.allow_apigateway: Refreshing state... [id=AllowInvokeFromApiGateway]
module.api_gateway.aws_apigatewayv2_integration.lambda_integration: Refreshing state... [id=vfdjtep]
module.api_gateway.aws_apigatewayv2_route.lambda_function_route: Refreshing state... [id=n414fla]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration
and found no differences, so no changes are needed.

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

api_gateway_invoke_url = "https://0pdgg6nqu1.execute-api.ap-northeast-1.amazonaws.com/"

```

</details>

<!-- github-comment: {"Command":"apply","JobName":"terraform","PRNumber":16,"Program":"tfcmt","SHA1":"2406c8c4bb11402e429365bb25a1adb405e56cea","Vars":{},"WorkflowName":"Terraform Multi-Env CI"} -->
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-05-24T12:38:55Z
body: 
## :white_check_mark: Apply Succeeded

[CI link](https://github.com/goda6565/lambda-bot/actions/runs/15227120744)



<pre><code>Apply complete! Resources: 17 added, 0 changed, 0 destroyed.</code></pre>

<details><summary>Details (Click me)</summary>

```hcl
module.lambda.data.aws_iam_policy_document.lambda_policy_document: Reading...
module.lambda.data.aws_iam_policy_document.lambda_policy_document: Read complete after 0s [id=2690255455]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create
 <= read (data resources)

Terraform will perform the following actions:

  # module.api_gateway.aws_apigatewayv2_api.lambda_api will be created
  + resource "aws_apigatewayv2_api" "lambda_api" {
      + api_endpoint                 = (known after apply)
      + api_key_selection_expression = "$request.header.x-api-key"
      + arn                          = (known after apply)
      + execution_arn                = (known after apply)
      + id                           = (known after apply)
      + ip_address_type              = (known after apply)
      + name                         = "lambda-bot-dev-api"
      + protocol_type                = "HTTP"
      + route_selection_expression   = "$request.method $request.path"
      + tags_all                     = (known after apply)
    }

  # module.api_gateway.aws_apigatewayv2_integration.lambda_integration will be created
  + resource "aws_apigatewayv2_integration" "lambda_integration" {
      + api_id                                    = (known after apply)
      + connection_type                           = "INTERNET"
      + id                                        = (known after apply)
      + integration_method                        = "POST"
      + integration_response_selection_expression = (known after apply)
      + integration_type                          = "AWS_PROXY"
      + integration_uri                           = (known after apply)
      + payload_format_version                    = "2.0"
      + timeout_milliseconds                      = 30000
    }

  # module.api_gateway.aws_apigatewayv2_route.lambda_function_route will be created
  + resource "aws_apigatewayv2_route" "lambda_function_route" {
      + api_id             = (known after apply)
      + api_key_required   = false
      + authorization_type = "NONE"
      + id                 = (known after apply)
      + route_key          = "POST /invoke"
      + target             = (known after apply)
    }

  # module.api_gateway.aws_apigatewayv2_stage.lambda_function_invoke_stage will be created
  + resource "aws_apigatewayv2_stage" "lambda_function_invoke_stage" {
      + api_id        = (known after apply)
      + arn           = (known after apply)
      + auto_deploy   = true
      + deployment_id = (known after apply)
      + execution_arn = (known after apply)
      + id            = (known after apply)
      + invoke_url    = (known after apply)
      + name          = "$default"
      + tags_all      = (known after apply)

      + access_log_settings {
          + destination_arn = (known after apply)
          + format          = jsonencode(
                {
                  + httpMethod   = "$context.httpMethod"
                  + ip           = "$context.identity.sourceIp"
                  + protocol     = "$context.protocol"
                  + requestId    = "$context.requestId"
                  + requestTime  = "$context.requestTime"
                  + responseTime = "$context.responseLatency"
                  + routeKey     = "$context.routeKey"
                  + status       = "$context.status"
                }
            )
        }
    }

  # module.api_gateway.aws_cloudwatch_log_group.api_gateway will be created
  + resource "aws_cloudwatch_log_group" "api_gateway" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + log_group_class   = (known after apply)
      + name              = "/aws/lambda/lambda-bot-dev-api-gateway"
      + name_prefix       = (known after apply)
      + retention_in_days = 30
      + skip_destroy      = false
      + tags              = {
          + "Name" = "/aws/lambda/lambda-bot-dev-api-gateway"
        }
      + tags_all          = {
          + "Name" = "/aws/lambda/lambda-bot-dev-api-gateway"
        }
    }

  # module.api_gateway.aws_lambda_permission.allow_apigateway will be created
  + resource "aws_lambda_permission" "allow_apigateway" {
      + action              = "lambda:InvokeFunction"
      + function_name       = "lambda-bot-dev"
      + id                  = (known after apply)
      + principal           = "apigateway.amazonaws.com"
      + qualifier           = "dev"
      + source_arn          = (known after apply)
      + statement_id        = "AllowInvokeFromApiGateway"
      + statement_id_prefix = (known after apply)
    }

  # module.ecr.aws_ecr_repository.ecr_repository will be created
  + resource "aws_ecr_repository" "ecr_repository" {
      + arn                  = (known after apply)
      + id                   = (known after apply)
      + image_tag_mutability = "IMMUTABLE"
      + name                 = "lambda-bot-dev"
      + registry_id          = (known after apply)
      + repository_url       = (known after apply)
      + tags                 = {
          + "Name" = "lambda-bot-dev"
        }
      + tags_all             = {
          + "Name" = "lambda-bot-dev"
        }

      + image_scanning_configuration {
          + scan_on_push = true
        }
    }

  # module.lambda.data.aws_iam_policy_document.lambda_secret_manager_policy_document will be read during apply
  # (config refers to values not yet known)
 <= data "aws_iam_policy_document" "lambda_secret_manager_policy_document" {
      + id            = (known after apply)
      + json          = (known after apply)
      + minified_json = (known after apply)

      + statement {
          + actions   = [
              + "secretsmanager:GetSecretValue",
            ]
          + effect    = "Allow"
          + resources = [
              + (known after apply),
              + (known after apply),
            ]
        }
    }

  # module.lambda.aws_cloudwatch_log_group.lambda will be created
  + resource "aws_cloudwatch_log_group" "lambda" {
      + arn               = (known after apply)
      + id                = (known after apply)
      + log_group_class   = (known after apply)
      + name              = "/aws/lambda/lambda-bot-dev"
      + name_prefix       = (known after apply)
      + retention_in_days = 30
      + skip_destroy      = false
      + tags              = {
          + "Name" = "/aws/lambda/lambda-bot-dev"
        }
      + tags_all          = {
          + "Name" = "/aws/lambda/lambda-bot-dev"
        }
    }

  # module.lambda.aws_iam_role.lambda_role will be created
  + resource "aws_iam_role" "lambda_role" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "lambda.amazonaws.com"
                        }
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "lambda-bot-dev-role"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)

      + inline_policy (known after apply)
    }

  # module.lambda.aws_iam_role_policy.lambda_secret_manager_policy will be created
  + resource "aws_iam_role_policy" "lambda_secret_manager_policy" {
      + id          = (known after apply)
      + name        = "lambda-bot-dev-secret-manager-policy"
      + name_prefix = (known after apply)
      + policy      = (known after apply)
      + role        = (known after apply)
    }

  # module.lambda.aws_iam_role_policy_attachment.lambda_role_policy_attachment will be created
  + resource "aws_iam_role_policy_attachment" "lambda_role_policy_attachment" {
      + id         = (known after apply)
      + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
      + role       = "lambda-bot-dev-role"
    }

  # module.lambda.aws_lambda_alias.lambda will be created
  + resource "aws_lambda_alias" "lambda" {
      + arn              = (known after apply)
      + function_name    = "lambda-bot-dev"
      + function_version = (known after apply)
      + id               = (known after apply)
      + invoke_arn       = (known after apply)
      + name             = "dev"
    }

  # module.lambda.aws_lambda_function.lambda will be created
  + resource "aws_lambda_function" "lambda" {
      + architectures                  = [
          + "arm64",
        ]
      + arn                            = (known after apply)
      + code_sha256                    = (known after apply)
      + function_name                  = "lambda-bot-dev"
      + id                             = (known after apply)
      + image_uri                      = "061051222129.dkr.ecr.ap-northeast-1.amazonaws.com/lambda-bot-prod:latest"
      + invoke_arn                     = (known after apply)
      + last_modified                  = (known after apply)
      + memory_size                    = 128
      + package_type                   = "Image"
      + publish                        = true
      + qualified_arn                  = (known after apply)
      + qualified_invoke_arn           = (known after apply)
      + reserved_concurrent_executions = -1
      + role                           = (known after apply)
      + signing_job_arn                = (known after apply)
      + signing_profile_version_arn    = (known after apply)
      + skip_destroy                   = false
      + source_code_hash               = (known after apply)
      + source_code_size               = (known after apply)
      + tags                           = {
          + "Name" = "lambda-bot-dev"
        }
      + tags_all                       = {
          + "Name" = "lambda-bot-dev"
        }
      + timeout                        = 300
      + version                        = (known after apply)

      + environment {
          + variables = {
              + "ENV" = "dev"
            }
        }

      + ephemeral_storage (known after apply)

      + logging_config (known after apply)

      + tracing_config {
          + mode = "Active"
        }
    }

  # module.slack_bot_token.aws_secretsmanager_secret.secretsmanager_secret will be created
  + resource "aws_secretsmanager_secret" "secretsmanager_secret" {
      + arn                            = (known after apply)
      + force_overwrite_replica_secret = false
      + id                             = (known after apply)
      + name                           = "slack-bot-token-dev"
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + tags_all                       = (known after apply)

      + replica (known after apply)
    }

  # module.slack_bot_token.aws_secretsmanager_secret_version.secretmanager_secret_version will be created
  + resource "aws_secretsmanager_secret_version" "secretmanager_secret_version" {
      + arn                  = (known after apply)
      + has_secret_string_wo = (known after apply)
      + id                   = (known after apply)
      + secret_id            = (known after apply)
      + secret_string        = (sensitive value)
      + secret_string_wo     = (write-only attribute)
      + version_id           = (known after apply)
      + version_stages       = (known after apply)
    }

  # module.slack_signing_secret.aws_secretsmanager_secret.secretsmanager_secret will be created
  + resource "aws_secretsmanager_secret" "secretsmanager_secret" {
      + arn                            = (known after apply)
      + force_overwrite_replica_secret = false
      + id                             = (known after apply)
      + name                           = "slack-signing-secret-dev"
      + name_prefix                    = (known after apply)
      + policy                         = (known after apply)
      + recovery_window_in_days        = 30
      + tags_all                       = (known after apply)

      + replica (known after apply)
    }

  # module.slack_signing_secret.aws_secretsmanager_secret_version.secretmanager_secret_version will be created
  + resource "aws_secretsmanager_secret_version" "secretmanager_secret_version" {
      + arn                  = (known after apply)
      + has_secret_string_wo = (known after apply)
      + id                   = (known after apply)
      + secret_id            = (known after apply)
      + secret_string        = (sensitive value)
      + secret_string_wo     = (write-only attribute)
      + version_id           = (known after apply)
      + version_stages       = (known after apply)
    }

Plan: 17 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + api_gateway_invoke_url = (known after apply)
module.lambda.aws_cloudwatch_log_group.lambda: Creating...
module.slack_signing_secret.aws_secretsmanager_secret.secretsmanager_secret: Creating...
module.slack_bot_token.aws_secretsmanager_secret.secretsmanager_secret: Creating...
module.api_gateway.aws_cloudwatch_log_group.api_gateway: Creating...
module.lambda.aws_iam_role.lambda_role: Creating...
module.ecr.aws_ecr_repository.ecr_repository: Creating...
module.api_gateway.aws_apigatewayv2_api.lambda_api: Creating...
module.lambda.aws_iam_role.lambda_role: Creation complete after 0s [id=lambda-bot-dev-role]
module.lambda.aws_iam_role_policy_attachment.lambda_role_policy_attachment: Creating...
module.lambda.aws_iam_role_policy_attachment.lambda_role_policy_attachment: Creation complete after 1s [id=lambda-bot-dev-role-20250524123832605600000003]
module.slack_signing_secret.aws_secretsmanager_secret.secretsmanager_secret: Creation complete after 1s [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-signing-secret-dev-1NXj8H]
module.slack_signing_secret.aws_secretsmanager_secret_version.secretmanager_secret_version: Creating...
module.slack_bot_token.aws_secretsmanager_secret.secretsmanager_secret: Creation complete after 1s [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-bot-token-dev-1NXj8H]
module.lambda.data.aws_iam_policy_document.lambda_secret_manager_policy_document: Reading...
module.slack_bot_token.aws_secretsmanager_secret_version.secretmanager_secret_version: Creating...
module.lambda.data.aws_iam_policy_document.lambda_secret_manager_policy_document: Read complete after 0s [id=515532828]
module.lambda.aws_iam_role_policy.lambda_secret_manager_policy: Creating...
module.ecr.aws_ecr_repository.ecr_repository: Creation complete after 1s [id=lambda-bot-dev]
module.api_gateway.aws_cloudwatch_log_group.api_gateway: Creation complete after 1s [id=/aws/lambda/lambda-bot-dev-api-gateway]
module.lambda.aws_cloudwatch_log_group.lambda: Creation complete after 1s [id=/aws/lambda/lambda-bot-dev]
module.lambda.aws_lambda_function.lambda: Creating...
module.lambda.aws_iam_role_policy.lambda_secret_manager_policy: Creation complete after 0s [id=lambda-bot-dev-role:lambda-bot-dev-secret-manager-policy]
module.slack_bot_token.aws_secretsmanager_secret_version.secretmanager_secret_version: Creation complete after 1s [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-bot-token-dev-1NXj8H|terraform-20250524123833160800000005]
module.slack_signing_secret.aws_secretsmanager_secret_version.secretmanager_secret_version: Creation complete after 1s [id=arn:aws:secretsmanager:ap-northeast-1:061051222129:secret:slack-signing-secret-dev-1NXj8H|terraform-20250524123833157800000004]
module.api_gateway.aws_apigatewayv2_api.lambda_api: Creation complete after 2s [id=gm9f2o8qm9]
module.api_gateway.aws_apigatewayv2_stage.lambda_function_invoke_stage: Creating...
module.api_gateway.aws_apigatewayv2_stage.lambda_function_invoke_stage: Creation complete after 1s [id=$default]
module.lambda.aws_lambda_function.lambda: Still creating... [00m10s elapsed]
module.lambda.aws_lambda_function.lambda: Creation complete after 20s [id=lambda-bot-dev]
module.lambda.aws_lambda_alias.lambda: Creating...
module.lambda.aws_lambda_alias.lambda: Creation complete after 0s [id=arn:aws:lambda:ap-northeast-1:061051222129:function:lambda-bot-dev:dev]
module.api_gateway.aws_lambda_permission.allow_apigateway: Creating...
module.api_gateway.aws_apigatewayv2_integration.lambda_integration: Creating...
module.api_gateway.aws_lambda_permission.allow_apigateway: Creation complete after 1s [id=AllowInvokeFromApiGateway]
module.api_gateway.aws_apigatewayv2_integration.lambda_integration: Creation complete after 1s [id=3tqtjl4]
module.api_gateway.aws_apigatewayv2_route.lambda_function_route: Creating...
module.api_gateway.aws_apigatewayv2_route.lambda_function_route: Creation complete after 0s [id=eaug6as]

Apply complete! Resources: 17 added, 0 changed, 0 destroyed.

Outputs:

api_gateway_invoke_url = "https://gm9f2o8qm9.execute-api.ap-northeast-1.amazonaws.com/"

```

</details>

<!-- github-comment: {"Command":"apply","JobName":"terraform","PRNumber":16,"Program":"tfcmt","SHA1":"2406c8c4bb11402e429365bb25a1adb405e56cea","Vars":{},"WorkflowName":"Terraform Multi-Env CI"} -->
author_association: NONE