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

Switch to webview-based sign-in flow #2382

Merged
merged 3 commits into from
Nov 25, 2024

Conversation

pkukielka
Copy link
Contributor

@pkukielka pkukielka commented Oct 3, 2024

@pkukielka pkukielka changed the title Switch to webview-based sign-iin flow Switch to webview-based sign-in flow Oct 3, 2024
@pkukielka pkukielka marked this pull request as draft October 3, 2024 15:02
Copy link
Contributor

@mkondratek mkondratek left a comment

Choose a reason for hiding this comment

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

in general looks good - I will try it in the morning 🌅

import com.sourcegraph.cody.telemetry.TelemetryV2
import com.sourcegraph.cody.vscode.InlineCompletionTriggerKind
import com.sourcegraph.utils.CodyEditorUtil

class CodyDocumentListener(val project: Project) : BulkAwareDocumentListener {

// TODO: Looks like this functionality is broken after the migration to webview
Copy link
Contributor

@mkondratek mkondratek Oct 3, 2024

Choose a reason for hiding this comment

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

  • let us have a linear issue for this one

codyAccountManager.getAccounts().forEach { oldAccount ->
val token = codyAccountManager.getTokenForAccount(oldAccount)
if (token != null) {
CodyAccount(oldAccount.server).storeToken(token)
Copy link
Contributor

Choose a reason for hiding this comment

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

nice

val id: String,
val username: String,
val displayName: String?,
val avatarURL: String?
Copy link
Contributor

Choose a reason for hiding this comment

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

we do not use avatarURL anymore - I think we can remove it

Comment on lines +133 to +154
@JsonRequest("secrets/get")
fun secrets_get(params: Secrets_GetParams): CompletableFuture<String?> {
return CompletableFuture.completedFuture(
CodyAccount(SourcegraphServerPath(params.key)).getToken())
}

@JsonRequest("secrets/store")
fun secrets_store(params: Secrets_StoreParams): CompletableFuture<Null?> {
CodyAccount(SourcegraphServerPath(params.key)).storeToken(params.value)
return CompletableFuture.completedFuture(null)
}

@JsonRequest("secrets/delete")
fun secrets_delete(params: Secrets_DeleteParams): CompletableFuture<Null?> {
CodyAccount(SourcegraphServerPath(params.key)).storeToken(null)
return CompletableFuture.completedFuture(null)
}

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe a stupid question but... is it safe? are there any security issues? would the secrets be present in the trace logs?

Copy link
Contributor

Choose a reason for hiding this comment

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

We log the secrets in the agent trace, not the log. You have to set an extra environment variable to turn on that level of logging... I think it should be fine.

We already log tokens in that file today... the ExtensionConfiguration message from JetBrains to Agent has the token in it... see build/sourcegraph/cody-agent-trace.json after a debugging session.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is a s Dominic said :)

@@ -79,15 +64,4 @@ public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
notification.addAction(neverShowAgainAction);
Notifications.Bus.notify(notification);
}

private void showMissingTokenNotification() {
Copy link
Contributor

Choose a reason for hiding this comment

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

btw, I wonder... what if the token expires (or is removed)? 🤔 what will happen (with chat, with autocomplete)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will test this scenario today. In general I think we should then (if user try to call some action explicitly) show cody panel, and it should be showing login panel.

Copy link
Contributor

Choose a reason for hiding this comment

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

By the way, VSCode has various APIs for showing views, we don't implement them. If we need to show the view, we should see if the extension is trying to do it anyway. Maybe we just need to implement a couple of those methods/properties in the VSCode shim.

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we want to keep this action? I know it is possible to export chats from History tab in the webview. Simply, this action is an actual jetbrains action and can be searched for and run from anywhere

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, for now we should keep this, and Explain, etc.

It would be a nice cleanup project later to ingest the VSCode package.json and consider wiring up those commands automatically--or at least linting that we have them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, I reverted that changes.

@dominiccooney dominiccooney self-requested a review October 4, 2024 00:41
private val cardPanel = JPanel(cardLayout)
val allContentPanel: JComponent = JPanel(GridLayout(1, 1))
val allContentPanel: JComponent = JPanel(CardLayout())
private val mainPanel = JPanel(GridBagLayout())
Copy link
Contributor

Choose a reason for hiding this comment

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

We were using the cardlayout to swap between the loading, login and onboarding components.

We can't put the webview in a CardLayout because JetBrains remote doesn't render it, so we are swapping the components.

But now there are only two components to swap: Loading and webview. So we don't need this panel anymore.

Let's just have allContentPanel with whatever trivial layout (GridLayout(1,1) etc.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So this is weird, because I tried to simplify it at the start but it was not working without CardLayout.
But maybe it was error on my side, I will check again :)

}

