Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
4 changes: 2 additions & 2 deletions lib/init-action.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

703 changes: 403 additions & 300 deletions lib/start-proxy-action.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/init-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ import {
initConfig,
runDatabaseInitCluster,
} from "./init";
import { KnownLanguage } from "./languages";
import { JavaEnvVars, KnownLanguage } from "./languages";
import { getActionsLogger, Logger } from "./logging";
import {
downloadOverlayBaseDatabaseFromCache,
Expand Down Expand Up @@ -756,13 +756,13 @@ async function run(startedAt: Date) {

// Enable Java network debugging if the FF is enabled.
if (await features.getValue(Feature.JavaNetworkDebugging)) {
// Get the existing value of `JAVA_OPTS`, if any.
// Get the existing value of `JAVA_TOOL_OPTIONS`, if any.
const existingJavaToolOptions =
getOptionalEnvVar("JAVA_TOOL_OPTIONS") || "";
getOptionalEnvVar(JavaEnvVars.JAVA_TOOL_OPTIONS) || "";

// Add the network debugging options.
core.exportVariable(
"JAVA_TOOL_OPTIONS",
JavaEnvVars.JAVA_TOOL_OPTIONS,
`${existingJavaToolOptions} -Djavax.net.debug=all`,
);
}
Expand Down
8 changes: 8 additions & 0 deletions src/languages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,11 @@ export enum KnownLanguage {
rust = "rust",
swift = "swift",
}

/** Java-specific environment variable names that we may care about. */
export enum JavaEnvVars {
JAVA_HOME = "JAVA_HOME",
JAVA_TOOL_OPTIONS = "JAVA_TOOL_OPTIONS",
JDK_JAVA_OPTIONS = "JDK_JAVA_OPTIONS",
_JAVA_OPTIONS = "_JAVA_OPTIONS",
}
12 changes: 12 additions & 0 deletions src/start-proxy-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
ProxyConfig,
} from "./start-proxy";
import { generateCertificateAuthority } from "./start-proxy/ca";
import { checkProxyEnvironment } from "./start-proxy/environment";
import { checkConnections } from "./start-proxy/reachability";
import { ActionName, sendUnhandledErrorStatusReport } from "./status-report";
import * as util from "./util";
Expand Down Expand Up @@ -76,6 +77,17 @@ async function run(startedAt: Date) {
.join("\n")}`,
);

// Check the environment for any configurations which may affect the proxy.
// This is a best effort process to give us insights into potential factors
// which may affect the operation of our proxy.
try {
checkProxyEnvironment(logger, language);
} catch (err) {
logger.debug(
`Unable to inspect runner environment: ${util.getErrorMessage(err)}`,
);
}

const ca = generateCertificateAuthority(
await features.getValue(Feature.ImprovedProxyCertificates),
);
Expand Down
178 changes: 178 additions & 0 deletions src/start-proxy/environment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import * as fs from "fs";
import * as os from "os";
import path from "path";

import test, { ExecutionContext } from "ava";

import { JavaEnvVars, KnownLanguage } from "../languages";
import {
checkExpectedLogMessages,
getRecordingLogger,
LoggedMessage,
setupTests,
} from "../testing-utils";
import { withTmpDir } from "../util";

import {
checkJavaEnvVars,
checkJdkSettings,
checkProxyEnvironment,
checkProxyEnvVars,
discoverActionsJdks,
JAVA_PROXY_ENV_VARS,
ProxyEnvVars,
} from "./environment";

setupTests(test);

function assertEnvVarLogMessages(
t: ExecutionContext<any>,
envVars: string[],
messages: LoggedMessage[],
expectSet: boolean,
) {
const template = (envVar: string) =>
expectSet
? `Environment variable '${envVar}' is set to '${envVar}'`
: `Environment variable '${envVar}' is not set`;

const expected: string[] = [];

for (const envVar of envVars) {
expected.push(template(envVar));
}

checkExpectedLogMessages(t, messages, expected);
}

test("checkJavaEnvironment - none set", (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

checkJavaEnvVars(logger);
assertEnvVarLogMessages(t, JAVA_PROXY_ENV_VARS, messages, false);
});

test("checkJavaEnvironment - logs values when variables are set", (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

for (const envVar of Object.values(JavaEnvVars)) {
process.env[envVar] = envVar;
}

checkJavaEnvVars(logger);
assertEnvVarLogMessages(t, JAVA_PROXY_ENV_VARS, messages, true);
});

test("discoverActionsJdks - discovers JDK paths", (t) => {
// Clear GHA variables that may interfere with this test in CI.
for (const envVar of Object.keys(process.env)) {
if (envVar.startsWith("JAVA_HOME_")) {
delete process[envVar];
}
}

const jdk8 = "/usr/lib/jvm/temurin-8-jdk-amd64";
const jdk17 = "/usr/lib/jvm/temurin-17-jdk-amd64";
const jdk21 = "/usr/lib/jvm/temurin-21-jdk-amd64";

process.env[JavaEnvVars.JAVA_HOME] = jdk17;
process.env["JAVA_HOME_8_X64"] = jdk8;
process.env["JAVA_HOME_17_X64"] = jdk17;
process.env["JAVA_HOME_21_X64"] = jdk21;

const results = discoverActionsJdks();
t.is(results.size, 3);
t.true(results.has(jdk8));
t.true(results.has(jdk17));
t.true(results.has(jdk21));
});

test("checkJdkSettings - does not throw for an empty directory", async (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

await withTmpDir(async (tmpDir) => {
t.notThrows(() => checkJdkSettings(logger, tmpDir));
});
});

test("checkJdkSettings - finds files and logs relevant properties", async (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

await withTmpDir(async (tmpDir) => {
const dir = path.join(tmpDir, "conf");
fs.mkdirSync(dir);

const file = path.join(dir, "net.properties");
fs.writeFileSync(
file,
[
"irrelevant.property=foo",
"http.proxyHost=proxy.example.com",
"http.unrelated=bar",
].join(os.EOL),
{},
);
checkJdkSettings(logger, tmpDir);

checkExpectedLogMessages(t, messages, [
`Found '${file}'.`,
`Found 'http.proxyHost=proxy.example.com' in '${file}'`,
]);
});
});

test("checkProxyEnvVars - none set", (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

checkProxyEnvVars(logger);
assertEnvVarLogMessages(t, Object.values(ProxyEnvVars), messages, false);
});

test("checkProxyEnvVars - logs values when variables are set", (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

for (const envVar of Object.values(ProxyEnvVars)) {
process.env[envVar] = envVar;
}

for (const envVar of Object.values(ProxyEnvVars)) {
process.env[envVar] = envVar;
}

checkProxyEnvVars(logger);
assertEnvVarLogMessages(t, Object.values(ProxyEnvVars), messages, true);
});

test("checkProxyEnvironment - includes base checks for all known languages", (t) => {
for (const language of Object.values(KnownLanguage)) {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

checkProxyEnvironment(logger, language);
assertEnvVarLogMessages(t, Object.keys(ProxyEnvVars), messages, false);
}
});

test("checkProxyEnvironment - includes Java checks for Java", (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

checkProxyEnvironment(logger, KnownLanguage.java);
assertEnvVarLogMessages(t, Object.keys(ProxyEnvVars), messages, false);
assertEnvVarLogMessages(t, JAVA_PROXY_ENV_VARS, messages, false);
});

test("checkProxyEnvironment - includes language-specific checks if the language is undefined", (t) => {
const messages: LoggedMessage[] = [];
const logger = getRecordingLogger(messages);

checkProxyEnvironment(logger, undefined);
assertEnvVarLogMessages(t, Object.keys(ProxyEnvVars), messages, false);
assertEnvVarLogMessages(t, JAVA_PROXY_ENV_VARS, messages, false);
});
Loading
Loading