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
vgscli/errors.py ADDED
@@ -0,0 +1,263 @@
1
+ import traceback
2
+ import types
3
+ from functools import wraps
4
+
5
+ import click
6
+ from click import Context, UsageError
7
+ from click.exceptions import Abort, Exit
8
+ from simple_rest_client import exceptions
9
+
10
+
11
+ def is_debug(ctx) -> bool:
12
+ return bool(
13
+ getattr(ctx, "obj", None) and getattr(getattr(ctx, "obj", None), "debug", False)
14
+ )
15
+
16
+
17
+ def get_error_details(e):
18
+ resp = getattr(e, "response", None)
19
+ body = getattr(resp, "body", None)
20
+ if isinstance(body, dict) and body.get("errors"):
21
+ return [x.get("detail") for x in body["errors"] if isinstance(x, dict)]
22
+ return None
23
+
24
+
25
+ class VgsCliError(UsageError):
26
+ def __init__(self, message, ctx=None):
27
+ self.message = message
28
+ self.ctx = ctx
29
+
30
+ def show(self, file=None):
31
+ self.show_message()
32
+
33
+ def show_message(self):
34
+ debug = is_debug(self.ctx)
35
+ if debug:
36
+ click.echo(traceback.format_exc(), err=True)
37
+ click.echo(self.message, err=True)
38
+
39
+
40
+ class VaultNotFoundError(VgsCliError):
41
+ def __init__(self, vault_id, ctx=None):
42
+ self.message = "Vault " + vault_id + " doesn't exist."
43
+ self.ctx = ctx
44
+
45
+
46
+ class TokenNotValidError(VgsCliError):
47
+ def __init__(self, message=None, ctx=None):
48
+ self.message = (
49
+ message or "Please run `vgs login` because your session has been expired."
50
+ )
51
+ self.ctx = ctx
52
+
53
+
54
+ class AuthenticationRequiredError(VgsCliError):
55
+ def __init__(self, ctx=None):
56
+ self.message = "Please run `vgs login` because your session has been expired."
57
+ self.ctx = ctx
58
+
59
+
60
+ class AuthenticationError(VgsCliError):
61
+ def __init__(self, ctx=None, details=None):
62
+ debug = is_debug(ctx)
63
+ self.message = (
64
+ "Authentication error occurred"
65
+ if debug
66
+ else "Authentication error occurred."
67
+ )
68
+ if details:
69
+ self.message = "{message} {details}".format(
70
+ message=self.message, details=details
71
+ )
72
+ self.ctx = ctx
73
+
74
+
75
+ class ClientCredentialsAuthenticationError(VgsCliError):
76
+ def __init__(self, ctx=None):
77
+ debug = is_debug(ctx)
78
+ self.message = (
79
+ """Authentication error occurred.
80
+
81
+ NOTE: You may see this error if you're using an account with enabled OTP.
82
+ Auto login via environment variables with OTP is not supported.
83
+ """
84
+ if debug
85
+ else """Authentication error occurred. (Run with --debug for a traceback.)
86
+
87
+ NOTE: You may see this error if you're using an account with enabled OTP.
88
+ Auto login via environment variables with OTP is not supported.
89
+ """
90
+ )
91
+ self.ctx = ctx
92
+
93
+
94
+ class ApiError(VgsCliError):
95
+ def __init__(self, e, ctx=None):
96
+ details = get_error_details(e)
97
+ debug = is_debug(ctx)
98
+ if details:
99
+ self.message = f"API error occurred: {details}"
100
+ elif debug:
101
+ self.message = "API error occurred."
102
+ else:
103
+ self.message = "API error occurred. (Run with --debug for a traceback.)"
104
+ self.ctx = ctx
105
+
106
+
107
+ class UnhandledError(VgsCliError):
108
+ def __init__(self, ctx=None):
109
+ debug = is_debug(ctx)
110
+ self.message = (
111
+ "An unexpected error occurred."
112
+ if debug
113
+ else "An unexpected error occurred. (Run with --debug for a traceback.)"
114
+ )
115
+ self.ctx = ctx
116
+
117
+
118
+ class RouteNotValidError(VgsCliError):
119
+ def __init__(self, error_message: str, ctx=None):
120
+ debug = is_debug(ctx)
121
+ error_message = f"Route cannot be applied due to errors:\n{error_message}"
122
+ self.message = (
123
+ error_message
124
+ if debug
125
+ else f"{error_message} (Run with --debug for a traceback.)"
126
+ )
127
+ self.ctx = ctx
128
+
129
+
130
+ class SchemaValidationError(VgsCliError):
131
+ def __init__(self, message, ctx=None):
132
+ self.message = f"Error during validation of the file input: {message}."
133
+ self.ctx = ctx
134
+
135
+
136
+ class ServiceClientCreationError(VgsCliError):
137
+ def __init__(self, e, ctx=None):
138
+ details = get_error_details(e)
139
+ self.message = f"Service Account creation failed with error: {details}"
140
+ self.ctx = ctx
141
+
142
+
143
+ class ServiceClientDeletionError(VgsCliError):
144
+ def __init__(self, e, ctx=None):
145
+ details = get_error_details(e)
146
+ self.message = f"Service Account deletion failed with error: {details}"
147
+ self.ctx = ctx
148
+
149
+
150
+ class ServiceClientListingError(VgsCliError):
151
+ def __init__(self, e, ctx=None):
152
+ details = get_error_details(e)
153
+ self.message = f"Service Account listing failed with error: {details}"
154
+ self.ctx = ctx
155
+
156
+
157
+ class NoSuchFileOrDirectoryError(VgsCliError):
158
+ def __init__(self, message, ctx=None):
159
+ self.message = f"No such file or directory: {message}"
160
+ self.ctx = ctx
161
+
162
+
163
+ class InsufficientPermissionsError(VgsCliError):
164
+ def __init__(self, ctx=None):
165
+ self.message = (
166
+ "You don't have enough permissions to perform this operation. Please contact "
167
+ "support@verygoodsecurity.com. "
168
+ )
169
+ self.ctx = ctx
170
+
171
+
172
+ class PermissionDeniedError(VgsCliError):
173
+ def __init__(self, ctx=None):
174
+ self.message = "You don't have enough permissions to the requested resource"
175
+ self.ctx = ctx
176
+
177
+
178
+ class MaxNumberOfCredentialsExceededError(VgsCliError):
179
+ def __init__(self, ctx=None):
180
+ self.message = (
181
+ "Maximum number of access credentials (10 per vault) reached.. Please contact "
182
+ "support@verygoodsecurity.com to increase the limit. "
183
+ )
184
+ self.ctx = ctx
185
+
186
+
187
+ def status_code_error(**kwargs):
188
+ def init(self, e, ctx=None):
189
+ status = getattr(getattr(e, "response", None), "status_code", None)
190
+ error_handler = kwargs.get(f"e{status}")
191
+ if error_handler:
192
+ self.message = (
193
+ error_handler(e)
194
+ if isinstance(error_handler, types.FunctionType)
195
+ else error_handler
196
+ )
197
+ self.ctx = ctx
198
+ else:
199
+ ApiError.__init__(self, e, ctx=ctx)
200
+
201
+ return type(
202
+ "StatusCodeError",
203
+ (ApiError,),
204
+ {"__init__": init},
205
+ )
206
+
207
+
208
+ def handle_errors(**outer_kwargs):
209
+ def decorator_handle_errors(f):
210
+ @wraps(f)
211
+ def wrapper(*args, **kwargs):
212
+ try:
213
+ return f(*args, **kwargs)
214
+ except (Abort, Exit):
215
+ raise
216
+ except exceptions.ClientError as e:
217
+ ctx = args[0] if args and isinstance(args[0], Context) else None
218
+ if ctx:
219
+ status = getattr(getattr(e, "response", None), "status_code", None)
220
+ if status == 401:
221
+ raise outer_kwargs.get(
222
+ "TokenNotValidError", TokenNotValidError
223
+ )(ctx=ctx)
224
+ if status == 403:
225
+ body = getattr(getattr(e, "response", None), "body", None)
226
+ errors = body.get("errors") if isinstance(body, dict) else None
227
+ detail = (
228
+ (
229
+ errors
230
+ and isinstance(errors, list)
231
+ and errors
232
+ and errors[0].get("detail")
233
+ )
234
+ if errors
235
+ else None
236
+ )
237
+ if detail and "Maximum number of access credentials" in detail:
238
+ raise outer_kwargs.get(
239
+ "MaxNumberOfCredentialsExceededError",
240
+ MaxNumberOfCredentialsExceededError,
241
+ )(ctx=ctx)
242
+ if errors:
243
+ raise outer_kwargs.get(
244
+ "InsufficientPermissionsError",
245
+ InsufficientPermissionsError,
246
+ )(ctx=ctx)
247
+ raise outer_kwargs.get(
248
+ "PermissionDeniedError", PermissionDeniedError
249
+ )(ctx=ctx)
250
+ raise outer_kwargs.get("ApiError", ApiError)(e, ctx=ctx)
251
+ # No click.Context available; re-raise original error
252
+ raise
253
+ except (VgsCliError, click.BadParameter, click.BadArgumentUsage):
254
+ raise
255
+ except Exception:
256
+ ctx = args[0] if args and isinstance(args[0], Context) else None
257
+ if ctx:
258
+ raise UnhandledError(ctx=ctx)
259
+ raise
260
+
261
+ return wrapper
262
+
263
+ return decorator_handle_errors
@@ -0,0 +1,30 @@
1
+ import os
2
+ import tempfile
3
+
4
+ import click
5
+ from vgs.sdk.utils import is_file_accessible
6
+
7
+
8
+ class FileTokenUtil:
9
+ def __init__(self, token_file_name):
10
+ temp_dir = tempfile.gettempdir()
11
+ self.temp_file = os.path.join(temp_dir, token_file_name)
12
+
13
+ @property
14
+ def exists(self):
15
+ return os.path.exists(self.temp_file)
16
+
17
+ def read_token(self):
18
+ with open(self.temp_file, "r+") as tmp:
19
+ return tmp.read()
20
+
21
+ def write_token(self, token):
22
+ with open(self.temp_file, "w+") as tmp:
23
+ tmp.write(token)
24
+ return token
25
+
26
+ def remove_token(self):
27
+ if is_file_accessible(self.temp_file, "r+"):
28
+ os.remove(self.temp_file)
29
+ else:
30
+ click.echo("No authenticated session", err=True)
vgscli/id_generator.py ADDED
@@ -0,0 +1,46 @@
1
+ from typing import (
2
+ Optional,
3
+ Union,
4
+ )
5
+ from uuid import UUID
6
+
7
+ import base58
8
+
9
+ BASE58_ALPHABET = b"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"
10
+
11
+
12
+ def base58_to_uuid(public_id: str, prefix: Optional[str] = None) -> str:
13
+ """
14
+ >>> base58_to_uuid('fBpkbaCp2dqfowSaRDL3g7')
15
+ '765159e7-750c-4b0b-8be0-a07fbc8f3ac4'
16
+ >>> base58_to_uuid('ACgwBwv1PeYLXpxsMyrSKYbw', 'AC')
17
+ '7dbf495e-254b-4e76-aaab-1bb5b726a53a'
18
+ >>> base58_to_uuid('bPpQJd2cwkVewGNBtCYMC')
19
+ '0182a7e1-d2e9-48dc-805b-d79156802ce6'
20
+ >>> base58_to_uuid('3iEhRdf9YZCNViqA1FRU6')
21
+ '00525efa-b7f3-41c4-b315-8d1836c9ec89'
22
+ """
23
+ prefix = prefix or ""
24
+ return str(
25
+ UUID(
26
+ int=base58.b58decode_int(public_id[len(prefix) :], alphabet=BASE58_ALPHABET)
27
+ )
28
+ )
29
+
30
+
31
+ def uuid_to_base58(internal_id: Union[UUID, str], prefix: Optional[str] = None) -> str:
32
+ """
33
+ >>> uuid_to_base58('765159e7-750c-4b0b-8be0-a07fbc8f3ac4', 'GR')
34
+ 'GRfBpkbaCp2dqfowSaRDL3g7'
35
+ >>> uuid_to_base58('7dbf495e-254b-4e76-aaab-1bb5b726a53a')
36
+ 'gwBwv1PeYLXpxsMyrSKYbw'
37
+ >>> uuid_to_base58('0182a7e1-d2e9-48dc-805b-d79156802ce6', 'GR')
38
+ 'GRbPpQJd2cwkVewGNBtCYMC'
39
+ >>> uuid_to_base58('00525efa-b7f3-41c4-b315-8d1836c9ec89', 'GR')
40
+ 'GR3iEhRdf9YZCNViqA1FRU6'
41
+ """
42
+ prefix = prefix or ""
43
+ uuid = internal_id if isinstance(internal_id, UUID) else UUID(hex=internal_id)
44
+ encoded = base58.b58encode_int(uuid.int, alphabet=BASE58_ALPHABET)
45
+
46
+ return f"{prefix}{encoded.decode()}"
@@ -0,0 +1,128 @@
1
+ import jwt
2
+ import keyring
3
+ from cryptography.fernet import Fernet
4
+ from keyring.errors import PasswordDeleteError
5
+ from vgs.sdk.utils import expired
6
+
7
+ from vgscli.errors import TokenNotValidError
8
+ from vgscli.file_token_util import FileTokenUtil
9
+
10
+
11
+ class KeyringTokenUtil:
12
+ SERVICE_NAME = "vgs-cli"
13
+
14
+ ACCESS_TOKEN_KEY = "access_token"
15
+ REFRESH_TOKEN_KEY = "refresh_token"
16
+ ENCRYPT_TOKEN_SECRET_KEY = "vgs_encrypt_secret_key"
17
+
18
+ access_token_file = FileTokenUtil("vgs_access_token")
19
+ refresh_token_file = FileTokenUtil("vgs_refresh_token")
20
+
21
+ def put_encryption_secret(self, secret):
22
+ keyring.set_password(self.SERVICE_NAME, self.ENCRYPT_TOKEN_SECRET_KEY, secret)
23
+
24
+ def get_encryption_secret(self):
25
+ return keyring.get_credential(self.SERVICE_NAME, self.ENCRYPT_TOKEN_SECRET_KEY)
26
+
27
+ def remove_encryption_secret(self):
28
+ try:
29
+ keyring.delete_password(self.SERVICE_NAME, self.ENCRYPT_TOKEN_SECRET_KEY)
30
+ except PasswordDeleteError:
31
+ pass
32
+
33
+ def tokens_exist(self):
34
+ return self.access_token_file.exists and self.refresh_token_file.exists
35
+
36
+ def clear_tokens(self):
37
+ self.delete_access_token()
38
+ self.delete_refresh_token()
39
+
40
+ def validate_access_token(self):
41
+ if self.get_access_token():
42
+ token_json = jwt.decode(
43
+ self.get_access_token(), options={"verify_signature": False}
44
+ )
45
+ return not expired(token_json["exp"])
46
+ else:
47
+ raise TokenNotValidError("Access token not found")
48
+
49
+ def validate_refresh_token(self):
50
+ if self.get_refresh_token():
51
+ token_json = jwt.decode(
52
+ self.get_refresh_token(), options={"verify_signature": False}
53
+ )
54
+ if expired(token_json["exp"]):
55
+ raise TokenNotValidError("Refresh token expired")
56
+ else:
57
+ raise TokenNotValidError("Refresh token not found")
58
+
59
+ def is_access_token_valid(self) -> bool:
60
+ try:
61
+ return self.validate_access_token()
62
+ except TokenNotValidError:
63
+ return False
64
+
65
+ def is_access_token_azp_changed(self, azp) -> bool:
66
+ return (
67
+ jwt.decode(
68
+ self.get_access_token(), options={"verify_signature": False}
69
+ ).get("azp")
70
+ != azp
71
+ )
72
+
73
+ def put_tokens(self, response):
74
+ key = Fernet.generate_key()
75
+ cipher = Fernet(key)
76
+ self.remove_encryption_secret()
77
+ self.put_encryption_secret(str(key, "utf-8"))
78
+ self.access_token_file.write_token(
79
+ str(cipher.encrypt(response[self.ACCESS_TOKEN_KEY].encode()), "utf-8")
80
+ )
81
+
82
+ # https://datatracker.ietf.org/doc/html/rfc6749#section-4.4.3
83
+ if self.REFRESH_TOKEN_KEY in response:
84
+ self.refresh_token_file.write_token(
85
+ str(cipher.encrypt(response[self.REFRESH_TOKEN_KEY].encode()), "utf-8")
86
+ )
87
+
88
+ def put_access_token(self, token):
89
+ self.access_token_file.write_token(
90
+ str(self.fernet.encrypt(token.encode()), "utf-8")
91
+ )
92
+
93
+ def get_access_token(self):
94
+ try:
95
+ return str(
96
+ self.fernet.decrypt(self.access_token_file.read_token().encode()),
97
+ "utf-8",
98
+ )
99
+ except FileNotFoundError:
100
+ raise TokenNotValidError("Access token not found")
101
+
102
+ def delete_access_token(self):
103
+ self.access_token_file.remove_token()
104
+
105
+ def put_refresh_token(self, token):
106
+ self.refresh_token_file.write_token(
107
+ str(self.fernet.encrypt(token.encode()), "utf-8")
108
+ )
109
+
110
+ def get_refresh_token(self):
111
+ try:
112
+ return str(
113
+ self.fernet.decrypt(self.refresh_token_file.read_token().encode()),
114
+ "utf-8",
115
+ )
116
+ except FileNotFoundError:
117
+ raise TokenNotValidError("Refresh token not found")
118
+
119
+ def delete_refresh_token(self):
120
+ self.refresh_token_file.remove_token()
121
+
122
+ @property
123
+ def fernet(self):
124
+ secret = self.get_encryption_secret()
125
+ if not secret:
126
+ raise FileNotFoundError("Can't find secret in keystore")
127
+
128
+ return Fernet(secret.password.encode())
@@ -0,0 +1,61 @@
1
+ apiVersion: vault.vgs.io/v1
2
+ kind: HttpRoute
3
+ metadata:
4
+ name: your-name-here
5
+ labels:
6
+ vgs.io/vaultId: your-vault-id-here
7
+ spec:
8
+ # TODO: Change this ID
9
+ id: &routeId 7478d3b7-beef-cafe-0000-000000000000
10
+ type: rule_chain
11
+ attributes:
12
+ id: *routeId
13
+ host_endpoint: httpbin.org
14
+ destination_override_endpoint: '*'
15
+ ordinal: 0
16
+ port: 0
17
+ protocol: http
18
+ source_endpoint: '*'
19
+ tags:
20
+ # TODO: add a good name
21
+ name: Display name of route here
22
+ # TODO: add version here
23
+ vgs.io/version: 0.1.0
24
+ # filters
25
+ entries:
26
+ # first filter - document here what it does
27
+ - classifiers: {}
28
+ config:
29
+ condition: OR
30
+ rules:
31
+ - expression:
32
+ field: PathInfo
33
+ operator: matches
34
+ type: string
35
+ values:
36
+ - /post
37
+ id: 955834e8-beef-cafe-0000-000000000000
38
+ id_selector: null
39
+ operation: ENRICH
40
+ operations:
41
+ - name: github.com/verygoodsecurity/common/compute/larky/http/Process
42
+ parameters:
43
+ script: |
44
+ load('@stdlib//json', 'json')
45
+ load("@stdlib//builtins", "builtins")
46
+
47
+ load("@vgs//vault", "vault")
48
+
49
+ def process(input, ctx):
50
+ # TODO: write your larky code here.
51
+
52
+ return input
53
+ phase: REQUEST
54
+ public_token_generator: UUID
55
+ targets:
56
+ - body
57
+ token_manager: PERSISTENT
58
+ transformer: JSON_PATH
59
+ transformer_config:
60
+ - $.whatever_this_field_is_unused
61
+ transformer_config_map: null
@@ -0,0 +1,10 @@
1
+ ---
2
+ apiVersion: mft.vgs.io/v1beta
3
+ kind: MftRoute
4
+ metadata:
5
+ name: my-mft-route
6
+ id: foo
7
+ spec:
8
+ source: foo
9
+ destination: bar
10
+ filters: []
@@ -0,0 +1,16 @@
1
+ apiVersion: 1.0.0
2
+ kind: ServiceAccount
3
+ data:
4
+ name: calm
5
+ {%- if vaults | length == 0 %}
6
+ {{ cli_fail("This template needs single vault to be specified. Please use '--vault <vault-identifier>' to pass the vault.") }}
7
+ {% elif vaults | length == 1 %}
8
+ vaults:
9
+ - {{ vaults[0] }}
10
+ {%- else %}
11
+ {{ cli_fail("This template doesn't allow multiple vaults.") }}
12
+ {% endif %}
13
+ scopes:
14
+ - name: cards:write
15
+ - name: network-tokens:write
16
+ - name: merchants:write
@@ -0,0 +1,21 @@
1
+ apiVersion: 1.0.0
2
+ kind: ServiceAccount
3
+ data:
4
+ name: {{ name }}
5
+ {%- if vaults | length == 0 %}
6
+ {{ cli_fail("This template needs single vault to be specified. Please use '--vault <vault-identifier>' to pass the vault.") }}
7
+ {% elif vaults | length == 1 %}
8
+ vaults:
9
+ - {{ vaults[0] }}
10
+ {%- else %}
11
+ {{ cli_fail("This template doesn't allow multiple vaults.") }}
12
+ {% endif %}
13
+ scopes:
14
+ - name: financial-instruments:write
15
+ optional: true
16
+ - name: transfers:write
17
+ optional: true
18
+ - name: orders:write
19
+ optional: true
20
+
21
+ accessTokenLifespan: 28800
@@ -0,0 +1,25 @@
1
+ apiVersion: 1.0.0
2
+ kind: ServiceAccount
3
+ data:
4
+ {%- if vaults | length == 0 %}
5
+ {{ cli_fail("This template needs single vault to be specified. Please use '--vault <vault-identifier>' to pass the vault.") }}
6
+ {%- elif vaults | length == 1 %}
7
+ name: payments-{{ vaults[0] }}
8
+ vaults:
9
+ - {{ vaults[0] }}
10
+ {%- else %}
11
+ {{ cli_fail("This template doesn't allow multiple vaults.") }}
12
+ {% endif %}
13
+ scopes:
14
+ - name: financial-instruments:admin
15
+ - name: gateways:admin
16
+ - name: rules:admin
17
+ - name: transfers:admin
18
+ - name: orders:admin
19
+ - name: threeds:admin
20
+ - name: sub-accounts:admin
21
+ - name: cards:write
22
+ - name: network-tokens:write
23
+ - name: merchants:write
24
+
25
+ accessTokenLifespan: 28800
@@ -0,0 +1,23 @@
1
+ apiVersion: 1.0.0
2
+ kind: ServiceAccount
3
+ data:
4
+ name: {{ sub_account_id }}
5
+ annotations:
6
+ "vgs.io/sub-account": "{{ sub_account_id }}"
7
+ {%- if vaults | length == 0 %}
8
+ {{ cli_fail("This template needs single vault to be specified. Please use '--vault <vault-identifier>' to pass the vault.") }}
9
+ {% elif vaults | length == 1 %}
10
+ vaults:
11
+ - {{ vaults[0] }}
12
+ {%- else %}
13
+ {{ cli_fail("This template doesn't allow multiple vaults.") }}
14
+ {% endif %}
15
+ scopes:
16
+ - name: financial-instruments:write
17
+ optional: true
18
+ - name: transfers:write
19
+ optional: true
20
+ - name: orders:write
21
+ optional: true
22
+
23
+ accessTokenLifespan: 28800
@@ -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,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