Skip to content
Open
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
27 changes: 24 additions & 3 deletions keepercommander/commands/discoveryrotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2340,7 +2340,8 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'):

for c in configurations: # type: vault.TypedRecord
if c.record_type in ('pamAwsConfiguration', 'pamAzureConfiguration', 'pamGcpConfiguration',
'pamDomainConfiguration', 'pamNetworkConfiguration', 'pamOciConfiguration'):
'pamDomainConfiguration', 'pamNetworkConfiguration', 'pamOciConfiguration',
'pamGitHubConfiguration'):
facade.record = c
shared_folder_parents = find_parent_top_folder(params, c.record_uid)
if shared_folder_parents:
Expand Down Expand Up @@ -2402,7 +2403,7 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'):

common_parser = argparse.ArgumentParser(add_help=False)
common_parser.add_argument('--environment', '-env', dest='config_type', action='store',
choices=['local', 'aws', 'azure', 'gcp', 'domain', 'oci'], help='PAM Configuration Type')
choices=['local', 'aws', 'azure', 'gcp', 'domain', 'oci', 'github'], help='PAM Configuration Type')
common_parser.add_argument('--title', '-t', dest='title', action='store', help='Title of the PAM Configuration')
common_parser.add_argument('--gateway', '-g', dest='gateway_uid', action='store', help='Gateway UID or Name')
common_parser.add_argument('--shared-folder', '-sf', dest='shared_folder_uid', action='store',
Expand Down Expand Up @@ -2461,6 +2462,12 @@ def print_root_rotation_setting(params, is_verbose=False, format_type='table'):
help='Google Workspace Administrator Email Address')
gcp_group.add_argument('--gcp-region', dest='region_names', action='append', help='GCP Region Names')

github_group = common_parser.add_argument_group('github', 'GitHub configuration')
github_group.add_argument('--github-id', dest='github_id', action='store', help='GitHub Id')
github_group.add_argument('--personal-access-token', dest='personal_access_token', action='store',
help='Personal Access Token')
github_group.add_argument('--github-base-url', dest='github_base_url', action='store',
help='GitHub Base URL')

class PamConfigurationEditMixin(RecordEditMixin):
pam_record_types = None
Expand Down Expand Up @@ -2642,6 +2649,16 @@ def parse_properties(self, params, record, **kwargs): # type: (KeeperParams, va
if gcp_region:
regions = '\n'.join(gcp_region)
extra_properties.append(f'multiline.pamGcpRegionName={regions}')
elif record.record_type == 'pamGitHubConfiguration':
github_id = kwargs.get('github_id')
if github_id:
extra_properties.append(f'text.pamGitHubId={github_id}')
personal_access_token = kwargs.get('personal_access_token')
if personal_access_token:
extra_properties.append(f'secret.personalAccessToken={personal_access_token}')
github_base_url = kwargs.get('github_base_url')
if github_base_url:
extra_properties.append(f'text.pamGitHubBaseUrl={github_base_url}')
elif record.record_type == 'pamAzureConfiguration':
azure_id = kwargs.get('azure_id')
if azure_id:
Expand Down Expand Up @@ -2803,13 +2820,15 @@ def execute(self, params, **kwargs):
record_type = 'pamNetworkConfiguration'
elif config_type == 'gcp':
record_type = 'pamGcpConfiguration'
elif config_type == 'github':
record_type = 'pamGitHubConfiguration'
elif config_type == 'domain':
record_type = 'pamDomainConfiguration'
elif config_type == 'oci':
record_type = 'pamOciConfiguration'
else:
raise CommandError('pam-config-new', f'--environment {config_type} is not supported'
' - supported options: local, aws, azure, gcp, domain, oci')
' - supported options: local, aws, azure, gcp, domain, oci, github')

title = kwargs.get('title')
if not title:
Expand Down Expand Up @@ -2958,6 +2977,8 @@ def execute(self, params, **kwargs):
record_type = 'pamNetworkConfiguration'
elif config_type == 'gcp':
record_type = 'pamGcpConfiguration'
elif config_type == 'github':
record_type = 'pamGitHubConfiguration'
elif config_type == 'domain':
record_type = 'pamDomainConfiguration'
elif config_type == 'oci':
Expand Down
10 changes: 7 additions & 3 deletions unit-tests/test_command_enterprise_api_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ def test_api_key_list_json_format(self):

self.assertEqual(len(TestEnterpriseApiKeys.expected_commands), 0)
self.assertIsNotNone(result)
# Compute the expected expiration date for the active token (matches mock: now + 365 days)
token4_expiry = datetime.datetime.now() + datetime.timedelta(days=365)
token4_expiry_str = token4_expiry.strftime('%Y-%m-%d %H:%M:%S')
# Assert that the JSON result matches the expected values for all entries
expected_json = [
{
Expand Down Expand Up @@ -100,7 +103,7 @@ def test_api_key_list_json_format(self):
"name": "SIEM Tool",
"status": "Active",
"issued_date": "2025-07-08 14:16:07",
"expiration_date": "2030-07-08 14:16:07",
"expiration_date": token4_expiry_str,
"integration": "SIEM:2"
},
{
Expand Down Expand Up @@ -661,13 +664,14 @@ def communicate_rest_success(params, request, path, rs_type=None):
integration5.apiIntegrationTypeName = "SIEM"
integration5.actionType = 2

# Token 53 - Active
# Token 53 - Active (expiration is always 1 year from now to keep tests passing over time)
token4 = rs.tokens.add()
token4.token = "active_token_53"
token4.name = "SIEM Tool"
token4.enterprise_id = 8560
token4.issuedDate = int(datetime.datetime(2025, 7, 8, 14, 16, 7).timestamp() * 1000)
token4.expirationDate = int(datetime.datetime(2030, 7, 8, 14, 16, 7).timestamp() * 1000)
token4_expiry = datetime.datetime.now() + datetime.timedelta(days=365)
token4.expirationDate = int(token4_expiry.timestamp() * 1000)
integration7 = token4.integrations.add()
integration7.roleName = "SIEM"
integration7.apiIntegrationTypeName = "SIEM"
Expand Down
Loading