package scoutpkg import ( "archive/zip" "bytes" "encoding/json" "os" "path/filepath" "testing" ) func TestNormalizeAndMatchTarget(t *testing.T) { targets := []Target{ {Platform: "any", Architecture: "universal", Path: "targets/all"}, {Platform: "linux", Architecture: "universal", Path: "targets/linux"}, {Platform: "linux", Architecture: "amd64", Path: "targets/linux-amd64"}, } target, ok := MatchTarget(targets, "linux", "x86_64") if !ok || target.Path != "targets/linux-amd64" { t.Fatalf("目标匹配错误: %+v", target) } target, ok = MatchTarget(targets, "linux", "arm64") if !ok || target.Path != "targets/linux" { t.Fatalf("通用目标匹配错误: %+v", target) } } func TestOpenAndExtract(t *testing.T) { archivePath := filepath.Join(t.TempDir(), "demo.scout") manifest := Manifest{ SchemaVersion: 1, Name: "demo-core", Version: "1.2.0", Channel: "stable", PackageType: "full", Targets: []Target{{ Platform: "linux", Architecture: "amd64", Path: "targets/linux/amd64", Entrypoint: "targets/linux/amd64/demo", }}, } createArchive(t, archivePath, manifest, map[string][]byte{ "targets/linux/amd64/demo": []byte("binary"), }) archive, err := Open(archivePath) if err != nil { t.Fatal(err) } defer archive.Close() destination := filepath.Join(t.TempDir(), "release") target, err := archive.Extract("linux", "amd64", destination) if err != nil { t.Fatal(err) } if target.Entrypoint != "targets/linux/amd64/demo" { t.Fatalf("启动入口错误: %s", target.Entrypoint) } content, err := os.ReadFile(filepath.Join(destination, "demo")) if err != nil || string(content) != "binary" { t.Fatalf("解压结果错误: %q, %v", content, err) } } func TestRejectsPathTraversal(t *testing.T) { archivePath := filepath.Join(t.TempDir(), "unsafe.scout") buffer := bytes.NewBuffer(nil) writer := zip.NewWriter(buffer) manifest := Manifest{ SchemaVersion: 1, Name: "unsafe", Version: "1.0.0", Targets: []Target{{ Platform: "linux", Architecture: "amd64", Path: "targets/linux/amd64", }}, } manifestData, _ := json.Marshal(manifest) entry, _ := writer.Create(ManifestName) _, _ = entry.Write(manifestData) entry, _ = writer.Create("../escape") _, _ = entry.Write([]byte("unsafe")) _ = writer.Close() if err := os.WriteFile(archivePath, buffer.Bytes(), 0o644); err != nil { t.Fatal(err) } if _, err := Open(archivePath); err == nil { t.Fatal("路径穿越包没有被拒绝") } } func createArchive(t *testing.T, fileName string, manifest Manifest, files map[string][]byte) { t.Helper() output, err := os.Create(fileName) if err != nil { t.Fatal(err) } writer := zip.NewWriter(output) manifestData, err := json.Marshal(manifest) if err != nil { t.Fatal(err) } entry, err := writer.Create(ManifestName) if err != nil { t.Fatal(err) } if _, err := entry.Write(manifestData); err != nil { t.Fatal(err) } for name, content := range files { entry, err := writer.Create(name) if err != nil { t.Fatal(err) } if _, err := entry.Write(content); err != nil { t.Fatal(err) } } if err := writer.Close(); err != nil { t.Fatal(err) } if err := output.Close(); err != nil { t.Fatal(err) } }