test(01-04): cover tool, output, watch loop and workspace modules

- Non-TTY widgets/prompts, flag parsing, secret non-leak and malicious IDs
- Real hello workspace rebuild latency line, debounce and ignored bin/tmp
- scripts/check-phase1.sh runs vet/test/race across root, hello, base, greeter, optional
This commit is contained in:
Jakub Zych
2026-09-16 14:14:05 +02:00
parent a43c734546
commit dc7997e45c
6 changed files with 542 additions and 2 deletions

View File

@@ -263,6 +263,65 @@ func TestAddPluginRejectsPathTraversal(t *testing.T) {
}
}
func TestParseManifestRejectsDuplicateModule(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "dupmod.yaml")
write(t, path, "module: example.com/app\nbinary: app\nplugins:\n - id: a.b\n module: example.com/one\n - id: a.c\n module: example.com/one\n")
if _, err := LoadManifest(path); err == nil || !strings.Contains(err.Error(), "example.com/one") {
t.Fatalf("want duplicate module error, got %v", err)
}
}
func TestMakePluginRejectsPathTraversalAndShellMeta(t *testing.T) {
dir := t.TempDir()
write(t, filepath.Join(dir, "summer.yaml"), "module: example.com/app\nbinary: app\nplugins:\n")
write(t, filepath.Join(dir, "go.mod"), "module example.com/app\n\ngo 1.27.0\n")
for _, id := range []string{
"golem15.demo/../tmp",
"golem15.demo;rm",
`golem15.demo$(x)`,
"golem15.demo`x`",
"/tmp.evil",
"..evil.plugin",
} {
if _, err := MakePlugin(t.Context(), dir, id); err == nil {
t.Fatalf("id %q: want error", id)
}
}
}
func TestBuiltHelloFailsOnInvalidRequires(t *testing.T) {
dir := copyHelloApp(t)
path := filepath.Join(dir, "plugins", "greeter", "plugin.go")
src, err := os.ReadFile(path)
if err != nil {
t.Fatal(err)
}
patched := bytes.ReplaceAll(src, []byte(`return []string{"golem15.hello"}`), []byte(`return []string{"golem15.hello", "golem15.missing"}`))
if bytes.Equal(src, patched) {
t.Fatal("failed to patch greeter Requires")
}
if err := os.WriteFile(path, patched, 0o644); err != nil {
t.Fatal(err)
}
var buf bytes.Buffer
if err := App(t.Context(), dir, &buf); err != nil {
t.Fatalf("build should succeed, got %v\n%s", err, buf.String())
}
bin := filepath.Join(dir, "bin", "hello")
cmd := exec.CommandContext(t.Context(), bin, "greeter:hello")
cmd.Dir = dir
out, err := cmd.CombinedOutput()
if err == nil {
t.Fatalf("expected non-zero exit for missing Requires, output:\n%s", out)
}
msg := string(out)
if !strings.Contains(msg, "golem15.greeter") || !strings.Contains(msg, "golem15.missing") {
t.Fatalf("error should name both plugin IDs, got %q", msg)
}
}
func TestParseManifestRejectsUppercaseID(t *testing.T) {
dir := t.TempDir()
path := filepath.Join(dir, "bad.yaml")