@exabugs/dynamodb-client 1.19.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/bin/dynamodb-system-change.js +6 -0
  4. package/dist/server/handler.cjs +3 -3
  5. package/dist/server/media-handler.cjs +2 -2
  6. package/dist/server/media-process-handler-dlq.cjs +2 -2
  7. package/dist/server/media-process-handler.cjs +2 -2
  8. package/dist/tools/dynamodb-system-change/cli.d.ts +35 -0
  9. package/dist/tools/dynamodb-system-change/cli.d.ts.map +1 -0
  10. package/dist/tools/dynamodb-system-change/cli.js +226 -0
  11. package/dist/tools/dynamodb-system-change/cli.js.map +1 -0
  12. package/dist/tools/dynamodb-system-change/details.d.ts +42 -0
  13. package/dist/tools/dynamodb-system-change/details.d.ts.map +1 -0
  14. package/dist/tools/dynamodb-system-change/details.js +59 -0
  15. package/dist/tools/dynamodb-system-change/details.js.map +1 -0
  16. package/dist/tools/dynamodb-system-change/index.d.ts +13 -0
  17. package/dist/tools/dynamodb-system-change/index.d.ts.map +1 -0
  18. package/dist/tools/dynamodb-system-change/index.js +9 -0
  19. package/dist/tools/dynamodb-system-change/index.js.map +1 -0
  20. package/dist/tools/dynamodb-system-change/releases.d.ts +34 -0
  21. package/dist/tools/dynamodb-system-change/releases.d.ts.map +1 -0
  22. package/dist/tools/dynamodb-system-change/releases.js +108 -0
  23. package/dist/tools/dynamodb-system-change/releases.js.map +1 -0
  24. package/dist/tools/dynamodb-system-change/run.d.ts +2 -0
  25. package/dist/tools/dynamodb-system-change/run.d.ts.map +1 -0
  26. package/dist/tools/dynamodb-system-change/run.js +6 -0
  27. package/dist/tools/dynamodb-system-change/run.js.map +1 -0
  28. package/dist/tools/dynamodb-system-change/send.d.ts +43 -0
  29. package/dist/tools/dynamodb-system-change/send.d.ts.map +1 -0
  30. package/dist/tools/dynamodb-system-change/send.js +97 -0
  31. package/dist/tools/dynamodb-system-change/send.js.map +1 -0
  32. package/docs/DYNAMODB_ACCESS.md +1 -1
  33. package/docs/NOTIFY.md +2 -2
  34. package/docs/SYSTEM_CHANGES.md +68 -1
  35. package/package.json +7 -2
  36. package/terraform/README.md +9 -0
  37. package/terraform/alerts-cleanup/README.md +65 -0
  38. package/terraform/alerts-cleanup/main.tf +111 -0
  39. package/terraform/alerts-cleanup/outputs.tf +14 -0
  40. package/terraform/alerts-cleanup/variables.tf +42 -0
  41. package/terraform/alerts-cleanup/versions.tf +16 -0
  42. package/terraform/ops-notify/README.md +109 -0
  43. package/terraform/ops-notify/main.tf +295 -0
  44. package/terraform/ops-notify/outputs.tf +19 -0
  45. package/terraform/ops-notify/us-east-1.tf +68 -0
  46. package/terraform/ops-notify/variables.tf +105 -0
  47. package/terraform/ops-notify/versions.tf +18 -0
  48. package/terraform/system-change-recorder/README.md +71 -0
  49. package/terraform/system-change-recorder/main.tf +122 -0
  50. package/terraform/system-change-recorder/outputs.tf +14 -0
  51. package/terraform/system-change-recorder/variables.tf +53 -0
  52. package/terraform/system-change-recorder/versions.tf +16 -0
@@ -0,0 +1,18 @@
1
+ # provider の版: astro(5.x)と asanowa(6.x)の両方で使う。
2
+ # 下限は Lambda の logging_config(5.x の途中で追加)。上限は data.aws_region の name(6.x で非推奨)が消える 7.x の前まで
3
+ terraform {
4
+ required_version = ">= 1.5"
5
+
6
+ required_providers {
7
+ aws = {
8
+ source = "hashicorp/aws"
9
+ version = ">= 5.30, < 7.0"
10
+ # us-east-1 のアラームの転送(us-east-1.tf)。呼び出し側は providers = { aws.us_east_1 = aws.us_east_1 } を常に渡す
11
+ configuration_aliases = [aws.us_east_1]
12
+ }
13
+ archive = {
14
+ source = "hashicorp/archive"
15
+ version = ">= 2.0"
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,71 @@
1
+ # システム変更履歴の記録 Lambda Terraformモジュール
2
+
3
+ ADR 0006 の (b)(1.21.0)。asanowa・astro の `infra/modules/system-change-recorder` を 1 つにしたもの。使い方の詳細は [docs/SYSTEM_CHANGES.md](../../docs/SYSTEM_CHANGES.md)。
4
+
5
+ ## 作るもの
6
+
7
+ - Lambda `<project>-<env>-system-change-recorder`(Node.js 22、arm64、15 秒、256 MB。構造化ログ JSON)と、そのロググループ・実行ロール
8
+ - 権限: Records の IAM 版 URL の呼び出し(`lambda:InvokeFunctionUrl`)、Slack の webhook のパラメータの読み取り(`slack_webhook_param_name` があるときだけ)。DynamoDB には直接触れない
9
+ - 非同期の呼び出しの再試行 0(同じ入力の再試行は、同じ変更が 2 件になる)
10
+ - 作らないもの: Function URL・EventBridge・`aws_lambda_permission`(呼び出しは人・CI の AWS の認証。`dynamodb-system-change` の CLI)
11
+
12
+ ## 前提
13
+
14
+ - 参照は `node_modules` のパス(版は npm の版で固定される。git の `ref` ではない)。例: アプリの infra が `infra/` なら `source = "../node_modules/@exabugs/dynamodb-client/terraform/system-change-recorder"`、`infra/apps/<app>/` なら `"../../../node_modules/..."`
15
+ - **Lambda の成果物はアプリが作り、`source_file`(バンドル済みの 1 ファイル)と `handler` で渡す**。エントリはアプリの数行(`createSystemChangeHandler`。アプリ名や、権限チェック層を通すアプリの包み方を渡す)なので、ライブラリの dist は使わない
16
+ - zip は `${path.root}/.terraform/archives/system-change-recorder.zip` に作る(`path.module` を使わない。pnpm の版つきのパスが state に入ると、版を上げるたびに差分が出るため)
17
+ - pnpm では、版を上げた後に `.terraform/modules` を消してから `terraform init` する([../README.md](../README.md) の注意)
18
+ - モジュール全体の `depends_on` は使わない(依存先に変更があると、中のデータソースが apply 時の読み取りになり、既存のリソースが作り直しになる)。依存は、出力の値(`log_group_name` など)で渡す
19
+
20
+ ## 使い方
21
+
22
+ ```hcl
23
+ module "system_change_recorder" {
24
+ source = "../node_modules/@exabugs/dynamodb-client/terraform/system-change-recorder"
25
+
26
+ project_name = var.project_name
27
+ environment = var.environment
28
+ records_iam_function_url = module.records.iam_function_url
29
+ records_iam_alias_arn = module.records.iam_alias_arn
30
+ log_retention_days = var.log_retention_days
31
+
32
+ # アプリのバンドル(エントリは createSystemChangeHandler の数行)
33
+ source_file = "${path.root}/../apps/server/dist/system-change-recorder.cjs"
34
+ handler = "system-change-recorder.handler"
35
+
36
+ slack_webhook_param_name = "/${var.project_name}/${var.environment}/ops/slack-webhook"
37
+ admin_base_url = var.ops_admin_base_url
38
+ }
39
+ ```
40
+
41
+ ## 変数
42
+
43
+ | 変数 | 既定 | 説明 |
44
+ | ---------------------------------------------------- | ------- | ----------------------------------------------------------------------------- |
45
+ | `project_name` / `environment` | 必須 | 名前の接頭辞 `<project>-<env>`。環境変数 `PROJECT_NAME` / `ENV_NAME` |
46
+ | `records_iam_function_url` / `records_iam_alias_arn` | 必須 | Records の IAM 版 Function URL と、そのエイリアスの ARN(呼び出し権限の対象) |
47
+ | `source_file` / `handler` | 必須 | アプリのバンドル(1 ファイル)と、ハンドラ |
48
+ | `log_retention_days` | 7 | ロググループの保持日数 |
49
+ | `slack_webhook_param_name` | `""` | Slack の webhook の SSM パラメータ名(SecureString)。空なら Slack に送らない |
50
+ | `admin_base_url` | `""` | 管理画面の URL(Slack の通知に詳細のリンクを付ける) |
51
+ | `notify_started` | `false` | 「開始」も Slack に送るか |
52
+
53
+ ## 出力
54
+
55
+ `function_name`(CLI の `--function` の既定と同じ名前)、`function_arn`、`log_group_name`(ops-notify に購読させる)
56
+
57
+ ## アプリに残るもの
58
+
59
+ - 上の module ブロック(`source`・`source_file`・`handler` と設定の値)
60
+ - Lambda のエントリ(`createSystemChangeHandler` を呼ぶ数行)とバンドルの作成(esbuild など)
61
+ - 秘密(webhook の URL など)の SSM パラメータの作成
62
+
63
+ ## アプリのモジュールからの移行(置き換えを起こさない)
64
+
65
+ リソースのアドレス・名前は、asanowa / astro の旧モジュール(`infra/modules/system-change-recorder`)と同じ。**module ブロックの名前(`module "system_change_recorder"`)を変えずに `source` だけを差し替え**、`source_file`・`handler` を足す。アドレスが変わらないので `moved` は要らない(ラッパーのモジュールで包むと、アドレスが変わり `moved` が要る)。
66
+
67
+ 1. `terraform init`(モジュールの取り直し)→ `terraform plan`
68
+ 2. **0 to add / 0 to destroy、`must be replaced` が無い**ことを確かめる。出てよいのは in-place の更新だけ(文言の差。asanowa / astro では Lambda の description の ADR の番号が消える)
69
+ 3. 確認のうえ apply。旧モジュールのディレクトリを消す
70
+
71
+ 詳細と実機の確認は [ADR 0006](../../docs/adr/0006-library-owns-table-operations.md) の段階 6。
@@ -0,0 +1,122 @@
1
+ # システム変更履歴(systemChanges)の記録 Lambda(ADR 0006 の (b)。docs/SYSTEM_CHANGES.md)
2
+ #
3
+ # 入力(直接呼び出し)を検証し、Records の IAM URL で systemChanges に書く(削除しない)。
4
+ # Lambda の成果物(バンドル済みの 1 ファイル)はアプリが作り、source_file で渡す(エントリでアプリの設定・
5
+ # 権限チェック層を渡すため。実装は `createSystemChangeHandler`)。
6
+ #
7
+ # 呼び出しは、人・CI の AWS の認証(lambda:InvokeFunction)で行う。Function URL・EventBridge・
8
+ # リソースベースのポリシー(aws_lambda_permission)は作らない。
9
+ # 失敗は構造化ログ(warn / error)に出す。このロググループは、通知(../ops-notify)に購読させる。
10
+ #
11
+ # リソースのアドレス・名前は、asanowa / astro の旧モジュール(infra/modules/system-change-recorder)と同じ
12
+ # (module ブロックの名前を変えずに source だけを差し替えれば、moved なしで置き換えが起きない)。
13
+
14
+ locals {
15
+ prefix = "${var.project_name}-${var.environment}"
16
+ }
17
+
18
+ data "aws_caller_identity" "current" {}
19
+ data "aws_region" "current" {}
20
+
21
+ data "archive_file" "recorder" {
22
+ type = "zip"
23
+ source_file = var.source_file
24
+ output_path = "${path.root}/.terraform/archives/system-change-recorder.zip"
25
+ }
26
+
27
+ resource "aws_cloudwatch_log_group" "recorder" {
28
+ name = "/aws/lambda/${local.prefix}-system-change-recorder"
29
+ retention_in_days = var.log_retention_days
30
+ }
31
+
32
+ resource "aws_iam_role" "recorder" {
33
+ name = "${local.prefix}-system-change-recorder-role"
34
+
35
+ assume_role_policy = jsonencode({
36
+ Version = "2012-10-17"
37
+ Statement = [{
38
+ Action = "sts:AssumeRole"
39
+ Effect = "Allow"
40
+ Principal = { Service = "lambda.amazonaws.com" }
41
+ }]
42
+ })
43
+ }
44
+
45
+ resource "aws_iam_role_policy_attachment" "recorder_logs" {
46
+ role = aws_iam_role.recorder.name
47
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
48
+ }
49
+
50
+ # Records Lambda の IAM 認証版 URL(エイリアス)を呼ぶ権限だけ(最小権限)。DynamoDB には直接触れない
51
+ resource "aws_iam_role_policy" "recorder_invoke_records" {
52
+ name = "${local.prefix}-system-change-recorder-invoke-records"
53
+ role = aws_iam_role.recorder.id
54
+
55
+ policy = jsonencode({
56
+ Version = "2012-10-17"
57
+ Statement = [{
58
+ Effect = "Allow"
59
+ Action = ["lambda:InvokeFunctionUrl"]
60
+ Resource = [var.records_iam_alias_arn]
61
+ }]
62
+ })
63
+ }
64
+
65
+ # Slack の webhook(SecureString)を読む権限だけ。通知 Lambda と同じ(暗号化は、AWS 管理の鍵で、追加の KMS 権限は不要。PoC で確認)
66
+ resource "aws_iam_role_policy" "recorder_read_slack_webhook" {
67
+ count = var.slack_webhook_param_name == "" ? 0 : 1
68
+ name = "${local.prefix}-system-change-recorder-read-slack-webhook"
69
+ role = aws_iam_role.recorder.id
70
+
71
+ policy = jsonencode({
72
+ Version = "2012-10-17"
73
+ Statement = [{
74
+ Effect = "Allow"
75
+ Action = ["ssm:GetParameter"]
76
+ Resource = ["arn:aws:ssm:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:parameter${var.slack_webhook_param_name}"]
77
+ }]
78
+ })
79
+ }
80
+
81
+ resource "aws_lambda_function" "recorder" {
82
+ function_name = "${local.prefix}-system-change-recorder"
83
+ description = "Record a system change (release, OTA, infra, Lambda) to the systemChanges records"
84
+ role = aws_iam_role.recorder.arn
85
+ filename = data.archive_file.recorder.output_path
86
+ source_code_hash = data.archive_file.recorder.output_base64sha256
87
+ handler = var.handler
88
+ runtime = "nodejs22.x"
89
+ architectures = ["arm64"]
90
+ # HTTP の時間切れ(RECORD_HTTP_TIMEOUT_MS = 5 秒)より長く
91
+ timeout = 15
92
+ memory_size = 256
93
+
94
+ environment {
95
+ variables = merge(
96
+ {
97
+ PROJECT_NAME = var.project_name
98
+ ENV_NAME = var.environment
99
+ RECORDS_IAM_URL = var.records_iam_function_url
100
+ },
101
+ var.slack_webhook_param_name == "" ? {} : {
102
+ SLACK_WEBHOOK_PARAM = var.slack_webhook_param_name
103
+ NOTIFY_STARTED = tostring(var.notify_started)
104
+ },
105
+ var.admin_base_url == "" ? {} : { ADMIN_BASE_URL = var.admin_base_url },
106
+ )
107
+ }
108
+
109
+ logging_config {
110
+ log_format = "JSON"
111
+ log_group = aws_cloudwatch_log_group.recorder.name
112
+ }
113
+
114
+ depends_on = [aws_iam_role_policy_attachment.recorder_logs]
115
+ }
116
+
117
+ # 非同期の呼び出し(--invocation-type Event)の再試行は 0
118
+ # (同じ入力の再試行は、同じ変更が 2 件になる。失敗はログ → 通知で知る)
119
+ resource "aws_lambda_function_event_invoke_config" "recorder" {
120
+ function_name = aws_lambda_function.recorder.function_name
121
+ maximum_retry_attempts = 0
122
+ }
@@ -0,0 +1,14 @@
1
+ output "function_name" {
2
+ description = "システム変更履歴の記録 Lambda の関数名(aws lambda invoke で呼ぶ)"
3
+ value = aws_lambda_function.recorder.function_name
4
+ }
5
+
6
+ output "function_arn" {
7
+ description = "システム変更履歴の記録 Lambda の ARN"
8
+ value = aws_lambda_function.recorder.arn
9
+ }
10
+
11
+ output "log_group_name" {
12
+ description = "システム変更履歴の記録 Lambda のロググループ名(通知 Lambda が購読する)"
13
+ value = aws_cloudwatch_log_group.recorder.name
14
+ }
@@ -0,0 +1,53 @@
1
+ variable "project_name" {
2
+ description = "プロジェクト名"
3
+ type = string
4
+ }
5
+
6
+ variable "environment" {
7
+ description = "環境識別子(dev, prd)"
8
+ type = string
9
+ }
10
+
11
+ variable "records_iam_function_url" {
12
+ description = "Records Lambda の AWS_IAM 認証版 Function URL(systemChanges に書く)"
13
+ type = string
14
+ }
15
+
16
+ variable "records_iam_alias_arn" {
17
+ description = "Records Lambda の IAM 認証用エイリアスの ARN(lambda:InvokeFunctionUrl の Resource)"
18
+ type = string
19
+ }
20
+
21
+ variable "log_retention_days" {
22
+ description = "CloudWatch Logsの保持期間(日数)"
23
+ type = number
24
+ default = 7
25
+ }
26
+
27
+ variable "slack_webhook_param_name" {
28
+ description = "Slack の webhook の SSM パラメータ名(SecureString。通知 Lambda と同じもの)。空なら、Slack に送らない"
29
+ type = string
30
+ default = ""
31
+ }
32
+
33
+ variable "admin_base_url" {
34
+ description = "管理画面の URL(Slack の通知に、システム変更履歴の詳細へのリンクを付ける)。空ならリンクを付けない"
35
+ type = string
36
+ default = ""
37
+ }
38
+
39
+ variable "notify_started" {
40
+ description = "「開始」も Slack に送るか。既定は false(1 回の適用で 2 通になるため。結果だけを送る)"
41
+ type = bool
42
+ default = false
43
+ }
44
+
45
+ variable "source_file" {
46
+ description = "Lambda の成果物(バンドル済みの 1 ファイル。例: apps/server/dist/system-change-recorder.cjs)。zip にして使う"
47
+ type = string
48
+ }
49
+
50
+ variable "handler" {
51
+ description = "Lambda のハンドラ(例: system-change-recorder.handler)"
52
+ type = string
53
+ }
@@ -0,0 +1,16 @@
1
+ # provider の版: astro(5.x)と asanowa(6.x)の両方で使う。
2
+ # 下限は Lambda の logging_config(5.x の途中で追加)。上限は data.aws_region の name(6.x で非推奨)が消える 7.x の前まで
3
+ terraform {
4
+ required_version = ">= 1.5"
5
+
6
+ required_providers {
7
+ aws = {
8
+ source = "hashicorp/aws"
9
+ version = ">= 5.30, < 7.0"
10
+ }
11
+ archive = {
12
+ source = "hashicorp/archive"
13
+ version = ">= 2.0"
14
+ }
15
+ }
16
+ }