Fix four critical bugs: array merging (#2281), AWS SDK logging (#2270), helmDefaults skip flags (#2269), and OCI chart versions (#2247)#2288
Conversation
…elmfile#2247 This commit addresses four critical bugs in helmfile: 1. **Issue helmfile#2281**: Fix array merging in --state-values-set - Problem: Arrays were being replaced entirely instead of merged element-by-element - Root cause: MergeMaps() didn't handle arrays, and mergo.Merge was used in some places - Solution: * Enhanced MergeMaps() with mergeSlices() and toInterfaceSlice() functions * Replaced mergo.Merge calls with MergeMaps in environment.go and create.go * Arrays now merge element-by-element, with nested maps merged recursively - Files changed: * pkg/maputil/maputil.go - Added array merging logic * pkg/maputil/maputil_test.go - Added comprehensive unit tests * pkg/environment/environment.go - Use MergeMaps instead of mergo.Merge * pkg/state/create.go - Use MergeMaps instead of mergo.Merge * test/integration/test-cases/issue-2281-array-merge/ - Integration test * test/integration/run.sh - Added new integration test 2. **Issue helmfile#2270**: Suppress AWS SDK debug logging - Problem: AWS SDK debug logs exposing sensitive information (tokens, auth headers) - Root cause: vals.New() called without LogOutput option - Solution: Set LogOutput to io.Discard in ValsInstance() - Files changed: * pkg/plugins/vals.go - Added LogOutput: io.Discard option 3. **Issue helmfile#2269**: Fix helmDefaults.skipDeps and helmDefaults.skipRefresh being ignored - Problem: skipRefresh only checked CLI flags, not helmDefaults or release settings - Root cause: Incomplete calculation at line 1559 in state.go - Solution: Added proper skipRefresh calculation mirroring skipDeps logic - Files changed: * pkg/state/state.go - Fixed skipRefresh calculation (lines 1522-1525, 1564) * pkg/state/skip_test.go - Added unit tests for skipDeps and skipRefresh 4. **Issue helmfile#2247**: Allow OCI charts without explicit version - Problem: OCI charts without version defaulted to "latest" which was then rejected - Root cause: getOCIQualifiedChartName() defaulted chartVersion to "latest" - Solution: Use release.Version directly without defaulting, only reject explicit "latest" - Files changed: * pkg/state/state.go - Remove default to "latest", use empty string * pkg/state/oci_chart_version_test.go - Added comprehensive unit tests * test/integration/test-cases/issue-2247/ - Integration test with registry * test/integration/run.sh - Added new integration test Fixes helmfile#2281, helmfile#2270, helmfile#2269, helmfile#2247 Signed-off-by: Aditya Menon <[email protected]>
6c83685 to
78ab47d
Compare
The helmfile template needed to pass the 'top' values to the chart so that .Values.top is accessible in the template context. Changes: - Pass state values to chart values using toYaml - Adjusted indentation for proper YAML structure - Template now correctly accesses .Values.top for array data Test output now matches expected output with proper element-by-element array merging. Signed-off-by: Aditya Menon <[email protected]>
Improved version parsing to handle edge cases in CI environments: - Added fallback to 3.8 if version parsing fails - Added default values for HELM_MAJOR and HELM_MINOR - Prevents test failures due to version detection issues This ensures the test runs correctly across different environments and Helm versions. Signed-off-by: Aditya Menon <[email protected]>
Added debug logging to show: - helmfile command output when it succeeds unexpectedly - Helm version being used by the test This will help diagnose why the validation isn't triggering in CI. Signed-off-by: Aditya Menon <[email protected]>
The validation for explicit 'latest' in OCI charts was depending on
helm.IsVersionAtLeast("3.8.0") which could fail if Helm version
detection has issues in CI environments.
Changes:
- Remove Helm version check from validation
- Always reject explicit 'latest' for OCI charts
- Remove Helm version check from integration test
- Update unit tests to expect 'latest' to fail for all Helm versions
This ensures consistent behavior across all environments and
Helm versions, fixing the CI failure where helm version detection
was problematic.
Fixes integration test failure in CI.
Signed-off-by: Aditya Menon <[email protected]>
Since the Helm version check was removed from the OCI validation, the helm parameter is no longer needed in getOCIQualifiedChartName. Changes: - Removed helm parameter from function signature - Updated all callers to not pass helm argument - Removed unused mockHelmExec test implementation - Removed unused imports (testutil, helmexec, chart) This resolves the golangci-lint unparam error. Signed-off-by: Aditya Menon <[email protected]>
Updated test case for Helm 3.7.0 to expect error when using 'latest' since we now reject explicit 'latest' for all Helm versions, not just >= 3.8.0. This aligns the test with the updated validation logic that ensures consistent behavior across all Helm versions. Signed-off-by: Aditya Menon <[email protected]>
The integration test script is sourced by run.sh which has `set -e` enabled. When helmfile commands fail (as expected for validation tests), the script would exit immediately before capturing the exit code. This fix temporarily disables `set -e` around each helmfile command that may fail, allowing proper exit code capture and validation. This resolves the persistent CI test failure where the test would exit at Test 1.1 without showing any error message. Signed-off-by: Aditya Menon <[email protected]>
Extends the previous set -e fix to cover helm package and push commands in the registry tests (Test 2.2). These commands can fail and need proper error handling without triggering immediate script exit. This ensures: - helm package failures are caught and handled gracefully - helm push failures are caught and handled gracefully - Test can skip registry tests and pass with validation-only results - set -e is properly re-enabled after each command sequence Signed-off-by: Aditya Menon <[email protected]>
There was a problem hiding this comment.
Pull request overview
This PR addresses four critical bugs in helmfile: array merging for --state-values-set (#2281), AWS SDK credential logging (#2270), helmDefaults skip flags being ignored (#2269), and OCI chart version handling (#2247). Each fix is well-isolated with comprehensive test coverage.
Key Changes
- Array Merging (#2281): Enhanced
MergeMapsinpkg/maputil/maputil.goto merge arrays element-by-element instead of replacing them entirely - AWS SDK Logging (#2270): Added
LogOutput: io.Discardto vals initialization to prevent credential leakage - Skip Flags (#2269): Fixed
skipRefreshlogic to properly respect helmDefaults, release-level, and CLI flag settings - OCI Versions (#2247): Modified OCI chart handling to reject explicit "latest" but allow omitted versions
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
pkg/maputil/maputil.go |
Added mergeSlices() and toInterfaceSlice() functions for element-by-element array merging |
pkg/maputil/maputil_test.go |
Comprehensive test coverage for array merging scenarios including issue #2281 cases |
pkg/environment/environment.go |
Replaced mergo.Merge with MergeMaps in GetMergedValues() |
pkg/state/create.go |
Replaced mergo.Merge with MergeMaps for environment value merging |
pkg/plugins/vals.go |
Added LogOutput: io.Discard to suppress AWS SDK debug logs |
pkg/state/state.go |
Fixed skipRefresh logic and OCI chart version handling |
pkg/state/skip_test.go |
New test file with 6 test cases for skip flags behavior |
pkg/state/oci_chart_version_test.go |
New test file with 7 test cases for OCI version scenarios |
pkg/state/state_test.go |
Updated existing test to reflect new behavior and removed unused import |
test/integration/test-cases/issue-2281-array-merge/* |
Integration test for array merging with state-values-set |
test/integration/test-cases/issue-2247/* |
Comprehensive integration test with validation and OCI registry tests |
test/integration/run.sh |
Added new integration test entries |
|
@aditmeno great! do you wanna be a member of helmfile? |
Sure, I've used helmfile at most of the companies I've worked at so can definitely help out with squashing issues/bugs which pop up here 😀 |
|
@aditmeno I will push the process. |
|
@aditmeno @yxxhero re #2270 I don't have permissions to reopen issue but this still happens with helmfile 1.2.1 I've tried to fix that in helmfile itself but it seems like the issue is coming from vals 0.42.1 and started happening with helmfile 1.1.6, potentially after the Go SDK upgrade. This workaround fixes it |
This commit properly fixes issue helmfile#2270 where AWS SDK debug logs were still appearing despite the fix in PR helmfile#2288. ## Problem The original fix in PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard, but did not address: 1. AWS SDK v2's separate logging system 2. AWS SDK clients created directly in remote.go 3. No way for users to enable logs for debugging As reported in PR helmfile#2288 comment, users still see: SDK 2025/11/24 07:54:06 DEBUG Request PUT /latest/api/token HTTP/1.1 Host: 169.254.169.254 ## Root Cause AWS SDK v2 uses its own logging mechanism controlled by: - AWS_SDK_GO_LOG_LEVEL environment variable (for vals library) - WithClientLogMode config option (for direct AWS SDK usage) The LogOutput option in vals.Options only affects vals' internal logging, not the AWS SDK's debug output. ## Solution Made logging configurable with secure defaults: 1. Added HELMFILE_ENABLE_AWS_SDK_LOGS environment variable - Default: false (suppress all logs for security) - Set to "true" to enable debugging 2. Updated remote.go to conditionally suppress AWS SDK logs - Added enableAWSSDKLogs flag (reads env var on init) - Made WithClientLogMode(0) conditional in all 3 config locations - Only suppresses when HELMFILE_ENABLE_AWS_SDK_LOGS != "true" 3. Updated vals.go to make LogOutput configurable - Only sets io.Discard when HELMFILE_ENABLE_AWS_SDK_LOGS != "true" - Allows enabling vals logs for debugging ## Security Impact - Default behavior: Suppresses sensitive information (tokens, auth headers, credentials) from appearing in logs - User control: Enables debugging when explicitly requested ## Testing - All existing tests pass - golangci-lint passes with no issues - Build succeeds Fixes helmfile#2270 (properly this time) Signed-off-by: Aditya Menon <[email protected]>
This commit properly fixes issue helmfile#2270 where AWS SDK debug logs were still appearing despite the fix in PR helmfile#2288. ## Problem The original fix in PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard, but did not address: 1. AWS SDK v2's separate logging system 2. AWS SDK clients created directly in remote.go 3. No way for users to enable logs for debugging As reported in PR helmfile#2288 comment, users still see: SDK 2025/11/24 07:54:06 DEBUG Request PUT /latest/api/token HTTP/1.1 Host: 169.254.169.254 ## Root Cause AWS SDK v2 uses its own logging mechanism controlled by: - AWS_SDK_GO_LOG_LEVEL environment variable (for vals library) - WithClientLogMode config option (for direct AWS SDK usage) The LogOutput option in vals.Options only affects vals' internal logging, not the AWS SDK's debug output. ## Solution Two-part solution across helmfile and vals: ### Part 1: vals library enhancement (PR helmfile/vals#893) - Added Options.AWSLogLevel field for programmatic control - Changed default from logging to no logging (secure by default) - Supports presets: "off", "minimal", "standard", "verbose" ### Part 2: helmfile changes (this PR) Made logging configurable with secure defaults via HELMFILE_ENABLE_AWS_SDK_LOGS: 1. **Added environment variable** (pkg/envvar/const.go) - HELMFILE_ENABLE_AWS_SDK_LOGS controls all AWS SDK logging - Default: false (suppress logs for security) - Set to "true" to enable debugging 2. **Conditional AWS SDK log suppression in remote.go** - Added enableAWSSDKLogs flag (reads env var on init) - Made WithClientLogMode(0) conditional in all 3 AWS config locations - Only suppresses when HELMFILE_ENABLE_AWS_SDK_LOGS != "true" 3. **Conditional vals configuration in vals.go** - Uses new Options.AWSLogLevel field from vals PR helmfile#893 - Sets to "off" by default (secure) - Sets to "standard" when HELMFILE_ENABLE_AWS_SDK_LOGS=true ## Security Impact - Default behavior: Suppresses sensitive information (tokens, auth headers, credentials) from appearing in logs - User control: Enables debugging when explicitly requested via HELMFILE_ENABLE_AWS_SDK_LOGS=true ## Dependencies - Requires vals PR helmfile/vals#893 to be merged - Once merged, helmfile's go.mod should be updated to use new vals version ## Testing - All existing tests pass - golangci-lint passes with no issues - Build succeeds Fixes helmfile#2270 Depends-on: helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
This commit properly fixes issue helmfile#2270 where AWS SDK debug logs were still appearing despite the fix in PR helmfile#2288. ## Problem The original fix in PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard, but did not address: 1. AWS SDK v2's separate logging system 2. AWS SDK clients created directly in remote.go 3. No way for users to enable logs for debugging As reported in PR helmfile#2288 comment, users still see: SDK 2025/11/24 07:54:06 DEBUG Request PUT /latest/api/token HTTP/1.1 Host: 169.254.169.254 ## Root Cause AWS SDK v2 uses its own logging mechanism controlled by: - AWS_SDK_GO_LOG_LEVEL environment variable (for vals library) - WithClientLogMode config option (for direct AWS SDK usage) The LogOutput option in vals.Options only affects vals' internal logging, not the AWS SDK's debug output. ## Solution Two-part solution across helmfile and vals: ### Part 1: vals library enhancement (PR helmfile/vals#893) - Added Options.AWSLogLevel field for programmatic control - Changed default from logging to no logging (secure by default) - Supports presets: "off", "minimal", "standard", "verbose" ### Part 2: helmfile changes (this PR) Made logging configurable with secure defaults via HELMFILE_ENABLE_AWS_SDK_LOGS: 1. **Added environment variable** (pkg/envvar/const.go) - HELMFILE_ENABLE_AWS_SDK_LOGS controls all AWS SDK logging - Default: false (suppress logs for security) - Set to "true" to enable debugging 2. **Conditional AWS SDK log suppression in remote.go** - Added enableAWSSDKLogs flag (reads env var on init) - Made WithClientLogMode(0) conditional in all 3 AWS config locations - Only suppresses when HELMFILE_ENABLE_AWS_SDK_LOGS != "true" 3. **Conditional vals configuration in vals.go** - Uses new Options.AWSLogLevel field from vals PR helmfile#893 - Sets to "off" by default (secure) - Sets to "standard" when HELMFILE_ENABLE_AWS_SDK_LOGS=true ## Security Impact - Default behavior: Suppresses sensitive information (tokens, auth headers, credentials) from appearing in logs - User control: Enables debugging when explicitly requested via HELMFILE_ENABLE_AWS_SDK_LOGS=true ## Dependencies - Requires vals PR helmfile/vals#893 to be merged - Once merged, helmfile's go.mod should be updated to use new vals version ## Testing - All existing tests pass - golangci-lint passes with no issues - Build succeeds Fixes helmfile#2270 Depends-on: helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
This PR fixes issue helmfile#2270 where AWS SDK debug logs expose sensitive credentials in helmfile output, by adding flexible, configurable AWS SDK logging with secure defaults. Problem: -------- Despite PR helmfile#2288's fix, AWS SDK debug logs still appeared in helmfile output, exposing sensitive information: - AWS tokens and authorization headers - Request/response bodies containing credentials - Secret metadata from vals providers Root Cause: ----------- 1. PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard 2. AWS SDK v2 uses separate logging (AWS_SDK_GO_LOG_LEVEL, WithClientLogMode) 3. Vals library defaulted to verbose logging (aws.LogRetries | aws.LogRequest) 4. No programmatic way to control AWS SDK logging Solution: --------- Two-part fix in conjunction with vals PR helmfile#893: 1. Vals library enhancement (helmfile/vals#893): - Added Options.AWSLogLevel field for programmatic control - Changed default from verbose to secure (no logging) - Added preset levels: off, minimal, standard, verbose - Maintains AWS_SDK_GO_LOG_LEVEL precedence 2. Helmfile changes (this PR): - Added HELMFILE_AWS_SDK_LOG_LEVEL environment variable - Enhanced vals configuration to use new AWSLogLevel field - Added conditional AWS SDK log suppression in remote.go (3 locations) - Comprehensive unit tests (15 test cases) Configuration: -------------- Preset levels via HELMFILE_AWS_SDK_LOG_LEVEL: - "off" (default) - No logging, secure, prevents credential leakage - "minimal" - Log retries only - "standard" - Log retries + requests (previous default behavior) - "verbose" - Log everything (requests, responses, bodies, signing) - Custom - Comma-separated values (e.g., "request,response") Priority order: 1. AWS_SDK_GO_LOG_LEVEL env var (highest) 2. HELMFILE_AWS_SDK_LOG_LEVEL env var 3. Secure default ("off") Testing: -------- Added comprehensive unit tests: - pkg/plugins/vals_test.go: 9 test cases * TestAWSSDKLogLevelConfiguration - all preset levels * TestEnvironmentVariableReading - env var parsing - pkg/remote/remote_test.go: 6 test cases * TestAWSSDKLogLevelInit - init() logic All tests passing: - pkg/plugins: PASS (3/3 test suites) - pkg/remote: PASS (all test suites) - golangci-lint: 0 issues Files changed: 7 files, 271 insertions(+), 31 deletions(-) Security: --------- Before: Credentials exposed by default (aws.LogRetries | aws.LogRequest) After: Credentials protected by default (no logging unless explicitly enabled) Follows security principles: - Secure by default - Principle of least privilege - Explicit opt-in for sensitive logging - Defense in depth Dependency: ----------- Depends on: helmfile/vals#893 Currently using: aditmeno/vals@a97336ce2bf6 (via go.mod replace) After vals PR merges: Update to official release Fixes: helmfile#2270 Related: helmfile#2288, helmfile#2289, helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
This PR fixes issue helmfile#2270 where AWS SDK debug logs expose sensitive credentials in helmfile output, by adding flexible, configurable AWS SDK logging with secure defaults. Problem: -------- Despite PR helmfile#2288's fix, AWS SDK debug logs still appeared in helmfile output, exposing sensitive information: - AWS tokens and authorization headers - Request/response bodies containing credentials - Secret metadata from vals providers Root Cause: ----------- 1. PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard 2. AWS SDK v2 uses separate logging (AWS_SDK_GO_LOG_LEVEL, WithClientLogMode) 3. Vals library defaulted to verbose logging (aws.LogRetries | aws.LogRequest) 4. No programmatic way to control AWS SDK logging Solution: --------- Two-part fix in conjunction with vals PR helmfile#893: 1. Vals library enhancement (helmfile/vals#893): - Added Options.AWSLogLevel field for programmatic control - Changed default from verbose to secure (no logging) - Added preset levels: off, minimal, standard, verbose - Maintains AWS_SDK_GO_LOG_LEVEL precedence 2. Helmfile changes (this PR): - Added HELMFILE_AWS_SDK_LOG_LEVEL environment variable - Enhanced vals configuration to use new AWSLogLevel field - Added conditional AWS SDK log suppression in remote.go (3 locations) - Comprehensive unit tests (15 test cases) Configuration: -------------- Preset levels via HELMFILE_AWS_SDK_LOG_LEVEL: - "off" (default) - No logging, secure, prevents credential leakage - "minimal" - Log retries only - "standard" - Log retries + requests (previous default behavior) - "verbose" - Log everything (requests, responses, bodies, signing) - Custom - Comma-separated values (e.g., "request,response") Priority order: 1. AWS_SDK_GO_LOG_LEVEL env var (highest) 2. HELMFILE_AWS_SDK_LOG_LEVEL env var 3. Secure default ("off") Testing: -------- Added comprehensive unit tests: - pkg/plugins/vals_test.go: 9 test cases * TestAWSSDKLogLevelConfiguration - all preset levels * TestEnvironmentVariableReading - env var parsing - pkg/remote/remote_test.go: 6 test cases * TestAWSSDKLogLevelInit - init() logic All tests passing: - pkg/plugins: PASS (3/3 test suites) - pkg/remote: PASS (all test suites) - golangci-lint: 0 issues Files changed: 7 files, 271 insertions(+), 31 deletions(-) Security: --------- Before: Credentials exposed by default (aws.LogRetries | aws.LogRequest) After: Credentials protected by default (no logging unless explicitly enabled) Follows security principles: - Secure by default - Principle of least privilege - Explicit opt-in for sensitive logging - Defense in depth Dependency: ----------- Depends on: helmfile/vals#893 Currently using: aditmeno/vals@a97336ce2bf6 (via go.mod replace) After vals PR merges: Update to official release Fixes: helmfile#2270 Related: helmfile#2288, helmfile#2289, helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
This PR fixes issue helmfile#2270 where AWS SDK debug logs expose sensitive credentials in helmfile output, by adding flexible, configurable AWS SDK logging with secure defaults. Problem: -------- Despite PR helmfile#2288's fix, AWS SDK debug logs still appeared in helmfile output, exposing sensitive information: - AWS tokens and authorization headers - Request/response bodies containing credentials - Secret metadata from vals providers Root Cause: ----------- 1. PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard 2. AWS SDK v2 uses separate logging (AWS_SDK_GO_LOG_LEVEL, WithClientLogMode) 3. Vals library defaulted to verbose logging (aws.LogRetries | aws.LogRequest) 4. No programmatic way to control AWS SDK logging Solution: --------- Two-part fix in conjunction with vals PR helmfile#893: 1. Vals library enhancement (helmfile/vals#893): - Added Options.AWSLogLevel field for programmatic control - Changed default from verbose to secure (no logging) - Added preset levels: off, minimal, standard, verbose - Maintains AWS_SDK_GO_LOG_LEVEL precedence 2. Helmfile changes (this PR): - Added HELMFILE_AWS_SDK_LOG_LEVEL environment variable - Enhanced vals configuration to use new AWSLogLevel field - Added conditional AWS SDK log suppression in remote.go (3 locations) - Comprehensive unit tests (15 test cases) Configuration: -------------- Preset levels via HELMFILE_AWS_SDK_LOG_LEVEL: - "off" (default) - No logging, secure, prevents credential leakage - "minimal" - Log retries only - "standard" - Log retries + requests (previous default behavior) - "verbose" - Log everything (requests, responses, bodies, signing) - Custom - Comma-separated values (e.g., "request,response") Priority order: 1. AWS_SDK_GO_LOG_LEVEL env var (highest) 2. HELMFILE_AWS_SDK_LOG_LEVEL env var 3. Secure default ("off") Testing: -------- Added comprehensive unit tests: - pkg/plugins/vals_test.go: 9 test cases * TestAWSSDKLogLevelConfiguration - all preset levels * TestEnvironmentVariableReading - env var parsing - pkg/remote/remote_test.go: 6 test cases * TestAWSSDKLogLevelInit - init() logic All tests passing: - pkg/plugins: PASS (3/3 test suites) - pkg/remote: PASS (all test suites) - golangci-lint: 0 issues Files changed: 7 files, 271 insertions(+), 31 deletions(-) Security: --------- Before: Credentials exposed by default (aws.LogRetries | aws.LogRequest) After: Credentials protected by default (no logging unless explicitly enabled) Follows security principles: - Secure by default - Principle of least privilege - Explicit opt-in for sensitive logging - Defense in depth Dependency: ----------- Depends on: helmfile/vals#893 Currently using: aditmeno/vals@a97336ce2bf6 (via go.mod replace) After vals PR merges: Update to official release Fixes: helmfile#2270 Related: helmfile#2288, helmfile#2289, helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
This PR fixes issue helmfile#2270 where AWS SDK debug logs expose sensitive credentials in helmfile output, by adding flexible, configurable AWS SDK logging with secure defaults. Problem: -------- Despite PR helmfile#2288's fix, AWS SDK debug logs still appeared in helmfile output, exposing sensitive information: - AWS tokens and authorization headers - Request/response bodies containing credentials - Secret metadata from vals providers Root Cause: ----------- 1. PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard 2. AWS SDK v2 uses separate logging (AWS_SDK_GO_LOG_LEVEL, WithClientLogMode) 3. Vals library defaulted to verbose logging (aws.LogRetries | aws.LogRequest) 4. No programmatic way to control AWS SDK logging Solution: --------- Two-part fix in conjunction with vals PR helmfile#893: 1. Vals library enhancement (helmfile/vals#893): - Added Options.AWSLogLevel field for programmatic control - Changed default from verbose to secure (no logging) - Added preset levels: off, minimal, standard, verbose - Maintains AWS_SDK_GO_LOG_LEVEL precedence 2. Helmfile changes (this PR): - Added HELMFILE_AWS_SDK_LOG_LEVEL environment variable - Enhanced vals configuration to use new AWSLogLevel field - Added conditional AWS SDK log suppression in remote.go (3 locations) - Comprehensive unit tests (15 test cases) Configuration: -------------- Preset levels via HELMFILE_AWS_SDK_LOG_LEVEL: - "off" (default) - No logging, secure, prevents credential leakage - "minimal" - Log retries only - "standard" - Log retries + requests (previous default behavior) - "verbose" - Log everything (requests, responses, bodies, signing) - Custom - Comma-separated values (e.g., "request,response") Priority order: 1. AWS_SDK_GO_LOG_LEVEL env var (highest) 2. HELMFILE_AWS_SDK_LOG_LEVEL env var 3. Secure default ("off") Testing: -------- Added comprehensive unit tests: - pkg/plugins/vals_test.go: 9 test cases * TestAWSSDKLogLevelConfiguration - all preset levels * TestEnvironmentVariableReading - env var parsing - pkg/remote/remote_test.go: 6 test cases * TestAWSSDKLogLevelInit - init() logic All tests passing: - pkg/plugins: PASS (3/3 test suites) - pkg/remote: PASS (all test suites) - golangci-lint: 0 issues Files changed: 7 files, 271 insertions(+), 31 deletions(-) Security: --------- Before: Credentials exposed by default (aws.LogRetries | aws.LogRequest) After: Credentials protected by default (no logging unless explicitly enabled) Follows security principles: - Secure by default - Principle of least privilege - Explicit opt-in for sensitive logging - Defense in depth Dependency: ----------- Depends on: helmfile/vals#893 Currently using: aditmeno/vals@a97336ce2bf6 (via go.mod replace) After vals PR merges: Update to official release Fixes: helmfile#2270 Related: helmfile#2288, helmfile#2289, helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
This PR fixes issue helmfile#2270 where AWS SDK debug logs expose sensitive credentials in helmfile output, by adding flexible, configurable AWS SDK logging with secure defaults. Problem: -------- Despite PR helmfile#2288's fix, AWS SDK debug logs still appeared in helmfile output, exposing sensitive information: - AWS tokens and authorization headers - Request/response bodies containing credentials - Secret metadata from vals providers Root Cause: ----------- 1. PR helmfile#2288 only suppressed vals' own logging via LogOutput: io.Discard 2. AWS SDK v2 uses separate logging (AWS_SDK_GO_LOG_LEVEL, WithClientLogMode) 3. Vals library defaulted to verbose logging (aws.LogRetries | aws.LogRequest) 4. No programmatic way to control AWS SDK logging Solution: --------- Two-part fix in conjunction with vals PR helmfile#893: 1. Vals library enhancement (helmfile/vals#893): - Added Options.AWSLogLevel field for programmatic control - Changed default from verbose to secure (no logging) - Added preset levels: off, minimal, standard, verbose - Maintains AWS_SDK_GO_LOG_LEVEL precedence 2. Helmfile changes (this PR): - Added HELMFILE_AWS_SDK_LOG_LEVEL environment variable - Enhanced vals configuration to use new AWSLogLevel field - Added conditional AWS SDK log suppression in remote.go (3 locations) - Comprehensive unit tests (15 test cases) Configuration: -------------- Preset levels via HELMFILE_AWS_SDK_LOG_LEVEL: - "off" (default) - No logging, secure, prevents credential leakage - "minimal" - Log retries only - "standard" - Log retries + requests (previous default behavior) - "verbose" - Log everything (requests, responses, bodies, signing) - Custom - Comma-separated values (e.g., "request,response") Priority order: 1. AWS_SDK_GO_LOG_LEVEL env var (highest) 2. HELMFILE_AWS_SDK_LOG_LEVEL env var 3. Secure default ("off") Testing: -------- Added comprehensive unit tests: - pkg/plugins/vals_test.go: 9 test cases * TestAWSSDKLogLevelConfiguration - all preset levels * TestEnvironmentVariableReading - env var parsing - pkg/remote/remote_test.go: 6 test cases * TestAWSSDKLogLevelInit - init() logic All tests passing: - pkg/plugins: PASS (3/3 test suites) - pkg/remote: PASS (all test suites) - golangci-lint: 0 issues Files changed: 7 files, 271 insertions(+), 31 deletions(-) Security: --------- Before: Credentials exposed by default (aws.LogRetries | aws.LogRequest) After: Credentials protected by default (no logging unless explicitly enabled) Follows security principles: - Secure by default - Principle of least privilege - Explicit opt-in for sensitive logging - Defense in depth Dependency: ----------- Depends on: helmfile/vals#893 Currently using: aditmeno/vals@a97336ce2bf6 (via go.mod replace) After vals PR merges: Update to official release Fixes: helmfile#2270 Related: helmfile#2288, helmfile#2289, helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]>
) * fix: make AWS SDK debug logging configurable (issue #2270) This PR fixes issue #2270 where AWS SDK debug logs expose sensitive credentials in helmfile output, by adding flexible, configurable AWS SDK logging with secure defaults. Problem: -------- Despite PR #2288's fix, AWS SDK debug logs still appeared in helmfile output, exposing sensitive information: - AWS tokens and authorization headers - Request/response bodies containing credentials - Secret metadata from vals providers Root Cause: ----------- 1. PR #2288 only suppressed vals' own logging via LogOutput: io.Discard 2. AWS SDK v2 uses separate logging (AWS_SDK_GO_LOG_LEVEL, WithClientLogMode) 3. Vals library defaulted to verbose logging (aws.LogRetries | aws.LogRequest) 4. No programmatic way to control AWS SDK logging Solution: --------- Two-part fix in conjunction with vals PR #893: 1. Vals library enhancement (helmfile/vals#893): - Added Options.AWSLogLevel field for programmatic control - Changed default from verbose to secure (no logging) - Added preset levels: off, minimal, standard, verbose - Maintains AWS_SDK_GO_LOG_LEVEL precedence 2. Helmfile changes (this PR): - Added HELMFILE_AWS_SDK_LOG_LEVEL environment variable - Enhanced vals configuration to use new AWSLogLevel field - Added conditional AWS SDK log suppression in remote.go (3 locations) - Comprehensive unit tests (15 test cases) Configuration: -------------- Preset levels via HELMFILE_AWS_SDK_LOG_LEVEL: - "off" (default) - No logging, secure, prevents credential leakage - "minimal" - Log retries only - "standard" - Log retries + requests (previous default behavior) - "verbose" - Log everything (requests, responses, bodies, signing) - Custom - Comma-separated values (e.g., "request,response") Priority order: 1. AWS_SDK_GO_LOG_LEVEL env var (highest) 2. HELMFILE_AWS_SDK_LOG_LEVEL env var 3. Secure default ("off") Testing: -------- Added comprehensive unit tests: - pkg/plugins/vals_test.go: 9 test cases * TestAWSSDKLogLevelConfiguration - all preset levels * TestEnvironmentVariableReading - env var parsing - pkg/remote/remote_test.go: 6 test cases * TestAWSSDKLogLevelInit - init() logic All tests passing: - pkg/plugins: PASS (3/3 test suites) - pkg/remote: PASS (all test suites) - golangci-lint: 0 issues Files changed: 7 files, 271 insertions(+), 31 deletions(-) Security: --------- Before: Credentials exposed by default (aws.LogRetries | aws.LogRequest) After: Credentials protected by default (no logging unless explicitly enabled) Follows security principles: - Secure by default - Principle of least privilege - Explicit opt-in for sensitive logging - Defense in depth Dependency: ----------- Depends on: helmfile/vals#893 Currently using: aditmeno/vals@a97336ce2bf6 (via go.mod replace) After vals PR merges: Update to official release Fixes: #2270 Related: #2288, #2289, helmfile/vals#893 Signed-off-by: Aditya Menon <[email protected]> * chore: update vals to use parameter-based AWS log level configuration Updated vals dependency to commit 06d7cd29 which implements clean parameter-based AWS SDK logging configuration instead of using global state mutation. Changes in vals implementation: - AWS log level passed through function parameters to each provider - No os.Setenv() - no environment mutation - No package-level global variables - No sync/atomic dependency needed - Thread-safe by design - each provider instance has its own log level This maintains the same functionality as before but with a cleaner implementation that avoids global state mutation. Signed-off-by: Aditya Menon <[email protected]> * deps: update vals to upstream v0.42.6 Update from vals fork (aditmeno/vals) to official release v0.42.6. Remove replace directive now that vals PR #893 has been merged upstream. This brings in the AWS SDK log level configuration improvements: - SetDefaultLogLevel() package-level function - Options.AWSLogLevel field support - Secure default (no logging) - Preset log levels (off, minimal, standard, verbose) Also updates related dependencies: - Azure SDK and auth libraries - AWS SDK config and credentials - OAuth2 library Signed-off-by: Aditya Menon <[email protected]> --------- Signed-off-by: Aditya Menon <[email protected]>
|
@aditmeno Invitation sent!j please check. |
Received and accepted, thank you! |
…file#2353) PR helmfile#2288 introduced element-by-element array merging to fix helmfile#2281, but this caused a regression where layer/environment arrays were merged instead of replacing base arrays entirely. This fix uses automatic sparse array detection: - Arrays with nil values (from --state-values-set) merge element-by-element - Arrays without nils (from layer YAML) replace entirely This follows Helm's documented behavior where arrays replace rather than merge. Signed-off-by: Aditya Menon <[email protected]>
…file#2353) PR helmfile#2288 introduced element-by-element array merging to fix helmfile#2281, but this caused a regression where layer/environment arrays were merged instead of replacing base arrays entirely. This fix uses automatic sparse array detection: - Arrays with nil values (from --state-values-set) merge element-by-element - Arrays without nils (from layer YAML) replace entirely This follows Helm's documented behavior where arrays replace rather than merge. Signed-off-by: Aditya Menon <[email protected]>
…file#2353) PR helmfile#2288 introduced element-by-element array merging to fix helmfile#2281, but this caused a regression where layer/environment arrays were merged instead of replacing base arrays entirely. This fix uses automatic sparse array detection: - Arrays with nil values (from --state-values-set) merge element-by-element - Arrays without nils (from layer YAML) replace entirely This follows Helm's documented behavior where arrays replace rather than merge. Signed-off-by: Aditya Menon <[email protected]>
…file#2353) PR helmfile#2288 introduced element-by-element array merging to fix helmfile#2281, but this caused a regression where layer/environment arrays were merged instead of replacing base arrays entirely. This fix uses automatic sparse array detection: - Arrays with nil values (from --state-values-set) merge element-by-element - Arrays without nils (from layer YAML) replace entirely This follows Helm's documented behavior where arrays replace rather than merge. Signed-off-by: Aditya Menon <[email protected]>
* fix: array merge regression - layer arrays now replace defaults (#2353) PR #2288 introduced element-by-element array merging to fix #2281, but this caused a regression where layer/environment arrays were merged instead of replacing base arrays entirely. This fix uses automatic sparse array detection: - Arrays with nil values (from --state-values-set) merge element-by-element - Arrays without nils (from layer YAML) replace entirely This follows Helm's documented behavior where arrays replace rather than merge. Signed-off-by: Aditya Menon <[email protected]> * fix: use separate CLIOverrides field for element-by-element array merging The previous approach using ArrayMergeStrategySparse detection didn't work for --state-values-set array[0]=value because setting index 0 produces no nils in the array. This fix adds a CLIOverrides field to Environment that keeps CLI values separate from layer values. CLI overrides are merged last using ArrayMergeStrategyMerge (always element-by-element), while layer values use the default strategy (arrays replace). This ensures: - --state-values-set array[0]=x only changes index 0, preserving other elements - Layer/environment file arrays still replace base arrays entirely - Issue #2281 fix is preserved (--state-values-set array[1].field=x works) Signed-off-by: Aditya Menon <[email protected]> * fix: correct comment about array merge strategy in test Signed-off-by: Aditya Menon <[email protected]> * fix: propagate Defaults in multi-part helmfiles and fix merge order - Add Defaults field merging from ctxEnv to preserve base values across helmfile parts separated by --- - Fix merge order: current part values now correctly override previous parts (was reversed, causing older values to win) - Update 147 snapshot test files for new Environment log format with CLIOverrides field This completes the fix for issue #2353 by ensuring: 1. Layer arrays replace entirely (not element-by-element merge) 2. CLI --state-values-set sparse arrays still merge element-by-element 3. Multi-part helmfiles properly inherit and override values Signed-off-by: Aditya Menon <[email protected]> * fix: address Copilot review comments - Initialize EmptyEnvironment with empty maps to match New() constructor - Update test comment to accurately describe ArrayMergeStrategySparse Signed-off-by: Aditya Menon <[email protected]> * fix: ensure templates access merged values via .Environment.Values This commit fixes a regression in the CLIOverrides integration where templates accessing .Environment.Values couldn't see CLI override values. Changes: - Remove CLIOverrides-into-Values merge from Merge() to keep proper layering order (Defaults → Values → CLIOverrides) in GetMergedValues() - Update NewEnvironmentTemplateData to set envCopy.Values to the merged values, ensuring templates see the same values via both .Values and .Environment.Values This ensures: - Issue #2353: Layer arrays still replace entirely (Sparse strategy) - Issue #2281: CLI sparse arrays still merge element-by-element - Templates can access CLI overrides via .Environment.Values Signed-off-by: Aditya Menon <[email protected]> * docs: improve mergeSlices documentation per Copilot review Address Copilot review comments on PR #2367: - Document empty array edge case: explicitly setting [] clears base array - Document recursive strategy propagation for nested map merging - Add comprehensive behavior description for all array merge strategies Signed-off-by: Aditya Menon <[email protected]> * fix: use merged values when rendering environment value files Environment value files (*.yaml.gotmpl) can reference CLI values via .Values. Previously, only env.Values was passed to template rendering, which didn't include CLIOverrides. Now we call env.GetMergedValues() to get Defaults + Values + CLIOverrides before rendering, so templates can access CLI values like: --state-values-set foo=bar This fixes the state-values-set-cli-args-in-environments integration test. Signed-off-by: Aditya Menon <[email protected]> --------- Signed-off-by: Aditya Menon <[email protected]>
Summary
This PR fixes four critical bugs in helmfile:
--state-values-sethelmDefaults.skipDepsandhelmDefaults.skipRefreshbeing ignoredAll fixes include comprehensive unit tests and integration tests where applicable.
Issue #2281: Fix array merging in --state-values-set
Problem
When using
--state-values-setto set array values, arrays were being replaced entirely instead of merged element-by-element. This made it impossible to override individual array elements.Example:
Running
helmfile --state-values-set 'array[1].value=999'would replace the entire array instead of just updatingarray[1].value.Root Cause
MergeMaps()function inpkg/maputil/maputil.godidn't handle arraysmergo.Merge()which doesn't do element-by-element array mergingSolution
MergeMaps()with array handling:mergeSlices()function for element-by-element array mergingtoInterfaceSlice()helper for type detectionmergo.Merge()calls withMergeMaps()in:pkg/environment/environment.gopkg/state/create.goFiles Changed
pkg/maputil/maputil.go- Core array merging logicpkg/maputil/maputil_test.go- Comprehensive unit testspkg/environment/environment.go- Use MergeMaps instead of mergo.Mergepkg/state/create.go- Use MergeMaps instead of mergo.Mergetest/integration/test-cases/issue-2281-array-merge/- Integration testtest/integration/run.sh- Added new integration testTests
✅ Unit tests: 3 comprehensive test cases covering array merging scenarios
✅ Integration test: Real-world helmfile scenario with
--state-values-setIssue #2270: Suppress AWS SDK debug logging
Problem
Starting from helmfile 1.1.6, AWS SDK debug logs were being written to stdout, exposing sensitive information including:
Root Cause
vals.New()was called without theLogOutputoption, causing AWS SDK to write debug logs to stdout by default.Solution
Set
LogOutput: io.DiscardinValsInstance()to suppress debug logging from AWS SDK and other vals providers.Files Changed
pkg/plugins/vals.go- AddedLogOutput: io.DiscardoptionSecurity Impact
🔒 Prevents credential leakage in helmfile logs
Issue #2269: Fix helmDefaults.skipDeps and helmDefaults.skipRefresh being ignored
Problem
The
helmDefaults.skipRefreshconfiguration was being completely ignored. Only CLI flags were checked, nothelmDefaultsor release-level settings.Root Cause
Incomplete logic at line 1559 in
pkg/state/state.go:This didn't follow the same pattern as
skipDeps, which properly checked all three levels:Solution
Added proper
skipRefreshcalculation mirroring theskipDepslogic:Files Changed
pkg/state/state.go- Fixed skipRefresh calculation (lines 1522-1525, 1564)pkg/state/skip_test.go- Unit tests for skipDeps and skipRefreshTests
✅ Unit tests: 6 test cases covering all combinations of CLI/Release/HelmDefaults settings
Issue #2247: Allow OCI charts without explicit version
Problem
When using OCI charts without specifying a version, helmfile would fail with:
This prevented users from deploying OCI charts without versions, which is a critical use case for many deployment pipelines where you want to always pull the latest version.
Background
helm install xxx oci://...without a versionRoot Cause
getOCIQualifiedChartName()inpkg/state/state.gowould defaultchartVersionto"latest", which was then rejected by the validation check for Helm >= 3.8.0.Solution
release.Versiondirectly (empty string if not specified)version: "latest", not when omittedFiles Changed
pkg/state/state.go- Remove default to "latest", improved logic (lines 4426-4443)pkg/state/oci_chart_version_test.go- Comprehensive unit tests (7 scenarios)test/integration/test-cases/issue-2247/- Integration test with real OCI registrytest/integration/run.sh- Added new integration testTests
✅ Unit tests: 7 test cases covering all OCI version scenarios
✅ Integration test: Two-part test with validation checks + real OCI registry
The integration test includes:
Testing
All changes include comprehensive tests:
Running Tests
Code Quality
✅ All code passes
golangci-lint run✅ Commits are signed with
-s -S(signoff + GPG)✅ Import formatting fixed per gci standards
Checklist
Related Issues
Fixes #2281
Fixes #2270
Fixes #2269
Fixes #2247
Note on Issue #2247
While this issue was labeled "wontfix" upstream, it represents a regression from version 0.162.0 that breaks real-world deployment workflows. The fix:
This change should be reconsidered given its impact on production workflows.