@heroku/skynet 1.4.1
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.
- package/README.md +76 -0
- package/commands/categories.js +27 -0
- package/commands/deprovision.js +70 -0
- package/commands/suspend/app-owner.js +70 -0
- package/commands/suspend/apps.js +25 -0
- package/commands/suspend/user.js +70 -0
- package/commands/unsuspend/apps.js +24 -0
- package/commands/unsuspend/user.js +26 -0
- package/commands/userpass/add.js +21 -0
- package/commands/userpass/remove.js +21 -0
- package/index.js +17 -0
- package/lib/skynet.js +169 -0
- package/lib/sudo.js +5 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Skynet CLI Plugin
|
|
2
|
+
[](https://travis-ci.com/heroku/heroku-skynet-cli)
|
|
3
|
+
|
|
4
|
+
Use Skynet from Heroku CLI
|
|
5
|
+
|
|
6
|
+
### Installation
|
|
7
|
+
```
|
|
8
|
+
heroku plugins:install heroku-skynet-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Development
|
|
12
|
+
- `git clone https://github.com/heroku/heroku-skynet-cli.git`
|
|
13
|
+
- Change directories into the cloned repository
|
|
14
|
+
- Link the plugin with `heroku plugins:link .`
|
|
15
|
+
|
|
16
|
+
### Publishing to `npm`
|
|
17
|
+
1. Contact `heroku-cli@salesforce.com` to get credentials to Heroku's private NPM registry
|
|
18
|
+
|
|
19
|
+
2. Make sure you have `np` installed. Install by running `npm install np`
|
|
20
|
+
|
|
21
|
+
3. When you are ready to publish what you have locally, run `np` and you will see an output like this:
|
|
22
|
+
```
|
|
23
|
+
λ bargenbright[heroku-skynet-cli/] (git:master)~$ np
|
|
24
|
+
|
|
25
|
+
Publish a new version of heroku-skynet-cli (current: 1.3.5)
|
|
26
|
+
|
|
27
|
+
? Select semver increment or specify new version minor 1.4.0
|
|
28
|
+
|
|
29
|
+
Commits:
|
|
30
|
+
- Merge pull request #28 from heroku/refactor+appowner f2c5655
|
|
31
|
+
- add app-owner command b07940b
|
|
32
|
+
- adds app-owner command and refactors e914b09
|
|
33
|
+
|
|
34
|
+
? Will bump from 1.3.5 to 1.4.0. Continue? Yes
|
|
35
|
+
✔ Prerequisite check
|
|
36
|
+
✔ Git
|
|
37
|
+
✔ Cleanup
|
|
38
|
+
✔ Installing dependencies using Yarn
|
|
39
|
+
✔ Running tests
|
|
40
|
+
✔ Bumping version using Yarn
|
|
41
|
+
✖ Publishing package using Yarn
|
|
42
|
+
→ info Visit https://yarnpkg.com/en/docs/cli/publish for documentation about this command.
|
|
43
|
+
Pushing tags
|
|
44
|
+
|
|
45
|
+
✖ Error: Command failed: yarn publish --new-version 1.4.0
|
|
46
|
+
warning package.json: No license field
|
|
47
|
+
warning package.json: No license field
|
|
48
|
+
error An unexpected error occurred: "No token found and can't prompt for login when running with --non-interactive.".
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
4. After you get the `np` error, run `npm publish` to finish pushing the new release.
|
|
52
|
+
```
|
|
53
|
+
λ bargenbright[heroku-skynet-cli/] (git:master)~$ npm publish
|
|
54
|
+
+ heroku-skynet-cli@1.4.0
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
5. Then, push the tags to the git repository
|
|
58
|
+
```
|
|
59
|
+
λ bargenbright[heroku-skynet-cli/] (git:master)~$ git push origin --tags
|
|
60
|
+
Counting objects: 4, done.
|
|
61
|
+
Delta compression using up to 8 threads.
|
|
62
|
+
Compressing objects: 100% (4/4), done.
|
|
63
|
+
Writing objects: 100% (4/4), 416 bytes | 416.00 KiB/s, done.
|
|
64
|
+
Total 4 (delta 2), reused 0 (delta 0)
|
|
65
|
+
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
|
|
66
|
+
To github.com:heroku/heroku-skynet-cli.git
|
|
67
|
+
* [new tag] v1.4.0 -> v1.4.0
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
6. Finally, push the version change commit done by the `np` tool
|
|
71
|
+
```
|
|
72
|
+
λ bargenbright[heroku-skynet-cli/] (git:master)~$ git push origin master
|
|
73
|
+
Total 0 (delta 0), reused 0 (delta 0)
|
|
74
|
+
To github.com:heroku/heroku-skynet-cli.git
|
|
75
|
+
f2c5655..e8ad793 master -> master
|
|
76
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function * run (context) {
|
|
7
|
+
sudo()
|
|
8
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
9
|
+
let response = yield skynet.categories()
|
|
10
|
+
response = JSON.parse(response)
|
|
11
|
+
cli.table(response, {
|
|
12
|
+
columns: [
|
|
13
|
+
{key: 'Category'},
|
|
14
|
+
{key: 'Description'}
|
|
15
|
+
]
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
topic: 'skynet',
|
|
21
|
+
command: 'categories',
|
|
22
|
+
description: 'categories to use for suspension and deprovisions',
|
|
23
|
+
help: `Examples:
|
|
24
|
+
$ heroku skynet:categories`,
|
|
25
|
+
flags: [],
|
|
26
|
+
run: cli.command(co.wrap(run))
|
|
27
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function readlines (file) {
|
|
7
|
+
return new Promise(function (resolve, reject) {
|
|
8
|
+
let split = require('split')
|
|
9
|
+
let fs = require('fs')
|
|
10
|
+
|
|
11
|
+
let users = []
|
|
12
|
+
|
|
13
|
+
fs.createReadStream(file).pipe(split())
|
|
14
|
+
.on('data', function (line) {
|
|
15
|
+
line = line.trim()
|
|
16
|
+
if (line) {
|
|
17
|
+
users.push(line)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
.on('end', function () {
|
|
21
|
+
resolve(users)
|
|
22
|
+
})
|
|
23
|
+
.on('error', function (err) {
|
|
24
|
+
reject(err)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function * run (context) {
|
|
30
|
+
sudo()
|
|
31
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
32
|
+
let user = context.flags.user || process.env.HEROKU_USER
|
|
33
|
+
let file = context.flags.infile
|
|
34
|
+
let notes = context.flags.notes
|
|
35
|
+
let category = context.flags.category
|
|
36
|
+
let force = context.flags.bypass
|
|
37
|
+
|
|
38
|
+
if (user && file) {
|
|
39
|
+
throw new Error('Either --user USER or --infile must be passed, but not both')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (file) {
|
|
43
|
+
let users = yield readlines(file)
|
|
44
|
+
yield cli.action(`bulk deprovisioning for ${cli.color.cyan(users.length)} users`, skynet.bulkDeprovision(users.join(), notes, category))
|
|
45
|
+
} else {
|
|
46
|
+
if (!user) {
|
|
47
|
+
throw new Error('Required flag: --user USER or --infile FILE')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let response = yield cli.action(`deprovisioning ${cli.color.cyan(user)}`, skynet.deprovision(user, notes, category, force))
|
|
51
|
+
response = JSON.parse(response)
|
|
52
|
+
cli.log(`${response.status}. ${response.message}`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
topic: 'skynet',
|
|
58
|
+
command: 'deprovision',
|
|
59
|
+
description: 'suspends a user and deprovisions all addons',
|
|
60
|
+
help: `Examples:
|
|
61
|
+
$ heroku skynet:deprovision -u foo@bar.com -n "helpful suspend message" -c "spam"`,
|
|
62
|
+
flags: [
|
|
63
|
+
{name: 'user', char: 'u', description: 'user to deprovision', hasValue: true},
|
|
64
|
+
{name: 'infile', char: 'i', description: 'file list of users to deprovision', hasValue: true},
|
|
65
|
+
{name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true},
|
|
66
|
+
{name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true},
|
|
67
|
+
{name: 'bypass', description: 'bypass the whitelist', hasValue: false, required: false}
|
|
68
|
+
],
|
|
69
|
+
run: cli.command(co.wrap(run))
|
|
70
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function readlines (file) {
|
|
7
|
+
return new Promise(function (resolve, reject) {
|
|
8
|
+
let split = require('split')
|
|
9
|
+
let fs = require('fs')
|
|
10
|
+
|
|
11
|
+
let users = []
|
|
12
|
+
|
|
13
|
+
fs.createReadStream(file).pipe(split())
|
|
14
|
+
.on('data', function (line) {
|
|
15
|
+
line = line.trim()
|
|
16
|
+
if (line) {
|
|
17
|
+
users.push(line)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
.on('end', function () {
|
|
21
|
+
resolve(users)
|
|
22
|
+
})
|
|
23
|
+
.on('error', function (err) {
|
|
24
|
+
reject(err)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function * run (context) {
|
|
30
|
+
sudo()
|
|
31
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
32
|
+
let app = context.flags.app
|
|
33
|
+
let file = context.flags.infile
|
|
34
|
+
let notes = context.flags.notes
|
|
35
|
+
let category = context.flags.category
|
|
36
|
+
let force = context.flags.bypass
|
|
37
|
+
|
|
38
|
+
if (app && file) {
|
|
39
|
+
throw new Error('Either --app or --infile must be passed, but not both')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (file) {
|
|
43
|
+
let apps = yield readlines(file)
|
|
44
|
+
yield cli.action(`bulk app-owner suspension for ${cli.color.cyan(apps.length)} apps.`, skynet.bulkSuspendAppOwner(apps.join(), notes, category))
|
|
45
|
+
} else {
|
|
46
|
+
if (!app) {
|
|
47
|
+
throw new Error('Required flag: --owner OWNER or --infile FILE')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let response = yield cli.action(`suspending the owner of ${cli.color.cyan(app)}`, skynet.suspendAppOwner(app, notes, category, force))
|
|
51
|
+
response = JSON.parse(response)
|
|
52
|
+
cli.log(`${response.status}. ${response.message}`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
topic: 'skynet',
|
|
58
|
+
command: 'suspend:app-owner',
|
|
59
|
+
description: 'suspends the owner of a given app',
|
|
60
|
+
help: `Examples:
|
|
61
|
+
$ heroku skynet:suspend:app-owner -a foobar -n "helpful suspend message" -c "ddos"`,
|
|
62
|
+
flags: [
|
|
63
|
+
{name: 'app', char: 'a', description: 'app that requires owner suspension', hasValue: true},
|
|
64
|
+
{name: 'infile', char: 'i', description: 'file of apps that require owner suspension', hasValue: true},
|
|
65
|
+
{name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true},
|
|
66
|
+
{name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true},
|
|
67
|
+
{name: 'bypass', description: 'bypass the whitelist', hasValue: false, required: false}
|
|
68
|
+
],
|
|
69
|
+
run: cli.command(co.wrap(run))
|
|
70
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function * run (context) {
|
|
7
|
+
sudo()
|
|
8
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
9
|
+
let response = yield skynet.suspendApp(context.flags.app, context.flags.notes)
|
|
10
|
+
response = JSON.parse(response)
|
|
11
|
+
cli.log(`suspending...${cli.color.cyan(response.status)}.\n${response.message}`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
topic: 'skynet',
|
|
16
|
+
command: 'suspend:app',
|
|
17
|
+
description: 'suspends an app',
|
|
18
|
+
help: `Examples:
|
|
19
|
+
$ heroku skynet:suspend:app -a test-app -n "helpful suspend message"`,
|
|
20
|
+
flags: [
|
|
21
|
+
{name: 'app', char: 'a', description: 'app to suspend', hasValue: true, required: true},
|
|
22
|
+
{name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true}
|
|
23
|
+
],
|
|
24
|
+
run: cli.command(co.wrap(run))
|
|
25
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function readlines (file) {
|
|
7
|
+
return new Promise(function (resolve, reject) {
|
|
8
|
+
let split = require('split')
|
|
9
|
+
let fs = require('fs')
|
|
10
|
+
|
|
11
|
+
let users = []
|
|
12
|
+
|
|
13
|
+
fs.createReadStream(file).pipe(split())
|
|
14
|
+
.on('data', function (line) {
|
|
15
|
+
line = line.trim()
|
|
16
|
+
if (line) {
|
|
17
|
+
users.push(line)
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
.on('end', function () {
|
|
21
|
+
resolve(users)
|
|
22
|
+
})
|
|
23
|
+
.on('error', function (err) {
|
|
24
|
+
reject(err)
|
|
25
|
+
})
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function * run (context) {
|
|
30
|
+
sudo()
|
|
31
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
32
|
+
let user = context.flags.user || process.env.HEROKU_USER
|
|
33
|
+
let file = context.flags.infile
|
|
34
|
+
let notes = context.flags.notes
|
|
35
|
+
let category = context.flags.category
|
|
36
|
+
let force = context.flags.bypass
|
|
37
|
+
|
|
38
|
+
if (user && file) {
|
|
39
|
+
throw new Error('Either --user USER or --infile must be passed, but not both')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (file) {
|
|
43
|
+
let users = yield readlines(file)
|
|
44
|
+
yield cli.action(`bulk user suspension for ${cli.color.cyan(users.length)} users.`, skynet.bulkSuspendUsers(users.join(), notes, category))
|
|
45
|
+
} else {
|
|
46
|
+
if (!user) {
|
|
47
|
+
throw new Error('Required flag: --user USER or --infile FILE')
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let response = yield cli.action(`suspending ${cli.color.cyan(user)}`, skynet.suspendUser(user, notes, category, force))
|
|
51
|
+
response = JSON.parse(response)
|
|
52
|
+
cli.log(`${response.status}. ${response.message}`)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
topic: 'skynet',
|
|
58
|
+
command: 'suspend:user',
|
|
59
|
+
description: 'suspends a user',
|
|
60
|
+
help: `Examples:
|
|
61
|
+
$ heroku skynet:suspend:user -u foo@bar.com -n "helpful suspend message" -c "ddos"`,
|
|
62
|
+
flags: [
|
|
63
|
+
{name: 'user', char: 'u', description: 'user to suspend', hasValue: true},
|
|
64
|
+
{name: 'infile', char: 'i', description: 'file of users to suspend', hasValue: true},
|
|
65
|
+
{name: 'category', char: 'c', description: 'suspension category', hasValue: true, required: true},
|
|
66
|
+
{name: 'notes', char: 'n', description: 'suspend notes', hasValue: true, required: true},
|
|
67
|
+
{name: 'bypass', description: 'bypass the whitelist', hasValue: false, required: false}
|
|
68
|
+
],
|
|
69
|
+
run: cli.command(co.wrap(run))
|
|
70
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function * run (context) {
|
|
7
|
+
sudo()
|
|
8
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
9
|
+
let response = yield skynet.unsuspendApp(context.flags.app, context.flags.notes)
|
|
10
|
+
response = JSON.parse(response)
|
|
11
|
+
cli.log(`suspending...${cli.color.cyan(response.status)}.\n${response.message}`)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = {
|
|
15
|
+
topic: 'skynet',
|
|
16
|
+
command: 'unsuspend:app',
|
|
17
|
+
description: 'unsuspends an app',
|
|
18
|
+
help: `Examples:
|
|
19
|
+
$ heroku skynet:unsuspend:app -a test-app`,
|
|
20
|
+
flags: [
|
|
21
|
+
{name: 'app', char: 'a', description: 'app to unsuspend', hasValue: true, required: true}
|
|
22
|
+
],
|
|
23
|
+
run: cli.command(co.wrap(run))
|
|
24
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let sudo = require('../../lib/sudo')
|
|
4
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
5
|
+
|
|
6
|
+
function * run (context) {
|
|
7
|
+
sudo()
|
|
8
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
9
|
+
let user = context.flags.user || process.env.HEROKU_USER
|
|
10
|
+
|
|
11
|
+
let response = yield cli.action(`unsuspending ${cli.color.cyan(user)}`, skynet.unsuspendUser(user))
|
|
12
|
+
response = JSON.parse(response)
|
|
13
|
+
cli.log(`${response.status}. ${response.message}`)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
topic: 'skynet',
|
|
18
|
+
command: 'unsuspend:user',
|
|
19
|
+
description: 'unsuspends a user',
|
|
20
|
+
help: `Examples:
|
|
21
|
+
$ heroku skynet:unsuspend:user -u foo@bar.com`,
|
|
22
|
+
flags: [
|
|
23
|
+
{name: 'user', char: 'u', description: 'user to unsuspend', hasValue: true}
|
|
24
|
+
],
|
|
25
|
+
run: cli.command(co.wrap(run))
|
|
26
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
4
|
+
|
|
5
|
+
function * run (context) {
|
|
6
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
7
|
+
yield cli.action(`adding ${cli.color.cyan(context.flags.userpass)} to ${cli.color.cyan(context.flags.user)}`, skynet.addUserpass(context.flags.user, context.flags.userpass))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
topic: 'skynet',
|
|
12
|
+
command: 'userpass:add',
|
|
13
|
+
description: 'adds a userpass flag to a given user',
|
|
14
|
+
help: `Examples:
|
|
15
|
+
$ heroku skynet:userpass:add -u foo@bar.com -f cant-install-abused-addons`,
|
|
16
|
+
flags: [
|
|
17
|
+
{name: 'user', char: 'u', description: 'user to apply userpass flag to', hasValue: true, required: true},
|
|
18
|
+
{name: 'userpass', char: 'f', description: 'flag to add to the given user', hasValue: true, required: true}
|
|
19
|
+
],
|
|
20
|
+
run: cli.command(co.wrap(run))
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
let cli = require('heroku-cli-util')
|
|
2
|
+
let co = require('co')
|
|
3
|
+
let SkynetAPI = require('../../lib/skynet')
|
|
4
|
+
|
|
5
|
+
function * run (context) {
|
|
6
|
+
const skynet = new SkynetAPI(context.version, context.auth.password)
|
|
7
|
+
yield cli.action(`removing ${cli.color.cyan(context.flags.userpass)} from ${cli.color.cyan(context.flags.user)}`, skynet.removeUserpass(context.flags.user, context.flags.userpass))
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
module.exports = {
|
|
11
|
+
topic: 'skynet',
|
|
12
|
+
command: 'userpass:remove',
|
|
13
|
+
description: 'removes given flag from a given user',
|
|
14
|
+
help: `Examples:
|
|
15
|
+
$ heroku skynet:userpass:remove -u foo@bar.com -f cant-install-abused-addons`,
|
|
16
|
+
flags: [
|
|
17
|
+
{name: 'user', char: 'u', description: 'user to remove user_pass from', hasValue: true, required: true},
|
|
18
|
+
{name: 'userpass', char: 'f', description: 'flag to remove from given user', hasValue: true, required: true}
|
|
19
|
+
],
|
|
20
|
+
run: cli.command(co.wrap(run))
|
|
21
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
exports.topic = {
|
|
2
|
+
name: 'skynet',
|
|
3
|
+
// this is the help text that shows up under `heroku help`
|
|
4
|
+
description: 'use Skynet from Heroku CLI'
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
exports.commands = [
|
|
8
|
+
require('./commands/userpass/add.js'),
|
|
9
|
+
require('./commands/userpass/remove.js'),
|
|
10
|
+
require('./commands/suspend/app-owner.js'),
|
|
11
|
+
require('./commands/suspend/apps.js'),
|
|
12
|
+
require('./commands/suspend/user.js'),
|
|
13
|
+
require('./commands/unsuspend/apps.js'),
|
|
14
|
+
require('./commands/unsuspend/user.js'),
|
|
15
|
+
require('./commands/deprovision.js'),
|
|
16
|
+
require('./commands/categories.js')
|
|
17
|
+
]
|
package/lib/skynet.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
const cli = require('heroku-cli-util')
|
|
2
|
+
const qs = require('querystring')
|
|
3
|
+
const SKYNET_BASE_URL = 'https://skynet.herokai.com/api-h'
|
|
4
|
+
|
|
5
|
+
module.exports = class SkynetAPI {
|
|
6
|
+
constructor (version, token) {
|
|
7
|
+
this.version = version
|
|
8
|
+
this.token = token
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
request (url, options = {}) {
|
|
12
|
+
options.headers = Object.assign({
|
|
13
|
+
Authorization: `Bearer ${this.token}`,
|
|
14
|
+
'User-Agent': this.version
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
if (['POST', 'PATCH', 'DELETE'].includes(options.method)) {
|
|
18
|
+
options.headers['Content-type'] = 'application/x-www-form-urlencoded'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
options.json = false
|
|
22
|
+
|
|
23
|
+
return cli.got(SKYNET_BASE_URL + url, options).then((res) => res.body)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
categories () {
|
|
27
|
+
return this.request(`/categories`, {
|
|
28
|
+
method: 'GET'
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
removeUserpass (user, flag) {
|
|
33
|
+
var body = {
|
|
34
|
+
user: user,
|
|
35
|
+
flag: flag
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return this.request(`/userpass/remove`, {
|
|
39
|
+
method: 'POST',
|
|
40
|
+
body: qs.stringify(body)
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
addUserpass (user, flag) {
|
|
45
|
+
var body = {
|
|
46
|
+
user: user,
|
|
47
|
+
flag: flag
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return this.request(`/userpass/add`, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
body: qs.stringify(body)
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
suspendAppOwner (app, notes, category) {
|
|
57
|
+
var body = {
|
|
58
|
+
value: app,
|
|
59
|
+
reason: notes,
|
|
60
|
+
method: 'skynet-cli',
|
|
61
|
+
category: category
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return this.request('/suspend/app-owner', {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
body: qs.stringify(body)
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
suspendApp (app, notes, category) {
|
|
71
|
+
var body = {
|
|
72
|
+
value: app,
|
|
73
|
+
reason: notes,
|
|
74
|
+
method: 'skynet-cli',
|
|
75
|
+
category: category
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return this.request('/suspend/app', {
|
|
79
|
+
method: 'POST',
|
|
80
|
+
body: qs.stringify(body)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
unsuspendApp (app) {
|
|
85
|
+
return this.request(`/suspensions/app/${app}`, {
|
|
86
|
+
method: 'DELETE'
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
suspendUser (user, notes, category, force = false) {
|
|
90
|
+
var body = {
|
|
91
|
+
value: user,
|
|
92
|
+
reason: notes,
|
|
93
|
+
method: 'skynet-cli',
|
|
94
|
+
category: category,
|
|
95
|
+
force: force
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return this.request(`/suspend/user`, {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
body: qs.stringify(body)
|
|
101
|
+
})
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
unsuspendUser (user) {
|
|
105
|
+
return this.request(`/suspensions/user/${user}`, {
|
|
106
|
+
method: 'DELETE'
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
bulkSuspendUsers (users, notes, category) {
|
|
111
|
+
var body = {
|
|
112
|
+
value: users,
|
|
113
|
+
reason: notes,
|
|
114
|
+
method: 'skynet-cli',
|
|
115
|
+
category: category,
|
|
116
|
+
bulk: 'true'
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return this.request(`/suspend/user`, {
|
|
120
|
+
method: 'POST',
|
|
121
|
+
body: qs.stringify(body)
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
bulkSuspendAppOwner (apps, notes, category) {
|
|
126
|
+
var body = {
|
|
127
|
+
value: apps,
|
|
128
|
+
reason: notes,
|
|
129
|
+
method: 'skynet-cli',
|
|
130
|
+
category: category,
|
|
131
|
+
bulk: 'true'
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return this.request(`/suspend/app-owner`, {
|
|
135
|
+
method: 'POST',
|
|
136
|
+
body: qs.stringify(body)
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
deprovision (user, notes, category, force = false) {
|
|
141
|
+
var body = {
|
|
142
|
+
value: user,
|
|
143
|
+
reason: notes,
|
|
144
|
+
method: 'skynet-cli',
|
|
145
|
+
category: category,
|
|
146
|
+
force: force
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return this.request(`/deprovision`, {
|
|
150
|
+
method: 'POST',
|
|
151
|
+
body: qs.stringify(body)
|
|
152
|
+
})
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
bulkDeprovision (users, notes, category) {
|
|
156
|
+
var body = {
|
|
157
|
+
value: users,
|
|
158
|
+
reason: notes,
|
|
159
|
+
method: 'skynet-cli',
|
|
160
|
+
category: category,
|
|
161
|
+
bulk: 'true'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return this.request(`/deprovision`, {
|
|
165
|
+
method: 'POST',
|
|
166
|
+
body: qs.stringify(body)
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
}
|
package/lib/sudo.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@heroku/skynet",
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"description": "use Skynet from Heroku CLI",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"author": "Bob Argenbright @byt3smith",
|
|
7
|
+
"repository": "heroku/heroku-skynet-cli",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/heroku/heroku-skynet/issues"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"heroku-plugin"
|
|
13
|
+
],
|
|
14
|
+
"files": [
|
|
15
|
+
"/index.js",
|
|
16
|
+
"/lib",
|
|
17
|
+
"/commands"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"co": "^4.6.0",
|
|
21
|
+
"heroku-cli-util": "~6.2.12",
|
|
22
|
+
"split": "^1.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"mocha": "^3.4.2",
|
|
26
|
+
"mockdate": "^2.0.1",
|
|
27
|
+
"nock": "^9.0.13",
|
|
28
|
+
"standard": "^10.0.2",
|
|
29
|
+
"unexpected": "^10.29.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"test": "mocha && standard"
|
|
33
|
+
}
|
|
34
|
+
}
|