@ -4,6 +4,7 @@ import (
"fmt"
"net/url"
"os"
"strings"
"testing"
"time"
@ -11,6 +12,7 @@ import (
"github.com/containrrr/watchtower/pkg/registry/auth"
wtTypes "github.com/containrrr/watchtower/pkg/types"
ref "github.com/docker/distribution/reference"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
@ -52,7 +54,7 @@ var _ = Describe("the auth module", func() {
mockCreated ,
mockDigest )
When( "getting an auth url ", func ( ) {
Describe( "GetToken ", func ( ) {
It ( "should parse the token from the response" ,
SkipIfCredentialsEmpty ( GHCRCredentials , func ( ) {
creds := fmt . Sprintf ( "%s:%s" , GHCRCredentials . Username , GHCRCredentials . Password )
@ -61,73 +63,100 @@ var _ = Describe("the auth module", func() {
Expect ( token ) . NotTo ( Equal ( "" ) )
} ) ,
)
} )
Describe ( "GetAuthURL" , func ( ) {
It ( "should create a valid auth url object based on the challenge header supplied" , func ( ) {
input := ` bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:user/image:pull" `
challenge := ` bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:user/image:pull" `
imageRef , err := ref . ParseNormalizedNamed ( "containrrr/watchtower" )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
expected := & url . URL {
Host : "ghcr.io" ,
Scheme : "https" ,
Path : "/token" ,
RawQuery : "scope=repository%3Acontainrrr%2Fwatchtower%3Apull&service=ghcr.io" ,
}
res , err := auth . GetAuthURL ( input , "containrrr/watchtower" )
URL , err := auth . GetAuthURL ( challenge , imageRef )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( res ) . To ( Equal ( expected ) )
Expect ( URL ) . To ( Equal ( expected ) )
} )
It ( "should create a valid auth url object based on the challenge header supplied" , func ( ) {
input := ` bearer realm="https://ghcr.io/token" `
res , err := auth . GetAuthURL ( input , "containrrr/watchtower" )
When ( "given an invalid challenge header" , func ( ) {
It ( "should return an error" , func ( ) {
challenge := ` bearer realm="https://ghcr.io/token" `
imageRef , err := ref . ParseNormalizedNamed ( "containrrr/watchtower" )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
URL , err := auth . GetAuthURL ( challenge , imageRef )
Expect ( err ) . To ( HaveOccurred ( ) )
Expect ( res ) . To ( BeNil ( ) )
Expect ( URL ) . To ( BeNil ( ) )
} )
} )
When ( "deriving the auth scope from an image name" , func ( ) {
It ( "should prepend official dockerhub images with \"library/\"" , func ( ) {
Expect ( getScopeFromImageAuthURL ( "registry" ) ) . To ( Equal ( "library/registry" ) )
Expect ( getScopeFromImageAuthURL ( "docker.io/registry" ) ) . To ( Equal ( "library/registry" ) )
Expect ( getScopeFromImageAuthURL ( "index.docker.io/registry" ) ) . To ( Equal ( "library/registry" ) )
} )
It ( "should not include vanity hosts\"" , func ( ) {
Expect ( getScopeFromImageAuthURL ( "docker.io/containrrr/watchtower" ) ) . To ( Equal ( "containrrr/watchtower" ) )
Expect ( getScopeFromImageAuthURL ( "index.docker.io/containrrr/watchtower" ) ) . To ( Equal ( "containrrr/watchtower" ) )
} )
It ( "should not destroy three segment image names\"" , func ( ) {
Expect ( getScopeFromImageAuthURL ( "piksel/containrrr/watchtower" ) ) . To ( Equal ( "piksel/containrrr/watchtower" ) )
Expect ( getScopeFromImageAuthURL ( "ghcr.io/piksel/containrrr/watchtower" ) ) . To ( Equal ( "piksel/containrrr/watchtower" ) )
} )
It ( "should not prepend library/ to image names if they're not on dockerhub" , func ( ) {
Expect ( getScopeFromImageAuthURL ( "ghcr.io/watchtower" ) ) . To ( Equal ( "watchtower" ) )
Expect ( getScopeFromImageAuthURL ( "ghcr.io/containrrr/watchtower" ) ) . To ( Equal ( "containrrr/watchtower" ) )
} )
} )
It ( "should not crash when an empty field is recieved" , func ( ) {
input := ` bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:user/image:pull", `
res , err := auth . GetAuthURL ( input , "containrrr/watchtower" )
imageRef , err := ref . ParseNormalizedNamed ( "containrrr/watchtower" )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
res , err := auth . GetAuthURL ( input , imageRef )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( res ) . NotTo ( BeNil ( ) )
} )
It ( "should not crash when a field without a value is recieved" , func ( ) {
input := ` bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:user/image:pull",valuelesskey `
res , err := auth . GetAuthURL ( input , "containrrr/watchtower" )
imageRef , err := ref . ParseNormalizedNamed ( "containrrr/watchtower" )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
res , err := auth . GetAuthURL ( input , imageRef )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
Expect ( res ) . NotTo ( BeNil ( ) )
} )
} )
When ( "getting a challenge url" , func ( ) {
Describe ( "GetChallengeURL" , func ( ) {
It ( "should create a valid challenge url object based on the image ref supplied" , func ( ) {
expected := url . URL { Host : "ghcr.io" , Scheme : "https" , Path : "/v2/" }
Expect ( auth . GetChallengeURL ( "ghcr.io/containrrr/watchtower:latest" ) ) . To ( Equal ( expected ) )
imageRef , _ := ref . ParseNormalizedNamed ( "ghcr.io/containrrr/watchtower:latest" )
Expect ( auth . GetChallengeURL ( imageRef ) ) . To ( Equal ( expected ) )
} )
It ( "should assume dockerhub if the image ref is not fully qualified" , func ( ) {
It ( "should assume Docker Hub for image refs with no explicit registry ", func ( ) {
expected := url . URL { Host : "index.docker.io" , Scheme : "https" , Path : "/v2/" }
Expect ( auth . GetChallengeURL ( "containrrr/watchtower:latest" ) ) . To ( Equal ( expected ) )
imageRef , _ := ref . ParseNormalizedNamed ( "containrrr/watchtower:latest" )
Expect ( auth . GetChallengeURL ( imageRef ) ) . To ( Equal ( expected ) )
} )
It ( "should convert legacy dockerhub hostnames to index. docker.io", func ( ) {
It ( "should use index.docker.io if the image ref specifies docker.io", func ( ) {
expected := url . URL { Host : "index.docker.io" , Scheme : "https" , Path : "/v2/" }
Expect ( auth . GetChallengeURL ( "docker.io/containrrr/watchtower:latest" ) ) . To ( Equal ( expected ) )
Expect ( auth . GetChallengeURL ( "registry-1.docker.io/containrrr/watchtower:latest" ) ) . To ( Equal ( expected ) )
imageRef , _ := ref . ParseNormalizedNamed ( "docker.io/containrrr/watchtower:latest" )
Expect ( auth . GetChallengeURL ( imageRef ) ) . To ( Equal ( expected ) )
} )
} )
When ( "getting the auth scope from an image name" , func ( ) {
It ( "should prepend official dockerhub images with \"library/\"" , func ( ) {
Expect ( auth . GetScopeFromImageName ( "docker.io/registry" , "index.docker.io" ) ) . To ( Equal ( "library/registry" ) )
Expect ( auth . GetScopeFromImageName ( "docker.io/registry" , "docker.io" ) ) . To ( Equal ( "library/registry" ) )
} )
Expect ( auth . GetScopeFromImageName ( "registry" , "index.docker.io" ) ) . To ( Equal ( "library/registry" ) )
Expect ( auth . GetScopeFromImageName ( "watchtower" , "registry-1.docker.io" ) ) . To ( Equal ( "library/watchtower" ) )
var scopeImageRegexp = MatchRegexp ( "^repository:[a-z0-9]+(/[a-z0-9]+)*:pull$" )
} )
It ( "should not include vanity hosts\"" , func ( ) {
Expect ( auth . GetScopeFromImageName ( "docker.io/containrrr/watchtower" , "index.docker.io" ) ) . To ( Equal ( "containrrr/watchtower" ) )
Expect ( auth . GetScopeFromImageName ( "index.docker.io/containrrr/watchtower" , "index.docker.io" ) ) . To ( Equal ( "containrrr/watchtower" ) )
} )
It ( "should not destroy three segment image names\"" , func ( ) {
Expect ( auth . GetScopeFromImageName ( "piksel/containrrr/watchtower" , "index.docker.io" ) ) . To ( Equal ( "containrrr/watchtower" ) )
Expect ( auth . GetScopeFromImageName ( "piksel/containrrr/watchtower" , "ghcr.io" ) ) . To ( Equal ( "piksel/containrrr/watchtower" ) )
} )
It ( "should not add \"library/\" for one segment image names if they're not on dockerhub" , func ( ) {
Expect ( auth . GetScopeFromImageName ( "ghcr.io/watchtower" , "ghcr.io" ) ) . To ( Equal ( "watchtower" ) )
Expect ( auth . GetScopeFromImageName ( "watchtower" , "ghcr.io" ) ) . To ( Equal ( "watchtower" ) )
} )
} )
} )
func getScopeFromImageAuthURL ( imageName string ) string {
normalizedRef , _ := ref . ParseNormalizedNamed ( imageName )
challenge := ` bearer realm="https://dummy.host/token",service="dummy.host",scope="repository:user/image:pull" `
URL , _ := auth . GetAuthURL ( challenge , normalizedRef )
scope := URL . Query ( ) . Get ( "scope" )
Expect ( scopeImageRegexp . Match ( scope ) ) . To ( BeTrue ( ) )
return strings . Replace ( scope [ 11 : ] , ":pull" , "" , 1 )
}