mirror of
https://github.com/drone/drone-kaniko.git
synced 2026-06-14 14:02:33 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3af953651 | |||
| e6ab8aa3c0 | |||
| 113a61b0e1 | |||
| 982c141391 | |||
| f41d7cb836 | |||
| a71177d4b4 | |||
| 5582e3ed7c | |||
| 4c0f781999 | |||
| 20525e5403 | |||
| 04885c8ec8 |
+2
-2
@@ -11,7 +11,7 @@ platform:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: build
|
||||||
image: golang:1.22
|
image: golang:1.22.4
|
||||||
commands:
|
commands:
|
||||||
- go test ./...
|
- go test ./...
|
||||||
- sh scripts/build.sh
|
- sh scripts/build.sh
|
||||||
@@ -178,7 +178,7 @@ pool:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: build
|
||||||
image: golang:1.22
|
image: golang:1.22.4
|
||||||
commands:
|
commands:
|
||||||
- go test ./...
|
- go test ./...
|
||||||
- sh scripts/build.sh
|
- sh scripts/build.sh
|
||||||
|
|||||||
@@ -4,6 +4,12 @@ Drone kaniko plugin uses [kaniko](https://github.com/GoogleContainerTools/kaniko
|
|||||||
|
|
||||||
Plugin images are published with 1.6.0 as well as 1.9.1 kaniko version from 1.5.1 release tag. `plugins/kaniko:<release-tag>` uses 1.6.0 version while `plugins/kaniko:<release-tag>-kaniko1.9.1` uses 1.9.1 version. Similar convention is used for plugins/kaniko-ecr & plugins/kaniko-gcr images as well.
|
Plugin images are published with 1.6.0 as well as 1.9.1 kaniko version from 1.5.1 release tag. `plugins/kaniko:<release-tag>` uses 1.6.0 version while `plugins/kaniko:<release-tag>-kaniko1.9.1` uses 1.9.1 version. Similar convention is used for plugins/kaniko-ecr & plugins/kaniko-gcr images as well.
|
||||||
|
|
||||||
|
Run the following script to install git-leaks support to this repo.
|
||||||
|
```
|
||||||
|
chmod +x ./git-hooks/install.sh
|
||||||
|
./git-hooks/install.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Build the binaries with the following commands:
|
Build the binaries with the following commands:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
v2RegistryURL string = "https://index.docker.io/v2/" // v2 registry is not supported
|
v2RegistryURL string = "https://index.docker.io/v2/" // v2 registry is not supported
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateDockerConfigWithBaseRegistry(t *testing.T) {
|
func TestCreateDockerConfigWithBaseRegistry(t *testing.T) {
|
||||||
@@ -100,22 +100,7 @@ func TestCreateDockerConfigWithBaseRegistry(t *testing.T) {
|
|||||||
Password: "",
|
Password: "",
|
||||||
},
|
},
|
||||||
}, tempDir)
|
}, tempDir)
|
||||||
assert.NoError(t, err)
|
assert.EqualError(t, err, "Username must be specified for registry: "+dockerRegistry)
|
||||||
|
|
||||||
// v2 registry but without username password
|
|
||||||
err = config.CreateDockerConfig([]docker.RegistryCredentials{
|
|
||||||
{
|
|
||||||
Registry: registry,
|
|
||||||
Username: username,
|
|
||||||
Password: password,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Registry: v2RegistryURL,
|
|
||||||
Username: "",
|
|
||||||
Password: "",
|
|
||||||
},
|
|
||||||
}, tempDir)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
// private base registry without username/password
|
// private base registry without username/password
|
||||||
err = config.CreateDockerConfig([]docker.RegistryCredentials{
|
err = config.CreateDockerConfig([]docker.RegistryCredentials{
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/drone/drone-kaniko/pkg/docker"
|
||||||
|
)
|
||||||
|
|
||||||
func Test_buildRepo(t *testing.T) {
|
func Test_buildRepo(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -36,58 +42,80 @@ func Test_buildRepo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreateDockerConfigFromGivenRegistry(t *testing.T) {
|
func TestCreateDockerConfig(t *testing.T) {
|
||||||
|
config := docker.NewConfig()
|
||||||
|
tempDir, err := ioutil.TempDir("", "docker-config-test")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create temporary directory: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(tempDir)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
username string
|
credentials []docker.RegistryCredentials
|
||||||
password string
|
wantErr bool
|
||||||
registry string
|
|
||||||
dockerUsername string
|
|
||||||
dockerPassword string
|
|
||||||
dockerRegistry string
|
|
||||||
wantErr bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "valid credentials",
|
name: "valid credentials",
|
||||||
username: "testuser",
|
credentials: []docker.RegistryCredentials{
|
||||||
password: "testpassword",
|
{
|
||||||
registry: "https://index.docker.io/v1/",
|
Registry: "https://index.docker.io/v1/",
|
||||||
wantErr: false,
|
Username: "testuser",
|
||||||
|
Password: "testpassword",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "v2 registry",
|
name: "v2 registry",
|
||||||
username: "testuser",
|
credentials: []docker.RegistryCredentials{
|
||||||
password: "testpassword",
|
{
|
||||||
registry: "https://index.docker.io/v2/",
|
Registry: "https://index.docker.io/v2/",
|
||||||
wantErr: false,
|
Username: "testuser",
|
||||||
|
Password: "testpassword",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "docker registry credentials",
|
name: "docker registry credentials",
|
||||||
username: "testuser",
|
credentials: []docker.RegistryCredentials{
|
||||||
password: "testpassword",
|
{
|
||||||
registry: "https://index.docker.io/v1/",
|
Registry: "https://index.docker.io/v1/",
|
||||||
dockerUsername: "dockeruser",
|
Username: "testuser",
|
||||||
dockerPassword: "dockerpassword",
|
Password: "testpassword",
|
||||||
dockerRegistry: "https://docker.io",
|
},
|
||||||
wantErr: false,
|
{
|
||||||
|
Registry: "https://docker.io",
|
||||||
|
Username: "dockeruser",
|
||||||
|
Password: "dockerpassword",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty docker registry",
|
name: "empty docker registry",
|
||||||
username: "testuser",
|
credentials: []docker.RegistryCredentials{
|
||||||
password: "testpassword",
|
{
|
||||||
registry: "https://index.docker.io/v1/",
|
Registry: "https://index.docker.io/v1/",
|
||||||
dockerUsername: "dockeruser",
|
Username: "testuser",
|
||||||
dockerPassword: "",
|
Password: "testpassword",
|
||||||
dockerRegistry: "https://docker.io",
|
},
|
||||||
wantErr: false,
|
{
|
||||||
|
Registry: "https://docker.io",
|
||||||
|
Username: "dockeruser",
|
||||||
|
Password: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
err := createDockerConfig(tt.username, tt.password, tt.registry, tt.dockerUsername, tt.dockerPassword, tt.dockerRegistry)
|
err := config.CreateDockerConfig(tt.credentials, tempDir)
|
||||||
if (err != nil) != tt.wantErr {
|
if (err != nil) != tt.wantErr {
|
||||||
t.Errorf("createDockerConfig() error = %v, wantErr %v", err, tt.wantErr)
|
t.Errorf("CreateDockerConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CustomStringSliceFlag is like a regular StringSlice flag but with
|
||||||
|
// semicolon as a delimiter
|
||||||
|
type CustomStringSliceFlag struct {
|
||||||
|
Value []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CustomStringSliceFlag) GetValue() []string {
|
||||||
|
if f.Value == nil {
|
||||||
|
return make([]string, 0)
|
||||||
|
}
|
||||||
|
return f.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CustomStringSliceFlag) String() string {
|
||||||
|
if f.Value == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.Join(f.Value, ";")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *CustomStringSliceFlag) Set(v string) error {
|
||||||
|
for _, s := range strings.Split(v, ";") {
|
||||||
|
s = strings.TrimSpace(s)
|
||||||
|
f.Value = append(f.Value, s)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+76
-2
@@ -7,6 +7,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go-v2/aws"
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
"github.com/aws/aws-sdk-go-v2/config"
|
"github.com/aws/aws-sdk-go-v2/config"
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
ecrv1 "github.com/aws/aws-sdk-go/service/ecr"
|
ecrv1 "github.com/aws/aws-sdk-go/service/ecr"
|
||||||
ecrpublicv1 "github.com/aws/aws-sdk-go/service/ecrpublic"
|
ecrpublicv1 "github.com/aws/aws-sdk-go/service/ecrpublic"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sts"
|
||||||
"github.com/aws/smithy-go"
|
"github.com/aws/smithy-go"
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
@@ -35,6 +37,7 @@ const (
|
|||||||
secretKeyEnv string = "AWS_SECRET_ACCESS_KEY"
|
secretKeyEnv string = "AWS_SECRET_ACCESS_KEY"
|
||||||
ecrPublicDomain string = "public.ecr.aws"
|
ecrPublicDomain string = "public.ecr.aws"
|
||||||
kanikoVersionEnv string = "KANIKO_VERSION"
|
kanikoVersionEnv string = "KANIKO_VERSION"
|
||||||
|
sessionKeyEnv string = "AWS_SESSION_TOKEN"
|
||||||
|
|
||||||
oneDotEightVersion string = "1.8.0"
|
oneDotEightVersion string = "1.8.0"
|
||||||
defaultDigestFile string = "/kaniko/digest-file"
|
defaultDigestFile string = "/kaniko/digest-file"
|
||||||
@@ -122,6 +125,17 @@ func main() {
|
|||||||
Usage: "build args",
|
Usage: "build args",
|
||||||
EnvVar: "PLUGIN_BUILD_ARGS",
|
EnvVar: "PLUGIN_BUILD_ARGS",
|
||||||
},
|
},
|
||||||
|
cli.GenericFlag{
|
||||||
|
Name: "args-new",
|
||||||
|
Usage: "build args new",
|
||||||
|
EnvVar: "PLUGIN_BUILD_ARGS_NEW",
|
||||||
|
Value: new(CustomStringSliceFlag),
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "plugin-multiple-build-agrs",
|
||||||
|
Usage: "plugin multiple build agrs",
|
||||||
|
EnvVar: "PLUGIN_MULTIPLE_BUILD_ARGS",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "target",
|
Name: "target",
|
||||||
Usage: "build target",
|
Usage: "build target",
|
||||||
@@ -384,6 +398,11 @@ func main() {
|
|||||||
Usage: "Number of retries for downloading base images.",
|
Usage: "Number of retries for downloading base images.",
|
||||||
EnvVar: "PLUGIN_IMAGE_DOWNLOAD_RETRY",
|
EnvVar: "PLUGIN_IMAGE_DOWNLOAD_RETRY",
|
||||||
},
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "oidc-token-id",
|
||||||
|
Usage: "OIDC token for assuming role via web identity",
|
||||||
|
EnvVar: "PLUGIN_OIDC_TOKEN_ID",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
@@ -398,6 +417,7 @@ func run(c *cli.Context) error {
|
|||||||
noPush := c.Bool("no-push")
|
noPush := c.Bool("no-push")
|
||||||
assumeRole := c.String("assume-role")
|
assumeRole := c.String("assume-role")
|
||||||
externalId := c.String("external-id")
|
externalId := c.String("external-id")
|
||||||
|
oidcToken := c.String("oidc-token-id")
|
||||||
|
|
||||||
// setup docker config for azure registry and base image docker registry
|
// setup docker config for azure registry and base image docker registry
|
||||||
err := setDockerAuth(
|
err := setDockerAuth(
|
||||||
@@ -411,6 +431,7 @@ func run(c *cli.Context) error {
|
|||||||
externalId,
|
externalId,
|
||||||
region,
|
region,
|
||||||
noPush,
|
noPush,
|
||||||
|
oidcToken,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to create docker config")
|
return errors.Wrap(err, "failed to create docker config")
|
||||||
@@ -454,6 +475,8 @@ func run(c *cli.Context) error {
|
|||||||
AutoTagSuffix: c.String("auto-tag-suffix"),
|
AutoTagSuffix: c.String("auto-tag-suffix"),
|
||||||
ExpandTag: c.Bool("expand-tag"),
|
ExpandTag: c.Bool("expand-tag"),
|
||||||
Args: c.StringSlice("args"),
|
Args: c.StringSlice("args"),
|
||||||
|
ArgsNew: c.Generic("args-new").(*CustomStringSliceFlag).GetValue(),
|
||||||
|
IsMultipleBuildArgs: c.Bool("plugin-multiple-build-agrs"),
|
||||||
Target: c.String("target"),
|
Target: c.String("target"),
|
||||||
Repo: fmt.Sprintf("%s/%s", c.String("registry"), c.String("repo")),
|
Repo: fmt.Sprintf("%s/%s", c.String("registry"), c.String("repo")),
|
||||||
Mirrors: c.StringSlice("registry-mirrors"),
|
Mirrors: c.StringSlice("registry-mirrors"),
|
||||||
@@ -518,7 +541,7 @@ func run(c *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setDockerAuth(dockerRegistry, dockerUsername, dockerPassword, accessKey, secretKey,
|
func setDockerAuth(dockerRegistry, dockerUsername, dockerPassword, accessKey, secretKey,
|
||||||
registry, assumeRole, externalId, region string, noPush bool) error {
|
registry, assumeRole, externalId, region string, noPush bool, oidcToken string) error {
|
||||||
dockerConfig := docker.NewConfig()
|
dockerConfig := docker.NewConfig()
|
||||||
credentials := []docker.RegistryCredentials{}
|
credentials := []docker.RegistryCredentials{}
|
||||||
// set docker credentials for base image registry
|
// set docker credentials for base image registry
|
||||||
@@ -531,7 +554,24 @@ func setDockerAuth(dockerRegistry, dockerUsername, dockerPassword, accessKey, se
|
|||||||
credentials = append(credentials, pullFromRegistryCreds)
|
credentials = append(credentials, pullFromRegistryCreds)
|
||||||
}
|
}
|
||||||
|
|
||||||
if assumeRole != "" {
|
if assumeRole != "" && oidcToken != "" {
|
||||||
|
oidcAccessKey, oidcSecretKey, oidcSessionKey, err := getOidcCreds(oidcToken, assumeRole)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = os.Setenv(accessKeyEnv, oidcAccessKey)
|
||||||
|
_ = os.Setenv(secretKeyEnv, oidcSecretKey)
|
||||||
|
_ = os.Setenv(sessionKeyEnv, oidcSessionKey)
|
||||||
|
|
||||||
|
// kaniko-executor >=1.8.0 does not require additional cred helper logic for ECR,
|
||||||
|
// as it discovers ECR repositories automatically and acts accordingly.
|
||||||
|
if isKanikoVersionBelowOneDotEight(os.Getenv(kanikoVersionEnv)) {
|
||||||
|
dockerConfig.SetCredHelper(ecrPublicDomain, "ecr-login")
|
||||||
|
dockerConfig.SetCredHelper(registry, "ecr-login")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if assumeRole != "" {
|
||||||
var err error
|
var err error
|
||||||
username, password, registry, err := getAssumeRoleCreds(region, assumeRole, externalId, "")
|
username, password, registry, err := getAssumeRoleCreds(region, assumeRole, externalId, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -771,3 +811,37 @@ func isKanikoVersionBelowOneDotEight(v string) bool {
|
|||||||
|
|
||||||
return currVer.LessThan(oneEightVer)
|
return currVer.LessThan(oneEightVer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOidcCreds(oidcToken, assumeRole string) (string, string, string, error) {
|
||||||
|
// Create a new session
|
||||||
|
sess, err := session.NewSession()
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", fmt.Errorf("failed to create AWS session: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new STS client
|
||||||
|
svc := sts.New(sess)
|
||||||
|
|
||||||
|
// Prepare the input parameters for the STS call
|
||||||
|
duration := int64(time.Hour / time.Second)
|
||||||
|
input := &sts.AssumeRoleWithWebIdentityInput{
|
||||||
|
RoleArn: aws.String(assumeRole),
|
||||||
|
RoleSessionName: aws.String("kaniko-ecr-oidc"),
|
||||||
|
WebIdentityToken: aws.String(oidcToken),
|
||||||
|
DurationSeconds: aws.Int64(duration),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the AssumeRoleWithWebIdentity function
|
||||||
|
result, err := svc.AssumeRoleWithWebIdentity(input)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", "", fmt.Errorf("failed to assume role with web identity: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if credentials exist in the result
|
||||||
|
if result.Credentials == nil {
|
||||||
|
return "", "", "", errors.New("no credentials returned by AssumeRoleWithWebIdentity")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the credentials
|
||||||
|
return *result.Credentials.AccessKeyId, *result.Credentials.SecretAccessKey, *result.Credentials.SessionToken, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
ADD release/linux/amd64/kaniko-acr /kaniko/
|
ADD release/linux/amd64/kaniko-acr /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-acr"]
|
ENTRYPOINT ["/kaniko/kaniko-acr"]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.0
|
||||||
|
|
||||||
ENV HOME /root
|
ENV HOME /root
|
||||||
ENV USER root
|
ENV USER root
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.0
|
||||||
ADD release/linux/arm64/kaniko-acr /kaniko/
|
ADD release/linux/arm64/kaniko-acr /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-acr"]
|
ENTRYPOINT ["/kaniko/kaniko-acr"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
ADD release/linux/amd64/kaniko-docker /kaniko/
|
ADD release/linux/amd64/kaniko-docker /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-docker"]
|
ENTRYPOINT ["/kaniko/kaniko-docker"]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV HOME /root
|
ENV HOME /root
|
||||||
ENV USER root
|
ENV USER root
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
ADD release/linux/arm64/kaniko-docker /kaniko/
|
ADD release/linux/arm64/kaniko-docker /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-docker"]
|
ENTRYPOINT ["/kaniko/kaniko-docker"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
ADD release/linux/amd64/kaniko-ecr /kaniko/
|
ADD release/linux/amd64/kaniko-ecr /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-ecr"]
|
ENTRYPOINT ["/kaniko/kaniko-ecr"]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV HOME /root
|
ENV HOME /root
|
||||||
ENV USER root
|
ENV USER root
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
|
|
||||||
ADD release/linux/arm64/kaniko-ecr /kaniko/
|
ADD release/linux/arm64/kaniko-ecr /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-ecr"]
|
ENTRYPOINT ["/kaniko/kaniko-ecr"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
ADD release/linux/amd64/kaniko-gar /kaniko/
|
ADD release/linux/amd64/kaniko-gar /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-gar"]
|
ENTRYPOINT ["/kaniko/kaniko-gar"]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV HOME /root
|
ENV HOME /root
|
||||||
ENV USER root
|
ENV USER root
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
|
|
||||||
ADD release/linux/arm64/kaniko-gar /kaniko/
|
ADD release/linux/arm64/kaniko-gar /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-gar"]
|
ENTRYPOINT ["/kaniko/kaniko-gar"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
ADD release/linux/amd64/kaniko-gcr /kaniko/
|
ADD release/linux/amd64/kaniko-gcr /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-gcr"]
|
ENTRYPOINT ["/kaniko/kaniko-gcr"]
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
FROM gcr.io/kaniko-project/executor:v1.20.1
|
FROM gcr.io/kaniko-project/executor:v1.23.2
|
||||||
|
|
||||||
ENV HOME /root
|
ENV HOME /root
|
||||||
ENV USER root
|
ENV USER root
|
||||||
ENV KANIKO_VERSION=1.20.1
|
ENV KANIKO_VERSION=1.23.2
|
||||||
|
|
||||||
ADD release/linux/arm64/kaniko-gcr /kaniko/
|
ADD release/linux/arm64/kaniko-gcr /kaniko/
|
||||||
ENTRYPOINT ["/kaniko/kaniko-gcr"]
|
ENTRYPOINT ["/kaniko/kaniko-gcr"]
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
This document explains on how to install certain git hooks globally for all repositories in your machine.
|
||||||
|
|
||||||
|
Step 1: git clone https://github.com/drone/drone-kaniko.git
|
||||||
|
Step 2: cd git-hooks
|
||||||
|
Step 3: Run install.sh
|
||||||
|
|
||||||
|
"install.sh" script will create .git_template in the user directory and will put the git hook and its dependent scripts in it. Along with the .git_template folder, it will add 2 sections "init" and "hooks boolean" in the .gitconfig file in the same user's root directory.
|
||||||
|
After running "install.sh" if you create/clone a new git repository then all the hooks will get install automatically for the git repository. In case of existing git repository copy the contents of ~/.git_template/hooks into the .git/hooks directory of existing git repository.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#Helper script to be used as a pre-commit hook.
|
||||||
|
|
||||||
|
echo "This hook checks for any secrets getting pushed as part of commit. If you feel that scan is false positive. \
|
||||||
|
Then add the exclusion in .gitleaksignore file. For more info visit: https://github.com/zricethezav/gitleaks"
|
||||||
|
|
||||||
|
GIT_LEAKS_PRE_COMMIT=s$(git config --bool hook.pre-commit.gitleak)
|
||||||
|
|
||||||
|
echo "INFO: Scanning Commits information for any GIT LEAKS"
|
||||||
|
gitleaks protect --staged -v --exit-code=100
|
||||||
|
STATUS=$?
|
||||||
|
if [ $STATUS = 100 ]; then
|
||||||
|
echo "WARNING: GIT LEAKS has detected sensitive information in your changes. Please remove them or add them (IF NON-SENSITIVE) in .gitleaksignore file."
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#Helper script to be used as a pre-commit hook.
|
||||||
|
|
||||||
|
echo "This hook checks for any secrets getting pushed as part of commit. If you feel that scan is false positive. \
|
||||||
|
Then add the exclusion in .gitleaksignore file. For more info visit: https://github.com/zricethezav/gitleaks"
|
||||||
|
|
||||||
|
GIT_LEAKS=$(git config --bool hook.pre-push.gitleaks)
|
||||||
|
|
||||||
|
echo "INFO: Scanning Commits information for any GIT LEAKS"
|
||||||
|
gitleaks detect -s ./ --log-level=debug --log-opts=-1 -v
|
||||||
|
STATUS=$?
|
||||||
|
if [ $STATUS != 0 ]; then
|
||||||
|
echo "WARNING: GIT LEAKS has detected sensitive information in your changes. Please remove them or add them (IF NON-SENSITIVE) in .gitleaksignore file."
|
||||||
|
exit $STATUS
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
GL_SCRIPT_PATH="$HOME/.git_template/hooks/git-leaks-pre-commit.sh"
|
||||||
|
|
||||||
|
pushd `dirname $0` > /dev/null && cd ../.. && BASEDIR=$(pwd -L) && popd > /dev/null
|
||||||
|
BASENAME=`basename $0`
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
against=HEAD
|
||||||
|
else
|
||||||
|
#Initial commit : diff against an empty tree object
|
||||||
|
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||||
|
fi
|
||||||
|
|
||||||
|
GIT_LEAKS_PRE_COMMIT=hook.pre-commit.gitleaks
|
||||||
|
if [ "`git config $GIT_LEAKS_PRE_COMMIT`" == "false" ]
|
||||||
|
then
|
||||||
|
echo -e '\033[0;31m' checking git leaks is disabled - to enable: '\033[0;37m'git config --unset $GIT_LEAKS_PRE_COMMIT '\033[0m'
|
||||||
|
echo -e '\033[0;34m' checking git leaks ... to enable: '\033[0;37m'git config --add $GIT_LEAKS_PRE_COMMIT true '\033[0m'
|
||||||
|
else
|
||||||
|
echo -e '\033[0;34m' checking for git leaks...
|
||||||
|
[ -f "${GL_SCRIPT_PATH}" ] && . ${GL_SCRIPT_PATH} || echo "ERROR: Hook Script Not Found..." && exit 404
|
||||||
|
fi
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
GL_SCRIPT_PATH="$HOME/.git_template/hooks/git-leaks.sh"
|
||||||
|
|
||||||
|
pushd `dirname $0` > /dev/null && cd ../.. && BASEDIR=$(pwd -L) && popd > /dev/null
|
||||||
|
BASENAME=`basename $0`
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
against=HEAD
|
||||||
|
else
|
||||||
|
#Initial commit : diff against an empty tree object
|
||||||
|
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
|
||||||
|
fi
|
||||||
|
|
||||||
|
GIT_LEAKS=hook.pre-push.gitleaks
|
||||||
|
if [ "`git config $GIT_LEAKS`" == "false" ]
|
||||||
|
then
|
||||||
|
echo -e '\033[0;31m' checking git leaks is disabled - to enable: '\033[0;37m'git config --unset $GIT_LEAKS '\033[0m'
|
||||||
|
echo -e '\033[0;34m' checking git leaks ... to enable: '\033[0;37m'git config --add $GIT_LEAKS true '\033[0m'
|
||||||
|
else
|
||||||
|
echo -e '\033[0;34m' checking for git leaks...
|
||||||
|
[ -f "${GL_SCRIPT_PATH}" ] && . ${GL_SCRIPT_PATH} || echo "ERROR: Hook Script Not Found..." && exit 404
|
||||||
|
fi
|
||||||
Executable
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
#Function to check if package is installed or not
|
||||||
|
#args: $1: Name of the Package
|
||||||
|
function check_package_installed() {
|
||||||
|
LOCAL_PACKAGE_NAME=$1
|
||||||
|
echo "Checking if $LOCAL_PACKAGE_NAME is installed or not..."
|
||||||
|
brew list $LOCAL_PACKAGE_NAME
|
||||||
|
if [ "$?" -eq 1 ];then
|
||||||
|
echo "Installing $LOCAL_PACKAGE_NAME package..."
|
||||||
|
brew install $LOCAL_PACKAGE_NAME
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_git_template() {
|
||||||
|
cd $BASEDIR
|
||||||
|
mkdir -p ~/.git_template/hooks
|
||||||
|
git config --global init.templatedir ${GIT_TEMPLATE}
|
||||||
|
git config --global --add $GIT_LEAKS true
|
||||||
|
git config --global --add $GIT_LEAKS_PRE_COMMIT true
|
||||||
|
find hooks/ -type f -exec cp "{}" ~/.git_template/hooks \;
|
||||||
|
#cp -f hooks/* ~/.git_template/hooks
|
||||||
|
cat ~/.gitconfig
|
||||||
|
}
|
||||||
|
|
||||||
|
GIT_TEMPLATE="~/.git_template"
|
||||||
|
GIT_LEAKS=hook.pre-push.gitleaks
|
||||||
|
GIT_LEAKS_PRE_COMMIT=hook.pre-commit.gitleaks
|
||||||
|
|
||||||
|
pushd `dirname $0` && BASEDIR=$(pwd -L) && popd
|
||||||
|
|
||||||
|
echo This script will install hooks that run scripts that could be updated without notice.
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -p "Do you wish to install these hooks?" yn
|
||||||
|
case $yn in
|
||||||
|
[Yy]* ) check_package_installed "gitleaks";
|
||||||
|
break;;
|
||||||
|
[Nn]* ) exit;;
|
||||||
|
* ) echo "Please answer yes or no.";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
create_git_template
|
||||||
@@ -47,4 +47,4 @@ require (
|
|||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.22.0
|
go 1.22.4
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/drone/drone-kaniko/pkg/artifact"
|
"github.com/drone/drone-kaniko/pkg/artifact"
|
||||||
@@ -16,30 +17,32 @@ import (
|
|||||||
type (
|
type (
|
||||||
// Build defines Docker build parameters.
|
// Build defines Docker build parameters.
|
||||||
Build struct {
|
Build struct {
|
||||||
DroneCommitRef string // Drone git commit reference
|
DroneCommitRef string // Drone git commit reference
|
||||||
DroneRepoBranch string // Drone repo branch
|
DroneRepoBranch string // Drone repo branch
|
||||||
Dockerfile string // Docker build Dockerfile
|
Dockerfile string // Docker build Dockerfile
|
||||||
Context string // Docker build context
|
Context string // Docker build context
|
||||||
Tags []string // Docker build tags
|
Tags []string // Docker build tags
|
||||||
AutoTag bool // Set this to auto detect tags from git commits and semver-tagged labels
|
AutoTag bool // Set this to auto detect tags from git commits and semver-tagged labels
|
||||||
AutoTagSuffix string // Suffix to append to the auto detect tags
|
AutoTagSuffix string // Suffix to append to the auto detect tags
|
||||||
ExpandTag bool // Set this to expand the `Tags` into semver-tagged labels
|
ExpandTag bool // Set this to expand the `Tags` into semver-tagged labels
|
||||||
Args []string // Docker build args
|
Args []string // Docker build args
|
||||||
Target string // Docker build target
|
ArgsNew []string // docker build args with comma seperated values
|
||||||
Repo string // Docker build repository
|
IsMultipleBuildArgs bool // env variable for fallback for docker build args
|
||||||
Mirrors []string // Docker repository mirrors
|
Target string // Docker build target
|
||||||
Labels []string // Label map
|
Repo string // Docker build repository
|
||||||
SkipTlsVerify bool // Docker skip tls certificate verify for registry
|
Mirrors []string // Docker repository mirrors
|
||||||
SnapshotMode string // Kaniko snapshot mode
|
Labels []string // Label map
|
||||||
EnableCache bool // Whether to enable kaniko cache
|
SkipTlsVerify bool // Docker skip tls certificate verify for registry
|
||||||
CacheRepo string // Remote repository that will be used to store cached layers
|
SnapshotMode string // Kaniko snapshot mode
|
||||||
CacheTTL int // Cache timeout in hours
|
EnableCache bool // Whether to enable kaniko cache
|
||||||
DigestFile string // Digest file location
|
CacheRepo string // Remote repository that will be used to store cached layers
|
||||||
NoPush bool // Set this flag if you only want to build the image, without pushing to a registry
|
CacheTTL int // Cache timeout in hours
|
||||||
Verbosity string // Log level
|
DigestFile string // Digest file location
|
||||||
Platform string // Allows to build with another default platform than the host, similarly to docker build --platform
|
NoPush bool // Set this flag if you only want to build the image, without pushing to a registry
|
||||||
SkipUnusedStages bool // Build only used stages
|
Verbosity string // Log level
|
||||||
TarPath string // Set this flag to save the image as a tarball at path
|
Platform string // Allows to build with another default platform than the host, similarly to docker build --platform
|
||||||
|
SkipUnusedStages bool // Build only used stages
|
||||||
|
TarPath string // Set this flag to save the image as a tarball at path
|
||||||
|
|
||||||
Cache bool // Enable or disable caching during the build process.
|
Cache bool // Enable or disable caching during the build process.
|
||||||
CacheDir string // Directory to store cached layers.
|
CacheDir string // Directory to store cached layers.
|
||||||
@@ -202,8 +205,14 @@ func (p Plugin) Exec() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the build arguments
|
// Set the build arguments
|
||||||
for _, arg := range p.Build.Args {
|
if p.Build.IsMultipleBuildArgs {
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--build-arg=%s", arg))
|
for _, arg := range p.Build.ArgsNew {
|
||||||
|
cmdArgs = append(cmdArgs, "--build-arg", arg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, arg := range p.Build.Args {
|
||||||
|
cmdArgs = append(cmdArgs, "--build-arg", arg)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Set the labels
|
// Set the labels
|
||||||
for _, label := range p.Build.Labels {
|
for _, label := range p.Build.Labels {
|
||||||
@@ -222,7 +231,7 @@ func (p Plugin) Exec() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.Build.SnapshotMode != "" {
|
if p.Build.SnapshotMode != "" {
|
||||||
cmdArgs = append(cmdArgs, fmt.Sprintf("--snapshotMode=%s", p.Build.SnapshotMode))
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--snapshot-mode=%s", p.Build.SnapshotMode))
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Build.EnableCache {
|
if p.Build.EnableCache {
|
||||||
@@ -258,6 +267,12 @@ func (p Plugin) Exec() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.Build.TarPath != "" {
|
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))
|
cmdArgs = append(cmdArgs, fmt.Sprintf("--tar-path=%s", p.Build.TarPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,7 +422,11 @@ func (p Plugin) Exec() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if p.Output.OutputFile != "" {
|
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)
|
fmt.Fprintf(os.Stderr, "failed to write plugin output file at path: %s with error: %s\n", p.Output.OutputFile, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -415,6 +434,15 @@ func (p Plugin) Exec() error {
|
|||||||
return nil
|
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 {
|
func getDigest(digestFile string) string {
|
||||||
content, err := ioutil.ReadFile(digestFile)
|
content, err := ioutil.ReadFile(digestFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+132
@@ -1,6 +1,8 @@
|
|||||||
package kaniko
|
package kaniko
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
@@ -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")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,20 +53,3 @@ func TestConfig(t *testing.T) {
|
|||||||
assert.Equal(t, c.Auths, configFromFile.Auths)
|
assert.Equal(t, c.Auths, configFromFile.Auths)
|
||||||
assert.Equal(t, c.CredHelpers, configFromFile.CredHelpers)
|
assert.Equal(t, c.CredHelpers, configFromFile.CredHelpers)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteDockerConfig(t *testing.T) {
|
|
||||||
tempDir, err := ioutil.TempDir("", "docker-config-test")
|
|
||||||
assert.NoError(t, err)
|
|
||||||
defer os.RemoveAll(tempDir)
|
|
||||||
|
|
||||||
data := []byte(`{"auths":{"https://index.docker.io/v1/":{"auth":"dGVzdDpwYXNzd29yZA=="}}}`)
|
|
||||||
err = WriteDockerConfig(data, tempDir)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
configPath := filepath.Join(tempDir, "config.json")
|
|
||||||
_, err = os.Stat(configPath)
|
|
||||||
assert.NoError(t, err)
|
|
||||||
|
|
||||||
err = WriteDockerConfig(data, "/invalid/path")
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,9 +4,15 @@ import (
|
|||||||
"github.com/joho/godotenv"
|
"github.com/joho/godotenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func WritePluginOutputFile(outputFilePath, digest string) error {
|
func WritePluginOutputFile(outputFilePath, digest string, pluginTarPath string) error {
|
||||||
output := map[string]string{
|
output := make(map[string]string)
|
||||||
"digest": digest,
|
if digest != "" {
|
||||||
|
output["digest"] = digest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if pluginTarPath != "" {
|
||||||
|
output["IMAGE_TAR_PATH"] = pluginTarPath
|
||||||
|
}
|
||||||
|
|
||||||
return godotenv.Write(output, outputFilePath)
|
return godotenv.Write(output, outputFilePath)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user