Skip to content

Conversation

@yhakbar
Copy link
Collaborator

@yhakbar yhakbar commented Sep 9, 2025

Description

Upgrades to the latest version of Boilerplate.

Also adds --no-shell and --no-hooks to control the relevant settings in Boilerplate.

TODOs

Read the Gruntwork contribution guidelines.

  • I authored this code entirely myself
  • I am submitting code based on open source software (e.g. MIT, MPL-2.0, Apache)]
  • I am adding or upgrading a dependency or adapted code and confirm it has a compatible open source license
  • Update the docs.
  • Run the relevant tests successfully, including pre-commit checks.
  • Include release notes. If this PR is backward incompatible, include a migration guide.

Release Notes (draft)

Added / Removed / Updated [X].

Migration Guide

Summary by CodeRabbit

Release Notes

  • New Features
    • Added --no-shell and --no-hooks flags to scaffold and catalog commands for controlling template execution behavior.
    • Catalog configurations now support no_shell and no_hooks optional settings, with CLI flags taking priority.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 9, 2025

📝 Walkthrough

Walkthrough

The PR consolidates scaffold-related flag definitions into a shared module, introduces NoShell and NoHooks security options for both catalog and scaffold commands with CLI-flag-takes-precedence semantics, and refactors scaffold implementation to thread TerragruntOptions throughout helper functions while maintaining backward compatibility.

Changes

Cohort / File(s) Summary
Shared flag infrastructure
cli/flags/shared/shared.go, cli/commands/catalog/cli.go, cli/commands/scaffold/cli.go
Introduces NewScaffoldingFlags() function and public constants (RootFileNameFlagName, NoIncludeRootFlagName, NoShellFlagName, NoHooksFlagName) with validation logic. Updates catalog and scaffold CLI commands to use shared scaffolding flags instead of inline definitions.
Scaffold command refactoring
cli/commands/scaffold/scaffold.go
Adds NewBoilerplateOptions() constructor and applyCatalogConfigToScaffold() to merge catalog config into scaffold behavior (with CLI flags taking precedence). Refactors Run() and helper functions (downloadTemplate, prepareBoilerplateFiles, parseVariables, parseModuleURL, rewriteModuleURL, rewriteTemplateURL, addRefToModuleURL) to accept TerragruntOptions parameter. Updates references to flag names to use shared constants.
Scaffold testing
cli/commands/scaffold/scaffold_test.go
Adds newTestBoilerplateOptions() helper and comprehensive test coverage for catalog config application, catalog config parsing, shell template function behavior, and hooks execution (TestCatalogConfigApplication, TestCatalogConfigParsing, TestBoilerplateShellTemplateFunctionDisabled/Enabled, TestBoilerplateHooksDisabled/Enabled, etc.).
Configuration model updates
config/catalog.go, config/config.go, options/options.go
Adds NoShell and NoHooks boolean fields to CatalogConfig struct; updates CatalogConfig.WriteTo() and String() methods. Adds NoShell and NoHooks boolean fields to TerragruntOptions struct with default false initialization.
Test fixtures
test/fixtures/scaffold/catalog-config-test/terragrunt.hcl, test/fixtures/scaffold/with-shell-and-hooks/.../*, test/fixtures/scaffold/with-hooks/.../*, test/fixtures/scaffold/with-shell-commands/.../*
Adds terragrunt.hcl config fixture with catalog rules; adds boilerplate template directories with hooks (before/after echo commands), shell template functions, and corresponding Terraform modules for integration testing.
Integration tests
test/integration_scaffold_test.go, test/integration_parse_test.go
Adds integration tests validating shell commands and hooks behavior (enabled/disabled individually and combined) and catalog config integration. Updates knownBadFiles list with new boilerplate template fixtures.
Documentation
docs-starlight/src/content/docs/03-features/06-catalog.mdx, docs-starlight/src/data/commands/catalog.mdx, docs-starlight/src/data/commands/scaffold.mdx, docs-starlight/src/data/flags/catalog-no-shell.mdx, docs-starlight/src/data/flags/catalog-no-hooks.mdx, docs-starlight/src/data/flags/scaffold-no-shell.mdx, docs-starlight/src/data/flags/scaffold-no-hooks.mdx
Adds Security Configuration section documenting no_shell and no_hooks options with CLI/catalog/default precedence clarification. Documents new flags with environment variable bindings (TG_NO_SHELL, TG_NO_HOOKS) and usage examples.
Dependencies
go.mod
Bumps numerous dependency versions: boilerplate v0.8.1 → v0.10.1, AWS SDK v2 components (v1.39.2 → v1.39.3 + transitive updates), google.golang.org/api v0.252.0 → v0.253.0, and various other indirect dependencies.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Command
    participant Run as scaffold.Run()
    participant CatalogMerge as applyCatalogConfigToScaffold()
    participant Opts as TerragruntOptions
    participant BoilerplateOpts as BoilerplateOptions

    CLI->>Run: scaffold module-url<br/>(with --no-shell, --no-hooks)
    activate Run
    Note over Run: TerragruntOptions flags set<br/>from CLI args
    
    Run->>CatalogMerge: apply catalog config
    activate CatalogMerge
    Note over CatalogMerge: Read catalog.no_shell,<br/>catalog.no_hooks
    
    alt CLI flags already set
        CatalogMerge->>Opts: Skip (CLI takes precedence)
    else CLI flags not set (default false)
        CatalogMerge->>Opts: Apply catalog config values
    end
    deactivate CatalogMerge
    
    Run->>BoilerplateOpts: NewBoilerplateOptions()<br/>with Opts.NoShell, Opts.NoHooks
    activate BoilerplateOpts
    Note over BoilerplateOpts: Final config with<br/>precedence resolved
    deactivate BoilerplateOpts
    
    Note over Run: Process template with<br/>shell/hooks disabled if needed
    deactivate Run
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

The changes span multiple architectural layers (flags, config, options, implementation) with consistent patterns (threading opts parameter across functions). While individual changes are straightforward, the breadth across many files and the need to verify correct precedence logic (CLI > catalog > defaults) and proper opts threading throughout the call chain requires careful, deliberate review.

Possibly related PRs

Suggested reviewers

  • denis256
  • wakeful

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The pull request title "chore: Bumping boilerplate" refers to a real component change present in the changeset (boilerplate dependency upgraded from v0.8.1 to v0.10.1 in go.mod). However, examining the raw_summary reveals that this PR encompasses substantially more than a simple dependency bump: it introduces new security-related CLI flags (no-shell, no-hooks), adds significant refactoring across multiple command modules, includes new exported functions and configuration fields, provides extensive documentation updates, and adds multiple integration tests. The title fails to capture these substantial changes and would mislead developers scanning the commit history into believing this is merely maintenance work, when the primary purpose appears to be implementing new security configuration options for scaffold and catalog commands. While the boilerplate bump is necessary to support these features, the title does not adequately represent the scope and main intent of the changeset.
Description Check ⚠️ Warning The PR description is largely incomplete and fails to meet the template requirements. The main description section contains only a single vague sentence: "Upgrades to the latest version of Boilerplate." without explaining what specifically changed, which new features were added, why substantial refactoring occurred across multiple modules, or how the changes affect user-facing behavior. Additionally, the release notes section remains unfilled with only the placeholder text "Added / Removed / Updated [X]", and there is no migration guide content provided despite the extensive API changes visible in the raw_summary (new exported functions, modified signatures, new configuration fields, new CLI flags). The description must be substantially expanded to explain the actual changes made by this PR. It should detail: (1) what new features are being introduced (no-shell and no-hooks flags), (2) the purpose of these additions (security/safety during scaffolding), (3) a summary of the refactoring across command modules and flag handling, (4) any breaking changes or migration guidance needed, and (5) concrete, specific release notes rather than placeholder text. This will help reviewers understand the scope and ensure appropriate testing and documentation coverage.
Docstring Coverage ⚠️ Warning Docstring coverage is 56.76% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch chore/bumping-boilerplate

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
Copy link

vercel bot commented Sep 9, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
terragrunt-docs Ready Ready Preview Comment Oct 23, 2025 7:18pm

@yhakbar yhakbar marked this pull request as ready for review October 23, 2025 21:41
@yhakbar yhakbar requested a review from denis256 as a code owner October 23, 2025 21:41
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (9)
cli/flags/shared/shared.go (1)

179-214: Redundant assignment in RootFileNameFlagName Action.

The Destination: &opts.ScaffoldRootFileName on line 187 already handles assigning the flag value to the field. The manual assignment on line 195 (opts.ScaffoldRootFileName = value) is redundant since Actions are executed after the Destination assignment.

Apply this diff to remove the redundant assignment:

 		flags.NewFlag(&cli.GenericFlag[string]{
 			Name:        RootFileNameFlagName,
 			EnvVars:     tgPrefix.EnvVars(RootFileNameFlagName),
 			Destination: &opts.ScaffoldRootFileName,
 			Usage:       "Name of the root Terragrunt configuration file, if used.",
 			Action: func(ctx *cli.Context, value string) error {
 				if value == "" {
 					return cli.NewExitError("root-file-name flag cannot be empty", cli.ExitCodeGeneralError)
 				}
 
 				if value != opts.TerragruntConfigPath {
-					opts.ScaffoldRootFileName = value
-
 					return nil
 				}
 
 				if err := opts.StrictControls.FilterByNames("RootTerragruntHCL").Evaluate(ctx); err != nil {
 					return cli.NewExitError(err, cli.ExitCodeGeneralError)
 				}
 
 				return nil
 			},
 		}),
docs-starlight/src/content/docs/03-features/06-catalog.mdx (1)

52-53: Optional: Consider rewording for variety.

The phrasing "organizations that want to prevent the use of" is repeated on consecutive lines. While clear, you could vary the wording slightly for better readability:

-- `no_shell` (bool): When set to `true`, disables shell command execution in boilerplate templates during scaffolding. This is useful for organizations that want to prevent the use of shell commands in templates for security reasons.
-- `no_hooks` (bool): When set to `true`, disables hook execution in boilerplate templates during scaffolding. This is useful for organizations that want to prevent the use of hooks in templates for security reasons.
+- `no_shell` (bool): When set to `true`, disables shell command execution in boilerplate templates during scaffolding. This is useful for organizations that want to prevent the execution of shell commands in templates for security reasons.
+- `no_hooks` (bool): When set to `true`, disables hook execution in boilerplate templates during scaffolding. This is useful when you need to restrict the execution of hooks in templates for security reasons.
cli/commands/scaffold/scaffold_test.go (5)

109-361: Precedence test emulates logic locally; not exercising production code.

TestCatalogConfigApplication duplicates precedence logic instead of calling the real resolver (applyCatalogConfigToScaffold). This can drift from implementation and currently masks the CLI-false vs config-true issue.

Prefer one of:

  • Move this test into package scaffold (not scaffold_test) and call applyCatalogConfigToScaffold directly, or
  • Export a small resolver helper to test, or
  • Drive via scaffold.Run with a minimal local template to verify end-to-end.

Also, once you track “flag set” state (see code comment in scaffold.go), validate both directions:

  • CLI true overrides config false
  • CLI false overrides config true (when explicitly set)

I can draft the refactor and tests if helpful.


443-500: Shell template disabled: good assertions; consider Windows skip.

TestBoilerplateShellTemplateFunctionDisabled is correct. However, the template engine may invoke shell binary resolution differently on Windows. Add a Windows skip guard to avoid flaky runs.

 func TestBoilerplateShellTemplateFunctionDisabled(t *testing.T) {
+  if runtime.GOOS == "windows" {
+    t.Skip("shell function semantics differ on Windows")
+  }
   t.Parallel()
   ...
 }

And import runtime. Apply similarly to other shell/hook tests.


557-623: Hooks disabled: relies on touch; add cross-platform guard.

The before/after hooks use touch, which isn’t present on Windows. Either:

  • Wrap commands in sh -c and skip on Windows, or
  • Guard the test with runtime.GOOS != "windows".

This will reduce CI flakes.


625-691: Hooks enabled: same portability concern.

Apply the same Windows skip or shell wrapping here.


693-755: Both flags disabled: solid coverage; add Windows skip if needed.

Same rationale as above.

test/integration_scaffold_test.go (2)

178-206: Shell enabled integration test: OK; consider end-to-end precedence case.

Looks good. To fully validate precedence, add a companion test where catalog sets no_shell = true and CLI explicitly sets --no-shell=false (once flag-set tracking is implemented) to verify CLI wins.


317-357: Catalog integration: good; add Windows guard if fixtures rely on POSIX tools.

If the catalog template or hooks rely on POSIX shell, guard with runtime.GOOS or provide platform-neutral fixtures.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 879ddb7 and d49da22.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (28)
  • cli/commands/catalog/cli.go (2 hunks)
  • cli/commands/scaffold/cli.go (3 hunks)
  • cli/commands/scaffold/scaffold.go (10 hunks)
  • cli/commands/scaffold/scaffold_test.go (4 hunks)
  • cli/flags/shared/shared.go (2 hunks)
  • config/catalog.go (1 hunks)
  • config/config.go (1 hunks)
  • docs-starlight/src/content/docs/03-features/06-catalog.mdx (3 hunks)
  • docs-starlight/src/data/commands/catalog.mdx (1 hunks)
  • docs-starlight/src/data/commands/scaffold.mdx (1 hunks)
  • docs-starlight/src/data/flags/catalog-no-hooks.mdx (1 hunks)
  • docs-starlight/src/data/flags/catalog-no-shell.mdx (1 hunks)
  • docs-starlight/src/data/flags/scaffold-no-hooks.mdx (1 hunks)
  • docs-starlight/src/data/flags/scaffold-no-shell.mdx (1 hunks)
  • go.mod (16 hunks)
  • options/options.go (2 hunks)
  • test/fixtures/scaffold/catalog-config-test/terragrunt.hcl (1 hunks)
  • test/fixtures/scaffold/with-hooks/.boilerplate/boilerplate.yml (1 hunks)
  • test/fixtures/scaffold/with-hooks/.boilerplate/terragrunt.hcl (1 hunks)
  • test/fixtures/scaffold/with-hooks/main.tf (1 hunks)
  • test/fixtures/scaffold/with-shell-and-hooks/.boilerplate/boilerplate.yml (1 hunks)
  • test/fixtures/scaffold/with-shell-and-hooks/.boilerplate/terragrunt.hcl (1 hunks)
  • test/fixtures/scaffold/with-shell-and-hooks/main.tf (1 hunks)
  • test/fixtures/scaffold/with-shell-commands/.boilerplate/boilerplate.yml (1 hunks)
  • test/fixtures/scaffold/with-shell-commands/.boilerplate/terragrunt.hcl (1 hunks)
  • test/fixtures/scaffold/with-shell-commands/main.tf (1 hunks)
  • test/integration_parse_test.go (1 hunks)
  • test/integration_scaffold_test.go (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go

⚙️ CodeRabbit configuration file

Review the Go code for quality and correctness. Make sure that the Go code follows best practices, is performant, and is easy to understand and maintain.

Files:

  • test/integration_parse_test.go
  • options/options.go
  • cli/commands/catalog/cli.go
  • cli/commands/scaffold/cli.go
  • config/catalog.go
  • config/config.go
  • cli/commands/scaffold/scaffold_test.go
  • cli/commands/scaffold/scaffold.go
  • test/integration_scaffold_test.go
  • cli/flags/shared/shared.go
docs-starlight/**/*.md*

