Repository navigation
Expand file tree
/
Copy pathhubkit.test.js
More file actions
129 lines (121 loc) · 4.93 KB
/
Copy pathhubkit.test.js
File metadata and controls
129 lines (121 loc) · 4.93 KB
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
'use strict';
const assert = require('node:assert/strict');
const {readFileSync} = require('node:fs');
const test = require('node:test');
const vm = require('node:vm');
const Hubkit = require('./index.js');
const browser = {self: {}, lrucache: require('lru-cache')};
vm.runInNewContext(readFileSync(require.resolve('./hubkit.js'), 'utf8'), browser);
const cases = [
{
message: 'Your account was suspended.',
code: 'account-suspended', category: 'badauth', error: 'GitHub account suspended'
},
{
message: 'Your email address must be verified.',
code: 'email-unverified', category: 'badauth', error: 'Email address not verified'
},
{
message: 'Resource protected by organization SAML enforcement.',
code: 'saml-enforcement', category: 'badauth', error: 'Incomplete SAML authorization'
},
{
message: 'You must have admin rights to this repository.',
code: 'admin-required', category: 'badauth', error: 'No admin rights'
},
{
message: 'You must enable two-factor authentication.',
code: 'two-factor-required', category: 'badauth', error: 'Two-factor authentication not set up'
},
{
message: 'The `example-org` organization has enabled OAuth App access restrictions.',
code: 'oauth-app-restrictions', category: 'thirdparty',
error: 'Third-party app restrictions in effect'
},
{
message: 'Although you appear to have the correct authorization credentials, ' +
'the `example-org` organization has an IP allow list enabled, and your IP address is not ' +
'permitted to access this resource.',
code: 'ip-allow-list', category: 'iprestricted', error: 'GitHub IP allow list blocks access'
},
{
message: 'Repository access blocked.',
code: 'access-blocked', category: 'notfound', error: 'Repository access blocked'
},
{
message: 'You have exceeded a secondary rate limit. Please wait a few minutes.',
code: 'secondary-rate-limit', quota: true
},
{
message: 'This endpoint is temporarily being throttled. Please try again later.',
code: 'secondary-rate-limit', quota: true
},
{
message: 'You have triggered an abuse detection mechanism.',
code: 'secondary-rate-limit', quota: true
},
{
message: 'API rate limit exceeded for user ID 1234.',
code: 'rate-limit', quota: true
}
];
for (const [environment, implementation] of [['Node', Hubkit], ['browser', browser.self.Hubkit]]) {
for (const {message, ...expected} of cases) {
test(`${environment}: identifies ${expected.code} from raw and wrapped messages`, () => {
for (const prefix of [
'',
'GitHub error 403 on GET https://api.github.com/repos/first/repo: ',
'GitHub error 429 on GET https://api.github.com/repos/first/repo: ',
'Internal error: GitHub error 403 on POST https://ghe.example/api/graphql: '
]) {
const text = prefix + message;
for (const input of [text, new Error(text), {message: text}]) {
assert.deepEqual({...implementation.identify403Error(input)}, expected);
}
}
});
}
test(`${environment}: recognizes legacy quota wording and case variants`, () => {
for (const message of [
'THIS ENDPOINT IS TEMPORARILY BEING THROTTLED',
'You have triggered an ABUSE DETECTION mechanism.'
]) {
assert.deepEqual({...implementation.identify403Error(message)},
{code: 'secondary-rate-limit', quota: true});
}
for (const message of [
'API RATE LIMIT EXCEEDED', 'Your request quota is exhausted.'
]) {
assert.deepEqual(
{...implementation.identify403Error(message)}, {code: 'rate-limit', quota: true});
}
for (const {message, ...expected} of cases.filter(value => [
'admin-required', 'two-factor-required', 'ip-allow-list', 'access-blocked'
].includes(value.code))) {
assert.deepEqual({...implementation.identify403Error(message.toUpperCase())}, expected);
}
});
test(`${environment}: preserves specific causes ahead of generic quota wording`, () => {
for (const {message, ...expected} of cases.filter(value => value.category)) {
assert.deepEqual(
{...implementation.identify403Error(message + ' See rate limit documentation.')}, expected);
}
});
test(`${environment}: leaves unknown causes unidentified`, () => {
for (const message of [
'', 'Forbidden', 'Resource not accessible by integration', 'Your request is throttled',
'Your organization has an IP allow list enabled.'
]) {
assert.equal(implementation.identify403Error(message), undefined);
assert.equal(implementation.identify403Error(new Error(message)), undefined);
}
});
test(`${environment}: quota failures cannot be mistaken for broad access errors`, () => {
for (const {message} of cases.slice(-2)) {
const reason = implementation.identify403Error(message);
assert.equal(reason.quota, true);
assert.equal(reason.category, undefined);
assert.equal(reason.error, undefined);
}
});
}