@tetsuo-ai/agenc 0.16.1 → 0.19.0
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/generated/agenc-runtime-manifest-v2.json +104 -102
- package/generated/startup-preflight.mjs +1 -0
- package/lib/generated-wrapper.mjs +49 -12
- package/lib/home-authority.d.mts +26 -0
- package/lib/home-authority.mjs +64 -0
- package/lib/runtime-manager.mjs +161 -25
- package/lib/sqlite-lock.d.mts +4 -0
- package/lib/sqlite-lock.mjs +375 -38
- package/package.json +6 -3
- package/scripts/postinstall.mjs +23 -2
- package/src/launcher.mjs +163 -38
package/lib/runtime-manager.mjs
CHANGED
|
@@ -56,6 +56,9 @@ import {
|
|
|
56
56
|
validateRuntimeReleaseManifest,
|
|
57
57
|
} from "./runtime-release-contract.mjs";
|
|
58
58
|
import { acquireLocalSqliteLock } from "./sqlite-lock.mjs";
|
|
59
|
+
import { resolveAgenCHome } from "./home-authority.mjs";
|
|
60
|
+
|
|
61
|
+
export { resolveAgenCHome } from "./home-authority.mjs";
|
|
59
62
|
|
|
60
63
|
export {
|
|
61
64
|
MAX_RUNTIME_ARTIFACT_BYTES,
|
|
@@ -75,18 +78,140 @@ const MANIFEST_PATH = resolve(
|
|
|
75
78
|
const DEFAULT_RUNTIME_FETCH_TIMEOUT_MS = 120_000;
|
|
76
79
|
const DEFAULT_RUNTIME_EXTRACTION_TIMEOUT_MS = 120_000;
|
|
77
80
|
const WINDOWS_SYSTEM_ROOT = String.raw`\\?\GLOBALROOT\SystemRoot`;
|
|
81
|
+
const WINDOWS_INVALID_FILE_ID = 0xffff_ffff_ffff_ffffn;
|
|
82
|
+
const WINDOWS_RESERVED_DEVICE_BASENAME =
|
|
83
|
+
/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\..*)?$/iu;
|
|
84
|
+
const WINDOWS_EXECUTABLE_FILESYSTEM = {
|
|
85
|
+
lstat: (path) => lstatSync(path, { bigint: true }),
|
|
86
|
+
open: (path) => openSync(
|
|
87
|
+
path,
|
|
88
|
+
fsConstants.O_RDONLY | (fsConstants.O_NOFOLLOW ?? 0),
|
|
89
|
+
),
|
|
90
|
+
fstat: (descriptor) => fstatSync(descriptor, { bigint: true }),
|
|
91
|
+
close: closeSync,
|
|
92
|
+
};
|
|
78
93
|
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
? configured
|
|
83
|
-
: join(userHome, ".agenc");
|
|
84
|
-
if (!isAbsolute(requested)) {
|
|
94
|
+
function trustedWindowsSystemPaths(canonicalize = realpathSync.native) {
|
|
95
|
+
const systemRoot = canonicalize(WINDOWS_SYSTEM_ROOT);
|
|
96
|
+
if (!/^[a-z]:\\/iu.test(systemRoot) || win32.normalize(systemRoot) !== systemRoot) {
|
|
85
97
|
throw new Error(
|
|
86
|
-
"agenc:
|
|
98
|
+
"agenc: trusted Windows SystemRoot did not resolve to a canonical local DOS path",
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
const system32 = win32.join(systemRoot, "System32");
|
|
102
|
+
const powershellRoot = win32.join(system32, "WindowsPowerShell", "v1.0");
|
|
103
|
+
return {
|
|
104
|
+
systemRoot,
|
|
105
|
+
system32,
|
|
106
|
+
powershellRoot,
|
|
107
|
+
namespaceSystemRoot: WINDOWS_SYSTEM_ROOT,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function trustedWindowsSystemExecutable(
|
|
112
|
+
paths,
|
|
113
|
+
relativeSegments,
|
|
114
|
+
filesystem = WINDOWS_EXECUTABLE_FILESYSTEM,
|
|
115
|
+
) {
|
|
116
|
+
if (
|
|
117
|
+
relativeSegments.length === 0 ||
|
|
118
|
+
relativeSegments.some((segment) => !isSafeWindowsExecutableSegment(segment))
|
|
119
|
+
) {
|
|
120
|
+
throw new TypeError("trusted Windows executable segments are invalid");
|
|
121
|
+
}
|
|
122
|
+
const executable = win32.join(paths.systemRoot, ...relativeSegments);
|
|
123
|
+
const namespaceExecutable = win32.join(
|
|
124
|
+
paths.namespaceSystemRoot,
|
|
125
|
+
...relativeSegments,
|
|
126
|
+
);
|
|
127
|
+
verifyWindowsExecutableAliases(namespaceExecutable, executable, filesystem);
|
|
128
|
+
return executable;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isSafeWindowsExecutableSegment(segment) {
|
|
132
|
+
return segment.length > 0 && segment !== "." && segment !== ".." &&
|
|
133
|
+
win32.basename(segment) === segment &&
|
|
134
|
+
!/[\u0000-\u001f<>:"/\\|?*]/u.test(segment) && !/[ .]$/u.test(segment) &&
|
|
135
|
+
!WINDOWS_RESERVED_DEVICE_BASENAME.test(segment);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function verifyWindowsExecutableAliases(namespaceExecutable, executable, filesystem) {
|
|
139
|
+
let namespaceDescriptor;
|
|
140
|
+
let candidateDescriptor;
|
|
141
|
+
let operationError;
|
|
142
|
+
try {
|
|
143
|
+
const namespaceBefore = filesystem.lstat(namespaceExecutable);
|
|
144
|
+
const candidateBefore = filesystem.lstat(executable);
|
|
145
|
+
assertRegularWindowsExecutable(namespaceBefore, "GLOBALROOT path");
|
|
146
|
+
assertRegularWindowsExecutable(candidateBefore, "DOS path");
|
|
147
|
+
namespaceDescriptor = filesystem.open(namespaceExecutable);
|
|
148
|
+
candidateDescriptor = filesystem.open(executable);
|
|
149
|
+
const namespaceOpened = filesystem.fstat(namespaceDescriptor);
|
|
150
|
+
const candidateOpened = filesystem.fstat(candidateDescriptor);
|
|
151
|
+
const namespaceAfter = filesystem.lstat(namespaceExecutable);
|
|
152
|
+
const candidateAfter = filesystem.lstat(executable);
|
|
153
|
+
assertRegularWindowsExecutable(namespaceOpened, "GLOBALROOT descriptor");
|
|
154
|
+
assertRegularWindowsExecutable(candidateOpened, "DOS descriptor");
|
|
155
|
+
assertRegularWindowsExecutable(namespaceAfter, "GLOBALROOT path");
|
|
156
|
+
assertRegularWindowsExecutable(candidateAfter, "DOS path");
|
|
157
|
+
for (const identity of [
|
|
158
|
+
namespaceBefore,
|
|
159
|
+
candidateBefore,
|
|
160
|
+
namespaceOpened,
|
|
161
|
+
candidateOpened,
|
|
162
|
+
namespaceAfter,
|
|
163
|
+
candidateAfter,
|
|
164
|
+
]) {
|
|
165
|
+
if (
|
|
166
|
+
identity.dev <= 0n || identity.ino <= 0n ||
|
|
167
|
+
identity.dev === WINDOWS_INVALID_FILE_ID || identity.ino === WINDOWS_INVALID_FILE_ID
|
|
168
|
+
) {
|
|
169
|
+
throw new Error("trusted Windows system executable identity is unavailable");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (
|
|
173
|
+
!sameWindowsExecutableIdentity(namespaceBefore, namespaceOpened) ||
|
|
174
|
+
!sameWindowsExecutableIdentity(namespaceOpened, namespaceAfter) ||
|
|
175
|
+
!sameWindowsExecutableIdentity(candidateBefore, candidateOpened) ||
|
|
176
|
+
!sameWindowsExecutableIdentity(candidateOpened, candidateAfter) ||
|
|
177
|
+
!sameWindowsExecutableIdentity(namespaceOpened, candidateOpened)
|
|
178
|
+
) {
|
|
179
|
+
throw new Error("trusted Windows system executable identity mismatch");
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
operationError = error;
|
|
183
|
+
}
|
|
184
|
+
const closeErrors = [];
|
|
185
|
+
for (const descriptor of [candidateDescriptor, namespaceDescriptor]) {
|
|
186
|
+
if (descriptor === undefined) continue;
|
|
187
|
+
try { filesystem.close(descriptor); } catch (error) { closeErrors.push(error); }
|
|
188
|
+
}
|
|
189
|
+
if (operationError !== undefined) {
|
|
190
|
+
if (closeErrors.length > 0) {
|
|
191
|
+
throw new AggregateError(
|
|
192
|
+
[operationError, ...closeErrors],
|
|
193
|
+
"trusted Windows executable validation and cleanup both failed",
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
throw operationError;
|
|
197
|
+
}
|
|
198
|
+
if (closeErrors.length === 1) throw closeErrors[0];
|
|
199
|
+
if (closeErrors.length > 1) {
|
|
200
|
+
throw new AggregateError(
|
|
201
|
+
closeErrors,
|
|
202
|
+
"trusted Windows executable descriptor cleanup failed",
|
|
87
203
|
);
|
|
88
204
|
}
|
|
89
|
-
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function assertRegularWindowsExecutable(identity, spelling) {
|
|
208
|
+
if (!identity.isFile() || identity.isSymbolicLink()) {
|
|
209
|
+
throw new Error(`trusted Windows ${spelling} executable is not a regular non-link file`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function sameWindowsExecutableIdentity(left, right) {
|
|
214
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
90
215
|
}
|
|
91
216
|
|
|
92
217
|
function canonicalizeAgenCHome(requested) {
|
|
@@ -1106,31 +1231,39 @@ export function resolveTrustedSystemTar(platform = process.platform) {
|
|
|
1106
1231
|
throw new Error(`agenc: trusted operating-system tar is unsupported on ${platform}`);
|
|
1107
1232
|
}
|
|
1108
1233
|
|
|
1109
|
-
//
|
|
1110
|
-
//
|
|
1111
|
-
const
|
|
1112
|
-
const
|
|
1113
|
-
const tarPath =
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1234
|
+
// Derive CreateProcess-compatible DOS spellings from GLOBALROOT and prove
|
|
1235
|
+
// each executable still aliases its namespace path immediately before use.
|
|
1236
|
+
const windowsPaths = trustedWindowsSystemPaths();
|
|
1237
|
+
const { systemRoot, system32, powershellRoot } = windowsPaths;
|
|
1238
|
+
const tarPath = trustedWindowsSystemExecutable(windowsPaths, [
|
|
1239
|
+
"System32",
|
|
1240
|
+
"tar.exe",
|
|
1241
|
+
]);
|
|
1242
|
+
const powershell = trustedWindowsSystemExecutable(windowsPaths, [
|
|
1243
|
+
"System32",
|
|
1244
|
+
"WindowsPowerShell",
|
|
1245
|
+
"v1.0",
|
|
1246
|
+
"powershell.exe",
|
|
1247
|
+
]);
|
|
1121
1248
|
const env = {
|
|
1122
1249
|
APPDATA: "",
|
|
1123
1250
|
COMSPEC: win32.join(system32, "cmd.exe"),
|
|
1124
1251
|
HOME: "",
|
|
1252
|
+
HOMEDRIVE: "",
|
|
1253
|
+
HOMEPATH: "",
|
|
1125
1254
|
LOCALAPPDATA: "",
|
|
1255
|
+
LOGONSERVER: "",
|
|
1126
1256
|
PATH: `${system32};${powershellRoot}`,
|
|
1127
1257
|
PATHEXT: ".COM;.EXE",
|
|
1128
1258
|
PSModulePath: win32.join(powershellRoot, "Modules"),
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1259
|
+
SYSTEMDRIVE: "",
|
|
1260
|
+
SystemRoot: systemRoot,
|
|
1261
|
+
TEMP: win32.join(systemRoot, "Temp"),
|
|
1262
|
+
TMP: win32.join(systemRoot, "Temp"),
|
|
1263
|
+
USERDOMAIN: "",
|
|
1264
|
+
USERNAME: "",
|
|
1132
1265
|
USERPROFILE: powershellRoot,
|
|
1133
|
-
WINDIR:
|
|
1266
|
+
WINDIR: systemRoot,
|
|
1134
1267
|
};
|
|
1135
1268
|
const signature = spawnSync(
|
|
1136
1269
|
powershell,
|
|
@@ -1159,7 +1292,10 @@ export function resolveTrustedSystemTar(platform = process.platform) {
|
|
|
1159
1292
|
if (signature.error !== undefined || signature.status !== 0) {
|
|
1160
1293
|
throw new Error("agenc: Windows operating-system tar failed Authenticode validation");
|
|
1161
1294
|
}
|
|
1162
|
-
return {
|
|
1295
|
+
return {
|
|
1296
|
+
path: trustedWindowsSystemExecutable(windowsPaths, ["System32", "tar.exe"]),
|
|
1297
|
+
env,
|
|
1298
|
+
};
|
|
1163
1299
|
}
|
|
1164
1300
|
|
|
1165
1301
|
function extractTarGz(archive, destDir) {
|
package/lib/sqlite-lock.d.mts
CHANGED
|
@@ -4,6 +4,10 @@ export interface LocalSqliteLockOptions {
|
|
|
4
4
|
readonly timeoutMs?: number;
|
|
5
5
|
readonly label?: string;
|
|
6
6
|
readonly deadline?: number;
|
|
7
|
+
/** Optional phase-only diagnostics; never receives a protected path. */
|
|
8
|
+
readonly onProgress?: (phase: string) => void | PromiseLike<void>;
|
|
9
|
+
/** Shorten one busy sleep; does not cancel, grant ownership or renew the deadline. */
|
|
10
|
+
readonly retryWakeSignal?: AbortSignal;
|
|
7
11
|
/** Permit a root/current-user-owned sticky directory as the validated leaf. */
|
|
8
12
|
readonly allowTrustedStickyLeaf?: boolean;
|
|
9
13
|
}
|