⚙️ CodeRabbit configuration file

Review the documentation for clarity, grammar, and spelling. Make sure that the documentation is easy to understand and follow. There is currently a migration underway from the Jekyll based documentation in docs to the Starlight + Astro based documentation in docs-starlight. Make sure that the docs-starlight documentation is accurate and up-to-date with the docs documentation, and that any difference between them results in an improvement in the docs-starlight documentation.

Files:

  • docs-starlight/src/data/flags/scaffold-no-hooks.mdx
  • docs-starlight/src/data/flags/scaffold-no-shell.mdx
  • docs-starlight/src/content/docs/03-features/06-catalog.mdx
  • docs-starlight/src/data/flags/catalog-no-shell.mdx
  • docs-starlight/src/data/commands/catalog.mdx
  • docs-starlight/src/data/commands/scaffold.mdx
  • docs-starlight/src/data/flags/catalog-no-hooks.mdx
🧠 Learnings (2)
📚 Learning: 2025-02-10T13:36:19.542Z
Learnt from: levkohimins
PR: gruntwork-io/terragrunt#3723
File: cli/commands/stack/action.go:160-160
Timestamp: 2025-02-10T13:36:19.542Z
Learning: The project uses a custom error package `github.com/gruntwork-io/terragrunt/internal/errors` which provides similar functionality to `fmt.Errorf` but includes stack traces. Prefer using this package's error functions (e.g., `errors.Errorf`, `errors.New`) over the standard library's error handling.

