Repository navigation
fix(git): tolerate config errors for CI git-clone bootstrap pre-Cobra #2879
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Andriy Knysh (aknysh)
merged 61 commits into
main
from
osterman/test-container-fields-ignored
Aug 18, 2026
Merged
Changes from all commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
f3586d4
test(container): cover combined buildx driver/cache/tags/context args
osterman 2bedf69
fix(git): tolerate config errors for CI git-clone bootstrap pre-Cobra
osterman 915f7c9
docs(fixes): record CI git-clone bootstrap profile fix
osterman 6428e34
fix(git): parse CI bootstrap flags with real pflag arity, not a heuri…
osterman 14c9abc
docs(fixes): update CI git-clone bootstrap fix record for pflag rewrite
osterman a7b992b
fix(schema): decode with: into Build/Run/Push/Inspect for custom comm…
osterman 28e59ac
fix(workdir): sanitize nested component names in BuildPath
osterman 3c3b864
docs(fixes): record custom-command with: and workdir path-depth fixes
osterman bf74e17
fix(terraform/output): retarget containment-guard test at stack trave…
osterman 056b183
fix(terraform/output): strip ANSI before asserting cache-hit visibili…
osterman 17efc2a
chore(claude): deny gofmt in Claude Code permissions
osterman 427985e
test: close Codecov patch-coverage gaps on PR #2879
osterman c3ccf2d
docs(fixes): record terraform/output CI fixes; correct gofmt->gofumpt…
osterman c8e5fed
Merge remote-tracking branch 'origin/main' into osterman/test-contain…
osterman 6577f9e
test(registry): widen timing margin in provider-mirror concurrency test
osterman f807b4d
fix(workdir): sanitize nested component names in createWorkdirDirectory
osterman 6688f7b
fix(provisioner): guard path traversal in source-vendoring fallback
osterman a332d5e
fix(cli): decode and execute custom-command step-level container: ove…
osterman 4befe0f
fix(container): pass restart/healthcheck through to ephemeral run steps
osterman 5ad33c1
fix(config): surface swallowed import errors and hide-nothing validation
osterman 3431325
fix(security): remediate 7 Dependabot alerts in website dependencies
osterman a3ca9e0
fix(schema): reject unknown fields in container step with:/driver: bl…
osterman 96c1e1d
fix(security): remediate 5 Dependabot alerts, 2 unpatched and deferred
osterman 1548c31
Merge remote-tracking branch 'origin/main' into osterman/test-contain…
osterman 4b73560
Merge remote-tracking branch 'origin/main' into osterman/test-contain…
osterman e69be9f
fix(cmd): update stale path assertions in container build argv test
osterman cad624c
Merge remote-tracking branch 'origin/main' into osterman/test-contain…
osterman f96b4a8
fix(provisioner): pass OutputWriters in nested-workdir Provision test
osterman 80653c6
test(cmd): assert cache/driver flag values, not just presence
osterman b17cfa3
fix(cmd): normalize marker path for cross-platform shell command
osterman 101b59e
fix(provisioner): sanitize backslash in workdir component names
osterman 4fbcaaf
test(runner): make step-name assertion independent, cover empty type
osterman 25336e8
fix(schema): reject unknown fields in container: override blocks
osterman ab0bc4e
docs(fixtures): sync workdir-nested fixture with path-safety fixes
osterman 8c69210
docs(fixes): correct formatter name, markdown syntax, typos, spelling
osterman d4d1646
docs(fixes): correct macOS spelling in CI platform list
osterman b5868b4
fix(provisioner): use filepath.Rel for component base path containment
osterman e049953
fix(schema): wrap WorkflowContainer JSON decode error
osterman 16179fe
docs(fixtures): sync stack-manifest comments with path-safety fixes
osterman b2bbbf7
fix(provisioner,cmd): close symlink containment gap and route script …
osterman f9d1f32
fix(cmd): propagate Cobra cancellation to custom-command step execution
osterman 3057f22
docs(fixes): add missing comma after "e.g." in fix-log doc
osterman 193dfbe
fix(cmd,schema): address CodeRabbit findings on PR #2879
osterman ade24e6
Merge remote-tracking branch 'origin/main' into osterman/test-contain…
osterman 61e816f
docs(workdir): document BuildPath's separator sanitization in its doc…
osterman 8171ac6
test(cmd): add regression test for RootCmd.Commands() restoration
osterman 7095b2c
fix(workdir,schema): close BuildPath collision/traversal gaps, stop m…
osterman f310e93
docs(fixes): fix EditorConfig indentation in workdir fix-log doc
osterman a7b8ad1
fix(workdir,cmd): make BuildPath's encoding fully injective, restore …
osterman 903639a
test: update hardcoded workdir names for BuildPath's injective encoding
osterman 640fa26
fix(workdir): give backslash its own escape token, route CleanWorkdir…
osterman 26dd2f4
fix(workdir): handle filesystem-root basePath, de-tautologize workdir…
osterman 5840877
Merge branch 'main' into osterman/test-container-fields-ignored
osterman ff9b9aa
test: cover BuildPath's error-propagation branches across workdir con…
osterman 2244339
fix(workdir,cmd,tests): contain stack traversal to component-type roo…
osterman 8c7606c
fix(workdir,cmd/git): address PR #2879 CodeRabbit round and fix local…
osterman 2eda097
fix(workdir): reject only '.'/'..' segments in stack, not every '/'
osterman 41fd4f5
refactor(cmd): extract shared container-override step helper
osterman 92eb2fa
fix(cmd,workdir,terraform): address PR #2879 CodeRabbit round 3 findings
osterman 1460d6c
fix(cmd): make workdir clean/describe/show honor atmos_component over…
osterman 78d9b85
fix(cmd,provisioner): address PR #2879 CodeRabbit round 4 findings
osterman File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
|
|
||
| cfg "github.com/cloudposse/atmos/pkg/config" | ||
| "github.com/cloudposse/atmos/pkg/schema" | ||
| "github.com/cloudposse/atmos/tests/testhelpers" | ||
| ) | ||
|
|
||
| // TestCustomCommandContainerBuildPassesWithBlockToDocker reproduces | ||
| // https://github.com/cloudposse/atmos/issues/2876 end to end: a | ||
| // `.atmos.d/commands.yaml`-style custom command with a `type: container, | ||
| // action: build` step and a `with:` block must invoke docker with the full | ||
| // configured Buildx engine, builder, cache, tags, dockerfile, and context -- | ||
| // not silently fall back to `docker build -f Dockerfile .`. | ||
| // | ||
| // This writes real config to disk, loads it through cfg.InitCliConfig (the | ||
| // same production config-loading path `atmos` itself uses), registers it via | ||
| // processCustomCommands, and invokes the resulting custom command | ||
| // through RootCmd.Execute() exactly as a user would from the shell. A fake, | ||
| // logging `docker` executable on PATH (testhelpers.InstallFakeContainerRuntime) | ||
| // captures the real argv Atmos emits, so this exercises the real command | ||
| // executor rather than manually constructing schema.Task/WorkflowStep/ | ||
| // ContainerBuildStep values in Go. | ||
| func TestCustomCommandContainerBuildPassesWithBlockToDocker(t *testing.T) { | ||
| _ = NewTestKit(t) | ||
|
|
||
| tempDir := t.TempDir() | ||
| appDir := filepath.Join(tempDir, "app") | ||
| require.NoError(t, os.MkdirAll(appDir, 0o755)) | ||
| require.NoError(t, os.WriteFile(filepath.Join(appDir, "Dockerfile"), []byte("FROM scratch\n"), 0o644)) | ||
|
|
||
| atmosYAML := ` | ||
| base_path: "." | ||
| commands: | ||
| - name: test-container-build-with-block | ||
| description: Build the application image | ||
| steps: | ||
| - name: build | ||
| type: container | ||
| action: build | ||
| provider: docker | ||
| with: | ||
| engine: buildx | ||
| context: app | ||
| dockerfile: Dockerfile | ||
| tags: | ||
| - "example.invalid/demo:sha-test" | ||
| driver: | ||
| name: atmos-native-ci | ||
| provider: docker-container | ||
| opts: | ||
| image: mirror.gcr.io/moby/buildkit:buildx-stable-1 | ||
| cache: | ||
| from: | ||
| - type: registry | ||
| ref: "example.invalid/demo:buildcache" | ||
| to: | ||
| - type: registry | ||
| ref: "example.invalid/demo:buildcache" | ||
| mode: max | ||
| ` | ||
| require.NoError(t, os.WriteFile(filepath.Join(tempDir, "atmos.yaml"), []byte(atmosYAML), 0o644)) | ||
|
|
||
| t.Setenv("ATMOS_CLI_CONFIG_PATH", tempDir) | ||
| t.Setenv("ATMOS_BASE_PATH", tempDir) | ||
| t.Chdir(tempDir) | ||
|
|
||
| argsPath := filepath.Join(t.TempDir(), "docker-args.log") | ||
| t.Setenv("ATMOS_FAKE_RUNTIME_ARGS_FILE", argsPath) | ||
| testhelpers.InstallFakeContainerRuntime(t, testhelpers.FakeContainerRuntimeSpec{ | ||
| Name: "docker", | ||
| Mode: testhelpers.FakeContainerRuntimeStep, | ||
| }) | ||
|
|
||
| atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, false) | ||
| require.NoError(t, err) | ||
|
|
||
| require.NoError(t, processCustomCommands(atmosConfig, atmosConfig.Commands, RootCmd)) | ||
|
|
||
| RootCmd.SetArgs([]string{"test-container-build-with-block"}) | ||
| require.NoError(t, RootCmd.Execute()) | ||
|
|
||
| content, err := os.ReadFile(argsPath) | ||
| require.NoError(t, err, "the fake docker executable must have been invoked at least once") | ||
| lines := strings.Split(strings.TrimSpace(string(content)), "\n") | ||
|
|
||
| var buildLine string | ||
| for _, line := range lines { | ||
| fields := strings.Split(line, "\t") | ||
| if len(fields) > 1 && fields[0] == "buildx" && fields[1] == "build" { | ||
| buildLine = line | ||
| break | ||
| } | ||
| } | ||
| require.NotEmpty(t, buildLine, | ||
| "expected a `docker buildx build ...` invocation; got invocations: %v", lines) | ||
|
|
||
| fields := strings.Split(buildLine, "\t") | ||
| assert.Contains(t, fields, "--builder", "configured Buildx driver must be applied") | ||
| assert.Contains(t, fields, "atmos-native-ci") | ||
| assert.Contains(t, fields, "-t", "configured tag must be applied") | ||
| assert.Contains(t, fields, "example.invalid/demo:sha-test") | ||
| assert.Contains(t, fields, "-f", "configured Dockerfile must be applied") | ||
| // context/dockerfile are relative paths in the with: block, resolved | ||
| // against the step's working directory (#2880) into absolute paths -- | ||
| // docker still receives the same file, just no longer as a bare relative | ||
| // string a differing subprocess cwd could silently misresolve. | ||
| assert.Contains(t, fields, filepath.Join(appDir, "Dockerfile"), "configured Dockerfile must be applied") | ||
| assert.Contains(t, fields, appDir, "configured context must be applied") | ||
|
|
||
| // The driver: block must provision a real Buildx builder before the build | ||
| // runs (pkg/container/docker.go's ensureBuilder calls `docker buildx | ||
| // create` as a separate invocation), and the cache entries must reach | ||
| // docker as the exact configured reference/mode, not merely as a bare | ||
| // `--cache-from`/`--cache-to` flag with an unchecked value. The fake | ||
| // runtime already records every invocation unconditionally, so both are | ||
| // present in the same recorded args log used above. | ||
| var createLine string | ||
| for _, line := range lines { | ||
| createFields := strings.Split(line, "\t") | ||
| if len(createFields) > 1 && createFields[0] == "buildx" && createFields[1] == "create" { | ||
| createLine = line | ||
| break | ||
| } | ||
| } | ||
| require.NotEmpty(t, createLine, | ||
| "expected a `docker buildx create ...` invocation provisioning the configured driver; got invocations: %v", lines) | ||
| createFields := strings.Split(createLine, "\t") | ||
|
|
||
| flagValueCases := []struct { | ||
| name string | ||
| fields []string | ||
| flag string | ||
| want string | ||
| }{ | ||
| {"builder uses configured driver provider", createFields, "--driver", "docker-container"}, | ||
| {"builder uses configured driver image opt", createFields, "--driver-opt", "image=mirror.gcr.io/moby/buildkit:buildx-stable-1"}, | ||
| {"cache-from carries the configured ref", fields, "--cache-from", "ref=example.invalid/demo:buildcache,type=registry"}, | ||
| {"cache-to carries the configured ref and mode=max", fields, "--cache-to", "mode=max,ref=example.invalid/demo:buildcache,type=registry"}, | ||
| } | ||
| for _, tc := range flagValueCases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| assertFlagValue(t, tc.fields, tc.flag, tc.want) | ||
| }) | ||
| } | ||
| assert.Contains(t, createFields, "atmos-native-ci", "builder create must use the configured driver name") | ||
|
|
||
| // The exact bug report's symptom: Atmos must not fall back to a bare, | ||
| // unconfigured `docker build -f Dockerfile .`. | ||
| for _, line := range lines { | ||
| assert.NotEqual(t, "build\t-f\tDockerfile\t.", line, | ||
| "must not silently fall back to a bare, unconfigured docker build") | ||
| } | ||
| } | ||
|
|
||
| // assertFlagValue asserts fields contains flag immediately followed by want, | ||
| // so a flag's actual configured value is checked rather than merely its | ||
| // presence somewhere in the argv. | ||
| func assertFlagValue(t *testing.T, fields []string, flag, want string) { | ||
| t.Helper() | ||
|
|
||
| for i, field := range fields { | ||
| if field == flag { | ||
| if i+1 >= len(fields) { | ||
| t.Errorf("flag %q has no following value in %v", flag, fields) | ||
| return | ||
| } | ||
| assert.Equal(t, want, fields[i+1], "%s value", flag) | ||
| return | ||
| } | ||
| } | ||
| t.Errorf("expected flag %q not found in %v", flag, fields) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.