mirror of https://github.com/helm/helm
Merge pull request #11711 from helm/oci-transport-refinement
commit
d27d1bde4c
@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type TLSRegistryClientTestSuite struct {
|
||||
TestSuite
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) SetupSuite() {
|
||||
// init test client
|
||||
dockerRegistry := setup(&suite.TestSuite, true, false)
|
||||
|
||||
// Start Docker registry
|
||||
go dockerRegistry.ListenAndServe()
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) TearDownSuite() {
|
||||
os.RemoveAll(suite.WorkspaceDir)
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) Test_0_Login() {
|
||||
err := suite.RegistryClient.Login(suite.DockerRegistryHost,
|
||||
LoginOptBasicAuth("badverybad", "ohsobad"),
|
||||
LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA))
|
||||
suite.NotNil(err, "error logging into registry with bad credentials")
|
||||
|
||||
err = suite.RegistryClient.Login(suite.DockerRegistryHost,
|
||||
LoginOptBasicAuth(testUsername, testPassword),
|
||||
LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA))
|
||||
suite.Nil(err, "no error logging into registry with good credentials")
|
||||
|
||||
err = suite.RegistryClient.Login(suite.DockerRegistryHost,
|
||||
LoginOptBasicAuth(testUsername, testPassword),
|
||||
LoginOptTLSClientConfig(tlsCert, tlsKey, tlsCA))
|
||||
suite.Nil(err, "no error logging into registry with good credentials, insecure mode")
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) Test_1_Push() {
|
||||
testPush(&suite.TestSuite)
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) Test_2_Pull() {
|
||||
testPull(&suite.TestSuite)
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) Test_3_Tags() {
|
||||
testTags(&suite.TestSuite)
|
||||
}
|
||||
|
||||
func (suite *TLSRegistryClientTestSuite) Test_4_Logout() {
|
||||
err := suite.RegistryClient.Logout("this-host-aint-real:5000")
|
||||
suite.NotNil(err, "error logging out of registry that has no entry")
|
||||
|
||||
err = suite.RegistryClient.Logout(suite.DockerRegistryHost)
|
||||
suite.Nil(err, "no error logging out of registry")
|
||||
}
|
||||
|
||||
func TestTLSRegistryClientTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(TLSRegistryClientTestSuite))
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDhzCCAm+gAwIBAgIUdI/ees1mQ4N++1jpF5xI5fq6TSUwDQYJKoZIhvcNAQEL
|
||||
BQAwUjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjENMAsG
|
||||
A1UECgwEaGVsbTEaMBgGA1UEAwwRcmVnaXN0cnktdGVzdC5jb20wIBcNMjIwOTIw
|
||||
MDgyMDQ2WhgPMzAyMjAxMjEwODIwNDZaMFIxCzAJBgNVBAYTAlVTMQswCQYDVQQI
|
||||
DAJDQTELMAkGA1UEBwwCU0YxDTALBgNVBAoMBGhlbG0xGjAYBgNVBAMMEXJlZ2lz
|
||||
dHJ5LXRlc3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0mxP
|
||||
WVkpDo3PnXalJhy9rSYuK8OIxcO1kBroEnILYrNWn5zpKioaBXZEYcaU6crc5N4j
|
||||
wQRC16wucyQAQh/d3ty7j5Wyy79CgH5AAKDbCacii4BgGUJ2xY6UXuKvwdsROAXN
|
||||
wEtXT5f3yO8bVboYrZRxJ4UuTUFndtuz2b230JFs2FzTv4QdLaPHo/S4FTW5xRn5
|
||||
Irhmcmkns+XY4AduscYtzydvIuuOS3CVmB8/sClo62F5DpBl68b+/WFwqLrkX5Sn
|
||||
ZWKx/fJPIxln5SavPXHEEcI14ZGNUhsv+4+sABHzVjBPK8oKjoNo8QmxDWdeWPgR
|
||||
sPj/H2oldE6KfgyoQQIDAQABo1MwUTAdBgNVHQ4EFgQUkkmPK6SIj4PY8YOw+Yer
|
||||
hKCOS7owHwYDVR0jBBgwFoAUkkmPK6SIj4PY8YOw+YerhKCOS7owDwYDVR0TAQH/
|
||||
BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEADSz9s8rcObLrUo8DpVRptWUxK3NH
|
||||
hvD7bYGQ9eJO9B4ojKSBKJRchP0m5kpVLorMRZDRw17T2GouKQn3g+Wcy+8CygxW
|
||||
1JDO/1iCZ8QX3vfwIfHTaKuY6eYcJyVmxL58bRI3qQNRZIU4s18tKFIazBluxS3g
|
||||
5Wp8kOCBssttsM+lEgC/cj7skl9CBKhUFupHPzXzha+1upJUK51Egc7M7nsrnpaZ
|
||||
2SY+PBEhSY5Wcuzb5m9tw7PJnkdRDS/dUOY6kSzJXgNMVV0GnN+Smucqmvrez0M5
|
||||
vHFMiQjlRxViVLJDNOCJYIjWNygAOvhJyRU2cTodIhZ/jbYqpNGAPc5Eyg==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDsTCCApmgAwIBAgIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEL
|
||||
MAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMQ0wCwYDVQQKDARoZWxtMRowGAYDVQQD
|
||||
DBFyZWdpc3RyeS10ZXN0LmNvbTAgFw0yMjA5MjAwODI4MzBaGA8yMTIyMDgyNzA4
|
||||
MjgzMFowWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEN
|
||||
MAsGA1UECgwEaGVsbTEhMB8GA1UEAwwYY2xpZW50LnJlZ2lzdHJ5LXRlc3QuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnvxfrJn8PeerlHJLnMVo
|
||||
p1yOT/kvFAoNhObhtDUosDLjQBt+vICfjWoTNIabIiBRTwkVt5CdGvx1oKsbH3iT
|
||||
VErL6N6MagIJdnOfBjxtlTL/TFtJ7U/VSUSxZwa+SV6HS4cmIntC/FV3MHjBlFJn
|
||||
klSdDXa5YdYE2xuSPse+zlGRfmPTNmHsiNWphGC54U6WZ1UI0G22+L/yO8BuEkSq
|
||||
47iCN6ZIw8ds+azl/woIEDJsVSgEapNsanBrJFnBUJBXh4lwpMB37U+6Ds1kUUuz
|
||||
GXhVWz1pmRBt+vXWN802MqRg2RnCjTb2gWbmg7En4uFCTzx/GhRlJiV47O15n0g+
|
||||
tQIDAQABo4GIMIGFMB8GA1UdIwQYMBaAFJJJjyukiI+D2PGDsPmHq4Sgjku6MAkG
|
||||
A1UdEwQCMAAwCwYDVR0PBAQDAgTwMCsGA1UdEQQkMCKCCWxvY2FsaG9zdIIKMHg3
|
||||
ZjAwMDAwMYIJMTI3LjAuMC4xMB0GA1UdDgQWBBT+cCGLyj5wOIMG7TVqPyxPQsBi
|
||||
+DANBgkqhkiG9w0BAQsFAAOCAQEATIDXr3LmD1S+13lVG263rn21cDT3m4VycQCu
|
||||
oGNDuxtFwd/Zn/XnZLk2r1msz6YXWUqErJ8C7Ea7fFdimoJR5V3m7LYrYRPeLYVn
|
||||
aVqyNN4LD48Su3VO5sjTyFxXJJJ9C5HX8LU/Pw/517qzLOFrmsO/fXN/XE52erBE
|
||||
+K6vX4lyxnZyPfl3A/X/33G2tsGtHFK1uBILpn29fpeC/Pgm3Nj8ZqQ8rtcLZbog
|
||||
heqdKkHKWdL3i1deplwxT7xVnqsWszU6Znzm/C/VQSB4Isn4puQDKqVPwGobHgxY
|
||||
1zZr5mueot8mX9Qmg8IcWOVZ2u7nz8lw6+wpabkyjjdTC6iizg==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCe/F+smfw956uU
|
||||
ckucxWinXI5P+S8UCg2E5uG0NSiwMuNAG368gJ+NahM0hpsiIFFPCRW3kJ0a/HWg
|
||||
qxsfeJNUSsvo3oxqAgl2c58GPG2VMv9MW0ntT9VJRLFnBr5JXodLhyYie0L8VXcw
|
||||
eMGUUmeSVJ0Ndrlh1gTbG5I+x77OUZF+Y9M2YeyI1amEYLnhTpZnVQjQbbb4v/I7
|
||||
wG4SRKrjuII3pkjDx2z5rOX/CggQMmxVKARqk2xqcGskWcFQkFeHiXCkwHftT7oO
|
||||
zWRRS7MZeFVbPWmZEG369dY3zTYypGDZGcKNNvaBZuaDsSfi4UJPPH8aFGUmJXjs
|
||||
7XmfSD61AgMBAAECggEAKYp/5TWG9xXlezAyGZBrO++vL65IYtANoEBDkTainwds
|
||||
4X9NqithhS3GPt89Abm4BRK2nfQnWLnGcmjC+YIj3M5+YSZlQf2uQ0kKsDJx354n
|
||||
nufrdRp6/F36jJTye3E7oLx7dl8GrbAXKI8k5YByl4WMU8xFvA6TzjxyBf1jGb1E
|
||||
8JBZpnqwSHgtH0zGPqgcIsqmQjiMJ+wHNZxdvtjPPC8exy/yLL9Hhj2UaqZSMMRi
|
||||
afaAFXBLNvJ6Y/SUjRaL9liAyTQ0kJ+xR6TMDJ7ix0toGlylsK/3YesXEgAyui6c
|
||||
UC3dmSC4UDJW+fGLrj/hVBLdpMRpgrWzwXnRyr0RMQKBgQDDnJqAtULhlo0W4E29
|
||||
Oo7XYFEcilzxB3hxEQSmts53GeQZHo1gI4wthyMzAgY3uOCIUtB2lPkNLV+dU86A
|
||||
Cy1WTRL2vbwdM1qHz2tls4LNa+k+XTMWX7aqfCzOydBpV3Yehmnzb4NvFn9+QHjp
|
||||
5omwwOaG7dhJCVet3CUJctoeOwKBgQDQETAVd4xfwQ/cBbKgoQhrkHOr+gTWcKYP
|
||||
WD86EFDbRVboYDevU/dAj5Vwm5763zRsBFyL6/ZVUr9Wa1HHy0paE5YfdewMrRje
|
||||
LhHeTbrLJ4Q3I0ix3bawv/04B66hw+Yaom0bQV3gBrNk+Cn8VFAo6IKNy7A0pK3i
|
||||
KQmwoO+XzwKBgC3EqInQ33M07JIbrVTHLMDL8m6BGTn0C4Q4/SOcxjYrwqj18xI5
|
||||
fwTwB5ZZtOa4xSBgcBIuzQ7+PM7s2vYup073/aXpwuf6KgZ4y6IiHErAIvTKjbeA
|
||||
cZb2Mu23XqInKqX9wTCKOPB3DSGXKDNiE3ldyRJs+BwuqWsuhSPu0YYdAoGADjd+
|
||||
b5kRkGFisgf5opweNStTnAajWfusfRPsjg0bWUAtpgcdBu/XzyOAdIdNn5qsvEy3
|
||||
/h+LX10eEcuXdO1hETKRaWjnTh5tupCvS99HyiXTFOlmSDD8EKuto6xytD7sdBlx
|
||||
FxGqVmpey6FhTQp9x63LbeDjE1XFQ9TGArmcZWUCgYEAprSfhSemz9tP5tKKdYTc
|
||||
LM5eWqK0aB1sN/hCZVx86VcNBxRbV+POEASTYO9AyVMjthGRe6UnCjwdXKTJ/ToX
|
||||
KdtXINYeeK3hzANeCvtqg81qxi+8nmNLimtcjvFsB5g44LOFYyXqAD5FeQYTog1n
|
||||
t/TLHYY+S8BbJ9cXfObXqyE=
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDsTCCApmgAwIBAgIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzEL
|
||||
MAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMQ0wCwYDVQQKDARoZWxtMRowGAYDVQQD
|
||||
DBFyZWdpc3RyeS10ZXN0LmNvbTAgFw0yMjA5MjAwODI3NDZaGA8yMTIyMDgyNzA4
|
||||
Mjc0NlowWTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQHDAJTRjEN
|
||||
MAsGA1UECgwEaGVsbTEhMB8GA1UEAwwYc2VydmVyLnJlZ2lzdHJ5LXRlc3QuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxve7spJ44uC/f6BCUEKQ
|
||||
PA9Sqc+ulTXyptZROLa90o7GK9P1WW8hcDRIYaIU3Rh+o6E0QYwBwvspoEAKYP0q
|
||||
kp16pD1Ezf5VTikVElq20qvYOaAjvxFltIAmrxoCokkwEIsgEY6RYHZedimKWtdg
|
||||
kG7R0aNnwgognoz6j4GD/Z/HejCY54jckQczDdaxWrcbBdQ0h/WNjLwHmlids4H9
|
||||
ni4cas4An5TZ3cOA9ah+8PSRNYgSLFR34KuydLd8xx5E2fG8OuU5zCNaDQ4puYKP
|
||||
u+D6GNCdwi+w+Ac/3MTAX8ORLrB/8BCIMwnYi7g7En4a47ck21VqhfE+CH10AR07
|
||||
nQIDAQABo4GIMIGFMB8GA1UdIwQYMBaAFJJJjyukiI+D2PGDsPmHq4Sgjku6MAkG
|
||||
A1UdEwQCMAAwCwYDVR0PBAQDAgTwMCsGA1UdEQQkMCKCCWxvY2FsaG9zdIIKMHg3
|
||||
ZjAwMDAwMYIJMTI3LjAuMC4xMB0GA1UdDgQWBBRoIiJ5S3EJmcNUmjT+dxWO+14k
|
||||
ADANBgkqhkiG9w0BAQsFAAOCAQEAb6UOBss8IA3uT76LIK9TSNSyn6BoYlTFGwgx
|
||||
O2Cp4kqyKb370qAWV1QVVefQP1uftXpsdqhtwEL4jUptYO5yP4Udtg0QV0SsyMsg
|
||||
jXgaeuC7589lcJpmTvPj/XlnAZE6vmTrVPG4c1wEC+qCTSHAu3EBRN8hHKZFmLON
|
||||
254/6x2HlSTqwKzzJY5YEL8pP1kAIww40YMd5G5gFqCNdcg2FKB3ZWo9cFzCU3VK
|
||||
HoeOUG286GuEN6AG/YT2DIFAZpP+SUgjY8mj1CxoIv9LMNyF1Tm8kzQDU0IA2dfW
|
||||
1AY0edoHL2kLoUUKet/d7tayP9gnt0sOUrY2oZXrp+TvSHVTlw==
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,28 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG97uyknji4L9/
|
||||
oEJQQpA8D1Kpz66VNfKm1lE4tr3SjsYr0/VZbyFwNEhhohTdGH6joTRBjAHC+ymg
|
||||
QApg/SqSnXqkPUTN/lVOKRUSWrbSq9g5oCO/EWW0gCavGgKiSTAQiyARjpFgdl52
|
||||
KYpa12CQbtHRo2fCCiCejPqPgYP9n8d6MJjniNyRBzMN1rFatxsF1DSH9Y2MvAea
|
||||
WJ2zgf2eLhxqzgCflNndw4D1qH7w9JE1iBIsVHfgq7J0t3zHHkTZ8bw65TnMI1oN
|
||||
Dim5go+74PoY0J3CL7D4Bz/cxMBfw5EusH/wEIgzCdiLuDsSfhrjtyTbVWqF8T4I
|
||||
fXQBHTudAgMBAAECggEAD13Tr7tzPaZ487znUjaJ2DGgwz+obpqvhmYX+MbYSzo+
|
||||
oOTqVoFoNje7fVrcvKSnJzEMjaFoA2yNbvRzOMFkt9UUwzl+JmClqvcuSvAZnZSr
|
||||
CuxMxnVsAvBAzJY4LNt1LFnqXKDDpo0Nx5d2uYRXz1/XsZaqrUhF86jUsx+gF4bM
|
||||
LYe6SjXWtf1sumgE1gbil8NDLbqHPMvimQhLu1WgVxiarlye2NMyHxk6MTqwYOX3
|
||||
iinf3cuRFYuFyD1IHorreVAdOH0zuYvqLFylBbRqEfeOozVytX73yKfRK4lPobc+
|
||||
Q1n/mPzwyc9aVWKRo4WId0mA2rhP8sL7BvMFRwYnSwKBgQDdUqlel4/Fj2WfcsKa
|
||||
SMjmqM66tFDxH27Vp55RoS/Fr+RZSVYda7cdbMJaGVswbZevwsCS46l2BJJdJXHt
|
||||
UE1viKkKiIxGJzpH9Q1vyUEf+21eESnkr7HKoUrSpopwqOlc1dYPvn47aJukcGee
|
||||
vwMkiaG5IUaR5MCfLA8xQ89UPwKBgQDmJGWtrwcUIdEvRI1wg8Unj0chAyz+/KIR
|
||||
9jkVIyu4SUfThQp6GsCHsvc5TGN6yieGLIfrVb7qb8F2gDPdg8L/13zqAorpcK6E
|
||||
AagYLDgKWV4O2oGT4AGQrcz/66BYAfeD868r442bhyEkD7zLqZSbHlPTpy8bPKuC
|
||||
nen88JGJIwKBgD/OawHYVByywKt9XFk6jqDhHeh5v7QkScHS9zO1cp5dnUmYePk2
|
||||
aq5TAp0THlUR419KmFZAyEQ8AS5Vc0jlk82J6qIcx8QZ3xWLsnn93Yao59jsvdUu
|
||||
SeWPJpEgbl0YdV7MT1BurNnXyLdZqKX9j5xjCXrj+wJonpfFDgQ39nflAoGAd1bo
|
||||
YuggA5CFqL0jmvS5h4oEmFnNO2xFnorPjuZuBWH6nPSgOjElJTjoeg3iiAnL9Qei
|
||||
c6ZDGc5Zw9k3C+cHdyOG4tHutp534Hv7bo1/gd5Vp94m00eViDCX3R2SSBC9CO+U
|
||||
Jm4ZQE0SImEGxZVqOgW/8kD/bGBJj7HTZBZbYYECgYEAoGwLnE2TiMLfXIKXsmII
|
||||
h9+rZrPfFyDCM27+QIADpCv7Ae2cIGanqSbyPJrFWD4CRXBv+92L2LyG7yA9C498
|
||||
uyMJ98DVp4SAaNWFha+JCz5TO6KCXOuwGrQTSUitqxQ2rMv2WpXnO2T8puvXW8dD
|
||||
mxfiHuvNMNHfA9Bd4tsbbPE=
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,371 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/distribution/distribution/v3/configuration"
|
||||
"github.com/distribution/distribution/v3/registry"
|
||||
_ "github.com/distribution/distribution/v3/registry/auth/htpasswd"
|
||||
_ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory"
|
||||
"github.com/phayes/freeport"
|
||||
"github.com/stretchr/testify/suite"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"helm.sh/helm/v3/internal/tlsutil"
|
||||
)
|
||||
|
||||
const (
|
||||
tlsServerKey = "./testdata/tls/server-key.pem"
|
||||
tlsServerCert = "./testdata/tls/server-cert.pem"
|
||||
tlsCA = "./testdata/tls/ca-cert.pem"
|
||||
tlsKey = "./testdata/tls/client-key.pem"
|
||||
tlsCert = "./testdata/tls/client-cert.pem"
|
||||
)
|
||||
|
||||
var (
|
||||
testWorkspaceDir = "helm-registry-test"
|
||||
testHtpasswdFileBasename = "authtest.htpasswd"
|
||||
testUsername = "myuser"
|
||||
testPassword = "mypass"
|
||||
)
|
||||
|
||||
type TestSuite struct {
|
||||
suite.Suite
|
||||
Out io.Writer
|
||||
DockerRegistryHost string
|
||||
CompromisedRegistryHost string
|
||||
WorkspaceDir string
|
||||
RegistryClient *Client
|
||||
}
|
||||
|
||||
func setup(suite *TestSuite, tlsEnabled bool, insecure bool) *registry.Registry {
|
||||
suite.WorkspaceDir = testWorkspaceDir
|
||||
os.RemoveAll(suite.WorkspaceDir)
|
||||
os.Mkdir(suite.WorkspaceDir, 0700)
|
||||
|
||||
var (
|
||||
out bytes.Buffer
|
||||
err error
|
||||
)
|
||||
suite.Out = &out
|
||||
credentialsFile := filepath.Join(suite.WorkspaceDir, CredentialsFileBasename)
|
||||
|
||||
// init test client
|
||||
if tlsEnabled {
|
||||
var tlsConf *tls.Config
|
||||
tlsConf, err = tlsutil.NewClientTLS(tlsCert, tlsKey, tlsCA, insecure)
|
||||
httpClient := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: tlsConf,
|
||||
},
|
||||
}
|
||||
suite.Nil(err, "no error loading tlsconfog")
|
||||
suite.RegistryClient, err = NewClient(
|
||||
ClientOptDebug(true),
|
||||
ClientOptEnableCache(true),
|
||||
ClientOptWriter(suite.Out),
|
||||
ClientOptCredentialsFile(credentialsFile),
|
||||
ClientOptHTTPClient(httpClient),
|
||||
)
|
||||
} else {
|
||||
suite.RegistryClient, err = NewClient(
|
||||
ClientOptDebug(true),
|
||||
ClientOptEnableCache(true),
|
||||
ClientOptWriter(suite.Out),
|
||||
ClientOptCredentialsFile(credentialsFile),
|
||||
)
|
||||
}
|
||||
|
||||
suite.Nil(err, "no error creating registry client")
|
||||
|
||||
// create htpasswd file (w BCrypt, which is required)
|
||||
pwBytes, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost)
|
||||
suite.Nil(err, "no error generating bcrypt password for test htpasswd file")
|
||||
htpasswdPath := filepath.Join(suite.WorkspaceDir, testHtpasswdFileBasename)
|
||||
err = ioutil.WriteFile(htpasswdPath, []byte(fmt.Sprintf("%s:%s\n", testUsername, string(pwBytes))), 0644)
|
||||
suite.Nil(err, "no error creating test htpasswd file")
|
||||
|
||||
// Registry config
|
||||
config := &configuration.Configuration{}
|
||||
port, err := freeport.GetFreePort()
|
||||
suite.Nil(err, "no error finding free port for test registry")
|
||||
if tlsEnabled {
|
||||
// docker has "MatchLocalhost is a host match function which returns true for
|
||||
// localhost, and is used to enforce http for localhost requests."
|
||||
// That function does not handle matching of ip addresses in octal,
|
||||
// decimal or hex form.
|
||||
suite.DockerRegistryHost = fmt.Sprintf("0x7f000001:%d", port)
|
||||
} else {
|
||||
suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port)
|
||||
}
|
||||
config.HTTP.Addr = fmt.Sprintf(":%d", port)
|
||||
// config.HTTP.Addr = fmt.Sprintf("127.0.0.1:%d", port)
|
||||
config.HTTP.DrainTimeout = time.Duration(10) * time.Second
|
||||
config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}}
|
||||
config.Auth = configuration.Auth{
|
||||
"htpasswd": configuration.Parameters{
|
||||
"realm": "localhost",
|
||||
"path": htpasswdPath,
|
||||
},
|
||||
}
|
||||
|
||||
// config tls
|
||||
if tlsEnabled {
|
||||
// TLS config
|
||||
// this set tlsConf.ClientAuth = tls.RequireAndVerifyClientCert in the
|
||||
// server tls config
|
||||
config.HTTP.TLS.Certificate = tlsServerCert
|
||||
config.HTTP.TLS.Key = tlsServerKey
|
||||
config.HTTP.TLS.ClientCAs = []string{tlsCA}
|
||||
}
|
||||
dockerRegistry, err := registry.NewRegistry(context.Background(), config)
|
||||
suite.Nil(err, "no error creating test registry")
|
||||
|
||||
suite.CompromisedRegistryHost = initCompromisedRegistryTestServer()
|
||||
return dockerRegistry
|
||||
}
|
||||
|
||||
func initCompromisedRegistryTestServer() string {
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if strings.Contains(r.URL.Path, "manifests") {
|
||||
w.Header().Set("Content-Type", "application/vnd.oci.image.manifest.v1+json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
// layers[0] is the blob []byte("a")
|
||||
w.Write([]byte(
|
||||
fmt.Sprintf(`{ "schemaVersion": 2, "config": {
|
||||
"mediaType": "%s",
|
||||
"digest": "sha256:a705ee2789ab50a5ba20930f246dbd5cc01ff9712825bb98f57ee8414377f133",
|
||||
"size": 181
|
||||
},
|
||||
"layers": [
|
||||
{
|
||||
"mediaType": "%s",
|
||||
"digest": "sha256:ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
|
||||
"size": 1
|
||||
}
|
||||
]
|
||||
}`, ConfigMediaType, ChartLayerMediaType)))
|
||||
} else if r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:a705ee2789ab50a5ba20930f246dbd5cc01ff9712825bb98f57ee8414377f133" {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte("{\"name\":\"mychart\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\\n" +
|
||||
"an 'application' or a 'library' chart.\",\"apiVersion\":\"v2\",\"appVersion\":\"1.16.0\",\"type\":" +
|
||||
"\"application\"}"))
|
||||
} else if r.URL.Path == "/v2/testrepo/supposedlysafechart/blobs/sha256:ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" {
|
||||
w.Header().Set("Content-Type", ChartLayerMediaType)
|
||||
w.WriteHeader(200)
|
||||
w.Write([]byte("b"))
|
||||
} else {
|
||||
w.WriteHeader(500)
|
||||
}
|
||||
}))
|
||||
|
||||
u, _ := url.Parse(s.URL)
|
||||
return fmt.Sprintf("localhost:%s", u.Port())
|
||||
}
|
||||
|
||||
func testPush(suite *TestSuite) {
|
||||
// Bad bytes
|
||||
ref := fmt.Sprintf("%s/testrepo/testchart:1.2.3", suite.DockerRegistryHost)
|
||||
_, err := suite.RegistryClient.Push([]byte("hello"), ref)
|
||||
suite.NotNil(err, "error pushing non-chart bytes")
|
||||
|
||||
// Load a test chart
|
||||
chartData, err := ioutil.ReadFile("../repo/repotest/testdata/examplechart-0.1.0.tgz")
|
||||
suite.Nil(err, "no error loading test chart")
|
||||
meta, err := extractChartMeta(chartData)
|
||||
suite.Nil(err, "no error extracting chart meta")
|
||||
|
||||
// non-strict ref (chart name)
|
||||
ref = fmt.Sprintf("%s/testrepo/boop:%s", suite.DockerRegistryHost, meta.Version)
|
||||
_, err = suite.RegistryClient.Push(chartData, ref)
|
||||
suite.NotNil(err, "error pushing non-strict ref (bad basename)")
|
||||
|
||||
// non-strict ref (chart name), with strict mode disabled
|
||||
_, err = suite.RegistryClient.Push(chartData, ref, PushOptStrictMode(false))
|
||||
suite.Nil(err, "no error pushing non-strict ref (bad basename), with strict mode disabled")
|
||||
|
||||
// non-strict ref (chart version)
|
||||
ref = fmt.Sprintf("%s/testrepo/%s:latest", suite.DockerRegistryHost, meta.Name)
|
||||
_, err = suite.RegistryClient.Push(chartData, ref)
|
||||
suite.NotNil(err, "error pushing non-strict ref (bad tag)")
|
||||
|
||||
// non-strict ref (chart version), with strict mode disabled
|
||||
_, err = suite.RegistryClient.Push(chartData, ref, PushOptStrictMode(false))
|
||||
suite.Nil(err, "no error pushing non-strict ref (bad tag), with strict mode disabled")
|
||||
|
||||
// basic push, good ref
|
||||
chartData, err = ioutil.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz")
|
||||
suite.Nil(err, "no error loading test chart")
|
||||
meta, err = extractChartMeta(chartData)
|
||||
suite.Nil(err, "no error extracting chart meta")
|
||||
ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version)
|
||||
_, err = suite.RegistryClient.Push(chartData, ref)
|
||||
suite.Nil(err, "no error pushing good ref")
|
||||
|
||||
_, err = suite.RegistryClient.Pull(ref)
|
||||
suite.Nil(err, "no error pulling a simple chart")
|
||||
|
||||
// Load another test chart
|
||||
chartData, err = ioutil.ReadFile("../downloader/testdata/signtest-0.1.0.tgz")
|
||||
suite.Nil(err, "no error loading test chart")
|
||||
meta, err = extractChartMeta(chartData)
|
||||
suite.Nil(err, "no error extracting chart meta")
|
||||
|
||||
// Load prov file
|
||||
provData, err := ioutil.ReadFile("../downloader/testdata/signtest-0.1.0.tgz.prov")
|
||||
suite.Nil(err, "no error loading test prov")
|
||||
|
||||
// push with prov
|
||||
ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version)
|
||||
result, err := suite.RegistryClient.Push(chartData, ref, PushOptProvData(provData))
|
||||
suite.Nil(err, "no error pushing good ref with prov")
|
||||
|
||||
_, err = suite.RegistryClient.Pull(ref)
|
||||
suite.Nil(err, "no error pulling a simple chart")
|
||||
|
||||
// Validate the output
|
||||
// Note: these digests/sizes etc may change if the test chart/prov files are modified,
|
||||
// or if the format of the OCI manifest changes
|
||||
suite.Equal(ref, result.Ref)
|
||||
suite.Equal(meta.Name, result.Chart.Meta.Name)
|
||||
suite.Equal(meta.Version, result.Chart.Meta.Version)
|
||||
suite.Equal(int64(512), result.Manifest.Size)
|
||||
suite.Equal(int64(99), result.Config.Size)
|
||||
suite.Equal(int64(973), result.Chart.Size)
|
||||
suite.Equal(int64(695), result.Prov.Size)
|
||||
suite.Equal(
|
||||
"sha256:af4c20a1df1431495e673c14ecfa3a2ba24839a7784349d6787cd67957392e83",
|
||||
result.Manifest.Digest)
|
||||
suite.Equal(
|
||||
"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580",
|
||||
result.Config.Digest)
|
||||
suite.Equal(
|
||||
"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55",
|
||||
result.Chart.Digest)
|
||||
suite.Equal(
|
||||
"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256",
|
||||
result.Prov.Digest)
|
||||
}
|
||||
|
||||
func testPull(suite *TestSuite) {
|
||||
// bad/missing ref
|
||||
ref := fmt.Sprintf("%s/testrepo/no-existy:1.2.3", suite.DockerRegistryHost)
|
||||
_, err := suite.RegistryClient.Pull(ref)
|
||||
suite.NotNil(err, "error on bad/missing ref")
|
||||
|
||||
// Load test chart (to build ref pushed in previous test)
|
||||
chartData, err := ioutil.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz")
|
||||
suite.Nil(err, "no error loading test chart")
|
||||
meta, err := extractChartMeta(chartData)
|
||||
suite.Nil(err, "no error extracting chart meta")
|
||||
ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version)
|
||||
|
||||
// Simple pull, chart only
|
||||
_, err = suite.RegistryClient.Pull(ref)
|
||||
suite.Nil(err, "no error pulling a simple chart")
|
||||
|
||||
// Simple pull with prov (no prov uploaded)
|
||||
_, err = suite.RegistryClient.Pull(ref, PullOptWithProv(true))
|
||||
suite.NotNil(err, "error pulling a chart with prov when no prov exists")
|
||||
|
||||
// Simple pull with prov, ignoring missing prov
|
||||
_, err = suite.RegistryClient.Pull(ref,
|
||||
PullOptWithProv(true),
|
||||
PullOptIgnoreMissingProv(true))
|
||||
suite.Nil(err,
|
||||
"no error pulling a chart with prov when no prov exists, ignoring missing")
|
||||
|
||||
// Load test chart (to build ref pushed in previous test)
|
||||
chartData, err = ioutil.ReadFile("../downloader/testdata/signtest-0.1.0.tgz")
|
||||
suite.Nil(err, "no error loading test chart")
|
||||
meta, err = extractChartMeta(chartData)
|
||||
suite.Nil(err, "no error extracting chart meta")
|
||||
ref = fmt.Sprintf("%s/testrepo/%s:%s", suite.DockerRegistryHost, meta.Name, meta.Version)
|
||||
|
||||
// Load prov file
|
||||
provData, err := ioutil.ReadFile("../downloader/testdata/signtest-0.1.0.tgz.prov")
|
||||
suite.Nil(err, "no error loading test prov")
|
||||
|
||||
// no chart and no prov causes error
|
||||
_, err = suite.RegistryClient.Pull(ref,
|
||||
PullOptWithChart(false),
|
||||
PullOptWithProv(false))
|
||||
suite.NotNil(err, "error on both no chart and no prov")
|
||||
|
||||
// full pull with chart and prov
|
||||
result, err := suite.RegistryClient.Pull(ref, PullOptWithProv(true))
|
||||
suite.Nil(err, "no error pulling a chart with prov")
|
||||
|
||||
// Validate the output
|
||||
// Note: these digests/sizes etc may change if the test chart/prov files are modified,
|
||||
// or if the format of the OCI manifest changes
|
||||
suite.Equal(ref, result.Ref)
|
||||
suite.Equal(meta.Name, result.Chart.Meta.Name)
|
||||
suite.Equal(meta.Version, result.Chart.Meta.Version)
|
||||
suite.Equal(int64(512), result.Manifest.Size)
|
||||
suite.Equal(int64(99), result.Config.Size)
|
||||
suite.Equal(int64(973), result.Chart.Size)
|
||||
suite.Equal(int64(695), result.Prov.Size)
|
||||
suite.Equal(
|
||||
"sha256:af4c20a1df1431495e673c14ecfa3a2ba24839a7784349d6787cd67957392e83",
|
||||
result.Manifest.Digest)
|
||||
suite.Equal(
|
||||
"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580",
|
||||
result.Config.Digest)
|
||||
suite.Equal(
|
||||
"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55",
|
||||
result.Chart.Digest)
|
||||
suite.Equal(
|
||||
"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256",
|
||||
result.Prov.Digest)
|
||||
suite.Equal("{\"schemaVersion\":2,\"config\":{\"mediaType\":\"application/vnd.cncf.helm.config.v1+json\",\"digest\":\"sha256:8d17cb6bf6ccd8c29aace9a658495cbd5e2e87fc267876e86117c7db681c9580\",\"size\":99},\"layers\":[{\"mediaType\":\"application/vnd.cncf.helm.chart.provenance.v1.prov\",\"digest\":\"sha256:b0a02b7412f78ae93324d48df8fcc316d8482e5ad7827b5b238657a29a22f256\",\"size\":695},{\"mediaType\":\"application/vnd.cncf.helm.chart.content.v1.tar+gzip\",\"digest\":\"sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55\",\"size\":973}]}",
|
||||
string(result.Manifest.Data))
|
||||
suite.Equal("{\"name\":\"signtest\",\"version\":\"0.1.0\",\"description\":\"A Helm chart for Kubernetes\",\"apiVersion\":\"v1\"}",
|
||||
string(result.Config.Data))
|
||||
suite.Equal(chartData, result.Chart.Data)
|
||||
suite.Equal(provData, result.Prov.Data)
|
||||
}
|
||||
|
||||
func testTags(suite *TestSuite) {
|
||||
// Load test chart (to build ref pushed in previous test)
|
||||
chartData, err := ioutil.ReadFile("../downloader/testdata/local-subchart-0.1.0.tgz")
|
||||
suite.Nil(err, "no error loading test chart")
|
||||
meta, err := extractChartMeta(chartData)
|
||||
suite.Nil(err, "no error extracting chart meta")
|
||||
ref := fmt.Sprintf("%s/testrepo/%s", suite.DockerRegistryHost, meta.Name)
|
||||
|
||||
// Query for tags and validate length
|
||||
tags, err := suite.RegistryClient.Tags(ref)
|
||||
suite.Nil(err, "no error retrieving tags")
|
||||
suite.Equal(1, len(tags))
|
||||
}
|
Loading…
Reference in new issue