Browse code

Add integration cli trust tests

Added notary server to docker base image.
Created trust suite which runs trust server for running trusted commands.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)

Derek McGowan authored on 2015/07/20 14:56:10
Showing 9 changed files
... ...
@@ -136,6 +136,16 @@ RUN set -x \
136 136
 		go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
137 137
 	&& rm -rf "$GOPATH"
138 138
 
139
+# Install notary server
140
+ENV NOTARY_COMMIT 77bced079e83d80f40c1f0a544b1a8a3b97fb052
141
+RUN set -x \
142
+	&& export GOPATH="$(mktemp -d)" \
143
+	&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
144
+	&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_COMMIT") \
145
+	&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
146
+		go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
147
+	&& rm -rf "$GOPATH"
148
+
139 149
 # Get the "docker-py" source so we can run their integration tests
140 150
 ENV DOCKER_PY_COMMIT 8a87001d09852058f08a807ab6e8491d57ca1e88
141 151
 RUN git clone https://github.com/docker/docker-py.git /docker-py \
... ...
@@ -61,3 +61,26 @@ func (s *DockerDaemonSuite) TearDownTest(c *check.C) {
61 61
 	s.d.Stop()
62 62
 	s.ds.TearDownTest(c)
63 63
 }
64
+
65
+func init() {
66
+	check.Suite(&DockerTrustSuite{
67
+		ds: &DockerSuite{},
68
+	})
69
+}
70
+
71
+type DockerTrustSuite struct {
72
+	ds  *DockerSuite
73
+	reg *testRegistryV2
74
+	not *testNotary
75
+}
76
+
77
+func (s *DockerTrustSuite) SetUpTest(c *check.C) {
78
+	s.reg = setupRegistry(c)
79
+	s.not = setupNotary(c)
80
+}
81
+
82
+func (s *DockerTrustSuite) TearDownTest(c *check.C) {
83
+	s.reg.Close()
84
+	s.not.Close()
85
+	s.ds.TearDownTest(c)
86
+}
... ...
@@ -2,6 +2,7 @@ package main
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"os/exec"
5 6
 	"strings"
6 7
 
7 8
 	"github.com/go-check/check"
... ...
@@ -151,3 +152,33 @@ func (s *DockerSuite) TestPullImageWithAllTagFromCentralRegistry(c *check.C) {
151 151
 		c.Fatalf("Pulling with all tags should get more images")
152 152
 	}
153 153
 }
154
+
155
+func (s *DockerTrustSuite) TestTrustedPull(c *check.C) {
156
+	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
157
+	// tag the image and upload it to the private registry
158
+	dockerCmd(c, "tag", "busybox", repoName)
159
+
160
+	pushCmd := exec.Command(dockerBinary, "push", repoName)
161
+	s.trustedCmd(pushCmd)
162
+	out, _, err := runCommandWithOutput(pushCmd)
163
+	if err != nil {
164
+		c.Fatalf("Error running trusted push: %s\n%s", err, out)
165
+	}
166
+	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
167
+		c.Fatalf("Missing expected output on trusted push:\n%s", out)
168
+	}
169
+
170
+	dockerCmd(c, "rmi", repoName)
171
+
172
+	// Try pull
173
+	pullCmd := exec.Command(dockerBinary, "pull", repoName)
174
+	s.trustedCmd(pullCmd)
175
+	out, _, err = runCommandWithOutput(pullCmd)
176
+	if err != nil {
177
+		c.Fatalf("Error running trusted pull: %s\n%s", err, out)
178
+	}
179
+
180
+	if !strings.Contains(string(out), "Tagging") {
181
+		c.Fatalf("Missing expected output on trusted push:\n%s", out)
182
+	}
183
+}
... ...
@@ -143,3 +143,19 @@ func (s *DockerRegistrySuite) TestPushEmptyLayer(c *check.C) {
143 143
 		c.Fatalf("pushing the image to the private registry has failed: %s, %v", out, err)
144 144
 	}
145 145
 }
