Skip to content

Commit

Permalink
feat:[CI-15236]: Added IMAGE_TAR_PATH as output variable for the plug…
Browse files Browse the repository at this point in the history
…in. (#132)

* feat:[CI-15236]: Added PLUGIN_TAR_PATH as output variable for the plugin.

* feat:[CI-15236]: Added PLUGIN_TAR_PATH as output variable for the plugin.

* feat:[CI-15236]: Added PLUGIN_TAR_PATH as output variable for the plugin.

* feat:[CI-15236]: Added PLUGIN_TAR_PATH as output variable for the plugin.

* feat:[CI-15236]: Test commit.

* feat:[CI-15236]: Test commit.

* feat:[CI-15236]: Added PLUGIN_TAR_PATH as output variable for the plugin.

* feat:[CI-15236]: Directory check and UTs.

* Update pkg/output/output.go

* feat:[CI-15236]: fixes

* feat:[CI-15236]: Test fixes - removed root

* feat:[CI-15236]: Test fixes - removed root

* feat:[CI-15236]: Test fixes - removed root

* feat:[CI-15236]: If tarPath directory no present it will create it.

* feat:[CI-15236]: If tarPath directory no present it will create it.

* feat:[CI-15236]: fixes

* Update kaniko.go

removed as getTarPath is only called when tarPath isn't empty

---------

Co-authored-by: OP (oppenheimer) <[email protected]>
  • Loading branch information
Anshika2203 and Ompragash authored Nov 28, 2024
1 parent 113a61b commit e6ab8aa
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 4 deletions.
22 changes: 21 additions & 1 deletion kaniko.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/drone/drone-kaniko/pkg/artifact"
Expand Down Expand Up @@ -258,6 +259,12 @@ func (p Plugin) Exec() error {
}

if p.Build.TarPath != "" {
tarDir := filepath.Dir(p.Build.TarPath)
if _, err := os.Stat(tarDir); os.IsNotExist(err) {
if mkdirErr := os.MkdirAll(tarDir, 0755); mkdirErr != nil {
return fmt.Errorf("failed to create directory for tar path %s: %v", tarDir, mkdirErr)
}
}
cmdArgs = append(cmdArgs, fmt.Sprintf("--tar-path=%s", p.Build.TarPath))
}

Expand Down Expand Up @@ -407,14 +414,27 @@ func (p Plugin) Exec() error {
}

if p.Output.OutputFile != "" {
if err = output.WritePluginOutputFile(p.Output.OutputFile, getDigest(p.Build.DigestFile)); err != nil {
var tarPath string
if p.Build.TarPath != "" {
tarPath = getTarPath(p.Build.TarPath)
}
if err = output.WritePluginOutputFile(p.Output.OutputFile, getDigest(p.Build.DigestFile), tarPath); err != nil {
fmt.Fprintf(os.Stderr, "failed to write plugin output file at path: %s with error: %s\n", p.Output.OutputFile, err)
}
}

return nil
}

func getTarPath(tarPath string) string {
tarDir := filepath.Dir(tarPath)
if _, err := os.Stat(tarDir); err != nil && os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "Warning: tar path does not exist: %s\n", tarPath)
return ""
}
return tarPath
}

func getDigest(digestFile string) string {
content, err := ioutil.ReadFile(digestFile)
if err != nil {
Expand Down
132 changes: 132 additions & 0 deletions kaniko_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package kaniko

import (
"os"
"path/filepath"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -148,3 +150,133 @@ func TestBuild_AutoTags(t *testing.T) {
}
})
}

func TestTarPathValidation(t *testing.T) {
tests := []struct {
name string
tarPath string
setup func(string) error
cleanup func(string) error
expectSuccess bool
privileged bool
}{
{
name: "valid_path_privileged",
tarPath: "",
setup: func(path string) error {
tmpDir, err := os.MkdirTemp("", "test-image-tar")
if err != nil {
return err
}
os.Setenv("DRONE_WORKSPACE", tmpDir)
return nil
},
cleanup: func(path string) error {
tmpDir := os.Getenv("DRONE_WORKSPACE")
os.Unsetenv("DRONE_WORKSPACE")
return os.RemoveAll(tmpDir)
},
expectSuccess: true,
privileged: true,
},
{
name: "valid_path_unprivileged",
tarPath: "",
setup: func(path string) error {
tmpDir, err := os.MkdirTemp("", "test-image-tar")
if err != nil {
return err
}
os.Setenv("DRONE_WORKSPACE", tmpDir)
return nil
},
cleanup: func(path string) error {
tmpDir := os.Getenv("DRONE_WORKSPACE")
os.Unsetenv("DRONE_WORKSPACE")
return os.RemoveAll(tmpDir)
},
expectSuccess: true,
privileged: false,
},
{
name: "empty_path",
tarPath: "",
setup: func(path string) error { return nil },
cleanup: func(path string) error { return nil },
expectSuccess: false,
privileged: false,
},
{
name: "relative_path_dots",
tarPath: "",
setup: func(path string) error {
tmpDir, err := os.MkdirTemp("", "test-image-tar")
if err != nil {
return err
}
os.Setenv("DRONE_WORKSPACE", tmpDir)
return nil
},
cleanup: func(path string) error {
tmpDir := os.Getenv("DRONE_WORKSPACE")
os.Unsetenv("DRONE_WORKSPACE")
return os.RemoveAll(tmpDir)
},
expectSuccess: true,
privileged: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Skip privileged tests if not running as root
if tt.privileged && os.Getuid() != 0 {
t.Skip("Skipping privileged test as not running as root")
}

if err := tt.setup(tt.tarPath); err != nil {
t.Fatalf("Setup failed: %v", err)
}
defer tt.cleanup(tt.tarPath)

// Determine tar path based on test case
var tarPath string
tmpDir := os.Getenv("DRONE_WORKSPACE")
switch tt.name {
case "valid_path_privileged", "valid_path_unprivileged":
tarPath = filepath.Join(tmpDir, "test", "image.tar")
case "invalid_path_no_permissions":
tarPath = "/test/image.tar"
case "relative_path_dots":
tarPath = filepath.Join("..", "test", "image.tar")
default:
tarPath = tt.tarPath
}

p := Plugin{
Build: Build{
TarPath: tarPath,
},
}

tarDir := filepath.Dir(p.Build.TarPath)
err := os.MkdirAll(tarDir, 0755)
if tt.expectSuccess {
if err != nil {
t.Errorf("Expected directory creation to succeed, got error: %v", err)
}
if _, err := os.Stat(tarDir); err != nil {
t.Errorf("Expected directory to exist after creation, got error: %v", err)
}
}

result := getTarPath(p.Build.TarPath)
if tt.expectSuccess && result == "" {
t.Error("Expected non-empty tar path, got empty string")
}
if !tt.expectSuccess && result != "" {
t.Error("Expected empty tar path, got non-empty string")
}
})
}
}
12 changes: 9 additions & 3 deletions pkg/output/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import (
"github.com/joho/godotenv"
)