Applied to files:

  • cli/commands/scaffold/cli.go
📚 Learning: 2025-04-17T13:02:28.098Z
Learnt from: yhakbar
PR: gruntwork-io/terragrunt#4169
File: cli/commands/hcl/validate/cli.go:29-60
Timestamp: 2025-04-17T13:02:28.098Z
Learning: Avoid shadowing imported packages with local variables in Go code, such as using a variable named `flags` when the `github.com/gruntwork-io/terragrunt/cli/flags` package is imported. Use more specific variable names like `flagSet` instead.

Applied to files:

  • cli/commands/scaffold/cli.go
  • cli/commands/scaffold/scaffold.go
  • cli/flags/shared/shared.go
🧬 Code graph analysis (6)
cli/commands/catalog/cli.go (1)
cli/flags/shared/shared.go (1)
  • NewScaffoldingFlags (180-229)
cli/commands/scaffold/cli.go (3)
cli/commands/catalog/cli.go (1)
  • NewFlags (18-20)
options/options.go (1)
  • TerragruntOptions (99-335)
cli/flags/shared/shared.go (1)
  • NewScaffoldingFlags (180-229)
cli/commands/scaffold/scaffold_test.go (5)
cli/commands/scaffold/scaffold.go (1)
  • Run (131-248)
util/file.go (3)
  • JoinPath (626-628)
  • FileExists (61-64)
  • ReadFileAsString (369-376)
options/options.go (1)
  • NewTerragruntOptions (386-388)
test/helpers/logger/logger.go (1)
  • CreateLogger (9-14)
config/catalog.go (1)
  • ReadCatalogConfig (83-102)
cli/commands/scaffold/scaffold.go (3)
options/options.go (1)
  • TerragruntOptions (99-335)
cli/flags/shared/shared.go (1)
  • NoIncludeRootFlagName (33-33)
config/catalog.go (1)
  • ReadCatalogConfig (83-102)
test/integration_scaffold_test.go (2)
test/helpers/package.go (1)
  • RunTerragruntCommandWithOutput (1004-1008)
util/file.go (1)
  • ReadFileAsString (369-376)
cli/flags/shared/shared.go (4)
options/options.go (1)
  • TerragruntOptions (99-335)
internal/cli/generic_flag.go (1)
  • GenericFlag (19-48)
internal/cli/errors.go (1)
  • NewExitError (53-69)
internal/cli/bool_flag.go (1)
  • BoolFlag (13-49)
🪛 LanguageTool
docs-starlight/src/content/docs/03-features/06-catalog.mdx

[style] ~53-~53: You have already used this phrasing in nearby sentences. Consider replacing it to add variety to your writing.
Context: .... This is useful for organizations that want to prevent the use of hooks in templates f...

(REP_WANT_TO_VB)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
  • GitHub Check: integration_tests / Test (Fixtures with Latest OSS Terraform)
