Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor project structure #76

Merged
merged 14 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 10 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
358 changes: 172 additions & 186 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
"jose": "^5.2.3",
"rxjs": "^7.8.1",
"vscode-languageserver": "^9.0.1",
"vscode-languageserver-textdocument": "^1.0.11"
"vscode-languageserver-protocol": "^3.17.5",
"vscode-languageserver-textdocument": "^1.0.11",
"vscode-languageserver-types": "^3.17.5"
},
"devDependencies": {
"@types/mocha": "^10.0.1",
Expand Down
5 changes: 0 additions & 5 deletions src/features/index.ts

This file was deleted.

5 changes: 5 additions & 0 deletions src/protocol/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## AWS Language Servers Runtimes Protocol

This folder contains definition of AWS Language Servers Protocol, which defines a protocol for communication between Servers and Clients.
It is modelled after LSP, and provides several custom extensions to enable custom AWS Language Server Runtimes features.

49 changes: 49 additions & 0 deletions src/protocol/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ProtocolRequestType, ProtocolNotificationType0, ProtocolRequestType0 } from './lsp'

export type IamCredentials = {
readonly accessKeyId: string
readonly secretAccessKey: string
readonly sessionToken?: string
}

export type BearerCredentials = {
readonly token: string
}

export interface SsoProfileData {
startUrl?: string
}

export interface ConnectionMetadata {
sso?: SsoProfileData
}

export interface UpdateCredentialsParams {
// Plaintext Credentials (for browser based environments) or encrypted JWT token
data: IamCredentials | BearerCredentials | string
// If the payload is encrypted
// Defaults to false if undefined or null
encrypted?: boolean
}

export const iamCredentialsUpdateRequestType = new ProtocolRequestType<UpdateCredentialsParams, null, void, void, void>(
'aws/credentials/iam/update'
)

export const iamCredentialsDeleteNotificationType = new ProtocolNotificationType0<void>('aws/credentials/iam/delete')

export const bearerCredentialsUpdateRequestType = new ProtocolRequestType<
UpdateCredentialsParams,
null,
void,
void,
void
>('aws/credentials/token/update')

export const bearerCredentialsDeleteNotificationType = new ProtocolNotificationType0<void>(
'aws/credentials/token/delete'
)

export const getConnectionMetadataRequestType = new ProtocolRequestType0<ConnectionMetadata, never, void, void>(
'aws/credentials/getConnectionMetadata'
)
2 changes: 2 additions & 0 deletions src/protocol/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './lsp'
export * from './auth'
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
InlineCompletionRegistrationOptions,
ProtocolNotificationType,
ProtocolRequestType,
} from 'vscode-languageserver'
} from './lsp'

export type InlineCompletionWithReferencesParams = InlineCompletionParams & {
// No added parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import {
InlineCompletionItem,
InlineCompletionList,
InlineCompletionParams,
InlineCompletionRegistrationOptions,
ProtocolRequestType,
} from 'vscode-languageserver'
InlineCompletionRegistrationOptions,
} from './lsp'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there still a copy/paste here from the 3.18 branch of vscode-languageserver?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, 3.18 LSP is not yet published


