diff --git a/packages/core/src/awsService/sagemaker/commands.ts b/packages/core/src/awsService/sagemaker/commands.ts index decc098942c..dd1e5bc0e09 100644 --- a/packages/core/src/awsService/sagemaker/commands.ts +++ b/packages/core/src/awsService/sagemaker/commands.ts @@ -132,8 +132,13 @@ export async function deeplinkConnect( try { let connectionType = 'sm_dl' - if (domain === '') { + if (!domain && eksClusterArn && workspaceName && namespace) { + const { accountId, region, clusterName } = parseEKSClusterArn(eksClusterArn) connectionType = 'sm_hp' + session = `${workspaceName}_${namespace}_${clusterName}_${region}_${accountId}` + if (!isValidK8sLabel(session)) { + session = createValidK8sSession(workspaceName, namespace, clusterName, region, accountId) + } } const remoteEnv = await prepareDevEnvConnection( connectionIdentifier, @@ -179,6 +184,52 @@ export async function deeplinkConnect( } } +function parseEKSClusterArn(eksClusterArn: string): { accountId: string; region: string; clusterName: string } { + const parts = eksClusterArn.split(':') + if (parts.length !== 6) { + throw new Error(`Invalid EKS cluster ARN: ${eksClusterArn}`) + } + const accountId = parts[4] + const region = parts[3] + const clusterName = parts[5].split('/')[1] + return { accountId, region, clusterName } +} + +/** + * Validates and sanitizes session names for Kubernetes DNS label compliance + */ +function createValidK8sSession( + workspaceName: string, + namespace: string, + clusterName: string, + region: string, + accountId: string +): string { + const sanitize = (str: string): string => + str + .toLowerCase() + .replace(/[^a-z0-9-]/g, '-') + .replace(/^-+|-+$/g, '') + .substring(0, 15) + + const components = [workspaceName, namespace, clusterName, region, accountId] + .map(sanitize) + .filter((c) => c.length > 0) + + const session = components + .join('_') + .substring(0, 63) + .replace(/^-+|-+$/g, '') + return session +} + +/** + * Validates if a string meets K8s DNS label requirements + */ +function isValidK8sLabel(label: string): boolean { + return /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/.test(label) +} + export async function stopSpace( node: SagemakerSpaceNode | SagemakerUnifiedStudioSpaceNode, ctx: vscode.ExtensionContext, diff --git a/packages/core/src/awsService/sagemaker/model.ts b/packages/core/src/awsService/sagemaker/model.ts index 95fd635c6b9..6139c32edac 100644 --- a/packages/core/src/awsService/sagemaker/model.ts +++ b/packages/core/src/awsService/sagemaker/model.ts @@ -186,7 +186,7 @@ export async function prepareDevEnvConnection( const hyperPodEnv: NodeJS.ProcessEnv = { AWS_REGION: region, - SESSION_ID: session || '', + SESSION_ID: hostname || '', STREAM_URL: decodedWsUrl, TOKEN: decodedToken, AWS_SSM_CLI: ssm,