🔇 Additional comments (36)
go.mod (3)

84-89: AWS SDK coordinated updates look reasonable.

The AWS SDK main package and service modules (config, credentials, s3, sts) are bumped consistently. Patch and minor version bumps for these stable packages carry low risk, but confirm the service SDK versions align with the main package expectations.


10-10: Routine dependency maintenance updates approved.

Patch and minor version bumps for google.golang.org/api, golang.org/x/exp, and AWS SDK are standard maintenance. These appear routine unless there are known compatibility gaps with the codebase.

Also applies to: 77-77, 99-99


23-23: Boilerplate v0.10.1 bump is safe and fully supported.

The web search confirms boilerplate v0.10.1 has no breaking changes and adds GitHub Actions workflows migration and a RenderVariablesWithContext function. The PR implementation is complete:

  • NoShell and NoHooks flags are fully implemented in options/options.go, config/catalog.go, and cli/commands/scaffold/scaffold.go, with flags passed directly to boilerplate's BoilerplateOptions.
  • Test coverage is comprehensive: config parsing, CLI flag override behavior, optional attribute handling, and actual boilerplate behavior with these flags enabled/disabled are all tested in cli/commands/scaffold/scaffold_test.go.
  • Backward compatibility is maintained: both flags are optional in config and default to false.

The version bump is appropriate for the scaffolding feature additions in this PR.

options/options.go (2)

331-334: LGTM! Security flags added correctly.

The NoShell and NoHooks fields are well-documented and appropriately positioned in the struct. The comments clearly explain their purpose for disabling shell commands and hooks in boilerplate templates.


443-444: LGTM! Proper initialization with secure defaults.

Both NoShell and NoHooks are correctly initialized to false, which maintains backward compatibility by keeping shell and hooks enabled by default. Users must explicitly opt into the security restrictions.

cli/flags/shared/shared.go (2)

31-35: LGTM! Scaffolding flag constants follow established naming conventions.

The new scaffolding-related constants are well-named and grouped appropriately with clear comments.


215-229: LGTM! NoShell and NoHooks flags properly configured.

The NoShellFlagName and NoHooksFlagName flags are correctly wired to their respective TerragruntOptions fields with clear usage descriptions and environment variable support.

docs-starlight/src/data/commands/catalog.mdx (1)

20-21: LGTM! Documentation updated with new security flags.

The catalog-no-shell and catalog-no-hooks flags are correctly added to the flags list.

test/fixtures/scaffold/with-shell-commands/.boilerplate/boilerplate.yml (1)

1-5: LGTM! Well-structured test fixture.

The boilerplate definition is clear and properly formatted for testing scaffolding functionality with variables.

test/fixtures/scaffold/with-shell-and-hooks/main.tf (1)

1-21: LGTM! Well-designed test fixture for shell and hooks testing.

The Terraform configuration correctly defines variables to capture shell command outputs and corresponding outputs for verification. The structure is clean and suitable for testing the NoShell and NoHooks functionality.

test/fixtures/scaffold/catalog-config-test/terragrunt.hcl (1)

1-6: LGTM! Appropriate test fixture for catalog config testing.

The catalog configuration correctly sets no_shell and no_hooks to test the security flag behavior with catalog-driven defaults. The relative path reference is appropriate for the test fixture structure.

docs-starlight/src/data/commands/scaffold.mdx (1)

15-16: LGTM! Documentation updated with new security flags.

The scaffold-no-shell and scaffold-no-hooks flags are correctly added to the flags list, consistent with the catalog command documentation.

docs-starlight/src/data/flags/catalog-no-shell.mdx (1)

1-28: LGTM! Comprehensive and well-structured documentation.

The documentation clearly explains the security purpose of the no-shell flag with appropriate warnings and examples. The caution about untrusted templates and the note about non-interactive mode are valuable additions for users.

test/integration_parse_test.go (1)

32-33: LGTM! Correctly excluding template files from parsing.

The template files contain Go template syntax (e.g., {{ shell "..." }}) that isn't valid HCL before template processing, so excluding them from the parse test is appropriate.

test/fixtures/scaffold/with-shell-and-hooks/.boilerplate/boilerplate.yml (1)

1-17: LGTM! Well-structured test fixture.

The boilerplate configuration correctly defines a test variable and lifecycle hooks for exercising the scaffolding functionality with the new NoHooks flag.

test/fixtures/scaffold/with-hooks/.boilerplate/terragrunt.hcl (1)

1-8: LGTM! Valid template structure.

The template correctly uses Go template syntax and will produce valid HCL after processing. The test fixture appropriately exercises hook functionality.

cli/commands/catalog/cli.go (1)

8-19: LGTM! Excellent refactoring to consolidate flag definitions.

Using shared.NewScaffoldingFlags eliminates duplication and ensures consistent flag behavior across catalog and scaffold commands while maintaining the same public API.

test/fixtures/scaffold/with-shell-commands/.boilerplate/terragrunt.hcl (1)

