Update dependencies and force-update qs (#6440)

* Update dependencies and force-update qs

This is mainly an attempt to get rid of as many resolutions as possible
since it seems they are unnecessary except for qs (according to yarn/npm
audit).

For qs use 6.9.7 since Express is using 6.9.6 and that matches the most
closely.

Also add overrides since this is npm's version of yarn's resolutions and
we need it for the shrinkwrap to generate with the right dependencies.

Decided to keep pinning @types/node as well although I am not sure it is
necessary.  Express is pulling in v20 types.  Since this is
development-only we only need it in resolutions.

* Run formatter

Some rules seem to have changed with the dependency updates.

* Replace deprecated bodyParser.json() usage

* Audit npm shrinkwrap as well

* Skip installing dependencies in audit

It seems the tools only require the lock files.

* Fix tests when using ipv6

* Add missing openssl dependency to flake
This commit is contained in:
Asher 2023-09-21 16:13:34 -08:00 committed by GitHub
parent 47ee7ae670
commit acc50a5d36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1050 additions and 1215 deletions

View File

@ -31,7 +31,7 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Run prettier with actionsx/prettier - name: Run prettier with actionsx/prettier
uses: actionsx/prettier@v2 uses: actionsx/prettier@v3
with: with:
args: --check --loglevel=warn . args: --check --loglevel=warn .

View File

@ -34,21 +34,12 @@ jobs:
with: with:
node-version: "18" node-version: "18"
- name: Fetch dependencies from cache - name: Audit yarn for vulnerabilities
id: cache-yarn run: yarn audit
uses: actions/cache@v3 if: success()
with:
path: "**/node_modules"
key: yarn-build-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
yarn-build-
- name: Install dependencies - name: Audit npm for vulnerabilities
if: steps.cache-yarn.outputs.cache-hit != 'true' run: npm shrinkwrap && npm audit
run: SKIP_SUBMODULE_DEPS=1 yarn --frozen-lockfile
- name: Audit for vulnerabilities
run: yarn _audit
if: success() if: success()
trivy-scan-repo: trivy-scan-repo:

View File

@ -12,7 +12,7 @@
in { in {
devShells.default = pkgs.mkShell { devShells.default = pkgs.mkShell {
nativeBuildInputs = with pkgs; [ nativeBuildInputs = with pkgs; [
nodejs yarn' python3 pkg-config git rsync jq moreutils quilt bats nodejs yarn' python3 pkg-config git rsync jq moreutils quilt bats openssl
]; ];
buildInputs = with pkgs; (lib.optionals (!stdenv.isDarwin) [ libsecret libkrb5 ] buildInputs = with pkgs; (lib.optionals (!stdenv.isDarwin) [ libsecret libkrb5 ]
++ (with xorg; [ libX11 libxkbfile ]) ++ (with xorg; [ libX11 libxkbfile ])

View File

@ -38,75 +38,62 @@
}, },
"main": "out/node/entry.js", "main": "out/node/entry.js",
"devDependencies": { "devDependencies": {
"@schemastore/package": "^0.0.6", "@schemastore/package": "^0.0.10",
"@types/compression": "^1.7.0", "@types/compression": "^1.7.3",
"@types/cookie-parser": "^1.4.2", "@types/cookie-parser": "^1.4.4",
"@types/express": "^4.17.8", "@types/express": "^4.17.17",
"@types/http-proxy": "^1.17.4", "@types/http-proxy": "1.17.7",
"@types/js-yaml": "^4.0.0", "@types/js-yaml": "^4.0.6",
"@types/node": "^18.0.0", "@types/node": "^18.0.0",
"@types/pem": "^1.9.5", "@types/pem": "^1.14.1",
"@types/proxy-from-env": "^1.0.1", "@types/proxy-from-env": "^1.0.1",
"@types/safe-compare": "^1.1.0", "@types/safe-compare": "^1.1.0",
"@types/semver": "^7.1.0", "@types/semver": "^7.5.2",
"@types/trusted-types": "^2.0.2", "@types/trusted-types": "^2.0.4",
"@types/ws": "^8.5.3", "@types/ws": "^8.5.5",
"@typescript-eslint/eslint-plugin": "^5.41.0", "@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^5.41.0", "@typescript-eslint/parser": "^6.7.2",
"audit-ci": "^6.0.0", "audit-ci": "^6.6.1",
"doctoc": "2.2.1", "doctoc": "^2.2.1",
"eslint": "^8.26.0", "eslint": "^8.49.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.5.2", "eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.28.1",
"eslint-plugin-prettier": "^4.2.1", "eslint-plugin-prettier": "^5.0.0",
"prettier": "2.8.0", "prettier": "^3.0.3",
"prettier-plugin-sh": "^0.12.8", "prettier-plugin-sh": "^0.13.1",
"ts-node": "^10.0.0", "ts-node": "^10.9.1",
"typescript": "^5.0.4" "typescript": "^5.2.2"
},
"resolutions": {
"ansi-regex": "^5.0.1",
"normalize-package-data": "^5.0.0",
"doctoc/underscore": "^1.13.1",
"doctoc/**/trim": "^1.0.0",
"postcss": "^8.2.1",
"browserslist": "^4.16.5",
"safe-buffer": "^5.1.1",
"vfile-message": "^2.0.2",
"tar": "^6.1.9",
"path-parse": "^1.0.7",
"vm2": "^3.9.11",
"follow-redirects": "^1.14.8",
"node-fetch": "^2.6.7",
"nanoid": "^3.1.31",
"minimist": "npm:minimist-lite@2.2.1",
"glob-parent": "^6.0.1",
"@types/node": "^18.0.0",
"qs": "^6.7.3"
}, },
"dependencies": { "dependencies": {
"@coder/logger": "^3.0.0", "@coder/logger": "^3.0.1",
"argon2": "0.31.0", "argon2": "^0.31.1",
"compression": "^1.7.4", "compression": "^1.7.4",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.6",
"env-paths": "^2.2.0", "env-paths": "^2.2.1",
"express": "5.0.0-alpha.8", "express": "5.0.0-alpha.8",
"http-proxy": "^1.18.0", "http-proxy": "^1.18.1",
"httpolyglot": "^0.1.2", "httpolyglot": "^0.1.2",
"i18next": "^23.2.11", "i18next": "^23.5.1",
"js-yaml": "^4.0.0", "js-yaml": "^4.1.0",
"limiter": "^2.1.0", "limiter": "^2.1.0",
"pem": "^1.14.2", "pem": "^1.14.8",
"proxy-agent": "^6.2.1", "proxy-agent": "^6.3.1",
"qs": "6.11.0", "qs": "6.9.7",
"rotating-file-stream": "^3.0.0", "rotating-file-stream": "^3.1.1",
"safe-buffer": "^5.1.1", "safe-buffer": "^5.2.1",
"safe-compare": "^1.1.4", "safe-compare": "^1.1.4",
"semver": "^7.1.3", "semver": "^7.5.4",
"ws": "^8.0.0", "ws": "^8.14.2",
"xdg-basedir": "^4.0.0" "xdg-basedir": "^4.0.0"
}, },
"resolutions": {
"@types/node": "^18.0.0",
"qs": "6.9.7"
},
"overrides": {
"qs": "6.9.7"
},
"bin": { "bin": {
"code-server": "out/node/entry.js" "code-server": "out/node/entry.js"
}, },

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />

View File

@ -46,7 +46,9 @@ button {
.card-box { .card-box {
background-color: rgb(250, 253, 258); background-color: rgb(250, 253, 258);
border-radius: 5px; border-radius: 5px;
box-shadow: rgba(60, 66, 87, 0.117647) 0px 7px 14px 0px, rgba(0, 0, 0, 0.117647) 0px 3px 6px 0px; box-shadow:
rgba(60, 66, 87, 0.117647) 0px 7px 14px 0px,
rgba(0, 0, 0, 0.117647) 0px 3px 6px 0px;
max-width: 650px; max-width: 650px;
width: 100%; width: 100%;
} }

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />

View File

@ -14,7 +14,11 @@ export enum HttpCode {
* used in the HTTP response. * used in the HTTP response.
*/ */
export class HttpError extends Error { export class HttpError extends Error {
public constructor(message: string, public readonly statusCode: HttpCode, public readonly details?: object) { public constructor(
message: string,
public readonly statusCode: HttpCode,
public readonly details?: object,
) {
super(message) super(message)
this.name = this.constructor.name this.name = this.constructor.name
} }

View File

@ -9,7 +9,10 @@ export class Heart {
private heartbeatInterval = 60000 private heartbeatInterval = 60000
public lastHeartbeat = 0 public lastHeartbeat = 0
public constructor(private readonly heartbeatPath: string, private readonly isActive: () => Promise<boolean>) { public constructor(
private readonly heartbeatPath: string,
private readonly isActive: () => Promise<boolean>,
) {
this.beat = this.beat.bind(this) this.beat = this.beat.bind(this)
this.alive = this.alive.bind(this) this.alive = this.alive.bind(this)
} }

View File

@ -1,8 +1,8 @@
import i18next, { init } from "i18next" import i18next, { init } from "i18next"
import * as en from "./locales/en.json" import * as en from "./locales/en.json"
import * as ja from "./locales/ja.json"
import * as th from "./locales/th.json" import * as th from "./locales/th.json"
import * as zhCn from "./locales/zh-cn.json" import * as zhCn from "./locales/zh-cn.json"
import * as ja from "./locales/ja.json"
init({ init({
lng: "en", lng: "en",
fallbackLng: "en", // language to use if translations in user language are not available. fallbackLng: "en", // language to use if translations in user language are not available.

View File

@ -78,7 +78,10 @@ type ChildMessage = RelaunchMessage | ChildHandshakeMessage
type ParentMessage = ParentHandshakeMessage type ParentMessage = ParentHandshakeMessage
class ProcessError extends Error { class ProcessError extends Error {
public constructor(message: string, public readonly code: number | undefined) { public constructor(
message: string,
public readonly code: number | undefined,
) {
super(message) super(message)
this.name = this.constructor.name this.name = this.constructor.name
Error.captureStackTrace(this, this.constructor) Error.captureStackTrace(this, this.constructor)

View File

@ -269,7 +269,10 @@ export class CodeServer {
export class CodeServerPage { export class CodeServerPage {
private readonly editorSelector = "div.monaco-workbench" private readonly editorSelector = "div.monaco-workbench"
constructor(private readonly codeServer: CodeServer, public readonly page: Page) { constructor(
private readonly codeServer: CodeServer,
public readonly page: Page,
) {
this.page.on("console", (message) => { this.page.on("console", (message) => {
this.codeServer.logger.debug(message.text()) this.codeServer.logger.debug(message.text())
}) })

View File

@ -92,7 +92,7 @@ describe("createApp", () => {
app.dispose() app.dispose()
} }
expect(() => masterBall()).rejects.toThrow(`listen EACCES: permission denied 127.0.0.1:${port}`) expect(() => masterBall()).rejects.toThrow("listen EACCES: permission denied")
}) })
it("should unlink a socket before listening on the socket", async () => { it("should unlink a socket before listening on the socket", async () => {

View File

@ -1,4 +1,3 @@
import * as bodyParser from "body-parser"
import * as express from "express" import * as express from "express"
import * as http from "http" import * as http from "http"
import nodeFetch from "node-fetch" import nodeFetch from "node-fetch"
@ -110,7 +109,7 @@ describe("proxy", () => {
}) })
it("should allow post bodies", async () => { it("should allow post bodies", async () => {
e.use(bodyParser.json({ strict: false })) e.use(express.json({ strict: false }))
e.post("/wsup", (req, res) => { e.post("/wsup", (req, res) => {
res.json(req.body) res.json(req.body)
}) })
@ -127,7 +126,7 @@ describe("proxy", () => {
}) })
it("should handle bad requests", async () => { it("should handle bad requests", async () => {
e.use(bodyParser.json({ strict: false })) e.use(express.json({ strict: false }))
e.post("/wsup", (req, res) => { e.post("/wsup", (req, res) => {
res.json(req.body) res.json(req.body)
}) })
@ -154,7 +153,7 @@ describe("proxy", () => {
}) })
it("should handle errors", async () => { it("should handle errors", async () => {
e.use(bodyParser.json({ strict: false })) e.use(express.json({ strict: false }))
e.post("/wsup", (req, res) => { e.post("/wsup", (req, res) => {
throw new Error("BROKEN") throw new Error("BROKEN")
}) })

View File

@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />

View File

@ -1,10 +1,10 @@
import { logger } from "@coder/logger" import { logger } from "@coder/logger"
import * as http from "http" import * as http from "http"
import { AddressInfo } from "net"
import * as path from "path" import * as path from "path"
import { ensureAddress } from "../../../src/node/app"
import { SettingsProvider, UpdateSettings } from "../../../src/node/settings" import { SettingsProvider, UpdateSettings } from "../../../src/node/settings"
import { LatestResponse, UpdateProvider } from "../../../src/node/update" import { LatestResponse, UpdateProvider } from "../../../src/node/update"
import { clean, isAddressInfo, mockLogger, tmpdir } from "../../utils/helpers" import { clean, mockLogger, tmpdir } from "../../utils/helpers"
describe("update", () => { describe("update", () => {
let version = "1.0.0" let version = "1.0.0"
@ -79,7 +79,6 @@ describe("update", () => {
} }
let _provider: UpdateProvider | undefined let _provider: UpdateProvider | undefined
let _address: string | AddressInfo | null
const provider = (): UpdateProvider => { const provider = (): UpdateProvider => {
if (!_provider) { if (!_provider) {
throw new Error("Update provider has not been created") throw new Error("Update provider has not been created")
@ -87,6 +86,7 @@ describe("update", () => {
return _provider return _provider
} }
let address = new URL("http://localhost")
beforeAll(async () => { beforeAll(async () => {
mockLogger() mockLogger()
@ -105,12 +105,13 @@ describe("update", () => {
}) })
}) })
_address = server.address() const addr = ensureAddress(server, "http")
if (!isAddressInfo(_address)) { if (typeof addr === "string") {
throw new Error("unexpected address") throw new Error("unable to run update tests with unix sockets")
} }
address = addr
_provider = new UpdateProvider(`http://${_address?.address}:${_address?.port}/latest`, _settings) address.pathname = "/latest"
_provider = new UpdateProvider(address.toString(), _settings)
}) })
afterAll(() => { afterAll(() => {
@ -220,59 +221,51 @@ describe("update", () => {
}) })
it("should reject if response has status code 500", async () => { it("should reject if response has status code 500", async () => {
if (isAddressInfo(_address)) { address.pathname = "/reject-status-code"
const mockURL = `http://${_address.address}:${_address.port}/reject-status-code` const provider = new UpdateProvider(address.toString(), settings())
const provider = new UpdateProvider(mockURL, settings()) const update = await provider.getUpdate(true)
const update = await provider.getUpdate(true)
expect(update.version).toBe("unknown") expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled() expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", { expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error", identifier: "error",
value: `${mockURL}: 500`, value: `${address.toString()}: 500`,
}) })
}
}) })
it("should reject if no location header provided", async () => { it("should reject if no location header provided", async () => {
if (isAddressInfo(_address)) { address.pathname = "/no-location-header"
const mockURL = `http://${_address.address}:${_address.port}/no-location-header` const provider = new UpdateProvider(address.toString(), settings())
const provider = new UpdateProvider(mockURL, settings()) const update = await provider.getUpdate(true)
const update = await provider.getUpdate(true)
expect(update.version).toBe("unknown") expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled() expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", { expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error", identifier: "error",
value: `received redirect with no location header`, value: `received redirect with no location header`,
}) })
}
}) })
it("should resolve the request with response.headers.location", async () => { it("should resolve the request with response.headers.location", async () => {
version = "4.1.1" version = "4.1.1"
if (isAddressInfo(_address)) { address.pathname = "/with-location-header"
const mockURL = `http://${_address.address}:${_address.port}/with-location-header` const provider = new UpdateProvider(address.toString(), settings())
const provider = new UpdateProvider(mockURL, settings()) const update = await provider.getUpdate(true)
const update = await provider.getUpdate(true)
expect(logger.error).not.toHaveBeenCalled() expect(logger.error).not.toHaveBeenCalled()
expect(update.version).toBe("4.1.1") expect(update.version).toBe("4.1.1")
}
}) })
it("should reject if more than 10 redirects", async () => { it("should reject if more than 10 redirects", async () => {
if (isAddressInfo(_address)) { address.pathname = "/redirect/11"
const mockURL = `http://${_address.address}:${_address.port}/redirect/11` const provider = new UpdateProvider(address.toString(), settings())
const provider = new UpdateProvider(mockURL, settings()) const update = await provider.getUpdate(true)
const update = await provider.getUpdate(true)
expect(update.version).toBe("unknown") expect(update.version).toBe("unknown")
expect(logger.error).toHaveBeenCalled() expect(logger.error).toHaveBeenCalled()
expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", { expect(logger.error).toHaveBeenCalledWith("Failed to get latest version", {
identifier: "error", identifier: "error",
value: `reached max redirects`, value: `reached max redirects`,
}) })
}
}) })
}) })

View File

@ -108,20 +108,6 @@ export function idleTimer(message: string, reject: (error: Error) => void, delay
} }
} }
/**
* A helper function which returns a boolean indicating whether
* the given address is AddressInfo and has .address
* and a .port property.
*/
export function isAddressInfo(address: unknown): address is net.AddressInfo {
return (
address !== null &&
typeof address !== "string" &&
(address as net.AddressInfo).port !== undefined &&
(address as net.AddressInfo).address !== undefined
)
}
/** /**
* If using a proxy, return the address of the proxy. * If using a proxy, return the address of the proxy.
* *

View File

@ -35,7 +35,7 @@ export class HttpServer {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.hs.on("error", reject) this.hs.on("error", reject)
this.hs.listen(0, "localhost", () => { this.hs.listen(0, "127.0.0.1", () => {
this.hs.off("error", reject) this.hs.off("error", reject)
resolve() resolve()

1994
yarn.lock

File diff suppressed because it is too large Load Diff