File: host.go

package info (click to toggle)
golang-github-notaryproject-notation 1.2.0-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 2,160 kB
  • sloc: sh: 202; makefile: 67
file content (278 lines) | stat: -rw-r--r-- 9,028 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
// Copyright The Notary Project 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 notation

import (
	"os"
	"path/filepath"

	"github.com/notaryproject/notation/test/e2e/internal/utils"
	. "github.com/onsi/ginkgo/v2"
)

// CoreTestFunc is the test function running in a VirtualHost.
//
// notation is an Executor isolated by $XDG_CONFIG_HOME.
// artifact is a generated artifact in a new repository.
// vhost is the VirtualHost instance.
type CoreTestFunc func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost)

// OCILayoutTestFunc is the test function running in a VirtualHost with isolated
// OCI layout for each test case.
//
// notation is an Executor isolated by $XDG_CONFIG_HOME.
// vhost is the VirtualHost instance.
type OCILayoutTestFunc func(notation *utils.ExecOpts, ocilayout *OCILayout, vhost *utils.VirtualHost)

// Host creates a virtualized notation testing host by modify
// the "XDG_CONFIG_HOME" environment variable of the Executor.
//
// options is the required testing environment options
// fn is the callback function containing the testing logic.
func Host(options []utils.HostOption, fn CoreTestFunc) {
	// create a notation vhost
	vhost, err := createNotationHost(NotationBinPath, options...)
	if err != nil {
		panic(err)
	}

	// generate a repository with an artifact
	artifact := GenerateArtifact("", "")

	// run the main logic
	fn(vhost.Executor, artifact, vhost)
}

// HostInGithubAction only run the test in GitHub Actions.
//
// The booting script will setup TLS reverse proxy and TLS certificate
// for Github Actions environment.
func HostInGithubAction(options []utils.HostOption, fn CoreTestFunc) {
	if os.Getenv("GITHUB_ACTIONS") != "true" {
		Skip("only run in GitHub Actions")
	}
	Host(options, fn)
}

// HostWithOCILayout creates a virtualized notation testing host by modify
// the "XDG_CONFIG_HOME" environment variable of the Executor. It generates
// isolated OCI layout in the testing host.
//
// options is the required testing environment options
// fn is the callback function containing the testing logic.
func HostWithOCILayout(options []utils.HostOption, fn OCILayoutTestFunc) {
	// create a notation vhost
	vhost, err := createNotationHost(NotationBinPath, options...)
	if err != nil {
		panic(err)
	}

	ocilayout, err := GenerateOCILayout("")
	if err != nil {
		panic(err)
	}

	// run the main logic
	fn(vhost.Executor, ocilayout, vhost)
}

// OldNotation create an old version notation ExecOpts in a VirtualHost
// for testing forward compatibility.
func OldNotation(options ...utils.HostOption) *utils.ExecOpts {
	if len(options) == 0 {
		options = BaseOptions()
	}

	vhost, err := createNotationHost(NotationOldBinPath, options...)
	if err != nil {
		panic(err)
	}

	return vhost.Executor
}

func createNotationHost(path string, options ...utils.HostOption) (*utils.VirtualHost, error) {
	vhost, err := utils.NewVirtualHost(path, CreateNotationDirOption())
	if err != nil {
		return nil, err
	}

	// set additional options
	vhost.SetOption(options...)
	return vhost, nil
}

// Opts is a grammar sugar to generate a list of HostOption.
func Opts(options ...utils.HostOption) []utils.HostOption {
	return options
}

// BaseOptions returns a list of base Options for a valid notation.
// testing environment.
func BaseOptions() []utils.HostOption {
	return Opts(
		AuthOption("", ""),
		AddKeyOption("e2e.key", "e2e.crt"),
		AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")),
		AddTrustPolicyOption("trustpolicy.json"),
	)
}

// TimestampOptions returns a list of timestamp Options for a valid
// notation testing environment.
func TimestampOptions(verifyTimestamp string) []utils.HostOption {
	var trustPolicyOption utils.HostOption
	if verifyTimestamp == "afterCertExpiry" {
		trustPolicyOption = AddTrustPolicyOption("timestamp_after_cert_expiry_trustpolicy.json")
	} else {
		trustPolicyOption = AddTrustPolicyOption("timestamp_trustpolicy.json")
	}

	return Opts(
		AuthOption("", ""),
		AddKeyOption("e2e.key", "e2e.crt"),
		AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")),
		AddTimestampTrustStoreOption("e2e", filepath.Join(NotationE2EConfigPath, "timestamp", "globalsignTSARoot.cer")),
		AddTimestampTrustStoreOption("e2e", filepath.Join(NotationE2EConfigPath, "timestamp", "DigiCertTSARootSHA384.cer")),
		trustPolicyOption,
	)
}

