From 0bc96989c2c79f1310c44046151c8dc2b0e5d971 Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Mon, 22 Nov 2021 19:36:04 +0000 Subject: [PATCH 001/890] chore(deps): upgrade json-schema version to 0.4.0 (#4543) --- test/package.json | 3 ++- test/yarn.lock | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/package.json b/test/package.json index 49e4cfef7662..d50371666ba4 100644 --- a/test/package.json +++ b/test/package.json @@ -23,6 +23,7 @@ "argon2/@mapbox/node-pre-gyp/tar": "^6.1.9", "set-value": "^4.0.1", "tmpl": "^1.0.5", - "path-parse": "^1.0.7" + "path-parse": "^1.0.7", + "json-schema": "^0.4.0" } } diff --git a/test/yarn.lock b/test/yarn.lock index ebc0f3202df7..629429543253 100644 --- a/test/yarn.lock +++ b/test/yarn.lock @@ -3000,10 +3000,10 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= +json-schema@0.2.3, json-schema@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== json-stringify-safe@~5.0.1: version "5.0.1" From 65d7420ee795a30f25499beb765c4837a7c6b20e Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Mon, 22 Nov 2021 20:18:58 +0000 Subject: [PATCH 002/890] feat: add test for onLine throw error (#4542) --- test/unit/node/util.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/unit/node/util.test.ts b/test/unit/node/util.test.ts index 3a37f4a90058..45289229abda 100644 --- a/test/unit/node/util.test.ts +++ b/test/unit/node/util.test.ts @@ -447,6 +447,28 @@ describe("onLine", () => { expect(await received).toEqual(expected) }) + + describe("used with a process missing stdout ", () => { + it("should throw an error", async () => { + // Initialize a process that does not have stdout. + // "If the child was spawned with stdio set to anything + // other than 'pipe', then subprocess.stdout will be null." + // Source: https://stackoverflow.com/a/46024006/3015595 + // Other source: https://nodejs.org/api/child_process.html#child_process_subprocess_stdout + // NOTE@jsjoeio - I'm not sure if this actually happens though + // which is why I have to set proc.stdout = null + // a couple lines below. + const proc = cp.spawn("node", [], { + stdio: "ignore", + }) + const mockCallback = jest.fn() + + expect(() => util.onLine(proc, mockCallback)).toThrowError(/stdout/) + + // Cleanup + proc?.kill() + }) + }) }) describe("escapeHtml", () => { From 3d4660491aad617d2778c21489fde6376cc0dc4b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Nov 2021 11:31:35 -0700 Subject: [PATCH 003/890] chore(deps): update minor dependency updates (#4531) Co-authored-by: Renovate Bot --- .github/workflows/ci.yaml | 2 +- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ad253b6b2161..61dd82c0aaa2 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -428,7 +428,7 @@ jobs: uses: actions/checkout@v2 - name: Run Trivy vulnerability scanner in repo mode #Commit SHA for v0.0.17 - uses: aquasecurity/trivy-action@2a2157eb22c08c9a1fac99263430307b8d1bc7a2 + uses: aquasecurity/trivy-action@0769bbf0d2a77b3c15b3b57fbcdd2edd25a1c3f0 with: scan-type: "fs" scan-ref: "." diff --git a/package.json b/package.json index f3201daa7e3d..4e30b43d2960 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "eslint-plugin-import": "^2.18.2", "eslint-plugin-prettier": "^4.0.0", "prettier": "^2.2.1", - "prettier-plugin-sh": "^0.7.1", + "prettier-plugin-sh": "^0.8.0", "shellcheck": "^1.0.0", "stylelint": "^13.0.0", "stylelint-config-recommended": "^5.0.0", diff --git a/yarn.lock b/yarn.lock index 7c5a5215b303..0c008c9a97f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3441,10 +3441,10 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier-plugin-sh@^0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/prettier-plugin-sh/-/prettier-plugin-sh-0.7.1.tgz#a2d38de10e55919ea945a6e72c4815b16d6614ad" - integrity sha512-2MWRdGOSz0yf/z2kTKF1AqxDuH9MZD8faoDAz5ySGphxssi9oyM3Ys+jp7AfqsCXvGUDbRA4EJOlKS0yZKAW6w== +prettier-plugin-sh@^0.8.0: + version "0.8.1" + resolved "https://registry.yarnpkg.com/prettier-plugin-sh/-/prettier-plugin-sh-0.8.1.tgz#50698d95f2006c1b3eae570d430c3c1c05a31327" + integrity sha512-tz0g6y+ZaJF0PWaa1F7vhCv4nLgYYl2zYzYU4XJFD1McoY0oHI+l2osvXqv1s5yQdtjdlzKszN6VY7WTaw2Gqw== dependencies: mvdan-sh "^0.5.0" From 6a2740f57ec6290548263191a90698c1eb295cc0 Mon Sep 17 00:00:00 2001 From: Ben Potter Date: Mon, 29 Nov 2021 12:03:33 -0800 Subject: [PATCH 004/890] chore: add deprecation notice for --link (#4562) Co-authored-by: Joe Previte --- docs/README.md | 4 ---- docs/link.md | 4 +++- src/node/cli.ts | 8 ++++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index 58e00397e9d1..9c3ae36d707e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -56,10 +56,6 @@ code-server. We also have an in-depth [setup and configuration](https://coder.com/docs/code-server/latest/guide) guide. -## TLS and authentication (beta) - -To add TLS and authentication out of the box, use [code-server --link](https://coder.com/docs/code-server/latest/link). - ## Questions? See answers to [frequently asked diff --git a/docs/link.md b/docs/link.md index 7b21244c5ded..8bef6bb69121 100644 --- a/docs/link.md +++ b/docs/link.md @@ -1,6 +1,8 @@ # code-server --link -Run code-server with the beta flag `--link` and you'll get TLS, authentication, and a dedicated URL +> Note: This feature is no longer recommended due to instability. Stay tuned for a revised version. + +Run code-server with the flag `--link` and you'll get TLS, authentication, and a dedicated URL for accessing your IDE out of the box. ```console diff --git a/src/node/cli.ts b/src/node/cli.ts index 388cf8555178..31ad9a1c85ff 100644 --- a/src/node/cli.ts +++ b/src/node/cli.ts @@ -104,9 +104,9 @@ interface Option { description?: string /** - * If marked as beta, the option is marked as beta in help. + * If marked as deprecated, the option is marked as deprecated in help. */ - beta?: boolean + deprecated?: boolean } type OptionType = T extends boolean @@ -230,7 +230,7 @@ const options: Options> = { https://hostname-username.cdr.co at which you can easily access your code-server instance. Authorization is done via GitHub. `, - beta: true, + deprecated: true, }, } @@ -253,7 +253,7 @@ export const optionDescriptions = (): string[] => { .map((line, i) => { line = line.trim() if (i === 0) { - return " ".repeat(widths.long - k.length) + (v.beta ? "(beta) " : "") + line + return " ".repeat(widths.long - k.length) + (v.deprecated ? "(deprecated) " : "") + line } return " ".repeat(widths.long + widths.short + 6) + line }) From 62b3a6fd9f00ce182d12a357de076008f5838fd0 Mon Sep 17 00:00:00 2001 From: Teffen Date: Wed, 1 Dec 2021 19:21:52 -0500 Subject: [PATCH 005/890] Proxy path fixes (#4548) * Fix issue where HTTP error status codes are not read. * Fix issues surrounding sessions when accessed from a proxy. - Updated vscode args to match latest upstream. - Fixed issues surrounding trailing slashes affecting base paths. - Updated cookie names to better match upstream's usage, debuggability. * Bump vendor. * Update tests. * Fix issue where tests lack cookie key. Co-authored-by: Asher --- src/common/http.ts | 6 +++++- src/node/http.ts | 4 ++-- src/node/main.ts | 9 ++++++--- src/node/routes/login.ts | 11 ++++------- src/node/routes/logout.ts | 14 +++++++++----- src/node/routes/vscode.ts | 9 ++++++--- src/node/util.ts | 2 +- test/unit/common/http.test.ts | 2 +- test/utils/globalSetup.ts | 3 ++- vendor/package.json | 2 +- vendor/yarn.lock | 4 ++-- 11 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/common/http.ts b/src/common/http.ts index c08c8673b477..5709c455c842 100644 --- a/src/common/http.ts +++ b/src/common/http.ts @@ -13,8 +13,12 @@ export enum HttpCode { * used in the HTTP response. */ export class HttpError extends Error { - public constructor(message: string, public readonly status: HttpCode, public readonly details?: object) { + public constructor(message: string, public readonly statusCode: HttpCode, public readonly details?: object) { super(message) this.name = this.constructor.name } } + +export enum CookieKeys { + Session = "code-server-session", +} diff --git a/src/node/http.ts b/src/node/http.ts index 461aefc0d6b4..09f472ba91d1 100644 --- a/src/node/http.ts +++ b/src/node/http.ts @@ -6,7 +6,7 @@ import * as net from "net" import path from "path" import qs from "qs" import { Disposable } from "../common/emitter" -import { HttpCode, HttpError } from "../common/http" +import { CookieKeys, HttpCode, HttpError } from "../common/http" import { normalize } from "../common/util" import { AuthType, DefaultedArgs } from "./cli" import { version as codeServerVersion } from "./constants" @@ -93,7 +93,7 @@ export const authenticated = async (req: express.Request): Promise => { const passwordMethod = getPasswordMethod(hashedPasswordFromArgs) const isCookieValidArgs: IsCookieValidArgs = { passwordMethod, - cookieKey: sanitizeString(req.cookies.key), + cookieKey: sanitizeString(req.cookies[CookieKeys.Session]), passwordFromArgs: req.args.password || "", hashedPasswordFromArgs: req.args["hashed-password"], } diff --git a/src/node/main.ts b/src/node/main.ts index 32dd48a29410..1bda3b74bfcb 100644 --- a/src/node/main.ts +++ b/src/node/main.ts @@ -1,6 +1,6 @@ import { field, logger } from "@coder/logger" -import * as os from "os" import http from "http" +import * as os from "os" import path from "path" import { Disposable } from "../common/emitter" import { plural } from "../common/util" @@ -37,8 +37,11 @@ export const runVsCodeCli = async (args: DefaultedArgs): Promise => { try { await spawnCli({ ...args, - // For some reason VS Code takes the port as a string. - port: typeof args.port !== "undefined" ? args.port.toString() : undefined, + /** Type casting. */ + "accept-server-license-terms": true, + help: !!args.help, + version: !!args.version, + port: args.port?.toString(), }) } catch (error: any) { logger.error("Got error from VS Code", error) diff --git a/src/node/routes/login.ts b/src/node/routes/login.ts index c0b5fde889ca..dc3b594803b1 100644 --- a/src/node/routes/login.ts +++ b/src/node/routes/login.ts @@ -3,14 +3,11 @@ import { promises as fs } from "fs" import { RateLimiter as Limiter } from "limiter" import * as os from "os" import * as path from "path" +import { CookieKeys } from "../../common/http" import { rootPath } from "../constants" import { authenticated, getCookieDomain, redirect, replaceTemplates } from "../http" import { getPasswordMethod, handlePasswordValidation, humanPath, sanitizeString, escapeHtml } from "../util" -export enum Cookie { - Key = "key", -} - // RateLimiter wraps around the limiter library for logins. // It allows 2 logins every minute plus 12 logins every hour. export class RateLimiter { @@ -62,7 +59,7 @@ router.get("/", async (req, res) => { res.send(await getRoot(req)) }) -router.post("/", async (req, res) => { +router.post<{}, string, { password: string; base?: string }, { to?: string }>("/", async (req, res) => { const password = sanitizeString(req.body.password) const hashedPasswordFromArgs = req.args["hashed-password"] @@ -87,13 +84,13 @@ router.post("/", async (req, res) => { if (isPasswordValid) { // The hash does not add any actual security but we do it for // obfuscation purposes (and as a side effect it handles escaping). - res.cookie(Cookie.Key, hashedPassword, { + res.cookie(CookieKeys.Session, hashedPassword, { domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]), // Browsers do not appear to allow cookies to be set relatively so we // need to get the root path from the browser since the proxy rewrites // it out of the path. Otherwise code-server instances hosted on // separate sub-paths will clobber each other. - path: req.body.base ? path.posix.join(req.body.base, "..") : "/", + path: req.body.base ? path.posix.join(req.body.base, "..", "/") : "/", sameSite: "lax", }) diff --git a/src/node/routes/logout.ts b/src/node/routes/logout.ts index d1a19dfef286..5c8311266c43 100644 --- a/src/node/routes/logout.ts +++ b/src/node/routes/logout.ts @@ -1,17 +1,21 @@ import { Router } from "express" +import { CookieKeys } from "../../common/http" import { getCookieDomain, redirect } from "../http" -import { Cookie } from "./login" + +import { sanitizeString } from "../util" export const router = Router() -router.get("/", async (req, res) => { +router.get<{}, undefined, undefined, { base?: string; to?: string }>("/", async (req, res) => { + const path = sanitizeString(req.query.base) || "/" + const to = sanitizeString(req.query.to) || "/" + // Must use the *identical* properties used to set the cookie. - res.clearCookie(Cookie.Key, { + res.clearCookie(CookieKeys.Session, { domain: getCookieDomain(req.headers.host || "", req.args["proxy-domain"]), - path: req.query.base || "/", + path: decodeURIComponent(path), sameSite: "lax", }) - const to = (typeof req.query.to === "string" && req.query.to) || "/" return redirect(req, res, to, { to: undefined, base: undefined }) }) diff --git a/src/node/routes/vscode.ts b/src/node/routes/vscode.ts index 06272ba86b84..c9f4976554fc 100644 --- a/src/node/routes/vscode.ts +++ b/src/node/routes/vscode.ts @@ -24,7 +24,7 @@ export class CodeServerRouteWrapper { const isAuthenticated = await authenticated(req) if (!isAuthenticated) { - return redirect(req, res, "login", { + return redirect(req, res, "login/", { // req.baseUrl can be blank if already at the root. to: req.baseUrl && req.baseUrl !== "/" ? req.baseUrl : undefined, }) @@ -88,9 +88,12 @@ export class CodeServerRouteWrapper { try { this._codeServerMain = await createVSServer(null, { - connectionToken: "0000", + "connection-token": "0000", + "accept-server-license-terms": true, ...args, - // For some reason VS Code takes the port as a string. + /** Type casting. */ + help: !!args.help, + version: !!args.version, port: args.port?.toString(), }) } catch (createServerError) { diff --git a/src/node/util.ts b/src/node/util.ts index a55ae9a6d6d3..d12ba6f0c004 100644 --- a/src/node/util.ts +++ b/src/node/util.ts @@ -321,7 +321,7 @@ export async function isCookieValid({ * - greater than 0 characters * - trims whitespace */ -export function sanitizeString(str: string): string { +export function sanitizeString(str: unknown): string { // Very basic sanitization of string // Credit: https://stackoverflow.com/a/46719000/3015595 return typeof str === "string" && str.trim().length > 0 ? str.trim() : "" diff --git a/test/unit/common/http.test.ts b/test/unit/common/http.test.ts index fd49ae183b84..ba4981377498 100644 --- a/test/unit/common/http.test.ts +++ b/test/unit/common/http.test.ts @@ -19,7 +19,7 @@ describe("http", () => { const httpError = new HttpError(message, HttpCode.BadRequest) expect(httpError.message).toBe(message) - expect(httpError.status).toBe(400) + expect(httpError.statusCode).toBe(400) expect(httpError.details).toBeUndefined() }) it("should have details if provided", () => { diff --git a/test/utils/globalSetup.ts b/test/utils/globalSetup.ts index eace7f9b2d5e..7b19d882902a 100644 --- a/test/utils/globalSetup.ts +++ b/test/utils/globalSetup.ts @@ -1,4 +1,5 @@ import { Cookie } from "playwright" +import { CookieKeys } from "../../src/common/http" import { hash } from "../../src/node/util" import { PASSWORD, workspaceDir } from "./constants" import { clean } from "./helpers" @@ -27,7 +28,7 @@ export default async function () { domain: "localhost", expires: -1, httpOnly: false, - name: "key", + name: CookieKeys.Session, path: "/", sameSite: "Lax", secure: false, diff --git a/vendor/package.json b/vendor/package.json index 21a8624514bd..40fe2a2a7549 100644 --- a/vendor/package.json +++ b/vendor/package.json @@ -7,6 +7,6 @@ "postinstall": "./postinstall.sh" }, "devDependencies": { - "code-oss-dev": "cdr/vscode#a1d3f915454bb88e508c269a3c5bafb3cfa6f9f6" + "code-oss-dev": "cdr/vscode#5e0c6f3b95ed032e62c49101ae502a46c62ef202" } } diff --git a/vendor/yarn.lock b/vendor/yarn.lock index d4886aba5e91..2f6522058841 100644 --- a/vendor/yarn.lock +++ b/vendor/yarn.lock @@ -296,9 +296,9 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -code-oss-dev@cdr/vscode#a1d3f915454bb88e508c269a3c5bafb3cfa6f9f6: +code-oss-dev@cdr/vscode#5e0c6f3b95ed032e62c49101ae502a46c62ef202: version "1.61.1" - resolved "https://codeload.github.com/cdr/vscode/tar.gz/a1d3f915454bb88e508c269a3c5bafb3cfa6f9f6" + resolved "https://codeload.github.com/cdr/vscode/tar.gz/5e0c6f3b95ed032e62c49101ae502a46c62ef202" dependencies: "@microsoft/applicationinsights-web" "^2.6.4" "@vscode/sqlite3" "4.0.12" From 80f30fc42c1f1d38ec20f037c7d81167103161ed Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 6 Dec 2021 10:33:13 -0700 Subject: [PATCH 006/890] fix(deps): update dependency qs to v6.10.2 (#4581) Co-authored-by: Renovate Bot --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 4e30b43d2960..92fe003cc63d 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "pem": "^1.14.2", "proxy-agent": "^5.0.0", "proxy-from-env": "^1.1.0", - "qs": "6.10.1", + "qs": "6.10.2", "rotating-file-stream": "^3.0.0", "safe-buffer": "^5.1.1", "safe-compare": "^1.1.4", diff --git a/yarn.lock b/yarn.lock index 0c008c9a97f7..2e74db61aedf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3500,10 +3500,10 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.10.1: - version "6.10.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" - integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== +qs@6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.2.tgz#c1431bea37fc5b24c5bdbafa20f16bdf2a4b9ffe" + integrity sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw== dependencies: side-channel "^1.0.4" From d15731a57018a56554d7dd1cecdbd377c50b3c0d Mon Sep 17 00:00:00 2001 From: Joe Previte Date: Mon, 6 Dec 2021 17:58:04 +0000 Subject: [PATCH 007/890] docs: update sections around VS Code fork (#4571) * docs(CONTRIBUTING): update workflow based on vscode changes * docs(MAINTAINING): add section for syncing VS Code upstream Co-authored-by: repo-ranger[bot] <39074581+repo-ranger[bot]@users.noreply.github.com> --- docs/CONTRIBUTING.md | 21 ++++++++++----------- docs/MAINTAINING.md | 16 ++++++++++++++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index b2dc3d5f23af..0920c91c625b 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -84,32 +84,31 @@ Here are these steps you should follow to get your dev environment setup: 1. `git clone https://github.com/cdr/code-server.git` - Clone `code-server` 2. `git clone https://github.com/cdr/vscode.git` - Clone `vscode` -3. `cd vscode && git checkout code-server-v2` - checkout the branch we use (not the default) -4. `cd vscode && yarn install` - install the dependencies in the `vscode` repo -5. `cd code-server && yarn install` - install the dependencies in the `code-server` repo -6. `cd vscode && yarn link` - use `yarn` to create a symlink to the `vscode` repo (`code-oss-dev` package) -7. `cd code-server && yarn link code-oss-dev --modules-folder vendor/modules` - links your local `vscode` repo (`code-oss-dev` package) inside your local version of code-server -8. `cd code-server && yarn watch` - this will spin up code-server on localhost:8080 which you can start developing. It will live reload changes to the source. +3. `cd vscode && yarn install` - install the dependencies in the `vscode` repo +4. `cd code-server && yarn install` - install the dependencies in the `code-server` repo +5. `cd vscode && yarn link` - use `yarn` to create a symlink to the `vscode` repo (`code-oss-dev` package) +6. `cd code-server && yarn link code-oss-dev --modules-folder vendor/modules` - links your local `vscode` repo (`code-oss-dev` package) inside your local version of code-server +7. `cd code-server && yarn watch` - this will spin up code-server on localhost:8080 which you can start developing. It will live reload changes to the source. ### Updates to VS Code -If changes are made and merged into `code-server-v2` in the `cdr/vscode` repo, then you'll need to update the version in the `code-server` repo by following these steps: +If changes are made and merged into `main` in the [`cdr/vscode`](https://github.com/cdr/vscode) repo, then you'll need to update the version in the `code-server` repo by following these steps: 1. Update the package tag listed in `vendor/package.json`: ```json { "devDependencies": { - "vscode": "cdr/vscode#X.XX.X-code-server" + "vscode": "cdr/vscode#" } } ``` -1. From the code-server **project root**, run `yarn install`. +2. From the code-server **project root**, run `yarn install`. Then, test code-server locally to make sure everything works. -1. Check the Node.js version that's used by Electron (which is shipped with VS +3. Check the Node.js version that's used by Electron (which is shipped with VS Code. If necessary, update your version of Node.js to match. -1. Open a PR +4. Open a PR > Watch for updates to > `vendor/modules/code-oss-dev/src/vs/code/browser/workbench/workbench.html`. You may need to diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md index 466e6121d0ef..6a6d5cb76fec 100644 --- a/docs/MAINTAINING.md +++ b/docs/MAINTAINING.md @@ -19,6 +19,7 @@ - [Docker](#docker) - [Homebrew](#homebrew) - [npm](#npm) +- [Syncing with Upstream VS Code](#syncing-with-upstream-vs-code) - [Testing](#testing) - [Documentation](#documentation) - [Troubleshooting](#troubleshooting) @@ -126,8 +127,7 @@ the issue. ### Merge strategies -For most things, we recommend the **squash and merge** strategy. If you're -updating `lib/vscode`, we suggest using the **rebase and merge** strategy. There +For most things, we recommend the **squash and merge** strategy. There may be times where **creating a merge commit** makes sense as well. Use your best judgment. If you're unsure, you can always discuss in the PR with the team. @@ -215,6 +215,18 @@ We publish code-server as a npm package [here](https://www.npmjs.com/package/cod This is currently automated with the release process. +## Syncing with Upstream VS Code + +The VS Code portion of code-server lives under [`cdr/vscode`](https://github.com/cdr/vscode). To update VS Code for code-server, follow these steps: + +1. `git checkout -b vscode-update` - Create a new branch locally based off `main` +2. `git fetch upstream` - Fetch upstream (VS Code)'s latest `main` branch +3. `git merge upstream/main` - Merge it locally + 1. If there are merge conflicts, fix them locally +4. Open a PR merging your branch (`vscode-update`) into `main` and add the code-server review team + +Ideally, our fork stays as close to upstream as possible. See the differences between our fork and upstream [here](https://github.com/microsoft/vscode/compare/main...cdr:main). + ## Testing Our testing structure is laid out under our [Contributing docs](https://coder.com/docs/code-server/latest/CONTRIBUTING#test). From 6c9c84090efd68c612fbc679746b9b9cc9e26222 Mon Sep 17 00:00:00 2001 From: JounQin Date: Wed, 8 Dec 2021 05:39:01 +0800 Subject: [PATCH 008/890] chore: replace eslint-import-resolver-alias with eslint-import-resolver-typescript (#4546) Co-authored-by: Joe Previte --- .eslintrc.yaml | 9 +++----- package.json | 2 +- src/node/http.ts | 2 +- src/node/routes/pathProxy.ts | 2 +- src/node/wsRouter.ts | 1 + test/unit/node/proxy.test.ts | 2 +- test/unit/node/test-plugin/.eslintrc.js | 9 ++++++++ test/unit/node/test-plugin/.eslintrc.yaml | 5 ---- yarn.lock | 28 +++++++++++++++++++---- 9 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 test/unit/node/test-plugin/.eslintrc.js delete mode 100644 test/unit/node/test-plugin/.eslintrc.yaml diff --git a/.eslintrc.yaml b/.eslintrc.yaml index b579a9a24671..1bbbbd09e38e 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -36,11 +36,8 @@ rules: import/order: [error, { alphabetize: { order: "asc" }, groups: [["builtin", "external", "internal"], "parent", "sibling"] }] no-async-promise-executor: off - # This isn't a real module, just types, which apparently doesn't resolve. - import/no-unresolved: [error, { ignore: ["express-serve-static-core"] }] settings: - # Does not work with CommonJS unfortunately. - import/ignore: - - env-paths - - xdg-basedir + import/resolver: + typescript: + alwaysTryTypes: true diff --git a/package.json b/package.json index 92fe003cc63d..b031fbd4c327 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "doctoc": "^2.0.0", "eslint": "^7.7.0", "eslint-config-prettier": "^8.1.0", - "eslint-import-resolver-alias": "^1.1.2", + "eslint-import-resolver-typescript": "^2.5.0", "eslint-plugin-import": "^2.18.2", "eslint-plugin-prettier": "^4.0.0", "prettier": "^2.2.1", diff --git a/src/node/http.ts b/src/node/http.ts index 09f472ba91d1..1719aaba1ae1 100644 --- a/src/node/http.ts +++ b/src/node/http.ts @@ -4,7 +4,7 @@ import * as expressCore from "express-serve-static-core" import * as http from "http" import * as net from "net" import path from "path" -import qs from "qs" +import * as qs from "qs" import { Disposable } from "../common/emitter" import { CookieKeys, HttpCode, HttpError } from "../common/http" import { normalize } from "../common/util" diff --git a/src/node/routes/pathProxy.ts b/src/node/routes/pathProxy.ts index e32001743e19..5f4e9776d150 100644 --- a/src/node/routes/pathProxy.ts +++ b/src/node/routes/pathProxy.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express" import * as path from "path" -import qs from "qs" +import * as qs from "qs" import * as pluginapi from "../../../typings/pluginapi" import { HttpCode, HttpError } from "../../common/http" import { normalize } from "../../common/util" diff --git a/src/node/wsRouter.ts b/src/node/wsRouter.ts index d829d08213d6..0c60a5fa8b27 100644 --- a/src/node/wsRouter.ts +++ b/src/node/wsRouter.ts @@ -50,4 +50,5 @@ export function Router(): WebsocketRouter { return new WebsocketRouter() } +// eslint-disable-next-line import/no-named-as-default-member -- the typings are not updated correctly export const wss = new Websocket.Server({ noServer: true }) diff --git a/test/unit/node/proxy.test.ts b/test/unit/node/proxy.test.ts index 0861bfe840e6..55ea4367274a 100644 --- a/test/unit/node/proxy.test.ts +++ b/test/unit/node/proxy.test.ts @@ -1,4 +1,4 @@ -import bodyParser from "body-parser" +import * as bodyParser from "body-parser" import * as express from "express" import * as http from "http" import nodeFetch from "node-fetch" diff --git a/test/unit/node/test-plugin/.eslintrc.js b/test/unit/node/test-plugin/.eslintrc.js new file mode 100644 index 000000000000..3999419107b0 --- /dev/null +++ b/test/unit/node/test-plugin/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + settings: { + "import/resolver": { + typescript: { + project: __dirname, + }, + }, + }, +} diff --git a/test/unit/node/test-plugin/.eslintrc.yaml b/test/unit/node/test-plugin/.eslintrc.yaml deleted file mode 100644 index 67a20fa64112..000000000000 --- a/test/unit/node/test-plugin/.eslintrc.yaml +++ /dev/null @@ -1,5 +0,0 @@ -settings: - import/resolver: - alias: - map: - - [code-server, ./typings/pluginapi.d.ts] diff --git a/yarn.lock b/yarn.lock index 2e74db61aedf..0fafa4c90473 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1530,11 +1530,6 @@ eslint-config-prettier@^8.1.0: resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" integrity sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew== -eslint-import-resolver-alias@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz#297062890e31e4d6651eb5eba9534e1f6e68fc97" - integrity sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w== - eslint-import-resolver-node@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" @@ -1543,6 +1538,17 @@ eslint-import-resolver-node@^0.3.4: debug "^2.6.9" resolve "^1.13.1" +eslint-import-resolver-typescript@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.5.0.tgz#07661966b272d14ba97f597b51e1a588f9722f0a" + integrity sha512-qZ6e5CFr+I7K4VVhQu3M/9xGv9/YmwsEXrsm3nimw8vWaVHRDrQRp26BgCypTxBp3vUp4o5aVEJRiy0F2DFddQ== + dependencies: + debug "^4.3.1" + glob "^7.1.7" + is-glob "^4.0.1" + resolve "^1.20.0" + tsconfig-paths "^3.9.0" + eslint-module-utils@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz#b51be1e473dd0de1c5ea638e22429c2490ea8233" @@ -2036,6 +2042,18 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" From c3eb9b800e98e7b4e111ec8e021c4140af171ed9 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 7 Dec 2021 17:38:03 -0600 Subject: [PATCH 009/890] Remove excessive reloading before VS Code is ready (#4589) The watch script was reloading the web server after every extension compilation which is not necessary plus VS Code will not even be ready at that point anyway. Instead restart when the main compilation is finished. The string to match with includes a "with" because otherwise it would match "Finished compilation extensions" which is not the main compilation task where we actually need to restart the web server. I also replaced this.log with console.log because the former does not include a newline and it appears we want newlines with all these (otherwise the next log starts on the same line which looks odd). I removed the cache clean as well because the cache is meant to stay there to speed up builds. --- ci/dev/watch.ts | 63 +++++++++--------------------------------------- src/node/util.ts | 7 ------ 2 files changed, 12 insertions(+), 58 deletions(-) diff --git a/ci/dev/watch.ts b/ci/dev/watch.ts index 0bd3c5673b73..6f7291099620 100644 --- a/ci/dev/watch.ts +++ b/ci/dev/watch.ts @@ -2,7 +2,7 @@ import { spawn, fork, ChildProcess } from "child_process" import del from "del" import { promises as fs } from "fs" import * as path from "path" -import { CompilationStats, onLine, OnLineCallback, VSCodeCompileStatus } from "../../src/node/util" +import { CompilationStats, onLine, OnLineCallback } from "../../src/node/util" interface DevelopmentCompilers { [key: string]: ChildProcess | undefined @@ -52,24 +52,18 @@ class Watcher { plugins: this.paths.pluginDir ? spawn("yarn", ["build", "--watch"], { cwd: this.paths.pluginDir }) : undefined, } - private vscodeCompileStatus = VSCodeCompileStatus.Loading - public async initialize(): Promise { for (const event of ["SIGINT", "SIGTERM"]) { process.on(event, () => this.dispose(0)) } - if (!this.hasVerboseLogging) { - console.log("\n[Watcher]", "Compiler logs will be minimal. Pass --log to show all output.") - } - this.cleanFiles() for (const [processName, devProcess] of Object.entries(this.compilers)) { if (!devProcess) continue devProcess.on("exit", (code) => { - this.log(`[${processName}]`, "Terminated unexpectedly") + console.log(`[${processName}]`, "Terminated unexpectedly") this.dispose(code) }) @@ -91,33 +85,14 @@ class Watcher { //#region Line Parsers private parseVSCodeLine: OnLineCallback = (strippedLine, originalLine) => { - if (!strippedLine.includes("watch-extensions") || this.hasVerboseLogging) { - console.log("[VS Code]", originalLine) - } + if (!strippedLine.length) return + + console.log("[VS Code]", originalLine) - switch (this.vscodeCompileStatus) { - case VSCodeCompileStatus.Loading: - // Wait for watch-client since "Finished compilation" will appear multiple - // times before the client starts building. - if (strippedLine.includes("Starting 'watch-client'")) { - console.log("[VS Code] 🚧 Compiling 🚧", "(This may take a moment!)") - this.vscodeCompileStatus = VSCodeCompileStatus.Compiling - } - break - case VSCodeCompileStatus.Compiling: - if (strippedLine.includes("Finished compilation")) { - console.log("[VS Code] ✨ Finished compiling! ✨", "(Refresh your web browser ♻️)") - this.vscodeCompileStatus = VSCodeCompileStatus.Compiled - - this.emitCompilationStats() - this.reloadWebServer() - } - break - case VSCodeCompileStatus.Compiled: - console.log("[VS Code] 🔔 Finished recompiling! 🔔", "(Refresh your web browser ♻️)") - this.emitCompilationStats() - this.reloadWebServer() - break + if (strippedLine.includes("Finished compilation with")) { + console.log("[VS Code] ✨ Finished compiling! ✨", "(Refresh your web browser ♻️)") + this.emitCompilationStats() + this.reloadWebServer() } } @@ -128,7 +103,6 @@ class Watcher { if (strippedLine.includes("Watching for file changes")) { console.log("[Compiler][Code Server]", "Finished compiling!", "(Refresh your web browser ♻️)") - this.reloadWebServer() } } @@ -153,11 +127,7 @@ class Watcher { private cleanFiles(): Promise { console.log("[Watcher]", "Cleaning files from previous builds...") - return del([ - "out/**/*", - // Included because the cache can sometimes enter bad state when debugging compiled files. - ".cache/**/*", - ]) + return del(["out/**/*"]) } /** @@ -166,31 +136,22 @@ class Watcher { */ private emitCompilationStats(): Promise { const stats: CompilationStats = { - status: this.vscodeCompileStatus, lastCompiledAt: new Date(), } - this.log("Writing watcher stats...") + console.log("Writing watcher stats...") return fs.writeFile(this.paths.compilationStatsFile, JSON.stringify(stats, null, 2)) } - private log(...entries: string[]) { - process.stdout.write(entries.join(" ")) - } - private dispose(code: number | null): void { for (const [processName, devProcess] of Object.entries(this.compilers)) { - this.log(`[${processName}]`, "Killing...\n") + console.log(`[${processName}]`, "Killing...\n") devProcess?.removeAllListeners() devProcess?.kill() } process.exit(typeof code === "number" ? code : 0) } - private get hasVerboseLogging() { - return process.argv.includes("--log") - } - //#endregion } diff --git a/src/node/util.ts b/src/node/util.ts index d12ba6f0c004..24cd8b30efc0 100644 --- a/src/node/util.ts +++ b/src/node/util.ts @@ -524,14 +524,7 @@ export const loadAMDModule = async (amdPath: string, exportName: string): Pro return module[exportName] as T } -export const enum VSCodeCompileStatus { - Loading = "Loading", - Compiling = "Compiling", - Compiled = "Compiled", -} - export interface CompilationStats { - status: VSCodeCompileStatus lastCompiledAt: Date } From 9d9f3a41ab2b5fe57b8b0431392ec6c3a6690759 Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 7 Dec 2021 18:20:57 -0600 Subject: [PATCH 010/890] Fix spawning code-server within code-server (#4590) * Remove extra VS Code CLI spawn We already spawn VS Code's CLI when necessary in the lines below. Having the CLI spawn unconditionally when in a VS Code environment makes it impossible to run code-server within code-server (for example to develop it). * Update VS Code This sanitizes our environment variables so code-server does not always think it is a child spawn. Fixes https://github.com/cdr/code-server/issues/4519. --- src/node/entry.ts | 21 +-------------------- vendor/package.json | 2 +- vendor/yarn.lock | 4 ++-- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/src/node/entry.ts b/src/node/entry.ts index 685f62f36149..27b76f4f3886 100644 --- a/src/node/entry.ts +++ b/src/node/entry.ts @@ -1,32 +1,13 @@ import { logger } from "@coder/logger" import { optionDescriptions, parse, readConfigFile, setDefaults, shouldOpenInExistingInstance } from "./cli" -import { commit, pkgName, version } from "./constants" +import { commit, version } from "./constants" import { openInExistingInstance, runCodeServer, runVsCodeCli, shouldSpawnCliProcess } from "./main" import { monkeyPatchProxyProtocols } from "./proxy_agent" -import { loadAMDModule } from "./util" import { isChild, wrapper } from "./wrapper" -const cliPipe = process.env["VSCODE_IPC_HOOK_CLI"] as string -const cliCommand = process.env["VSCODE_CLIENT_COMMAND"] as string - async function entry(): Promise { monkeyPatchProxyProtocols() - if (cliPipe || cliCommand) { - const remoteAgentMain = await loadAMDModule("vs/server/remoteCli", "main") - - remoteAgentMain( - { - productName: pkgName, - version, - commit, - executableName: pkgName, - }, - process.argv.slice(2), - ) - return - } - // There's no need to check flags like --help or to spawn in an existing // instance for the child process because these would have already happened in // the parent and the child wouldn't have been spawned. We also get the diff --git a/vendor/package.json b/vendor/package.json index 40fe2a2a7549..12e95f6299bb 100644 --- a/vendor/package.json +++ b/vendor/package.json @@ -7,6 +7,6 @@ "postinstall": "./postinstall.sh" }, "devDependencies": { - "code-oss-dev": "cdr/vscode#5e0c6f3b95ed032e62c49101ae502a46c62ef202" + "code-oss-dev": "cdr/vscode#c2a251c6afaa13fbebf97fcd8a68192f8cf46031" } } diff --git a/vendor/yarn.lock b/vendor/yarn.lock index 2f6522058841..4a8833afcde3 100644 --- a/vendor/yarn.lock +++ b/vendor/yarn.lock @@ -296,9 +296,9 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" -code-oss-dev@cdr/vscode#5e0c6f3b95ed032e62c49101ae502a46c62ef202: +code-oss-dev@cdr/vscode#c2a251c6afaa13fbebf97fcd8a68192f8cf46031: version "1.61.1" - resolved "https://codeload.github.com/cdr/vscode/tar.gz/5e0c6f3b95ed032e62c49101ae502a46c62ef202" + resolved "https://codeload.github.com/cdr/vscode/tar.gz/c2a251c6afaa13fbebf97fcd8a68192f8cf46031" dependencies: "@microsoft/applicationinsights-web" "^2.6.4" "@vscode/sqlite3" "4.0.12" From 4b4ec37880b69d89faf8ec780d20471ee82a288b Mon Sep 17 00:00:00 2001 From: Asher Date: Wed, 8 Dec 2021 15:52:15 -0600 Subject: [PATCH 011/890] Fix relative paths (#4594) * Add tests for relativeRoot * Remove path.posix.join Since this is for file system paths it feels incorrect to use it on URL paths as they are different in many ways. * Rewrite cookie path logic Before we relied on the client to resolve the base given to it by the backend against the path. Instead have the client pass that information along so we can resolve it on the backend. This means the client has to do less work. * Do not remove out directory before watch This is re-used for incremental compilation. Also remove del since that was the only use (and we can use fs.rmdir in the future if we need something like this). * Remove unused function resolveBase --- ci/dev/watch.ts | 12 ------- package.json | 1 - src/browser/pages/login.html | 7 ++-- src/common/util.ts | 21 ++++-------- src/node/http.ts | 57 ++++++++++++++++++++++++++++---- src/node/routes/login.ts | 12 ++----- src/node/routes/logout.ts | 15 +++------ src/node/routes/vscode.ts | 2 +- src/node/util.ts | 2 +- test/unit/common/util.test.ts | 36 -------------------- test/unit/node/http.test.ts | 11 +++++++ vendor/package.json | 2 +- vendor/yarn.lock | 4 +-- yarn.lock | 62 +++++------------------------------ 14 files changed, 91 insertions(+), 153 deletions(-) create mode 100644 test/unit/node/http.test.ts diff --git a/ci/dev/watch.ts b/ci/dev/watch.ts index 6f7291099620..8ed59c4230fc 100644 --- a/ci/dev/watch.ts +++ b/ci/dev/watch.ts @@ -1,5 +1,4 @@ import { spawn, fork, ChildProcess } from "child_process" -import del from "del" import { promises as fs } from "fs" import * as path from "path" import { CompilationStats, onLine, OnLineCallback } from "../../src/node/util" @@ -57,8 +56,6 @@ class Watcher { process.on(event, () => this.dispose(0)) } - this.cleanFiles() - for (const [processName, devProcess] of Object.entries(this.compilers)) { if (!devProcess) continue @@ -121,15 +118,6 @@ class Watcher { //#region Utilities - /** - * Cleans files from previous builds. - */ - private cleanFiles(): Promise { - console.log("[Watcher]", "Cleaning files from previous builds...") - - return del(["out/**/*"]) - } - /** * Emits a file containing compilation data. * This is especially useful when Express needs to determine if VS Code is still compiling. diff --git a/package.json b/package.json index b031fbd4c327..39eb0226d660 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "@typescript-eslint/parser": "^5.0.0", "audit-ci": "^5.0.0", "codecov": "^3.8.3", - "del": "^6.0.0", "doctoc": "^2.0.0", "eslint": "^7.7.0", "eslint-config-prettier": "^8.1.0", diff --git a/src/browser/pages/login.html b/src/browser/pages/login.html index 75aa86dc2523..6149ecf11cd6 100644 --- a/src/browser/pages/login.html +++ b/src/browser/pages/login.html @@ -30,7 +30,8 @@

Welcome to code-server