Repository: victorskl/yawsso (language: python)

Issue:
Rename profile on sync
Not sure if a wider problem but the dotnet sdk doesn't support assuming a role with the source_profile is an SSO config. So yawsso sounds like a great workaround but the sdk decided to prioritize config file over the credentials file. When yawsso syncs I have the source_profile in both files and it still fails.  

Feature request to rename a profile on sync so I cound have `[profile rolesso]` in config and on sync it becomes `[role]` in the credentials file.

Maybe `yawsso -p rolesso:role`? From the docs, profile names "can use letters, numbers, hyphens ( - ), and underscores ( _ ), but no spaces."

Relates to https://github.com/aws/aws-sdk-net/issues/1853


Discussion / hints:
@supergibbs Yep; sound ok to me. Just hoping; folk won't intentionally name the _normal_ profile with colon in it! Bec it'd activate "rename" logic; if I understand correctly. Otherwise we could have _a dedicated flag_ or _a subcommand_ for this particular use case -- _rename profile on sync_ -- feature. How do you think?

My org and I, myself do not use `source_profile`; TBH. So it's all up to community user feedback. Likewise, happy to support this feature. 

Meanwhile, let me read the related issue pointer (thanks) to understand the context better.
Ya, I included a snippet from the docs that seems to say colons aren't allowed in profile names. I think this would be better so the rest of the functionality would still work without change. A flag or subcommand would limit to one profile probably or be harder to use. Thanks! 

Fix patch:
diff --git a/yawsso/cli.py b/yawsso/cli.py
index 9765ee4..bbd80ae 100644
--- a/yawsso/cli.py
+++ b/yawsso/cli.py
@@ -338,12 +338,15 @@ def is_sso_profile(profile):
 def is_source_profile(profile):
     return {"source_profile", "role_arn", "region"} <= profile.keys()
 
-
-def update_profile(profile_name, config):
+def update_profile(profile_name, config, new_profile_name=""):
     profile = load_profile_from_config(profile_name, config)
 
-    logger.log(TRACE, f"Syncing profile... {profile_name}: {profile}")
-
+    if new_profile_name == "":
+        new_profile_name = profile_name
+        logger.log(TRACE, f"Syncing profile... {profile_name}: {profile}")
+    else:
+        logger.log(TRACE, f"Syncing profile... {profile_name}->{new_profile_name}: {profile}")
+        
     if is_sso_profile(profile):
         credentials = fetch_credentials(profile_name, profile)
 
@@ -365,7 +368,7 @@ def update_profile(profile_name, config):
         logger.warning(f"Not an AWS SSO profile nor no source_profile found. Skip syncing profile `{profile_name}`")
         return
 
-    update_aws_cli_v1_credentials(profile_name, profile, credentials)
+    update_aws_cli_v1_credentials(new_profile_name, profile, credentials)
 
     return credentials
 
@@ -521,11 +524,20 @@ def main():
 
     global profiles
     profiles = named_profiles
+    profiles_new_name = dict()
 
     if args.profiles:
         profiles = []
         for np in args.profiles:
-            if np.endswith("*"):
+            if ":" in np:
+                old,new = np.split(":")
+                if old not in named_profiles:
+                    logger.warning(f"Named profile `{old}` is not specified in {aws_config_file} file. Skipping...")
+                    continue
+                logger.debug(f"Renaming profile {old} to {new}")
+                profiles.append(old)
+                profiles_new_name[old] = new
+            elif np.endswith("*"):
                 prefix = np.split("*")[0]
                 logger.log(TRACE, f"Collecting all named profiles start with '{prefix}'")
                 for _p in named_profiles:
@@ -540,6 +552,9 @@ def main():
         logger.debug(f"Syncing named profiles: {profiles}")
 
     for profile_name in profiles:
-        credentials = update_profile(profile_name, config)
+        if profile_name in profiles_new_name:
+            credentials = update_profile(profile_name, config, profiles_new_name[profile_name])
+        else:
+            credentials = update_profile(profile_name, config)
         if export_vars:
             get_export_vars(profile_name, credentials)


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 0c43714..0a39318 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -790,3 +790,17 @@ def test_append_cli_global_options(self):
         cmd = cli.append_cli_global_options("aws sso get-role-credentials", ca_bundle_profile)
         logger.info(cmd)
         self.assertIn('--ca-bundle', cmd)
+
+    def test_rename_profile(self):
+        with ArgvContext(program, '-p', 'dev:dev_renamed', '--debug'):
+            cli.main()
+            cred = cli.read_config(self.credentials.name)
+            new_tok = cred['dev_renamed']['aws_session_token']
+            self.assertNotEqual(new_tok, 'tok')
+            self.assertEqual(new_tok, 'VeryLongBase664String==')
+            verify(cli, times=2).invoke(...)
+
+    def test_rename_profile_not_found(self):
+        with ArgvContext(program, '-p', f"{uuid.uuid4().hex}:new_name", '-t'):
+            cli.main()
+        self.assertEqual(len(cli.profiles), 0)
\ No newline at end of file