diff --git a/patches/series b/patches/series index 61c801ae9357..3f7c5adde53b 100644 --- a/patches/series +++ b/patches/series @@ -20,3 +20,4 @@ getting-started.diff keepalive.diff clipboard.diff display-language.diff +trusted-domains.diff diff --git a/patches/trusted-domains.diff b/patches/trusted-domains.diff new file mode 100644 index 000000000000..98c012e61203 --- /dev/null +++ b/patches/trusted-domains.diff @@ -0,0 +1,49 @@ +Allow configuring trusted domains via product.json or flag. + +Index: code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts +=================================================================== +--- code-server.orig/lib/vscode/src/vs/server/node/serverEnvironmentService.ts ++++ code-server/lib/vscode/src/vs/server/node/serverEnvironmentService.ts +@@ -20,6 +20,7 @@ export const serverOptions: OptionDescri + 'disable-file-uploads': { type: 'boolean' }, + 'disable-getting-started-override': { type: 'boolean' }, + 'locale': { type: 'string' }, ++ 'link-protection-trusted-domains': { type: 'string[]' }, + + /* ----- server setup ----- */ + +@@ -108,6 +109,7 @@ export interface ServerParsedArgs { + 'disable-file-uploads'?: boolean; + 'disable-getting-started-override'?: boolean, + 'locale'?: string ++ 'link-protection-trusted-domains'?: string[], + + /* ----- server setup ----- */ + +Index: code-server/lib/vscode/src/vs/server/node/webClientServer.ts +=================================================================== +--- code-server.orig/lib/vscode/src/vs/server/node/webClientServer.ts ++++ code-server/lib/vscode/src/vs/server/node/webClientServer.ts +@@ -339,6 +339,14 @@ export class WebClientServer { + scopes: [['user:email'], ['repo']] + } : undefined; + ++ const linkProtectionTrustedDomains: string[] = []; ++ if (this._environmentService.args['link-protection-trusted-domains']) { ++ linkProtectionTrustedDomains.push(...this._environmentService.args['link-protection-trusted-domains']); ++ } ++ if (this._productService.linkProtectionTrustedDomains) { ++ linkProtectionTrustedDomains.push(...this._productService.linkProtectionTrustedDomains); ++ } ++ + const productConfiguration = { + codeServerVersion: this._productService.codeServerVersion, + rootEndpoint: rootBase, +@@ -353,6 +361,7 @@ export class WebClientServer { + telemetryEndpoint: this._productService.telemetryEndpoint, + embedderIdentifier: 'server-distro', + extensionsGallery: this._productService.extensionsGallery, ++ linkProtectionTrustedDomains, + } satisfies Partial; + + if (!this._environmentService.isBuilt) { diff --git a/src/node/cli.ts b/src/node/cli.ts index a07a18b0a260..a29ec591e0a4 100644 --- a/src/node/cli.ts +++ b/src/node/cli.ts @@ -30,7 +30,7 @@ export enum LogLevel { export class OptionalString extends Optional {} /** - * Code flags provided by the user. + * (VS) Code flags provided by the user. */ export interface UserProvidedCodeArgs { "disable-telemetry"?: boolean @@ -53,7 +53,9 @@ export interface UserProvidedCodeArgs { "disable-getting-started-override"?: boolean "disable-proxy"?: boolean "session-socket"?: string - "abs-proxy-base-path"?: string + "link-protection-trusted-domains"?: string[] + // locale is used by both VS Code and code-server. + locale?: string } /** @@ -73,7 +75,6 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs { enable?: string[] help?: boolean host?: string - locale?: string port?: number json?: boolean log?: LogLevel @@ -91,6 +92,7 @@ export interface UserProvidedArgs extends UserProvidedCodeArgs { verbose?: boolean "app-name"?: string "welcome-text"?: string + "abs-proxy-base-path"?: string /* Positional arguments. */ _?: string[] } @@ -194,6 +196,10 @@ export const options: Options> = { enable: { type: "string[]" }, help: { type: "boolean", short: "h", description: "Show this output." }, json: { type: "boolean" }, + "link-protection-trusted-domains": { + type: "string[]", + description: "Links matching a trusted domain can be opened without link protection.", + }, locale: { // The preferred way to set the locale is via the UI. type: "string", @@ -707,12 +713,16 @@ export function parseConfigFile(configFile: string, configPath: string): ConfigA // We convert the config file into a set of flags. // This is a temporary measure until we add a proper CLI library. - const configFileArgv = Object.entries(config).map(([optName, opt]) => { - if (opt === true) { - return `--${optName}` - } - return `--${optName}=${opt}` - }) + const configFileArgv = Object.entries(config) + .map(([optName, opt]) => { + if (opt === true) { + return `--${optName}` + } else if (Array.isArray(opt)) { + return opt.map((o) => `--${optName}=${o}`) + } + return `--${optName}=${opt}` + }) + .flat() const args = parse(configFileArgv, { configFile: configPath, }) diff --git a/test/unit/node/cli.test.ts b/test/unit/node/cli.test.ts index 552576fac4c9..d62edb840464 100644 --- a/test/unit/node/cli.test.ts +++ b/test/unit/node/cli.test.ts @@ -6,6 +6,7 @@ import { bindAddrFromArgs, defaultConfigFile, parse, + parseConfigFile, setDefaults, shouldOpenInExistingInstance, toCodeArgs, @@ -287,12 +288,17 @@ describe("parser", () => { }) it("should support repeatable flags", async () => { + expect(() => parse(["--proxy-domain", ""])).toThrowError(/--proxy-domain requires a value/) expect(parse(["--proxy-domain", "*.coder.com"])).toEqual({ "proxy-domain": ["*.coder.com"], }) expect(parse(["--proxy-domain", "*.coder.com", "--proxy-domain", "test.com"])).toEqual({ "proxy-domain": ["*.coder.com", "test.com"], }) + // Commas are literal, at the moment. + expect(parse(["--proxy-domain", "*.coder.com,test.com"])).toEqual({ + "proxy-domain": ["*.coder.com,test.com"], + }) }) it("should enforce cert-key with cert value or otherwise generate one", async () => { @@ -490,6 +496,20 @@ describe("parser", () => { }), ).toThrowError(expectedErrMsg) }) + it("should fail to parse invalid config", () => { + expect(() => parseConfigFile("test", "/fake-config-path")).toThrowError("invalid config: test") + }) + it("should parse repeatable options", () => { + const configContents = ` + install-extension: + - extension.number1 + - extension.number2 + ` + expect(parseConfigFile(configContents, "/fake-config-path")).toEqual({ + config: "/fake-config-path", + "install-extension": ["extension.number1", "extension.number2"], + }) + }) it("should ignore optional strings set to false", async () => { expect(parse(["--cert=false"])).toEqual({}) })