func BaseOptionsWithExperimental() []utils.HostOption {
	return Opts(
		AuthOption("", ""),
		AddKeyOption("e2e.key", "e2e.crt"),
		AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")),
		AddTrustPolicyOption("trustpolicy.json"),
		EnableExperimental(),
	)
}

// TestLoginOptions returns the BaseOptions with removing AuthOption and adding ConfigOption.
// testing environment.
func TestLoginOptions() []utils.HostOption {
	return Opts(
		AddKeyOption("e2e.key", "e2e.crt"),
		AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")),
		AddTrustPolicyOption("trustpolicy.json"),
		AddConfigJsonOption("pass_credential_helper_config.json"),
	)
}

// CreateNotationDirOption creates the notation directory in temp user dir.
func CreateNotationDirOption() utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		return os.MkdirAll(vhost.AbsolutePath(NotationDirName), os.ModePerm)
	}
}

// AuthOption sets the auth environment variables for notation.
func AuthOption(username, password string) utils.HostOption {
	if username == "" {
		username = TestRegistry.Username
	}
	if password == "" {
		password = TestRegistry.Password
	}
	return func(vhost *utils.VirtualHost) error {
		vhost.UpdateEnv(authEnv(username, password))
		return nil
	}
}

// AddKeyOption adds the test signingkeys.json, key and cert files to
// the notation directory.
func AddKeyOption(keyName, certName string) utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		return AddKeyPairs(vhost.AbsolutePath(NotationDirName), keyName, certName)
	}
}

// AddTrustStoreOption adds the test cert to the trust store.
func AddTrustStoreOption(namedstore string, srcCertPath string) utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		vhost.Executor.
			Exec("cert", "add", "--type", "ca", "--store", namedstore, srcCertPath).
			MatchKeyWords("Successfully added following certificates")
		return nil
	}
}

// AddTimestampTrustStoreOption adds the test tsa cert to the trust store.
func AddTimestampTrustStoreOption(namedstore string, srcCertPath string) utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		vhost.Executor.
			Exec("cert", "add", "--type", "tsa", "--store", namedstore, srcCertPath).
			MatchKeyWords("Successfully added following certificates")
		return nil
	}
}

// AddTrustPolicyOption adds a valid trust policy for testing.
func AddTrustPolicyOption(trustpolicyName string) utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		return copyFile(
			filepath.Join(NotationE2ETrustPolicyDir, trustpolicyName),
			vhost.AbsolutePath(NotationDirName, TrustPolicyName),
		)
	}
}

// AddConfigJsonOption adds a valid config.json for testing.
func AddConfigJsonOption(configJsonName string) utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		return copyFile(
			filepath.Join(NotationE2EConfigJsonDir, configJsonName),
			vhost.AbsolutePath(NotationDirName, ConfigJsonName),
		)
	}
}

// AddPlugin adds a pluginkeys.json config file and installs an e2e-plugin.
func AddPlugin(pluginPath string) utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		// add pluginkeys.json configuration file for e2e-plugin
		saveJSON(
			generatePluginKeys(vhost.AbsolutePath(NotationDirName)),
			vhost.AbsolutePath(NotationDirName, "pluginkeys.json"),
		)

		// install plugin
		e2ePluginDir := vhost.AbsolutePath(NotationDirName, PluginDirName, PluginName)
		if err := os.MkdirAll(e2ePluginDir, 0700); err != nil {
			return err
		}
		return copyFile(
			NotationE2EPluginPath,
			filepath.Join(e2ePluginDir, "notation-"+PluginName),
		)
	}
}

// authEnv creates an auth info.
// (By setting $NOTATION_USERNAME and $NOTATION_PASSWORD)
func authEnv(username, password string) map[string]string {
	return map[string]string{
		"NOTATION_USERNAME": username,
		"NOTATION_PASSWORD": password,
	}
}

// EnableExperimental enables experimental features.
func EnableExperimental() utils.HostOption {
	return func(vhost *utils.VirtualHost) error {
		vhost.UpdateEnv(map[string]string{"NOTATION_EXPERIMENTAL": "1"})
		return nil
	}
}