mirror of
https://github.com/project-zot/zot.git
synced 2024-12-30 22:34:13 -05:00
Upgraded build pipeline
Go version changed to 1.14.4 Golangci-lint changed to 1.26.0 Bazel version changed to 3.0.0 Bazel rules_go version changed to 0.23.3 Bazel gazelle version changed to v0.21.0 Bazel build tools version changed to 0.25.1 Bazel skylib version changed to 1.0.2
This commit is contained in:
parent
ff4a300057
commit
af77876306
22 changed files with 143 additions and 80 deletions
|
@ -14,3 +14,6 @@ linters-settings:
|
||||||
dupl:
|
dupl:
|
||||||
# tokens count to trigger issue, 150 by default
|
# tokens count to trigger issue, 150 by default
|
||||||
threshold: 200
|
threshold: 200
|
||||||
|
nestif:
|
||||||
|
# their are various nested if else, therefore specifying complexity as 26
|
||||||
|
min-complexity: 26
|
11
.travis.yml
11
.travis.yml
|
@ -1,7 +1,7 @@
|
||||||
language: go
|
language: go
|
||||||
|
|
||||||
go:
|
go:
|
||||||
- 1.12.x
|
- 1.14.x
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- GO111MODULE=on
|
- GO111MODULE=on
|
||||||
|
@ -19,7 +19,14 @@ cache:
|
||||||
- $HOME/.cache/bazel
|
- $HOME/.cache/bazel
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget -N https://github.com/bazelbuild/bazel/releases/download/0.26.1/bazel-0.26.1-installer-linux-x86_64.sh && chmod +x bazel-0.26.1-installer-linux-x86_64.sh && ./bazel-0.26.1-installer-linux-x86_64.sh --user; go get -u github.com/swaggo/swag/cmd/swag; go mod download; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget -N https://github.com/bazelbuild/bazel/releases/download/3.0.0/bazel-3.0.0-installer-linux-x86_64.sh && chmod +x bazel-3.0.0-installer-linux-x86_64.sh && ./bazel-3.0.0-installer-linux-x86_64.sh --user; go get -u github.com/swaggo/swag/cmd/swag; go mod download; sudo apt-get update; sudo apt-get install rpm; fi
|
||||||
|
|
||||||
|
script:
|
||||||
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make && make -f Makefile.bazel build; fi
|
||||||
|
|
||||||
|
after_success:
|
||||||
|
- bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make && make -f Makefile.bazel build; fi
|
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then make && make -f Makefile.bazel build; fi
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -27,7 +27,7 @@ covhtml:
|
||||||
|
|
||||||
.PHONY: check
|
.PHONY: check
|
||||||
check: .bazel/golangcilint.yaml
|
check: .bazel/golangcilint.yaml
|
||||||
golangci-lint --version || curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.21.0
|
golangci-lint --version || curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.26.0
|
||||||
golangci-lint --config .bazel/golangcilint.yaml run --enable-all ./cmd/... ./pkg/...
|
golangci-lint --config .bazel/golangcilint.yaml run --enable-all ./cmd/... ./pkg/...
|
||||||
|
|
||||||
docs/docs.go:
|
docs/docs.go:
|
||||||
|
|
22
WORKSPACE
22
WORKSPACE
|
@ -1,6 +1,6 @@
|
||||||
workspace(name = "com_github_anuvu_zot")
|
workspace(name = "com_github_anuvu_zot")
|
||||||
|
|
||||||
go_version = "1.12.9"
|
go_version = "1.14.4"
|
||||||
|
|
||||||
go_os = "linux"
|
go_os = "linux"
|
||||||
|
|
||||||
|
@ -9,22 +9,22 @@ go_arch = "amd64"
|
||||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||||
|
|
||||||
go_rules_version = "0.19.3"
|
go_rules_version = "v0.23.3"
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "io_bazel_rules_go",
|
name = "io_bazel_rules_go",
|
||||||
|
sha256 = "a8d6b1b354d371a646d2f7927319974e0f9e52f73a2452d2b3877118169eb6bb",
|
||||||
urls = [
|
urls = [
|
||||||
"https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version),
|
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version),
|
||||||
"https://github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version),
|
"https://github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version),
|
||||||
],
|
],
|
||||||
sha256 = "313f2c7a23fecc33023563f082f381a32b9b7254f727a7dd2d6380ccc6dfe09b",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
gazelle_version = "0.18.1"
|
gazelle_version = "v0.21.0"
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "bazel_gazelle",
|
name = "bazel_gazelle",
|
||||||
sha256 = "be9296bfd64882e3c08e3283c58fcb461fa6dd3c171764fcc4cf322f60615a9b",
|
sha256 = "bfd86b3cbe855d6c16c6fce60d76bd51f5c8dbc9cfcaef7a2bb5c1aafd0710e8",
|
||||||
urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/{}/bazel-gazelle-{}.tar.gz".format(gazelle_version, gazelle_version)],
|
urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/{}/bazel-gazelle-{}.tar.gz".format(gazelle_version, gazelle_version)],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -43,13 +43,15 @@ git_repository(
|
||||||
remote = "https://github.com/atlassian/bazel-tools.git",
|
remote = "https://github.com/atlassian/bazel-tools.git",
|
||||||
)
|
)
|
||||||
|
|
||||||
skylib_version = "0.8.0"
|
skylib_version = "1.0.2"
|
||||||
|
|
||||||
http_archive(
|
http_archive(
|
||||||
name = "bazel_skylib",
|
name = "bazel_skylib",
|
||||||
sha256 = "2ea8a5ed2b448baf4a6855d3ce049c4c452a6470b1efd1504fdb7c1c134d220a",
|
sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44",
|
||||||
strip_prefix = "bazel-skylib-{}".format(skylib_version),
|
urls = [
|
||||||
urls = ["https://github.com/bazelbuild/bazel-skylib/archive/{}.tar.gz".format(skylib_version)],
|
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib-{}.tar.gz".format(skylib_version, skylib_version),
|
||||||
|
"https://github.com/bazelbuild/bazel-skylib/releases/download/{}/bazel-skylib-{}.tar.gz".format(skylib_version, skylib_version),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
load("@bazel_skylib//lib:versions.bzl", "versions")
|
load("@bazel_skylib//lib:versions.bzl", "versions")
|
||||||
|
|
|
@ -24,4 +24,6 @@ var (
|
||||||
ErrCacheRootBucket = errors.New("cache: unable to create/update root bucket")
|
ErrCacheRootBucket = errors.New("cache: unable to create/update root bucket")
|
||||||
ErrCacheNoBucket = errors.New("cache: unable to find bucket")
|
ErrCacheNoBucket = errors.New("cache: unable to find bucket")
|
||||||
ErrCacheMiss = errors.New("cache: miss")
|
ErrCacheMiss = errors.New("cache: miss")
|
||||||
|
ErrRequireCred = errors.New("ldap: bind credentials required")
|
||||||
|
ErrInvalidCred = errors.New("ldap: invalid credentials")
|
||||||
)
|
)
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,6 +1,6 @@
|
||||||
module github.com/anuvu/zot
|
module github.com/anuvu/zot
|
||||||
|
|
||||||
go 1.13
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||||
|
|
|
@ -41,6 +41,7 @@ go_test(
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
race = "on",
|
race = "on",
|
||||||
deps = [
|
deps = [
|
||||||
|
"//errors:go_default_library",
|
||||||
"@com_github_chartmuseum_auth//:go_default_library",
|
"@com_github_chartmuseum_auth//:go_default_library",
|
||||||
"@com_github_mitchellh_mapstructure//:go_default_library",
|
"@com_github_mitchellh_mapstructure//:go_default_library",
|
||||||
"@com_github_nmcclain_ldap//:go_default_library",
|
"@com_github_nmcclain_ldap//:go_default_library",
|
||||||
|
|
|
@ -71,12 +71,13 @@ func bearerAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint (gocyclo) - we use closure making this a complex subroutine
|
// nolint:gocyclo // we use closure making this a complex subroutine
|
||||||
func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
realm := c.Config.HTTP.Realm
|
realm := c.Config.HTTP.Realm
|
||||||
if realm == "" {
|
if realm == "" {
|
||||||
realm = "Authorization Required"
|
realm = "Authorization Required"
|
||||||
}
|
}
|
||||||
|
|
||||||
realm = "Basic realm=" + strconv.Quote(realm)
|
realm = "Basic realm=" + strconv.Quote(realm)
|
||||||
|
|
||||||
// no password based authN, if neither LDAP nor HTTP BASIC is enabled
|
// no password based authN, if neither LDAP nor HTTP BASIC is enabled
|
||||||
|
@ -97,7 +98,9 @@ func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
credMap := make(map[string]string)
|
credMap := make(map[string]string)
|
||||||
|
|
||||||
delay := c.Config.HTTP.Auth.FailDelay
|
delay := c.Config.HTTP.Auth.FailDelay
|
||||||
|
|
||||||
var ldapClient *LDAPClient
|
var ldapClient *LDAPClient
|
||||||
|
|
||||||
if c.Config.HTTP.Auth != nil {
|
if c.Config.HTTP.Auth != nil {
|
||||||
|
@ -117,27 +120,36 @@ func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
Log: c.Log,
|
Log: c.Log,
|
||||||
SubtreeSearch: l.SubtreeSearch,
|
SubtreeSearch: l.SubtreeSearch,
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Config.HTTP.Auth.LDAP.CACert != "" {
|
if c.Config.HTTP.Auth.LDAP.CACert != "" {
|
||||||
caCert, err := ioutil.ReadFile(c.Config.HTTP.Auth.LDAP.CACert)
|
caCert, err := ioutil.ReadFile(c.Config.HTTP.Auth.LDAP.CACert)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
caCertPool := x509.NewCertPool()
|
caCertPool := x509.NewCertPool()
|
||||||
|
|
||||||
if !caCertPool.AppendCertsFromPEM(caCert) {
|
if !caCertPool.AppendCertsFromPEM(caCert) {
|
||||||
panic(errors.ErrBadCACert)
|
panic(errors.ErrBadCACert)
|
||||||
}
|
}
|
||||||
|
|
||||||
ldapClient.ClientCAs = caCertPool
|
ldapClient.ClientCAs = caCertPool
|
||||||
} else {
|
} else {
|
||||||
// default to system cert pool
|
// default to system cert pool
|
||||||
caCertPool, err := x509.SystemCertPool()
|
caCertPool, err := x509.SystemCertPool()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(errors.ErrBadCACert)
|
panic(errors.ErrBadCACert)
|
||||||
}
|
}
|
||||||
|
|
||||||
ldapClient.ClientCAs = caCertPool
|
ldapClient.ClientCAs = caCertPool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Config.HTTP.Auth.HTPasswd.Path != "" {
|
if c.Config.HTTP.Auth.HTPasswd.Path != "" {
|
||||||
f, err := os.Open(c.Config.HTTP.Auth.HTPasswd.Path)
|
f, err := os.Open(c.Config.HTTP.Auth.HTPasswd.Path)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -170,6 +182,7 @@ func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
s := strings.SplitN(basicAuth, " ", 2)
|
s := strings.SplitN(basicAuth, " ", 2)
|
||||||
|
|
||||||
if len(s) != 2 || strings.ToLower(s[0]) != "basic" {
|
if len(s) != 2 || strings.ToLower(s[0]) != "basic" {
|
||||||
authFail(w, realm, delay)
|
authFail(w, realm, delay)
|
||||||
return
|
return
|
||||||
|
@ -182,6 +195,7 @@ func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
pair := strings.SplitN(string(b), ":", 2)
|
pair := strings.SplitN(string(b), ":", 2)
|
||||||
|
// nolint:gomnd
|
||||||
if len(pair) != 2 {
|
if len(pair) != 2 {
|
||||||
authFail(w, realm, delay)
|
authFail(w, realm, delay)
|
||||||
return
|
return
|
||||||
|
@ -211,7 +225,6 @@ func basicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
authFail(w, realm, delay)
|
authFail(w, realm, delay)
|
||||||
return
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
dspec "github.com/opencontainers/distribution-spec"
|
dspec "github.com/opencontainers/distribution-spec"
|
||||||
)
|
)
|
||||||
|
|
||||||
//nolint (gochecknoglobals)
|
// Commit ...
|
||||||
var Commit string
|
var Commit string //nolint: gochecknoglobals
|
||||||
|
|
||||||
type StorageConfig struct {
|
type StorageConfig struct {
|
||||||
RootDirectory string
|
RootDirectory string
|
||||||
|
@ -85,7 +85,7 @@ func NewConfig() *Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanitize makes a sanitized copy of the config removing any secrets
|
// Sanitize makes a sanitized copy of the config removing any secrets.
|
||||||
func (c *Config) Sanitize() *Config {
|
func (c *Config) Sanitize() *Config {
|
||||||
if c.HTTP.Auth != nil && c.HTTP.Auth.LDAP != nil && c.HTTP.Auth.LDAP.BindPassword != "" {
|
if c.HTTP.Auth != nil && c.HTTP.Auth.LDAP != nil && c.HTTP.Auth.LDAP.BindPassword != "" {
|
||||||
s := &Config{}
|
s := &Config{}
|
||||||
|
|
|
@ -87,7 +87,7 @@ func (c *Controller) Run() error {
|
||||||
PreferServerCipherSuites: true,
|
PreferServerCipherSuites: true,
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
}
|
}
|
||||||
server.TLSConfig.BuildNameToCertificate()
|
server.TLSConfig.BuildNameToCertificate() // nolint: staticcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
return server.ServeTLS(l, c.Config.HTTP.TLS.Cert, c.Config.HTTP.TLS.Key)
|
return server.ServeTLS(l, c.Config.HTTP.TLS.Cert, c.Config.HTTP.TLS.Key)
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
|
@ -20,6 +19,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
|
||||||
|
"github.com/anuvu/zot/errors"
|
||||||
"github.com/anuvu/zot/pkg/api"
|
"github.com/anuvu/zot/pkg/api"
|
||||||
"github.com/chartmuseum/auth"
|
"github.com/chartmuseum/auth"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
@ -66,7 +66,7 @@ func makeHtpasswdFile() string {
|
||||||
|
|
||||||
// bcrypt(username="test", passwd="test")
|
// bcrypt(username="test", passwd="test")
|
||||||
content := []byte("test:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n")
|
content := []byte("test:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n")
|
||||||
if err := ioutil.WriteFile(f.Name(), content, 0644); err != nil {
|
if err := ioutil.WriteFile(f.Name(), content, 0600); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ func makeHtpasswdFileFromString(fileContent string) string {
|
||||||
|
|
||||||
// bcrypt(username="test", passwd="test")
|
// bcrypt(username="test", passwd="test")
|
||||||
content := []byte(fileContent)
|
content := []byte(fileContent)
|
||||||
if err := ioutil.WriteFile(f.Name(), content, 0644); err != nil {
|
if err := ioutil.WriteFile(f.Name(), content, 0600); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,7 +935,7 @@ func (l *testLDAPServer) Stop() {
|
||||||
|
|
||||||
func (l *testLDAPServer) Bind(bindDN, bindSimplePw string, conn net.Conn) (vldap.LDAPResultCode, error) {
|
func (l *testLDAPServer) Bind(bindDN, bindSimplePw string, conn net.Conn) (vldap.LDAPResultCode, error) {
|
||||||
if bindDN == "" || bindSimplePw == "" {
|
if bindDN == "" || bindSimplePw == "" {
|
||||||
return vldap.LDAPResultInappropriateAuthentication, errors.New("ldap: bind creds required")
|
return vldap.LDAPResultInappropriateAuthentication, errors.ErrRequireCred
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindDN == LDAPBindDN && bindSimplePw == LDAPBindPassword) ||
|
if (bindDN == LDAPBindDN && bindSimplePw == LDAPBindPassword) ||
|
||||||
|
@ -943,7 +943,7 @@ func (l *testLDAPServer) Bind(bindDN, bindSimplePw string, conn net.Conn) (vldap
|
||||||
return vldap.LDAPResultSuccess, nil
|
return vldap.LDAPResultSuccess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return vldap.LDAPResultInvalidCredentials, errors.New("ldap: invalid credentials")
|
return vldap.LDAPResultInvalidCredentials, errors.ErrInvalidCred
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *testLDAPServer) Search(boundDN string, req vldap.SearchRequest,
|
func (l *testLDAPServer) Search(boundDN string, req vldap.SearchRequest,
|
||||||
|
|
|
@ -17,7 +17,7 @@ type ErrorList struct {
|
||||||
|
|
||||||
type ErrorCode int
|
type ErrorCode int
|
||||||
|
|
||||||
// nolint (golint)
|
// nolint: golint, stylecheck
|
||||||
const (
|
const (
|
||||||
BLOB_UNKNOWN ErrorCode = iota
|
BLOB_UNKNOWN ErrorCode = iota
|
||||||
BLOB_UPLOAD_INVALID
|
BLOB_UPLOAD_INVALID
|
||||||
|
@ -58,7 +58,7 @@ func (e ErrorCode) String() string {
|
||||||
return m[e]
|
return m[e]
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewError(code ErrorCode, detail ...interface{}) Error { //nolint (interfacer)
|
func NewError(code ErrorCode, detail ...interface{}) Error { //nolint: interfacer
|
||||||
var errMap = map[ErrorCode]Error{
|
var errMap = map[ErrorCode]Error{
|
||||||
BLOB_UNKNOWN: {
|
BLOB_UNKNOWN: {
|
||||||
Message: "blob unknown to registry",
|
Message: "blob unknown to registry",
|
||||||
|
|
|
@ -55,12 +55,12 @@ func (lc *LDAPClient) Connect() error {
|
||||||
// Reconnect with TLS
|
// Reconnect with TLS
|
||||||
if !lc.SkipTLS {
|
if !lc.SkipTLS {
|
||||||
config := &tls.Config{
|
config := &tls.Config{
|
||||||
InsecureSkipVerify: lc.InsecureSkipVerify, // nolint (gosec): InsecureSkipVerify is not true by default
|
InsecureSkipVerify: lc.InsecureSkipVerify, // nolint: gosec // InsecureSkipVerify is not true by default
|
||||||
RootCAs: lc.ClientCAs,
|
RootCAs: lc.ClientCAs,
|
||||||
}
|
}
|
||||||
if lc.ClientCertificates != nil && len(lc.ClientCertificates) > 0 {
|
if lc.ClientCertificates != nil && len(lc.ClientCertificates) > 0 {
|
||||||
config.Certificates = lc.ClientCertificates
|
config.Certificates = lc.ClientCertificates
|
||||||
config.BuildNameToCertificate()
|
config.BuildNameToCertificate() // nolint: staticcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
err = l.StartTLS(config)
|
err = l.StartTLS(config)
|
||||||
|
@ -72,13 +72,13 @@ func (lc *LDAPClient) Connect() error {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
config := &tls.Config{
|
config := &tls.Config{
|
||||||
InsecureSkipVerify: lc.InsecureSkipVerify, // nolint (gosec): InsecureSkipVerify is not true by default
|
InsecureSkipVerify: lc.InsecureSkipVerify, // nolint: gosec // InsecureSkipVerify is not true by default
|
||||||
ServerName: lc.ServerName,
|
ServerName: lc.ServerName,
|
||||||
RootCAs: lc.ClientCAs,
|
RootCAs: lc.ClientCAs,
|
||||||
}
|
}
|
||||||
if lc.ClientCertificates != nil && len(lc.ClientCertificates) > 0 {
|
if lc.ClientCertificates != nil && len(lc.ClientCertificates) > 0 {
|
||||||
config.Certificates = lc.ClientCertificates
|
config.Certificates = lc.ClientCertificates
|
||||||
config.BuildNameToCertificate()
|
config.BuildNameToCertificate() // nolint: staticcheck
|
||||||
}
|
}
|
||||||
l, err = goldap.DialTLS("tcp", address, config)
|
l, err = goldap.DialTLS("tcp", address, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -2,7 +2,7 @@ package api
|
||||||
|
|
||||||
import "regexp"
|
import "regexp"
|
||||||
|
|
||||||
// nolint (gochecknoglobals)
|
// nolint: gochecknoglobals
|
||||||
var (
|
var (
|
||||||
// alphaNumericRegexp defines the alpha numeric atom, typically a
|
// alphaNumericRegexp defines the alpha numeric atom, typically a
|
||||||
// component of names. This only allows lower case characters and digits.
|
// component of names. This only allows lower case characters and digits.
|
||||||
|
|
|
@ -21,7 +21,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
_ "github.com/anuvu/zot/docs" // nolint (golint) - as required by swaggo
|
_ "github.com/anuvu/zot/docs" // as required by swaggo
|
||||||
"github.com/anuvu/zot/errors"
|
"github.com/anuvu/zot/errors"
|
||||||
"github.com/anuvu/zot/pkg/log"
|
"github.com/anuvu/zot/pkg/log"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
@ -50,7 +50,7 @@ func NewRouteHandler(c *Controller) *RouteHandler {
|
||||||
return rh
|
return rh
|
||||||
}
|
}
|
||||||
|
|
||||||
// blobRLockWrapper calls the real handler with read-lock held
|
// blobRLockWrapper calls the real handler with read-lock held.
|
||||||
func (rh *RouteHandler) blobRLockWrapper(f func(w http.ResponseWriter,
|
func (rh *RouteHandler) blobRLockWrapper(f func(w http.ResponseWriter,
|
||||||
r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -60,7 +60,7 @@ func (rh *RouteHandler) blobRLockWrapper(f func(w http.ResponseWriter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// blobLockWrapper calls the real handler with write-lock held
|
// blobLockWrapper calls the real handler with write-lock held.
|
||||||
func (rh *RouteHandler) blobLockWrapper(f func(w http.ResponseWriter,
|
func (rh *RouteHandler) blobLockWrapper(f func(w http.ResponseWriter,
|
||||||
r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -117,7 +117,7 @@ func (rh *RouteHandler) SetupRoutes() {
|
||||||
// @Router /v2/ [get]
|
// @Router /v2/ [get]
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok".
|
||||||
func (rh *RouteHandler) CheckVersionSupport(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) CheckVersionSupport(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set(DistAPIVersion, "registry/2.0")
|
w.Header().Set(DistAPIVersion, "registry/2.0")
|
||||||
// NOTE: compatibility workaround - return this header in "allowed-read" mode to allow for clients to
|
// NOTE: compatibility workaround - return this header in "allowed-read" mode to allow for clients to
|
||||||
|
@ -151,7 +151,7 @@ type ImageTags struct {
|
||||||
// @Param last query string true "last tag value for pagination"
|
// @Param last query string true "last tag value for pagination"
|
||||||
// @Success 200 {object} api.ImageTags
|
// @Success 200 {object} api.ImageTags
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 400 {string} string "bad request"
|
// @Failure 400 {string} string "bad request".
|
||||||
func (rh *RouteHandler) ListTags(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) ListTags(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -260,7 +260,7 @@ func (rh *RouteHandler) ListTags(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Header 200 {object} api.DistContentDigestKey
|
// @Header 200 {object} api.DistContentDigestKey
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error".
|
||||||
func (rh *RouteHandler) CheckManifest(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) CheckManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -299,7 +299,7 @@ func (rh *RouteHandler) CheckManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: https://github.com/swaggo/swag/issues/387
|
// NOTE: https://github.com/swaggo/swag/issues/387.
|
||||||
type ImageManifest struct {
|
type ImageManifest struct {
|
||||||
ispec.Manifest
|
ispec.Manifest
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,7 @@ type ImageManifest struct {
|
||||||
// @Header 200 {object} api.DistContentDigestKey
|
// @Header 200 {object} api.DistContentDigestKey
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/manifests/{reference} [get]
|
// @Router /v2/{name}/manifests/{reference} [get].
|
||||||
func (rh *RouteHandler) GetManifest(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) GetManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -367,7 +367,7 @@ func (rh *RouteHandler) GetManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Failure 400 {string} string "bad request"
|
// @Failure 400 {string} string "bad request"
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/manifests/{reference} [put]
|
// @Router /v2/{name}/manifests/{reference} [put].
|
||||||
func (rh *RouteHandler) UpdateManifest(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) UpdateManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -433,7 +433,7 @@ func (rh *RouteHandler) UpdateManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Param name path string true "repository name"
|
// @Param name path string true "repository name"
|
||||||
// @Param reference path string true "image reference or digest"
|
// @Param reference path string true "image reference or digest"
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Router /v2/{name}/manifests/{reference} [delete]
|
// @Router /v2/{name}/manifests/{reference} [delete].
|
||||||
func (rh *RouteHandler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -481,7 +481,7 @@ func (rh *RouteHandler) DeleteManifest(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Param digest path string true "blob/layer digest"
|
// @Param digest path string true "blob/layer digest"
|
||||||
// @Success 200 {object} api.ImageManifest
|
// @Success 200 {object} api.ImageManifest
|
||||||
// @Header 200 {object} api.DistContentDigestKey
|
// @Header 200 {object} api.DistContentDigestKey
|
||||||
// @Router /v2/{name}/blobs/{digest} [head]
|
// @Router /v2/{name}/blobs/{digest} [head].
|
||||||
func (rh *RouteHandler) CheckBlob(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) CheckBlob(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -535,7 +535,7 @@ func (rh *RouteHandler) CheckBlob(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Param digest path string true "blob/layer digest"
|
// @Param digest path string true "blob/layer digest"
|
||||||
// @Header 200 {object} api.DistContentDigestKey
|
// @Header 200 {object} api.DistContentDigestKey
|
||||||
// @Success 200 {object} api.ImageManifest
|
// @Success 200 {object} api.ImageManifest
|
||||||
// @Router /v2/{name}/blobs/{digest} [get]
|
// @Router /v2/{name}/blobs/{digest} [get].
|
||||||
func (rh *RouteHandler) GetBlob(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) GetBlob(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -584,7 +584,7 @@ func (rh *RouteHandler) GetBlob(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Param name path string true "repository name"
|
// @Param name path string true "repository name"
|
||||||
// @Param digest path string true "blob/layer digest"
|
// @Param digest path string true "blob/layer digest"
|
||||||
// @Success 202 {string} string "accepted"
|
// @Success 202 {string} string "accepted"
|
||||||
// @Router /v2/{name}/blobs/{digest} [delete]
|
// @Router /v2/{name}/blobs/{digest} [delete].
|
||||||
func (rh *RouteHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -631,7 +631,7 @@ func (rh *RouteHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Header 202 {string} Range "bytes=0-0"
|
// @Header 202 {string} Range "bytes=0-0"
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/blobs/uploads [post]
|
// @Router /v2/{name}/blobs/uploads [post].
|
||||||
func (rh *RouteHandler) CreateBlobUpload(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) CreateBlobUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -736,7 +736,7 @@ func (rh *RouteHandler) CreateBlobUpload(w http.ResponseWriter, r *http.Request)
|
||||||
// @Header 202 {string} Range "bytes=0-128"
|
// @Header 202 {string} Range "bytes=0-128"
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/blobs/uploads/{session_id} [get]
|
// @Router /v2/{name}/blobs/uploads/{session_id} [get].
|
||||||
func (rh *RouteHandler) GetBlobUpload(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) GetBlobUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -795,7 +795,7 @@ func (rh *RouteHandler) GetBlobUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 416 {string} string "range not satisfiable"
|
// @Failure 416 {string} string "range not satisfiable"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/blobs/uploads/{session_id} [patch]
|
// @Router /v2/{name}/blobs/uploads/{session_id} [patch].
|
||||||
func (rh *RouteHandler) PatchBlobUpload(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) PatchBlobUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -893,7 +893,7 @@ func (rh *RouteHandler) PatchBlobUpload(w http.ResponseWriter, r *http.Request)
|
||||||
// @Header 200 {object} api.DistContentDigestKey
|
// @Header 200 {object} api.DistContentDigestKey
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/blobs/uploads/{session_id} [put]
|
// @Router /v2/{name}/blobs/uploads/{session_id} [put].
|
||||||
func (rh *RouteHandler) UpdateBlobUpload(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) UpdateBlobUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
rh.c.Log.Info().Interface("headers", r.Header).Msg("HEADERS")
|
rh.c.Log.Info().Interface("headers", r.Header).Msg("HEADERS")
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
|
@ -1018,7 +1018,7 @@ finish:
|
||||||
// @Success 200 {string} string "ok"
|
// @Success 200 {string} string "ok"
|
||||||
// @Failure 404 {string} string "not found"
|
// @Failure 404 {string} string "not found"
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/{name}/blobs/uploads/{session_id} [delete]
|
// @Router /v2/{name}/blobs/uploads/{session_id} [delete].
|
||||||
func (rh *RouteHandler) DeleteBlobUpload(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) DeleteBlobUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
name, ok := vars["name"]
|
name, ok := vars["name"]
|
||||||
|
@ -1064,7 +1064,7 @@ type RepositoryList struct {
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} api.RepositoryList
|
// @Success 200 {object} api.RepositoryList
|
||||||
// @Failure 500 {string} string "internal server error"
|
// @Failure 500 {string} string "internal server error"
|
||||||
// @Router /v2/_catalog [get]
|
// @Router /v2/_catalog [get].
|
||||||
func (rh *RouteHandler) ListRepositories(w http.ResponseWriter, r *http.Request) {
|
func (rh *RouteHandler) ListRepositories(w http.ResponseWriter, r *http.Request) {
|
||||||
repos, err := rh.c.ImageStore.GetRepositories()
|
repos, err := rh.c.ImageStore.GetRepositories()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// metadataConfig reports metadata after parsing, which we use to track
|
// metadataConfig reports metadata after parsing, which we use to track
|
||||||
// errors
|
// errors.
|
||||||
func metadataConfig(md *mapstructure.Metadata) viper.DecoderConfigOption {
|
func metadataConfig(md *mapstructure.Metadata) viper.DecoderConfigOption {
|
||||||
return func(c *mapstructure.DecoderConfig) {
|
return func(c *mapstructure.DecoderConfig) {
|
||||||
c.Metadata = md
|
c.Metadata = md
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//nolint (dupl)
|
// nolint: dupl
|
||||||
package v1_0_0
|
package v1_0_0 // nolint:stylecheck,golint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@ -14,7 +14,7 @@ import (
|
||||||
"github.com/anuvu/zot/pkg/compliance"
|
"github.com/anuvu/zot/pkg/compliance"
|
||||||
godigest "github.com/opencontainers/go-digest"
|
godigest "github.com/opencontainers/go-digest"
|
||||||
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey" // nolint:golint,stylecheck
|
||||||
"github.com/smartystreets/goconvey/convey/reporting"
|
"github.com/smartystreets/goconvey/convey/reporting"
|
||||||
"gopkg.in/resty.v1"
|
"gopkg.in/resty.v1"
|
||||||
)
|
)
|
||||||
|
@ -29,8 +29,8 @@ func Location(baseURL string, resp *resty.Response) string {
|
||||||
if loc[0] == '/' {
|
if loc[0] == '/' {
|
||||||
return baseURL + loc
|
return baseURL + loc
|
||||||
}
|
}
|
||||||
return loc
|
|
||||||
|
|
||||||
|
return loc
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
||||||
|
@ -40,6 +40,7 @@ func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
||||||
|
|
||||||
if config.OutputJSON {
|
if config.OutputJSON {
|
||||||
outputJSONEnter()
|
outputJSONEnter()
|
||||||
|
|
||||||
defer outputJSONExit()
|
defer outputJSONExit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -688,6 +689,7 @@ func CheckWorkflows(t *testing.T, config *compliance.Config) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint: gochecknoglobals
|
||||||
var (
|
var (
|
||||||
old *os.File
|
old *os.File
|
||||||
r *os.File
|
r *os.File
|
||||||
|
@ -709,7 +711,12 @@ func outputJSONEnter() {
|
||||||
// copy the output in a separate goroutine so printing can't block indefinitely
|
// copy the output in a separate goroutine so printing can't block indefinitely
|
||||||
go func() {
|
go func() {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
io.Copy(&buf, r)
|
|
||||||
|
_, err := io.Copy(&buf, r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
outC <- buf.String()
|
outC <- buf.String()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -717,7 +724,9 @@ func outputJSONEnter() {
|
||||||
func outputJSONExit() {
|
func outputJSONExit() {
|
||||||
// back to normal state
|
// back to normal state
|
||||||
w.Close()
|
w.Close()
|
||||||
|
|
||||||
os.Stdout = old // restoring the real stdout
|
os.Stdout = old // restoring the real stdout
|
||||||
|
|
||||||
out := <-outC
|
out := <-outC
|
||||||
|
|
||||||
// The output of JSON is combined with regular output, so we look for the
|
// The output of JSON is combined with regular output, so we look for the
|
||||||
|
@ -734,13 +743,16 @@ func outputJSONExit() {
|
||||||
|
|
||||||
func validateMinifyRawJSON(rawJSON string) string {
|
func validateMinifyRawJSON(rawJSON string) string {
|
||||||
var j interface{}
|
var j interface{}
|
||||||
|
|
||||||
err := json.Unmarshal([]byte(rawJSON), &j)
|
err := json.Unmarshal([]byte(rawJSON), &j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
rawJSONBytesMinified, err := json.Marshal(j)
|
rawJSONBytesMinified, err := json.Marshal(j)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return string(rawJSONBytesMinified)
|
return string(rawJSONBytesMinified)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
//nolint (dupl)
|
|
||||||
package v1_0_0_test
|
package v1_0_0_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -16,6 +15,7 @@ import (
|
||||||
"gopkg.in/resty.v1"
|
"gopkg.in/resty.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint: gochecknoglobals
|
||||||
var (
|
var (
|
||||||
listenAddress = "127.0.0.1"
|
listenAddress = "127.0.0.1"
|
||||||
)
|
)
|
||||||
|
@ -39,12 +39,13 @@ func TestWorkflowsOutputJSON(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// start local server on random open port
|
// start local server on random open port.
|
||||||
func startServer() (*api.Controller, string) {
|
func startServer() (*api.Controller, string) {
|
||||||
portInt, err := freeport.GetFreePort()
|
portInt, err := freeport.GetFreePort()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
randomPort := fmt.Sprintf("%d", portInt)
|
randomPort := fmt.Sprintf("%d", portInt)
|
||||||
fmt.Println(randomPort)
|
fmt.Println(randomPort)
|
||||||
|
|
||||||
|
@ -52,12 +53,14 @@ func startServer() (*api.Controller, string) {
|
||||||
config.HTTP.Address = listenAddress
|
config.HTTP.Address = listenAddress
|
||||||
config.HTTP.Port = randomPort
|
config.HTTP.Port = randomPort
|
||||||
ctrl := api.NewController(config)
|
ctrl := api.NewController(config)
|
||||||
|
|
||||||
dir, err := ioutil.TempDir("", "oci-repo-test")
|
dir, err := ioutil.TempDir("", "oci-repo-test")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrl.Config.Storage.RootDirectory = dir
|
ctrl.Config.Storage.RootDirectory = dir
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// this blocks
|
// this blocks
|
||||||
if err := ctrl.Run(); err != nil {
|
if err := ctrl.Run(); err != nil {
|
||||||
|
@ -66,12 +69,14 @@ func startServer() (*api.Controller, string) {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
baseURL := fmt.Sprintf("http://%s:%s", listenAddress, randomPort)
|
baseURL := fmt.Sprintf("http://%s:%s", listenAddress, randomPort)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// poll until ready
|
// poll until ready
|
||||||
resp, _ := resty.R().Get(baseURL)
|
resp, _ := resty.R().Get(baseURL)
|
||||||
if resp.StatusCode() == 404 {
|
if resp.StatusCode() == 404 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +84,13 @@ func startServer() (*api.Controller, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func stopServer(ctrl *api.Controller) {
|
func stopServer(ctrl *api.Controller) {
|
||||||
ctrl.Server.Shutdown(context.Background())
|
err := ctrl.Server.Shutdown(context.Background())
|
||||||
os.RemoveAll(ctrl.Config.Storage.RootDirectory)
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.RemoveAll(ctrl.Config.Storage.RootDirectory)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger extends zerolog's Logger
|
// Logger extends zerolog's Logger.
|
||||||
type Logger struct {
|
type Logger struct {
|
||||||
zerolog.Logger
|
zerolog.Logger
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Cache struct {
|
||||||
log zlog.Logger
|
log zlog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blob is a blob record
|
// Blob is a blob record.
|
||||||
type Blob struct {
|
type Blob struct {
|
||||||
Path string
|
Path string
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
// BlobUploadDir defines the upload directory for blob uploads.
|
// BlobUploadDir defines the upload directory for blob uploads.
|
||||||
BlobUploadDir = ".uploads"
|
BlobUploadDir = ".uploads"
|
||||||
|
schemaVersion = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlobUpload models and upload request.
|
// BlobUpload models and upload request.
|
||||||
|
@ -68,22 +69,22 @@ func NewImageStore(rootDir string, gc bool, dedupe bool, log zlog.Logger) *Image
|
||||||
return is
|
return is
|
||||||
}
|
}
|
||||||
|
|
||||||
// RLock read-lock
|
// RLock read-lock.
|
||||||
func (is *ImageStore) RLock() {
|
func (is *ImageStore) RLock() {
|
||||||
is.lock.RLock()
|
is.lock.RLock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RUnlock read-unlock
|
// RUnlock read-unlock.
|
||||||
func (is *ImageStore) RUnlock() {
|
func (is *ImageStore) RUnlock() {
|
||||||
is.lock.RUnlock()
|
is.lock.RUnlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock write-lock
|
// Lock write-lock.
|
||||||
func (is *ImageStore) Lock() {
|
func (is *ImageStore) Lock() {
|
||||||
is.lock.Lock()
|
is.lock.Lock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unlock write-unlock
|
// Unlock write-unlock.
|
||||||
func (is *ImageStore) Unlock() {
|
func (is *ImageStore) Unlock() {
|
||||||
is.lock.Unlock()
|
is.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -111,7 +112,7 @@ func (is *ImageStore) InitRepo(name string) error {
|
||||||
is.log.Panic().Err(err).Msg("unable to marshal JSON")
|
is.log.Panic().Err(err).Msg("unable to marshal JSON")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.WriteFile(ilPath, buf, 0644); err != nil {
|
if err := ioutil.WriteFile(ilPath, buf, 0644); err != nil { //nolint: gosec
|
||||||
is.log.Error().Err(err).Str("file", ilPath).Msg("unable to write file")
|
is.log.Error().Err(err).Str("file", ilPath).Msg("unable to write file")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -128,7 +129,7 @@ func (is *ImageStore) InitRepo(name string) error {
|
||||||
is.log.Panic().Err(err).Msg("unable to marshal JSON")
|
is.log.Panic().Err(err).Msg("unable to marshal JSON")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.WriteFile(indexPath, buf, 0644); err != nil {
|
if err := ioutil.WriteFile(indexPath, buf, 0644); err != nil { //nolint: gosec
|
||||||
is.log.Error().Err(err).Str("file", indexPath).Msg("unable to write file")
|
is.log.Error().Err(err).Str("file", indexPath).Msg("unable to write file")
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -152,7 +153,7 @@ func (is *ImageStore) ValidateRepo(name string) (bool, error) {
|
||||||
is.log.Error().Err(err).Str("dir", dir).Msg("unable to read directory")
|
is.log.Error().Err(err).Str("dir", dir).Msg("unable to read directory")
|
||||||
return false, errors.ErrRepoNotFound
|
return false, errors.ErrRepoNotFound
|
||||||
}
|
}
|
||||||
|
// nolint:gomnd
|
||||||
if len(files) < 3 {
|
if len(files) < 3 {
|
||||||
return false, errors.ErrRepoBadVersion
|
return false, errors.ErrRepoBadVersion
|
||||||
}
|
}
|
||||||
|
@ -365,7 +366,7 @@ func (is *ImageStore) PutImageManifest(repo string, reference string, mediaType
|
||||||
return "", errors.ErrBadManifest
|
return "", errors.ErrBadManifest
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.SchemaVersion != 2 {
|
if m.SchemaVersion != schemaVersion {
|
||||||
is.log.Error().Int("SchemaVersion", m.SchemaVersion).Msg("invalid manifest")
|
is.log.Error().Int("SchemaVersion", m.SchemaVersion).Msg("invalid manifest")
|
||||||
return "", errors.ErrBadManifest
|
return "", errors.ErrBadManifest
|
||||||
}
|
}
|
||||||
|
@ -463,7 +464,7 @@ func (is *ImageStore) PutImageManifest(repo string, reference string, mediaType
|
||||||
ensureDir(dir, is.log)
|
ensureDir(dir, is.log)
|
||||||
file := path.Join(dir, mDigest.Encoded())
|
file := path.Join(dir, mDigest.Encoded())
|
||||||
|
|
||||||
if err := ioutil.WriteFile(file, body, 0644); err != nil {
|
if err := ioutil.WriteFile(file, body, 0600); err != nil {
|
||||||
is.log.Error().Err(err).Str("file", file).Msg("unable to write")
|
is.log.Error().Err(err).Str("file", file).Msg("unable to write")
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -479,7 +480,7 @@ func (is *ImageStore) PutImageManifest(repo string, reference string, mediaType
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.WriteFile(file, buf, 0644); err != nil {
|
if err := ioutil.WriteFile(file, buf, 0644); err != nil { //nolint: gosec
|
||||||
is.log.Error().Err(err).Str("file", file).Msg("unable to write")
|
is.log.Error().Err(err).Str("file", file).Msg("unable to write")
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -556,7 +557,7 @@ func (is *ImageStore) DeleteImageManifest(repo string, reference string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ioutil.WriteFile(file, buf, 0644); err != nil {
|
if err := ioutil.WriteFile(file, buf, 0644); err != nil { //nolint: gosec
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -771,7 +772,7 @@ func (is *ImageStore) FinishBlobUpload(repo string, uuid string, body io.Reader,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FullBlobUpload handles a full blob upload, and no partial session is created
|
// FullBlobUpload handles a full blob upload, and no partial session is created.
|
||||||
func (is *ImageStore) FullBlobUpload(repo string, body io.Reader, digest string) (string, int64, error) {
|
func (is *ImageStore) FullBlobUpload(repo string, body io.Reader, digest string) (string, int64, error) {
|
||||||
if err := is.InitRepo(repo); err != nil {
|
if err := is.InitRepo(repo); err != nil {
|
||||||
return "", -1, err
|
return "", -1, err
|
||||||
|
@ -836,11 +837,14 @@ func (is *ImageStore) FullBlobUpload(repo string, body io.Reader, digest string)
|
||||||
return uuid, n, nil
|
return uuid, n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint (interfacer)
|
// nolint:interfacer
|
||||||
func (is *ImageStore) DedupeBlob(src string, dstDigest godigest.Digest, dst string) error {
|
func (is *ImageStore) DedupeBlob(src string, dstDigest godigest.Digest, dst string) error {
|
||||||
retry:
|
retry:
|
||||||
is.log.Debug().Str("src", src).Str("dstDigest", dstDigest.String()).Str("dst", dst).Msg("dedupe: ENTER")
|
is.log.Debug().Str("src", src).Str("dstDigest", dstDigest.String()).Str("dst", dst).Msg("dedupe: ENTER")
|
||||||
|
|
||||||
dstRecord, err := is.cache.GetBlob(dstDigest.String())
|
dstRecord, err := is.cache.GetBlob(dstDigest.String())
|
||||||
|
|
||||||
|
// nolint:goerr113
|
||||||
if err != nil && err != errors.ErrCacheMiss {
|
if err != nil && err != errors.ErrCacheMiss {
|
||||||
is.log.Error().Err(err).Str("blobPath", dst).Msg("dedupe: unable to lookup blob record")
|
is.log.Error().Err(err).Str("blobPath", dst).Msg("dedupe: unable to lookup blob record")
|
||||||
return err
|
return err
|
||||||
|
@ -849,14 +853,17 @@ retry:
|
||||||
if dstRecord == "" {
|
if dstRecord == "" {
|
||||||
if err := is.cache.PutBlob(dstDigest.String(), dst); err != nil {
|
if err := is.cache.PutBlob(dstDigest.String(), dst); err != nil {
|
||||||
is.log.Error().Err(err).Str("blobPath", dst).Msg("dedupe: unable to insert blob record")
|
is.log.Error().Err(err).Str("blobPath", dst).Msg("dedupe: unable to insert blob record")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// move the blob from uploads to final dest
|
// move the blob from uploads to final dest
|
||||||
if err := os.Rename(src, dst); err != nil {
|
if err := os.Rename(src, dst); err != nil {
|
||||||
is.log.Error().Err(err).Str("src", src).Str("dst", dst).Msg("dedupe: unable to rename blob")
|
is.log.Error().Err(err).Str("src", src).Str("dst", dst).Msg("dedupe: unable to rename blob")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
is.log.Debug().Str("src", src).Str("dst", dst).Msg("dedupe: rename")
|
is.log.Debug().Str("src", src).Str("dst", dst).Msg("dedupe: rename")
|
||||||
} else {
|
} else {
|
||||||
dstRecord = path.Join(is.rootDir, dstRecord)
|
dstRecord = path.Join(is.rootDir, dstRecord)
|
||||||
|
@ -866,7 +873,9 @@ retry:
|
||||||
is.log.Error().Err(err).Str("blobPath", dstRecord).Msg("dedupe: unable to stat")
|
is.log.Error().Err(err).Str("blobPath", dstRecord).Msg("dedupe: unable to stat")
|
||||||
// the actual blob on disk may have been removed by GC, so sync the cache
|
// the actual blob on disk may have been removed by GC, so sync the cache
|
||||||
if err := is.cache.DeleteBlob(dstDigest.String(), dst); err != nil {
|
if err := is.cache.DeleteBlob(dstDigest.String(), dst); err != nil {
|
||||||
|
// nolint:lll
|
||||||
is.log.Error().Err(err).Str("dstDigest", dstDigest.String()).Str("dst", dst).Msg("dedupe: unable to delete blob record")
|
is.log.Error().Err(err).Str("dstDigest", dstDigest.String()).Str("dst", dst).Msg("dedupe: unable to delete blob record")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
goto retry
|
goto retry
|
||||||
|
@ -874,11 +883,13 @@ retry:
|
||||||
dstFi, err := os.Stat(dst)
|
dstFi, err := os.Stat(dst)
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
is.log.Error().Err(err).Str("blobPath", dstRecord).Msg("dedupe: unable to stat")
|
is.log.Error().Err(err).Str("blobPath", dstRecord).Msg("dedupe: unable to stat")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !os.SameFile(dstFi, dstRecordFi) {
|
if !os.SameFile(dstFi, dstRecordFi) {
|
||||||
if err := os.Link(dstRecord, dst); err != nil {
|
if err := os.Link(dstRecord, dst); err != nil {
|
||||||
is.log.Error().Err(err).Str("blobPath", dst).Str("link", dstRecord).Msg("dedupe: unable to hard link")
|
is.log.Error().Err(err).Str("blobPath", dst).Str("link", dstRecord).Msg("dedupe: unable to hard link")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -930,7 +941,7 @@ func (is *ImageStore) CheckBlob(repo string, digest string,
|
||||||
|
|
||||||
// GetBlob returns a stream to read the blob.
|
// GetBlob returns a stream to read the blob.
|
||||||
// FIXME: we should probably parse the manifest and use (digest, mediaType) as a
|
// FIXME: we should probably parse the manifest and use (digest, mediaType) as a
|
||||||
// blob selector instead of directly downloading the blob
|
// blob selector instead of directly downloading the blob.
|
||||||
func (is *ImageStore) GetBlob(repo string, digest string, mediaType string) (io.Reader, int64, error) {
|
func (is *ImageStore) GetBlob(repo string, digest string, mediaType string) (io.Reader, int64, error) {
|
||||||
d, err := godigest.Parse(digest)
|
d, err := godigest.Parse(digest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -989,7 +1000,7 @@ func (is *ImageStore) DeleteBlob(repo string, digest string) error {
|
||||||
// garbage collection
|
// garbage collection
|
||||||
|
|
||||||
// Scrub will clean up all unreferenced blobs.
|
// Scrub will clean up all unreferenced blobs.
|
||||||
// TODO
|
// TODO.
|
||||||
func Scrub(dir string, fix bool) error {
|
func Scrub(dir string, fix bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -563,7 +563,7 @@ func TestNegativeCases(t *testing.T) {
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
So(os.RemoveAll(path.Join(dir, "test")), ShouldBeNil)
|
So(os.RemoveAll(path.Join(dir, "test")), ShouldBeNil)
|
||||||
So(il.InitRepo("test"), ShouldBeNil)
|
So(il.InitRepo("test"), ShouldBeNil)
|
||||||
So(ioutil.WriteFile(path.Join(dir, "test", "index.json"), []byte{}, 0755), ShouldBeNil)
|
So(ioutil.WriteFile(path.Join(dir, "test", "index.json"), []byte{}, 0600), ShouldBeNil)
|
||||||
_, err = il.GetImageTags("test")
|
_, err = il.GetImageTags("test")
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
})
|
})
|
||||||
|
@ -586,7 +586,7 @@ func TestNegativeCases(t *testing.T) {
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
So(os.RemoveAll(path.Join(dir, "test")), ShouldBeNil)
|
So(os.RemoveAll(path.Join(dir, "test")), ShouldBeNil)
|
||||||
So(il.InitRepo("test"), ShouldBeNil)
|
So(il.InitRepo("test"), ShouldBeNil)
|
||||||
So(ioutil.WriteFile(path.Join(dir, "test", "index.json"), []byte{}, 0755), ShouldBeNil)
|
So(ioutil.WriteFile(path.Join(dir, "test", "index.json"), []byte{}, 0600), ShouldBeNil)
|
||||||
_, _, _, err = il.GetImageManifest("test", "")
|
_, _, _, err = il.GetImageManifest("test", "")
|
||||||
So(err, ShouldNotBeNil)
|
So(err, ShouldNotBeNil)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue