Skip to content

Commit 5192b18

Browse files
authored
Merge pull request #56 from britive/develop
v0.10.2
2 parents 03f6f56 + 45df6d8 commit 5192b18

7 files changed

Lines changed: 73 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
All changes to the package starting with v0.3.1 will be logged here.
44

5+
## v0.10.2 [2023-02-06]
6+
#### What's New
7+
* None
8+
9+
#### Enhancements
10+
* None
11+
12+
#### Bug Fixes
13+
* Fix issue with `checkout` and related commands that use the `PROFILE` positional argument when the one or more of the `PROFILE` components (application, environment, profile) have a `/` in the name. Caller must now properly escape any `/` with a `\` (e.g. `AWS/Dev\/Test/Admin`).
14+
15+
#### Dependencies
16+
* None
17+
18+
#### Other
19+
* None
20+
521
## v0.10.1 [2023-01-19]
622
#### What's New
723
* None

docs/index.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,18 @@ This can be overwritten by specifying environment variable `PYBRITIVE_HOME_DIR`.
147147
the end user wants to persist the `.britive` directory. Note that `.britive` will still be created so do not specify
148148
that as part of the path.
149149

150+
151+
## Escaping
152+
If the name of an application, environment, or profile contains a `/` then that character must be properly escaped with a `\`.
153+
154+
Example:
155+
* Application: AWS
156+
* Environment: Dev/Test
157+
* Profile: Admin
158+
159+
As we construct the checkout command it would generally be `AWS/Dev/Test/Admin` but since the environment has a `/`
160+
in it, we need to escape that to be `AWS/Dev\/Test/Admin` so the CLI can properly parse out the 3 required parts of the string .
161+
150162
## Shell Completion
151163

152164
TODO: Provide more automated scripts here to automatically add the required configs to the profiles. For now the below works just fine though.

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ certifi==2022.6.15
33
charset-normalizer==2.1.0
44
click==8.1.3
55
idna==3.3
6-
merge-args==0.1.4
6+
merge-args==0.1.5
77
PyYAML==6.0
88
requests==2.28.1
99
six==1.16.0

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[metadata]
22
name = pybritive
3-
version = 0.10.1
3+
version = 0.10.2
44
author = Britive Inc.
55
author_email = support@britive.com
66
description = A pure Python CLI for Britive

src/pybritive/britive_cli.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from britive.britive import Britive
33
from .helpers.config import ConfigManager
44
from .helpers.credentials import FileCredentialManager, EncryptedFileCredentialManager
5+
from .helpers.split import profile_split
56
import json
67
import click
78
import csv
@@ -143,7 +144,7 @@ def print(self, data: object, ignore_silent: bool = False):
143144
click.echo(json.dumps(data, indent=2, default=str))
144145
elif self.output_format == 'list':
145146
for row in data:
146-
click.echo(self.list_separator.join(row.values()))
147+
click.echo(self.list_separator.join([self.escape_profile_element(x) for x in row.values()]))
147148
elif self.output_format == 'csv':
148149
fields = list(data[0].keys())
149150
output = io.StringIO()
@@ -359,7 +360,7 @@ def _should_check_force_renew(app, force_renew, console):
359360

360361
def _split_profile_into_parts(self, profile):
361362
profile_real = self.config.profile_aliases.get(profile, profile)
362-
parts = profile_real.split('/')
363+
parts = profile_split(profile_real)
363364
if len(parts) != 3:
364365
raise click.ClickException('Provided profile string does not have the required 3 parts.')
365366
parts_dict = {
@@ -551,9 +552,18 @@ def cache_profiles(self, load=True):
551552
self._set_available_profiles()
552553
profiles = []
553554
for p in self.available_profiles:
554-
profiles.append(f"{p['app_name']}/{p['env_name']}/{p['profile_name']}")
555+
profile = self.escape_profile_element(p['app_name'])
556+
profile += '/'
557+
profile += self.escape_profile_element(p['env_name'])
558+
profile += '/'
559+
profile += self.escape_profile_element(p['profile_name'])
560+
profiles.append(profile)
555561
Cache().save_profiles(profiles)
556562

563+
@staticmethod
564+
def escape_profile_element(element):
565+
return element.replace('/', '\\/')
566+
557567
@staticmethod
558568
def cache_clear():
559569
Cache().clear()

src/pybritive/helpers/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ..choices.output_format import output_format_choices
99
from ..choices.backend import backend_choices
1010
from britive.britive import Britive
11+
from ..helpers.split import profile_split
1112

1213

1314
def extract_tenant(tenant_key):
@@ -256,7 +257,7 @@ def validate_global(self, section, fields):
256257

257258
def validate_profile_aliases(self, section, fields):
258259
for field, value in fields.items():
259-
if len(value.split('/')) != 3:
260+
if len(profile_split(value)) != 3:
260261
error = f'Invalid {section} field {field} value {value} provided. Value must be 3 parts ' \
261262
'separated by a /'
262263
self.validation_error_messages.append(error)

src/pybritive/helpers/split.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
def profile_split(profile):
2+
def str_escape_split(str_to_escape, delimiter=',', escape='\\'):
3+
if len(delimiter) > 1 or len(escape) > 1:
4+
raise ValueError("Either delimiter or escape must be an one char value")
5+
token = ''
6+
escaped = False
7+
for c in str_to_escape:
8+
if c == escape:
9+
if escaped:
10+
token += escape
11+
escaped = False
12+
else:
13+
escaped = True
14+
continue
15+
if c == delimiter:
16+
if not escaped:
17+
yield token
18+
token = ''
19+
else:
20+
token += c
21+
escaped = False
22+
else:
23+
if escaped:
24+
token += escape
25+
escaped = False
26+
token += c
27+
yield token
28+
return list(str_escape_split(profile, delimiter='/', escape='\\'))

0 commit comments

Comments
 (0)