1-10: LGTM! Template correctly exercises shell functionality.

The Go template syntax {{ shell "echo" "-n" "VALUE" }} is correct and will be processed before HCL parsing. The nested quotes are valid template syntax and are appropriately handled by marking this file in knownBadFiles.

test/fixtures/scaffold/with-shell-and-hooks/.boilerplate/terragrunt.hcl (1)

1-10: LGTM! Correctly combines shell and hook functionality.

The template appropriately tests both shell commands and hooks with valid Go template syntax. The file is properly excluded from direct HCL parsing via knownBadFiles.

docs-starlight/src/data/flags/scaffold-no-hooks.mdx (1)

1-28: LGTM! Clear and comprehensive documentation.

The documentation effectively explains the security benefits of the --no-hooks flag, includes appropriate warnings about untrusted templates, and provides a helpful usage example.

config/catalog.go (2)

42-43: LGTM! Properly structured optional configuration fields.

Using *bool allows for tri-state logic (true/false/unset), which is appropriate for configuration that can be overridden by CLI flags or left unset to use defaults.


49-49: LGTM! String() method correctly updated.

The verbose representation now includes the new NoShell and NoHooks fields, which will be helpful for debugging and logging.

test/fixtures/scaffold/with-hooks/main.tf (1)

1-11: LGTM!

This test fixture provides a clean, minimal Terraform configuration for testing hooks functionality. The variable and output definitions are correct and appropriate for the test scenarios.

test/fixtures/scaffold/with-hooks/.boilerplate/boilerplate.yml (1)

1-17: LGTM!

This boilerplate configuration is well-designed for testing hook execution. The before and after hooks with echo commands provide clear signals for verifying hook behavior during scaffold operations.

docs-starlight/src/data/flags/catalog-no-hooks.mdx (1)

1-28: LGTM!

The documentation is comprehensive and well-structured. It clearly explains:

  • The flag's purpose and security implications
  • Important security warnings via Aside blocks
  • Non-interactive mode behavior
  • Example usage

The documentation follows the established pattern for flag documentation files.

docs-starlight/src/data/flags/scaffold-no-shell.mdx (1)

1-28: LGTM!

The documentation effectively communicates the flag's purpose and security considerations. The structure mirrors other flag documentation, maintaining consistency across the docs.

config/config.go (1)

581-588: LGTM!

The implementation correctly extends the catalog block serialization to include no_shell and no_hooks attributes. The code follows the established pattern with proper nil checks and consistent use of the catalogAsCty conversion.

cli/commands/scaffold/cli.go (1)

28-65: LGTM!

Excellent refactoring that consolidates shared scaffolding flags into a shared module. The implementation:

  • Eliminates code duplication by delegating to shared.NewScaffoldingFlags
  • Cleanly appends scaffold-specific flags
  • Maintains backward compatibility
  • Follows the DRY principle

This aligns well with the parallel changes in the catalog command, providing consistent flag behavior across both commands.

docs-starlight/src/content/docs/03-features/06-catalog.mdx (1)

48-71: Excellent documentation of the new security features.

The new "Security Configuration" section effectively communicates:

  • Purpose and usage of no_shell and no_hooks options
  • Security considerations with appropriate warnings
  • Configuration precedence (CLI flags > catalog configuration > defaults)
  • Clear examples for both catalog and scaffold commands

The placement before "Custom templates for scaffolding" is logical, as security should be addressed before discussing customization.

test/fixtures/scaffold/with-shell-commands/main.tf (1)

1-21: LGTM!

This test fixture appropriately supports testing of shell command execution during scaffolding. The dual variables and outputs allow verification of multiple shell command results, which is useful for comprehensive test coverage.

cli/commands/scaffold/scaffold.go (1)

110-129: Constructor looks good; threads security flags and non-interactive correctly.

No issues spotted; matches boilerplate options usage and keeps defaults centralized.

cli/commands/scaffold/scaffold_test.go (1)

22-36: Helper is solid; centralizes default BoilerplateOptions for tests.

Good defaults (OnMissingKey/Config, NonInteractive). No changes needed.

test/integration_scaffold_test.go (4)

207-234: Shell disabled integration test: OK.

Assertions are clear and resilient.


235-259: Hooks enabled: OK.

Validates output minimally; good signal.


261-286: Hooks disabled: OK.

Validates that generation remains valid.


287-315: Both flags disabled: OK.

Covers combined path.

