Skip to content

Commit 41f28f4

Browse files
committed
fix(sidecar): close identity and child env gaps
1 parent 612b1a7 commit 41f28f4

17 files changed

Lines changed: 167 additions & 40 deletions

File tree

apps/daemon/src/sidecar/payload-desktop-handoff.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ import {
2020
type LauncherRuntimeDescriptor,
2121
type LauncherVersionPointer,
2222
} from "@open-design/launcher-proto";
23-
import { releaseChannelFromNamespace, releaseChannelFromVersion } from "@open-design/release";
23+
import { releaseChannelFromIdentity } from "@open-design/release";
2424
import {
2525
readJsonFile,
2626
writeJsonFile,
2727
} from "@open-design/sidecar";
2828
import {
29+
OPEN_DESIGN_RUNTIME_DEFAULTS,
2930
OPEN_DESIGN_RUNTIME_SOURCES as SIDECAR_SOURCES,
3031
OPEN_DESIGN_SERVICES as APP_KEYS,
3132
type OpenDesignRuntimeSource as SidecarSource,
@@ -267,8 +268,11 @@ export async function prepareLegacyPayloadDesktopHandoff(options: {
267268
} catch {
268269
return { kind: "none", reason: "invalid-launcher-state" };
269270
}
270-
const channel = releaseChannelFromVersion(appVersion)
271-
?? releaseChannelFromNamespace(options.namespace, "default")
271+
const channel = releaseChannelFromIdentity(
272+
appVersion,
273+
options.namespace,
274+
OPEN_DESIGN_RUNTIME_DEFAULTS.namespace,
275+
)
272276
?? "stable";
273277
const launcherPaths = resolveLauncherPaths({
274278
channel,

apps/packaged/src/control.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import {
22
createOpenDesignRuntimeProjection,
3+
OPEN_DESIGN_RUNTIME_DEFAULTS,
34
OPEN_DESIGN_RUNTIME_MODES,
45
OPEN_DESIGN_RUNTIME_SOURCES,
56
type OpenDesignRuntimeContext,
67
} from "@open-design/contracts/runtime/sidecars";
7-
import { releaseChannelFromVersion } from "@open-design/release";
8+
import { releaseChannelFromIdentity } from "@open-design/release";
89
import { bootstrapControlPlane, type SidecarControlPlane } from "@open-design/sidecar/control";
910

1011
import type { PackagedNamespacePaths } from "./paths.js";
@@ -15,7 +16,11 @@ export function createPackagedControl(
1516
namespace: string,
1617
paths: PackagedNamespacePaths,
1718
): { control: SidecarControlPlane; runtime: OpenDesignRuntimeContext } {
18-
const channel = appVersion == null ? "local" : releaseChannelFromVersion(appVersion) ?? "local";
19+
const channel = releaseChannelFromIdentity(
20+
appVersion,
21+
namespace,
22+
OPEN_DESIGN_RUNTIME_DEFAULTS.namespace,
23+
) ?? "local";
1924
const projection = createOpenDesignRuntimeProjection(
2025
OPEN_DESIGN_RUNTIME_MODES.RUNTIME,
2126
OPEN_DESIGN_RUNTIME_SOURCES.PACKAGED,

apps/packaged/src/launcher-runtime.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
type LauncherAttemptDescriptor,
2323
type LauncherTargetSelection,
2424
} from "@open-design/launcher-proto";
25-
import { releaseChannelFromNamespace, releaseChannelFromVersion } from "@open-design/release";
25+
import { releaseChannelFromIdentity } from "@open-design/release";
26+
import { OPEN_DESIGN_RUNTIME_DEFAULTS } from "@open-design/contracts/runtime/sidecars";
2627

2728
import type { PackagedConfig, PackagedWebOutputMode, RawPackagedConfig } from "./config.js";
2829
import type { LauncherExistingDesktopGateResult } from "./launcher-after-quit.js";
@@ -107,8 +108,11 @@ async function pathExists(path: string): Promise<boolean> {
107108
}
108109

109110
function inferLauncherChannel(config: Pick<PackagedConfig, "appVersion" | "namespace">): LauncherChannel {
110-
return releaseChannelFromVersion(config.appVersion)
111-
?? releaseChannelFromNamespace(config.namespace, "default")
111+
return releaseChannelFromIdentity(
112+
config.appVersion,
113+
config.namespace,
114+
OPEN_DESIGN_RUNTIME_DEFAULTS.namespace,
115+
)
112116
?? "stable";
113117
}
114118

apps/packaged/src/window-title.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import {
2-
releaseChannelFromNamespace,
3-
releaseChannelFromVersion,
2+
releaseChannelFromIdentity,
43
releaseInstallIdentity,
54
} from "@open-design/release";
5+
import { OPEN_DESIGN_RUNTIME_DEFAULTS } from "@open-design/contracts/runtime/sidecars";
66

77
const DEFAULT_WINDOW_TITLE = "Open Design";
88

99
export function resolvePackagedWindowTitle(config: { appVersion: string | null; namespace: string }): string {
10-
const channel =
11-
releaseChannelFromVersion(config.appVersion) ??
12-
releaseChannelFromNamespace(config.namespace);
10+
const channel = releaseChannelFromIdentity(
11+
config.appVersion,
12+
config.namespace,
13+
OPEN_DESIGN_RUNTIME_DEFAULTS.namespace,
14+
);
1315
return channel == null ? DEFAULT_WINDOW_TITLE : releaseInstallIdentity(channel).productName;
1416
}

apps/packaged/tests/identity.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ describe("packaged identity markers", () => {
5151
expect(result.runtime).toMatchObject(result.control.scope);
5252
});
5353

54+
it.each([
55+
{ appVersion: "1.2.3", channel: "stable", namespace: "default" },
56+
{ appVersion: "1.2.3", channel: "stable", namespace: "release-stable" },
57+
{ appVersion: null, channel: "beta", namespace: "release-beta-linux" },
58+
] as const)(
59+
"resolves $channel control identity for version=$appVersion namespace=$namespace",
60+
({ appVersion, channel, namespace }) => {
61+
const paths = fakePaths(join(tmpdir(), `od-packaged-control-${process.pid}-${namespace}`));
62+
const result = createPackagedControl(appVersion, 0, namespace, paths);
63+
64+
expect(result.control.scope).toEqual({ channel, generation: 0, namespace });
65+
expect(result.runtime).toMatchObject(result.control.scope);
66+
},
67+
);
68+
5469
it("can write and close the desktop identity shape at the headless marker path", async () => {
5570
const root = join(tmpdir(), `od-packaged-identity-${process.pid}-${Date.now()}`);
5671
const paths = fakePaths(root);

e2e/lib/vitest/packaged-win-identity.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import {
2-
releaseChannelFromNamespace,
3-
releaseChannelFromVersion,
2+
releaseChannelFromIdentity,
43
releaseInstallIdentity,
54
} from "@open-design/release";
5+
import { OPEN_DESIGN_RUNTIME_DEFAULTS } from "@open-design/contracts/runtime/sidecars";
66

77
export { releaseAppVersionArgs } from "./packaged-release-version.js";
88

@@ -20,8 +20,11 @@ export function resolvePackagedWinInstallIdentity(options: {
2020
releaseVersion: string | null | undefined;
2121
}): PackagedWinInstallIdentity {
2222
const namespaceToken = sanitizeNamespace(options.namespace);
23-
const channel = releaseChannelFromVersion(options.releaseVersion)
24-
?? releaseChannelFromNamespace(options.namespace, "default");
23+
const channel = releaseChannelFromIdentity(
24+
options.releaseVersion,
25+
options.namespace,
26+
OPEN_DESIGN_RUNTIME_DEFAULTS.namespace,
27+
);
2528
const displayName = channel == null ? `Open Design ${namespaceToken}` : releaseInstallIdentity(channel).productName;
2629
return { displayName, namespaceToken };
2730
}

packages/release/src/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ export function releaseChannelFromNamespace(namespace: string, defaultNamespace
126126
return isReleaseChannel(match?.[1]) ? match[1] : null;
127127
}
128128

129+
/** Resolve one release channel identity with version precedence and namespace fallback. */
130+
export function releaseChannelFromIdentity(
131+
version: string | null | undefined,
132+
namespace: string,
133+
defaultNamespace = DEFAULT_NAMESPACE,
134+
): ReleaseChannel | null {
135+
return releaseChannelFromVersion(version)
136+
?? releaseChannelFromNamespace(namespace, defaultNamespace);
137+
}
138+
129139
export function isReleaseChannelNamespace(namespace: string, channel: ReleaseChannel): boolean {
130140
return new RegExp(`^release-${channel}(?:$|[-_.])`, "i").test(namespace);
131141
}

packages/release/tests/index.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
parseReleaseBaseVersion,
77
parseReleaseVersion,
88
releaseChannelDescriptor,
9+
releaseChannelFromIdentity,
910
releaseChannelFromNamespace,
1011
releaseChannelFromVersion,
1112
releaseInstallIdentity,
@@ -85,6 +86,13 @@ describe("@open-design/release", () => {
8586
expect(releaseChannelFromNamespace("release-local")).toBeNull();
8687
});
8788

89+
it("resolves one channel identity from version then namespace", () => {
90+
expect(releaseChannelFromIdentity("1.2.3-beta.1", "release-preview", "default")).toBe("beta");
91+
expect(releaseChannelFromIdentity("1.2.3", "default", "default")).toBe("stable");
92+
expect(releaseChannelFromIdentity(null, "release-beta-linux", "default")).toBe("beta");
93+
expect(releaseChannelFromIdentity(null, "local-smoke", "default")).toBeNull();
94+
});
95+
8896
it("derives Windows release identity from the same namespace token", () => {
8997
expect(resolveWindowsReleaseNamespaceToken("release beta/win x64")).toBe(
9098
"release-beta-win-x64",

packages/sidecar/src/control/controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ function createClient<TMethods>(descriptor: PrivateLaunchMetadata): SidecarContr
229229
: options.timeoutMs;
230230
return (await invoke({ kind: "call", input, method }, timeoutMs)) as never;
231231
},
232-
environment(extraEnv = {}) {
232+
environment(extraEnv) {
233233
return createPrivateLaunchEnv(descriptor, extraEnv);
234234
},
235235
identity: descriptor.identity,

packages/sidecar/src/control/private-protocol.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { createHash, randomUUID } from "node:crypto";
2-
import { tmpdir } from "node:os";
32
import { isAbsolute, join, resolve } from "node:path";
43

54
import { SidecarControlError, type SidecarControlErrorCode } from "./error.js";
@@ -13,6 +12,8 @@ import type {
1312

1413
const CONTROL_SCHEMA_VERSION = 1 as const;
1514
const CONTROL_BOOTSTRAP_ENV = "OD_SIDECAR_CONTROL_BOOTSTRAP_V1";
15+
// Launch environments may be exact allowlists, so endpoint identity cannot depend on TMPDIR.
16+
const POSIX_CONTROL_ROOT = "/tmp";
1617
const CONTROL_TOKEN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9])?$/;
1718
const CONTROL_NAMESPACE = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,126}[A-Za-z0-9])?$/;
1819

@@ -214,7 +215,7 @@ export function privateControlPaths(
214215
endpointPath:
215216
process.platform === "win32"
216217
? `\\\\.\\pipe\\open-design-sidecar-${key}`
217-
: join(tmpdir(), `od-sidecar-${key}.sock`),
218+
: join(POSIX_CONTROL_ROOT, `od-sidecar-${key}.sock`),
218219
};
219220
}
220221

@@ -303,11 +304,10 @@ export function installPrivateLaunchMetadata(
303304

304305
export function createPrivateLaunchEnv(
305306
metadata: PrivateLaunchMetadata,
306-
extraEnv: NodeJS.ProcessEnv = {},
307+
extraEnv?: NodeJS.ProcessEnv,
307308
): NodeJS.ProcessEnv {
308309
return {
309-
...process.env,
310-
...extraEnv,
310+
...(extraEnv ?? process.env),
311311
[CONTROL_BOOTSTRAP_ENV]: encodePrivateLaunchMetadata(metadata),
312312
};
313313
}

0 commit comments

Comments
 (0)