GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( 412f4e...f5d62c )
by Jackson
16:33 queued 06:27
created

edentialsWithRequestCheck   A

Complexity

Conditions 4

Size

Total Lines 39
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 29
nop 1
dl 0
loc 39
rs 9.184
c 0
b 0
f 0
1
package providers
2
3
import (
4
	"errors"
5
	"io"
6
	"io/ioutil"
7
	"net/http"
8
	"os"
9
	"path"
10
	"strconv"
11
	"strings"
12
	"testing"
13
	"time"
14
15
	"github.com/stretchr/testify/assert"
16
)
17
18
func TestOIDCCredentialsProviderGetCredentialsWithError(t *testing.T) {
19
	wd, _ := os.Getwd()
20
	p, err := NewOIDCCredentialsProviderBuilder().
21
		// read a normal token
22
		WithOIDCTokenFilePath(path.Join(wd, "fixtures/mock_oidctoken")).
23
		WithOIDCProviderARN("provider-arn").
24
		WithRoleArn("roleArn").
25
		WithRoleSessionName("rsn").
26
		WithPolicy("policy").
27
		WithDurationSeconds(1000).
28
		Build()
29
30
	assert.Nil(t, err)
31
	_, err = p.GetCredentials()
32
	assert.NotNil(t, err)
33
	assert.Contains(t, err.Error(), "AuthenticationFail.NoPermission")
34
}
35
36
func TestNewOIDCCredentialsProvider(t *testing.T) {
37
	_, err := NewOIDCCredentialsProviderBuilder().Build()
38
	assert.NotNil(t, err)
39
	assert.Equal(t, "the OIDCTokenFilePath is empty", err.Error())
40
41
	_, err = NewOIDCCredentialsProviderBuilder().WithOIDCTokenFilePath("/path/to/invalid/oidc.token").Build()
42
	assert.NotNil(t, err)
43
	assert.Equal(t, "the OIDCProviderARN is empty", err.Error())
44
45
	_, err = NewOIDCCredentialsProviderBuilder().
46
		WithOIDCTokenFilePath("/path/to/invalid/oidc.token").
47
		WithOIDCProviderARN("provider-arn").
48
		Build()
49
	assert.NotNil(t, err)
50
	assert.Equal(t, "the RoleArn is empty", err.Error())
51
52
	p, err := NewOIDCCredentialsProviderBuilder().
53
		WithOIDCTokenFilePath("/path/to/invalid/oidc.token").
54
		WithOIDCProviderARN("provider-arn").
55
		WithRoleArn("roleArn").
56
		Build()
57
	assert.Nil(t, err)
58
59
	assert.Equal(t, "/path/to/invalid/oidc.token", p.oidcTokenFilePath)
60
	assert.True(t, strings.HasPrefix(p.roleSessionName, "credentials-go-"))
61
	assert.Equal(t, 3600, p.durationSeconds)
62
63
	_, err = NewOIDCCredentialsProviderBuilder().
64
		WithOIDCTokenFilePath("/path/to/invalid/oidc.token").
65
		WithOIDCProviderARN("provider-arn").
66
		WithRoleArn("roleArn").
67
		WithDurationSeconds(100).
68
		Build()
69
	assert.NotNil(t, err)
70
	assert.Equal(t, "the Assume Role session duration should be in the range of 15min - max duration seconds", err.Error())
71
72
	os.Setenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE", "/path/from/env")
73
	os.Setenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN", "provider_arn_from_env")
74
	os.Setenv("ALIBABA_CLOUD_ROLE_ARN", "role_arn_from_env")
75
76
	defer func() {
77
		os.Unsetenv("ALIBABA_CLOUD_OIDC_TOKEN_FILE")
78
		os.Unsetenv("ALIBABA_CLOUD_OIDC_PROVIDER_ARN")
79
		os.Unsetenv("ALIBABA_CLOUD_ROLE_ARN")
80
	}()
81
82
	p, err = NewOIDCCredentialsProviderBuilder().
83
		Build()
84
	assert.Nil(t, err)
85
86
	assert.Equal(t, "/path/from/env", p.oidcTokenFilePath)
87
	assert.Equal(t, "provider_arn_from_env", p.oidcProviderARN)
88
	assert.Equal(t, "role_arn_from_env", p.roleArn)
89
	// sts endpoint: default
90
	assert.Equal(t, "sts.aliyuncs.com", p.stsEndpoint)
91
	// sts endpoint: with sts endpoint
92
	p, err = NewOIDCCredentialsProviderBuilder().
93
		WithSTSEndpoint("sts.cn-shanghai.aliyuncs.com").
94
		Build()
95
	assert.Nil(t, err)
96
	assert.Equal(t, "sts.cn-shanghai.aliyuncs.com", p.stsEndpoint)
97
98
	// sts endpoint: with sts regionId
99
	p, err = NewOIDCCredentialsProviderBuilder().
100
		WithStsRegionId("cn-beijing").
101
		Build()
102
	assert.Nil(t, err)
103
	assert.Equal(t, "sts.cn-beijing.aliyuncs.com", p.stsEndpoint)
104
105
	p, err = NewOIDCCredentialsProviderBuilder().
106
		WithOIDCTokenFilePath("/path/to/invalid/oidc.token").
107
		WithOIDCProviderARN("provider-arn").
108
		WithRoleArn("roleArn").
109
		WithRoleSessionName("rsn").
110
		WithStsRegionId("cn-hangzhou").
111
		WithPolicy("policy").
112
		Build()
113
	assert.Nil(t, err)
114
115
	assert.Equal(t, "/path/to/invalid/oidc.token", p.oidcTokenFilePath)
116
	assert.Equal(t, "provider-arn", p.oidcProviderARN)
117
	assert.Equal(t, "roleArn", p.roleArn)
118
	assert.Equal(t, "rsn", p.roleSessionName)
119
	assert.Equal(t, "cn-hangzhou", p.stsRegionId)
120
	assert.Equal(t, "policy", p.policy)
121
	assert.Equal(t, 3600, p.durationSeconds)
122
	assert.Equal(t, "sts.cn-hangzhou.aliyuncs.com", p.stsEndpoint)
123
}
124
125
func TestOIDCCredentialsProvider_getCredentials(t *testing.T) {
126
	// case 0: invalid oidc token file path
127
	p, err := NewOIDCCredentialsProviderBuilder().
128
		WithOIDCTokenFilePath("/path/to/invalid/oidc.token").
129
		WithOIDCProviderARN("provider-arn").
130
		WithRoleArn("roleArn").
131
		WithRoleSessionName("rsn").
132
		WithStsRegionId("cn-hangzhou").
133
		WithPolicy("policy").
134
		Build()
135
	assert.Nil(t, err)
136
137
	_, err = p.getCredentials()
138
	assert.NotNil(t, err)
139
	assert.Equal(t, "open /path/to/invalid/oidc.token: no such file or directory", err.Error())
140
141
	// case 1: mock new http request failed
142
	wd, _ := os.Getwd()
143
	p, err = NewOIDCCredentialsProviderBuilder().
144
		// read a normal token
145
		WithOIDCTokenFilePath(path.Join(wd, "fixtures/mock_oidctoken")).
146
		WithOIDCProviderARN("provider-arn").
147
		WithRoleArn("roleArn").
148
		WithRoleSessionName("rsn").
149
		WithStsRegionId("cn-hangzhou").
150
		WithPolicy("policy").
151
		Build()
152
	assert.Nil(t, err)
153
154
	originNewRequest := hookNewRequest
155
	defer func() { hookNewRequest = originNewRequest }()
156
157
	hookNewRequest = func(fn newReuqest) newReuqest {
158
		return func(method, url string, body io.Reader) (*http.Request, error) {
159
			return nil, errors.New("new http request failed")
160
		}
161
	}
162
163
	_, err = p.getCredentials()
164
	assert.NotNil(t, err)
165
	assert.Equal(t, "new http request failed", err.Error())
166
167
	// reset new request
168
	hookNewRequest = originNewRequest
169
170
	originDo := hookDo
171
	defer func() { hookDo = originDo }()
172
173
	// case 2: server error
174
	hookDo = func(fn do) do {
175
		return func(req *http.Request) (res *http.Response, err error) {
176
			err = errors.New("mock server error")
177
			return
178
		}
179
	}
180
	_, err = p.getCredentials()
181
	assert.NotNil(t, err)
182
	assert.Equal(t, "mock server error", err.Error())
183
184
	// case 3: mock read response error
185
	hookDo = func(fn do) do {
186
		return func(req *http.Request) (res *http.Response, err error) {
187
			status := strconv.Itoa(200)
188
			res = &http.Response{
189
				Proto:      "HTTP/1.1",
190
				ProtoMajor: 1,
191
				Header:     map[string][]string{},
192
				StatusCode: 200,
193
				Status:     status + " " + http.StatusText(200),
194
			}
195
			res.Body = ioutil.NopCloser(&errorReader{})
196
			return
197
		}
198
	}
199
	_, err = p.getCredentials()
200
	assert.NotNil(t, err)
201
	assert.Equal(t, "read failed", err.Error())
202
203
	// case 4: 4xx error
204
	hookDo = func(fn do) do {
205
		return func(req *http.Request) (res *http.Response, err error) {
206
			res = mockResponse(400, "4xx error")
207
			return
208
		}
209
	}
210
	_, err = p.getCredentials()
211
	assert.NotNil(t, err)
212
	assert.Equal(t, "get session token failed: 4xx error", err.Error())
213
214
	// case 5: invalid json
215
	hookDo = func(fn do) do {
216
		return func(req *http.Request) (res *http.Response, err error) {
217
			res = mockResponse(200, "invalid json")
218
			return
219
		}
220
	}
221
	_, err = p.getCredentials()
222
	assert.NotNil(t, err)
223
	assert.Equal(t, "get oidc sts token err, json.Unmarshal fail: invalid character 'i' looking for beginning of value", err.Error())
224
225
	// case 6: empty response json
226
	hookDo = func(fn do) do {
227
		return func(req *http.Request) (res *http.Response, err error) {
228
			res = mockResponse(200, "null")
229
			return
230
		}
231
	}
232
	_, err = p.getCredentials()
233
	assert.NotNil(t, err)
234
	assert.Equal(t, "get oidc sts token err, fail to get credentials", err.Error())
235
236
	// case 7: empty session ak response json
237
	hookDo = func(fn do) do {
238
		return func(req *http.Request) (res *http.Response, err error) {
239
			res = mockResponse(200, `{"Credentials": {}}`)
240
			return
241
		}
242
	}
243
	_, err = p.getCredentials()
244
	assert.NotNil(t, err)
245
	assert.Equal(t, "refresh RoleArn sts token err, fail to get credentials", err.Error())
246
247
	// case 8: mock ok value
248
	hookDo = func(fn do) do {
249
		return func(req *http.Request) (res *http.Response, err error) {
250
			res = mockResponse(200, `{"Credentials": {"AccessKeyId":"saki","AccessKeySecret":"saks","Expiration":"2021-10-20T04:27:09Z","SecurityToken":"token"}}`)
251
			return
252
		}
253
	}
254
	creds, err := p.getCredentials()
255
	assert.Nil(t, err)
256
	assert.Equal(t, "saki", creds.AccessKeyId)
257
	assert.Equal(t, "saks", creds.AccessKeySecret)
258
	assert.Equal(t, "token", creds.SecurityToken)
259
	assert.Equal(t, "2021-10-20T04:27:09Z", creds.Expiration)
260
261
	// needUpdateCredential
262
	assert.True(t, p.needUpdateCredential())
263
	p.expirationTimestamp = time.Now().Unix()
264
	assert.True(t, p.needUpdateCredential())
265
266
	p.expirationTimestamp = time.Now().Unix() + 300
267
	assert.False(t, p.needUpdateCredential())
268
}
269
270
func TestOIDCCredentialsProvider_getCredentialsWithRequestCheck(t *testing.T) {
271
	originDo := hookDo
272
	defer func() { hookDo = originDo }()
273
274
	// case 1: mock new http request failed
275
	wd, _ := os.Getwd()
276
	p, err := NewOIDCCredentialsProviderBuilder().
277
		// read a normal token
278
		WithOIDCTokenFilePath(path.Join(wd, "fixtures/mock_oidctoken")).
279
		WithOIDCProviderARN("provider-arn").
280
		WithRoleArn("roleArn").
281
		WithRoleSessionName("rsn").
282
		WithPolicy("policy").
283
		WithDurationSeconds(1000).
284
		Build()
285
286
	assert.Nil(t, err)
287
288
	// case 1: server error
289
	hookDo = func(fn do) do {
290
		return func(req *http.Request) (res *http.Response, err error) {
291
			assert.Equal(t, "sts.aliyuncs.com", req.Host)
292
			assert.Contains(t, req.URL.String(), "Action=AssumeRoleWithOIDC")
293
			body, err := ioutil.ReadAll(req.Body)
294
			assert.Nil(t, err)
295
			bodyString := string(body)
296
			assert.Contains(t, bodyString, "Policy=policy")
297
			assert.Contains(t, bodyString, "RoleArn=roleArn")
298
			assert.Contains(t, bodyString, "RoleSessionName=rsn")
299
			assert.Contains(t, bodyString, "DurationSeconds=1000")
300
301
			err = errors.New("mock server error")
302
			return
303
		}
304
	}
305
306
	_, err = p.getCredentials()
307
	assert.NotNil(t, err)
308
	assert.Equal(t, "mock server error", err.Error())
309
}
310
311
func TestOIDCCredentialsProviderGetCredentials(t *testing.T) {
312
	originDo := hookDo
313
	defer func() { hookDo = originDo }()
314
315
	// case 1: mock new http request failed
316
	wd, _ := os.Getwd()
317
	p, err := NewOIDCCredentialsProviderBuilder().
318
		// read a normal token
319
		WithOIDCTokenFilePath(path.Join(wd, "fixtures/mock_oidctoken")).
320
		WithOIDCProviderARN("provider-arn").
321
		WithRoleArn("roleArn").
322
		WithRoleSessionName("rsn").
323
		WithPolicy("policy").
324
		WithDurationSeconds(1000).
325
		Build()
326
327
	assert.Nil(t, err)
328
329
	// case 1: get credentials failed
330
	hookDo = func(fn do) do {
331
		return func(req *http.Request) (res *http.Response, err error) {
332
			err = errors.New("mock server error")
333
			return
334
		}
335
	}
336
	_, err = p.GetCredentials()
337
	assert.NotNil(t, err)
338
	assert.Equal(t, "mock server error", err.Error())
339
340
	// case 2: get invalid expiration
341
	hookDo = func(fn do) do {
342
		return func(req *http.Request) (res *http.Response, err error) {
343
			res = mockResponse(200, `{"Credentials": {"AccessKeyId":"akid","AccessKeySecret":"aksecret","Expiration":"invalidexpiration","SecurityToken":"ststoken"}}`)
344
			return
345
		}
346
	}
347
	_, err = p.GetCredentials()
348
	assert.NotNil(t, err)
349
	assert.Equal(t, "parsing time \"invalidexpiration\" as \"2006-01-02T15:04:05Z\": cannot parse \"invalidexpiration\" as \"2006\"", err.Error())
350
351
	// case 3: happy result
352
	hookDo = func(fn do) do {
353
		return func(req *http.Request) (res *http.Response, err error) {
354
			res = mockResponse(200, `{"Credentials": {"AccessKeyId":"akid","AccessKeySecret":"aksecret","Expiration":"2021-10-20T04:27:09Z","SecurityToken":"ststoken"}}`)
355
			return
356
		}
357
	}
358
	cc, err := p.GetCredentials()
359
	assert.Nil(t, err)
360
	assert.Equal(t, "akid", cc.AccessKeyId)
361
	assert.Equal(t, "aksecret", cc.AccessKeySecret)
362
	assert.Equal(t, "ststoken", cc.SecurityToken)
363
	assert.True(t, p.needUpdateCredential())
364
}
365