Repository: stateful/vscode-runme
Pull request #1808 (2024-11-19 22:27:40)

Improve OS username resolution for EC2 instances
- Expanded supported patterns to include rhel and suse-sles images.
- Introduced a defaultUserName (ec2-user) for unsupported or unmatched image patterns.
- Updated resolveOsUserName function to handle null or undefined values for imageName.
- Fixed case-sensitivity issues by converting imageName to lowercase before matching.
- Simplified logic to ensure robust and predictable username resolution.
- Included the **--region** flag


Closes: #1807


Patch:
diff --git a/examples/aws/ec2.md b/examples/aws/ec2.md
index 0c409564..b7d4eee1 100644
--- a/examples/aws/ec2.md
+++ b/examples/aws/ec2.md
@@ -35,12 +35,12 @@ https://us-east-1.console.aws.amazon.com/ec2/home?region=us-east-1#Instances
 
 ```sh {"background":"true","id":"01J1B86EN48NRRJHPNVVGJAMXY"}
 echo "Connecting to instance via SSH..."
-aws ec2-instance-connect ssh --instance-id i-0656ca72923a992b7 --os-user=ec2-user
+aws ec2-instance-connect ssh --instance-id i-0656ca72923a992b7 --region=us-east-1 --os-user=ec2-user
 ```
 
 ```sh {"background":"true","id":"01J1B85H6ZJ6P0VA9PW3D3Q3H7"}
 echo "Connecting to instance via SSH..."
-aws ec2-instance-connect ssh --instance-id i-015097a0646c45ea8 --os-user=ubuntu
+aws ec2-instance-connect ssh --instance-id i-015097a0646c45ea8 --region=us-east-1 --os-user=ubuntu
 ```
 
 Isn't that cool? that's a **Runme cloud renderer** in Action!
@@ -104,4 +104,4 @@ aws ec2-instance-connect ssh --instance-id $EC2_INSTANCE_ID --os-user=ubuntu
 ### Feedback welcome!
 
 Do you have feedback or new ideas ? what about more Runme Cloud renderers for AWS features ?
-Feel free to [reach out to us](https://github.com/stateful/runme?tab=readme-ov-file#feedback)
\ No newline at end of file
+Feel free to [reach out to us](https://github.com/stateful/runme?tab=readme-ov-file#feedback)
diff --git a/src/client/components/aws/ec2Helper.ts b/src/client/components/aws/ec2Helper.ts
index 57565e88..806e1ee5 100644
--- a/src/client/components/aws/ec2Helper.ts
+++ b/src/client/components/aws/ec2Helper.ts
@@ -1,20 +1,20 @@
-export function resolveOsUserName(imageName: string) {
+export function resolveOsUserName(imageName: string | null | undefined) {
   if (!imageName) {
     return ''
   }
 
+  const defaultUserName = 'ec2-user'
   const amiPatterns: { [key: string]: string } = {
-    '^(amazon|amzn|al2023)': 'ec2-user',
+    '^(amazon|amzn|al2023|rhel|suse-sles)': defaultUserName,
     '^(ubuntu|centos|redhat|debian)': '\\1', // Use backreference for matched pattern (group 1)
-    '.+': '\\w+',
   }
 
   for (const pattern in amiPatterns) {
-    const match = imageName.match(new RegExp(pattern))
-    if (match) {
-      return match[1] ? amiPatterns[pattern].replace('\\1', match[1]) : amiPatterns[pattern]
+    const match = imageName.toLocaleLowerCase().match(new RegExp(pattern, 'i'))
+    if (match && match[1]) {
+      return amiPatterns[pattern].replace('\\1', match[1])
     }
   }
 
-  return ''
+  return defaultUserName
 }
diff --git a/src/extension/messages/aws.ts b/src/extension/messages/aws.ts
index 05d5a965..8fc314cc 100644
--- a/src/extension/messages/aws.ts
+++ b/src/extension/messages/aws.ts
@@ -31,7 +31,7 @@ export async function handleAWSMessage({ message, editor }: AWSStatusMessaging):
               editor,
               'echo "Connecting to instance via SSH..."\n' +
                 // eslint-disable-next-line max-len
-                `aws ec2-instance-connect ssh --instance-id ${message.output.instance} --os-user=${message.output.osUser}`,
+                `aws ec2-instance-connect ssh --instance-id ${message.output.instance} --region=${message.output.region} --os-user=${message.output.osUser}`,
               'sh',
               true,
             )


Test patch:
diff --git a/tests/client/components/aws/ec2Helper.test.ts b/tests/client/components/aws/ec2Helper.test.ts
new file mode 100644
index 00000000..d162538a
--- /dev/null
+++ b/tests/client/components/aws/ec2Helper.test.ts
@@ -0,0 +1,44 @@
+import { describe, it, expect } from 'vitest'
+
+import { resolveOsUserName } from '../../../../src/client/components/aws/ec2Helper'
+
+describe('resolveOsUserName', () => {
+  it('should return empty string when imageName is empty', () => {
+    expect(resolveOsUserName('')).toBe('')
+  })
+
+  it('should return "ec2-user" for Amazon Linux image names', () => {
+    expect(resolveOsUserName('amazon-linux')).toBe('ec2-user')
+    expect(resolveOsUserName('amzn-ami')).toBe('ec2-user')
+    expect(resolveOsUserName('al2023')).toBe('ec2-user')
+  })
+
+  it('should return "ec2-user" for RHEL or SUSE Linux image names', () => {
+    expect(resolveOsUserName('rhel-8')).toBe('ec2-user')
+    expect(resolveOsUserName('suse-sles')).toBe('ec2-user')
+  })
+
+  it('should return the corresponding user for Ubuntu, CentOS, RedHat, or Debian image names', () => {
+    expect(resolveOsUserName('ubuntu-20.04')).toBe('ubuntu')
+    expect(resolveOsUserName('centos-7')).toBe('centos')
+    expect(resolveOsUserName('redhat')).toBe('redhat')
+    expect(resolveOsUserName('debian')).toBe('debian')
+  })
+
+  it('should return "ec2-user" for unknown patterns', () => {
+    expect(resolveOsUserName('unknown-image')).toBe('ec2-user')
+    expect(resolveOsUserName('custom-linux-image')).toBe('ec2-user')
+  })
+
+  it('should be case insensitive', () => {
+    expect(resolveOsUserName('UbUnTu-18.04')).toBe('ubuntu')
+    expect(resolveOsUserName('AMAZON-LINUX')).toBe('ec2-user')
+    expect(resolveOsUserName('RHEL-7')).toBe('ec2-user')
+  })
+
+  it('should handle edge cases gracefully', () => {
+    expect(resolveOsUserName(null)).toBe('')
+    expect(resolveOsUserName(undefined)).toBe('')
+    expect(resolveOsUserName('   ')).toBe('ec2-user') // Assuming whitespace counts as unknown pattern
+  })
+})