@JsonRequest("secrets/store")
fun secrets_store(params: Secrets_StoreParams): CompletableFuture<Null?> {
Copy link
Contributor

Choose a reason for hiding this comment

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

A nullable null... Why not a nullable nullable null 🤔


@JsonNotification("window/didChangeContext")
fun window_didChangeContext(params: Window_DidChangeContextParams) {
println(params)
Copy link
Contributor

@dominiccooney dominiccooney Oct 4, 2024

Choose a reason for hiding this comment

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

Let's not spam the console. Info logging it might be fine.

Is this, in fact, important for refreshing the status bar icon? "cody.activated" will be true when the extension thinks it is good to go.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, refreshing status icon bar is part I/ know I missed but I forget to add it at the end.
Thanks, I will add it now!

@@ -0,0 +1,101 @@
package com.sourcegraph.cody.auth.depracated
Copy link
Contributor

Choose a reason for hiding this comment

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

Spelling: deprecated


@RequiresEdt
internal fun updateAccountToken(account: DeprecatedCodyAccount, newToken: String) {
service<DeprecatedCodyPersistentAccounts>().accounts = (getAccounts() - account) + account
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems tricky, maybe the method should be called addOrUpdateAccountToken or something?

@@ -172,7 +172,7 @@ class CodyAutocompleteManager {

val textDocument: TextDocument = IntelliJTextDocument(editor, project)

if (isTriggeredExplicitly && CodyAuthenticationManager.getInstance().hasNoActiveAccount()) {
if (isTriggeredExplicitly && !CodyAccount.hasActiveAccount()) {
HintManager.getInstance().showErrorHint(editor, "Cody: Sign in to use autocomplete")
Copy link
Contributor

Choose a reason for hiding this comment

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

Ugh, we should link to the sign in panel here! Maybe add a TODO?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I think we should just show it.
I will do the changes, thanks!

@@ -1,8 +0,0 @@
package com.sourcegraph.cody.chat.actions
Copy link
Contributor

Choose a reason for hiding this comment

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

This too, I believe we should keep these commands.

@@ -12,8 +12,7 @@ class NewChatAction : DumbAwareEDTAction() {
}

override fun update(event: AnActionEvent) {
val hasActiveAccount = CodyAuthenticationManager.getInstance().hasActiveAccount()
event.presentation.isEnabled = hasActiveAccount
event.presentation.isEnabled = CodyAccount.hasActiveAccount()
Copy link
Contributor

Choose a reason for hiding this comment

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

This CodyAccount.hasActiveAccount, we should be using the flag we got from window/didChangeContext "cody.activated" instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree in principle, but it is not as simple.
I need to also know account, in particular to be able to check if it's enterprise/pro/free, which in turn I need to properly render LLM selection in edit window.
But now I think maybe we should add additional flag to the model, and avoid this problem in the first place.
It would allow us to remove quite a bit of code on the jetbrains side.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK. Let's work out a practical split to get this landed, because there's a lot of great cleanup here. And we can smooth out the details later.

I agree for chat/models returning the models with the flag sounds good.

I tend to disagree in the specific case of NewChatAction, all we need to know is whether we have an active account. But let's land this first and take a fresh look at account type dependencies after this change is done.

RunOnceUtil.runOnceForProject(project, "CodyMigrateChatHistory-v2") {
ChatHistoryMigration.migrate(project)
}
RunOnceUtil.runOnceForProject(project, "AccountsToCodyMigration") {
AccountsMigration.migrate()
Copy link
Contributor

Choose a reason for hiding this comment

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

Just curious but are these guaranteed to run in this order? Is it important?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AFAIR their are, this code is synchronous.

Copy link
Contributor

@dominiccooney dominiccooney left a comment

Choose a reason for hiding this comment

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

Feedback inline, please take a look.

Approving to unblock since you have multiple sides to land.

We can go further than this, I think, by listening to window/didChangeContext and hooking a notification to the AuthStatus observer, but we can work on those in follow up patches if it is easier.

println(params)
}

@JsonNotification("globalStorage/didChange")
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's not sniff global storage for this. We should be listening to the configuration observable and pushing a semantic, application-level message to the IDE.

@pkukielka pkukielka force-pushed the pkukielka/switch-to-webview-signin-panel branch 2 times, most recently from 7a32f34 to a856cfd Compare October 16, 2024 14:34
@pkukielka pkukielka marked this pull request as ready for review October 16, 2024 15:15
@pkukielka pkukielka force-pushed the pkukielka/switch-to-webview-signin-panel branch 2 times, most recently from 1aaddb9 to 3a8922f Compare October 17, 2024 09:02
if ((command == "auth" && decodedJson.get("authKind")?.asString == "signout") ||
(isCommand && id == "cody.auth.signout")) {
CodyAuthenticationManager.getInstance().setActiveAccount(null)
} else if (isCommand && id == "cody.auth.switchAccount") {
Copy link
Contributor

Choose a reason for hiding this comment

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

cody.auth.switchAccount - we do not handle this command now 😕

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because it shouldn't handled by JetBrains anymore.
JetBrains is now only responsible for storing the tokens in the secure store.
Other than that all account management is done by Cody and we just receive notifications about it.

import com.sourcegraph.cody.telemetry.TelemetryV2
import com.sourcegraph.cody.vscode.InlineCompletionTriggerKind
import com.sourcegraph.utils.CodyEditorUtil

class CodyDocumentListener(val project: Project) : BulkAwareDocumentListener {

// TODO: Looks like this functionality is broken after the migration to webview
Copy link
Contributor

Choose a reason for hiding this comment

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

is it still broken or did you manage fix it? if it need more attention can you pls create an issue for that? 🙏

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's still broken, fix will be a bit more involved, I linked an linear issue

pkukielka added a commit to sourcegraph/cody that referenced this pull request Oct 17, 2024
## Changes

I've added `cody.serverEndpoint` context variable, which on the clients
side is received through `window/didChangeContext` notification. We need
it on the jetbrains side in few places, e.g. when we are checking if
current account is a dotcom account.

I think it might be better idea to replace this with a dedicated
endpoint, but I'm not sure if `cody.activated` is currently used
anywhere?
@dominiccooney @sqs WDYT?



## Test plan

Full QA with sourcegraph/jetbrains#2382 is
needed.
It does not change anything on the Cody side.
@pkukielka pkukielka force-pushed the pkukielka/switch-to-webview-signin-panel branch from 3f3603d to 5b24246 Compare November 25, 2024 12:50
@mkondratek
Copy link
Contributor

image

🚀

@pkukielka pkukielka force-pushed the pkukielka/switch-to-webview-signin-panel branch from 5b24246 to 39e8bce Compare November 25, 2024 14:19
pkukielka added a commit to sourcegraph/cody that referenced this pull request Nov 25, 2024
## Changes

That PR:
1. Fixes webview crashes when switching accounts with Account tab open
2. Add `Switch Account` button on the Accounts tab when
`accountSwitchingInWebview` capability is enabled in client.

## Test plan

Testing with jetbrains `main`:

**Fixes https://linear.app/sourcegraph/issue/QA-150**

1. Open Accounts tab
3. Click Cody icon, then `Manage Accounts`
4. Switch the account 
5. Account tab should re-render properly (after a 1-2s delay) showing
new account details

**Testing with jetbrains [migrated to webview account
management](sourcegraph/jetbrains#2382

Account switching:

1. Open Accounts tab
2. Click Switch Account
3. Select account you want to switch to from the list
4. Account tab should re-render properly (after a 1-2s delay) showing
new account details

Signing out:

1. Open Accounts tab
2. Click Sign Out
3. You should be moved to the Sign In panel

Account adding:

1. Open Accounts tab
2. Click 'Switch Account', and then 'Add another account'
3. Type url of your endpoint
4. You should be redirected to the web page to confirm adding the token
5. Account should be added and displayed as active

Note: If wrong endpoint is provided web redirection will fail, but no
error is displayed in the UI.
This definitely can be improved.

Account adding with token:

1. Open Accounts tab
2. Click 'Switch Account', and then 'Add another account'
3. Type url of your endpoint
4. Click 'Access Token (optional)'
5. Type incorrect access token and click 'Add and Switch'
6. You should get error saying `Invalid access token.`
7. Type correct access token and click 'Add and Switch'
9. Account should be added and displayed as active


![image](https://github.com/user-attachments/assets/cbd9e85d-8075-45ec-a4ba-2b3a68c07fdb)

![image](https://github.com/user-attachments/assets/10b6d94f-c15d-4fe3-ae70-5b968bb8d251)

![image](https://github.com/user-attachments/assets/0d617e8b-0cc4-48d2-98b7-8e5d548f3f6c)

![image](https://github.com/user-attachments/assets/0ad531f2-5880-4d7a-a66d-31abc2112a79)
@pkukielka pkukielka merged commit e07fe78 into main Nov 25, 2024
6 of 7 checks passed
@pkukielka pkukielka deleted the pkukielka/switch-to-webview-signin-panel branch November 25, 2024 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants