Skip to content

Add trust feature for VS Code Notebooks #12818

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

Merged
merged 12 commits into from
Jul 10, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions build/ci/vscode-python-pr-validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ stages:
'DataScience':
TestsToRun: 'testDataScience'
NeedsPythonTestReqs: true
NeedsPythonFunctionalReqs: true
'Smoke':
TestsToRun: 'testSmoke'
NeedsPythonTestReqs: true
Expand Down
43 changes: 43 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,25 @@
},
"enablement": "python.datascience.notebookeditor.canrestartNotebookkernel"
},
{
"command": "python.datascience.notebookeditor.trust",
"title": "%DataScience.trustNotebookCommandTitle%",
"category": "Python",
"icon": {
"light": "resources/light/un-trusted.svg",
"dark": "resources/dark/un-trusted.svg"
},
"enablement": "notebookEditorFocused && !python.datascience.isnotebooktrusted && python.datascience.trustfeatureenabled"
},
{
"command": "python.datascience.notebookeditor.trusted",
"title": "%DataScience.notebookIsTrusted%",
"category": "Python",
"icon": {
"light": "resources/light/trusted.svg",
"dark": "resources/dark/trusted.svg"
}
},
{
"command": "python.datascience.notebookeditor.runallcells",
"title": "%python.command.python.datascience.notebookeditor.runallcells.title%",
Expand Down Expand Up @@ -860,6 +879,18 @@
"group": "navigation",
"when": "notebookEditorFocused"
},
{
"command": "python.datascience.notebookeditor.trust",
"title": "%DataScience.trustNotebookCommandTitle%",
"group": "navigation@1",
"when": "notebookEditorFocused && !python.datascience.isnotebooktrusted && python.datascience.trustfeatureenabled"
},
{
"command": "python.datascience.notebookeditor.trusted",
"title": "%DataScience.notebookIsTrusted%",
"group": "navigation@1",
"when": "notebookEditorFocused && python.datascience.isnotebooktrusted && python.datascience.trustfeatureenabled"
},
{
"command": "python.datascience.export",
"title": "%DataScience.notebookExportAs%",
Expand Down Expand Up @@ -1138,6 +1169,18 @@
"category": "Python",
"when": "python.datascience.isnativeactive && python.datascience.featureenabled && python.datascience.isnotebooktrusted"
},
{
"command": "python.datascience.notebookeditor.trust",
"title": "%DataScience.trustNotebookCommandTitle%",
"category": "Python",
"when": "python.datascience.featureenabled && notebookEditorFocused && !python.datascience.isnotebooktrusted && python.datascience.trustfeatureenabled"
},
{
"command": "python.datascience.notebookeditor.trusted",
"title": "%DataScience.notebookIsTrusted%",
"category": "Python",
"when": "config.noExists"
},
{
"command": "python.datascience.notebookeditor.runallcells",
"title": "%python.command.python.datascience.notebookeditor.runallcells.title%",
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
"DataScience.fetchingDataViewer": "Fetching data ...",
"DataScience.noRowsInDataViewer": "No rows match current filter",
"DataScience.jupyterServer": "Jupyter Server",
"DataScience.trustNotebookCommandTitle": "Trust notebook",
"DataScience.notebookIsTrusted": "Trusted",
"DataScience.notebookIsNotTrusted": "Not Trusted",
"DataScience.noKernel": "No Kernel",
Expand Down
4 changes: 4 additions & 0 deletions resources/dark/trusted.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions resources/dark/un-trusted.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions resources/light/run-file.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions resources/light/trusted.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions resources/light/un-trusted.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/client/common/application/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,6 @@ export interface ICommandNameArgumentTypeMapping extends ICommandNameWithoutArgu
[DSCommands.OpenNotebookNonCustomEditor]: [Uri];
[DSCommands.GatherQuality]: [string];
[DSCommands.EnableLoadingWidgetsFrom3rdPartySource]: [undefined | never];
[DSCommands.TrustNotebook]: [undefined | never | Uri];
[DSCommands.TrustedNotebook]: [undefined | never];
}
2 changes: 2 additions & 0 deletions src/client/datascience/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ export namespace Commands {
export const SaveAsNotebookNonCustomEditor = 'python.datascience.notebookeditor.saveAs';
export const OpenNotebookNonCustomEditor = 'python.datascience.notebookeditor.open';
export const GatherQuality = 'python.datascience.gatherquality';
export const TrustNotebook = 'python.datascience.notebookeditor.trust';
export const TrustedNotebook = 'python.datascience.notebookeditor.trusted';
export const EnableLoadingWidgetsFrom3rdPartySource =
'python.datascience.enableLoadingWidgetScriptsFromThirdPartySource';
}
Expand Down
2 changes: 1 addition & 1 deletion src/client/datascience/context/activeEditorContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class ActiveEditorContextService implements IExtensionSingleActivationSer
.getOrCreateNotebook({ identity: activeEditor.file, getOnly: true })
.then((nb) => {
if (activeEditor === this.notebookEditorProvider.activeEditor) {
const canStart = nb && nb.status !== ServerStatus.NotStarted;
const canStart = nb && nb.status !== ServerStatus.NotStarted && activeEditor.model?.isTrusted;
this.canRestartNotebookKernelContext.set(!!canStart).ignoreErrors();
}
})
Expand Down
4 changes: 2 additions & 2 deletions src/client/datascience/export/exportUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class ExportUtil {
await this.jupyterExporter.exportToFile(cells, tempFile.filePath, false);
const newPath = path.join(tempDir.path, '.ipynb');
await this.fileSystem.copyFile(tempFile.filePath, newPath);
model = await this.notebookStorage.load(Uri.file(newPath));
model = await this.notebookStorage.get(Uri.file(newPath));
} finally {
tempFile.dispose();
tempDir.dispose();
Expand All @@ -73,7 +73,7 @@ export class ExportUtil {
}

public async removeSvgs(source: Uri) {
const model = await this.notebookStorage.load(source);
const model = await this.notebookStorage.get(source);

const newCells: ICell[] = [];
for (const cell of model.cells) {
Expand Down
48 changes: 13 additions & 35 deletions src/client/datascience/interactive-ipynb/nativeEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as path from 'path';
import {
CancellationToken,
CancellationTokenSource,
commands,
Event,
EventEmitter,
Memento,
Expand Down Expand Up @@ -98,7 +97,6 @@ import { KernelSwitcher } from '../jupyter/kernels/kernelSwitcher';
const nativeEditorDir = path.join(EXTENSION_ROOT_DIR, 'out', 'datascience-ui', 'notebook');
@injectable()
export class NativeEditor extends InteractiveBase implements INotebookEditor {
public readonly type: 'old' | 'custom' = 'custom';
public get onDidChangeViewState(): Event<void> {
return this._onDidChangeViewState.event;
}
Expand Down Expand Up @@ -140,6 +138,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
public get isDirty(): boolean {
return this.model ? this.model.isDirty : false;
}
public readonly type: 'old' | 'custom' = 'custom';
public model: Readonly<INotebookModel> | undefined;
protected savedEvent: EventEmitter<INotebookEditor> = new EventEmitter<INotebookEditor>();
protected closedEvent: EventEmitter<INotebookEditor> = new EventEmitter<INotebookEditor>();
Expand All @@ -152,6 +151,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
private startupTimer: StopWatch = new StopWatch();
private loadedAllCells: boolean = false;
private executeCancelTokens = new Set<CancellationTokenSource>();
private previouslyNotTrusted: boolean = false;

constructor(
@multiInject(IInteractiveWindowListener) listeners: IInteractiveWindowListener[],
Expand Down Expand Up @@ -227,6 +227,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
);
asyncRegistry.push(this);

asyncRegistry.push(this.trustService.onDidSetNotebookTrust(this.monitorChangesToTrust, this));
this.synchronizer.subscribeToUserActions(this, this.postMessage.bind(this));
}

Expand All @@ -251,6 +252,7 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {

// Sign up for dirty events
model.changed(this.modelChanged.bind(this));
this.previouslyNotTrusted = model.isTrusted;
}

// tslint:disable-next-line: no-any
Expand Down Expand Up @@ -596,7 +598,13 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
}
}
}

private async monitorChangesToTrust() {
if (this.previouslyNotTrusted && this.model?.isTrusted) {
this.previouslyNotTrusted = false;
// Tell UI to update main state
this.postMessage(InteractiveWindowMessages.TrustNotebookComplete).ignoreErrors();
}
}
private renameVariableExplorerHeights(name: string, updatedName: string) {
// Updates the workspace storage to reflect the updated name of the notebook
// should be called if the name of the notebook changes
Expand All @@ -612,38 +620,8 @@ export class NativeEditor extends InteractiveBase implements INotebookEditor {
}

private async launchNotebookTrustPrompt() {
const prompts = [
localize.DataScience.trustNotebook(),
localize.DataScience.doNotTrustNotebook(),
localize.DataScience.trustAllNotebooks()
];
const selection = await this.applicationShell.showErrorMessage(
localize.DataScience.launchNotebookTrustPrompt(),
...prompts
);
if (!selection) {
return;
}
if (this.model && selection === localize.DataScience.trustNotebook() && !this.model.isTrusted) {
try {
const contents = this.model.getContent();
await this.trustService.trustNotebook(this.model.file, contents);
// Update model trust
this.model.update({
source: 'user',
kind: 'updateTrust',
oldDirty: this.model.isDirty,
newDirty: this.model.isDirty,
isNotebookTrusted: true
});
// Tell UI to update main state
await this.postMessage(InteractiveWindowMessages.TrustNotebookComplete);
} catch (err) {
traceError(err);
}
} else if (selection === localize.DataScience.trustAllNotebooks()) {
// Take the user to the settings UI where they can manually turn on the alwaysTrustNotebooks setting
commands.executeCommand('workbench.action.openSettings', 'python.dataScience.alwaysTrustNotebooks');
if (this.model && !this.model.isTrusted) {
await this.commandManager.executeCommand(Commands.TrustNotebook, this.model.file);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export class NativeEditorProvider implements INotebookEditorProvider, CustomEdit
this.untitledCounter = getNextUntitledCounter(file, this.untitledCounter);

// Load our model from our storage object.
const model = await this.storage.load(file, contents, options);
const model = await this.storage.get(file, contents, options);

// Make sure to listen to events on the model
this.trackModel(model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,20 @@ export class NativeEditorStorage implements INotebookStorage {
return `${path.basename(model.file.fsPath)}-${uuid()}`;
}

public load(
public get(
file: Uri,
possibleContents?: string,
backupId?: string,
forVSCodeNotebook?: boolean
): Promise<INotebookModel>;
public load(
public get(
file: Uri,
possibleContents?: string,
// tslint:disable-next-line: unified-signatures
skipDirtyContents?: boolean,
forVSCodeNotebook?: boolean
): Promise<INotebookModel>;
public load(
public get(
file: Uri,
possibleContents?: string,
// tslint:disable-next-line: no-any
Expand Down
Loading