mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
fix: MacOS MDM based Deployment (#277)
* fix: MacOS MDM deployment script * fix: Handle shell alias for bash on macos * fix: Code review fixes * fix: Code review fixes * feat: Add support for global config file * feat: Add support for global config file * fix: Code review fixes * fix: Avoid blocking CLI for analytics flush
This commit is contained in:
@@ -1,10 +1,16 @@
|
||||
package alias
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestShellPathExport(t *testing.T) {
|
||||
@@ -53,6 +59,207 @@ func TestShellPathExport(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrimaryShellName(t *testing.T) {
|
||||
t.Run("from SHELL", func(t *testing.T) {
|
||||
t.Setenv("SHELL", "/usr/bin/fish")
|
||||
assert.Equal(t, "fish", PrimaryShellName())
|
||||
})
|
||||
|
||||
t.Run("falls back to OS default when unset", func(t *testing.T) {
|
||||
t.Setenv("SHELL", "")
|
||||
want := "bash"
|
||||
if runtime.GOOS == "darwin" {
|
||||
want = "zsh"
|
||||
}
|
||||
assert.Equal(t, want, PrimaryShellName())
|
||||
})
|
||||
}
|
||||
|
||||
func TestBashInstallRcFiles(t *testing.T) {
|
||||
const (
|
||||
bashrc = ".bashrc"
|
||||
bashProfile = ".bash_profile"
|
||||
profile = ".profile"
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
goos string
|
||||
create bool
|
||||
existing map[string]string
|
||||
wantRel []string
|
||||
wantMade []string
|
||||
}{
|
||||
{
|
||||
name: "darwin bashrc only, primary also creates bash_profile",
|
||||
goos: "darwin",
|
||||
create: true,
|
||||
existing: map[string]string{bashrc: "# bashrc\n"},
|
||||
wantRel: []string{bashrc, bashProfile},
|
||||
wantMade: []string{bashProfile},
|
||||
},
|
||||
{
|
||||
name: "darwin login already sources bashrc is skipped",
|
||||
goos: "darwin",
|
||||
create: true,
|
||||
existing: map[string]string{bashrc: "# bashrc\n", bashProfile: "source ~/.bashrc\n"},
|
||||
wantRel: []string{bashrc},
|
||||
},
|
||||
{
|
||||
name: "darwin login not sourcing bashrc gets both",
|
||||
goos: "darwin",
|
||||
create: true,
|
||||
existing: map[string]string{bashrc: "# bashrc\n", bashProfile: "# profile\n"},
|
||||
wantRel: []string{bashrc, bashProfile},
|
||||
},
|
||||
{
|
||||
name: "darwin login only mentions bashrc in a comment gets both",
|
||||
goos: "darwin",
|
||||
create: true,
|
||||
existing: map[string]string{bashrc: "# bashrc\n", bashProfile: "# see ~/.bashrc\n"},
|
||||
wantRel: []string{bashrc, bashProfile},
|
||||
},
|
||||
{
|
||||
name: "darwin nothing exists, primary creates bash_profile",
|
||||
goos: "darwin",
|
||||
create: true,
|
||||
existing: map[string]string{},
|
||||
wantRel: []string{bashProfile},
|
||||
wantMade: []string{bashProfile},
|
||||
},
|
||||
{
|
||||
name: "darwin nothing exists, non-primary creates nothing",
|
||||
goos: "darwin",
|
||||
create: false,
|
||||
existing: map[string]string{},
|
||||
wantRel: nil,
|
||||
},
|
||||
{
|
||||
name: "linux bashrc only does not create bash_profile",
|
||||
goos: "linux",
|
||||
create: true,
|
||||
existing: map[string]string{bashrc: "# bashrc\n"},
|
||||
wantRel: []string{bashrc},
|
||||
},
|
||||
{
|
||||
name: "linux nothing exists, primary creates bashrc",
|
||||
goos: "linux",
|
||||
create: true,
|
||||
existing: map[string]string{},
|
||||
wantRel: []string{bashrc},
|
||||
wantMade: []string{bashrc},
|
||||
},
|
||||
{
|
||||
name: "existing login file wired even when non-primary",
|
||||
goos: "linux",
|
||||
create: false,
|
||||
existing: map[string]string{profile: "# profile\n"},
|
||||
wantRel: []string{profile},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
home := t.TempDir()
|
||||
for name, content := range tc.existing {
|
||||
require.NoError(t, os.WriteFile(filepath.Join(home, name), []byte(content), 0o644))
|
||||
}
|
||||
|
||||
got, err := bashInstallRcFiles(home, tc.create, tc.goos)
|
||||
require.NoError(t, err)
|
||||
|
||||
want := make([]string, 0, len(tc.wantRel))
|
||||
for _, rel := range tc.wantRel {
|
||||
want = append(want, filepath.Join(home, rel))
|
||||
}
|
||||
assert.ElementsMatch(t, want, got)
|
||||
|
||||
for _, rel := range tc.wantMade {
|
||||
assert.FileExists(t, filepath.Join(home, rel))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReferencesBashrc(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
content string
|
||||
want bool
|
||||
}{
|
||||
{"source with tilde", "source ~/.bashrc\n", true},
|
||||
{"dot command", ". ~/.bashrc\n", true},
|
||||
{"quoted home var", "[ -f \"$HOME/.bashrc\" ] && source \"$HOME/.bashrc\"\n", true},
|
||||
{"conditional dot", "[ -f ~/.bashrc ] && . ~/.bashrc\n", true},
|
||||
{"commented mention", "# see ~/.bashrc for details\n", false},
|
||||
{"inline comment", "echo hi # ~/.bashrc\n", false},
|
||||
{"unrelated command", "cat ~/.bashrc\n", false},
|
||||
{"different file", "source ~/.bashrc-backup\n", false},
|
||||
{"no mention", "export PATH=/usr/bin\n", false},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "profile")
|
||||
require.NoError(t, os.WriteFile(path, []byte(tc.content), 0o644))
|
||||
assert.Equal(t, tc.want, referencesBashrc(path))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRewriteFileDroppingLines(t *testing.T) {
|
||||
t.Run("drops matching lines and keeps the rest", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "rc")
|
||||
require.NoError(t, os.WriteFile(path, []byte("keep1\ndrop me\nkeep2\n"), 0o644))
|
||||
|
||||
err := RewriteFileDroppingLines(path, func(line string) bool {
|
||||
return strings.Contains(line, "drop")
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "keep1\nkeep2\n", string(data))
|
||||
|
||||
info, err := os.Stat(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, os.FileMode(0o644), info.Mode().Perm())
|
||||
})
|
||||
|
||||
t.Run("preserves a line longer than the scanner token limit", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "rc")
|
||||
longLine := strings.Repeat("x", bufio.MaxScanTokenSize+1024)
|
||||
require.NoError(t, os.WriteFile(path, []byte(longLine+"\nPMG drop\nafter\n"), 0o644))
|
||||
|
||||
err := RewriteFileDroppingLines(path, func(line string) bool {
|
||||
return strings.Contains(line, "PMG drop")
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, longLine+"\nafter\n", string(data))
|
||||
})
|
||||
|
||||
t.Run("leaves the file untouched when nothing matches", func(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "rc")
|
||||
original := "line1\nline2"
|
||||
require.NoError(t, os.WriteFile(path, []byte(original), 0o644))
|
||||
|
||||
err := RewriteFileDroppingLines(path, func(string) bool { return false })
|
||||
require.NoError(t, err)
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, original, string(data))
|
||||
})
|
||||
|
||||
t.Run("missing file is a no-op", func(t *testing.T) {
|
||||
err := RewriteFileDroppingLines(filepath.Join(t.TempDir(), "nope"), func(string) bool { return true })
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestDetectShell(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user