@agent-vm/gondolin-adapter 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.d.ts +225 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +461 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Shravan Sunder
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { BuildConfig, BuildConfig as BuildConfig$1, getDefaultBuildConfig } from "@earendil-works/gondolin";
|
|
2
|
+
|
|
3
|
+
//#region src/build-pipeline.d.ts
|
|
4
|
+
interface BuildImageOptions {
|
|
5
|
+
readonly buildConfig: BuildConfig$1;
|
|
6
|
+
readonly cacheDir: string;
|
|
7
|
+
/** Directory to resolve relative paths in buildConfig (e.g. postBuild.copy.src).
|
|
8
|
+
* Defaults to process.cwd() if not provided. */
|
|
9
|
+
readonly configDir?: string;
|
|
10
|
+
readonly fullReset?: boolean;
|
|
11
|
+
readonly fingerprintInput?: unknown;
|
|
12
|
+
}
|
|
13
|
+
interface BuildImageResult {
|
|
14
|
+
readonly built: boolean;
|
|
15
|
+
readonly fingerprint: string;
|
|
16
|
+
readonly imagePath: string;
|
|
17
|
+
}
|
|
18
|
+
interface BuildPipelineDependencies {
|
|
19
|
+
readonly buildAssets?: (buildConfig: BuildConfig$1, outputDirectory: string, configDir?: string) => Promise<unknown>;
|
|
20
|
+
readonly gondolinVersion?: string;
|
|
21
|
+
}
|
|
22
|
+
declare function computeBuildFingerprint(buildConfig: BuildConfig$1, gondolinVersion?: string, fingerprintInput?: unknown): string;
|
|
23
|
+
declare function buildImage(options: BuildImageOptions, dependencies?: BuildPipelineDependencies): Promise<BuildImageResult>;
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/gondolin-package.d.ts
|
|
26
|
+
declare function parseMinimumZigVersion(rawContents: string): string;
|
|
27
|
+
declare function resolveGondolinPackageJsonPath(): string;
|
|
28
|
+
declare function resolveGondolinPackageSpec(): Promise<string>;
|
|
29
|
+
interface ResolveGondolinMinimumZigVersionOptions {
|
|
30
|
+
readonly buildZigZonPath?: string;
|
|
31
|
+
}
|
|
32
|
+
declare function resolveGondolinMinimumZigVersion(options?: ResolveGondolinMinimumZigVersionOptions): Promise<string>;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/mount-policy.d.ts
|
|
35
|
+
interface WritableMountPolicy {
|
|
36
|
+
readonly allowAuthWrite: boolean;
|
|
37
|
+
readonly writableAllowedGuestPrefixes: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
interface RuntimeMountPolicyConfig {
|
|
40
|
+
readonly extraMounts: Readonly<Record<string, string>>;
|
|
41
|
+
readonly mountControls: WritableMountPolicy;
|
|
42
|
+
}
|
|
43
|
+
declare function resolveGuestMountPath(guestPath: string, workDir: string): string;
|
|
44
|
+
declare function validateWritableMount(guestPath: string, policy: WritableMountPolicy, options: {
|
|
45
|
+
readonly workDir: string;
|
|
46
|
+
}): void;
|
|
47
|
+
declare function validateRuntimeMountPolicy(config: RuntimeMountPolicyConfig, options: {
|
|
48
|
+
readonly hostHome: string;
|
|
49
|
+
readonly workDir: string;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/policy-compiler.d.ts
|
|
53
|
+
interface PolicySources {
|
|
54
|
+
readonly base: readonly string[];
|
|
55
|
+
readonly profile: readonly string[];
|
|
56
|
+
readonly extra: readonly string[];
|
|
57
|
+
}
|
|
58
|
+
declare function normalizeHostname(rawHostname: string): string;
|
|
59
|
+
declare function dedupeStable(values: readonly string[]): string[];
|
|
60
|
+
declare function compilePolicy(sources: PolicySources): string[];
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/types.d.ts
|
|
63
|
+
interface SecretSpec {
|
|
64
|
+
readonly hosts: readonly string[];
|
|
65
|
+
readonly value: string;
|
|
66
|
+
}
|
|
67
|
+
type SecretRef = {
|
|
68
|
+
readonly source: '1password';
|
|
69
|
+
readonly ref: string;
|
|
70
|
+
} | {
|
|
71
|
+
readonly source: 'environment';
|
|
72
|
+
readonly ref: string;
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/secret-resolver.d.ts
|
|
76
|
+
interface SecretResolverClient {
|
|
77
|
+
readonly secrets: {
|
|
78
|
+
resolve(secretReference: string): Promise<string>;
|
|
79
|
+
resolveAll(secretReferences: readonly string[]): Promise<unknown>;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
interface SecretResolver {
|
|
83
|
+
resolve(ref: SecretRef): Promise<string>;
|
|
84
|
+
resolveAll(refs: Record<string, SecretRef>): Promise<Record<string, string>>;
|
|
85
|
+
}
|
|
86
|
+
type TokenSource = {
|
|
87
|
+
readonly type: 'op-cli';
|
|
88
|
+
readonly ref: string;
|
|
89
|
+
} | {
|
|
90
|
+
readonly type: 'env';
|
|
91
|
+
readonly envVar?: string | undefined;
|
|
92
|
+
} | {
|
|
93
|
+
readonly type: 'keychain';
|
|
94
|
+
readonly service: string;
|
|
95
|
+
readonly account: string;
|
|
96
|
+
};
|
|
97
|
+
interface ExecFileOptions {
|
|
98
|
+
readonly env?: Readonly<Record<string, string | undefined>>;
|
|
99
|
+
}
|
|
100
|
+
interface ExecFileResult {
|
|
101
|
+
readonly stdout: string;
|
|
102
|
+
readonly stderr: string;
|
|
103
|
+
}
|
|
104
|
+
declare function resolveServiceAccountToken(source: TokenSource, dependencies?: {
|
|
105
|
+
readonly execFileAsync?: (command: string, args: readonly string[], options?: ExecFileOptions) => Promise<ExecFileResult>;
|
|
106
|
+
}): Promise<string>;
|
|
107
|
+
interface CreateSecretResolverDependencies {
|
|
108
|
+
readonly createClient?: (config: {
|
|
109
|
+
auth: string;
|
|
110
|
+
integrationName: string;
|
|
111
|
+
integrationVersion: string;
|
|
112
|
+
}) => Promise<SecretResolverClient>;
|
|
113
|
+
readonly execFileAsync?: (command: string, args: readonly string[], options?: ExecFileOptions) => Promise<ExecFileResult>;
|
|
114
|
+
readonly integrationName?: string;
|
|
115
|
+
readonly integrationVersion?: string;
|
|
116
|
+
}
|
|
117
|
+
declare function createSecretResolver(options: {
|
|
118
|
+
readonly serviceAccountToken: string;
|
|
119
|
+
}, dependencies?: CreateSecretResolverDependencies): Promise<SecretResolver>;
|
|
120
|
+
declare function createOpCliSecretResolver(options: {
|
|
121
|
+
readonly serviceAccountToken: string;
|
|
122
|
+
}, dependencies?: Pick<CreateSecretResolverDependencies, 'execFileAsync'>): Promise<SecretResolver>;
|
|
123
|
+
//#endregion
|
|
124
|
+
//#region src/vm-adapter.d.ts
|
|
125
|
+
interface ExecResult {
|
|
126
|
+
readonly exitCode: number;
|
|
127
|
+
readonly stdout: string;
|
|
128
|
+
readonly stderr: string;
|
|
129
|
+
}
|
|
130
|
+
interface IngressRoute {
|
|
131
|
+
readonly prefix: string;
|
|
132
|
+
readonly port: number;
|
|
133
|
+
readonly stripPrefix?: boolean;
|
|
134
|
+
}
|
|
135
|
+
interface SshAccess {
|
|
136
|
+
readonly host: string;
|
|
137
|
+
readonly command?: string;
|
|
138
|
+
readonly identityFile?: string;
|
|
139
|
+
readonly port: number;
|
|
140
|
+
readonly user?: string;
|
|
141
|
+
}
|
|
142
|
+
interface IngressAccess {
|
|
143
|
+
readonly host: string;
|
|
144
|
+
readonly port: number;
|
|
145
|
+
}
|
|
146
|
+
interface ManagedVmInstance {
|
|
147
|
+
readonly id: string;
|
|
148
|
+
exec(command: string): Promise<{
|
|
149
|
+
readonly exitCode: number;
|
|
150
|
+
readonly stdout?: string;
|
|
151
|
+
readonly stderr?: string;
|
|
152
|
+
}>;
|
|
153
|
+
enableSsh(options?: unknown): Promise<SshAccess>;
|
|
154
|
+
enableIngress(options?: unknown): Promise<IngressAccess>;
|
|
155
|
+
setIngressRoutes(routes: readonly IngressRoute[]): void;
|
|
156
|
+
close(): Promise<void>;
|
|
157
|
+
}
|
|
158
|
+
interface ManagedVmDependencies {
|
|
159
|
+
createVm(vmOptions: unknown): Promise<ManagedVmInstance>;
|
|
160
|
+
createHttpHooks(options: {
|
|
161
|
+
readonly allowedHosts: readonly string[];
|
|
162
|
+
readonly secrets: Record<string, SecretSpec>;
|
|
163
|
+
readonly onRequest?: (request: Request) => Promise<Request | Response | void>;
|
|
164
|
+
readonly onResponse?: (response: Response) => Promise<Response | void>;
|
|
165
|
+
}): {
|
|
166
|
+
readonly env: Record<string, string>;
|
|
167
|
+
readonly httpHooks: unknown;
|
|
168
|
+
};
|
|
169
|
+
createRealFsProvider(hostPath: string): unknown;
|
|
170
|
+
createReadonlyProvider(provider: unknown): unknown;
|
|
171
|
+
createMemoryProvider(): unknown;
|
|
172
|
+
createShadowProvider(provider: unknown, options: unknown): unknown;
|
|
173
|
+
createShadowPathPredicate(paths: readonly string[]): unknown;
|
|
174
|
+
}
|
|
175
|
+
interface VfsMountSpec {
|
|
176
|
+
readonly kind: 'realfs' | 'realfs-readonly' | 'memory' | 'shadow';
|
|
177
|
+
readonly hostPath?: string;
|
|
178
|
+
readonly shadowConfig?: {
|
|
179
|
+
readonly deny: readonly string[];
|
|
180
|
+
readonly tmpfs: readonly string[];
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
interface CreateVmOptions {
|
|
184
|
+
readonly imagePath: string;
|
|
185
|
+
readonly memory: string;
|
|
186
|
+
readonly cpus: number;
|
|
187
|
+
readonly rootfsMode: 'readonly' | 'memory' | 'cow';
|
|
188
|
+
readonly allowedHosts: readonly string[];
|
|
189
|
+
readonly secrets: Record<string, SecretSpec>;
|
|
190
|
+
readonly vfsMounts: Record<string, VfsMountSpec>;
|
|
191
|
+
readonly tcpHosts?: Record<string, string>;
|
|
192
|
+
readonly env?: Record<string, string>;
|
|
193
|
+
readonly sessionLabel?: string;
|
|
194
|
+
readonly onRequest?: (request: Request) => Promise<Request | Response | void>;
|
|
195
|
+
readonly onResponse?: (response: Response) => Promise<Response | void>;
|
|
196
|
+
}
|
|
197
|
+
interface ManagedVm {
|
|
198
|
+
readonly id: string;
|
|
199
|
+
exec(command: string): Promise<ExecResult>;
|
|
200
|
+
enableSsh(options?: unknown): Promise<SshAccess>;
|
|
201
|
+
enableIngress(options?: unknown): Promise<IngressAccess>;
|
|
202
|
+
getVmInstance(): ManagedVmInstance;
|
|
203
|
+
setIngressRoutes(routes: readonly IngressRoute[]): void;
|
|
204
|
+
close(): Promise<void>;
|
|
205
|
+
}
|
|
206
|
+
declare function createManagedVm(options: CreateVmOptions, dependencies?: ManagedVmDependencies): Promise<ManagedVm>;
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/volume-manager.d.ts
|
|
209
|
+
interface VolumeConfigEntry {
|
|
210
|
+
readonly guestPath: string;
|
|
211
|
+
}
|
|
212
|
+
interface ResolvedVolume {
|
|
213
|
+
readonly hostDir: string;
|
|
214
|
+
readonly guestPath: string;
|
|
215
|
+
}
|
|
216
|
+
declare function ensureVolumeDir(cacheBase: string, workspaceHash: string, volumeName: string): Promise<string>;
|
|
217
|
+
declare function resolveVolumeDirs(cacheBase: string, workspaceHash: string, volumes: Readonly<Record<string, VolumeConfigEntry>>): Promise<Record<string, ResolvedVolume>>;
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/write-file-atomically.d.ts
|
|
220
|
+
declare function writeFileAtomically(filePath: string, content: string, options?: {
|
|
221
|
+
readonly mode?: number;
|
|
222
|
+
}): Promise<void>;
|
|
223
|
+
//#endregion
|
|
224
|
+
export { type BuildConfig, BuildImageOptions, BuildImageResult, CreateSecretResolverDependencies, CreateVmOptions, ExecFileOptions, ExecFileResult, ExecResult, IngressAccess, IngressRoute, ManagedVm, ManagedVmDependencies, ManagedVmInstance, PolicySources, ResolveGondolinMinimumZigVersionOptions, ResolvedVolume, RuntimeMountPolicyConfig, SecretRef, SecretResolver, SecretResolverClient, SecretSpec, SshAccess, TokenSource, VfsMountSpec, VolumeConfigEntry, WritableMountPolicy, buildImage, compilePolicy, computeBuildFingerprint, createManagedVm, createOpCliSecretResolver, createSecretResolver, dedupeStable, ensureVolumeDir, getDefaultBuildConfig, normalizeHostname, parseMinimumZigVersion, resolveGondolinMinimumZigVersion, resolveGondolinPackageJsonPath, resolveGondolinPackageSpec, resolveGuestMountPath, resolveServiceAccountToken, resolveVolumeDirs, validateRuntimeMountPolicy, validateWritableMount, writeFileAtomically };
|
|
225
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/build-pipeline.ts","../src/gondolin-package.ts","../src/mount-policy.ts","../src/policy-compiler.ts","../src/types.ts","../src/secret-resolver.ts","../src/vm-adapter.ts","../src/volume-manager.ts","../src/write-file-atomically.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { createClient } from "@1password/sdk";
|
|
8
|
+
import { MemoryProvider, ReadonlyProvider, RealFSProvider, ShadowProvider, VM, createHttpHooks, createShadowPathPredicate, getDefaultBuildConfig } from "@earendil-works/gondolin";
|
|
9
|
+
|
|
10
|
+
//#region src/build-pipeline.ts
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === "object" && value !== null;
|
|
13
|
+
}
|
|
14
|
+
function stableSerialize(value) {
|
|
15
|
+
if (Array.isArray(value)) return `[${value.map((entry) => stableSerialize(entry)).join(",")}]`;
|
|
16
|
+
if (isRecord(value)) return `{${Object.entries(value).filter(([, entryValue]) => entryValue !== void 0).toSorted(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)).map(([entryKey, entryValue]) => `${JSON.stringify(entryKey)}:${stableSerialize(entryValue)}`).join(",")}}`;
|
|
17
|
+
return JSON.stringify(value);
|
|
18
|
+
}
|
|
19
|
+
async function pathExists(filePath) {
|
|
20
|
+
try {
|
|
21
|
+
await fs.access(filePath);
|
|
22
|
+
return true;
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function hasBuiltAssets(outputDirectoryPath) {
|
|
28
|
+
return await pathExists(path.join(outputDirectoryPath, "manifest.json")) && await pathExists(path.join(outputDirectoryPath, "rootfs.ext4")) && await pathExists(path.join(outputDirectoryPath, "initramfs.cpio.lz4")) && await pathExists(path.join(outputDirectoryPath, "vmlinuz-virt"));
|
|
29
|
+
}
|
|
30
|
+
async function loadBuildAssets() {
|
|
31
|
+
const gondolinModule = await import("@earendil-works/gondolin");
|
|
32
|
+
return async (buildConfig, outputDirectory, configDir) => await gondolinModule.buildAssets(buildConfig, {
|
|
33
|
+
outputDir: outputDirectory,
|
|
34
|
+
verbose: false,
|
|
35
|
+
...configDir ? { configDir } : {}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function computeBuildFingerprint(buildConfig, gondolinVersion = "unknown", fingerprintInput) {
|
|
39
|
+
const payload = fingerprintInput === void 0 ? `${stableSerialize(buildConfig)}|${gondolinVersion}` : `${stableSerialize(buildConfig)}|${gondolinVersion}|${stableSerialize(fingerprintInput)}`;
|
|
40
|
+
return crypto.createHash("sha256").update(payload).digest("hex").slice(0, 16);
|
|
41
|
+
}
|
|
42
|
+
async function buildImage(options, dependencies = {}) {
|
|
43
|
+
const fingerprint = computeBuildFingerprint(options.buildConfig, dependencies.gondolinVersion, options.fingerprintInput);
|
|
44
|
+
const imagePath = path.join(options.cacheDir, fingerprint);
|
|
45
|
+
if (options.fullReset) await fs.rm(imagePath, {
|
|
46
|
+
recursive: true,
|
|
47
|
+
force: true
|
|
48
|
+
});
|
|
49
|
+
if (await hasBuiltAssets(imagePath)) return {
|
|
50
|
+
built: false,
|
|
51
|
+
fingerprint,
|
|
52
|
+
imagePath
|
|
53
|
+
};
|
|
54
|
+
await fs.mkdir(imagePath, { recursive: true });
|
|
55
|
+
await (dependencies.buildAssets ?? await loadBuildAssets())(options.buildConfig, imagePath, options.configDir);
|
|
56
|
+
if (!await hasBuiltAssets(imagePath)) throw new Error(`Expected Gondolin assets to be written to ${imagePath}.`);
|
|
57
|
+
return {
|
|
58
|
+
built: true,
|
|
59
|
+
fingerprint,
|
|
60
|
+
imagePath
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/gondolin-package.ts
|
|
66
|
+
const requireFromHere = createRequire(import.meta.url);
|
|
67
|
+
const gondolinPackageJsonSchema = z.object({ version: z.string().min(1) });
|
|
68
|
+
function isMissingFileError(error) {
|
|
69
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
70
|
+
}
|
|
71
|
+
function getErrorMessage(error) {
|
|
72
|
+
return error instanceof Error ? error.message : String(error);
|
|
73
|
+
}
|
|
74
|
+
function parseMinimumZigVersion(rawContents) {
|
|
75
|
+
const match = rawContents.match(/\.minimum_zig_version\s*=\s*"([^"]*)"/u);
|
|
76
|
+
if (!match) throw new Error("minimum_zig_version declaration not found. Expected a line like `.minimum_zig_version = \"0.15.2\"`.");
|
|
77
|
+
const version = match[1];
|
|
78
|
+
if (!version) throw new Error("minimum_zig_version is empty.");
|
|
79
|
+
return version;
|
|
80
|
+
}
|
|
81
|
+
function resolveGondolinPackageJsonPath() {
|
|
82
|
+
return requireFromHere.resolve("@earendil-works/gondolin/package.json");
|
|
83
|
+
}
|
|
84
|
+
async function resolveGondolinPackageSpec() {
|
|
85
|
+
const packageJsonPath = resolveGondolinPackageJsonPath();
|
|
86
|
+
const parsed = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
|
|
87
|
+
return `@earendil-works/gondolin@${gondolinPackageJsonSchema.parse(parsed).version}`;
|
|
88
|
+
}
|
|
89
|
+
async function resolveDefaultBuildZigZonPath() {
|
|
90
|
+
const packageJsonPath = resolveGondolinPackageJsonPath();
|
|
91
|
+
return path.join(path.dirname(packageJsonPath), "dist", "guest", "build.zig.zon");
|
|
92
|
+
}
|
|
93
|
+
async function resolveGondolinMinimumZigVersion(options = {}) {
|
|
94
|
+
const zonPath = options.buildZigZonPath ?? await resolveDefaultBuildZigZonPath();
|
|
95
|
+
let rawContents;
|
|
96
|
+
try {
|
|
97
|
+
rawContents = await fs.readFile(zonPath, "utf8");
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (isMissingFileError(error)) throw new Error(`Missing Gondolin build.zig.zon at '${zonPath}'.`, { cause: error });
|
|
100
|
+
throw new Error(`Failed to read Gondolin build.zig.zon at '${zonPath}': ${getErrorMessage(error)}`, { cause: error });
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
return parseMinimumZigVersion(rawContents);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
throw new Error(`Failed to parse Gondolin build.zig.zon at '${zonPath}': ${getErrorMessage(error)}`, { cause: error });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/mount-policy.ts
|
|
111
|
+
const AUTH_GUEST_PATH_PREFIXES = [
|
|
112
|
+
"/home/agent/.aws",
|
|
113
|
+
"/home/agent/.claude",
|
|
114
|
+
"/home/agent/.codex",
|
|
115
|
+
"/home/agent/.gemini",
|
|
116
|
+
"/home/openclaw/.aws",
|
|
117
|
+
"/home/openclaw/.claude",
|
|
118
|
+
"/home/openclaw/.codex",
|
|
119
|
+
"/home/openclaw/.gemini",
|
|
120
|
+
"/home/openclaw/.openclaw"
|
|
121
|
+
];
|
|
122
|
+
function resolveAuthHostPrefixes(hostHome) {
|
|
123
|
+
return [
|
|
124
|
+
path.join(hostHome, ".aws"),
|
|
125
|
+
path.join(hostHome, ".claude"),
|
|
126
|
+
path.join(hostHome, ".codex"),
|
|
127
|
+
path.join(hostHome, ".gemini")
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
function resolveGuestMountPath(guestPath, workDir) {
|
|
131
|
+
if (path.isAbsolute(guestPath)) return path.resolve(guestPath);
|
|
132
|
+
return path.resolve(workDir, guestPath);
|
|
133
|
+
}
|
|
134
|
+
function isPathWithinPrefix(candidatePath, prefixPath) {
|
|
135
|
+
const relativePath = path.relative(prefixPath, candidatePath);
|
|
136
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
|
|
137
|
+
}
|
|
138
|
+
async function normalizeHostPath(hostPath) {
|
|
139
|
+
const resolvedHostPath = path.resolve(hostPath);
|
|
140
|
+
try {
|
|
141
|
+
return await fs.realpath(resolvedHostPath);
|
|
142
|
+
} catch {
|
|
143
|
+
return resolvedHostPath;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function pathsOverlap(candidatePath, protectedPath) {
|
|
147
|
+
return isPathWithinPrefix(candidatePath, protectedPath) || isPathWithinPrefix(protectedPath, candidatePath);
|
|
148
|
+
}
|
|
149
|
+
function validateWritableMount(guestPath, policy, options) {
|
|
150
|
+
const resolvedGuestPath = resolveGuestMountPath(guestPath, options.workDir);
|
|
151
|
+
const resolvedAllowedPrefixes = policy.writableAllowedGuestPrefixes.map((allowedPrefix) => resolveGuestMountPath(allowedPrefix, options.workDir));
|
|
152
|
+
if (!resolvedAllowedPrefixes.some((allowedPrefix) => isPathWithinPrefix(resolvedGuestPath, allowedPrefix))) throw new Error(`Writable mount guest path '${resolvedGuestPath}' is outside writable allowlist [${resolvedAllowedPrefixes.join(", ")}].`);
|
|
153
|
+
if (!policy.allowAuthWrite) {
|
|
154
|
+
if (AUTH_GUEST_PATH_PREFIXES.some((authPrefix) => isPathWithinPrefix(resolvedGuestPath, authPrefix))) throw new Error(`Writable mount guest path '${resolvedGuestPath}' targets an auth mount path. Set mountControls.allowAuthWrite=true to permit auth writes.`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function validateRuntimeMountPolicy(config, options) {
|
|
158
|
+
const mountEntries = Object.entries(config.extraMounts);
|
|
159
|
+
for (const [guestPath] of mountEntries) validateWritableMount(guestPath, config.mountControls, options);
|
|
160
|
+
if (config.mountControls.allowAuthWrite) return;
|
|
161
|
+
const absoluteHostMountEntries = mountEntries.filter(([, hostPath]) => path.isAbsolute(hostPath));
|
|
162
|
+
const [protectedHostPaths, writableHostPaths] = await Promise.all([Promise.all(resolveAuthHostPrefixes(options.hostHome).map(async (authHostPrefix) => await normalizeHostPath(authHostPrefix))), Promise.all(absoluteHostMountEntries.map(async ([, hostPath]) => await normalizeHostPath(hostPath)))]);
|
|
163
|
+
for (const resolvedWritableHostPath of writableHostPaths) if (protectedHostPaths.some((authHostPrefix) => pathsOverlap(resolvedWritableHostPath, authHostPrefix))) throw new Error(`Writable host path '${resolvedWritableHostPath}' targets an auth host directory. Set mountControls.allowAuthWrite=true to permit auth writes.`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
//#endregion
|
|
167
|
+
//#region src/policy-compiler.ts
|
|
168
|
+
function normalizeHostname(rawHostname) {
|
|
169
|
+
return rawHostname.trim().toLowerCase().replace(/\.+$/u, "");
|
|
170
|
+
}
|
|
171
|
+
function dedupeStable(values) {
|
|
172
|
+
const seenHostnames = /* @__PURE__ */ new Set();
|
|
173
|
+
const normalizedValues = [];
|
|
174
|
+
for (const value of values) {
|
|
175
|
+
const normalizedValue = normalizeHostname(value);
|
|
176
|
+
if (normalizedValue.length === 0 || normalizedValue.startsWith("#")) continue;
|
|
177
|
+
if (!seenHostnames.has(normalizedValue)) {
|
|
178
|
+
seenHostnames.add(normalizedValue);
|
|
179
|
+
normalizedValues.push(normalizedValue);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return normalizedValues;
|
|
183
|
+
}
|
|
184
|
+
function compilePolicy(sources) {
|
|
185
|
+
return dedupeStable([
|
|
186
|
+
...sources.base,
|
|
187
|
+
...sources.profile,
|
|
188
|
+
...sources.extra
|
|
189
|
+
]);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/secret-resolver.ts
|
|
194
|
+
function writeStderr(message) {
|
|
195
|
+
process.stderr.write(`${message}\n`);
|
|
196
|
+
}
|
|
197
|
+
function ensureMacOsForKeychain() {
|
|
198
|
+
if (process.platform !== "darwin") throw new Error("Keychain token source is only supported on macOS. Use an env or op-cli token source on this platform so cmd-ts can surface a clear startup error.");
|
|
199
|
+
}
|
|
200
|
+
function execFileAsync(command, args, options) {
|
|
201
|
+
return new Promise((resolve, reject) => {
|
|
202
|
+
execFile(command, [...args], {
|
|
203
|
+
env: options?.env,
|
|
204
|
+
timeout: 3e4
|
|
205
|
+
}, (error, stdout, stderr) => {
|
|
206
|
+
if (error) {
|
|
207
|
+
const errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
|
|
208
|
+
reject(/* @__PURE__ */ new Error(`${command} failed: ${stderr.trim() || errorMessage}`));
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
resolve({
|
|
212
|
+
stdout,
|
|
213
|
+
stderr
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
const SAFE_IDENTIFIER_PATTERN = /^[\w.@-]+$/u;
|
|
219
|
+
async function resolveServiceAccountToken(source, dependencies) {
|
|
220
|
+
const exec = dependencies?.execFileAsync ?? execFileAsync;
|
|
221
|
+
switch (source.type) {
|
|
222
|
+
case "op-cli": {
|
|
223
|
+
const token = (await exec("op", ["read", source.ref])).stdout.trim();
|
|
224
|
+
if (token.length === 0) throw new Error("op-cli token resolution returned empty value");
|
|
225
|
+
return token;
|
|
226
|
+
}
|
|
227
|
+
case "env": {
|
|
228
|
+
const envVar = source.envVar ?? "OP_SERVICE_ACCOUNT_TOKEN";
|
|
229
|
+
const token = process.env[envVar]?.trim();
|
|
230
|
+
if (!token) throw new Error(`Environment variable ${envVar} is not set`);
|
|
231
|
+
return token;
|
|
232
|
+
}
|
|
233
|
+
case "keychain": {
|
|
234
|
+
ensureMacOsForKeychain();
|
|
235
|
+
if (!SAFE_IDENTIFIER_PATTERN.test(source.service)) throw new Error("Keychain service name contains invalid characters");
|
|
236
|
+
if (!SAFE_IDENTIFIER_PATTERN.test(source.account)) throw new Error("Keychain account name contains invalid characters");
|
|
237
|
+
const token = (await exec("security", [
|
|
238
|
+
"find-generic-password",
|
|
239
|
+
"-s",
|
|
240
|
+
source.service,
|
|
241
|
+
"-a",
|
|
242
|
+
source.account,
|
|
243
|
+
"-w"
|
|
244
|
+
])).stdout.trim();
|
|
245
|
+
if (token.length === 0) throw new Error("Keychain token resolution returned empty value");
|
|
246
|
+
return token;
|
|
247
|
+
}
|
|
248
|
+
default: throw new Error(`Unsupported token source: ${JSON.stringify(source)}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function resolveSecretWithOpCli(serviceAccountToken, secretReference, exec) {
|
|
252
|
+
return (await exec("op", ["read", secretReference], { env: {
|
|
253
|
+
...process.env,
|
|
254
|
+
OP_SERVICE_ACCOUNT_TOKEN: serviceAccountToken
|
|
255
|
+
} })).stdout.trim();
|
|
256
|
+
}
|
|
257
|
+
async function resolveAllSecretsWithOpCli(serviceAccountToken, refs, exec) {
|
|
258
|
+
const resolvedSecrets = {};
|
|
259
|
+
for (const [secretName, secretRef] of Object.entries(refs)) resolvedSecrets[secretName] = await resolveSecretWithOpCli(serviceAccountToken, secretRef.ref, exec);
|
|
260
|
+
return resolvedSecrets;
|
|
261
|
+
}
|
|
262
|
+
async function createSecretResolver(options, dependencies = {}) {
|
|
263
|
+
const exec = dependencies.execFileAsync ?? execFileAsync;
|
|
264
|
+
try {
|
|
265
|
+
const client = await (dependencies.createClient ?? createClient)({
|
|
266
|
+
auth: options.serviceAccountToken,
|
|
267
|
+
integrationName: dependencies.integrationName ?? "agent-vm",
|
|
268
|
+
integrationVersion: dependencies.integrationVersion ?? "0.0.1"
|
|
269
|
+
});
|
|
270
|
+
return {
|
|
271
|
+
resolve: async (ref) => {
|
|
272
|
+
try {
|
|
273
|
+
return await client.secrets.resolve(ref.ref);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
276
|
+
writeStderr(`[secret-resolver] 1Password SDK resolve failed for ${ref.ref}; falling back to op CLI: ${message}`);
|
|
277
|
+
return await resolveSecretWithOpCli(options.serviceAccountToken, ref.ref, exec);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
resolveAll: async (refs) => {
|
|
281
|
+
const resolvedSecrets = {};
|
|
282
|
+
for (const [secretName, secretRef] of Object.entries(refs)) try {
|
|
283
|
+
resolvedSecrets[secretName] = await client.secrets.resolve(secretRef.ref);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
286
|
+
writeStderr(`[secret-resolver] 1Password SDK resolve failed for ${secretRef.ref}; falling back to op CLI: ${message}`);
|
|
287
|
+
resolvedSecrets[secretName] = await resolveSecretWithOpCli(options.serviceAccountToken, secretRef.ref, exec);
|
|
288
|
+
}
|
|
289
|
+
return resolvedSecrets;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
} catch (error) {
|
|
293
|
+
writeStderr(`[secret-resolver] 1Password SDK client creation failed; falling back to op CLI: ${error instanceof Error ? error.message : String(error)}`);
|
|
294
|
+
return {
|
|
295
|
+
resolve: async (ref) => await resolveSecretWithOpCli(options.serviceAccountToken, ref.ref, exec),
|
|
296
|
+
resolveAll: async (refs) => await resolveAllSecretsWithOpCli(options.serviceAccountToken, refs, exec)
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function createOpCliSecretResolver(options, dependencies = {}) {
|
|
301
|
+
const exec = dependencies.execFileAsync ?? execFileAsync;
|
|
302
|
+
return {
|
|
303
|
+
resolve: async (ref) => await resolveSecretWithOpCli(options.serviceAccountToken, ref.ref, exec),
|
|
304
|
+
resolveAll: async (refs) => await resolveAllSecretsWithOpCli(options.serviceAccountToken, refs, exec)
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
//#endregion
|
|
309
|
+
//#region src/vm-adapter.ts
|
|
310
|
+
function createDefaultDependencies() {
|
|
311
|
+
return {
|
|
312
|
+
createVm: async (vmOptions) => await VM.create(vmOptions),
|
|
313
|
+
createHttpHooks: (hookOptions) => createHttpHooks({
|
|
314
|
+
allowedHosts: [...hookOptions.allowedHosts],
|
|
315
|
+
secrets: Object.fromEntries(Object.entries(hookOptions.secrets).map(([secretName, secretSpec]) => [secretName, {
|
|
316
|
+
hosts: [...secretSpec.hosts],
|
|
317
|
+
value: secretSpec.value
|
|
318
|
+
}])),
|
|
319
|
+
...hookOptions.onRequest ? { onRequest: hookOptions.onRequest } : {},
|
|
320
|
+
...hookOptions.onResponse ? { onResponse: hookOptions.onResponse } : {}
|
|
321
|
+
}),
|
|
322
|
+
createRealFsProvider: (hostPath) => new RealFSProvider(hostPath),
|
|
323
|
+
createReadonlyProvider: (provider) => new ReadonlyProvider(provider),
|
|
324
|
+
createMemoryProvider: () => new MemoryProvider(),
|
|
325
|
+
createShadowProvider: (provider, shadowOptions) => new ShadowProvider(provider, shadowOptions),
|
|
326
|
+
createShadowPathPredicate: (paths) => createShadowPathPredicate([...paths])
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function normalizeShadowPath(pathValue) {
|
|
330
|
+
const trimmedPath = pathValue.trim();
|
|
331
|
+
if (trimmedPath.startsWith("/")) return trimmedPath;
|
|
332
|
+
return `/${trimmedPath.startsWith("./") ? trimmedPath.slice(2) : trimmedPath}`;
|
|
333
|
+
}
|
|
334
|
+
function createProviderFromSpec(mountSpec, dependencies) {
|
|
335
|
+
switch (mountSpec.kind) {
|
|
336
|
+
case "memory": return dependencies.createMemoryProvider();
|
|
337
|
+
case "realfs":
|
|
338
|
+
if (!mountSpec.hostPath) throw new Error("realfs mounts require hostPath");
|
|
339
|
+
return dependencies.createRealFsProvider(mountSpec.hostPath);
|
|
340
|
+
case "realfs-readonly":
|
|
341
|
+
if (!mountSpec.hostPath) throw new Error("realfs-readonly mounts require hostPath");
|
|
342
|
+
return dependencies.createReadonlyProvider(dependencies.createRealFsProvider(mountSpec.hostPath));
|
|
343
|
+
case "shadow": {
|
|
344
|
+
let shadowProvider = mountSpec.hostPath ? dependencies.createRealFsProvider(mountSpec.hostPath) : dependencies.createMemoryProvider();
|
|
345
|
+
const shadowConfig = mountSpec.shadowConfig;
|
|
346
|
+
if (shadowConfig?.deny.length) shadowProvider = dependencies.createShadowProvider(shadowProvider, {
|
|
347
|
+
shouldShadow: dependencies.createShadowPathPredicate(shadowConfig.deny.map((shadowPath) => normalizeShadowPath(shadowPath))),
|
|
348
|
+
writeMode: "deny"
|
|
349
|
+
});
|
|
350
|
+
if (shadowConfig?.tmpfs.length) shadowProvider = dependencies.createShadowProvider(shadowProvider, {
|
|
351
|
+
shouldShadow: dependencies.createShadowPathPredicate(shadowConfig.tmpfs.map((shadowPath) => normalizeShadowPath(shadowPath))),
|
|
352
|
+
writeMode: "tmpfs"
|
|
353
|
+
});
|
|
354
|
+
return shadowProvider;
|
|
355
|
+
}
|
|
356
|
+
default: throw new Error(`Unsupported VFS mount kind: ${String(mountSpec.kind)}`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function createVfsMounts(vfsMounts, dependencies) {
|
|
360
|
+
const mountMap = {};
|
|
361
|
+
for (const [guestPath, mountSpec] of Object.entries(vfsMounts)) mountMap[guestPath] = createProviderFromSpec(mountSpec, dependencies);
|
|
362
|
+
return mountMap;
|
|
363
|
+
}
|
|
364
|
+
async function createManagedVm(options, dependencies = createDefaultDependencies()) {
|
|
365
|
+
const hookBundle = dependencies.createHttpHooks({
|
|
366
|
+
allowedHosts: options.allowedHosts,
|
|
367
|
+
secrets: options.secrets,
|
|
368
|
+
...options.onRequest ? { onRequest: options.onRequest } : {},
|
|
369
|
+
...options.onResponse ? { onResponse: options.onResponse } : {}
|
|
370
|
+
});
|
|
371
|
+
const hasTcpHosts = options.tcpHosts && Object.keys(options.tcpHosts).length > 0;
|
|
372
|
+
const sandboxOptions = options.imagePath !== void 0 && options.imagePath.length > 0 ? { imagePath: options.imagePath } : {};
|
|
373
|
+
const vmInstance = await dependencies.createVm({
|
|
374
|
+
...Object.keys(sandboxOptions).length > 0 ? { sandbox: sandboxOptions } : {},
|
|
375
|
+
sessionLabel: options.sessionLabel,
|
|
376
|
+
rootfs: { mode: options.rootfsMode },
|
|
377
|
+
memory: options.memory,
|
|
378
|
+
cpus: options.cpus,
|
|
379
|
+
env: {
|
|
380
|
+
...hookBundle.env,
|
|
381
|
+
...options.env
|
|
382
|
+
},
|
|
383
|
+
httpHooks: hookBundle.httpHooks,
|
|
384
|
+
vfs: {
|
|
385
|
+
fuseMount: "/data",
|
|
386
|
+
mounts: createVfsMounts(options.vfsMounts, dependencies)
|
|
387
|
+
},
|
|
388
|
+
...hasTcpHosts ? {
|
|
389
|
+
dns: {
|
|
390
|
+
mode: "synthetic",
|
|
391
|
+
syntheticHostMapping: "per-host"
|
|
392
|
+
},
|
|
393
|
+
tcp: { hosts: options.tcpHosts }
|
|
394
|
+
} : {}
|
|
395
|
+
});
|
|
396
|
+
return {
|
|
397
|
+
id: vmInstance.id,
|
|
398
|
+
async exec(command) {
|
|
399
|
+
const executionResult = await vmInstance.exec(command);
|
|
400
|
+
return {
|
|
401
|
+
exitCode: executionResult.exitCode,
|
|
402
|
+
stdout: executionResult.stdout ?? "",
|
|
403
|
+
stderr: executionResult.stderr ?? ""
|
|
404
|
+
};
|
|
405
|
+
},
|
|
406
|
+
async enableSsh(sshOptions) {
|
|
407
|
+
return await vmInstance.enableSsh(sshOptions);
|
|
408
|
+
},
|
|
409
|
+
async enableIngress(ingressOptions) {
|
|
410
|
+
return await vmInstance.enableIngress(ingressOptions);
|
|
411
|
+
},
|
|
412
|
+
getVmInstance() {
|
|
413
|
+
return vmInstance;
|
|
414
|
+
},
|
|
415
|
+
setIngressRoutes(routes) {
|
|
416
|
+
vmInstance.setIngressRoutes(routes);
|
|
417
|
+
},
|
|
418
|
+
async close() {
|
|
419
|
+
await vmInstance.close();
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
//#endregion
|
|
425
|
+
//#region src/volume-manager.ts
|
|
426
|
+
async function ensureVolumeDir(cacheBase, workspaceHash, volumeName) {
|
|
427
|
+
const volumeDirectory = path.join(cacheBase, workspaceHash, volumeName);
|
|
428
|
+
await fs.mkdir(volumeDirectory, { recursive: true });
|
|
429
|
+
return volumeDirectory;
|
|
430
|
+
}
|
|
431
|
+
async function resolveVolumeDirs(cacheBase, workspaceHash, volumes) {
|
|
432
|
+
const resolvedVolumeEntries = await Promise.all(Object.entries(volumes).map(async ([volumeName, volumeConfig]) => [volumeName, {
|
|
433
|
+
guestPath: volumeConfig.guestPath,
|
|
434
|
+
hostDir: await ensureVolumeDir(cacheBase, workspaceHash, volumeName)
|
|
435
|
+
}]));
|
|
436
|
+
return Object.fromEntries(resolvedVolumeEntries);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region src/write-file-atomically.ts
|
|
441
|
+
async function writeFileAtomically(filePath, content, options = {}) {
|
|
442
|
+
const temporaryFilePath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
|
|
443
|
+
await fs.writeFile(temporaryFilePath, content, {
|
|
444
|
+
encoding: "utf8",
|
|
445
|
+
...options.mode ? { mode: options.mode } : {}
|
|
446
|
+
});
|
|
447
|
+
try {
|
|
448
|
+
await fs.rename(temporaryFilePath, filePath);
|
|
449
|
+
} catch (renameError) {
|
|
450
|
+
try {
|
|
451
|
+
await fs.rm(temporaryFilePath, { force: true });
|
|
452
|
+
} catch (cleanupError) {
|
|
453
|
+
throw new Error(`Failed to replace '${filePath}' (${renameError instanceof Error ? renameError.message : JSON.stringify(renameError)}) and failed to remove temporary file '${temporaryFilePath}': ${cleanupError instanceof Error ? cleanupError.message : JSON.stringify(cleanupError)}`, { cause: cleanupError });
|
|
454
|
+
}
|
|
455
|
+
throw renameError;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
//#endregion
|
|
460
|
+
export { buildImage, compilePolicy, computeBuildFingerprint, createManagedVm, createOpCliSecretResolver, createSecretResolver, dedupeStable, ensureVolumeDir, getDefaultBuildConfig, normalizeHostname, parseMinimumZigVersion, resolveGondolinMinimumZigVersion, resolveGondolinPackageJsonPath, resolveGondolinPackageSpec, resolveGuestMountPath, resolveServiceAccountToken, resolveVolumeDirs, validateRuntimeMountPolicy, validateWritableMount, writeFileAtomically };
|
|
461
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["parsed: unknown","rawContents: string","normalizedValues: string[]","resolvedSecrets: Record<string, string>","mountMap: Record<string, unknown>"],"sources":["../src/build-pipeline.ts","../src/gondolin-package.ts","../src/mount-policy.ts","../src/policy-compiler.ts","../src/secret-resolver.ts","../src/vm-adapter.ts","../src/volume-manager.ts","../src/write-file-atomically.ts"],"sourcesContent":["import crypto from 'node:crypto';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport type { BuildConfig, BuildOptions } from '@earendil-works/gondolin';\n\nexport type { BuildConfig } from '@earendil-works/gondolin';\n\nexport interface BuildImageOptions {\n\treadonly buildConfig: BuildConfig;\n\treadonly cacheDir: string;\n\t/** Directory to resolve relative paths in buildConfig (e.g. postBuild.copy.src).\n\t * Defaults to process.cwd() if not provided. */\n\treadonly configDir?: string;\n\treadonly fullReset?: boolean;\n\treadonly fingerprintInput?: unknown;\n}\n\nexport interface BuildImageResult {\n\treadonly built: boolean;\n\treadonly fingerprint: string;\n\treadonly imagePath: string;\n}\n\ninterface BuildPipelineDependencies {\n\treadonly buildAssets?: (\n\t\tbuildConfig: BuildConfig,\n\t\toutputDirectory: string,\n\t\tconfigDir?: string,\n\t) => Promise<unknown>;\n\treadonly gondolinVersion?: string;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === 'object' && value !== null;\n}\n\nfunction stableSerialize(value: unknown): string {\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map((entry) => stableSerialize(entry)).join(',')}]`;\n\t}\n\n\tif (isRecord(value)) {\n\t\tconst objectEntries = Object.entries(value)\n\t\t\t.filter(([, entryValue]) => entryValue !== undefined)\n\t\t\t.toSorted(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey));\n\t\treturn `{${objectEntries\n\t\t\t.map(([entryKey, entryValue]) => `${JSON.stringify(entryKey)}:${stableSerialize(entryValue)}`)\n\t\t\t.join(',')}}`;\n\t}\n\n\treturn JSON.stringify(value);\n}\n\nasync function pathExists(filePath: string): Promise<boolean> {\n\ttry {\n\t\tawait fs.access(filePath);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nasync function hasBuiltAssets(outputDirectoryPath: string): Promise<boolean> {\n\treturn (\n\t\t(await pathExists(path.join(outputDirectoryPath, 'manifest.json'))) &&\n\t\t(await pathExists(path.join(outputDirectoryPath, 'rootfs.ext4'))) &&\n\t\t(await pathExists(path.join(outputDirectoryPath, 'initramfs.cpio.lz4'))) &&\n\t\t(await pathExists(path.join(outputDirectoryPath, 'vmlinuz-virt')))\n\t);\n}\n\nasync function loadBuildAssets(): Promise<\n\t(buildConfig: BuildConfig, outputDirectory: string, configDir?: string) => Promise<unknown>\n> {\n\tconst gondolinModule = await import('@earendil-works/gondolin');\n\treturn async (\n\t\tbuildConfig: BuildConfig,\n\t\toutputDirectory: string,\n\t\tconfigDir?: string,\n\t): Promise<unknown> =>\n\t\tawait gondolinModule.buildAssets(buildConfig, {\n\t\t\toutputDir: outputDirectory,\n\t\t\tverbose: false,\n\t\t\t...(configDir ? { configDir } : {}),\n\t\t} satisfies BuildOptions);\n}\n\nexport function computeBuildFingerprint(\n\tbuildConfig: BuildConfig,\n\tgondolinVersion: string = 'unknown',\n\tfingerprintInput?: unknown,\n): string {\n\tconst payload =\n\t\tfingerprintInput === undefined\n\t\t\t? `${stableSerialize(buildConfig)}|${gondolinVersion}`\n\t\t\t: `${stableSerialize(buildConfig)}|${gondolinVersion}|${stableSerialize(fingerprintInput)}`;\n\n\treturn crypto.createHash('sha256').update(payload).digest('hex').slice(0, 16);\n}\n\nexport async function buildImage(\n\toptions: BuildImageOptions,\n\tdependencies: BuildPipelineDependencies = {},\n): Promise<BuildImageResult> {\n\tconst fingerprint = computeBuildFingerprint(\n\t\toptions.buildConfig,\n\t\tdependencies.gondolinVersion,\n\t\toptions.fingerprintInput,\n\t);\n\tconst imagePath = path.join(options.cacheDir, fingerprint);\n\n\tif (options.fullReset) {\n\t\tawait fs.rm(imagePath, { recursive: true, force: true });\n\t}\n\n\tif (await hasBuiltAssets(imagePath)) {\n\t\treturn {\n\t\t\tbuilt: false,\n\t\t\tfingerprint,\n\t\t\timagePath,\n\t\t};\n\t}\n\n\tawait fs.mkdir(imagePath, { recursive: true });\n\tconst buildAssetsImplementation = dependencies.buildAssets ?? (await loadBuildAssets());\n\tawait buildAssetsImplementation(options.buildConfig, imagePath, options.configDir);\n\n\tif (!(await hasBuiltAssets(imagePath))) {\n\t\tthrow new Error(`Expected Gondolin assets to be written to ${imagePath}.`);\n\t}\n\n\treturn {\n\t\tbuilt: true,\n\t\tfingerprint,\n\t\timagePath,\n\t};\n}\n","import fs from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport path from 'node:path';\n\nimport { z } from 'zod';\n\nconst requireFromHere = createRequire(import.meta.url);\n\nconst gondolinPackageJsonSchema = z.object({\n\tversion: z.string().min(1),\n});\n\nfunction isMissingFileError(error: unknown): boolean {\n\treturn typeof error === 'object' && error !== null && 'code' in error && error.code === 'ENOENT';\n}\n\nfunction getErrorMessage(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nexport function parseMinimumZigVersion(rawContents: string): string {\n\tconst match = rawContents.match(/\\.minimum_zig_version\\s*=\\s*\"([^\"]*)\"/u);\n\tif (!match) {\n\t\tthrow new Error(\n\t\t\t'minimum_zig_version declaration not found. Expected a line like `.minimum_zig_version = \"0.15.2\"`.',\n\t\t);\n\t}\n\n\tconst version = match[1];\n\tif (!version) {\n\t\tthrow new Error('minimum_zig_version is empty.');\n\t}\n\treturn version;\n}\n\nexport function resolveGondolinPackageJsonPath(): string {\n\treturn requireFromHere.resolve('@earendil-works/gondolin/package.json');\n}\n\nexport async function resolveGondolinPackageSpec(): Promise<string> {\n\tconst packageJsonPath = resolveGondolinPackageJsonPath();\n\tconst parsed: unknown = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));\n\tconst packageJson = gondolinPackageJsonSchema.parse(parsed);\n\treturn `@earendil-works/gondolin@${packageJson.version}`;\n}\n\nexport interface ResolveGondolinMinimumZigVersionOptions {\n\treadonly buildZigZonPath?: string;\n}\n\nasync function resolveDefaultBuildZigZonPath(): Promise<string> {\n\tconst packageJsonPath = resolveGondolinPackageJsonPath();\n\treturn path.join(path.dirname(packageJsonPath), 'dist', 'guest', 'build.zig.zon');\n}\n\nexport async function resolveGondolinMinimumZigVersion(\n\toptions: ResolveGondolinMinimumZigVersionOptions = {},\n): Promise<string> {\n\tconst zonPath = options.buildZigZonPath ?? (await resolveDefaultBuildZigZonPath());\n\tlet rawContents: string;\n\ttry {\n\t\trawContents = await fs.readFile(zonPath, 'utf8');\n\t} catch (error) {\n\t\tif (isMissingFileError(error)) {\n\t\t\tthrow new Error(`Missing Gondolin build.zig.zon at '${zonPath}'.`, { cause: error });\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Failed to read Gondolin build.zig.zon at '${zonPath}': ${getErrorMessage(error)}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n\n\ttry {\n\t\treturn parseMinimumZigVersion(rawContents);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to parse Gondolin build.zig.zon at '${zonPath}': ${getErrorMessage(error)}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nconst AUTH_GUEST_PATH_PREFIXES = [\n\t'/home/agent/.aws',\n\t'/home/agent/.claude',\n\t'/home/agent/.codex',\n\t'/home/agent/.gemini',\n\t'/home/openclaw/.aws',\n\t'/home/openclaw/.claude',\n\t'/home/openclaw/.codex',\n\t'/home/openclaw/.gemini',\n\t'/home/openclaw/.openclaw',\n] as const;\n\nexport interface WritableMountPolicy {\n\treadonly allowAuthWrite: boolean;\n\treadonly writableAllowedGuestPrefixes: readonly string[];\n}\n\nexport interface RuntimeMountPolicyConfig {\n\treadonly extraMounts: Readonly<Record<string, string>>;\n\treadonly mountControls: WritableMountPolicy;\n}\n\nfunction resolveAuthHostPrefixes(hostHome: string): readonly string[] {\n\treturn [\n\t\tpath.join(hostHome, '.aws'),\n\t\tpath.join(hostHome, '.claude'),\n\t\tpath.join(hostHome, '.codex'),\n\t\tpath.join(hostHome, '.gemini'),\n\t];\n}\n\nexport function resolveGuestMountPath(guestPath: string, workDir: string): string {\n\tif (path.isAbsolute(guestPath)) {\n\t\treturn path.resolve(guestPath);\n\t}\n\n\treturn path.resolve(workDir, guestPath);\n}\n\nfunction isPathWithinPrefix(candidatePath: string, prefixPath: string): boolean {\n\tconst relativePath = path.relative(prefixPath, candidatePath);\n\treturn relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));\n}\n\nasync function normalizeHostPath(hostPath: string): Promise<string> {\n\tconst resolvedHostPath = path.resolve(hostPath);\n\n\ttry {\n\t\treturn await fs.realpath(resolvedHostPath);\n\t} catch {\n\t\treturn resolvedHostPath;\n\t}\n}\n\nfunction pathsOverlap(candidatePath: string, protectedPath: string): boolean {\n\treturn (\n\t\tisPathWithinPrefix(candidatePath, protectedPath) ||\n\t\tisPathWithinPrefix(protectedPath, candidatePath)\n\t);\n}\n\nexport function validateWritableMount(\n\tguestPath: string,\n\tpolicy: WritableMountPolicy,\n\toptions: { readonly workDir: string },\n): void {\n\tconst resolvedGuestPath = resolveGuestMountPath(guestPath, options.workDir);\n\tconst resolvedAllowedPrefixes = policy.writableAllowedGuestPrefixes.map((allowedPrefix) =>\n\t\tresolveGuestMountPath(allowedPrefix, options.workDir),\n\t);\n\n\tconst isAllowedGuestPath = resolvedAllowedPrefixes.some((allowedPrefix) =>\n\t\tisPathWithinPrefix(resolvedGuestPath, allowedPrefix),\n\t);\n\tif (!isAllowedGuestPath) {\n\t\tthrow new Error(\n\t\t\t`Writable mount guest path '${resolvedGuestPath}' is outside writable allowlist [${resolvedAllowedPrefixes.join(', ')}].`,\n\t\t);\n\t}\n\n\tif (!policy.allowAuthWrite) {\n\t\tconst targetsProtectedGuestPath = AUTH_GUEST_PATH_PREFIXES.some((authPrefix) =>\n\t\t\tisPathWithinPrefix(resolvedGuestPath, authPrefix),\n\t\t);\n\t\tif (targetsProtectedGuestPath) {\n\t\t\tthrow new Error(\n\t\t\t\t`Writable mount guest path '${resolvedGuestPath}' targets an auth mount path. Set mountControls.allowAuthWrite=true to permit auth writes.`,\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport async function validateRuntimeMountPolicy(\n\tconfig: RuntimeMountPolicyConfig,\n\toptions: { readonly hostHome: string; readonly workDir: string },\n): Promise<void> {\n\tconst mountEntries = Object.entries(config.extraMounts);\n\tfor (const [guestPath] of mountEntries) {\n\t\tvalidateWritableMount(guestPath, config.mountControls, options);\n\t}\n\n\tif (config.mountControls.allowAuthWrite) {\n\t\treturn;\n\t}\n\n\tconst absoluteHostMountEntries = mountEntries.filter(([, hostPath]) => path.isAbsolute(hostPath));\n\tconst [protectedHostPaths, writableHostPaths] = await Promise.all([\n\t\tPromise.all(\n\t\t\tresolveAuthHostPrefixes(options.hostHome).map(\n\t\t\t\tasync (authHostPrefix) => await normalizeHostPath(authHostPrefix),\n\t\t\t),\n\t\t),\n\t\tPromise.all(\n\t\t\tabsoluteHostMountEntries.map(async ([, hostPath]) => await normalizeHostPath(hostPath)),\n\t\t),\n\t]);\n\n\tfor (const resolvedWritableHostPath of writableHostPaths) {\n\t\tconst overlapsProtectedHostPath = protectedHostPaths.some((authHostPrefix) =>\n\t\t\tpathsOverlap(resolvedWritableHostPath, authHostPrefix),\n\t\t);\n\n\t\tif (overlapsProtectedHostPath) {\n\t\t\tthrow new Error(\n\t\t\t\t`Writable host path '${resolvedWritableHostPath}' targets an auth host directory. Set mountControls.allowAuthWrite=true to permit auth writes.`,\n\t\t\t);\n\t\t}\n\t}\n}\n","export interface PolicySources {\n\treadonly base: readonly string[];\n\treadonly profile: readonly string[];\n\treadonly extra: readonly string[];\n}\n\nexport function normalizeHostname(rawHostname: string): string {\n\treturn rawHostname.trim().toLowerCase().replace(/\\.+$/u, '');\n}\n\nexport function dedupeStable(values: readonly string[]): string[] {\n\tconst seenHostnames = new Set<string>();\n\tconst normalizedValues: string[] = [];\n\n\tfor (const value of values) {\n\t\tconst normalizedValue = normalizeHostname(value);\n\t\tif (normalizedValue.length === 0 || normalizedValue.startsWith('#')) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!seenHostnames.has(normalizedValue)) {\n\t\t\tseenHostnames.add(normalizedValue);\n\t\t\tnormalizedValues.push(normalizedValue);\n\t\t}\n\t}\n\n\treturn normalizedValues;\n}\n\nexport function compilePolicy(sources: PolicySources): string[] {\n\treturn dedupeStable([...sources.base, ...sources.profile, ...sources.extra]);\n}\n","import { execFile } from 'node:child_process';\n\nimport { createClient } from '@1password/sdk';\n\nimport type { SecretRef } from './types.js';\n\nexport interface SecretResolverClient {\n\treadonly secrets: {\n\t\tresolve(secretReference: string): Promise<string>;\n\t\tresolveAll(secretReferences: readonly string[]): Promise<unknown>;\n\t};\n}\n\nexport interface SecretResolver {\n\tresolve(ref: SecretRef): Promise<string>;\n\tresolveAll(refs: Record<string, SecretRef>): Promise<Record<string, string>>;\n}\n\n// --- Token source: how to obtain the 1Password service account token ---\n\nexport type TokenSource =\n\t| { readonly type: 'op-cli'; readonly ref: string }\n\t| { readonly type: 'env'; readonly envVar?: string | undefined }\n\t| { readonly type: 'keychain'; readonly service: string; readonly account: string };\n\nexport interface ExecFileOptions {\n\treadonly env?: Readonly<Record<string, string | undefined>>;\n}\n\nexport interface ExecFileResult {\n\treadonly stdout: string;\n\treadonly stderr: string;\n}\n\nfunction writeStderr(message: string): void {\n\tprocess.stderr.write(`${message}\\n`);\n}\n\nfunction ensureMacOsForKeychain(): void {\n\tif (process.platform !== 'darwin') {\n\t\tthrow new Error(\n\t\t\t'Keychain token source is only supported on macOS. Use an env or op-cli token source on this platform so cmd-ts can surface a clear startup error.',\n\t\t);\n\t}\n}\n\nfunction execFileAsync(\n\tcommand: string,\n\targs: readonly string[],\n\toptions?: ExecFileOptions,\n): Promise<ExecFileResult> {\n\treturn new Promise((resolve, reject) => {\n\t\texecFile(\n\t\t\tcommand,\n\t\t\t[...args],\n\t\t\t{ env: options?.env, timeout: 30_000 },\n\t\t\t(error, stdout, stderr) => {\n\t\t\t\tif (error) {\n\t\t\t\t\tconst errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\t\t\treject(new Error(`${command} failed: ${stderr.trim() || errorMessage}`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresolve({ stdout, stderr });\n\t\t\t},\n\t\t);\n\t});\n}\n\nconst SAFE_IDENTIFIER_PATTERN = /^[\\w.@-]+$/u;\n\nexport async function resolveServiceAccountToken(\n\tsource: TokenSource,\n\tdependencies?: {\n\t\treadonly execFileAsync?: (\n\t\t\tcommand: string,\n\t\t\targs: readonly string[],\n\t\t\toptions?: ExecFileOptions,\n\t\t) => Promise<ExecFileResult>;\n\t},\n): Promise<string> {\n\tconst exec = dependencies?.execFileAsync ?? execFileAsync;\n\n\tswitch (source.type) {\n\t\tcase 'op-cli': {\n\t\t\t// Uses `op read` which triggers biometric auth (Touch ID) on macOS\n\t\t\tconst result = await exec('op', ['read', source.ref]);\n\t\t\tconst token = result.stdout.trim();\n\t\t\tif (token.length === 0) {\n\t\t\t\tthrow new Error('op-cli token resolution returned empty value');\n\t\t\t}\n\n\t\t\treturn token;\n\t\t}\n\n\t\tcase 'env': {\n\t\t\tconst envVar = source.envVar ?? 'OP_SERVICE_ACCOUNT_TOKEN';\n\t\t\tconst token = process.env[envVar]?.trim();\n\t\t\tif (!token) {\n\t\t\t\tthrow new Error(`Environment variable ${envVar} is not set`);\n\t\t\t}\n\n\t\t\treturn token;\n\t\t}\n\n\t\tcase 'keychain': {\n\t\t\tensureMacOsForKeychain();\n\n\t\t\t// Validate keychain identifiers to prevent argument injection\n\t\t\tif (!SAFE_IDENTIFIER_PATTERN.test(source.service)) {\n\t\t\t\tthrow new Error('Keychain service name contains invalid characters');\n\t\t\t}\n\n\t\t\tif (!SAFE_IDENTIFIER_PATTERN.test(source.account)) {\n\t\t\t\tthrow new Error('Keychain account name contains invalid characters');\n\t\t\t}\n\n\t\t\t// macOS Keychain via `security find-generic-password`\n\t\t\tconst result = await exec('security', [\n\t\t\t\t'find-generic-password',\n\t\t\t\t'-s',\n\t\t\t\tsource.service,\n\t\t\t\t'-a',\n\t\t\t\tsource.account,\n\t\t\t\t'-w',\n\t\t\t]);\n\t\t\tconst token = result.stdout.trim();\n\t\t\tif (token.length === 0) {\n\t\t\t\tthrow new Error('Keychain token resolution returned empty value');\n\t\t\t}\n\n\t\t\treturn token;\n\t\t}\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported token source: ${JSON.stringify(source)}`);\n\t}\n}\n\n// --- Secret resolver: uses the token to resolve secrets via 1Password SDK ---\n\nexport interface CreateSecretResolverDependencies {\n\treadonly createClient?: (config: {\n\t\tauth: string;\n\t\tintegrationName: string;\n\t\tintegrationVersion: string;\n\t}) => Promise<SecretResolverClient>;\n\treadonly execFileAsync?: (\n\t\tcommand: string,\n\t\targs: readonly string[],\n\t\toptions?: ExecFileOptions,\n\t) => Promise<ExecFileResult>;\n\treadonly integrationName?: string;\n\treadonly integrationVersion?: string;\n}\n\nasync function resolveSecretWithOpCli(\n\tserviceAccountToken: string,\n\tsecretReference: string,\n\texec: (\n\t\tcommand: string,\n\t\targs: readonly string[],\n\t\toptions?: ExecFileOptions,\n\t) => Promise<ExecFileResult>,\n): Promise<string> {\n\tconst result = await exec('op', ['read', secretReference], {\n\t\tenv: {\n\t\t\t...process.env,\n\t\t\tOP_SERVICE_ACCOUNT_TOKEN: serviceAccountToken,\n\t\t},\n\t});\n\treturn result.stdout.trim();\n}\n\nasync function resolveAllSecretsWithOpCli(\n\tserviceAccountToken: string,\n\trefs: Record<string, SecretRef>,\n\texec: (\n\t\tcommand: string,\n\t\targs: readonly string[],\n\t\toptions?: ExecFileOptions,\n\t) => Promise<ExecFileResult>,\n): Promise<Record<string, string>> {\n\tconst resolvedSecrets: Record<string, string> = {};\n\n\tfor (const [secretName, secretRef] of Object.entries(refs)) {\n\t\t// Sequential resolution avoids concurrent `op read` failures with the same service account token.\n\t\t// oxlint-disable-next-line eslint/no-await-in-loop\n\t\tresolvedSecrets[secretName] = await resolveSecretWithOpCli(\n\t\t\tserviceAccountToken,\n\t\t\tsecretRef.ref,\n\t\t\texec,\n\t\t);\n\t}\n\n\treturn resolvedSecrets;\n}\n\nexport async function createSecretResolver(\n\toptions: {\n\t\treadonly serviceAccountToken: string;\n\t},\n\tdependencies: CreateSecretResolverDependencies = {},\n): Promise<SecretResolver> {\n\tconst exec = dependencies.execFileAsync ?? execFileAsync;\n\ttry {\n\t\tconst client = await (dependencies.createClient ?? createClient)({\n\t\t\tauth: options.serviceAccountToken,\n\t\t\tintegrationName: dependencies.integrationName ?? 'agent-vm',\n\t\t\tintegrationVersion: dependencies.integrationVersion ?? '0.0.1',\n\t\t});\n\n\t\treturn {\n\t\t\tresolve: async (ref: SecretRef): Promise<string> => {\n\t\t\t\ttry {\n\t\t\t\t\treturn await client.secrets.resolve(ref.ref);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\twriteStderr(\n\t\t\t\t\t\t`[secret-resolver] 1Password SDK resolve failed for ${ref.ref}; falling back to op CLI: ${message}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn await resolveSecretWithOpCli(options.serviceAccountToken, ref.ref, exec);\n\t\t\t\t}\n\t\t\t},\n\t\t\tresolveAll: async (refs: Record<string, SecretRef>): Promise<Record<string, string>> => {\n\t\t\t\tconst resolvedSecrets: Record<string, string> = {};\n\n\t\t\t\tfor (const [secretName, secretRef] of Object.entries(refs)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// oxlint-disable-next-line eslint/no-await-in-loop\n\t\t\t\t\t\tresolvedSecrets[secretName] = await client.secrets.resolve(secretRef.ref);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\t\t\twriteStderr(\n\t\t\t\t\t\t\t`[secret-resolver] 1Password SDK resolve failed for ${secretRef.ref}; falling back to op CLI: ${message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// Sequential fallback avoids concurrent `op read` failures when the SDK path is unhealthy.\n\t\t\t\t\t\t// oxlint-disable-next-line eslint/no-await-in-loop\n\t\t\t\t\t\tresolvedSecrets[secretName] = await resolveSecretWithOpCli(\n\t\t\t\t\t\t\toptions.serviceAccountToken,\n\t\t\t\t\t\t\tsecretRef.ref,\n\t\t\t\t\t\t\texec,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn resolvedSecrets;\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\twriteStderr(\n\t\t\t`[secret-resolver] 1Password SDK client creation failed; falling back to op CLI: ${message}`,\n\t\t);\n\t\treturn {\n\t\t\tresolve: async (ref: SecretRef): Promise<string> =>\n\t\t\t\tawait resolveSecretWithOpCli(options.serviceAccountToken, ref.ref, exec),\n\t\t\tresolveAll: async (refs: Record<string, SecretRef>): Promise<Record<string, string>> =>\n\t\t\t\tawait resolveAllSecretsWithOpCli(options.serviceAccountToken, refs, exec),\n\t\t};\n\t}\n}\n\nexport async function createOpCliSecretResolver(\n\toptions: {\n\t\treadonly serviceAccountToken: string;\n\t},\n\tdependencies: Pick<CreateSecretResolverDependencies, 'execFileAsync'> = {},\n): Promise<SecretResolver> {\n\tconst exec = dependencies.execFileAsync ?? execFileAsync;\n\n\treturn {\n\t\tresolve: async (ref: SecretRef): Promise<string> =>\n\t\t\tawait resolveSecretWithOpCli(options.serviceAccountToken, ref.ref, exec),\n\t\tresolveAll: async (refs: Record<string, SecretRef>): Promise<Record<string, string>> =>\n\t\t\tawait resolveAllSecretsWithOpCli(options.serviceAccountToken, refs, exec),\n\t};\n}\n","import {\n\tMemoryProvider,\n\tReadonlyProvider,\n\tRealFSProvider,\n\tShadowProvider,\n\tVM,\n\tcreateHttpHooks,\n\tcreateShadowPathPredicate,\n} from '@earendil-works/gondolin';\n\nimport type { SecretSpec } from './types.js';\n\nexport interface ExecResult {\n\treadonly exitCode: number;\n\treadonly stdout: string;\n\treadonly stderr: string;\n}\n\nexport interface IngressRoute {\n\treadonly prefix: string;\n\treadonly port: number;\n\treadonly stripPrefix?: boolean;\n}\n\nexport interface SshAccess {\n\treadonly host: string;\n\treadonly command?: string;\n\treadonly identityFile?: string;\n\treadonly port: number;\n\treadonly user?: string;\n}\n\nexport interface IngressAccess {\n\treadonly host: string;\n\treadonly port: number;\n}\n\nexport interface ManagedVmInstance {\n\treadonly id: string;\n\texec(command: string): Promise<{\n\t\treadonly exitCode: number;\n\t\treadonly stdout?: string;\n\t\treadonly stderr?: string;\n\t}>;\n\tenableSsh(options?: unknown): Promise<SshAccess>;\n\tenableIngress(options?: unknown): Promise<IngressAccess>;\n\tsetIngressRoutes(routes: readonly IngressRoute[]): void;\n\tclose(): Promise<void>;\n}\n\nexport interface ManagedVmDependencies {\n\tcreateVm(vmOptions: unknown): Promise<ManagedVmInstance>;\n\tcreateHttpHooks(options: {\n\t\treadonly allowedHosts: readonly string[];\n\t\treadonly secrets: Record<string, SecretSpec>;\n\t\treadonly onRequest?: (request: Request) => Promise<Request | Response | void>;\n\t\treadonly onResponse?: (response: Response) => Promise<Response | void>;\n\t}): {\n\t\treadonly env: Record<string, string>;\n\t\treadonly httpHooks: unknown;\n\t};\n\tcreateRealFsProvider(hostPath: string): unknown;\n\tcreateReadonlyProvider(provider: unknown): unknown;\n\tcreateMemoryProvider(): unknown;\n\tcreateShadowProvider(provider: unknown, options: unknown): unknown;\n\tcreateShadowPathPredicate(paths: readonly string[]): unknown;\n}\n\nexport interface VfsMountSpec {\n\treadonly kind: 'realfs' | 'realfs-readonly' | 'memory' | 'shadow';\n\treadonly hostPath?: string;\n\treadonly shadowConfig?: {\n\t\treadonly deny: readonly string[];\n\t\treadonly tmpfs: readonly string[];\n\t};\n}\n\nexport interface CreateVmOptions {\n\treadonly imagePath: string;\n\treadonly memory: string;\n\treadonly cpus: number;\n\treadonly rootfsMode: 'readonly' | 'memory' | 'cow';\n\treadonly allowedHosts: readonly string[];\n\treadonly secrets: Record<string, SecretSpec>;\n\treadonly vfsMounts: Record<string, VfsMountSpec>;\n\treadonly tcpHosts?: Record<string, string>;\n\treadonly env?: Record<string, string>;\n\treadonly sessionLabel?: string;\n\treadonly onRequest?: (request: Request) => Promise<Request | Response | void>;\n\treadonly onResponse?: (response: Response) => Promise<Response | void>;\n}\n\nexport interface ManagedVm {\n\treadonly id: string;\n\texec(command: string): Promise<ExecResult>;\n\tenableSsh(options?: unknown): Promise<SshAccess>;\n\tenableIngress(options?: unknown): Promise<IngressAccess>;\n\tgetVmInstance(): ManagedVmInstance;\n\tsetIngressRoutes(routes: readonly IngressRoute[]): void;\n\tclose(): Promise<void>;\n}\n\n/* oxlint-disable typescript-eslint/no-unsafe-type-assertion -- Gondolin SDK boundary:\n The dependency injection pattern uses `unknown` to decouple from SDK internals.\n The `as never` casts bridge our unknown-typed providers to the SDK's concrete types. */\nfunction createDefaultDependencies(): ManagedVmDependencies {\n\treturn {\n\t\tcreateVm: async (vmOptions: unknown): Promise<ManagedVmInstance> =>\n\t\t\t(await VM.create(vmOptions as never)) as unknown as ManagedVmInstance,\n\t\tcreateHttpHooks: (hookOptions) =>\n\t\t\tcreateHttpHooks({\n\t\t\t\tallowedHosts: [...hookOptions.allowedHosts],\n\t\t\t\tsecrets: Object.fromEntries(\n\t\t\t\t\tObject.entries(hookOptions.secrets).map(([secretName, secretSpec]) => [\n\t\t\t\t\t\tsecretName,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thosts: [...secretSpec.hosts],\n\t\t\t\t\t\t\tvalue: secretSpec.value,\n\t\t\t\t\t\t},\n\t\t\t\t\t]),\n\t\t\t\t),\n\t\t\t\t...(hookOptions.onRequest ? { onRequest: hookOptions.onRequest } : {}),\n\t\t\t\t...(hookOptions.onResponse ? { onResponse: hookOptions.onResponse } : {}),\n\t\t\t}),\n\t\tcreateRealFsProvider: (hostPath: string): unknown => new RealFSProvider(hostPath),\n\t\tcreateReadonlyProvider: (provider: unknown): unknown => new ReadonlyProvider(provider as never),\n\t\tcreateMemoryProvider: (): unknown => new MemoryProvider(),\n\t\tcreateShadowProvider: (provider: unknown, shadowOptions: unknown): unknown =>\n\t\t\tnew ShadowProvider(provider as never, shadowOptions as never),\n\t\tcreateShadowPathPredicate: (paths: readonly string[]): unknown =>\n\t\t\tcreateShadowPathPredicate([...paths]),\n\t};\n}\n/* oxlint-enable typescript-eslint/no-unsafe-type-assertion */\n\nfunction normalizeShadowPath(pathValue: string): string {\n\tconst trimmedPath = pathValue.trim();\n\tif (trimmedPath.startsWith('/')) {\n\t\treturn trimmedPath;\n\t}\n\n\tconst relativePath = trimmedPath.startsWith('./') ? trimmedPath.slice('./'.length) : trimmedPath;\n\treturn `/${relativePath}`;\n}\n\nfunction createProviderFromSpec(\n\tmountSpec: VfsMountSpec,\n\tdependencies: ManagedVmDependencies,\n): unknown {\n\tswitch (mountSpec.kind) {\n\t\tcase 'memory':\n\t\t\treturn dependencies.createMemoryProvider();\n\t\tcase 'realfs': {\n\t\t\tif (!mountSpec.hostPath) {\n\t\t\t\tthrow new Error('realfs mounts require hostPath');\n\t\t\t}\n\n\t\t\treturn dependencies.createRealFsProvider(mountSpec.hostPath);\n\t\t}\n\t\tcase 'realfs-readonly': {\n\t\t\tif (!mountSpec.hostPath) {\n\t\t\t\tthrow new Error('realfs-readonly mounts require hostPath');\n\t\t\t}\n\n\t\t\treturn dependencies.createReadonlyProvider(\n\t\t\t\tdependencies.createRealFsProvider(mountSpec.hostPath),\n\t\t\t);\n\t\t}\n\t\tcase 'shadow': {\n\t\t\tconst baseProvider = mountSpec.hostPath\n\t\t\t\t? dependencies.createRealFsProvider(mountSpec.hostPath)\n\t\t\t\t: dependencies.createMemoryProvider();\n\n\t\t\tlet shadowProvider = baseProvider;\n\t\t\tconst shadowConfig = mountSpec.shadowConfig;\n\n\t\t\tif (shadowConfig?.deny.length) {\n\t\t\t\tshadowProvider = dependencies.createShadowProvider(shadowProvider, {\n\t\t\t\t\tshouldShadow: dependencies.createShadowPathPredicate(\n\t\t\t\t\t\tshadowConfig.deny.map((shadowPath) => normalizeShadowPath(shadowPath)),\n\t\t\t\t\t),\n\t\t\t\t\twriteMode: 'deny',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (shadowConfig?.tmpfs.length) {\n\t\t\t\tshadowProvider = dependencies.createShadowProvider(shadowProvider, {\n\t\t\t\t\tshouldShadow: dependencies.createShadowPathPredicate(\n\t\t\t\t\t\tshadowConfig.tmpfs.map((shadowPath) => normalizeShadowPath(shadowPath)),\n\t\t\t\t\t),\n\t\t\t\t\twriteMode: 'tmpfs',\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn shadowProvider;\n\t\t}\n\t\tdefault: {\n\t\t\tthrow new Error(`Unsupported VFS mount kind: ${String(mountSpec.kind)}`);\n\t\t}\n\t}\n}\n\nfunction createVfsMounts(\n\tvfsMounts: Record<string, VfsMountSpec>,\n\tdependencies: ManagedVmDependencies,\n): Record<string, unknown> {\n\tconst mountMap: Record<string, unknown> = {};\n\n\tfor (const [guestPath, mountSpec] of Object.entries(vfsMounts)) {\n\t\tmountMap[guestPath] = createProviderFromSpec(mountSpec, dependencies);\n\t}\n\n\treturn mountMap;\n}\n\nexport async function createManagedVm(\n\toptions: CreateVmOptions,\n\tdependencies: ManagedVmDependencies = createDefaultDependencies(),\n): Promise<ManagedVm> {\n\tconst hookBundle = dependencies.createHttpHooks({\n\t\tallowedHosts: options.allowedHosts,\n\t\tsecrets: options.secrets,\n\t\t...(options.onRequest ? { onRequest: options.onRequest } : {}),\n\t\t...(options.onResponse ? { onResponse: options.onResponse } : {}),\n\t});\n\n\tconst hasTcpHosts = options.tcpHosts && Object.keys(options.tcpHosts).length > 0;\n\tconst hasImagePath = options.imagePath !== undefined && options.imagePath.length > 0;\n\tconst sandboxOptions = hasImagePath ? { imagePath: options.imagePath } : {};\n\tconst vmInstance = await dependencies.createVm({\n\t\t...(Object.keys(sandboxOptions).length > 0 ? { sandbox: sandboxOptions } : {}),\n\t\tsessionLabel: options.sessionLabel,\n\t\trootfs: {\n\t\t\tmode: options.rootfsMode,\n\t\t},\n\t\tmemory: options.memory,\n\t\tcpus: options.cpus,\n\t\tenv: {\n\t\t\t...hookBundle.env,\n\t\t\t...options.env,\n\t\t},\n\t\thttpHooks: hookBundle.httpHooks,\n\t\tvfs: {\n\t\t\tfuseMount: '/data',\n\t\t\tmounts: createVfsMounts(options.vfsMounts, dependencies),\n\t\t},\n\t\t...(hasTcpHosts\n\t\t\t? {\n\t\t\t\t\tdns: {\n\t\t\t\t\t\tmode: 'synthetic',\n\t\t\t\t\t\tsyntheticHostMapping: 'per-host',\n\t\t\t\t\t},\n\t\t\t\t\ttcp: {\n\t\t\t\t\t\thosts: options.tcpHosts,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t});\n\n\treturn {\n\t\tid: vmInstance.id,\n\t\tasync exec(command: string): Promise<ExecResult> {\n\t\t\tconst executionResult = await vmInstance.exec(command);\n\t\t\treturn {\n\t\t\t\texitCode: executionResult.exitCode,\n\t\t\t\tstdout: executionResult.stdout ?? '',\n\t\t\t\tstderr: executionResult.stderr ?? '',\n\t\t\t};\n\t\t},\n\t\tasync enableSsh(sshOptions?: unknown): Promise<SshAccess> {\n\t\t\treturn await vmInstance.enableSsh(sshOptions);\n\t\t},\n\t\tasync enableIngress(ingressOptions?: unknown): Promise<IngressAccess> {\n\t\t\treturn await vmInstance.enableIngress(ingressOptions);\n\t\t},\n\t\tgetVmInstance(): ManagedVmInstance {\n\t\t\treturn vmInstance;\n\t\t},\n\t\tsetIngressRoutes(routes: readonly IngressRoute[]): void {\n\t\t\tvmInstance.setIngressRoutes(routes);\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tawait vmInstance.close();\n\t\t},\n\t};\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport interface VolumeConfigEntry {\n\treadonly guestPath: string;\n}\n\nexport interface ResolvedVolume {\n\treadonly hostDir: string;\n\treadonly guestPath: string;\n}\n\nexport async function ensureVolumeDir(\n\tcacheBase: string,\n\tworkspaceHash: string,\n\tvolumeName: string,\n): Promise<string> {\n\tconst volumeDirectory = path.join(cacheBase, workspaceHash, volumeName);\n\tawait fs.mkdir(volumeDirectory, { recursive: true });\n\treturn volumeDirectory;\n}\n\nexport async function resolveVolumeDirs(\n\tcacheBase: string,\n\tworkspaceHash: string,\n\tvolumes: Readonly<Record<string, VolumeConfigEntry>>,\n): Promise<Record<string, ResolvedVolume>> {\n\tconst resolvedVolumeEntries = await Promise.all(\n\t\tObject.entries(volumes).map(\n\t\t\tasync ([volumeName, volumeConfig]) =>\n\t\t\t\t[\n\t\t\t\t\tvolumeName,\n\t\t\t\t\t{\n\t\t\t\t\t\tguestPath: volumeConfig.guestPath,\n\t\t\t\t\t\thostDir: await ensureVolumeDir(cacheBase, workspaceHash, volumeName),\n\t\t\t\t\t},\n\t\t\t\t] satisfies readonly [string, ResolvedVolume],\n\t\t),\n\t);\n\n\treturn Object.fromEntries(resolvedVolumeEntries);\n}\n","import fs from 'node:fs/promises';\n\nexport async function writeFileAtomically(\n\tfilePath: string,\n\tcontent: string,\n\toptions: {\n\t\treadonly mode?: number;\n\t} = {},\n): Promise<void> {\n\tconst temporaryFilePath = `${filePath}.${process.pid}.${Date.now()}.tmp`;\n\tawait fs.writeFile(temporaryFilePath, content, {\n\t\tencoding: 'utf8',\n\t\t...(options.mode ? { mode: options.mode } : {}),\n\t});\n\ttry {\n\t\tawait fs.rename(temporaryFilePath, filePath);\n\t} catch (renameError) {\n\t\ttry {\n\t\t\tawait fs.rm(temporaryFilePath, { force: true });\n\t\t} catch (cleanupError) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to replace '${filePath}' (${renameError instanceof Error ? renameError.message : JSON.stringify(renameError)}) and failed to remove temporary file '${temporaryFilePath}': ${cleanupError instanceof Error ? cleanupError.message : JSON.stringify(cleanupError)}`,\n\t\t\t\t{ cause: cleanupError },\n\t\t\t);\n\t\t}\n\t\tthrow renameError;\n\t}\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-vm/gondolin-adapter",
|
|
3
|
+
"version": "0.0.20",
|
|
4
|
+
"description": "Adapter over @earendil-works/gondolin: VM build pipeline, image cache, and secret resolver.",
|
|
5
|
+
"homepage": "https://github.com/ShravanSunder/agent-vm#readme",
|
|
6
|
+
"bugs": {
|
|
7
|
+
"url": "https://github.com/ShravanSunder/agent-vm/issues"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "Shravan Sunder <ShravanSunder@users.noreply.github.com>",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ShravanSunder/agent-vm.git",
|
|
14
|
+
"directory": "packages/gondolin-adapter"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@1password/sdk": "^0.4.0",
|
|
33
|
+
"@earendil-works/gondolin": "0.8.0",
|
|
34
|
+
"zod": "^4"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsdown",
|
|
38
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
39
|
+
}
|
|
40
|
+
}
|