Terraform の external data sourceでbashスクリプトを実行しようとしてハマった

# 環境
- Terraform 1.7.4
- Terragrunt 0.55.1
- hashicorp/aws 5.36.0
- hashicorp/external 2.3.3
- WSL2(Ubuntu)

# 経緯
TerraformでLambda関数をデプロイするためにpnpmのプロジェクトをtfファイルと同一階層に配置し、apply時にトランスパイルや不要ファイルの削除を行いzip化しようとしていた
そのためにexternal data sourceやarchive_file data sourceを利用していたのだが、なぜかbashファイルの実行に失敗するという現象でハマってしまった

# ディレクトリ構成
.
├── bin
│   └── build.sh
├── lambda
│   ├── index.ts
│   ├── jest.config.js
│   ├── node_modules
│   ├── package.json
│   ├── pnpm-lock.yaml
│   ├── tests
│   │   └── index.spec.ts
│   └── tsconfig.json
└── lambda.tf

※記事の趣旨と関係のないファイルは除外しています

```terraform:lambda.tf
data "external" "tmp" {
  program = ["./bin/build.sh"]
}

data "archive_file" "lambda_src" {
  depends_on = [data.external.tmp]

  type        = "zip"
  source_dir  = "./tmp"
  output_path = "./lambda.zip"
}

resource "aws_lambda_function" "main" {
  depends_on = [data.archive_file.lambda_src]

  filename         = data.archive_file.lambda_src.output_path
  function_name    = "foo"
  role             = "bar"
  handler          = "index.lambdaHandler"
  runtime          = "nodejs20.x"
  source_code_hash = data.archive_file.lambda_src.output_base64sha256
}
```

```bash:build.sh
#!/bin/bash

# 前回実行時の一時ファイル等が残っていた場合に削除
if [ -d ./tmp ]; then
  rm -rf ./tmp
fi
if [ -f ./lambda.zip ]; then
  rm ./lambda.zip
fi

# pnpmのプロジェクトがあるディレクトリをコピー
cp -r ./lambda ./tmp
cd ./tmp

# jsへトランスパイル
tsc index.ts

# 本番環境で不要になるファイルの削除
rm -rf node_modules tests jest.config.js index.ts tsconfig.json

# 本番環境用のnode_modulesを取得
pnpm install --prod

exit 0
```

# エラー
上記の状態で`terragrunt apply`したところ以下のようなエラーが発生

```
│ The data source received unexpected results after executing the program.
│ 
│ Program output must be a JSON encoded map of string keys and string values.
│ 
│ If the error is unclear, the output can be viewed by enabling Terraform's
│ logging at TRACE level. Terraform documentation on logging:
│ https://www.terraform.io/internals/debugging
│ 
│ Program: ./bin/build.sh
│ Result Error: invalid character 'L' looking for beginning of value
```

# 解決方法
build.shを以下のように修正したところ問題なく実行された
修正点としては以下の２点
- `pnpm install`でsilentオプションを設定
- `echo '{}'`でjson形式の文字列を出力

```bash:build.sh
#!/bin/bash

# 前回実行時の一時ファイル等が残っていた場合に削除
if [ -d ./tmp ]; then
  rm -rf ./tmp
fi
if [ -f ./lambda.zip ]; then
  rm ./lambda.zip
fi

# pnpmのプロジェクトがあるディレクトリをコピー
cp -r ./lambda ./tmp
cd ./tmp

# jsへトランスパイル
tsc index.ts

# 本番環境で不要になるファイルの削除
rm -rf node_modules tests jest.config.js index.ts tsconfig.json

# 本番環境用のnode_modulesを取得
pnpm install --prod --silent # silentオプションで標準出力を防止

# json形式のoutputを出力
echo '{}'
exit 0
```

# 結論
[公式](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external#external-program-protocol)にちゃんと書いてありました。。。
公式はしっかり読むべき(N回目)

>The program must then produce a valid JSON object on stdout, which will be used to populate the result attribute exported to the rest of the Terraform configuration. This JSON object must again have all of its values as strings. On successful completion it must exit with status zero.
If the program encounters an error and is unable to produce a result, it must print a human-readable error message (ideally a single line) to stderr and exit with a non-zero status. Any data on stdout is ignored if the program returns a non-zero status.