2021-11-10 09:31:03 -05:00
|
|
|
package test
|
|
|
|
|
|
|
|
import (
|
2022-05-10 03:28:26 -05:00
|
|
|
"context"
|
2022-01-19 14:54:17 -05:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/json"
|
2021-11-10 09:31:03 -05:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"io/ioutil"
|
2022-01-19 14:54:17 -05:00
|
|
|
"log"
|
|
|
|
"math/big"
|
|
|
|
"net/url"
|
2021-11-10 09:31:03 -05:00
|
|
|
"os"
|
|
|
|
"path"
|
2021-11-22 03:12:01 -05:00
|
|
|
"time"
|
2021-11-10 09:31:03 -05:00
|
|
|
|
2022-01-19 14:54:17 -05:00
|
|
|
godigest "github.com/opencontainers/go-digest"
|
|
|
|
imagespec "github.com/opencontainers/image-spec/specs-go/v1"
|
2022-05-10 03:28:26 -05:00
|
|
|
"github.com/opencontainers/umoci"
|
2021-11-10 09:31:03 -05:00
|
|
|
"github.com/phayes/freeport"
|
|
|
|
"gopkg.in/resty.v1"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BaseURL = "http://127.0.0.1:%s"
|
|
|
|
BaseSecureURL = "https://127.0.0.1:%s"
|
2021-11-22 03:12:01 -05:00
|
|
|
SleepTime = 100 * time.Millisecond
|
2021-11-10 09:31:03 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func GetFreePort() string {
|
|
|
|
port, err := freeport.GetFreePort()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return fmt.Sprint(port)
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetBaseURL(port string) string {
|
|
|
|
return fmt.Sprintf(BaseURL, port)
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetSecureBaseURL(port string) string {
|
|
|
|
return fmt.Sprintf(BaseSecureURL, port)
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeHtpasswdFile() string {
|
|
|
|
// bcrypt(username="test", passwd="test")
|
|
|
|
content := "test:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n"
|
2021-12-13 14:23:31 -05:00
|
|
|
|
2021-11-10 09:31:03 -05:00
|
|
|
return MakeHtpasswdFileFromString(content)
|
|
|
|
}
|
|
|
|
|
|
|
|
func MakeHtpasswdFileFromString(fileContent string) string {
|
2021-12-13 14:23:31 -05:00
|
|
|
htpasswdFile, err := ioutil.TempFile("", "htpasswd-")
|
2021-11-10 09:31:03 -05:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// bcrypt(username="test", passwd="test")
|
|
|
|
content := []byte(fileContent)
|
2021-12-13 14:23:31 -05:00
|
|
|
if err := ioutil.WriteFile(htpasswdFile.Name(), content, 0o600); err != nil { //nolint:gomnd
|
2021-11-10 09:31:03 -05:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2021-12-13 14:23:31 -05:00
|
|
|
return htpasswdFile.Name()
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func Location(baseURL string, resp *resty.Response) string {
|
|
|
|
// For some API responses, the Location header is set and is supposed to
|
|
|
|
// indicate an opaque value. However, it is not clear if this value is an
|
|
|
|
// absolute URL (https://server:port/v2/...) or just a path (/v2/...)
|
|
|
|
// zot implements the latter as per the spec, but some registries appear to
|
|
|
|
// return the former - this needs to be clarified
|
|
|
|
loc := resp.Header().Get("Location")
|
2021-12-13 14:23:31 -05:00
|
|
|
|
2022-01-19 14:54:17 -05:00
|
|
|
uloc, err := url.Parse(loc)
|
|
|
|
if err != nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
path := uloc.Path
|
|
|
|
|
|
|
|
return baseURL + path
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
|
2022-03-21 12:37:23 -05:00
|
|
|
func CopyFiles(sourceDir, destDir string) error {
|
2021-11-10 09:31:03 -05:00
|
|
|
sourceMeta, err := os.Stat(sourceDir)
|
|
|
|
if err != nil {
|
2021-12-13 14:23:31 -05:00
|
|
|
return fmt.Errorf("CopyFiles os.Stat failed: %w", err)
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
if err := os.MkdirAll(destDir, sourceMeta.Mode()); err != nil {
|
2021-12-13 14:23:31 -05:00
|
|
|
return fmt.Errorf("CopyFiles os.MkdirAll failed: %w", err)
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
files, err := ioutil.ReadDir(sourceDir)
|
|
|
|
if err != nil {
|
2021-12-13 14:23:31 -05:00
|
|
|
return fmt.Errorf("CopyFiles ioutil.ReadDir failed: %w", err)
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
|
|
|
sourceFilePath := path.Join(sourceDir, file.Name())
|
|
|
|
destFilePath := path.Join(destDir, file.Name())
|
|
|
|
|
|
|
|
if file.IsDir() {
|
|
|
|
if err = CopyFiles(sourceFilePath, destFilePath); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sourceFile, err := os.Open(sourceFilePath)
|
|
|
|
if err != nil {
|
2021-12-13 14:23:31 -05:00
|
|
|
return fmt.Errorf("CopyFiles os.Open failed: %w", err)
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
defer sourceFile.Close()
|
|
|
|
|
|
|
|
destFile, err := os.Create(destFilePath)
|
|
|
|
if err != nil {
|
2021-12-13 14:23:31 -05:00
|
|
|
return fmt.Errorf("CopyFiles os.Create failed: %w", err)
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
defer destFile.Close()
|
|
|
|
|
|
|
|
if _, err = io.Copy(destFile, sourceFile); err != nil {
|
2021-12-13 14:23:31 -05:00
|
|
|
return fmt.Errorf("io.Copy failed: %w", err)
|
2021-11-10 09:31:03 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2021-11-22 03:12:01 -05:00
|
|
|
|
|
|
|
func WaitTillServerReady(url string) {
|
|
|
|
for {
|
|
|
|
_, err := resty.R().Get(url)
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(SleepTime)
|
|
|
|
}
|
|
|
|
}
|
2022-01-19 14:54:17 -05:00
|
|
|
|
2022-07-14 05:03:25 -05:00
|
|
|
func WaitTillTrivyDBDownloadStarted(rootDir string) {
|
|
|
|
for {
|
|
|
|
if _, err := os.Stat(path.Join(rootDir, "trivy.db")); err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(SleepTime)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-19 14:54:17 -05:00
|
|
|
// Adapted from https://gist.github.com/dopey/c69559607800d2f2f90b1b1ed4e550fb
|
|
|
|
func randomString(n int) string {
|
|
|
|
const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-"
|
|
|
|
|
|
|
|
ret := make([]byte, n)
|
|
|
|
|
|
|
|
for count := 0; count < n; count++ {
|
|
|
|
num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters))))
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ret[count] = letters[num.Int64()]
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetRandomImageConfig() ([]byte, godigest.Digest) {
|
|
|
|
const maxLen = 16
|
|
|
|
|
|
|
|
randomAuthor := randomString(maxLen)
|
|
|
|
|
|
|
|
config := imagespec.Image{
|
|
|
|
Architecture: "amd64",
|
|
|
|
OS: "linux",
|
|
|
|
RootFS: imagespec.RootFS{
|
|
|
|
Type: "layers",
|
|
|
|
DiffIDs: []godigest.Digest{},
|
|
|
|
},
|
|
|
|
Author: randomAuthor,
|
|
|
|
}
|
|
|
|
|
|
|
|
configBlobContent, err := json.MarshalIndent(&config, "", "\t")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
configBlobDigestRaw := godigest.FromBytes(configBlobContent)
|
|
|
|
|
|
|
|
return configBlobContent, configBlobDigestRaw
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetImageConfig() ([]byte, godigest.Digest) {
|
|
|
|
config := imagespec.Image{
|
|
|
|
Architecture: "amd64",
|
|
|
|
OS: "linux",
|
|
|
|
RootFS: imagespec.RootFS{
|
|
|
|
Type: "layers",
|
|
|
|
DiffIDs: []godigest.Digest{},
|
|
|
|
},
|
|
|
|
Author: "some author",
|
|
|
|
}
|
|
|
|
|
|
|
|
configBlobContent, err := json.MarshalIndent(&config, "", "\t")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
configBlobDigestRaw := godigest.FromBytes(configBlobContent)
|
|
|
|
|
|
|
|
return configBlobContent, configBlobDigestRaw
|
|
|
|
}
|
2022-05-10 03:28:26 -05:00
|
|
|
|
|
|
|
func GetOciLayoutDigests(imagePath string) (godigest.Digest, godigest.Digest, godigest.Digest) {
|
|
|
|
var (
|
|
|
|
manifestDigest godigest.Digest
|
|
|
|
configDigest godigest.Digest
|
|
|
|
layerDigest godigest.Digest
|
|
|
|
)
|
|
|
|
|
|
|
|
oci, err := umoci.OpenLayout(imagePath)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
defer oci.Close()
|
|
|
|
|
|
|
|
ctxUmoci := context.Background()
|
|
|
|
|
|
|
|
index, err := oci.GetIndex(ctxUmoci)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, manifest := range index.Manifests {
|
|
|
|
manifestDigest = manifest.Digest
|
|
|
|
|
|
|
|
manifestBlob, err := oci.GetBlob(ctxUmoci, manifest.Digest)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
manifestBuf, err := ioutil.ReadAll(manifestBlob)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var manifest imagespec.Manifest
|
|
|
|
|
|
|
|
err = json.Unmarshal(manifestBuf, &manifest)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
configDigest = manifest.Config.Digest
|
|
|
|
|
|
|
|
for _, layer := range manifest.Layers {
|
|
|
|
layerDigest = layer.Digest
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return manifestDigest, configDigest, layerDigest
|
|
|
|
}
|