/**
* inlineCompletionRequestType defines the custom method that the language client
Expand Down
12 changes: 12 additions & 0 deletions src/protocol/lsp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export { TextDocument, Position } from 'vscode-languageserver-textdocument'

// LSP protocol is a core dependency for LSP feature provided by runtimes.
// Since we aim to provide whole range of LSP specification for Clients and Capabilities,
// we re-exporting whole LSP protocol for usage.
// Scoping it down is not practical due to large surface of protocol and types relationship.
// It will be limiting implementors, if they choose to type their code with more specific types from LSP.
export * from 'vscode-languageserver-protocol'

// Custom Runtimes LSP extensions
export * from './inlineCompletions'
export * from './inlineCompletionWithReferences'
12 changes: 12 additions & 0 deletions src/runtimes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
## AWS Language server runtimes

This folder contains implementation of AWS Language server runtimes and Runtimes features.

Each runtime implements a LSP server and opens communication channel with client over LSP connection. Runtime initialised all registered Capabilities.

Runtime sets up message passing, that translates Runtimes Protocol messages to a function calls to Capabilities features, defined in Server and server features interfaces.

Runtime implementation acts as a intermediate layer between Runtime Client and a Runtime Servers, injected into runtime at build time.
The runtime implements message passing between Client application and injected Servers, and interface with both by predefined APIs:
* **Runtime Protocol**: a protocol to define communication between Runtime and Client application (e.g. Runtime<->AWS Toolkit extension). It uses LSP (and JSON-RPC) connection as a transport.
* **Runtime Server Interface**: defines an interface of the Server and features exposed to Runtime Server developers (e.g. Runtime<->AWS CodeWhisperer server).
68 changes: 35 additions & 33 deletions src/features/auth/auth.test.ts → src/runtimes/auth/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import { randomBytes } from 'node:crypto'
import * as jose from 'jose'
import { Duplex } from 'stream'
import { Connection, createConnection } from 'vscode-languageserver/node'
import {
Auth,
BearerCredentials,
CredentialsProvider,
CredentialsType,
IamCredentials,
UpdateCredentialsRequest,
credentialsProtocolMethodNames,
} from './auth'
import { Auth } from './auth'
import { UpdateCredentialsParams } from '../../protocol'
import { IamCredentials, BearerCredentials, CredentialsType, CredentialsProvider } from '../../server-interface'

export const credentialsProtocolMethodNames = {
iamCredentialsUpdate: 'aws/credentials/iam/update',
iamCredentialsDelete: 'aws/credentials/iam/delete',
bearerCredentialsUpdate: 'aws/credentials/token/update',
bearerCredentialsDelete: 'aws/credentials/token/delete',
getConnectionMetadata: 'aws/credentials/getConnectionMetadata',
}

class TestStream extends Duplex {
_write(chunk: string, _encoding: string, done: () => void) {
Expand All @@ -23,33 +25,33 @@ class TestStream extends Duplex {
}

const authHandlers = {
iamUpdateHandler: async (request: UpdateCredentialsRequest): Promise<void | Error> => {},
iamUpdateHandler: async (request: UpdateCredentialsParams): Promise<void | Error> => {},
iamDeleteHandler: () => {},
bearerUpdateHandler: async (request: UpdateCredentialsRequest): Promise<void | Error> => {},
bearerUpdateHandler: async (request: UpdateCredentialsParams): Promise<void | Error> => {},
bearerDeleteHandler: () => {},
}

function clearHandlers() {
authHandlers.iamUpdateHandler = async (request: UpdateCredentialsRequest): Promise<void | Error> => {}
authHandlers.iamUpdateHandler = async (request: UpdateCredentialsParams): Promise<void | Error> => {}
authHandlers.iamDeleteHandler = () => {}
authHandlers.bearerUpdateHandler = async (request: UpdateCredentialsRequest): Promise<void | Error> => {}
authHandlers.bearerUpdateHandler = async (request: UpdateCredentialsParams): Promise<void | Error> => {}
authHandlers.bearerDeleteHandler = () => {}
}

const serverLspConnectionMock = <Connection>{
onRequest: (method: string, handler: any) => {
if (method === credentialsProtocolMethodNames.iamCredentialsUpdate) {
onRequest: (requestType: any, handler: any) => {
if (requestType.method === credentialsProtocolMethodNames.iamCredentialsUpdate) {
authHandlers.iamUpdateHandler = handler
}
if (method === credentialsProtocolMethodNames.bearerCredentialsUpdate) {
if (requestType.method === credentialsProtocolMethodNames.bearerCredentialsUpdate) {
authHandlers.bearerUpdateHandler = handler
}
},
onNotification: (method: string, handler: any) => {
if (method === credentialsProtocolMethodNames.iamCredentialsDelete) {
onNotification: (requestType: any, handler: any) => {
if (requestType.method === credentialsProtocolMethodNames.iamCredentialsDelete) {
authHandlers.iamDeleteHandler = handler
}
if (method === credentialsProtocolMethodNames.bearerCredentialsDelete) {
if (requestType.method === credentialsProtocolMethodNames.bearerCredentialsDelete) {
authHandlers.bearerDeleteHandler = handler
}
},
Expand Down Expand Up @@ -93,7 +95,7 @@ describe('Auth', () => {
})

it('Handles IAM credentials', async () => {
const updateRequest: UpdateCredentialsRequest = {
const updateRequest: UpdateCredentialsParams = {
data: iamCredentials,
encrypted: false,
}
Expand All @@ -112,7 +114,7 @@ describe('Auth', () => {
})

it('Handles Set Bearer credentials request', async () => {
const updateRequest: UpdateCredentialsRequest = {
const updateRequest: UpdateCredentialsParams = {
data: bearerCredentials,
encrypted: false,
}
Expand All @@ -137,7 +139,7 @@ describe('Auth', () => {
return CONNECTION_METADATA
})

const updateRequest: UpdateCredentialsRequest = {
const updateRequest: UpdateCredentialsParams = {
data: bearerCredentials,
encrypted: false,
}
Expand All @@ -157,7 +159,7 @@ describe('Auth', () => {
throw new Error('TEST ERROR')
})

const updateRequest: UpdateCredentialsRequest = {
const updateRequest: UpdateCredentialsParams = {
data: bearerCredentials,
encrypted: false,
}
Expand All @@ -171,7 +173,7 @@ describe('Auth', () => {
})

it('Handles Bearer credentials delete request', done => {
const updateRequest: UpdateCredentialsRequest = {
const updateRequest: UpdateCredentialsParams = {
data: bearerCredentials,
encrypted: false,
}
Expand All @@ -193,7 +195,7 @@ describe('Auth', () => {
accessKeyId: 'testKey',
sessionToken: 'testSession',
}
const updateIamRequest: UpdateCredentialsRequest = {
const updateIamRequest: UpdateCredentialsParams = {
data: malformedIamCredentials as IamCredentials,
encrypted: false,
}
Expand All @@ -208,7 +210,7 @@ describe('Auth', () => {
const malformedBearerCredentials = {
token: undefined as unknown,
}
const updateBearerRequest: UpdateCredentialsRequest = {
const updateBearerRequest: UpdateCredentialsParams = {
data: malformedBearerCredentials as BearerCredentials,
encrypted: false,
}
Expand All @@ -221,7 +223,7 @@ describe('Auth', () => {

describe('Credentials provider', () => {
it('Prevents modifying IAM credentials object', async () => {
const updateIamRequest: UpdateCredentialsRequest = {
const updateIamRequest: UpdateCredentialsParams = {
data: iamCredentials,
encrypted: false,
}
Expand All @@ -239,7 +241,7 @@ describe('Auth', () => {
})

it('Prevents modifying Bearer credentials object', async () => {
const updateBearerRequest: UpdateCredentialsRequest = {
const updateBearerRequest: UpdateCredentialsParams = {
data: bearerCredentials,
encrypted: false,
}
Expand Down Expand Up @@ -273,7 +275,7 @@ describe('Auth', () => {

describe('Encrypted credentials', () => {
it('Rejects when encrypted flag is set wrong', async () => {
const updateIamRequest: UpdateCredentialsRequest = {
const updateIamRequest: UpdateCredentialsParams = {
data: iamCredentials as IamCredentials,
encrypted: true,
}
Expand All @@ -295,7 +297,7 @@ describe('Auth', () => {
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.encrypt(encryptionKey)

const updateIamRequest: UpdateCredentialsRequest = {
const updateIamRequest: UpdateCredentialsParams = {
data: jwt,
encrypted: true,
}
Expand All @@ -313,7 +315,7 @@ describe('Auth', () => {
.setProtectedHeader({ alg: 'dir', enc: 'A256GCM' })
.encrypt(encryptionKey)

const updateBearerRequest: UpdateCredentialsRequest = {
const updateBearerRequest: UpdateCredentialsParams = {
data: jwt,
encrypted: true,
}
Expand All @@ -331,7 +333,7 @@ describe('Auth', () => {
.setProtectedHeader({ alg: 'dir', enc: 'A128CBC-HS256' })
.encrypt(encryptionKey)

const updateBearerRequest: UpdateCredentialsRequest = {
const updateBearerRequest: UpdateCredentialsParams = {
data: jwt,
encrypted: true,
}
Expand All @@ -354,7 +356,7 @@ describe('Auth', () => {
.setExpirationTime(new Date().getTime() / 1000 - 70) //not allowed
.encrypt(encryptionKey)

const updateBearerRequest: UpdateCredentialsRequest = {
const updateBearerRequest: UpdateCredentialsParams = {
data: jwt,
encrypted: true,
}
Expand Down
Loading