146
+
147
+func (s *DockerTrustSuite) TestTrustedPush(c *check.C) {
148
+	repoName := fmt.Sprintf("%v/dockercli/trusted:latest", privateRegistryURL)
149
+	// tag the image and upload it to the private registry
150
+	dockerCmd(c, "tag", "busybox", repoName)
151
+
152
+	pushCmd := exec.Command(dockerBinary, "push", repoName)
153
+	s.trustedCmd(pushCmd)
154
+	out, _, err := runCommandWithOutput(pushCmd)
155
+	if err != nil {
156
+		c.Fatalf("Error running trusted push: %s\n%s", err, out)
157
+	}
158
+	if !strings.Contains(string(out), "Signing and pushing trust metadata") {
159
+		c.Fatalf("Missing expected output on trusted push:\n%s", out)
160
+	}
161
+}
... ...
@@ -1260,6 +1260,27 @@ func setupRegistry(c *check.C) *testRegistryV2 {
1260 1260
 	return reg
1261 1261
 }
1262 1262
 
1263
+func setupNotary(c *check.C) *testNotary {
1264
+	testRequires(c, NotaryHosting)
1265
+	ts, err := newTestNotary(c)
1266
+	if err != nil {
1267
+		c.Fatal(err)
1268
+	}
1269
+
1270
+	// Wait for notary to be ready to serve requests.
1271
+	for i := 1; i <= 5; i++ {
1272
+		if err = ts.Ping(); err == nil {
1273
+			break
1274
+		}
1275
+		time.Sleep(10 * time.Millisecond * time.Duration(i*i))
1276
+	}
1277
+
1278
+	if err != nil {
1279
+		c.Fatalf("Timeout waiting for test notary to become available: %s", err)
1280
+	}
1281
+	return ts
1282
+}
1283
+
1263 1284
 // appendBaseEnv appends the minimum set of environment variables to exec the
1264 1285
 // docker cli binary for testing with correct configuration to the given env
1265 1286
 // list.