Comment on lines 221 to 229
if _, found := vars[rootFileName]; !found {
vars[rootFileName] = opts.ScaffoldRootFileName
} else {
l.Warnf("The %s variable is already set in the var flag(s). The --%s flag will be ignored.", rootFileName, NoIncludeRootFlagName)
l.Warnf(
"The %s variable is already set in the var flag(s). The --%s flag will be ignored.",
rootFileName,
shared.NoIncludeRootFlagName,
)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Wrong flag name in warning for RootFileName.

The warning for RootFileName uses shared.NoIncludeRootFlagName. It should reference the root-file-name flag. Replace with the correct constant.

-    l.Warnf(
-      "The %s variable is already set in the var flag(s). The --%s flag will be ignored.",
-      rootFileName,
-      shared.NoIncludeRootFlagName,
-    )
+    l.Warnf(
+      "The %s variable is already set in the var flag(s). The --%s flag will be ignored.",
+      rootFileName,
+      shared.RootFileNameFlagName, // define if missing
+    )

If a dedicated constant doesn’t exist yet, add one alongside NoIncludeRootFlagName.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In cli/commands/scaffold/scaffold.go around lines 221 to 229, the warning
message for when the root-file-name var is already set incorrectly references
shared.NoIncludeRootFlagName; update the message to use the correct flag
constant for the root-file-name flag (replace shared.NoIncludeRootFlagName with
the appropriate shared constant, e.g. shared.RootFileNameFlagName). If that
constant does not exist yet, add a new exported constant next to
NoIncludeRootFlagName in the shared package (name it clearly like
RootFileNameFlagName), then use it in the l.Warnf call so the warning prints the
correct flag name.

Comment on lines +250 to +278
// applyCatalogConfigToScaffold applies catalog configuration settings to scaffold options.
// CLI flags take precedence over config file settings.
func applyCatalogConfigToScaffold(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) {
catalogCfg, err := config.ReadCatalogConfig(ctx, l, opts)
if err != nil {
// Don't fail if catalog config can't be read - it's optional
l.Debugf("Could not read catalog config for scaffold: %v", err)
return
}

if catalogCfg == nil {
return
}

// Apply config settings only if CLI flags weren't explicitly set
// Since both NoShell and NoHooks default to false, we apply the config value
// only if it's true (enabling the restriction)
if catalogCfg.NoShell != nil && *catalogCfg.NoShell && !opts.NoShell {
l.Debugf("Applying catalog config: no_shell = true")

opts.NoShell = true
}

if catalogCfg.NoHooks != nil && *catalogCfg.NoHooks && !opts.NoHooks {
l.Debugf("Applying catalog config: no_hooks = true")

opts.NoHooks = true
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Precedence bug: CLI “false” cannot override catalog “true”.

applyCatalogConfigToScaffold can’t distinguish default false from an explicitly passed --no-shell=false/--no-hooks=false, so config=true always wins. This contradicts “CLI flags take precedence” and your unit test expectation (e.g., “cli_override_config_true_with_false”). Fix by tracking “flag was set” state and honoring it.

Suggested approach:

  • Add NoShellFlagSet/NoHooksFlagSet to options.TerragruntOptions and set them in the flags layer.
  • Gate config application on these.

Diff (scaffold.go):

-func applyCatalogConfigToScaffold(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) {
+func applyCatalogConfigToScaffold(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) {
   catalogCfg, err := config.ReadCatalogConfig(ctx, l, opts)
   if err != nil {
     l.Debugf("Could not read catalog config for scaffold: %v", err)
     return
   }
   if catalogCfg == nil {
     return
   }
-  if catalogCfg.NoShell != nil && *catalogCfg.NoShell && !opts.NoShell {
+  // Only apply when CLI did not set the flag explicitly.
+  if catalogCfg.NoShell != nil && *catalogCfg.NoShell && !opts.NoShellFlagSet {
     l.Debugf("Applying catalog config: no_shell = true")
     opts.NoShell = true
   }
-  if catalogCfg.NoHooks != nil && *catalogCfg.NoHooks && !opts.NoHooks {
+  if catalogCfg.NoHooks != nil && *catalogCfg.NoHooks && !opts.NoHooksFlagSet {
     l.Debugf("Applying catalog config: no_hooks = true")
     opts.NoHooks = true
   }
 }

And in options.TerragruntOptions (separate file):

 type TerragruntOptions struct {
   // existing...
   NoShell bool
   NoHooks bool
+  // Set by flag parsing layer to preserve CLI-precedence semantics
+  NoShellFlagSet bool
+  NoHooksFlagSet bool
 }

Update flag parsing to set these booleans when the corresponding CLI flags are present.

Run to locate flags to update:


🏁 Script executed:

#!/usr/bin/env bash
rg -nP --type=go -C3 '\bNoShell\b|\bNoHooks\b|no-?shell|no-?hooks' cli/ --hidden

Length of output: 20069



---

🏁 Script executed:

```shell
#!/bin/bash
# Find TerragruntOptions struct definition
fd -e go -x grep -l 'type TerragruntOptions struct' {} \;

Length of output: 20


🏁 Script executed:

#!/bin/bash
# Show snippet of TerragruntOptions struct
fd -e go -x grep -A 30 'type TerragruntOptions struct' {} \;

Length of output: 1468



---

🏁 Script executed:

```shell
#!/bin/bash
# Get entire TerragruntOptions struct definition
cat options/options.go | awk '/type TerragruntOptions struct/,/^}/ {print NR": "$0}'

Length of output: 12716





🏁 Script executed:

#!/bin/bash
# Check cli package and flag parsing details
rg -nP --type=go 'import.*cli' cli/flags/shared/shared.go -A 5 -B 2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at complete flag parsing context for NoShell and NoHooks
rg -nP --type=go -B 10 -A 5 'Destination:.*NoShell|Destination:.*NoHooks' cli/flags/shared/shared.go

Length of output: 795



---

🌐 Web query:

```web
urfave/cli BoolFlag explicit value detection when flag not provided

💡 Result:

Use the flag/Context IsSet check instead of the boolean value.

  • Context.IsSet("name") returns true when the flag was provided (including --no-foo), false when it was not provided. Use that to distinguish "not provided" from "provided false". [1][2]

Minimal example (urfave/cli/v3):

app := &cli.App{
  Flags: []cli.Flag{
    &cli.BoolFlag{Name: "foo"},
  },
  Action: func(c *cli.Context) error {
    if c.IsSet("foo") {
      // user explicitly passed --foo (true) or --no-foo (false)
      val := c.Bool("foo")
      fmt.Println("explicit:", val)
    } else {
      // flag not provided
      fmt.Println("not provided")
    }
    return nil
  },
}

References:

  • Context and Flag API (IsSet / BoolFlag docs). [1]
  • Change notes adding IsSet / BoolFlag.Value features. [2]

Sources:
[1] pkg.go.dev — github.com/urfave/cli/v3 (Flag/Context docs).
[2] urfave/cli CHANGELOG (IsSet / BoolFlag.Value).





🏁 Script executed:

#!/bin/bash
# Find where flags are used/applied, look for OnAction or Action callbacks
rg -nP --type=go 'OnAction|Action.*func|flag.*action' cli/ -A 3 -B 3 | head -100

Length of output: 6426


🏁 Script executed:

#!/bin/bash
# Look for where applyCatalogConfigToScaffold is called
rg -nP --type=go 'applyCatalogConfigToScaffold' cli/

Length of output: 353





🏁 Script executed:

#!/bin/bash
# View the call site of applyCatalogConfigToScaffold
sed -n '120,145p' cli/commands/scaffold/scaffold.go

Length of output: 940


🏁 Script executed:

#!/bin/bash
# Check scaffold command Action callback signature
sed -n '74,95p' cli/commands/scaffold/cli.go

Length of output: 502


Precedence bug confirmed: CLI "false" cannot override catalog "true".

The review comment correctly identifies the issue. The applyCatalogConfigToScaffold function checks !opts.NoShell and !opts.NoHooks, which cannot distinguish an explicit --no-shell=false from a default unset state, so catalog config with true always wins—contradicting the stated precedence.

The architecture prevents using urfave/cli's Context.IsSet() at the applyCatalogConfigToScaffold call site (it receives a Go context.Context, not a CLI Context). The suggested approach of adding NoShellFlagSet and NoHooksFlagSet tracking fields aligns with the existing pattern (TFPathExplicitlySet at options.go:326) and is the correct fix.

Required changes:

  1. options/options.go: Add NoShellFlagSet bool and NoHooksFlagSet bool fields to TerragruntOptions struct.
  2. cli/flags/shared/shared.go: Add Action callbacks to NoShellFlagName and NoHooksFlagName flags (similar to lines 104–115 in cli/commands/stack/cli.go) to set the tracking fields when flags are parsed.
  3. cli/commands/scaffold/scaffold.go: Update the precedence checks at lines 267 and 273 to use !opts.NoShellFlagSet and !opts.NoHooksFlagSet instead of !opts.NoShell and !opts.NoHooks.
🤖 Prompt for AI Agents
In cli/commands/scaffold/scaffold.go around lines 250 to 278: the function
currently cannot tell if the CLI explicitly set --no-shell/--no-hooks to false
vs left them unset, so catalog true always wins; add two boolean tracking fields
NoShellFlagSet and NoHooksFlagSet to TerragruntOptions in options/options.go,
add Action callbacks on the NoShell and NoHooks flag definitions in
cli/flags/shared/shared.go that set those tracking fields when the flags are
parsed, and update the precedence checks in this file (lines ~267 and ~273) to
use !opts.NoShellFlagSet and !opts.NoHooksFlagSet instead of !opts.NoShell and
!opts.NoHooks so explicit CLI false overrides catalog true.

@yhakbar yhakbar merged commit 9e6d7c5 into main Oct 27, 2025
96 of 97 checks passed
@yhakbar yhakbar deleted the chore/bumping-boilerplate branch October 27, 2025 14:44
yhakbar added a commit that referenced this pull request Oct 27, 2025
* chore: Bumping Boilerplate to `v0.10.0`

* fix: Adding support for `no-shell` and `no-hooks`

* feat: Adding tests for scaffold

* fix: Fixing initialization of BoilerplateOptions

* chore: Refactoring out shared `scaffold` flags to `shared`

* docs: Updating docs with additional call-out

* chore: Upgrading `boilerplate`

* fix: Addressing lints

* fix: Fixing test for Boilerplate bump

* fix: Addressing lints

* fix: Ignoring boilerplated configurations during tests
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants