vgs-cli 0.0.1.dev0__py3-none-any.whl

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.
Files changed (56) hide show
  1. vgs_cli-0.0.1.dev0.data/data/vgscli/calm.yaml +16 -0
  2. vgs_cli-0.0.1.dev0.data/data/vgscli/checkout.yaml +21 -0
  3. vgs_cli-0.0.1.dev0.data/data/vgscli/http-route-template.yaml +61 -0
  4. vgs_cli-0.0.1.dev0.data/data/vgscli/mft-route-template.yaml +10 -0
  5. vgs_cli-0.0.1.dev0.data/data/vgscli/payments-admin.yaml +25 -0
  6. vgs_cli-0.0.1.dev0.data/data/vgscli/service-account-schema.yaml +54 -0
  7. vgs_cli-0.0.1.dev0.data/data/vgscli/sub-account-checkout.yaml +23 -0
  8. vgs_cli-0.0.1.dev0.data/data/vgscli/vault-resources.yaml +710 -0
  9. vgs_cli-0.0.1.dev0.data/data/vgscli/vault-schema.yaml +36 -0
  10. vgs_cli-0.0.1.dev0.data/data/vgscli/vault-template.yaml +12 -0
  11. vgs_cli-0.0.1.dev0.data/data/vgscli/vgs-cli.yaml +17 -0
  12. vgs_cli-0.0.1.dev0.dist-info/METADATA +139 -0
  13. vgs_cli-0.0.1.dev0.dist-info/RECORD +56 -0
  14. vgs_cli-0.0.1.dev0.dist-info/WHEEL +5 -0
  15. vgs_cli-0.0.1.dev0.dist-info/entry_points.txt +2 -0
  16. vgs_cli-0.0.1.dev0.dist-info/licenses/LICENSE +22 -0
  17. vgs_cli-0.0.1.dev0.dist-info/top_level.txt +1 -0
  18. vgscli/__init__.py +0 -0
  19. vgscli/_version.py +32 -0
  20. vgscli/access_logs.py +65 -0
  21. vgscli/audits_api.py +102 -0
  22. vgscli/auth.py +68 -0
  23. vgscli/auth_server.py +131 -0
  24. vgscli/auth_utils.py +24 -0
  25. vgscli/callback_server.py +41 -0
  26. vgscli/cert_manager_api.py +34 -0
  27. vgscli/cli/__init__.py +23 -0
  28. vgscli/cli/commands/__init__.py +3 -0
  29. vgscli/cli/commands/apply.py +307 -0
  30. vgscli/cli/commands/generate.py +134 -0
  31. vgscli/cli/commands/get.py +200 -0
  32. vgscli/cli/types/__init__.py +2 -0
  33. vgscli/cli/types/resource_id.py +39 -0
  34. vgscli/cli/types/variable.py +21 -0
  35. vgscli/cli_utils.py +132 -0
  36. vgscli/click_extensions.py +88 -0
  37. vgscli/config_file.py +58 -0
  38. vgscli/errors.py +263 -0
  39. vgscli/file_token_util.py +30 -0
  40. vgscli/id_generator.py +46 -0
  41. vgscli/keyring_token_util.py +128 -0
  42. vgscli/resource-templates/http-route-template.yaml +61 -0
  43. vgscli/resource-templates/mft-route-template.yaml +10 -0
  44. vgscli/resource-templates/service-account/calm.yaml +16 -0
  45. vgscli/resource-templates/service-account/checkout.yaml +21 -0
  46. vgscli/resource-templates/service-account/payments-admin.yaml +25 -0
  47. vgscli/resource-templates/service-account/sub-account-checkout.yaml +23 -0
  48. vgscli/resource-templates/service-account/vgs-cli.yaml +17 -0
  49. vgscli/resource-templates/vault-template.yaml +12 -0
  50. vgscli/testing.py +48 -0
  51. vgscli/text.py +9 -0
  52. vgscli/token_handler.py +11 -0
  53. vgscli/validation-schemas/service-account-schema.yaml +54 -0
  54. vgscli/validation-schemas/vault-resources.yaml +710 -0
  55. vgscli/validation-schemas/vault-schema.yaml +36 -0
  56. vgscli/vgs.py +249 -0
@@ -0,0 +1,36 @@
1
+ ---
2
+ "$schema": http://json-schema.org/draft-07/schema#
3
+ type: object
4
+ properties:
5
+ apiVersion:
6
+ type: string
7
+ enum:
8
+ - 1.0.0
9
+ kind:
10
+ type: string
11
+ enum:
12
+ - Vault
13
+ data:
14
+ type: object
15
+ properties:
16
+ name:
17
+ type: string
18
+ minLength: 3
19
+ maxLength: 50
20
+ environment:
21
+ type: string
22
+ enum:
23
+ - SANDBOX
24
+ - LIVE
25
+ organizationId:
26
+ type: string
27
+ pattern: ^AC[A-Za-z0-9]{22}$
28
+ required:
29
+ - name
30
+ - environment
31
+ additionalProperties: false
32
+ required:
33
+ - apiVersion
34
+ - kind
35
+ - data
36
+ additionalProperties: false
@@ -0,0 +1,12 @@
1
+ apiVersion: 1.0.0
2
+ kind: Vault
3
+ data:
4
+ # Name of the vault to create. (Must be between 3 and 50 characters long.)
5
+ name: Very Good Vault
6
+
7
+ # Environment to create the vault within.
8
+ # See https://www.verygoodsecurity.com/docs/terminology/vaults#environments
9
+ environment: SANDBOX
10
+
11
+ # ID of the organization to associate the vault with.
12
+ organizationId: AC6mGNNRecR7K5N7AjX5niz4
@@ -0,0 +1,17 @@
1
+ apiVersion: 1.0.0
2
+ kind: ServiceAccount
3
+ data:
4
+ name: vgs-cli
5
+ {%- if vaults | length == 0 %}
6
+ {{- cli_warn("Service Account won't have access to any vaults inside organization. If you need it to access vault(s) please use --vault <vault-identifier>.") or "" }}
7
+ {%- else %}
8
+ vaults:
9
+ {%- for vault_id in vaults %}
10
+ - {{ vault_id }}
11
+ {%- endfor %}
12
+ {%- endif %}
13
+ scopes:
14
+ - name: access-logs:read
15
+ - name: organizations:read
16
+ - name: routes:write
17
+ - name: vaults:write
@@ -0,0 +1,139 @@
1
+ Metadata-Version: 2.4
2
+ Name: vgs-cli
3
+ Version: 0.0.1.dev0
4
+ Summary: VGS Client
5
+ Home-page: https://github.com/verygoodsecurity/vgs-cli
6
+ Author: Very Good Security
7
+ Author-email: dev@verygoodsecurity.com
8
+ License: BSD
9
+ Platform: any
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: BSD License
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: base58<3,>=2.1.1
18
+ Requires-Dist: click-plugins<2,>=1.1.1
19
+ Requires-Dist: click<9,>=7
20
+ Requires-Dist: configobj-dev>=2019.9.1
21
+ Requires-Dist: cryptography>=44.0.1
22
+ Requires-Dist: jsonschema<5,>=3.2.0
23
+ Requires-Dist: keyring<26,>=16.1.0
24
+ Requires-Dist: keyrings.alt<6,>=3.1
25
+ Requires-Dist: pyhumps
26
+ Requires-Dist: semver<4,>=3
27
+ Requires-Dist: termcolor<3,>=2
28
+ Requires-Dist: Jinja2>=2.10
29
+ Requires-Dist: vgs-api-client<1,>=0.0.51
30
+ Requires-Dist: async-timeout
31
+ Requires-Dist: pip>=25.3
32
+ Dynamic: author
33
+ Dynamic: author-email
34
+ Dynamic: classifier
35
+ Dynamic: description
36
+ Dynamic: description-content-type
37
+ Dynamic: home-page
38
+ Dynamic: license
39
+ Dynamic: license-file
40
+ Dynamic: platform
41
+ Dynamic: requires-dist
42
+ Dynamic: summary
43
+
44
+ # VGS CLI
45
+
46
+ [![CircleCI](https://dl.circleci.com/status-badge/img/gh/verygoodsecurity/vgs-cli/tree/master.svg?style=svg&circle-token=6d4536882cc1d60a7ecf15cf4b4c93286abff2d8)](https://dl.circleci.com/status-badge/redirect/gh/verygoodsecurity/vgs-cli/tree/master)
47
+
48
+ Command Line Tool for programmatic configurations on VGS.
49
+
50
+ [Official Documentation](https://www.verygoodsecurity.com/docs/vgs-cli/getting-started)
51
+
52
+ ## Table of Contents
53
+
54
+ - [Requirements](#requirements)
55
+ - [Installation](#installation)
56
+ - [PyPI](#pypi)
57
+ - [Run](#run)
58
+ - [Running in Docker](#running-in-docker)
59
+ - [Commands](#commands)
60
+ - [Code Standards](#code-standards)
61
+ - [Automation with VGS CLI](#automation-with-vgs-cli)
62
+ - [Sphinx Documentation](#sphinx-documentation)
63
+ - [Plugins Development](#plugins-development)
64
+
65
+ ## Requirements
66
+ [Python 3](https://www.python.org/downloads/) or [Docker](https://docs.docker.com/get-docker/).
67
+
68
+ ## Installation
69
+
70
+ ### PyPI
71
+ Install the latest version from [PyPI](https://pypi.org/project/vgs-cli/):
72
+ ```
73
+ pip install vgs-cli
74
+ ```
75
+
76
+ ## Run
77
+
78
+ Verify your installation by running:
79
+ ```
80
+ vgs --version
81
+ ```
82
+
83
+ ## Running in Docker
84
+
85
+ Check our [official documentation](https://www.verygoodsecurity.com/docs/vgs-cli/docker).
86
+
87
+ ## Commands
88
+
89
+ - [`help`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#exploring-the-cli)
90
+ - [`login`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#login)
91
+ - [`logout`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#logout)
92
+ - [`routes get`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#get)
93
+ - [`routes apply`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#apply)
94
+ - [`logs access`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#access)
95
+ - [`access-credentials get`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#get)
96
+ - [`access-credentials generate`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#generate)
97
+ - [`organizations get`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#get)
98
+ - [`vaults get`](https://www.verygoodsecurity.com/docs/vgs-cli/commands#get)
99
+
100
+ ## Code Standards
101
+
102
+ We follow the defaults enforced by [Black](https://black.readthedocs.io/en/stable/) and [isort](https://pycqa.github.io/isort/) (with the Black profile). A formatting workflow runs in CI and installs `black`, `isort`, and `ruff`. Before opening a pull request, install the tools with `pip install black isort ruff` and run:
103
+
104
+ ```
105
+ black .
106
+ isort --profile black .
107
+ ruff check .
108
+ ```
109
+
110
+ ## Automation with VGS CLI
111
+
112
+ If you want to use the VGS CLI for automation you might be interested in creating a [service account](https://www.verygoodsecurity.com/docs/vgs-cli/service-account).
113
+
114
+ ## Plugins Development
115
+
116
+ See [Click - Developing Plugins](https://github.com/click-contrib/click-plugins#developing-plugins).
117
+
118
+ In order to develop a plugin you need to register your commands to an entrypoint in `setup.py`.
119
+
120
+ Supported entrypoints:
121
+
122
+ - `vgs.plugins` - for extending `vgs` with sub-commands
123
+ - `vgs.get.plugins` - for extending `vgs get` with sub-commands
124
+ - `vgs.apply.plugins` - for extending `vgs apply` with sub-commands
125
+ - `vgs.logs.plugins` - for extending `vgs logs` with sub-commands
126
+
127
+ Example:
128
+ ```python
129
+ entry_points='''
130
+ [vgs.plugins]
131
+ activate=vgscliplugin.myplugin:new_command
132
+
133
+ [vgs.get.plugins]
134
+ preferences=vgscliplugin.myplugin:new_get_command
135
+ '''
136
+ ```
137
+
138
+ ### Plugin catalog
139
+ - [vgs-cli-admin-plugin](https://github.com/verygoodsecurity/vgs-cli-admin-plugin)
@@ -0,0 +1,56 @@
1
+ vgs_cli-0.0.1.dev0.data/data/vgscli/calm.yaml,sha256=kkZKW_D2gQHq5uDRn2eS8AMMVfSRP72gDerDY5q4hQU,482
2
+ vgs_cli-0.0.1.dev0.data/data/vgscli/checkout.yaml,sha256=ig5MZXQFiAAsQcRpLhdoBM-6eWq7hhV69H3IkLntjwA,588
3
+ vgs_cli-0.0.1.dev0.data/data/vgscli/http-route-template.yaml,sha256=nIXh_oF0pirA_dtFeyO-SG4p72No9KE7J_ShqAb_HyM,1662
4
+ vgs_cli-0.0.1.dev0.data/data/vgscli/mft-route-template.yaml,sha256=3TwiVS6yDir3uc0g0G_p5Hj4Gje2aq8Zi6vnnRa4j5Q,142
5
+ vgs_cli-0.0.1.dev0.data/data/vgscli/payments-admin.yaml,sha256=hXLVSB-6QYuvCEa3ozUdw8LBClxjVMs7t5ZSXsSsHJg,733
6
+ vgs_cli-0.0.1.dev0.data/data/vgscli/service-account-schema.yaml,sha256=L1pjNXgnks15N1wNgf_1GmGcOvxn0nu49v7ersUjFno,1090
7
+ vgs_cli-0.0.1.dev0.data/data/vgscli/sub-account-checkout.yaml,sha256=pDl0BRa8TZowlOJ8exs8JC--6JW8NPY_UFzaKXdDXqc,662
8
+ vgs_cli-0.0.1.dev0.data/data/vgscli/vault-resources.yaml,sha256=oOdNs5yhfipKS3VMGMeewz49RHyE77pBnzW6fxVPOIk,26334
9
+ vgs_cli-0.0.1.dev0.data/data/vgscli/vault-schema.yaml,sha256=sNiIIyIQ_iwfW234dSzsolyN4MADZLtV2mkcoG2A8Rs,622
10
+ vgs_cli-0.0.1.dev0.data/data/vgscli/vault-template.yaml,sha256=IlDisL3H5LXUDMkhUaouKMarRdu0-pJxpTz8ij_lp_M,383
11
+ vgs_cli-0.0.1.dev0.data/data/vgscli/vgs-cli.yaml,sha256=qvRq9_rmg1Wp1w6bO0JAVZrJmeOcvmBfbdMY8OnKn4Q,498
12
+ vgs_cli-0.0.1.dev0.dist-info/licenses/LICENSE,sha256=NwSyzgDYdzv6O2ns2C6UODGI8LN1VnVe_FPTnWS4eXY,1082
13
+ vgscli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
+ vgscli/_version.py,sha256=voOYriGKhzp76O3vbl7xYBRZGbaFSxSBjgP5ksZuebg,812
15
+ vgscli/access_logs.py,sha256=G0GjlLjWiC-N6OzK6-RCvWddcVGQlLCLAcyO9pLWIOM,1928
16
+ vgscli/audits_api.py,sha256=6FjpS1yTALio-DejgIS2eDw75ChjDp4GoAGXh4uZExU,3211
17
+ vgscli/auth.py,sha256=vdUZ12nqtefIuSHNmwCFvxoqwS3m6ZP5TqLZFNwKnSU,2104
18
+ vgscli/auth_server.py,sha256=e-xYoVebWM6cQNxuMr5rYzKuswNIrexnLSYo1ma48WY,4096
19
+ vgscli/auth_utils.py,sha256=aC1VI0dFdFeupLS9Okz4uDz-wHhhFabqiLUg2R5vO2s,600
20
+ vgscli/callback_server.py,sha256=oFFF5AGbbwhF7Hsc5fzS7jeGFzIMbebc9Qdq8uEl1PY,1055
21
+ vgscli/cert_manager_api.py,sha256=uBrqbk5Qn7z1bSugSdCBHde6XksclNsW9358UDii2fc,1061
22
+ vgscli/cli_utils.py,sha256=NzXK29_yIDrB-3T_XdLLB8NCWneQ-cpZFi9mazQL9tQ,3810
23
+ vgscli/click_extensions.py,sha256=y59iSxnh-BW_GUyRoBmWeH6dsiyXf6WNr6OKea72Z-Q,2962
24
+ vgscli/config_file.py,sha256=HB8lANU0qoO09Wnkf-QDzPh2qtrnFcqcetnCaQgtQ3U,1543
25
+ vgscli/errors.py,sha256=rQ8M3MbtcirwE3vxICEekga_JqWeOvZbqReswiOEzv8,8682
26
+ vgscli/file_token_util.py,sha256=537b54paMGw0u5PL5VJgQqQ7awKa9lQP88n3tUc_lyw,771
27
+ vgscli/id_generator.py,sha256=3CbvSOUSyLON76p6M8wUhVQVig8j75_rnWdpxLhBifM,1510
28
+ vgscli/keyring_token_util.py,sha256=Meo1XxlSpIUjYF1TqKqWCUKiNaidroiavUAGPmWS254,4215
29
+ vgscli/testing.py,sha256=MLrsvy3mEwvjtqyuG0UjwEX-rDkbWUo52aXvu2H2sTk,1437
30
+ vgscli/text.py,sha256=c2d1As7awq8PlEF9NiI6JrjsYYousj9YT0o1xOQ2MQM,172
31
+ vgscli/token_handler.py,sha256=MvtmlicqnGrcopNkTr8Q2RlKE7IDj_sJFxF_39Jd7W8,183
32
+ vgscli/vgs.py,sha256=n2_to8Dcb2cetkI9hYyyRehAJx3EOttMNZgxlPUsSeI,7097
33
+ vgscli/cli/__init__.py,sha256=4g6-RMMhl907F-MegDac28V1y8fDVhLGp3Scz27afNo,628
34
+ vgscli/cli/commands/__init__.py,sha256=h9vpkJzjaRQVZ6eR3FkSXvAjiDvngbxYzMSA30tiBCM,77
35
+ vgscli/cli/commands/apply.py,sha256=b74CFIIZ6R8CPz08EAlSIje5vt1S2sVqbMrDG7Gn4rc,8968
36
+ vgscli/cli/commands/generate.py,sha256=CIEcLnH5hEBftKP9mMjYWLh4ZvblwKXLw13PH4w88zs,3674
37
+ vgscli/cli/commands/get.py,sha256=48Q2rfAi3A1zmalQ9eUXn1v8hXSNf9cJWSNyg96JNWk,5102
38
+ vgscli/cli/types/__init__.py,sha256=a-P-SoGHpLzMg7CL1hhg5x_nf6sHq0qAuGm_AtIITmw,107
39
+ vgscli/cli/types/resource_id.py,sha256=7JILR-KjoVGQDHB40tXJfTcU53iR8wM9Zr24fY5le3o,1172
40
+ vgscli/cli/types/variable.py,sha256=IVcszPoWmTjeo_evDsLN06LuUZGTLL-wcZCVfBNBP8I,414
41
+ vgscli/resource-templates/http-route-template.yaml,sha256=nIXh_oF0pirA_dtFeyO-SG4p72No9KE7J_ShqAb_HyM,1662
42
+ vgscli/resource-templates/mft-route-template.yaml,sha256=3TwiVS6yDir3uc0g0G_p5Hj4Gje2aq8Zi6vnnRa4j5Q,142
43
+ vgscli/resource-templates/vault-template.yaml,sha256=IlDisL3H5LXUDMkhUaouKMarRdu0-pJxpTz8ij_lp_M,383
44
+ vgscli/resource-templates/service-account/calm.yaml,sha256=kkZKW_D2gQHq5uDRn2eS8AMMVfSRP72gDerDY5q4hQU,482
45
+ vgscli/resource-templates/service-account/checkout.yaml,sha256=ig5MZXQFiAAsQcRpLhdoBM-6eWq7hhV69H3IkLntjwA,588
46
+ vgscli/resource-templates/service-account/payments-admin.yaml,sha256=hXLVSB-6QYuvCEa3ozUdw8LBClxjVMs7t5ZSXsSsHJg,733
47
+ vgscli/resource-templates/service-account/sub-account-checkout.yaml,sha256=pDl0BRa8TZowlOJ8exs8JC--6JW8NPY_UFzaKXdDXqc,662
48
+ vgscli/resource-templates/service-account/vgs-cli.yaml,sha256=qvRq9_rmg1Wp1w6bO0JAVZrJmeOcvmBfbdMY8OnKn4Q,498
49
+ vgscli/validation-schemas/service-account-schema.yaml,sha256=L1pjNXgnks15N1wNgf_1GmGcOvxn0nu49v7ersUjFno,1090
50
+ vgscli/validation-schemas/vault-resources.yaml,sha256=oOdNs5yhfipKS3VMGMeewz49RHyE77pBnzW6fxVPOIk,26334
51
+ vgscli/validation-schemas/vault-schema.yaml,sha256=sNiIIyIQ_iwfW234dSzsolyN4MADZLtV2mkcoG2A8Rs,622
52
+ vgs_cli-0.0.1.dev0.dist-info/METADATA,sha256=iH5mcBiJXL7iEpZjPE3fGnjMbL_NKliqjqlO8fTQtd0,4684
53
+ vgs_cli-0.0.1.dev0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
54
+ vgs_cli-0.0.1.dev0.dist-info/entry_points.txt,sha256=wCWhRQiMX4Ja6kkqJlYr8LbuiywpmXyyRAZPsau-_RY,39
55
+ vgs_cli-0.0.1.dev0.dist-info/top_level.txt,sha256=gabTxCWMkl80q6ha_m-hs_1wQMfGntZcv5DEmkl8JEw,7
56
+ vgs_cli-0.0.1.dev0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vgs = vgscli.vgs:cli
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 Very Good Security, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1 @@
1
+ vgscli
vgscli/__init__.py ADDED
File without changes
vgscli/_version.py ADDED
@@ -0,0 +1,32 @@
1
+ from typing import Optional
2
+
3
+ import click
4
+ import requests
5
+ from semver import VersionInfo
6
+
7
+ from vgscli.text import bold, green
8
+
9
+ __version__ = "0.0.1-dev"
10
+
11
+
12
+ # noinspection PyBroadException
13
+ def get_latest_version(**kwargs) -> Optional[VersionInfo]:
14
+ try:
15
+ response_json = requests.get(
16
+ "https://pypi.org/pypi/vgs-cli/json", **kwargs
17
+ ).json()
18
+ return VersionInfo.parse(response_json["info"]["version"])
19
+ except Exception:
20
+ return None
21
+
22
+
23
+ def check_for_updates() -> None:
24
+ latest_version = get_latest_version(timeout=2)
25
+
26
+ if latest_version and latest_version > __version__:
27
+ message = f"CLI update available from {bold(green(__version__))} to {bold(green(str(latest_version)))}."
28
+ click.echo(message, err=True)
29
+
30
+
31
+ def version():
32
+ return __version__
vgscli/access_logs.py ADDED
@@ -0,0 +1,65 @@
1
+ import math
2
+
3
+
4
+ def calculate_start_page(total_records, tail, records_per_page):
5
+ if tail > total_records or total_records <= records_per_page:
6
+ return 1
7
+ total_pages_num = math.ceil(total_records / records_per_page)
8
+ tail_pages_num = math.ceil(
9
+ (tail - total_records % records_per_page) / records_per_page
10
+ )
11
+ return total_pages_num - tail_pages_num
12
+
13
+
14
+ def calculate_start_index(total_records, tail, records_per_page):
15
+ if tail > total_records:
16
+ return 0
17
+ offset_total = total_records % records_per_page
18
+ offset_tail = tail % records_per_page
19
+ return offset_total - offset_tail
20
+
21
+
22
+ def fetch_logs(api, params, tail):
23
+ records_per_page = 30
24
+ count = 0
25
+ current_page = 1
26
+ start_page = None
27
+
28
+ params["sort"] = "occurred_at"
29
+
30
+ while True:
31
+ params["page[number]"] = current_page
32
+ result = api.access_logs.list(params=params)
33
+ page_data = result.body["data"]
34
+
35
+ if tail:
36
+ if not start_page:
37
+ start_page = calculate_start_page(
38
+ result.body["meta"]["count"], tail, records_per_page
39
+ )
40
+ current_page = start_page
41
+ if start_page != 1:
42
+ continue
43
+
44
+ if current_page == start_page:
45
+ start_index = calculate_start_index(
46
+ result.body["meta"]["count"], tail, records_per_page
47
+ )
48
+ page_data = page_data[start_index:]
49
+ elif tail - count < records_per_page:
50
+ page_data = page_data[: (tail - count)]
51
+
52
+ yield page_data
53
+
54
+ count += len(page_data)
55
+ current_page += 1
56
+
57
+ if not result.body["links"].get("next") or (tail and tail <= count):
58
+ break
59
+
60
+
61
+ def prepare_filter(filter_options):
62
+ result = {}
63
+ for pair in filter_options.items():
64
+ result["filter[{}]".format(pair[0])] = pair[1]
65
+ return result
vgscli/audits_api.py ADDED
@@ -0,0 +1,102 @@
1
+ import logging
2
+ from copy import deepcopy
3
+ from typing import Dict
4
+
5
+ from simple_rest_client.api import API
6
+ from simple_rest_client.resource import Resource
7
+
8
+ from vgscli._version import __version__
9
+ from vgscli.errors import VaultNotFoundError
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ env_url = {
14
+ "dev": "https://audits.verygoodsecurity.io",
15
+ "prod": "https://audits.apps.verygood.systems",
16
+ }
17
+
18
+
19
+ class AccessLogsResource(Resource):
20
+ actions = {
21
+ "retrieve": {"method": "GET", "url": "access-logs/{}"},
22
+ "list": {"method": "GET", "url": "access-logs"},
23
+ }
24
+
25
+
26
+ class OperationsLogsResource(Resource):
27
+ actions = {
28
+ "list": {"method": "GET", "url": "op-pipeline-logs"},
29
+ }
30
+
31
+
32
+ class OperationLogsQueryConfig:
33
+
34
+ TENANT_ID_KEY = "filter[tenant_id]"
35
+ TRACE_ID_KEY = "filter[trace_id]"
36
+
37
+ PAGE_SIZE_KEY = "page[size]"
38
+
39
+ def __init__(self, tenant_id: str, trace_id: str, page_size: int = 1000):
40
+ self._configs: Dict[str, str] = {
41
+ OperationLogsQueryConfig.TENANT_ID_KEY: tenant_id,
42
+ OperationLogsQueryConfig.PAGE_SIZE_KEY: page_size,
43
+ OperationLogsQueryConfig.TRACE_ID_KEY: trace_id,
44
+ }
45
+
46
+ def to_query_params(self):
47
+ return deepcopy({k: v for k, v in self._configs.items() if v is not None})
48
+
49
+ @property
50
+ def tenant_id(self):
51
+ return self._configs.get(OperationLogsQueryConfig.TENANT_ID_KEY)
52
+
53
+ @tenant_id.setter
54
+ def tenant_id(self, value: str):
55
+ self._configs[OperationLogsQueryConfig.TENANT_ID_KEY] = value
56
+
57
+ @property
58
+ def page_size(self):
59
+ return self._configs.get(OperationLogsQueryConfig.PAGE_SIZE_KEY)
60
+
61
+ @page_size.setter
62
+ def page_size(self, value: str):
63
+ self._configs[OperationLogsQueryConfig.PAGE_SIZE_KEY] = value
64
+
65
+ @property
66
+ def trace_id(self):
67
+ return self._configs.get(OperationLogsQueryConfig.TRACE_ID_KEY)
68
+
69
+ @page_size.setter
70
+ def trace_id(self, value: str):
71
+ self._configs[OperationLogsQueryConfig.TRACE_ID_KEY] = value
72
+
73
+
74
+ def create_api(ctx, vault_id, environment, token):
75
+ api = API(
76
+ api_root_url=env_url[environment],
77
+ params={}, # default params
78
+ headers={
79
+ "VGS-Tenant": vault_id,
80
+ "Content-Type": "application/vnd.api+json",
81
+ "Accept": "application/vnd.api+json",
82
+ "User-Agent": "VGS CLI {}".format(__version__),
83
+ "Authorization": "Bearer {}".format(token),
84
+ }, # default headers
85
+ timeout=50, # default timeout in seconds
86
+ append_slash=False, # append slash to final url
87
+ json_encode_body=True, # encode body as json
88
+ )
89
+ api.add_resource(resource_name="access_logs", resource_class=AccessLogsResource)
90
+ api.add_resource(
91
+ resource_name="operations_logs", resource_class=OperationsLogsResource
92
+ )
93
+ return api
94
+
95
+
96
+ def get_api_url(ctx, vault_id, api):
97
+ response = api.accounts_api.get_vault_by_id(vault_id)
98
+ try:
99
+ return response.body["data"][0]["links"]["vault_management_api"]
100
+ except (KeyError, IndexError):
101
+ # if we weren't able to extract the vault_management_api it means that the provided vault_id doesn't exist
102
+ raise VaultNotFoundError(vault_id, ctx)
vgscli/auth.py ADDED
@@ -0,0 +1,68 @@
1
+ import click
2
+ from simple_rest_client.exceptions import ClientError
3
+
4
+ from vgscli.auth_server import AuthServer
5
+ from vgscli.errors import (
6
+ AuthenticationError,
7
+ AuthenticationRequiredError,
8
+ ClientCredentialsAuthenticationError,
9
+ TokenNotValidError,
10
+ )
11
+ from vgscli.keyring_token_util import KeyringTokenUtil
12
+
13
+ token_util = KeyringTokenUtil()
14
+ TOKEN_FILE_NAME = "vgs_token"
15
+
16
+
17
+ def handshake(ctx, environment):
18
+ try:
19
+ if not token_util.validate_access_token():
20
+ token_util.validate_refresh_token()
21
+ AuthServer(environment).refresh_authentication()
22
+ except ClientError as e:
23
+ if (
24
+ e.response.body
25
+ and e.response.body.get("error_description") == "Invalid refresh token"
26
+ ):
27
+ raise AuthenticationRequiredError(ctx)
28
+ else:
29
+ raise AuthenticationError(ctx, e.args[0])
30
+ except TokenNotValidError:
31
+ raise AuthenticationRequiredError(ctx)
32
+ except Exception as e:
33
+ raise AuthenticationError(ctx, e.args[0])
34
+
35
+
36
+ def login(ctx, environment, **kwargs):
37
+ try:
38
+ access_token = AuthServer(environment).login(environment, **kwargs)
39
+ click.echo("Success!")
40
+ return access_token
41
+ except Exception as e:
42
+ raise AuthenticationError(ctx, e.args[0])
43
+
44
+
45
+ def logout(ctx, environment):
46
+ try:
47
+ if token_util.tokens_exist():
48
+ AuthServer(environment).logout()
49
+ token_util.clear_tokens()
50
+ token_util.remove_encryption_secret()
51
+ click.echo("Success!")
52
+ else:
53
+ click.echo("Login data not found.")
54
+ except Exception as e:
55
+ raise AuthenticationError(ctx, e.args[0])
56
+
57
+
58
+ def client_credentials_login(ctx, client_id, client_secret, environment):
59
+ try:
60
+ if (
61
+ not token_util.is_access_token_valid()
62
+ or token_util.is_access_token_azp_changed(client_id)
63
+ ):
64
+ AuthServer(environment).client_credentials_login(client_id, client_secret)
65
+ except (TokenNotValidError, ClientError):
66
+ raise ClientCredentialsAuthenticationError(ctx)
67
+
68
+ return True