- Added unit tests for `ToTar` and `FromTar` in `pkg/datanode`, including a round-trip test and invalid input handling. - Added unit tests for `Walk` options (`MaxDepth`, `Filter`, `SkipErrors`) in `pkg/datanode`. - Added security tests for `pkg/tim` to verify protection against path traversal (Zip Slip) attacks and handling of invalid inputs. - Fixed `cmd` package tests execution by adding `TestHelperProcess` to `cmd/run_test.go` to support mocked command execution. - Increased coverage for `pkg/datanode` to 84.2%, `pkg/tim` to 74.2%, and `cmd` to 44.1%.
151 lines
3.6 KiB
Go
151 lines
3.6 KiB
Go
package tim
|
|
|
|
import (
|
|
"archive/tar"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestRun(t *testing.T) {
|
|
// Create a dummy tim file.
|
|
timPath := createDummyTim(t)
|
|
|
|
// Mock the exec.Command function.
|
|
origExecCommand := ExecCommand
|
|
ExecCommand = func(command string, args ...string) *exec.Cmd {
|
|
cs := []string{"-test.run=TestHelperProcess", "--", command}
|
|
cs = append(cs, args...)
|
|
cmd := exec.Command(os.Args[0], cs...)
|
|
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
|
|
return cmd
|
|
}
|
|
t.Cleanup(func() {
|
|
ExecCommand = origExecCommand
|
|
})
|
|
|
|
// Run the run command.
|
|
err := Run(timPath)
|
|
if err != nil {
|
|
t.Fatalf("run command failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRun_BadInput(t *testing.T) {
|
|
// Test non-existent file
|
|
err := Run("nonexistent.tim")
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent file, got nil")
|
|
}
|
|
|
|
// Test invalid file (not a tar)
|
|
f, err := os.CreateTemp("", "bad-tim-*.tim")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(f.Name())
|
|
f.Write([]byte("not a tar file"))
|
|
f.Close()
|
|
|
|
// Mock ExecCommand to fail if run called
|
|
origExecCommand := ExecCommand
|
|
ExecCommand = func(command string, args ...string) *exec.Cmd {
|
|
// If we reach here, it means we tried to run runc.
|
|
// For a bad tar, we might still reach here.
|
|
// Let's just return a command that fails.
|
|
return exec.Command("false")
|
|
}
|
|
t.Cleanup(func() { ExecCommand = origExecCommand })
|
|
|
|
err = Run(f.Name())
|
|
if err == nil {
|
|
t.Error("expected error when running bad tim file")
|
|
}
|
|
}
|
|
|
|
func TestRun_ZipSlip(t *testing.T) {
|
|
// Create a malicious tim file with ../ path
|
|
file, err := os.CreateTemp("", "zipslip-*.tim")
|
|
if err != nil {
|
|
t.Fatalf("failed to create temp file: %v", err)
|
|
}
|
|
defer os.Remove(file.Name())
|
|
defer file.Close()
|
|
|
|
tw := tar.NewWriter(file)
|
|
|
|
hdr := &tar.Header{
|
|
Name: "../evil.txt",
|
|
Mode: 0600,
|
|
Size: 4,
|
|
Typeflag: tar.TypeReg,
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := tw.Write([]byte("evil")); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tw.Close()
|
|
|
|
err = Run(file.Name())
|
|
if err == nil {
|
|
t.Fatal("expected error for zip slip attempt, got nil")
|
|
}
|
|
if !strings.Contains(err.Error(), "invalid file path") {
|
|
t.Errorf("expected 'invalid file path' error, got: %v", err)
|
|
}
|
|
}
|
|
|
|
// createDummyTim creates a valid, empty tim file for testing.
|
|
func createDummyTim(t *testing.T) string {
|
|
t.Helper()
|
|
// Create a dummy tim file.
|
|
file, err := os.CreateTemp("", "tim-*.tim")
|
|
if err != nil {
|
|
t.Fatalf("failed to create dummy tim file: %v", err)
|
|
}
|
|
defer file.Close()
|
|
|
|
tw := tar.NewWriter(file)
|
|
|
|
// Add a dummy config.json. This is not a valid config, but it's enough to test the run command.
|
|
configContent := []byte(`{}`)
|
|
hdr := &tar.Header{
|
|
Name: "config.json",
|
|
Mode: 0600,
|
|
Size: int64(len(configContent)),
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
t.Fatalf("failed to write tar header: %v", err)
|
|
}
|
|
if _, err := tw.Write(configContent); err != nil {
|
|
t.Fatalf("failed to write tar content: %v", err)
|
|
}
|
|
|
|
// Add the rootfs directory.
|
|
hdr = &tar.Header{
|
|
Name: "rootfs/",
|
|
Mode: 0755,
|
|
Typeflag: tar.TypeDir,
|
|
}
|
|
if err := tw.WriteHeader(hdr); err != nil {
|
|
t.Fatalf("failed to write tar header: %v", err)
|
|
}
|
|
|
|
if err := tw.Close(); err != nil {
|
|
t.Fatalf("failed to close tar writer: %v", err)
|
|
}
|
|
return file.Name()
|
|
}
|
|
|
|
// TestHelperProcess isn't a real test. It's used as a helper for tests that need to mock exec.Command.
|
|
func TestHelperProcess(t *testing.T) {
|
|
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
|
|
return
|
|
}
|
|
// The rest of the arguments are the command and its arguments.
|
|
// In our case, we don't need to do anything with them.
|
|
os.Exit(0)
|
|
}
|