fix(agent): give compose.override.yaml the owner of the stack (#24) (#26)
Docker Build / docker (push) Successful in 40s
Docker Build / docker (push) Successful in 40s
This commit was merged in pull request #26.
This commit is contained in:
@@ -29,11 +29,96 @@ func serviceImage(doc map[string]any, name string) any {
|
||||
return entry["image"]
|
||||
}
|
||||
|
||||
// stackFile creates dir/compose.yaml and returns its path.
|
||||
func stackFile(t *testing.T, dir string) string {
|
||||
t.Helper()
|
||||
p := filepath.Join(dir, "compose.yaml")
|
||||
require.NoError(t, os.WriteFile(p, []byte("services: {}\n"), 0o644))
|
||||
return p
|
||||
}
|
||||
|
||||
func TestPickOwner(t *testing.T) {
|
||||
compose := fileOwner{1000, 1000}
|
||||
fromCompose := func() (fileOwner, error) { return compose, nil }
|
||||
failing := func() (fileOwner, error) { return fileOwner{}, errors.New("boom") }
|
||||
tests := []struct {
|
||||
name string
|
||||
override *fileOwner
|
||||
compose func() (fileOwner, error)
|
||||
want fileOwner
|
||||
wantErr bool
|
||||
}{
|
||||
{"no override uses the compose file", nil, fromCompose, compose, false},
|
||||
{"override owned by a user wins", &fileOwner{1001, 1002}, fromCompose, fileOwner{1001, 1002}, false},
|
||||
{"root-owned override uses the compose file", &fileOwner{0, 0}, fromCompose, compose, false},
|
||||
{"compose file is not read when the override decides", &fileOwner{1001, 1002}, failing, fileOwner{1001, 1002}, false},
|
||||
{"unreadable compose file is an error", nil, failing, fileOwner{}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := pickOwner(tt.override, tt.compose)
|
||||
assert.Equal(t, tt.wantErr, err != nil)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveOwner(t *testing.T) {
|
||||
me := fileOwner{os.Getuid(), os.Getgid()}
|
||||
t.Run("no override uses the compose file", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
got, err := resolveOwner(filepath.Join(dir, OverrideName), stackFile(t, dir))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, me, got)
|
||||
})
|
||||
t.Run("existing override is used without the compose file", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, OverrideName), nil, 0o644))
|
||||
got, err := resolveOwner(filepath.Join(dir, OverrideName), filepath.Join(dir, "missing.yaml"))
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, me, got)
|
||||
})
|
||||
t.Run("neither file is an error", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
_, err := resolveOwner(filepath.Join(dir, OverrideName), filepath.Join(dir, "missing.yaml"))
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteOverride_Owner(t *testing.T) {
|
||||
t.Run("success sets no ownerErr", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
_, ownerErr, err := WriteOverride(dir, "web", "a:1@sha256:aa", stackFile(t, dir))
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, ownerErr)
|
||||
})
|
||||
t.Run("unreadable owner is reported and the file is still written", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
_, ownerErr, err := WriteOverride(dir, "web", "a:1@sha256:aa", filepath.Join(dir, "missing.yaml"))
|
||||
require.NoError(t, err)
|
||||
assert.ErrorContains(t, ownerErr, "read owner")
|
||||
_, doc := readOverride(t, dir)
|
||||
assert.Equal(t, "a:1@sha256:aa", serviceImage(doc, "web"))
|
||||
})
|
||||
t.Run("chown failure is reported and the file is still written", func(t *testing.T) {
|
||||
if os.Getuid() == 0 {
|
||||
t.Skip("root can chown to anyone")
|
||||
}
|
||||
dir := t.TempDir()
|
||||
_, ownerErr, err := writeOverride(dir, "web", "a:1@sha256:aa", func() (fileOwner, error) { return fileOwner{0, 0}, nil })
|
||||
require.NoError(t, err)
|
||||
assert.ErrorContains(t, ownerErr, "set owner 0:0")
|
||||
_, doc := readOverride(t, dir)
|
||||
assert.Equal(t, "a:1@sha256:aa", serviceImage(doc, "web"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteOverride(t *testing.T) {
|
||||
t.Run("new file", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path, err := WriteOverride(dir, "web", "a:1@sha256:aa")
|
||||
path, ownerErr, err := WriteOverride(dir, "web", "a:1@sha256:aa", stackFile(t, dir))
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, ownerErr)
|
||||
assert.Equal(t, filepath.Join(dir, OverrideName), path)
|
||||
raw, doc := readOverride(t, dir)
|
||||
assert.True(t, len(raw) > len(overrideHeader) && raw[:len(overrideHeader)] == overrideHeader)
|
||||
@@ -42,7 +127,7 @@ func TestWriteOverride(t *testing.T) {
|
||||
t.Run("keeps other services", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, OverrideName), []byte(overrideHeader+"services:\n db:\n image: db:1\n"), 0o644))
|
||||
_, err := WriteOverride(dir, "web", "a:1@sha256:aa")
|
||||
_, _, err := WriteOverride(dir, "web", "a:1@sha256:aa", stackFile(t, dir))
|
||||
require.NoError(t, err)
|
||||
_, doc := readOverride(t, dir)
|
||||
assert.Equal(t, "db:1", serviceImage(doc, "db"))
|
||||
@@ -51,7 +136,7 @@ func TestWriteOverride(t *testing.T) {
|
||||
t.Run("replaces own entry", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, OverrideName), []byte(overrideHeader+"services:\n web:\n image: old\n"), 0o644))
|
||||
_, err := WriteOverride(dir, "web", "a:2@sha256:bb")
|
||||
_, _, err := WriteOverride(dir, "web", "a:2@sha256:bb", stackFile(t, dir))
|
||||
require.NoError(t, err)
|
||||
_, doc := readOverride(t, dir)
|
||||
assert.Equal(t, "a:2@sha256:bb", serviceImage(doc, "web"))
|
||||
@@ -60,7 +145,7 @@ func TestWriteOverride(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
const body = "services:\n web:\n environment: [A=1]\n"
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, OverrideName), []byte(body), 0o644))
|
||||
_, err := WriteOverride(dir, "web", "a:1@sha256:aa")
|
||||
_, _, err := WriteOverride(dir, "web", "a:1@sha256:aa", stackFile(t, dir))
|
||||
assert.ErrorContains(t, err, "refused")
|
||||
got, _ := os.ReadFile(filepath.Join(dir, OverrideName))
|
||||
assert.Equal(t, body, string(got))
|
||||
@@ -69,7 +154,7 @@ func TestWriteOverride(t *testing.T) {
|
||||
t.Run("refuses next to "+other, func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
require.NoError(t, os.WriteFile(filepath.Join(dir, other), []byte("services: {}\n"), 0o644))
|
||||
_, err := WriteOverride(dir, "web", "a:1@sha256:aa")
|
||||
_, _, err := WriteOverride(dir, "web", "a:1@sha256:aa", stackFile(t, dir))
|
||||
assert.ErrorContains(t, err, other)
|
||||
_, statErr := os.Stat(filepath.Join(dir, OverrideName))
|
||||
assert.True(t, errors.Is(statErr, os.ErrNotExist))
|
||||
@@ -77,12 +162,13 @@ func TestWriteOverride(t *testing.T) {
|
||||
}
|
||||
t.Run("leaves no temp files", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
_, err := WriteOverride(dir, "web", "a:1@sha256:aa")
|
||||
_, _, err := WriteOverride(dir, "web", "a:1@sha256:aa", stackFile(t, dir))
|
||||
require.NoError(t, err)
|
||||
entries, err := os.ReadDir(dir)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, entries, 1)
|
||||
assert.Equal(t, OverrideName, entries[0].Name())
|
||||
require.Len(t, entries, 2)
|
||||
assert.Equal(t, "compose.override.yaml", entries[0].Name())
|
||||
assert.Equal(t, "compose.yaml", entries[1].Name())
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user