@heroku/skynet 1.11.0 → 1.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const SkynetAPI = require('../../lib/skynet')
4
4
 
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const SkynetAPI = require('../../lib/skynet')
4
4
 
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../lib/command')
3
3
  const SkynetAPI = require('../lib/skynet')
4
4
 
@@ -0,0 +1,40 @@
1
+ const cli = require('@heroku/heroku-cli-util')
2
+ const command = require('../../lib/command')
3
+ const sudo = require('../../lib/sudo')
4
+ const SkynetAPI = require('../../lib/skynet')
5
+
6
+ async function run (context) {
7
+ sudo()
8
+ const skynet = new SkynetAPI(context.auth.password)
9
+ await cli.action(
10
+ `adding ${cli.color.cyan(
11
+ context.flags.name
12
+ )} to categories`,
13
+ skynet.addCategory(context.flags.name, context.flags.description)
14
+ )
15
+ }
16
+
17
+ module.exports = {
18
+ topic: 'skynet',
19
+ command: 'categories:add',
20
+ description: '(requires sudo) Adds a category for use when suspending or deprovisioning',
21
+ help: `Examples:
22
+ $ heroku skynet:add -n Cryptominer -d Abusers running cryptomining on the platform`,
23
+ flags: [
24
+ {
25
+ name: 'name',
26
+ char: 'n',
27
+ description: 'The name of the category',
28
+ hasValue: true,
29
+ required: true
30
+ },
31
+ {
32
+ name: 'description',
33
+ char: 'd',
34
+ description: 'The description of the category',
35
+ hasValue: true,
36
+ required: true
37
+ }
38
+ ],
39
+ run: command(run)
40
+ }
@@ -1,7 +1,7 @@
1
- const cli = require('heroku-cli-util')
2
- const command = require('../lib/command')
3
- const sudo = require('../lib/sudo')
4
- const SkynetAPI = require('../lib/skynet')
1
+ const cli = require('@heroku/heroku-cli-util')
2
+ const command = require('../../lib/command')
3
+ const sudo = require('../../lib/sudo')
4
+ const SkynetAPI = require('../../lib/skynet')
5
5
 
6
6
  async function run (context) {
7
7
  sudo()
@@ -0,0 +1,33 @@
1
+ const cli = require('@heroku/heroku-cli-util')
2
+ const command = require('../../lib/command')
3
+ const sudo = require('../../lib/sudo')
4
+ const SkynetAPI = require('../../lib/skynet')
5
+
6
+ async function run (context) {
7
+ sudo()
8
+ const skynet = new SkynetAPI(context.auth.password)
9
+ await cli.action(
10
+ `removing ${cli.color.cyan(
11
+ context.flags.name
12
+ )} from categories`,
13
+ skynet.removeCategory(context.flags.name)
14
+ )
15
+ }
16
+
17
+ module.exports = {
18
+ topic: 'skynet',
19
+ command: 'categories:remove',
20
+ description: '(requires sudo) Removes a category from Skynet',
21
+ help: `Examples:
22
+ $ heroku skynet:add -n Cryptominer`,
23
+ flags: [
24
+ {
25
+ name: 'name',
26
+ char: 'n',
27
+ description: 'The name of the category',
28
+ hasValue: true,
29
+ required: true
30
+ }
31
+ ],
32
+ run: command(run)
33
+ }
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../lib/command')
3
3
  const sudo = require('../lib/sudo')
4
4
  const SkynetAPI = require('../lib/skynet')
@@ -10,7 +10,7 @@ async function run (context) {
10
10
  const user = context.flags.user || process.env.HEROKU_USER
11
11
  const notes = context.flags.notes
12
12
  const category = context.flags.category
13
- const force = context.flags.bypass
13
+ const force = context.flags.bypass || process.env.HEROKU_FORCE === '1'
14
14
 
15
15
  const notify = notifyOption.set(context.flags.notify, context.flags['no-notify'])
16
16
  const notificationStatus = (notify) ? 'enabled' : 'disabled'
@@ -34,7 +34,7 @@ module.exports = {
34
34
  { name: 'user', char: 'u', description: 'user to deprovision', hasValue: true },
35
35
  { name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true },
36
36
  { name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true },
37
- { name: 'bypass', description: 'bypass the allowlist', hasValue: false, required: false },
37
+ { name: 'bypass', description: 'force suspension, bypassing skynet safety checks', hasValue: false, required: false },
38
38
  { name: 'notify', description: 'send user suspension email notification', hasValue: false, required: false },
39
39
  { name: 'no-notify', description: 'skip user suspension email notification', hasValue: false, required: false }
40
40
  ],
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const sudo = require('../../lib/sudo')
4
4
  const SkynetAPI = require('../../lib/skynet')
@@ -12,7 +12,8 @@ async function run (context) {
12
12
  const file = context.flags.infile
13
13
  const notes = context.flags.notes
14
14
  const category = context.flags.category
15
- const force = context.flags.bypass
15
+ const force = context.flags.bypass || process.env.HEROKU_FORCE === '1'
16
+ const deprovision = context.flags.deprovision
16
17
 
17
18
  if (app && file) {
18
19
  throw new Error('Either --app or --infile must be passed, but not both')
@@ -23,7 +24,7 @@ async function run (context) {
23
24
  const chunks = utils.arrayChunks(apps, chunkSize)
24
25
  for (const chunk of chunks) {
25
26
  cli.log('Suspending app owners: ' + chunk.join())
26
- const response = await skynet.bulkSuspendAppOwner(apps.join(), notes, category)
27
+ const response = await skynet.bulkSuspendAppOwner(apps.join(), notes, category, deprovision)
27
28
  cli.log(`${cli.color.cyan(response.status)}. ${response.message}`)
28
29
  cli.log()
29
30
  }
@@ -32,8 +33,8 @@ async function run (context) {
32
33
  throw new Error('Required flag: --owner OWNER or --infile FILE')
33
34
  }
34
35
 
35
- let response = await cli.action(`Deprovisioning app owner of ${cli.color.cyan(app)}`,
36
- skynet.suspendAppOwner(app, notes, category, force))
36
+ let response = await cli.action(`Suspending app owner of ${cli.color.cyan(app)}`,
37
+ skynet.suspendAppOwner(app, notes, category, force, deprovision))
37
38
  response = JSON.parse(response)
38
39
  cli.log(`${cli.color.cyan(response.status)}. ${response.message}`)
39
40
  }
@@ -50,7 +51,8 @@ module.exports = {
50
51
  { name: 'infile', char: 'i', description: 'file of apps that require owner suspension', hasValue: true },
51
52
  { name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true },
52
53
  { name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true },
53
- { name: 'bypass', description: 'bypass the allowlist', hasValue: false, required: false }
54
+ { name: 'bypass', description: 'force suspension, bypassing skynet safety checks', hasValue: false, required: false },
55
+ { name: 'deprovision', char: 'd', description: 'put user into the fast resource deletion flow', hasValue: false, required: false }
54
56
  ],
55
57
  run: command(run)
56
58
  }
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const sudo = require('../../lib/sudo')
4
4
  const SkynetAPI = require('../../lib/skynet')
@@ -10,7 +10,7 @@ async function run (context) {
10
10
  context.flags.app,
11
11
  context.flags.notes,
12
12
  context.flags.category,
13
- context.flags.bypass
13
+ context.flags.bypass || process.env.HEROKU_FORCE === '1'
14
14
  )
15
15
  response = JSON.parse(response)
16
16
  cli.log(
@@ -25,33 +25,10 @@ module.exports = {
25
25
  help: `Examples:
26
26
  $ heroku skynet:suspend:app -a test-app -c "category" -n "helpful suspend message"`,
27
27
  flags: [
28
- {
29
- name: 'app',
30
- char: 'a',
31
- description: 'app to suspend',
32
- hasValue: true,
33
- required: true
34
- },
35
- {
36
- name: 'notes',
37
- char: 'n',
38
- description: 'suspend notes',
39
- hasValue: true,
40
- required: true
41
- },
42
- {
43
- name: 'category',
44
- char: 'c',
45
- description: 'suspension category',
46
- hasValue: true,
47
- required: true
48
- },
49
- {
50
- name: 'bypass',
51
- description: 'force suspension',
52
- hasValue: false,
53
- required: false
54
- }
28
+ { name: 'app', char: 'a', description: 'app to suspend', hasValue: true, required: true },
29
+ { name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true },
30
+ { name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true },
31
+ { name: 'bypass', description: 'force suspension, bypassing skynet safety checks', hasValue: false, required: false }
55
32
  ],
56
33
  run: command(run)
57
34
  }
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const sudo = require('../../lib/sudo')
4
4
  const SkynetAPI = require('../../lib/skynet')
@@ -20,8 +20,9 @@ async function run (context) {
20
20
  const file = context.flags.infile
21
21
  const notes = context.flags.notes
22
22
  const category = context.flags.category
23
- const force = context.flags.bypass
23
+ const force = context.flags.bypass || process.env.HEROKU_FORCE === '1'
24
24
  const unverify = context.flags.unverify
25
+ const deprovision = context.flags.deprovision
25
26
 
26
27
  const notify = notifyOption.set(context.flags.notify, context.flags['no-notify'])
27
28
  const notificationStatus = (notify) ? 'enabled' : 'disabled'
@@ -35,7 +36,7 @@ async function run (context) {
35
36
  const chunks = utils.arrayChunks(users, chunkSize)
36
37
  for (const chunk of chunks) {
37
38
  cli.log('Suspending users: ' + chunk.join())
38
- const response = await skynet.bulkSuspendUsers(chunk.join(), notes, category, notify, force)
39
+ const response = await skynet.bulkSuspendUsers(chunk.join(), notes, category, notify, force, deprovision)
39
40
  cli.log(`${response}. Notification ${notificationStatus}`)
40
41
  cli.log()
41
42
  }
@@ -48,7 +49,7 @@ async function run (context) {
48
49
  throw new Error('Required flag: --user USER or --infile FILE')
49
50
  }
50
51
 
51
- let response = await skynet.suspendUser(user, notes, category, notify, force)
52
+ let response = await skynet.suspendUser(user, notes, category, notify, force, deprovision)
52
53
  response = JSON.parse(response)
53
54
  cli.log(`Suspending user ${user}...\n${response.status}. ${response.message}. Notification ${notificationStatus}`)
54
55
 
@@ -69,10 +70,11 @@ module.exports = {
69
70
  { name: 'infile', char: 'i', description: 'file of users to suspend', hasValue: true },
70
71
  { name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true },
71
72
  { name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true },
72
- { name: 'bypass', description: 'bypass the allowlist', hasValue: false, required: false },
73
+ { name: 'bypass', description: 'force suspension, bypassing skynet safety checks', hasValue: false, required: false },
73
74
  { name: 'no-notify', description: 'skip user suspension email notification', hasValue: false, required: false },
74
75
  { name: 'notify', description: 'send user suspension email notification', hasValue: false, required: false },
75
- { name: 'unverify', description: 'unverifies a user account, removes all billing info', hasValue: false, required: false }
76
+ { name: 'unverify', description: 'unverifies a user account, removes all billing info', hasValue: false, required: false },
77
+ { name: 'deprovision', char: 'd', description: 'put user into the fast resource deletion flow', hasValue: false, required: false }
76
78
  ],
77
79
  run: command(run)
78
80
  }
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../lib/command')
3
3
  const sudo = require('../lib/sudo')
4
4
  const SkynetAPI = require('../lib/skynet')
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const sudo = require('../../lib/sudo')
4
4
  const SkynetAPI = require('../../lib/skynet')
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const sudo = require('../../lib/sudo')
4
4
  const SkynetAPI = require('../../lib/skynet')
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const SkynetAPI = require('../../lib/skynet')
4
4
 
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
  const command = require('../../lib/command')
3
3
  const SkynetAPI = require('../../lib/skynet')
4
4
 
package/index.js CHANGED
@@ -13,7 +13,9 @@ exports.commands = [
13
13
  require('./commands/unsuspend/apps.js'),
14
14
  require('./commands/unsuspend/user.js'),
15
15
  require('./commands/deprovision.js'),
16
- require('./commands/categories.js'),
16
+ require('./commands/categories/add.js'),
17
+ require('./commands/categories/get.js'),
18
+ require('./commands/categories/remove.js'),
17
19
  require('./commands/allowlist/add.js'),
18
20
  require('./commands/allowlist/remove.js'),
19
21
  require('./commands/allowlists.js'),
package/lib/command.js CHANGED
@@ -1,4 +1,4 @@
1
- const cli = require('heroku-cli-util')
1
+ const cli = require('@heroku/heroku-cli-util')
2
2
 
3
3
  module.exports = fn =>
4
4
  cli.command((context, client) =>
package/lib/skynet.js CHANGED
@@ -32,6 +32,23 @@ module.exports = class SkynetAPI {
32
32
  })
33
33
  }
34
34
 
35
+ addCategory (name, description) {
36
+ const body = {
37
+ category: name,
38
+ description: description
39
+ }
40
+ return this.request('/categories', {
41
+ method: 'POST',
42
+ form: body
43
+ })
44
+ }
45
+
46
+ removeCategory (name) {
47
+ return this.request(`/categories/${name}`, {
48
+ method: 'DELETE'
49
+ })
50
+ }
51
+
35
52
  allowlists () {
36
53
  return this.request('/whitelist', {
37
54
  method: 'GET'
@@ -46,16 +63,14 @@ module.exports = class SkynetAPI {
46
63
 
47
64
  return this.request('/whitelist', {
48
65
  method: 'POST',
49
- body: body,
50
- form: true
66
+ form: body
51
67
  })
52
68
  }
53
69
 
54
70
  removeAllowlist (appOrUserEmail) {
55
71
  return this.request(`/whitelist/${appOrUserEmail}`, {
56
72
  method: 'DELETE',
57
- body: {},
58
- json: true
73
+ json: {}
59
74
  })
60
75
  }
61
76
 
@@ -67,8 +82,7 @@ module.exports = class SkynetAPI {
67
82
 
68
83
  return this.request('/userpass/remove', {
69
84
  method: 'POST',
70
- body: body,
71
- form: true
85
+ form: body
72
86
  })
73
87
  }
74
88
 
@@ -80,24 +94,23 @@ module.exports = class SkynetAPI {
80
94
 
81
95
  return this.request('/userpass/add', {
82
96
  method: 'POST',
83
- body: body,
84
- form: true
97
+ form: body
85
98
  })
86
99
  }
87
100
 
88
- suspendAppOwner (app, notes, category, force = false) {
101
+ suspendAppOwner (app, notes, category, force = false, deprovision = false) {
89
102
  const body = {
90
103
  value: app,
91
104
  reason: notes,
92
105
  method: 'skynet-cli',
93
106
  category: category,
94
- force: force
107
+ force: force,
108
+ deprovision: deprovision
95
109
  }
96
110
 
97
111
  return this.request('/suspend/app-owner', {
98
112
  method: 'POST',
99
- body: body,
100
- form: true
113
+ form: body
101
114
  })
102
115
  }
103
116
 
@@ -112,45 +125,42 @@ module.exports = class SkynetAPI {
112
125
 
113
126
  return this.request('/suspend/app', {
114
127
  method: 'POST',
115
- body: body,
116
- form: true
128
+ form: body
117
129
  })
118
130
  }
119
131
 
120
132
  unsuspendApp (app, category, notes) {
121
133
  return this.request(`/suspensions/app/${app}?category=${category}&reason=${notes}`, {
122
134
  method: 'DELETE',
123
- body: {},
124
- json: true
135
+ json: {}
125
136
  })
126
137
  }
127
138
 
128
- suspendUser (user, notes, category, notify, force = false) {
139
+ suspendUser (user, notes, category, notify, force = false, deprovision = false) {
129
140
  const body = {
130
141
  value: user,
131
142
  reason: notes,
132
143
  method: 'skynet-cli',
133
144
  category: category,
134
145
  force: force,
135
- notify: notify
146
+ notify: notify,
147
+ deprovision: deprovision
136
148
  }
137
149
 
138
150
  return this.request('/suspend/user', {
139
151
  method: 'POST',
140
- body: body,
141
- form: true
152
+ form: body
142
153
  })
143
154
  }
144
155
 
145
156
  unsuspendUser (user, category, notes) {
146
157
  return this.request(`/suspensions/user/${user}?category=${category}&reason=${notes}`, {
147
158
  method: 'DELETE',
148
- body: {},
149
- json: true
159
+ json: {}
150
160
  })
151
161
  }
152
162
 
153
- bulkSuspendUsers (users, notes, category, notify, force = false) {
163
+ bulkSuspendUsers (users, notes, category, notify, force = false, deprovision = false) {
154
164
  const body = {
155
165
  value: users,
156
166
  reason: notes,
@@ -158,29 +168,29 @@ module.exports = class SkynetAPI {
158
168
  category: category,
159
169
  bulk: 'true',
160
170
  force: force,
161
- notify: notify
171
+ notify: notify,
172
+ deprovision: deprovision
162
173
  }
163
174
 
164
175
  return this.request('/suspend/user', {
165
176
  method: 'POST',
166
- body: body,
167
- form: true
177
+ form: body
168
178
  })
169
179
  }
170
180
 
171
- bulkSuspendAppOwner (apps, notes, category) {
181
+ bulkSuspendAppOwner (apps, notes, category, deprovision = false) {
172
182
  const body = {
173
183
  value: apps,
174
184
  reason: notes,
175
185
  method: 'skynet-cli',
176
186
  category: category,
177
- bulk: 'true'
187
+ bulk: 'true',
188
+ deprovision: deprovision
178
189
  }
179
190
 
180
191
  return this.request('/suspend/app-owner', {
181
192
  method: 'POST',
182
- body: body,
183
- form: true
193
+ form: body
184
194
  })
185
195
  }
186
196
 
@@ -196,8 +206,7 @@ module.exports = class SkynetAPI {
196
206
 
197
207
  return this.request('/deprovision', {
198
208
  method: 'POST',
199
- body: body,
200
- form: true
209
+ form: body
201
210
  })
202
211
  }
203
212
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroku/skynet",
3
- "version": "1.11.0",
3
+ "version": "1.13.0",
4
4
  "description": "use Skynet from Heroku CLI",
5
5
  "main": "index.js",
6
6
  "author": "Bob Argenbright @byt3smith",
@@ -21,8 +21,8 @@
21
21
  "npm": ">=10"
22
22
  },
23
23
  "dependencies": {
24
- "got": "^9.6.0",
25
- "heroku-cli-util": "^6.2.8",
24
+ "@heroku/heroku-cli-util": "^8.0.12",
25
+ "got": "^11.8.5",
26
26
  "split": "^1.0.0"
27
27
  },
28
28
  "devDependencies": {
@@ -31,7 +31,7 @@
31
31
  "mocha": "^9.2.2",
32
32
  "mockdate": "^2.0.1",
33
33
  "nock": "^12.0.3",
34
- "np": "^7.6.3",
34
+ "np": "^10.0.5",
35
35
  "standard": "^16.0.4",
36
36
  "unexpected": "^12.0.3"
37
37
  },