func WritePluginOutputFile(outputFilePath, digest string) error {
output := map[string]string{
"digest": digest,
func WritePluginOutputFile(outputFilePath, digest string, pluginTarPath string) error {
output := make(map[string]string)
if digest != "" {
output["digest"] = digest
}

if pluginTarPath != "" {
output["IMAGE_TAR_PATH"] = pluginTarPath
}

return godotenv.Write(output, outputFilePath)
}
145 changes: 145 additions & 0 deletions pkg/output/output_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package output

import (
"os"
"path/filepath"
"testing"
)

func TestWritePluginOutputFile(t *testing.T) {
tests := []struct {
name string
outputPath string
digest string
tarPath string
setup func(string) error
cleanup func(string) error
expectError bool
privileged bool
}{
{
name: "valid_output_privileged",
outputPath: "",
digest: "sha256:test",
tarPath: "",
setup: func(path string) error {
tmpDir, err := os.MkdirTemp("", "test-output")
if err != nil {
return err
}
os.Setenv("DRONE_WORKSPACE", tmpDir)
return nil
},
cleanup: func(path string) error {
tmpDir := os.Getenv("DRONE_WORKSPACE")
os.Unsetenv("DRONE_WORKSPACE")
return os.RemoveAll(tmpDir)
},
expectError: false,
privileged: true,
},
{
name: "valid_output_unprivileged",
outputPath: "",
digest: "sha256:test",
tarPath: "",
setup: func(path string) error {
tmpDir, err := os.MkdirTemp("", "test-output")
if err != nil {
return err
}
os.Setenv("DRONE_WORKSPACE", tmpDir)
return nil
},
cleanup: func(path string) error {
tmpDir := os.Getenv("DRONE_WORKSPACE")
os.Unsetenv("DRONE_WORKSPACE")
return os.RemoveAll(tmpDir)
},
expectError: false,
privileged: false,
},
{
name: "digest_only",
outputPath: "",
digest: "sha256:test",
tarPath: "",
setup: func(path string) error {
tmpDir, err := os.MkdirTemp("", "test-output")
if err != nil {
return err
}
os.Setenv("DRONE_WORKSPACE", tmpDir)
return nil
},
cleanup: func(path string) error {
tmpDir := os.Getenv("DRONE_WORKSPACE")
os.Unsetenv("DRONE_WORKSPACE")
return os.RemoveAll(tmpDir)
},
expectError: false,
privileged: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Skip privileged tests if not running as root
if tt.privileged && os.Getuid() != 0 {
t.Skip("Skipping privileged test as not running as root")
}

if err := tt.setup(tt.outputPath); err != nil {
t.Fatalf("Setup failed: %v", err)
}
defer tt.cleanup(tt.outputPath)

tmpDir := os.Getenv("DRONE_WORKSPACE")
var outputPath, tarPath string
switch tt.name {
case "valid_output_privileged", "valid_output_unprivileged":
outputPath = filepath.Join(tmpDir, "test", "output.env")
tarPath = filepath.Join(tmpDir, "test", "image.tar")
case "invalid_output_path":
outputPath = filepath.Join("/root", "test", "output.env")
tarPath = filepath.Join("/root", "test", "image.tar")
case "digest_only":
outputPath = filepath.Join(tmpDir, "test", "output.env")
tarPath = ""
}

err := os.MkdirAll(filepath.Dir(outputPath), 0755)
if err != nil {
t.Fatalf("Failed to create output directory: %v", err)
}

err = WritePluginOutputFile(outputPath, tt.digest, tarPath)

if tt.expectError && err == nil {
t.Error("Expected error, got none")
}
if !tt.expectError && err != nil {
t.Errorf("Expected no error, got: %v", err)
}

if !tt.expectError && err == nil {
content, err := os.ReadFile(outputPath)
if err != nil {
t.Fatalf("Failed to read output file: %v", err)
}

if tt.digest != "" && !contains(string(content), tt.digest) {
t.Error("Expected digest in output file")
}

if tarPath != "" && !contains(string(content), tarPath) {
t.Error("Expected tar path in output file")
}
}
})
}
}

func contains(content, substring string) bool {
return len(substring) > 0 && content != "" && content != "\n" && content != "\r\n"
}

0 comments on commit e6ab8aa

Please sign in to comment.