Files
trivy/pkg/fanal/test/integration/docker/docker.go
2025-07-29 07:13:54 +00:00

130 lines
2.9 KiB
Go

package docker
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/url"
"os"
"os/exec"
"github.com/docker/docker/api/types/image"
apiregistry "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
)
type RegistryConfig struct {
URL *url.URL
Username string
Password string
}
func (c RegistryConfig) GetAuthConfig() apiregistry.AuthConfig {
return apiregistry.AuthConfig{
Username: c.Username,
Password: c.Password,
ServerAddress: c.URL.Host,
}
}
func (c RegistryConfig) GetRegistryAuth() (string, error) {
authConfig := apiregistry.AuthConfig{
Username: c.Username,
Password: c.Password,
}
encodedJSON, err := json.Marshal(authConfig)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(encodedJSON), nil
}
func (c RegistryConfig) GetBasicAuthorization() string {
return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%s:%s", c.Username, c.Password)))
}
type Docker struct {
cli *client.Client
}
func New() (Docker, error) {
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil {
return Docker{}, err
}
return Docker{
cli: cli,
}, nil
}
func (d Docker) Login(conf RegistryConfig) error {
auth := conf.GetAuthConfig()
return exec.Command("docker", "login", "-u", auth.Username, "-p", auth.Password, auth.ServerAddress).Run()
}
func (d Docker) Logout(conf RegistryConfig) error {
auth := conf.GetAuthConfig()
return exec.Command("docker", "logout", auth.ServerAddress).Run()
}
// ReplicateImage tags the given imagePath and pushes it to the given dest registry.
func (d Docker) ReplicateImage(ctx context.Context, imageRef, imagePath string, dest RegistryConfig) error {
// remove existing Image if any
_, _ = d.cli.ImageRemove(ctx, imageRef, image.RemoveOptions{
Force: true,
PruneChildren: true,
})
testfile, err := os.Open(imagePath)
if err != nil {
return err
}
defer testfile.Close()
// load image into docker engine
resp, err := d.cli.ImageLoad(ctx, testfile, client.ImageLoadWithQuiet(true))
if err != nil {
return err
}
if _, err := io.Copy(io.Discard, resp.Body); err != nil {
return err
}
defer resp.Body.Close()
targetImageRef := fmt.Sprintf("%s/%s", dest.URL.Host, imageRef)
if err = d.cli.ImageTag(ctx, imageRef, targetImageRef); err != nil {
return err
}
defer func() {
_, _ = d.cli.ImageRemove(ctx, imageRef, image.RemoveOptions{
Force: true,
PruneChildren: true,
})
_, _ = d.cli.ImageRemove(ctx, targetImageRef, image.RemoveOptions{
Force: true,
PruneChildren: true,
})
}()
auth, err := dest.GetRegistryAuth()
if err != nil {
return err
}
pushOut, err := d.cli.ImagePush(ctx, targetImageRef, image.PushOptions{
RegistryAuth: auth,
})
if err != nil {
return err
}
defer pushOut.Close()
if _, err = io.Copy(io.Discard, pushOut); err != nil {
return err
}
return nil
}