Skip to content

Commit 8918612

Browse files
author
Akash Satheesan
authored
Merge branch 'main' into vscode-1.56
2 parents 4e73c7f + 2a4c14f commit 8918612

File tree

26 files changed

+326
-213
lines changed

26 files changed

+326
-213
lines changed

.github/workflows/ci.yaml

+58
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,61 @@ jobs:
406406
with:
407407
name: release-images
408408
path: ./release-images
409+
410+
trivy-scan-image:
411+
runs-on: ubuntu-20.04
412+
needs: docker-amd64
413+
414+
steps:
415+
- name: Checkout code
416+
uses: actions/checkout@v2
417+
418+
- name: Download release images
419+
uses: actions/download-artifact@v2
420+
with:
421+
name: release-images
422+
path: ./release-images
423+
424+
- name: Run Trivy vulnerability scanner in image mode
425+
# Commit SHA for v0.0.14
426+
uses: aquasecurity/trivy-action@b38389f8efef9798810fe0c5b5096ac198cffd54
427+
with:
428+
input: "./release-images/code-server-amd64-*.tar"
429+
scan-type: "image"
430+
ignore-unfixed: true
431+
format: "template"
432+
template: "@/contrib/sarif.tpl"
433+
output: "trivy-image-results.sarif"
434+
severity: "HIGH,CRITICAL"
435+
436+
- name: Upload Trivy scan results to GitHub Security tab
437+
uses: github/codeql-action/upload-sarif@v1
438+
with:
439+
sarif_file: "trivy-image-results.sarif"
440+
441+
# We have to use two trivy jobs
442+
# because GitHub only allows
443+
# codeql/upload-sarif action per job
444+
trivy-scan-repo:
445+
runs-on: ubuntu-20.04
446+
447+
steps:
448+
- name: Checkout code
449+
uses: actions/checkout@v2
450+
451+
- name: Run Trivy vulnerability scanner in repo mode
452+
# Commit SHA for v0.0.14
453+
uses: aquasecurity/trivy-action@b38389f8efef9798810fe0c5b5096ac198cffd54
454+
with:
455+
scan-type: "fs"
456+
scan-ref: "."
457+
ignore-unfixed: true
458+
format: "template"
459+
template: "@/contrib/sarif.tpl"
460+
output: "trivy-repo-results.sarif"
461+
severity: "HIGH,CRITICAL"
462+
463+
- name: Upload Trivy scan results to GitHub Security tab
464+
uses: github/codeql-action/upload-sarif@v1
465+
with:
466+
sarif_file: "trivy-repo-results.sarif"

docs/MAINTAINING.md