1266 1287
new file mode 100644
... ...
@@ -0,0 +1,19 @@
0
+-----BEGIN CERTIFICATE-----
1
+MIIDCTCCAfOgAwIBAgIQTOoFF+ypXwgdXnXHuCTvYDALBgkqhkiG9w0BAQswJjER
2
+MA8GA1UEChMIUXVpY2tUTFMxETAPBgNVBAMTCFF1aWNrVExTMB4XDTE1MDcxNzE5
3
+NDg1M1oXDTE4MDcwMTE5NDg1M1owJzERMA8GA1UEChMIUXVpY2tUTFMxEjAQBgNV
4
+BAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMDO
5
+qvTBAi0ApXLfe90ApJkdkRGwF838Qzt1UFSxomu5fHRV6l3FjX5XCVHiFQ4w3ROh
6
+dMOu9NahfGLJv9VvWU2MV3YoY9Y7lIXpKwnK1v064wuls4nPh13BUWKQKofcY/e2
7
+qaSPd6/qmSRc/kJUvOI9jZMSX6ZRPu9K4PCqm2CivlbLq9UYuo1AbRGfuqHRvTxg
8
+mQG7WQCzGSvSjuSg5qX3TEh0HckTczJG9ODULNRWNE7ld0W4sfv4VF8R7Uc/G7LO
9
+8QwLCZ9TIl3gYMPCrhUL3Q6z9Jnn1SQS4mhDnPi6ugRYO1X8k3jjdxV9C2sXwUvN
10
+OZI1rLEWl9TJNA7ZXtMCAwEAAaM2MDQwDgYDVR0PAQH/BAQDAgCgMAwGA1UdEwEB
11
+/wQCMAAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MAsGCSqGSIb3DQEBCwOCAQEAH6iq
12
+kM2+UMukGDLEQKHHiauioWJlHDlLXv76bJiNfjSz94B/2XOQMb9PT04//tnGUyPK
13
+K8Dx7RoxSodU6T5VRiz/A36mLOvt2t3bcL/1nHf9sAOHcexGtnCbQbW91V7RKfIL
14
+sjiLNFDkQ9VfVNY+ynQptZoyH1sy07+dplfkIiPzRs5WuVAnEGsX3r6BrhgUITzi
15
+g1B4kpmGZIohP4m6ZEBY5xuo/NQ0+GhjAENQMU38GpuoMyFS0i0dGcbx8weqnI/B
16
+Er/qa0+GE/rBnWY8TiRow8dzpneSFQnUZpJ4EwD9IoOIDHo7k2Nbz2P50HMiCXZf
17
+4RqzctVssRlrRVnO5w==
18
+-----END CERTIFICATE-----
0 19
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+-----BEGIN RSA PRIVATE KEY-----
1
+MIIEogIBAAKCAQEAwM6q9MECLQClct973QCkmR2REbAXzfxDO3VQVLGia7l8dFXq
2
+XcWNflcJUeIVDjDdE6F0w6701qF8Ysm/1W9ZTYxXdihj1juUhekrCcrW/TrjC6Wz
3
+ic+HXcFRYpAqh9xj97appI93r+qZJFz+QlS84j2NkxJfplE+70rg8KqbYKK+Vsur
4
+1Ri6jUBtEZ+6odG9PGCZAbtZALMZK9KO5KDmpfdMSHQdyRNzMkb04NQs1FY0TuV3
5
+Rbix+/hUXxHtRz8bss7xDAsJn1MiXeBgw8KuFQvdDrP0mefVJBLiaEOc+Lq6BFg7
6
+VfyTeON3FX0LaxfBS805kjWssRaX1Mk0Dtle0wIDAQABAoIBAHbuhNHZROhRn70O
7
+Ui9vOBki/dt1ThnH5AkHQngb4t6kWjrAzILvW2p1cdBKr0ZDqftz+rzCbVD/5+Rg
8
+Iq8bsnB9g23lWEBMHD/GJsAxmRA3hNooamk11IBmwTcVSsbnkdq5mEdkICYphjHC
9
+Ey0DbEf6RBxWlx3WvAWLoNmTw6iFaOCH8IyLavPpe7kLbZc219oNUw2qjCnCXCZE
10
+/NuViADHJBPN8r7g1gmyclJmTumdUK6oHgXEMMPe43vhReGcgcReK9QZjnTcIXPM
11
+4oJOraw+BtoZXVvvIPnC+5ntoLFOzjIzM0kaveReZbdgffqF4zy2vRfCHhWssanc
12
+7a0xR4ECgYEA3Xuvcqy5Xw+v/jVCO0VZj++Z7apA78dY4tWsPx5/0DUTTziTlXkC
13
+ADduEbwX6HgZ/iLvA9j4C3Z4mO8qByby/6UoBU8NEe+PQt6fT7S+dKSP4uy5ZxVM
14
+i5opkEyrJsMbve9Jrlj4bk5CICsydrZ+SBFHnpNGjbduGQick5LORWECgYEA3trt
15
+gepteDGiUYmnnBgjbYtcD11RvpKC8Z/QwGnzN5vk4eBu8r7DkMcLN+SiHjAovlJo
16
+r5j3EbF8sla1zBf/yySdQZFqUGcwtw7MaAKCLdhQl5WsViNMIx6p2OJapu0dzbv2
17
+KTXrnoRCafcH92k0dUX1ahE9eyc8KX6VhbWwXLMCgYATGCCuEDoC+gVAMzM8jOQF
18
+xrBMjwr+IP+GvskUv/pg5tJ9V/FRR5dmkWDJ4p9lCUWkZTqZ6FCqHFKVTLkg2LjG
19
+VWS34HLOAwskxrCRXJG22KEW/TWWr31j46yFpjZzJwrzOvftMfpo+BI3V8IH/f+x
20
+EtxLzYKdoRy6x8VH67YgwQKBgHor2vjV45142FuK83AHa6SqOZXSuvWWrGJ6Ep7p
21
+doSN2jRaLXi2S9AaznOdy6JxFGUCGJHrcccpXgsGrjNtFLXxJKTFa1sYtwQkALsk
22
+ZOltJQF09D1krGC0driHntrUMvqOiKye+sS0DRS6cIuaCUAhUiELwoC5SaoV0zKy
23
+IDUxAoGAOK8Xq+3/sqe79vTpw25RXl+nkAmOAeKjqf3Kh6jbnBhr81rmefyKXB9a
24
+uj0b980tzUnliwA5cCOsyxfN2vASvMnJxFE721QZI04arlcPFHcFqCtmNnUYTcLp
25
+0hgn/yLZptcoxpy+eTBu3eNsxz1Bu/Tx/198+2Wr3MbtGpLNIcA=
26
+-----END RSA PRIVATE KEY-----
... ...
@@ -74,6 +74,16 @@ var (
74 74
 		},
75 75
 		fmt.Sprintf("Test requires an environment that can host %s in the same host", v2binary),
76 76
 	}
77
+	NotaryHosting = testRequirement{
78
+		func() bool {
79
+			// for now notary binary is built only if we're running inside
80
+			// container through `make test`. Figure that out by testing if
81
+			// notary-server binary is in PATH.
82
+			_, err := exec.LookPath(notaryBinary)
83
+			return err == nil
84
+		},
85
+		fmt.Sprintf("Test requires an environment that can host %s in the same host", notaryBinary),
86
+	}
77 87
 	NativeExecDriver = testRequirement{
78 88
 		func() bool {
79 89
 			if daemonExecDriver == "" {
80 90
new file mode 100644
... ...
@@ -0,0 +1,110 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"net"
6
+	"net/http"
7
+	"os"
8
+	"os/exec"
9
+	"path/filepath"
10
+	"time"
11
+
12
+	"github.com/docker/docker/pkg/tlsconfig"
13
+	"github.com/go-check/check"
14
+)
15
+
16
+var notaryBinary = "notary-server"
17
+
18
+type testNotary struct {
19
+	cmd *exec.Cmd
20
+	dir string
21
+}
22
+
23
+func newTestNotary(c *check.C) (*testNotary, error) {
24
+	template := `{
25
+	"server": {
26
+		"addr": "%s",
27
+		"tls_key_file": "fixtures/notary/localhost.key",
28
+		"tls_cert_file": "fixtures/notary/localhost.cert"
29
+	},
30
+	"trust_service": {
31
+		"type": "local",
32
+		"hostname": "",
33
+		"port": ""
34
+	},
35
+	"logging": {
36
+		"level": 5
37
+	}
38
+}`
39
+	tmp, err := ioutil.TempDir("", "notary-test-")
40
+	if err != nil {
41
+		return nil, err
42
+	}
43
+	confPath := filepath.Join(tmp, "config.json")
44
+	config, err := os.Create(confPath)
45
+	if err != nil {
46
+		return nil, err
47
+	}
48
+	if _, err := fmt.Fprintf(config, template, "localhost:4443"); err != nil {
49
+		os.RemoveAll(tmp)
50
+		return nil, err
51
+	}
52
+
53
+	cmd := exec.Command(notaryBinary, "-config", confPath)
54
+	if err := cmd.Start(); err != nil {
55
+		os.RemoveAll(tmp)
56
+		if os.IsNotExist(err) {
57
+			c.Skip(err.Error())
58
+		}
59
+		return nil, err
60
+	}
61
+	return &testNotary{
62
+		cmd: cmd,
63
+		dir: tmp,
64
+	}, nil
65
+}
66
+
67
+func (t *testNotary) address() string {
68
+	return "localhost:4443"
69
+}
70
+
71
+func (t *testNotary) Ping() error {
72
+	tlsConfig := tlsconfig.ClientDefault
73
+	tlsConfig.InsecureSkipVerify = true
74
+	client := http.Client{
75
+		Transport: &http.Transport{
76
+			Proxy: http.ProxyFromEnvironment,
77
+			Dial: (&net.Dialer{
78
+				Timeout:   30 * time.Second,
79
+				KeepAlive: 30 * time.Second,
80
+			}).Dial,
81
+			TLSHandshakeTimeout: 10 * time.Second,
82
+			TLSClientConfig:     &tlsConfig,
83
+		},
84
+	}
85
+	resp, err := client.Get(fmt.Sprintf("https://%s/v2/", t.address()))
86
+	if err != nil {
87
+		return err
88
+	}
89
+	if resp.StatusCode != 200 {
90
+		return fmt.Errorf("notary ping replied with an unexpected status code %d", resp.StatusCode)
91
+	}
92
+	return nil
93
+}
94
+
95
+func (t *testNotary) Close() {
96
+	t.cmd.Process.Kill()
97
+	os.RemoveAll(t.dir)
98
+}
99
+
100
+func (s *DockerTrustSuite) trustedCmd(cmd *exec.Cmd) {
101
+	env := []string{
102
+		"DOCKER_TRUST=1",
103
+		fmt.Sprintf("DOCKER_TRUST_SERVER=%s", s.not.address()),
104
+		"DOCKER_TRUST_ROOT_PASSPHRASE=12345678",
105
+		"DOCKER_TRUST_TARGET_PASSPHRASE=12345678",
106
+		"DOCKER_TRUST_SNAPSHOT_PASSPHRASE=12345678",
107
+	}
108
+	cmd.Env = append(os.Environ(), env...)
109
+}