@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.
@@ -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
- export function resolveAgenCHome(env = process.env, userHome = homedir()) {
80
- const configured = env.AGENC_HOME;
81
- const requested = configured && configured.length > 0
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: AGENC_HOME must be an absolute path so its identity does not change with the working directory",
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
- return resolve(requested);
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
- // GLOBALROOT reaches the kernel's real SystemRoot namespace and cannot be
1110
- // redirected with caller-controlled SystemRoot/WINDIR values or drive maps.
1111
- const system32 = win32.join(WINDOWS_SYSTEM_ROOT, "System32");
1112
- const powershellRoot = win32.join(system32, "WindowsPowerShell", "v1.0");
1113
- const tarPath = win32.join(system32, "tar.exe");
1114
- const powershell = win32.join(powershellRoot, "powershell.exe");
1115
- for (const [path, label] of [[tarPath, "tar"], [powershell, "PowerShell"]]) {
1116
- const metadata = lstatSync(path, { bigint: true });
1117
- if (!metadata.isFile() || metadata.isSymbolicLink()) {
1118
- throw new Error(`agenc: trusted Windows ${label} is unavailable`);
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
- SystemRoot: WINDOWS_SYSTEM_ROOT,
1130
- TEMP: win32.join(WINDOWS_SYSTEM_ROOT, "Temp"),
1131
- TMP: win32.join(WINDOWS_SYSTEM_ROOT, "Temp"),
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: WINDOWS_SYSTEM_ROOT,
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 { path: tarPath, env };
1295
+ return {
1296
+ path: trustedWindowsSystemExecutable(windowsPaths, ["System32", "tar.exe"]),
1297
+ env,
1298
+ };
1163
1299
  }
1164
1300
 
1165
1301
  function extractTarGz(archive, destDir) {
@@ -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
  }