Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkg/generator/source/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ func resolveRemote(atmosConfig *schema.AtmosConfiguration, name, src string, tim
cleanup()
return nil, noop, err
}
// tempDir only exists to read files off disk and is removed by cleanup()
// once generation finishes; the recorded provenance must be the original
// source the caller passed in, not that ephemeral fetch destination.
conf.Source = src
return conf, cleanup, nil
}

Expand Down
61 changes: 61 additions & 0 deletions pkg/generator/source/resolver_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package source

import (
"archive/zip"
"bytes"
"net/http"
"net/http/httptest"
"net/url"
"os"
"os/exec"
Expand Down Expand Up @@ -71,6 +75,7 @@ func TestResolve_LocalPath(t *testing.T) {
defer cleanup()
require.NotNil(t, cfg)
assert.True(t, hasSampleFile(cfg.Files), "local template files must be loaded")
assert.Equal(t, dir, cfg.Source, "local sources must record the original path")
}

func TestResolve_LocalPathDefaultTimeout(t *testing.T) {
Expand Down Expand Up @@ -152,6 +157,7 @@ func TestHydrate_LocalStub(t *testing.T) {
require.NoError(t, err)
defer cleanup()
assert.True(t, hasSampleFile(stub.Files), "local stub must be hydrated from its source")
assert.Equal(t, dir, stub.Source, "hydrate's *stub = *resolved copy must preserve the original source")
}

func TestHydrate_LocalStubError(t *testing.T) {
Expand Down Expand Up @@ -233,6 +239,61 @@ func TestResolve_RemoteGitSubdirSuccess(t *testing.T) {
assert.True(t, hasSampleFile(cfg.Files), "remote git subdir template files must be loaded")
}

// zipArchive builds an in-memory ZIP archive containing the given files.
// go-getter's HTTP getter unpacks a recognized archive extension (.zip
// included) directly, so serving one over httptest.Server exercises a real
// remote (ClientModeDir) fetch through resolveRemote without needing git or
// any other external binary.
func zipArchive(t *testing.T, files map[string]string) []byte {
t.Helper()

var buf bytes.Buffer
zw := zip.NewWriter(&buf)
for name, content := range files {
w, err := zw.Create(name)
require.NoError(t, err)
_, err = w.Write([]byte(content))
require.NoError(t, err)
}
require.NoError(t, zw.Close())
return buf.Bytes()
}

// TestResolve_RemoteRecordsOriginalSource pins the bug where a remote
// (git::/https://) scaffold source ended up with Configuration.Source (and
// therefore the persisted spec.source in .atmos/scaffold.yaml) set to the
// ephemeral os.MkdirTemp download directory instead of the original source
// string. That tempdir is removed by cleanup() as soon as the command
// finishes, leaving spec.source pointing at nothing.
//
// Serves a ZIP archive from a local httptest.Server rather than using a git
// fixture: the ".zip" extension is enough for go-getter's HTTP getter to
// unpack it into the temp dir on its own, so this test never shells out to
// git (or any other external binary) and stays hermetic/cross-platform.
func TestResolve_RemoteRecordsOriginalSource(t *testing.T) {
archive := zipArchive(t, map[string]string{
"scaffold.yaml": sampleScaffold,
"file.txt": "hello",
})

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "application/zip")
_, _ = w.Write(archive)
}))
defer server.Close()

src := server.URL + "/template.zip"

cfg, cleanup, err := Resolve(&schema.AtmosConfiguration{}, "sample", src, time.Minute)
require.NoError(t, err)
require.NotNil(t, cleanup)
defer cleanup()
require.NotNil(t, cfg)

assert.True(t, hasSampleFile(cfg.Files), "remote archive template files must be loaded")
assert.Equal(t, src, cfg.Source, "remote sources must record the original source string, not the ephemeral fetch tempdir")
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

// TestResolve_RemoteGitSubdirMissing pins the exact failure mode reported for
// `atmos init aws/app`: a valid git remote whose requested //subdir does not exist.
func TestResolve_RemoteGitSubdirMissing(t *testing.T) {
Expand Down
Loading