Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

* As of v1.4.0 release candidates will be published in an effort to get new features out faster while still allowing time for full QA testing before moving the release candidate to a full release.

## v1.6.0rc4 [2023-11-03]
#### What's New
* None

#### Enhancements
* For command `ls profiles -c` show the time remaining for the checkout
* Add new flag `-e/--extend` to command `checkout` which will extend the expiration time of a currently checked out profile (only applicable to specific application types)

#### Bug Fixes
* Fix bug in `configure import` related to the default AWS checkout mode

#### Dependencies
* None

#### Other
* None

## v1.6.0rc3 [2023-10-31]
#### What's New
* None
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
boto3
britive>=2.22.0
britive==2.23.0rc1
certifi>=2022.12.7
charset-normalizer==2.1.0
click~=8.1.3
Expand Down
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = pybritive
version = 1.6.0rc3
version = 1.6.0rc4
author = Britive Inc.
author_email = support@britive.com
description = A pure Python CLI for Britive
Expand All @@ -27,7 +27,7 @@ install_requires =
toml
cryptography>=41.0.0
python-dateutil
britive>=2.22.0
britive==2.23.0rc1
jmespath
pyjwt

Expand Down
58 changes: 49 additions & 9 deletions src/pybritive/britive_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,26 +262,50 @@ def list_profiles(self, checked_out: bool = False):
self.login()
self._set_available_profiles()
data = []
checked_out_profiles = [
f'{p["papId"]}-{p["environmentId"]}'
for p in self.b.my_access.list_checked_out_profiles()
] if checked_out else []
checked_out_profiles = {}
if checked_out: # only make this call if we have to
now = datetime.utcnow()
for p in self.b.my_access.list_checked_out_profiles():
expiration_str = p['expiration']
expiration_timestamp = datetime.fromisoformat(expiration_str.replace('Z', ''))
seconds_until_expiration = int((expiration_timestamp - now).total_seconds())
key = f'{p["papId"]}-{p["environmentId"]}'
checked_out_profiles[key] = {
'expiration': expiration_str,
'expires_in_seconds': seconds_until_expiration
}

for profile in self.available_profiles:
if not checked_out or f'{profile["profile_id"]}-{profile["env_id"]}' in checked_out_profiles:
key = f'{profile["profile_id"]}-{profile["env_id"]}'
profile_is_checked_out = key in checked_out_profiles
if not checked_out or profile_is_checked_out:
row = {
'Application': profile['app_name'],
'Environment': profile['env_name'],
'Profile': profile['profile_name'],
'Description': profile['profile_description'],
'Type': profile['app_type']
}

if profile_is_checked_out:
row['Expiration'] = checked_out_profiles[key]['expiration']
total_seconds = checked_out_profiles[key]['expires_in_seconds']

hours, remainder = divmod(total_seconds, 3600)
minutes, seconds = divmod(remainder, 60)
time_format = '{:02d}:{:02d}:{:02d}'.format(hours, minutes, seconds)
row['TimeRemaining'] = time_format
row['TimeRemainingSeconds'] = total_seconds

if self.output_format == 'list':
self.list_separator = '/'
row.pop('Description')
row.pop('Type')
row.pop('Description', None)
row.pop('Type', None)
row.pop('TimeRemaining', None)
row.pop('TimeRemainingSeconds', None)
row.pop('Expiration', None)
if profile['2_part_profile_format_allowed']:
row.pop('Environment')
row.pop('Environment', None)
data.append(row)

# set special list output if needed
Expand Down Expand Up @@ -545,8 +569,24 @@ def _split_profile_into_parts(self, profile):
}
return parts_dict

def _extend_checkout(self, profile, console):
self.login()
parts = self._split_profile_into_parts(profile)
response = self.b.my_access.extend_checkout_by_name(
profile_name=parts['profile'],
environment_name=parts['env'],
application_name=parts['app'],
programmatic=not console
)

def checkout(self, alias, blocktime, console, justification, mode, maxpolltime, profile, passphrase,
force_renew, aws_credentials_file, gcloud_key_file, verbose):
force_renew, aws_credentials_file, gcloud_key_file, verbose, extend):

# handle this special use case and quit
if extend:
self._extend_checkout(profile, console)
return

credentials = None
app_type = None
cached_credentials_found = False
Expand Down
8 changes: 5 additions & 3 deletions src/pybritive/commands/checkout.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
@click.command()
@build_britive
@britive_options(names='alias,blocktime,console,justification,mode,maxpolltime,silent,force_renew,aws_credentials_file,'
'gcloud_key_file,verbose,tenant,token,passphrase,federation_provider')
'gcloud_key_file,verbose,extend,tenant,token,passphrase,federation_provider')
@click_smart_profile_argument
def checkout(ctx, alias, blocktime, console, justification, mode, maxpolltime, silent, force_renew,
aws_credentials_file, gcloud_key_file, verbose, tenant, token, passphrase, federation_provider, profile):
aws_credentials_file, gcloud_key_file, verbose, extend, tenant, token, passphrase, federation_provider,
profile):
"""Checkout a profile.
This command takes 1 required argument `PROFILE`. This should be a string representation of the profile
Expand All @@ -30,5 +31,6 @@ def checkout(ctx, alias, blocktime, console, justification, mode, maxpolltime, s
force_renew=force_renew,
aws_credentials_file=aws_credentials_file,
gcloud_key_file=gcloud_key_file,
verbose=verbose
verbose=verbose,
extend=extend
)
3 changes: 2 additions & 1 deletion src/pybritive/helpers/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,9 @@ def import_global_npm_config(self):
if aws_section:
checkout_mode = aws_section.get('checkoutMode')
if checkout_mode:
checkout_mode = checkout_mode.lower().replace('display', '')
self.cli.print(f'Found aws default checkout mode of {checkout_mode}.')
self.config['aws'] = {'default_checkout_mode': checkout_mode.lower()}
self.config['aws'] = {'default_checkout_mode': checkout_mode}

self.save()
self.load(force=True)
Expand Down
4 changes: 3 additions & 1 deletion src/pybritive/options/britive_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from ..options.aws_profile import option as aws_profile
from ..options.aws_console_duration import option as aws_console_duration
from ..options.browser import option as browser
from ..options.extend import option as extend

options_map = {
'tenant': tenant,
Expand Down Expand Up @@ -65,7 +66,8 @@
'ssh_key_source': ssh_key_source,
'aws_profile': aws_profile,
'aws_console_duration': aws_console_duration,
'browser': browser
'browser': browser,
'extend': extend
}


Expand Down
10 changes: 10 additions & 0 deletions src/pybritive/options/extend.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import click


option = click.option(
'--extend', '-e',
default=False,
is_flag=True,
show_default=True,
help='Extend the expiration time for a currently checked out profile.'
)