+20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
- [Maintaining](#maintaining)
66
- [Workflow](#workflow)
77
- [Milestones](#milestones)
8+
- [Triage](#triage)
89
- [Project Boards](#project-boards)
10+
- [Versioning](#versioning)
911

1012
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
1113

@@ -36,10 +38,28 @@ Here are the milestones we use and how we use them:
3638

3739
With this flow, any un-assigned issues are essentially in triage state and once triaged are either "Backlog" or "Backlog Candidates". They will eventually move to "On Deck" (or be closed). Lastly, they will end up on a version milestone where they will be worked on.
3840

41+
### Triage
42+
43+
We use the following process for triaging GitHub issues:
44+
45+
1. a submitter creates an issue
46+
1. add appropriate labels
47+
1. if we need to look into it further, add "needs-investigation"
48+
1. add to milestone
49+
1. if it should be fixed soon, add to version milestone or "On Deck"
50+
1. if not urgent, add to "Backlog"
51+
1. otherwise, add to "Backlog Candidate" if it should be considered
52+
3953
### Project Boards
4054

4155
We use project boards for projects or goals that span multiple milestones.
4256

4357
Think of this as a place to put miscellaneous things (like testing, clean up stuff, etc). As a maintainer, random todos may come up here and there. This gives you a place to add notes temporarily before opening a new issue. Given that our release milestones function off of issues, we believe tasks should have dedicated issues.
4458

4559
It also gives us a way to separate the issue triage from bigger-picture, long-term work.
60+
61+
## Versioning
62+
63+
`<major.minor.patch>`
64+
65+
The code-server project follows traditional [semantic versioning](ttps://semver.org/), with the objective of minimizing major changes that break backward compatibility. We increment the patch level for all releases, except when the upstream Visual Studio Code project increments its minor version or we change the plugin API in a backward-compatible manner. In those cases, we increment the minor version rather than the patch level.

lib/vscode/.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
# These are code-server code symlinks.
2020
src/vs/base/node/proxy_agent.ts
2121
src/vs/ipc.d.ts
22+
src/vs/server/common/util.ts

lib/vscode/src/vs/server/browser/client.ts

+40-52
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import * as path from 'vs/base/common/path';
2-
import { URI } from 'vs/base/common/uri';
32
import { Options } from 'vs/ipc';
43
import { localize } from 'vs/nls';
4+
import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
5+
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
56
import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';
7+
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
68
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
79
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
810
import { ILogService } from 'vs/platform/log/common/log';
@@ -11,10 +13,18 @@ import { Registry } from 'vs/platform/registry/common/platform';
1113
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
1214
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
1315
import { TelemetryChannelClient } from 'vs/server/common/telemetry';
16+
import { getOptions } from 'vs/server/common/util';
1417
import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
1518
import 'vs/workbench/services/localizations/browser/localizationsService';
1619
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
1720

21+
/**
22+
* All client-side customization to VS Code should live in this file when
23+
* possible.
24+
*/
25+
26+
const options = getOptions<Options>();
27+
1828
class TelemetryService extends TelemetryChannelClient {
1929
public constructor(
2030
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
@@ -23,26 +33,6 @@ class TelemetryService extends TelemetryChannelClient {
2333
}
2434
}
2535

26-
/**
27-
* Remove extra slashes in a URL.
28-
*/
29-
export const normalize = (url: string, keepTrailing = false): string => {
30-
return url.replace(/\/\/+/g, '/').replace(/\/+$/, keepTrailing ? '/' : '');
31-
};
32-
33-
/**
34-
* Get options embedded in the HTML.
35-
*/
36-
export const getOptions = <T extends Options>(): T => {
37-
try {
38-
return JSON.parse(document.getElementById('coder-options')!.getAttribute('data-settings')!);
39-
} catch (error) {
40-
return {} as T;
41-
}
42-
};
43-
44-
const options = getOptions();
45-
4636
const TELEMETRY_SECTION_ID = 'telemetry';
4737
Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfiguration({
4838
'id': TELEMETRY_SECTION_ID,
@@ -173,38 +163,36 @@ export const initialize = async (services: ServiceCollection): Promise<void> =>
173163
if (theme) {
174164
localStorage.setItem('colorThemeData', theme);
175165
}
176-
};
177166

178-
export interface Query {
179-
[key: string]: string | undefined;
180-
}
181-
182-
/**
183-
* Split a string up to the delimiter. If the delimiter doesn't exist the first
184-
* item will have all the text and the second item will be an empty string.
185-
*/
186-
export const split = (str: string, delimiter: string): [string, string] => {
187-
const index = str.indexOf(delimiter);
188-
return index !== -1 ? [str.substring(0, index).trim(), str.substring(index + 1)] : [str, ''];
189-
};
167+
// Use to show or hide logout commands and menu options.
168+
const contextKeyService = (services.get(IContextKeyService) as IContextKeyService);
169+
contextKeyService.createKey('code-server.authed', options.authed);
170+
171+
// Add a logout command.
172+
const logoutEndpoint = path.join(options.base, '/logout') + `?base=${options.base}`;
173+
const LOGOUT_COMMAND_ID = 'code-server.logout';
174+
CommandsRegistry.registerCommand(
175+
LOGOUT_COMMAND_ID,
176+
() => {
177+
window.location.href = logoutEndpoint;
178+
},
179+
);
180+
181+
// Add logout to command palette.
182+
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
183+
command: {
184+
id: LOGOUT_COMMAND_ID,
185+
title: localize('logout', "Log out")
186+
},
187+
when: ContextKeyExpr.has('code-server.authed')
188+
});
190189

191-
/**
192-
* Return the URL modified with the specified query variables. It's pretty
193-
* stupid so it probably doesn't cover any edge cases. Undefined values will
194-
* unset existing values. Doesn't allow duplicates.
195-
*/
196-
export const withQuery = (url: string, replace: Query): string => {
197-
const uri = URI.parse(url);
198-
const query = { ...replace };
199-
uri.query.split('&').forEach((kv) => {
200-
const [key, value] = split(kv, '=');
201-
if (!(key in query)) {
202-
query[key] = value;
203-
}
190+
// Add logout to the (web-only) home menu.
191+
MenuRegistry.appendMenuItem(MenuId.MenubarHomeMenu, {
192+
command: {
193+
id: LOGOUT_COMMAND_ID,
194+
title: localize('logout', "Log out")
195+
},
196+
when: ContextKeyExpr.has('code-server.authed')
204197
});
205-
return uri.with({
206-
query: Object.keys(query)
207-
.filter((k) => typeof query[k] !== 'undefined')
208-
.map((k) => `${k}=${query[k]}`).join('&'),
209-
}).toString(true);
210198
};

lib/vscode/src/vs/server/common/cookie.ts

-3
This file was deleted.
+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../../src/common/util.ts

lib/vscode/src/vs/workbench/browser/parts/titlebar/menubarControl.ts

+2-28
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { registerThemingParticipant, IThemeService } from 'vs/platform/theme/com
99
import { MenuBarVisibility, getTitleBarStyle, IWindowOpenable, getMenuBarVisibility } from 'vs/platform/windows/common/windows';
1010
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1111
import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions';
12-
import { addDisposableListener, Dimension, EventType, getCookieValue } from 'vs/base/browser/dom';
12+
import { addDisposableListener, Dimension, EventType } from 'vs/base/browser/dom';
1313
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
1414
import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform';
1515
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
@@ -38,8 +38,6 @@ import { KeyCode } from 'vs/base/common/keyCodes';
3838
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
3939
import { IsWebContext } from 'vs/platform/contextkey/common/contextkeys';
4040
import { ICommandService } from 'vs/platform/commands/common/commands';
41-
import { ILogService } from 'vs/platform/log/common/log';
42-
import { Cookie } from 'vs/server/common/cookie';
4341

4442
export type IOpenRecentAction = IAction & { uri: URI, remoteAuthority?: string };
4543

@@ -303,7 +301,6 @@ export class CustomMenubarControl extends MenubarControl {
303301
private readonly _onVisibilityChange: Emitter<boolean>;
304302
private readonly _onFocusStateChange: Emitter<boolean>;
305303

306-
// NOTE@coder: add logService (used in logout)
307304
constructor(
308305
@IMenuService menuService: IMenuService,
309306
@IWorkspacesService workspacesService: IWorkspacesService,
@@ -320,8 +317,7 @@ export class CustomMenubarControl extends MenubarControl {
320317
@IThemeService private readonly themeService: IThemeService,
321318
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
322319
@IHostService hostService: IHostService,
323-
@ICommandService commandService: ICommandService,
324-
@ILogService private readonly logService: ILogService
320+
@ICommandService commandService: ICommandService
325321
) {
326322
super(menuService, workspacesService, contextKeyService, keybindingService, configurationService, labelService, updateService, storageService, notificationService, preferencesService, environmentService, accessibilityService, hostService, commandService);
327323

@@ -723,28 +719,6 @@ export class CustomMenubarControl extends MenubarControl {
723719
webNavigationActions.pop();
724720
}
725721

726-
webNavigationActions.push(new Action('logout', localize('logout', "Log out"), undefined, true,
727-
async (_event?: any) => {
728-
const COOKIE_KEY = Cookie.Key;
729-
const loginCookie = getCookieValue(COOKIE_KEY);
730-
731-
this.logService.info('Logging out of code-server');
732-
733-
if(loginCookie) {
734-
this.logService.info(`Removing cookie under ${COOKIE_KEY}`);
735-
736-
if (document && document.cookie) {
737-
// We delete the cookie by setting the expiration to a date/time in the past
738-
document.cookie = COOKIE_KEY +'=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
739-
window.location.href = '/login';
740-
} else {
741-
this.logService.warn('Could not delete cookie because document and/or document.cookie is undefined');
742-
}
743-
} else {
744-
this.logService.warn('Could not log out because we could not find cookie');
745-
}
746-
}));
747-
748722
return webNavigationActions;
749723
}
750724

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"@types/wtfnode": "^0.7.0",
5656
"@typescript-eslint/eslint-plugin": "^4.7.0",
5757
"@typescript-eslint/parser": "^4.7.0",
58-
"audit-ci": "^3.1.1",
58+
"audit-ci": "^4.0.0",
5959
"codecov": "^3.8.1",
6060
"doctoc": "^2.0.0",
6161
"eslint": "^7.7.0",

src/browser/register.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { logger } from "@coder/logger"
12
import { getOptions, normalize, logError } from "../common/util"
23

34
import "./pages/error.css"
@@ -6,19 +7,21 @@ import "./pages/login.css"
67

78
export async function registerServiceWorker(): Promise<void> {
89
const options = getOptions()
10+
logger.level = options.logLevel
11+
912
const path = normalize(`${options.csStaticBase}/dist/serviceWorker.js`)
1013
try {
1114
await navigator.serviceWorker.register(path, {
1215
scope: options.base + "/",
1316
})
14-
console.log("[Service Worker] registered")
17+
logger.info(`[Service Worker] registered`)
1518
} catch (error) {
16-
logError(`[Service Worker] registration`, error)
19+
logError(logger, `[Service Worker] registration`, error)
1720
}
1821
}
1922

2023
if (typeof navigator !== "undefined" && "serviceWorker" in navigator) {
2124
registerServiceWorker()
2225
} else {
23-
console.error(`[Service Worker] navigator is undefined`)
26+
logger.error(`[Service Worker] navigator is undefined`)
2427
}

src/common/util.ts

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
1-
import { logger, field } from "@coder/logger"
1+
/*
2+
* This file exists in two locations:
3+
* - src/common/util.ts
4+
* - lib/vscode/src/vs/server/common/util.ts
5+
* The second is a symlink to the first.
6+
*/
27

8+
/**
9+
* Base options included on every page.
10+
*/
311
export interface Options {
412
base: string
513
csStaticBase: string
@@ -69,6 +77,9 @@ export const getOptions = <T extends Options>(): T => {
6977
options = {} as T
7078
}
7179

80+
// You can also pass options in stringified form to the options query
81+
// variable. Options provided here will override the ones in the options
82+
// element.
7283
const params = new URLSearchParams(location.search)
7384
const queryOpts = params.get("options")
7485
if (queryOpts) {
@@ -78,13 +89,9 @@ export const getOptions = <T extends Options>(): T => {
7889
}
7990
}
8091

81-
logger.level = options.logLevel
82-
8392
options.base = resolveBase(options.base)
8493
options.csStaticBase = resolveBase(options.csStaticBase)
8594

86-
logger.debug("got options", field("options", options))
87-
8895
return options
8996
}
9097

@@ -113,7 +120,8 @@ export const getFirstString = (value: string | string[] | object | undefined): s
113120
return typeof value === "string" ? value : undefined
114121
}
115122

116-
export function logError(prefix: string, err: any): void {
123+
// TODO: Might make sense to add Error handling to the logger itself.
124+
export function logError(logger: { error: (msg: string) => void }, prefix: string, err: Error | string): void {
117125
if (err instanceof Error) {
118126
logger.error(`${prefix}: ${err.message} ${err.stack}`)
119127
} else {

0 commit comments

Comments
 (0)