Skip to content

Commit 8cd61ad

Browse files
authored
Merge branch 'feature/v2-to-v3-migration' into migrate-redshift
2 parents e12e438 + 01da25f commit 8cd61ad

File tree

17 files changed

+815
-301
lines changed

17 files changed

+815
-301
lines changed

package-lock.json

Lines changed: 284 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "Amazon Q automatically refreshes expired IAM Credentials in Sagemaker instances"
4+
}

packages/amazonq/src/lsp/auth.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import * as crypto from 'crypto'
1717
import { LanguageClient } from 'vscode-languageclient'
1818
import { AuthUtil } from 'aws-core-vscode/codewhisperer'
1919
import { Writable } from 'stream'
20-
import { onceChanged } from 'aws-core-vscode/utils'
20+
import { onceChanged, onceChangedWithComparator } from 'aws-core-vscode/utils'
2121
import { getLogger, oneMinute, isSageMaker } from 'aws-core-vscode/shared'
22-
import { isSsoConnection, isIamConnection } from 'aws-core-vscode/auth'
22+
import { isSsoConnection, isIamConnection, areCredentialsEqual } from 'aws-core-vscode/auth'
2323

2424
export const encryptionKey = crypto.randomBytes(32)
2525

@@ -108,7 +108,10 @@ export class AmazonQLspAuth {
108108
this.client.info(`UpdateBearerToken: ${JSON.stringify(request)}`)
109109
}
110110

111-
public updateIamCredentials = onceChanged(this._updateIamCredentials.bind(this))
111+
public updateIamCredentials = onceChangedWithComparator(
112+
this._updateIamCredentials.bind(this),
113+
([prevCreds], [currentCreds]) => areCredentialsEqual(prevCreds, currentCreds)
114+
)
112115
private async _updateIamCredentials(credentials: any) {
113116
getLogger().info(
114117
`[SageMaker Debug] Updating IAM credentials - credentials received: ${credentials ? 'YES' : 'NO'}`

packages/core/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,8 @@
581581
"@aws-sdk/client-ec2": "<3.731.0",
582582
"@aws-sdk/client-glue": "^3.852.0",
583583
"@aws-sdk/client-iam": "<3.731.0",
584+
"@aws-sdk/client-iot": "~3.693.0",
585+
"@aws-sdk/client-iotsecuretunneling": "~3.693.0",
584586
"@aws-sdk/client-lambda": "<3.731.0",
585587
"@aws-sdk/client-redshift": "~3.693.0",
586588
"@aws-sdk/client-redshift-data": "~3.693.0",

packages/core/src/auth/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,7 @@ export class Auth implements AuthService, ConnectionManager {
862862

863863
private async createCachedCredentials(provider: CredentialsProvider) {
864864
const providerId = provider.getCredentialsId()
865+
getLogger().debug(`credentials: create cache credentials for ${provider.getProviderType()}`)
865866
globals.loginManager.store.invalidateCredentials(providerId)
866867
const { credentials, endpointUrl } = await globals.loginManager.store.upsertCredentials(providerId, provider)
867868
await globals.loginManager.validateCredentials(credentials, endpointUrl, provider.getDefaultRegion())

packages/core/src/auth/connection.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ export const isBuilderIdConnection = (conn?: Connection): conn is SsoConnection
7171
export const isValidCodeCatalystConnection = (conn?: Connection): conn is SsoConnection =>
7272
isSsoConnection(conn) && hasScopes(conn, scopesCodeCatalyst)
7373

74+
export const areCredentialsEqual = (creds1: any, creds2: any): boolean => {
75+
if (!creds1 || !creds2) {
76+
return creds1 === creds2
77+
}
78+
79+
return (
80+
creds1.accessKeyId === creds2.accessKeyId &&
81+
creds1.secretAccessKey === creds2.secretAccessKey &&
82+
creds1.sessionToken === creds2.sessionToken
83+
)
84+
}
85+
7486
export function hasScopes(target: SsoConnection | SsoProfile | string[], scopes: string[]): boolean {
7587
return scopes?.every((s) => (Array.isArray(target) ? target : target.scopes)?.includes(s))
7688
}

packages/core/src/auth/credentials/store.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,16 @@ export class CredentialsStore {
3131
* If the expiration property does not exist, it is assumed to never expire.
3232
*/
3333
public isValid(key: string): boolean {
34+
// Apply 60-second buffer similar to SSO token expiry logic
35+
const expirationBufferMs = 60000
36+
3437
if (this.credentialsCache[key]) {
3538
const expiration = this.credentialsCache[key].credentials.expiration
36-
return expiration !== undefined ? expiration >= new globals.clock.Date() : true
39+
const now = new globals.clock.Date()
40+
const bufferedNow = new globals.clock.Date(now.getTime() + expirationBufferMs)
41+
return expiration !== undefined ? expiration >= bufferedNow : true
3742
}
38-
43+
getLogger().debug(`credentials: no credentials found for ${key}`)
3944
return false
4045
}
4146

packages/core/src/auth/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export {
1919
getTelemetryMetadataForConn,
2020
isIamConnection,
2121
isSsoConnection,
22+
areCredentialsEqual,
2223
} from './connection'
2324
export { Auth } from './auth'
2425
export { CredentialsStore } from './credentials/store'

0 commit comments

Comments
 (0)