Releases: suzuki-shunsuke/tfcmt
v4.14.0
Pull Requests | Issues | v4.13.0...v4.14.0
Features
#1423 #1425 plan: Add the option -ignore-warning
We've Added the option -ignore-warning
to the tfcmt plan
command.
You can also configure this option in your configuration file.
terraform:
plan:
ignore_warning: true
By default, tfcmt emphasizes the warning of terraform plan
, and the option -skip-no-changes
is ignored if terraform plan
outputs warning.
This is because we think warning should not be ignored.
But actually we're aware that some users ignore warning normally and they feel warning is noisy.
In this case, it's desirable that tfcmt plan -skip-no-changes
doesn't post a comment even if warning is outputted.
So this pull request introduces a new option -ignore-warning
.
If terraform plan
outputs warning, this option makes the template variable .Warning
empty, removing the warning from the default template.
If terraform plan -skip-no-changes
has no change and outputs warning, this option disables to post a comment.
#1425 plan: Bind some environment variables to options
- TFCMT_PLAN_PATCH
- TFCMT_SKIP_NO_CHANGES
- TFCMT_IGNORE_WARNING
Others
#1417 Update Go 1.22.6 to 1.23.1
#1409 Create GitHub Artifact Attestations
https://github.com/suzuki-shunsuke/tfcmt/attestations
You can verify downloaded assets from GitHub Releases using GitHub CLI.
# Download assets from GitHub Releases.
gh release download -R suzuki-shunsuke/tfcmt v4.14.0 -p tfcmt_darwin_arm64.tar.gz
# Verify an asset.
gh attestation verify tfcmt_darwin_arm64.tar.gz \
-R suzuki-shunsuke/tfcmt \
--signer-workflow suzuki-shunsuke/go-release-workflow/.github/workflows/release.yaml
v4.14.0-1
v4.13.0
Pull Requests | Issues | v4.12.0...v4.13.0
Features
#1365 Update the template function wrapCode
to output the warning when the content is omitted
wrapCode
omits the content if it is too long.
#227 https://github.com/suzuki-shunsuke/tfcmt/releases/tag/v3.1.0
# ...
# ... The maximum length of GitHub Comment is 65536, so the content is omitted by tfcmt.
# ...
But this behaviour is a bit confusing.
This release updates wrapCode
to output the warning when the content is omitted.
v4.12.0
Pull Requests | Issues | v4.11.0...v4.12.0
Features
#1355 Get GitHub API endpoints from environment variables GITHUB_API_URL
and GITHUB_GRAPHQL_URL
in GitHub Actions
v4.11.0
Pull Requests | Issues | v4.10.0...v4.11.0
Features
#1336 #1339 Post comments to a pull request if the workflow run is triggered via GitHub Actions' merge_group event
Others
Update Go to 1.22.5
v4.11.0-1
v4.10.0
Pull Requests | Issues | v4.9.1...v4.10.0
Features
#1294 plan: Support disabling labels by a command line option and environment variable
Added a command line option -disable-label
and an environment variable TFCMT_DISABLE_LABEL
. If they are set, tfcmt plan
doesn't set labels.
tfcmt plan -disable-label -- terraform plan
export TFCMT_DISABLE_LABEL=true
tfcmt plan -- terraform plan
Fixes
#1295 validate if command is specified
tfcmt plan
and tfcmt apply
require command to be executed.
tfcmt plan -- terraform plan
tfcmt apply -- terraform apply
So this pull request adds a validation if command is specified.
If no command is specified, tfcmt plan and apply return an error immediately.
$ tfcmt plan
ERRO[0000] tfcmt failed error="no command specified"
Others
v4.9.1
Pull Requests | Issues | v4.9.0...v4.9.1
Fix
#1187 #1257 #1258 Exit commands with non zero exit code if any error such as API rate limit happens
This update changes the exit code of tfcmt when an error happens.
The exit code was same with the exit code of terraform plan
and terraform apply
.
This means tfcmt might have exited with zero even if tfcmt failed to post a comment due to some reason such as API rate limit.
This was not a bug but a expected behavior.
But this behaviour was dangerous because people might have missed unexpected changes.
So this update changes the behaviour as tfcmt exits with non zero if any error such as API rate limit happens.
v4.9.0
Pull Requests | Issues | v4.8.0...v4.9.0
Features
#1083 #1115 Support masking sensitive data
You can mask sensitive data in outputs of terraform.
This feature prevents the leak of sensitive data.
The following outputs are masked.
- Standard output of terraform command
- Standard error output of terraform command
- Pull request comment of
tfcmt plan
andtfcmt apply
- local files created by
--output
option
Caution
Even if you maske secrets using this feature, secrets are still stored in Terraform States.
Please see also Sensitive Data in State.
You can use environment variables TFCMT_MASKS
and TFCMT_MASKS_SEPARATOR
.
TFCMT_MASKS
: A list of masks. Masks are joined byTFCMT_MASKS_SEPARATOR
TFCMT_MASKS_SEPARATOR
: A separator of masks. The default value is,
The format of each mask is ${type}:${value}
.
${type}
must be either env
or regexp
.
If ${type}
is env
, ${value}
is a masked environment variable name.
If ${type}
is regexp
, ${value}
is a masked regular expression.
e.g. Mask GitHub access tokens and the environment variable DATADOG_API_KEY
.
export TFCMT_MASKS='env:GITHUB_TOKEN,env:DATADOG_API_KEY,regexp:ghp_[^ ]+'
tfcmt plan -- terraform plan
e.g. Change the separator to /
.
export TFCMT_MASKS_SEPARATOR=/
export TFCMT_MASKS='env:GITHUB_TOKEN/env:DATADOG_API_KEY/regexp:ghp_[^ ]+'
All matching strings are replaced with ***
.
Replacements are done in order of TFCMT_MASKS
, so the result depends on the order of TFCMT_MASKS
.
For example, if TFCMT_MASKS
is regexp:foo,regexp:foo.*
, regexp:foo.*
has no meaning because all foo
are replaced with ***
before replacing foo.*
with ***
so foo.*
doesn't match with anything.
Example
This example creates a resource google_cloudbuild_trigger.
This resource has a GitHub Access token as a field substitutions._GH_TOKEN
.
main.tf
resource "google_cloudbuild_trigger" "filename_trigger" {
location = "us-central1"
trigger_template {
branch_name = "main"
repo_name = "my-repo"
}
substitutions = {
_GH_TOKEN = var.gh_token # Secret
}
filename = "cloudbuild.yaml"
}
variable "gh_token" {
type = string
description = "GitHub Access token"
}
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "5.13.0"
}
}
}
If you run terraform plan
without masking, the secret would be leaked.
To prevent the leak, let's mask the secret.
export TFCMT_MASKS=env:TF_VAR_gh_token # Mask the environment variable TF_VAR_gh_token
Please see _GH_TOKEN
in the output of tfcmt plan
and the pull request comment.
You can confirm _GH_TOKEN
is masked as ***
properly.
$ tfcmt plan -- terraform plan
tfcmt plan -- terraform plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_cloudbuild_trigger.filename_trigger will be created
+ resource "google_cloudbuild_trigger" "filename_trigger" {
+ create_time = (known after apply)
+ filename = "cloudbuild.yaml"
+ id = (known after apply)
+ location = "us-central1"
+ name = (known after apply)
+ project = "hello"
+ substitutions = {
+ "_GH_TOKEN" = "***"
}
+ trigger_id = (known after apply)
+ trigger_template {
+ branch_name = "main"
+ project_id = (known after apply)
+ repo_name = "my-repo"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.
Terraform sensitive input variables and outputs and sensitive function
Terraform itself has features to prevent sensitive data from being leaked.
- https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables
- https://developer.hashicorp.com/terraform/language/functions/sensitive
- https://developer.hashicorp.com/terraform/language/values/outputs#sensitive-suppressing-values-in-cli-output
- https://developer.hashicorp.com/terraform/language/values/variables#suppressing-values-in-cli-output
- https://www.hashicorp.com/blog/terraform-0-14-adds-the-ability-to-redact-sensitive-values-in-console-output
- https://www.hashicorp.com/blog/announcing-hashicorp-terraform-0-15-general-availability
So first you should use these features.
But even if these features are available, it still makes sense for tfcmt to mask sensitive data.
Please imagine the situation that platform engineers manage Terraform workflows and product teams manage Terraform codes in a Monorepo.
Then platform engineers need to prevent sensitive data from being leaked, but if product teams forget to protect them with sensitive
flags, sensitive data would be leaked.
By protecting sensitive data using tfcmt, platform engineers can prevent sensitive data from being leaked while delegating the management of Terraform codes to product teams.
tfcmt's masking feature works as a guardrail.
v4.9.0-2
Changes from v4.9.0-1
56dfca4 fix(mask): Change the default separator from ;
to ,
Features
#1083 #1115 support masking secrets
You can mask secrets in outputs of terraform.
This feature prevents the leak of secrets.
The following outputs are masked.
- Standard output of terraform command
- Standard error output of terraform command
- Pull request comment of
tfcmt plan
andtfcmt apply
- local files created by
--output
option
Caution
Even if you maske secrets using this feature, secrets are still stored in Terraform States.
Please see also Sensitive Data in State.
You can use environment variables TFCMT_MASKS
and TFCMT_MASKS_SEPARATOR
.
TFCMT_MASKS
: A list of masks. Masks are joined byTFCMT_MASKS_SEPARATOR
TFCMT_MASKS_SEPARATOR
: A separator of masks. The default value is,
The format of each mask is ${type}:${value}
.
${type}
must be either env
or regexp
.
If ${type}
is env
, ${value}
is a masked environment variable name.
If ${type}
is regexp
, ${value}
is a masked regular expression.
e.g. Mask GitHub access tokens and the environment variable DATADOG_API_KEY
.
export TFCMT_MASKS="env:GITHUB_TOKEN,env:DATADOG_API_KEY,regexp:ghp_[^ ]+"
tfcmt plan -- terraform plan
e.g. Change the separator to /
.
export TFCMT_MASKS_SEPARATOR=/
export TFCMT_MASKS="env:GITHUB_TOKEN/env:DATADOG_API_KEY/regexp:ghp_[^ ]+"
All matching strings are replaced with ***
.
Replacements are done in order of TFCMT_MASKS
, so the result depends on the order of TFCMT_MASKS
.
For example, if TFCMT_MASKS
is regexp:foo,regexp:foo.*
, regexp:foo.*
has no meaning because all foo
are replaced with ***
before replacing foo.*
with ***
so foo.*
doesn't match with anything.
Example
This example creates a resource google_cloudbuild_trigger.
This resource has a GitHub Access token as a field substitutions._GH_TOKEN
.
main.tf
resource "google_cloudbuild_trigger" "filename_trigger" {
location = "us-central1"
trigger_template {
branch_name = "main"
repo_name = "my-repo"
}
substitutions = {
_GH_TOKEN = var.gh_token # Secret
}
filename = "cloudbuild.yaml"
}
variable "gh_token" {
type = string
description = "GitHub Access token"
}
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "5.13.0"
}
}
}
If you run terraform plan
without masking, the secret would be leaked.
To prevent the leak, let's mask the secret.
export TFCMT_MASKS=env:TF_VAR_gh_token # Mask the environment variable TF_VAR_gh_token
Please see _GH_TOKEN
in the output of tfcmt plan
and the pull request comment.
You can confirm _GH_TOKEN
is masked as ***
properly.
$ tfcmt plan -- terraform plan
tfcmt plan -- terraform plan
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# google_cloudbuild_trigger.filename_trigger will be created
+ resource "google_cloudbuild_trigger" "filename_trigger" {
+ create_time = (known after apply)
+ filename = "cloudbuild.yaml"
+ id = (known after apply)
+ location = "us-central1"
+ name = (known after apply)
+ project = "hello"
+ substitutions = {
+ "_GH_TOKEN" = "***"
}
+ trigger_id = (known after apply)
+ trigger_template {
+ branch_name = "main"
+ project_id = (known after apply)
+ repo_name = "my-repo"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
─────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.