@openclaw/crabline 0.1.10 → 0.1.11

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.
@@ -26,12 +26,17 @@ type PublishGenerationDependencies = {
26
26
  secureWindowsFile?: (filePath: string) => Promise<void>;
27
27
  syncParent?: typeof syncParentDirectory;
28
28
  };
29
+ type RecorderSnapshot = {
30
+ contents: string;
31
+ fileName: string;
32
+ };
29
33
  export declare function readOpenClawCrablineArtifactPointer(outputDir: string): Promise<OpenClawCrablineArtifactPointer | null>;
30
34
  export declare function publishOpenClawCrablineArtifactGeneration(params: {
31
35
  capabilityReport: unknown;
32
36
  lock: OpenClawCrablineSmokeRunLock;
33
37
  manifest: CrablineServerManifest;
34
38
  outputDir: string;
39
+ recorderSnapshot?: RecorderSnapshot;
35
40
  selection: OpenClawCrablineChannelDriverSelection;
36
41
  providerReadiness: Record<string, unknown>;
37
42
  }, dependencies?: PublishGenerationDependencies): Promise<PublishedOpenClawCrablineArtifactGeneration>;
@@ -4,6 +4,8 @@ import path from "node:path";
4
4
  import { captureDirectoryIdentity, publishPrivateFileAtomically, removeSecuredPrivateDirectory, securePrivateDirectory, syncParentDirectory, } from "./private-file.js";
5
5
  import { OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH, OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY, OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH, OPENCLAW_CRABLINE_CHANNEL_SMOKE_PATH, OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH, OPENCLAW_CRABLINE_MANIFEST_PATH, } from "./shared.js";
6
6
  const GENERATION_NAME_PATTERN = /^generation-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
7
+ const STAGING_NAME_PATTERN = /^\.staging-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
8
+ const REMOVAL_TOMBSTONE_PATTERN = /^\.(.+)\.\d+\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.remove$/iu;
7
9
  function resolveProviderReadinessArtifactPath(selection) {
8
10
  const readinessPath = selection.providerReadinessArtifactPath ?? selection.smokeArtifactPath;
9
11
  if (selection.capabilityMatrixPath !== OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH ||
@@ -23,6 +25,26 @@ function assertGenerationName(value, field) {
23
25
  function generationArtifactPath(generation, fileName) {
24
26
  return path.join(OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY, generation, fileName);
25
27
  }
28
+ function artifactRemovalTombstoneBaseName(name) {
29
+ const originalName = REMOVAL_TOMBSTONE_PATTERN.exec(name)?.[1];
30
+ return originalName !== undefined &&
31
+ (GENERATION_NAME_PATTERN.test(originalName) || STAGING_NAME_PATTERN.test(originalName))
32
+ ? originalName
33
+ : null;
34
+ }
35
+ function withRecorderSnapshotPath(providerReadiness, recorderPath) {
36
+ const result = providerReadiness.result;
37
+ if (!result || typeof result !== "object" || Array.isArray(result)) {
38
+ throw new Error("OpenClaw Crabline provider readiness result is malformed.");
39
+ }
40
+ return {
41
+ ...providerReadiness,
42
+ result: {
43
+ ...result,
44
+ recorderPath,
45
+ },
46
+ };
47
+ }
26
48
  function parseArtifactPointer(contents) {
27
49
  let value;
28
50
  try {
@@ -95,17 +117,21 @@ async function pruneArtifactStore(params) {
95
117
  ? [params.pointer.generation, params.pointer.previousGeneration].filter((generation) => generation !== undefined)
96
118
  : []);
97
119
  for (const entry of await fs.readdir(params.store.directoryPath, { withFileTypes: true })) {
98
- const isAbandonedStaging = entry.isDirectory() && entry.name.startsWith(".staging-");
120
+ const isAbandonedStaging = entry.isDirectory() && STAGING_NAME_PATTERN.test(entry.name);
99
121
  const isObsoleteGeneration = entry.isDirectory() &&
100
122
  GENERATION_NAME_PATTERN.test(entry.name) &&
101
123
  !retainedGenerations.has(entry.name);
102
- if (!isAbandonedStaging && !isObsoleteGeneration) {
124
+ const removalTombstoneBaseName = entry.isDirectory()
125
+ ? artifactRemovalTombstoneBaseName(entry.name)
126
+ : null;
127
+ const isRemovalTombstone = removalTombstoneBaseName !== null;
128
+ if (!isAbandonedStaging && !isObsoleteGeneration && !isRemovalTombstone) {
103
129
  continue;
104
130
  }
105
131
  await params.lock.assertOwned();
106
132
  await params.store.assertIdentityAt();
107
133
  const obsolete = await securePrivateDirectory(path.join(params.store.directoryPath, entry.name), params.directoryOptions);
108
- await removeSecuredPrivateDirectory(obsolete);
134
+ await removeSecuredPrivateDirectory(obsolete, undefined, removalTombstoneBaseName ?? entry.name);
109
135
  await params.store.assertIdentityAt();
110
136
  }
111
137
  }
@@ -121,6 +147,7 @@ export async function publishOpenClawCrablineArtifactGeneration(params, dependen
121
147
  ...(dependencies.secureWindowsDirectory
122
148
  ? { secureWindowsDirectory: dependencies.secureWindowsDirectory }
123
149
  : {}),
150
+ ...(dependencies.syncParent ? { syncParent: dependencies.syncParent } : {}),
124
151
  };
125
152
  const store = await securePrivateDirectory(storePath, directoryOptions);
126
153
  await output.assertIdentityAt();
@@ -175,13 +202,27 @@ export async function publishOpenClawCrablineArtifactGeneration(params, dependen
175
202
  smokeArtifactPath: generationArtifactPath(generation, providerReadinessArtifactPath),
176
203
  version: 1,
177
204
  };
205
+ if (params.recorderSnapshot &&
206
+ (path.basename(params.recorderSnapshot.fileName) !== params.recorderSnapshot.fileName ||
207
+ !params.recorderSnapshot.fileName.endsWith(".jsonl"))) {
208
+ throw new Error("OpenClaw Crabline recorder snapshot filename is malformed.");
209
+ }
210
+ const recorderSnapshotPath = params.recorderSnapshot
211
+ ? generationArtifactPath(generation, params.recorderSnapshot.fileName)
212
+ : undefined;
213
+ const publishedManifest = recorderSnapshotPath
214
+ ? { ...params.manifest, recorderPath: recorderSnapshotPath }
215
+ : params.manifest;
216
+ const providerReadinessBase = recorderSnapshotPath
217
+ ? withRecorderSnapshotPath(params.providerReadiness, recorderSnapshotPath)
218
+ : params.providerReadiness;
178
219
  const providerReadiness = {
179
- ...params.providerReadiness,
220
+ ...providerReadinessBase,
180
221
  manifestPath: pointer.manifestPath,
181
222
  };
182
223
  const artifactContents = [
183
224
  {
184
- contents: `${JSON.stringify(params.manifest, null, 2)}\n`,
225
+ contents: `${JSON.stringify(publishedManifest, null, 2)}\n`,
185
226
  fileName: OPENCLAW_CRABLINE_MANIFEST_PATH,
186
227
  },
187
228
  {
@@ -207,6 +248,14 @@ export async function publishOpenClawCrablineArtifactGeneration(params, dependen
207
248
  }, null, 2)}\n`,
208
249
  fileName: providerReadinessArtifactPath,
209
250
  },
251
+ ...(params.recorderSnapshot
252
+ ? [
253
+ {
254
+ contents: params.recorderSnapshot.contents,
255
+ fileName: params.recorderSnapshot.fileName,
256
+ },
257
+ ]
258
+ : []),
210
259
  ];
211
260
  await params.lock.assertOwned();
212
261
  for (const artifact of artifactContents) {
@@ -1 +1 @@
1
- {"version":3,"file":"artifact-generation.js","sourceRoot":"","sources":["../../../src/openclaw/artifact-generation.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CrablineServerManifest } from \"../servers/index.js\";\nimport {\n captureDirectoryIdentity,\n publishPrivateFileAtomically,\n removeSecuredPrivateDirectory,\n securePrivateDirectory,\n syncParentDirectory,\n} from \"./private-file.js\";\nimport {\n OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH,\n OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY,\n OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH,\n OPENCLAW_CRABLINE_CHANNEL_SMOKE_PATH,\n OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH,\n OPENCLAW_CRABLINE_MANIFEST_PATH,\n type OpenClawCrablineChannelDriverSelection,\n} from \"./shared.js\";\nimport type { OpenClawCrablineSmokeRunLock } from \"./smoke-lock.js\";\n\nconst GENERATION_NAME_PATTERN =\n /^generation-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;\nexport type OpenClawCrablineArtifactPointer = {\n capabilityMatrixPath: string;\n generation: string;\n manifestPath: string;\n previousGeneration?: string;\n providerReadinessArtifactPath: string;\n smokeArtifactPath: string;\n version: 1;\n};\n\nexport type PublishedOpenClawCrablineArtifactGeneration = OpenClawCrablineArtifactPointer & {\n pointerPath: string;\n providerReadiness: Record<string, unknown>;\n smoke: Record<string, unknown>;\n warnings?: string[];\n};\n\ntype PublishGenerationDependencies = {\n beforePointerSwitch?: (pointer: OpenClawCrablineArtifactPointer) => Promise<void>;\n createGenerationId?: () => string;\n platform?: NodeJS.Platform;\n publishPrivateFile?: typeof publishPrivateFileAtomically;\n secureWindowsDirectory?: (directoryPath: string) => Promise<void>;\n secureWindowsFile?: (filePath: string) => Promise<void>;\n syncParent?: typeof syncParentDirectory;\n};\n\nfunction resolveProviderReadinessArtifactPath(\n selection: OpenClawCrablineChannelDriverSelection,\n): typeof OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH {\n const readinessPath = selection.providerReadinessArtifactPath ?? selection.smokeArtifactPath;\n if (\n selection.capabilityMatrixPath !== OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH ||\n readinessPath !== OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH\n ) {\n throw new Error(\"OpenClaw Crabline artifact selection paths are malformed.\");\n }\n return readinessPath;\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException).code === \"ENOENT\";\n}\n\nfunction assertGenerationName(value: unknown, field: string): asserts value is string {\n if (typeof value !== \"string\" || !GENERATION_NAME_PATTERN.test(value)) {\n throw new Error(`OpenClaw Crabline artifact pointer ${field} is malformed.`);\n }\n}\n\nfunction generationArtifactPath(generation: string, fileName: string): string {\n return path.join(OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY, generation, fileName);\n}\n\nfunction parseArtifactPointer(contents: string): OpenClawCrablineArtifactPointer {\n let value: Partial<OpenClawCrablineArtifactPointer>;\n try {\n value = JSON.parse(contents) as Partial<OpenClawCrablineArtifactPointer>;\n } catch (error) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\", { cause: error });\n }\n if (value.version !== 1) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\");\n }\n assertGenerationName(value.generation, \"generation\");\n if (value.previousGeneration !== undefined) {\n assertGenerationName(value.previousGeneration, \"previousGeneration\");\n if (value.previousGeneration === value.generation) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\");\n }\n }\n\n const expected = {\n capabilityMatrixPath: generationArtifactPath(\n value.generation,\n OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH,\n ),\n manifestPath: generationArtifactPath(value.generation, OPENCLAW_CRABLINE_MANIFEST_PATH),\n providerReadinessArtifactPath: generationArtifactPath(\n value.generation,\n OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH,\n ),\n smokeArtifactPath: generationArtifactPath(\n value.generation,\n OPENCLAW_CRABLINE_CHANNEL_SMOKE_PATH,\n ),\n };\n if (\n typeof value.capabilityMatrixPath !== \"string\" ||\n value.capabilityMatrixPath !== expected.capabilityMatrixPath ||\n value.manifestPath !== expected.manifestPath ||\n (value.providerReadinessArtifactPath !== undefined &&\n value.providerReadinessArtifactPath !== expected.providerReadinessArtifactPath) ||\n (value.smokeArtifactPath !== undefined &&\n value.smokeArtifactPath !== expected.smokeArtifactPath) ||\n (value.providerReadinessArtifactPath === undefined && value.smokeArtifactPath === undefined)\n ) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\");\n }\n\n return {\n capabilityMatrixPath: value.capabilityMatrixPath,\n generation: value.generation,\n ...(value.previousGeneration ? { previousGeneration: value.previousGeneration } : {}),\n manifestPath: value.manifestPath,\n providerReadinessArtifactPath: value.providerReadinessArtifactPath ?? value.smokeArtifactPath!,\n smokeArtifactPath: value.smokeArtifactPath ?? value.providerReadinessArtifactPath!,\n version: 1,\n };\n}\n\nexport async function readOpenClawCrablineArtifactPointer(\n outputDir: string,\n): Promise<OpenClawCrablineArtifactPointer | null> {\n try {\n return parseArtifactPointer(\n await fs.readFile(\n path.join(path.resolve(outputDir), OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH),\n \"utf8\",\n ),\n );\n } catch (error) {\n if (isMissingPathError(error)) {\n return null;\n }\n throw error;\n }\n}\n\nasync function assertCurrentGenerationExists(\n outputDir: string,\n pointer: OpenClawCrablineArtifactPointer,\n): Promise<void> {\n for (const artifactPath of [\n pointer.manifestPath,\n pointer.capabilityMatrixPath,\n pointer.providerReadinessArtifactPath,\n ]) {\n const stats = await fs.lstat(path.join(outputDir, artifactPath));\n if (!stats.isFile()) {\n throw new Error(\"OpenClaw Crabline current artifact generation is incomplete.\");\n }\n }\n}\n\nasync function pruneArtifactStore(params: {\n lock: OpenClawCrablineSmokeRunLock;\n pointer: OpenClawCrablineArtifactPointer | null;\n store: Awaited<ReturnType<typeof securePrivateDirectory>>;\n directoryOptions?: Parameters<typeof securePrivateDirectory>[1];\n}): Promise<void> {\n const retainedGenerations = new Set(\n params.pointer\n ? [params.pointer.generation, params.pointer.previousGeneration].filter(\n (generation): generation is string => generation !== undefined,\n )\n : [],\n );\n for (const entry of await fs.readdir(params.store.directoryPath, { withFileTypes: true })) {\n const isAbandonedStaging = entry.isDirectory() && entry.name.startsWith(\".staging-\");\n const isObsoleteGeneration =\n entry.isDirectory() &&\n GENERATION_NAME_PATTERN.test(entry.name) &&\n !retainedGenerations.has(entry.name);\n if (!isAbandonedStaging && !isObsoleteGeneration) {\n continue;\n }\n await params.lock.assertOwned();\n await params.store.assertIdentityAt();\n const obsolete = await securePrivateDirectory(\n path.join(params.store.directoryPath, entry.name),\n params.directoryOptions,\n );\n await removeSecuredPrivateDirectory(obsolete);\n await params.store.assertIdentityAt();\n }\n}\n\nexport async function publishOpenClawCrablineArtifactGeneration(\n params: {\n capabilityReport: unknown;\n lock: OpenClawCrablineSmokeRunLock;\n manifest: CrablineServerManifest;\n outputDir: string;\n selection: OpenClawCrablineChannelDriverSelection;\n providerReadiness: Record<string, unknown>;\n },\n dependencies: PublishGenerationDependencies = {},\n): Promise<PublishedOpenClawCrablineArtifactGeneration> {\n const providerReadinessArtifactPath = resolveProviderReadinessArtifactPath(params.selection);\n const outputDir = path.resolve(params.outputDir);\n await fs.mkdir(outputDir, { recursive: true });\n const output = await captureDirectoryIdentity(outputDir);\n await output.assertIdentityAt();\n const storePath = path.join(outputDir, OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY);\n const directoryOptions = {\n ...(dependencies.platform ? { platform: dependencies.platform } : {}),\n ...(dependencies.secureWindowsDirectory\n ? { secureWindowsDirectory: dependencies.secureWindowsDirectory }\n : {}),\n };\n const store = await securePrivateDirectory(storePath, directoryOptions);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await params.lock.assertOwned();\n const currentPointer = await readOpenClawCrablineArtifactPointer(outputDir);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n if (currentPointer) {\n await assertCurrentGenerationExists(outputDir, currentPointer);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n }\n await pruneArtifactStore({\n directoryOptions,\n lock: params.lock,\n pointer: currentPointer,\n store,\n });\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n\n const generationId = dependencies.createGenerationId?.() ?? randomUUID();\n const generation = `generation-${generationId}`;\n if (!GENERATION_NAME_PATTERN.test(generation)) {\n throw new Error(\"OpenClaw Crabline artifact generation id is malformed.\");\n }\n const stagingPath = path.join(storePath, `.staging-${generationId}`);\n const generationPath = path.join(storePath, generation);\n const staging = await securePrivateDirectory(stagingPath, directoryOptions);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt();\n const publishPrivateFile = dependencies.publishPrivateFile ?? publishPrivateFileAtomically;\n const fileOptions = {\n ...(dependencies.platform ? { platform: dependencies.platform } : {}),\n ...(dependencies.secureWindowsFile\n ? { secureWindowsFile: dependencies.secureWindowsFile }\n : {}),\n ...(dependencies.syncParent ? { syncParent: dependencies.syncParent } : {}),\n };\n let installed = false;\n let committed = false;\n let primaryError: unknown;\n let published: PublishedOpenClawCrablineArtifactGeneration | undefined;\n try {\n const pointer: OpenClawCrablineArtifactPointer = {\n capabilityMatrixPath: generationArtifactPath(\n generation,\n params.selection.capabilityMatrixPath,\n ),\n generation,\n manifestPath: generationArtifactPath(generation, OPENCLAW_CRABLINE_MANIFEST_PATH),\n ...(currentPointer ? { previousGeneration: currentPointer.generation } : {}),\n providerReadinessArtifactPath: generationArtifactPath(\n generation,\n providerReadinessArtifactPath,\n ),\n smokeArtifactPath: generationArtifactPath(generation, providerReadinessArtifactPath),\n version: 1,\n };\n const providerReadiness = {\n ...params.providerReadiness,\n manifestPath: pointer.manifestPath,\n };\n const artifactContents = [\n {\n contents: `${JSON.stringify(params.manifest, null, 2)}\\n`,\n fileName: OPENCLAW_CRABLINE_MANIFEST_PATH,\n },\n {\n contents: `${JSON.stringify(\n {\n version: 1,\n source: \"openclaw/crabline\",\n channelDriver: params.selection.channelDriver,\n selectedChannel: params.selection.channel,\n manifestPath: pointer.manifestPath,\n report: params.capabilityReport,\n },\n null,\n 2,\n )}\\n`,\n fileName: params.selection.capabilityMatrixPath,\n },\n {\n contents: `${JSON.stringify(\n {\n version: 1,\n source: \"openclaw/crabline\",\n channelDriver: params.selection.channelDriver,\n selectedChannel: params.selection.channel,\n manifestPath: pointer.manifestPath,\n providerReadiness,\n smoke: providerReadiness,\n },\n null,\n 2,\n )}\\n`,\n fileName: providerReadinessArtifactPath,\n },\n ] as const;\n\n await params.lock.assertOwned();\n for (const artifact of artifactContents) {\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt();\n await publishPrivateFile(\n path.join(stagingPath, artifact.fileName),\n artifact.contents,\n fileOptions,\n );\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt();\n }\n await params.lock.assertOwned();\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await fs.rename(stagingPath, generationPath);\n installed = true;\n await (dependencies.syncParent ?? syncParentDirectory)(generationPath, dependencies.platform);\n await output.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n await store.assertIdentityAt();\n\n await dependencies.beforePointerSwitch?.(pointer);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n await params.lock.commitFileAtomically({\n contents: `${JSON.stringify(pointer, null, 2)}\\n`,\n destinationPath: path.join(outputDir, OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH),\n stageDirectory: store.directoryPath,\n stageFile: async (filePath, contents) => {\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n await publishPrivateFile(filePath, contents, fileOptions);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n },\n });\n committed = true;\n let warnings: string[] | undefined;\n try {\n const committedPointer = await readOpenClawCrablineArtifactPointer(outputDir);\n if (!committedPointer) {\n throw new Error(\"OpenClaw Crabline artifact pointer is missing after publication.\");\n }\n await pruneArtifactStore({\n directoryOptions,\n lock: params.lock,\n pointer: committedPointer,\n store,\n });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n warnings = [`OpenClaw Crabline artifact retention cleanup failed: ${detail}`];\n }\n\n published = {\n ...pointer,\n pointerPath: OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH,\n providerReadiness,\n smoke: providerReadiness,\n ...(warnings ? { warnings } : {}),\n };\n } catch (error) {\n primaryError = error;\n }\n\n if (!committed) {\n const unpublishedPath = installed ? generationPath : stagingPath;\n let referencedByPointer = false;\n if (installed) {\n try {\n const livePointer = await readOpenClawCrablineArtifactPointer(outputDir);\n referencedByPointer =\n livePointer?.generation === generation || livePointer?.previousGeneration === generation;\n } catch {\n referencedByPointer = true;\n }\n }\n if (!referencedByPointer) {\n try {\n await removeSecuredPrivateDirectory(staging, unpublishedPath);\n } catch (cleanupError) {\n if (primaryError !== undefined) {\n const primaryMessage =\n primaryError instanceof Error ? primaryError.message : String(primaryError);\n const aggregateError = new AggregateError(\n [primaryError, cleanupError],\n `${primaryMessage} OpenClaw Crabline artifact rollback cleanup also failed.`,\n );\n aggregateError.cause = primaryError;\n const primaryCode = (primaryError as NodeJS.ErrnoException).code;\n if (primaryCode) {\n Object.assign(aggregateError, { code: primaryCode });\n }\n throw aggregateError;\n }\n throw cleanupError;\n }\n }\n }\n\n if (primaryError !== undefined) {\n throw primaryError;\n }\n return published!;\n}\n"]}
1
+ {"version":3,"file":"artifact-generation.js","sourceRoot":"","sources":["../../../src/openclaw/artifact-generation.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { CrablineServerManifest } from \"../servers/index.js\";\nimport {\n captureDirectoryIdentity,\n publishPrivateFileAtomically,\n removeSecuredPrivateDirectory,\n securePrivateDirectory,\n syncParentDirectory,\n} from \"./private-file.js\";\nimport {\n OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH,\n OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY,\n OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH,\n OPENCLAW_CRABLINE_CHANNEL_SMOKE_PATH,\n OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH,\n OPENCLAW_CRABLINE_MANIFEST_PATH,\n type OpenClawCrablineChannelDriverSelection,\n} from \"./shared.js\";\nimport type { OpenClawCrablineSmokeRunLock } from \"./smoke-lock.js\";\n\nconst GENERATION_NAME_PATTERN =\n /^generation-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;\nconst STAGING_NAME_PATTERN =\n /^\\.staging-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;\nconst REMOVAL_TOMBSTONE_PATTERN =\n /^\\.(.+)\\.\\d+\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\.remove$/iu;\nexport type OpenClawCrablineArtifactPointer = {\n capabilityMatrixPath: string;\n generation: string;\n manifestPath: string;\n previousGeneration?: string;\n providerReadinessArtifactPath: string;\n smokeArtifactPath: string;\n version: 1;\n};\n\nexport type PublishedOpenClawCrablineArtifactGeneration = OpenClawCrablineArtifactPointer & {\n pointerPath: string;\n providerReadiness: Record<string, unknown>;\n smoke: Record<string, unknown>;\n warnings?: string[];\n};\n\ntype PublishGenerationDependencies = {\n beforePointerSwitch?: (pointer: OpenClawCrablineArtifactPointer) => Promise<void>;\n createGenerationId?: () => string;\n platform?: NodeJS.Platform;\n publishPrivateFile?: typeof publishPrivateFileAtomically;\n secureWindowsDirectory?: (directoryPath: string) => Promise<void>;\n secureWindowsFile?: (filePath: string) => Promise<void>;\n syncParent?: typeof syncParentDirectory;\n};\n\ntype RecorderSnapshot = {\n contents: string;\n fileName: string;\n};\n\nfunction resolveProviderReadinessArtifactPath(\n selection: OpenClawCrablineChannelDriverSelection,\n): typeof OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH {\n const readinessPath = selection.providerReadinessArtifactPath ?? selection.smokeArtifactPath;\n if (\n selection.capabilityMatrixPath !== OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH ||\n readinessPath !== OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH\n ) {\n throw new Error(\"OpenClaw Crabline artifact selection paths are malformed.\");\n }\n return readinessPath;\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n return (error as NodeJS.ErrnoException).code === \"ENOENT\";\n}\n\nfunction assertGenerationName(value: unknown, field: string): asserts value is string {\n if (typeof value !== \"string\" || !GENERATION_NAME_PATTERN.test(value)) {\n throw new Error(`OpenClaw Crabline artifact pointer ${field} is malformed.`);\n }\n}\n\nfunction generationArtifactPath(generation: string, fileName: string): string {\n return path.join(OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY, generation, fileName);\n}\n\nfunction artifactRemovalTombstoneBaseName(name: string): string | null {\n const originalName = REMOVAL_TOMBSTONE_PATTERN.exec(name)?.[1];\n return originalName !== undefined &&\n (GENERATION_NAME_PATTERN.test(originalName) || STAGING_NAME_PATTERN.test(originalName))\n ? originalName\n : null;\n}\n\nfunction withRecorderSnapshotPath(\n providerReadiness: Record<string, unknown>,\n recorderPath: string,\n): Record<string, unknown> {\n const result = providerReadiness.result;\n if (!result || typeof result !== \"object\" || Array.isArray(result)) {\n throw new Error(\"OpenClaw Crabline provider readiness result is malformed.\");\n }\n return {\n ...providerReadiness,\n result: {\n ...result,\n recorderPath,\n },\n };\n}\n\nfunction parseArtifactPointer(contents: string): OpenClawCrablineArtifactPointer {\n let value: Partial<OpenClawCrablineArtifactPointer>;\n try {\n value = JSON.parse(contents) as Partial<OpenClawCrablineArtifactPointer>;\n } catch (error) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\", { cause: error });\n }\n if (value.version !== 1) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\");\n }\n assertGenerationName(value.generation, \"generation\");\n if (value.previousGeneration !== undefined) {\n assertGenerationName(value.previousGeneration, \"previousGeneration\");\n if (value.previousGeneration === value.generation) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\");\n }\n }\n\n const expected = {\n capabilityMatrixPath: generationArtifactPath(\n value.generation,\n OPENCLAW_CRABLINE_CHANNEL_CAPABILITY_MATRIX_PATH,\n ),\n manifestPath: generationArtifactPath(value.generation, OPENCLAW_CRABLINE_MANIFEST_PATH),\n providerReadinessArtifactPath: generationArtifactPath(\n value.generation,\n OPENCLAW_CRABLINE_PROVIDER_READINESS_PATH,\n ),\n smokeArtifactPath: generationArtifactPath(\n value.generation,\n OPENCLAW_CRABLINE_CHANNEL_SMOKE_PATH,\n ),\n };\n if (\n typeof value.capabilityMatrixPath !== \"string\" ||\n value.capabilityMatrixPath !== expected.capabilityMatrixPath ||\n value.manifestPath !== expected.manifestPath ||\n (value.providerReadinessArtifactPath !== undefined &&\n value.providerReadinessArtifactPath !== expected.providerReadinessArtifactPath) ||\n (value.smokeArtifactPath !== undefined &&\n value.smokeArtifactPath !== expected.smokeArtifactPath) ||\n (value.providerReadinessArtifactPath === undefined && value.smokeArtifactPath === undefined)\n ) {\n throw new Error(\"OpenClaw Crabline artifact pointer is malformed.\");\n }\n\n return {\n capabilityMatrixPath: value.capabilityMatrixPath,\n generation: value.generation,\n ...(value.previousGeneration ? { previousGeneration: value.previousGeneration } : {}),\n manifestPath: value.manifestPath,\n providerReadinessArtifactPath: value.providerReadinessArtifactPath ?? value.smokeArtifactPath!,\n smokeArtifactPath: value.smokeArtifactPath ?? value.providerReadinessArtifactPath!,\n version: 1,\n };\n}\n\nexport async function readOpenClawCrablineArtifactPointer(\n outputDir: string,\n): Promise<OpenClawCrablineArtifactPointer | null> {\n try {\n return parseArtifactPointer(\n await fs.readFile(\n path.join(path.resolve(outputDir), OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH),\n \"utf8\",\n ),\n );\n } catch (error) {\n if (isMissingPathError(error)) {\n return null;\n }\n throw error;\n }\n}\n\nasync function assertCurrentGenerationExists(\n outputDir: string,\n pointer: OpenClawCrablineArtifactPointer,\n): Promise<void> {\n for (const artifactPath of [\n pointer.manifestPath,\n pointer.capabilityMatrixPath,\n pointer.providerReadinessArtifactPath,\n ]) {\n const stats = await fs.lstat(path.join(outputDir, artifactPath));\n if (!stats.isFile()) {\n throw new Error(\"OpenClaw Crabline current artifact generation is incomplete.\");\n }\n }\n}\n\nasync function pruneArtifactStore(params: {\n lock: OpenClawCrablineSmokeRunLock;\n pointer: OpenClawCrablineArtifactPointer | null;\n store: Awaited<ReturnType<typeof securePrivateDirectory>>;\n directoryOptions?: Parameters<typeof securePrivateDirectory>[1];\n}): Promise<void> {\n const retainedGenerations = new Set(\n params.pointer\n ? [params.pointer.generation, params.pointer.previousGeneration].filter(\n (generation): generation is string => generation !== undefined,\n )\n : [],\n );\n for (const entry of await fs.readdir(params.store.directoryPath, { withFileTypes: true })) {\n const isAbandonedStaging = entry.isDirectory() && STAGING_NAME_PATTERN.test(entry.name);\n const isObsoleteGeneration =\n entry.isDirectory() &&\n GENERATION_NAME_PATTERN.test(entry.name) &&\n !retainedGenerations.has(entry.name);\n const removalTombstoneBaseName = entry.isDirectory()\n ? artifactRemovalTombstoneBaseName(entry.name)\n : null;\n const isRemovalTombstone = removalTombstoneBaseName !== null;\n if (!isAbandonedStaging && !isObsoleteGeneration && !isRemovalTombstone) {\n continue;\n }\n await params.lock.assertOwned();\n await params.store.assertIdentityAt();\n const obsolete = await securePrivateDirectory(\n path.join(params.store.directoryPath, entry.name),\n params.directoryOptions,\n );\n await removeSecuredPrivateDirectory(\n obsolete,\n undefined,\n removalTombstoneBaseName ?? entry.name,\n );\n await params.store.assertIdentityAt();\n }\n}\n\nexport async function publishOpenClawCrablineArtifactGeneration(\n params: {\n capabilityReport: unknown;\n lock: OpenClawCrablineSmokeRunLock;\n manifest: CrablineServerManifest;\n outputDir: string;\n recorderSnapshot?: RecorderSnapshot;\n selection: OpenClawCrablineChannelDriverSelection;\n providerReadiness: Record<string, unknown>;\n },\n dependencies: PublishGenerationDependencies = {},\n): Promise<PublishedOpenClawCrablineArtifactGeneration> {\n const providerReadinessArtifactPath = resolveProviderReadinessArtifactPath(params.selection);\n const outputDir = path.resolve(params.outputDir);\n await fs.mkdir(outputDir, { recursive: true });\n const output = await captureDirectoryIdentity(outputDir);\n await output.assertIdentityAt();\n const storePath = path.join(outputDir, OPENCLAW_CRABLINE_ARTIFACT_STORE_DIRECTORY);\n const directoryOptions = {\n ...(dependencies.platform ? { platform: dependencies.platform } : {}),\n ...(dependencies.secureWindowsDirectory\n ? { secureWindowsDirectory: dependencies.secureWindowsDirectory }\n : {}),\n ...(dependencies.syncParent ? { syncParent: dependencies.syncParent } : {}),\n };\n const store = await securePrivateDirectory(storePath, directoryOptions);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await params.lock.assertOwned();\n const currentPointer = await readOpenClawCrablineArtifactPointer(outputDir);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n if (currentPointer) {\n await assertCurrentGenerationExists(outputDir, currentPointer);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n }\n await pruneArtifactStore({\n directoryOptions,\n lock: params.lock,\n pointer: currentPointer,\n store,\n });\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n\n const generationId = dependencies.createGenerationId?.() ?? randomUUID();\n const generation = `generation-${generationId}`;\n if (!GENERATION_NAME_PATTERN.test(generation)) {\n throw new Error(\"OpenClaw Crabline artifact generation id is malformed.\");\n }\n const stagingPath = path.join(storePath, `.staging-${generationId}`);\n const generationPath = path.join(storePath, generation);\n const staging = await securePrivateDirectory(stagingPath, directoryOptions);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt();\n const publishPrivateFile = dependencies.publishPrivateFile ?? publishPrivateFileAtomically;\n const fileOptions = {\n ...(dependencies.platform ? { platform: dependencies.platform } : {}),\n ...(dependencies.secureWindowsFile\n ? { secureWindowsFile: dependencies.secureWindowsFile }\n : {}),\n ...(dependencies.syncParent ? { syncParent: dependencies.syncParent } : {}),\n };\n let installed = false;\n let committed = false;\n let primaryError: unknown;\n let published: PublishedOpenClawCrablineArtifactGeneration | undefined;\n try {\n const pointer: OpenClawCrablineArtifactPointer = {\n capabilityMatrixPath: generationArtifactPath(\n generation,\n params.selection.capabilityMatrixPath,\n ),\n generation,\n manifestPath: generationArtifactPath(generation, OPENCLAW_CRABLINE_MANIFEST_PATH),\n ...(currentPointer ? { previousGeneration: currentPointer.generation } : {}),\n providerReadinessArtifactPath: generationArtifactPath(\n generation,\n providerReadinessArtifactPath,\n ),\n smokeArtifactPath: generationArtifactPath(generation, providerReadinessArtifactPath),\n version: 1,\n };\n if (\n params.recorderSnapshot &&\n (path.basename(params.recorderSnapshot.fileName) !== params.recorderSnapshot.fileName ||\n !params.recorderSnapshot.fileName.endsWith(\".jsonl\"))\n ) {\n throw new Error(\"OpenClaw Crabline recorder snapshot filename is malformed.\");\n }\n const recorderSnapshotPath = params.recorderSnapshot\n ? generationArtifactPath(generation, params.recorderSnapshot.fileName)\n : undefined;\n const publishedManifest = recorderSnapshotPath\n ? { ...params.manifest, recorderPath: recorderSnapshotPath }\n : params.manifest;\n const providerReadinessBase = recorderSnapshotPath\n ? withRecorderSnapshotPath(params.providerReadiness, recorderSnapshotPath)\n : params.providerReadiness;\n const providerReadiness = {\n ...providerReadinessBase,\n manifestPath: pointer.manifestPath,\n };\n const artifactContents: { contents: string; fileName: string }[] = [\n {\n contents: `${JSON.stringify(publishedManifest, null, 2)}\\n`,\n fileName: OPENCLAW_CRABLINE_MANIFEST_PATH,\n },\n {\n contents: `${JSON.stringify(\n {\n version: 1,\n source: \"openclaw/crabline\",\n channelDriver: params.selection.channelDriver,\n selectedChannel: params.selection.channel,\n manifestPath: pointer.manifestPath,\n report: params.capabilityReport,\n },\n null,\n 2,\n )}\\n`,\n fileName: params.selection.capabilityMatrixPath,\n },\n {\n contents: `${JSON.stringify(\n {\n version: 1,\n source: \"openclaw/crabline\",\n channelDriver: params.selection.channelDriver,\n selectedChannel: params.selection.channel,\n manifestPath: pointer.manifestPath,\n providerReadiness,\n smoke: providerReadiness,\n },\n null,\n 2,\n )}\\n`,\n fileName: providerReadinessArtifactPath,\n },\n ...(params.recorderSnapshot\n ? [\n {\n contents: params.recorderSnapshot.contents,\n fileName: params.recorderSnapshot.fileName,\n },\n ]\n : []),\n ];\n\n await params.lock.assertOwned();\n for (const artifact of artifactContents) {\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt();\n await publishPrivateFile(\n path.join(stagingPath, artifact.fileName),\n artifact.contents,\n fileOptions,\n );\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt();\n }\n await params.lock.assertOwned();\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await fs.rename(stagingPath, generationPath);\n installed = true;\n await (dependencies.syncParent ?? syncParentDirectory)(generationPath, dependencies.platform);\n await output.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n await store.assertIdentityAt();\n\n await dependencies.beforePointerSwitch?.(pointer);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n await params.lock.commitFileAtomically({\n contents: `${JSON.stringify(pointer, null, 2)}\\n`,\n destinationPath: path.join(outputDir, OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH),\n stageDirectory: store.directoryPath,\n stageFile: async (filePath, contents) => {\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n await publishPrivateFile(filePath, contents, fileOptions);\n await output.assertIdentityAt();\n await store.assertIdentityAt();\n await staging.assertIdentityAt(generationPath);\n },\n });\n committed = true;\n let warnings: string[] | undefined;\n try {\n const committedPointer = await readOpenClawCrablineArtifactPointer(outputDir);\n if (!committedPointer) {\n throw new Error(\"OpenClaw Crabline artifact pointer is missing after publication.\");\n }\n await pruneArtifactStore({\n directoryOptions,\n lock: params.lock,\n pointer: committedPointer,\n store,\n });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n warnings = [`OpenClaw Crabline artifact retention cleanup failed: ${detail}`];\n }\n\n published = {\n ...pointer,\n pointerPath: OPENCLAW_CRABLINE_ARTIFACT_POINTER_PATH,\n providerReadiness,\n smoke: providerReadiness,\n ...(warnings ? { warnings } : {}),\n };\n } catch (error) {\n primaryError = error;\n }\n\n if (!committed) {\n const unpublishedPath = installed ? generationPath : stagingPath;\n let referencedByPointer = false;\n if (installed) {\n try {\n const livePointer = await readOpenClawCrablineArtifactPointer(outputDir);\n referencedByPointer =\n livePointer?.generation === generation || livePointer?.previousGeneration === generation;\n } catch {\n referencedByPointer = true;\n }\n }\n if (!referencedByPointer) {\n try {\n await removeSecuredPrivateDirectory(staging, unpublishedPath);\n } catch (cleanupError) {\n if (primaryError !== undefined) {\n const primaryMessage =\n primaryError instanceof Error ? primaryError.message : String(primaryError);\n const aggregateError = new AggregateError(\n [primaryError, cleanupError],\n `${primaryMessage} OpenClaw Crabline artifact rollback cleanup also failed.`,\n );\n aggregateError.cause = primaryError;\n const primaryCode = (primaryError as NodeJS.ErrnoException).code;\n if (primaryCode) {\n Object.assign(aggregateError, { code: primaryCode });\n }\n throw aggregateError;\n }\n throw cleanupError;\n }\n }\n }\n\n if (primaryError !== undefined) {\n throw primaryError;\n }\n return published!;\n}\n"]}
@@ -11,10 +11,12 @@ export type SecuredPrivateDirectory = {
11
11
  };
12
12
  export declare function captureDirectoryIdentity(directoryPath: string): Promise<SecuredPrivateDirectory>;
13
13
  export declare function syncParentDirectory(filePath: string, platform?: NodeJS.Platform): Promise<void>;
14
- export declare function removeSecuredPrivateDirectory(secured: SecuredPrivateDirectory, currentPath?: string): Promise<void>;
14
+ export declare function removeSecuredPrivateDirectory(secured: SecuredPrivateDirectory, currentPath?: string, quarantineBaseName?: string): Promise<void>;
15
15
  export declare function securePrivateDirectory(directoryPath: string, options?: {
16
+ currentUserId?: number;
16
17
  platform?: NodeJS.Platform;
17
18
  secureWindowsDirectory?: (directoryPath: string) => Promise<void>;
19
+ syncParent?: (filePath: string, platform?: NodeJS.Platform) => Promise<void>;
18
20
  }): Promise<SecuredPrivateDirectory>;
19
21
  export declare function publishPrivateFileAtomically(filePath: string, contents: string, options?: {
20
22
  afterRename?: (filePath: string) => Promise<void>;
@@ -210,6 +210,7 @@ async function readDirectoryHandleIdentity(handle) {
210
210
  return {
211
211
  device: stats.dev,
212
212
  inode: stats.ino,
213
+ userId: stats.uid,
213
214
  };
214
215
  }
215
216
  async function assertDirectoryPathIdentity(directoryPath, expected) {
@@ -255,8 +256,46 @@ export async function syncParentDirectory(filePath, platform = process.platform)
255
256
  await handle.close();
256
257
  }
257
258
  }
258
- export async function removeSecuredPrivateDirectory(secured, currentPath = secured.directoryPath) {
259
- const quarantinePath = path.join(path.dirname(currentPath), `.${path.basename(currentPath)}.${process.pid}.${randomUUID()}.remove`);
259
+ async function syncParentAtAccessibleBoundary(filePath, syncParent, platform) {
260
+ try {
261
+ await syncParent(filePath, platform);
262
+ return true;
263
+ }
264
+ catch (error) {
265
+ const code = error.code;
266
+ if (code === "EACCES" || code === "EPERM") {
267
+ return false;
268
+ }
269
+ throw error;
270
+ }
271
+ }
272
+ async function syncPathAncestry(filePath, syncParent, platform, firstCreatedDirectory) {
273
+ const resolvedFilePath = path.resolve(filePath);
274
+ let currentPath = resolvedFilePath;
275
+ const syncThroughPath = firstCreatedDirectory === undefined ? undefined : path.resolve(firstCreatedDirectory);
276
+ for (;;) {
277
+ const mandatory = syncThroughPath !== undefined || currentPath === resolvedFilePath;
278
+ if (mandatory) {
279
+ await syncParent(currentPath, platform);
280
+ }
281
+ else if (!(await syncParentAtAccessibleBoundary(currentPath, syncParent, platform))) {
282
+ return;
283
+ }
284
+ if (currentPath === syncThroughPath) {
285
+ return;
286
+ }
287
+ const parentPath = path.dirname(currentPath);
288
+ if (path.dirname(parentPath) === parentPath) {
289
+ return;
290
+ }
291
+ currentPath = parentPath;
292
+ }
293
+ }
294
+ export async function removeSecuredPrivateDirectory(secured, currentPath = secured.directoryPath, quarantineBaseName = path.basename(currentPath)) {
295
+ if (path.basename(quarantineBaseName) !== quarantineBaseName || quarantineBaseName.length === 0) {
296
+ throw new Error("Private directory quarantine basename is malformed.");
297
+ }
298
+ const quarantinePath = path.join(path.dirname(currentPath), `.${quarantineBaseName}.${process.pid}.${randomUUID()}.remove`);
260
299
  await secured.assertIdentityAt(currentPath);
261
300
  await fs.rename(currentPath, quarantinePath);
262
301
  await secured.assertIdentityAt(quarantinePath);
@@ -311,9 +350,23 @@ export async function securePrivateDirectory(directoryPath, options = {}) {
311
350
  await (options.secureWindowsDirectory ?? applyOwnerOnlyWindowsDirectoryAcl)(directoryPath);
312
351
  }
313
352
  else {
353
+ const currentUserId = options.currentUserId ?? process.geteuid?.();
354
+ if (currentUserId === undefined ||
355
+ !Number.isSafeInteger(currentUserId) ||
356
+ currentUserId < 0 ||
357
+ identity.userId !== BigInt(currentUserId)) {
358
+ throw new Error("Private directory must be owned by the current POSIX user.");
359
+ }
314
360
  await handle.chmod(0o700);
315
361
  }
316
362
  await secured.assertIdentityAt();
363
+ const syncParent = options.syncParent ?? syncParentDirectory;
364
+ if (created) {
365
+ await syncParent(directoryPath, options.platform);
366
+ }
367
+ else {
368
+ await syncParentAtAccessibleBoundary(directoryPath, syncParent, options.platform);
369
+ }
317
370
  }
318
371
  catch (error) {
319
372
  let primaryError = error;
@@ -344,7 +397,8 @@ export async function securePrivateDirectory(directoryPath, options = {}) {
344
397
  }
345
398
  export async function publishPrivateFileAtomically(filePath, contents, options = {}) {
346
399
  const temporaryPath = path.join(path.dirname(filePath), `.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`);
347
- await fs.mkdir(path.dirname(filePath), { recursive: true });
400
+ const parentDirectory = path.resolve(path.dirname(filePath));
401
+ const firstCreatedDirectory = await fs.mkdir(parentDirectory, { recursive: true });
348
402
  let handle;
349
403
  let publicationFailed = false;
350
404
  let primaryError;
@@ -364,7 +418,7 @@ export async function publishPrivateFileAtomically(filePath, contents, options =
364
418
  await options.beforeRename?.(temporaryPath);
365
419
  await assertPathIdentity(temporaryPath, identity);
366
420
  await fs.rename(temporaryPath, filePath);
367
- await (options.syncParent ?? syncParentDirectory)(filePath, options.platform);
421
+ await syncPathAncestry(filePath, options.syncParent ?? syncParentDirectory, options.platform, firstCreatedDirectory);
368
422
  await options.afterRename?.(filePath);
369
423
  await assertPathIdentity(filePath, identity);
370
424
  }
@@ -1 +1 @@
1
- {"version":3,"file":"private-file.js","sourceRoot":"","sources":["../../../src/openclaw/private-file.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport fs, { type FileHandle } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nconst WINDOWS_OWNER_ONLY_ACL_SCRIPT = String.raw`\n$ErrorActionPreference = \"Stop\"\n$filePath = $env:CRABLINE_PRIVATE_FILE_PATH\nif ([string]::IsNullOrWhiteSpace($filePath)) {\n throw \"CRABLINE_PRIVATE_FILE_PATH is required.\"\n}\n\n$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()\n$sid = $identity.User\nif ($null -eq $sid) {\n throw \"Could not resolve the current Windows user SID.\"\n}\n\n$acl = Get-Acl -LiteralPath $filePath\n$acl.SetOwner($sid)\n$acl.SetAccessRuleProtection($true, $false)\n$existingRules = @($acl.GetAccessRules(\n $true,\n $false,\n [System.Security.Principal.SecurityIdentifier]\n))\nforeach ($existingRule in $existingRules) {\n [void]$acl.RemoveAccessRuleSpecific($existingRule)\n}\n$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(\n $sid,\n [System.Security.AccessControl.FileSystemRights]::FullControl,\n [System.Security.AccessControl.AccessControlType]::Allow\n)\n$acl.SetAccessRule($rule)\nSet-Acl -LiteralPath $filePath -AclObject $acl\n\n$actual = Get-Acl -LiteralPath $filePath\n$ownerSid = $actual.GetOwner([System.Security.Principal.SecurityIdentifier])\n$rules = @($actual.GetAccessRules(\n $true,\n $true,\n [System.Security.Principal.SecurityIdentifier]\n))\nif (-not $actual.AreAccessRulesProtected) {\n throw \"Private file DACL still inherits permissions.\"\n}\nif ($ownerSid.Value -ne $sid.Value) {\n throw \"Private file owner SID does not match the current user.\"\n}\nif ($rules.Count -ne 1) {\n throw \"Private file DACL must contain exactly one access rule.\"\n}\n$actualRule = $rules[0]\nif (\n $actualRule.IsInherited -or\n $actualRule.IdentityReference.Value -ne $sid.Value -or\n $actualRule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or\n (($actualRule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl)\n) {\n throw \"Private file DACL is not owner-only full control.\"\n}\n`;\n\nconst WINDOWS_OWNER_ONLY_DIRECTORY_ACL_SCRIPT = String.raw`\n$ErrorActionPreference = \"Stop\"\n$directoryPath = $env:CRABLINE_PRIVATE_DIRECTORY_PATH\nif ([string]::IsNullOrWhiteSpace($directoryPath)) {\n throw \"CRABLINE_PRIVATE_DIRECTORY_PATH is required.\"\n}\n\n$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()\n$sid = $identity.User\nif ($null -eq $sid) {\n throw \"Could not resolve the current Windows user SID.\"\n}\n\n$acl = Get-Acl -LiteralPath $directoryPath\n$acl.SetOwner($sid)\n$acl.SetAccessRuleProtection($true, $false)\n$existingRules = @($acl.GetAccessRules(\n $true,\n $false,\n [System.Security.Principal.SecurityIdentifier]\n))\nforeach ($existingRule in $existingRules) {\n [void]$acl.RemoveAccessRuleSpecific($existingRule)\n}\n$inheritance = (\n [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor\n [System.Security.AccessControl.InheritanceFlags]::ObjectInherit\n)\n$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(\n $sid,\n [System.Security.AccessControl.FileSystemRights]::FullControl,\n $inheritance,\n [System.Security.AccessControl.PropagationFlags]::None,\n [System.Security.AccessControl.AccessControlType]::Allow\n)\n$acl.SetAccessRule($rule)\nSet-Acl -LiteralPath $directoryPath -AclObject $acl\n\n$actual = Get-Acl -LiteralPath $directoryPath\n$ownerSid = $actual.GetOwner([System.Security.Principal.SecurityIdentifier])\n$rules = @($actual.GetAccessRules(\n $true,\n $true,\n [System.Security.Principal.SecurityIdentifier]\n))\nif (-not $actual.AreAccessRulesProtected) {\n throw \"Private directory DACL still inherits permissions.\"\n}\nif ($ownerSid.Value -ne $sid.Value) {\n throw \"Private directory owner SID does not match the current user.\"\n}\nif ($rules.Count -ne 1) {\n throw \"Private directory DACL must contain exactly one access rule.\"\n}\n$actualRule = $rules[0]\n$requiredInheritance = (\n [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor\n [System.Security.AccessControl.InheritanceFlags]::ObjectInherit\n)\nif (\n $actualRule.IsInherited -or\n $actualRule.IdentityReference.Value -ne $sid.Value -or\n $actualRule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or\n (($actualRule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl) -or\n (($actualRule.InheritanceFlags -band $requiredInheritance) -ne $requiredInheritance)\n) {\n throw \"Private directory DACL is not owner-only inheritable full control.\"\n}\n`;\n\nexport type WindowsAclRunner = (\n command: string,\n args: string[],\n options: {\n env: NodeJS.ProcessEnv;\n windowsHide: boolean;\n },\n) => Promise<void>;\n\nconst runWindowsAclCommand: WindowsAclRunner = async (command, args, options) => {\n await execFileAsync(command, args, options);\n};\n\nexport function resolveWindowsPowerShellPath(systemRoot: string | null | undefined): string {\n const normalizedRoot = systemRoot?.trim() ? path.win32.normalize(systemRoot.trim()) : undefined;\n if (!normalizedRoot || !/^[A-Za-z]:\\\\/.test(normalizedRoot)) {\n throw new Error(\"SystemRoot must be an absolute local Windows path.\");\n }\n return path.win32.join(normalizedRoot, \"System32\", \"WindowsPowerShell\", \"v1.0\", \"powershell.exe\");\n}\n\nexport async function applyOwnerOnlyWindowsAcl(\n filePath: string,\n run: WindowsAclRunner = runWindowsAclCommand,\n systemRoot: string | null | undefined = process.env.SystemRoot,\n): Promise<void> {\n try {\n const powershellPath = resolveWindowsPowerShellPath(systemRoot);\n await run(\n powershellPath,\n [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", WINDOWS_OWNER_ONLY_ACL_SCRIPT],\n {\n env: {\n ...process.env,\n CRABLINE_PRIVATE_FILE_PATH: path.resolve(filePath),\n },\n windowsHide: true,\n },\n );\n } catch (error) {\n throw new Error(\n \"Could not apply and verify an owner-only Windows ACL; powershell.exe with Set-Acl is required.\",\n { cause: error },\n );\n }\n}\n\nexport async function applyOwnerOnlyWindowsDirectoryAcl(\n directoryPath: string,\n run: WindowsAclRunner = runWindowsAclCommand,\n systemRoot: string | null | undefined = process.env.SystemRoot,\n): Promise<void> {\n try {\n const powershellPath = resolveWindowsPowerShellPath(systemRoot);\n await run(\n powershellPath,\n [\n \"-NoLogo\",\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n WINDOWS_OWNER_ONLY_DIRECTORY_ACL_SCRIPT,\n ],\n {\n env: {\n ...process.env,\n CRABLINE_PRIVATE_DIRECTORY_PATH: path.resolve(directoryPath),\n },\n windowsHide: true,\n },\n );\n } catch (error) {\n throw new Error(\n \"Could not apply and verify an owner-only Windows directory ACL; powershell.exe with Set-Acl is required.\",\n { cause: error },\n );\n }\n}\n\ntype FileIdentity = {\n device: bigint;\n inode: bigint;\n};\n\nasync function readHandleIdentity(handle: FileHandle): Promise<FileIdentity> {\n const stats = await handle.stat({ bigint: true });\n if (stats.ino <= 0n) {\n throw new Error(\"The filesystem did not provide a stable private file identity.\");\n }\n return {\n device: stats.dev,\n inode: stats.ino,\n };\n}\n\nasync function assertPathIdentity(filePath: string, expected: FileIdentity): Promise<void> {\n try {\n const stats = await fs.lstat(filePath, { bigint: true });\n if (\n stats.isFile() &&\n stats.nlink === 1n &&\n stats.dev === expected.device &&\n stats.ino === expected.inode\n ) {\n return;\n }\n } catch (error) {\n throw new Error(\"Private file path identity changed during publication.\", { cause: error });\n }\n throw new Error(\"Private file path identity changed during publication.\");\n}\n\ntype DirectoryIdentity = {\n device: bigint;\n inode: bigint;\n};\n\nasync function readDirectoryHandleIdentity(handle: FileHandle): Promise<DirectoryIdentity> {\n const stats = await handle.stat({ bigint: true });\n if (!stats.isDirectory() || stats.ino <= 0n) {\n throw new Error(\"The filesystem did not provide a stable private directory identity.\");\n }\n return {\n device: stats.dev,\n inode: stats.ino,\n };\n}\n\nasync function assertDirectoryPathIdentity(\n directoryPath: string,\n expected: DirectoryIdentity,\n): Promise<void> {\n try {\n const stats = await fs.lstat(directoryPath, { bigint: true });\n if (stats.isDirectory() && stats.dev === expected.device && stats.ino === expected.inode) {\n return;\n }\n } catch (error) {\n throw new Error(\"Private directory path identity changed during publication.\", {\n cause: error,\n });\n }\n throw new Error(\"Private directory path identity changed during publication.\");\n}\n\nexport type SecuredPrivateDirectory = {\n assertIdentityAt(directoryPath?: string): Promise<void>;\n directoryPath: string;\n};\n\nexport async function captureDirectoryIdentity(\n directoryPath: string,\n): Promise<SecuredPrivateDirectory> {\n const handle = await fs.open(directoryPath, \"r\");\n try {\n const identity = await readDirectoryHandleIdentity(handle);\n const secured: SecuredPrivateDirectory = {\n async assertIdentityAt(currentPath = directoryPath) {\n await assertDirectoryPathIdentity(currentPath, identity);\n },\n directoryPath,\n };\n await secured.assertIdentityAt();\n return secured;\n } finally {\n await handle.close();\n }\n}\n\nexport async function syncParentDirectory(\n filePath: string,\n platform: NodeJS.Platform = process.platform,\n): Promise<void> {\n if (platform === \"win32\") {\n return;\n }\n const handle = await fs.open(path.dirname(filePath), \"r\");\n try {\n await handle.sync();\n } finally {\n await handle.close();\n }\n}\n\nexport async function removeSecuredPrivateDirectory(\n secured: SecuredPrivateDirectory,\n currentPath = secured.directoryPath,\n): Promise<void> {\n const quarantinePath = path.join(\n path.dirname(currentPath),\n `.${path.basename(currentPath)}.${process.pid}.${randomUUID()}.remove`,\n );\n await secured.assertIdentityAt(currentPath);\n await fs.rename(currentPath, quarantinePath);\n await secured.assertIdentityAt(quarantinePath);\n await syncParentDirectory(quarantinePath);\n await fs.rm(quarantinePath, { force: true, recursive: true });\n await syncParentDirectory(quarantinePath);\n}\n\nexport async function securePrivateDirectory(\n directoryPath: string,\n options: {\n platform?: NodeJS.Platform;\n secureWindowsDirectory?: (directoryPath: string) => Promise<void>;\n } = {},\n): Promise<SecuredPrivateDirectory> {\n let created = false;\n try {\n await fs.mkdir(directoryPath, { mode: 0o700 });\n created = true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw error;\n }\n }\n\n const handle = await fs.open(directoryPath, \"r\");\n let handleOpen = true;\n const closeHandle = async () => {\n if (!handleOpen) {\n return;\n }\n handleOpen = false;\n await handle.close();\n };\n let identity: DirectoryIdentity;\n try {\n identity = await readDirectoryHandleIdentity(handle);\n } catch (error) {\n try {\n await closeHandle();\n } catch (closeError) {\n const aggregateError = new AggregateError(\n [error, closeError],\n \"Private directory identity verification failed and its handle could not be closed.\",\n );\n aggregateError.cause = error;\n throw aggregateError;\n }\n throw error;\n }\n const secured: SecuredPrivateDirectory = {\n async assertIdentityAt(currentPath = directoryPath) {\n await assertDirectoryPathIdentity(currentPath, identity);\n },\n directoryPath,\n };\n try {\n await secured.assertIdentityAt();\n if ((options.platform ?? process.platform) === \"win32\") {\n await (options.secureWindowsDirectory ?? applyOwnerOnlyWindowsDirectoryAcl)(directoryPath);\n } else {\n await handle.chmod(0o700);\n }\n await secured.assertIdentityAt();\n } catch (error) {\n let primaryError = error;\n try {\n await closeHandle();\n } catch (closeError) {\n const aggregateError = new AggregateError(\n [error, closeError],\n \"Private directory securing failed and its verification handle could not be closed.\",\n );\n aggregateError.cause = error;\n primaryError = aggregateError;\n }\n if (created) {\n try {\n await removeSecuredPrivateDirectory(secured);\n } catch (cleanupError) {\n const aggregateError = new AggregateError(\n [primaryError, cleanupError],\n `Private directory securing failed and rollback cleanup also failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n aggregateError.cause = primaryError;\n throw aggregateError;\n }\n }\n throw primaryError;\n } finally {\n await closeHandle();\n }\n\n return secured;\n}\n\nexport async function publishPrivateFileAtomically(\n filePath: string,\n contents: string,\n options: {\n afterRename?: (filePath: string) => Promise<void>;\n beforeRename?: (temporaryPath: string) => Promise<void>;\n platform?: NodeJS.Platform;\n removeTemporaryFile?: (temporaryPath: string) => Promise<void>;\n secureWindowsFile?: (temporaryPath: string) => Promise<void>;\n syncParent?: (filePath: string, platform?: NodeJS.Platform) => Promise<void>;\n } = {},\n): Promise<void> {\n const temporaryPath = path.join(\n path.dirname(filePath),\n `.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`,\n );\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n let handle: FileHandle | undefined;\n let publicationFailed = false;\n let primaryError: unknown;\n try {\n handle = await fs.open(temporaryPath, \"wx+\", 0o600);\n const identity = await readHandleIdentity(handle);\n if ((options.platform ?? process.platform) === \"win32\") {\n await (options.secureWindowsFile ?? applyOwnerOnlyWindowsAcl)(temporaryPath);\n } else {\n await handle.chmod(0o600);\n }\n\n await assertPathIdentity(temporaryPath, identity);\n await handle.writeFile(contents, \"utf8\");\n await handle.sync();\n await assertPathIdentity(temporaryPath, identity);\n await options.beforeRename?.(temporaryPath);\n await assertPathIdentity(temporaryPath, identity);\n await fs.rename(temporaryPath, filePath);\n await (options.syncParent ?? syncParentDirectory)(filePath, options.platform);\n await options.afterRename?.(filePath);\n await assertPathIdentity(filePath, identity);\n } catch (error) {\n publicationFailed = true;\n primaryError = error;\n }\n\n const cleanupErrors: unknown[] = [];\n try {\n await handle?.close();\n } catch (error) {\n cleanupErrors.push(error);\n }\n try {\n await (\n options.removeTemporaryFile ??\n ((candidatePath: string) => fs.rm(candidatePath, { force: true }))\n )(temporaryPath);\n } catch (error) {\n cleanupErrors.push(error);\n }\n\n if (publicationFailed) {\n if (cleanupErrors.length > 0) {\n const primaryMessage =\n primaryError instanceof Error ? primaryError.message : String(primaryError);\n const aggregateError = new AggregateError(\n [primaryError, ...cleanupErrors],\n `${primaryMessage} Private temporary file cleanup also failed.`,\n );\n aggregateError.cause = primaryError;\n const primaryCode =\n typeof primaryError === \"object\" && primaryError !== null\n ? (primaryError as NodeJS.ErrnoException).code\n : undefined;\n if (primaryCode) {\n Object.assign(aggregateError, { code: primaryCode });\n }\n throw aggregateError;\n }\n throw primaryError;\n }\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n if (cleanupErrors.length > 1) {\n throw new AggregateError(cleanupErrors, \"Private temporary file publication cleanup failed.\");\n }\n}\n"]}
1
+ {"version":3,"file":"private-file.js","sourceRoot":"","sources":["../../../src/openclaw/private-file.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport fs, { type FileHandle } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\nconst WINDOWS_OWNER_ONLY_ACL_SCRIPT = String.raw`\n$ErrorActionPreference = \"Stop\"\n$filePath = $env:CRABLINE_PRIVATE_FILE_PATH\nif ([string]::IsNullOrWhiteSpace($filePath)) {\n throw \"CRABLINE_PRIVATE_FILE_PATH is required.\"\n}\n\n$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()\n$sid = $identity.User\nif ($null -eq $sid) {\n throw \"Could not resolve the current Windows user SID.\"\n}\n\n$acl = Get-Acl -LiteralPath $filePath\n$acl.SetOwner($sid)\n$acl.SetAccessRuleProtection($true, $false)\n$existingRules = @($acl.GetAccessRules(\n $true,\n $false,\n [System.Security.Principal.SecurityIdentifier]\n))\nforeach ($existingRule in $existingRules) {\n [void]$acl.RemoveAccessRuleSpecific($existingRule)\n}\n$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(\n $sid,\n [System.Security.AccessControl.FileSystemRights]::FullControl,\n [System.Security.AccessControl.AccessControlType]::Allow\n)\n$acl.SetAccessRule($rule)\nSet-Acl -LiteralPath $filePath -AclObject $acl\n\n$actual = Get-Acl -LiteralPath $filePath\n$ownerSid = $actual.GetOwner([System.Security.Principal.SecurityIdentifier])\n$rules = @($actual.GetAccessRules(\n $true,\n $true,\n [System.Security.Principal.SecurityIdentifier]\n))\nif (-not $actual.AreAccessRulesProtected) {\n throw \"Private file DACL still inherits permissions.\"\n}\nif ($ownerSid.Value -ne $sid.Value) {\n throw \"Private file owner SID does not match the current user.\"\n}\nif ($rules.Count -ne 1) {\n throw \"Private file DACL must contain exactly one access rule.\"\n}\n$actualRule = $rules[0]\nif (\n $actualRule.IsInherited -or\n $actualRule.IdentityReference.Value -ne $sid.Value -or\n $actualRule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or\n (($actualRule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl)\n) {\n throw \"Private file DACL is not owner-only full control.\"\n}\n`;\n\nconst WINDOWS_OWNER_ONLY_DIRECTORY_ACL_SCRIPT = String.raw`\n$ErrorActionPreference = \"Stop\"\n$directoryPath = $env:CRABLINE_PRIVATE_DIRECTORY_PATH\nif ([string]::IsNullOrWhiteSpace($directoryPath)) {\n throw \"CRABLINE_PRIVATE_DIRECTORY_PATH is required.\"\n}\n\n$identity = [System.Security.Principal.WindowsIdentity]::GetCurrent()\n$sid = $identity.User\nif ($null -eq $sid) {\n throw \"Could not resolve the current Windows user SID.\"\n}\n\n$acl = Get-Acl -LiteralPath $directoryPath\n$acl.SetOwner($sid)\n$acl.SetAccessRuleProtection($true, $false)\n$existingRules = @($acl.GetAccessRules(\n $true,\n $false,\n [System.Security.Principal.SecurityIdentifier]\n))\nforeach ($existingRule in $existingRules) {\n [void]$acl.RemoveAccessRuleSpecific($existingRule)\n}\n$inheritance = (\n [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor\n [System.Security.AccessControl.InheritanceFlags]::ObjectInherit\n)\n$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(\n $sid,\n [System.Security.AccessControl.FileSystemRights]::FullControl,\n $inheritance,\n [System.Security.AccessControl.PropagationFlags]::None,\n [System.Security.AccessControl.AccessControlType]::Allow\n)\n$acl.SetAccessRule($rule)\nSet-Acl -LiteralPath $directoryPath -AclObject $acl\n\n$actual = Get-Acl -LiteralPath $directoryPath\n$ownerSid = $actual.GetOwner([System.Security.Principal.SecurityIdentifier])\n$rules = @($actual.GetAccessRules(\n $true,\n $true,\n [System.Security.Principal.SecurityIdentifier]\n))\nif (-not $actual.AreAccessRulesProtected) {\n throw \"Private directory DACL still inherits permissions.\"\n}\nif ($ownerSid.Value -ne $sid.Value) {\n throw \"Private directory owner SID does not match the current user.\"\n}\nif ($rules.Count -ne 1) {\n throw \"Private directory DACL must contain exactly one access rule.\"\n}\n$actualRule = $rules[0]\n$requiredInheritance = (\n [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor\n [System.Security.AccessControl.InheritanceFlags]::ObjectInherit\n)\nif (\n $actualRule.IsInherited -or\n $actualRule.IdentityReference.Value -ne $sid.Value -or\n $actualRule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow -or\n (($actualRule.FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -ne [System.Security.AccessControl.FileSystemRights]::FullControl) -or\n (($actualRule.InheritanceFlags -band $requiredInheritance) -ne $requiredInheritance)\n) {\n throw \"Private directory DACL is not owner-only inheritable full control.\"\n}\n`;\n\nexport type WindowsAclRunner = (\n command: string,\n args: string[],\n options: {\n env: NodeJS.ProcessEnv;\n windowsHide: boolean;\n },\n) => Promise<void>;\n\nconst runWindowsAclCommand: WindowsAclRunner = async (command, args, options) => {\n await execFileAsync(command, args, options);\n};\n\nexport function resolveWindowsPowerShellPath(systemRoot: string | null | undefined): string {\n const normalizedRoot = systemRoot?.trim() ? path.win32.normalize(systemRoot.trim()) : undefined;\n if (!normalizedRoot || !/^[A-Za-z]:\\\\/.test(normalizedRoot)) {\n throw new Error(\"SystemRoot must be an absolute local Windows path.\");\n }\n return path.win32.join(normalizedRoot, \"System32\", \"WindowsPowerShell\", \"v1.0\", \"powershell.exe\");\n}\n\nexport async function applyOwnerOnlyWindowsAcl(\n filePath: string,\n run: WindowsAclRunner = runWindowsAclCommand,\n systemRoot: string | null | undefined = process.env.SystemRoot,\n): Promise<void> {\n try {\n const powershellPath = resolveWindowsPowerShellPath(systemRoot);\n await run(\n powershellPath,\n [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", WINDOWS_OWNER_ONLY_ACL_SCRIPT],\n {\n env: {\n ...process.env,\n CRABLINE_PRIVATE_FILE_PATH: path.resolve(filePath),\n },\n windowsHide: true,\n },\n );\n } catch (error) {\n throw new Error(\n \"Could not apply and verify an owner-only Windows ACL; powershell.exe with Set-Acl is required.\",\n { cause: error },\n );\n }\n}\n\nexport async function applyOwnerOnlyWindowsDirectoryAcl(\n directoryPath: string,\n run: WindowsAclRunner = runWindowsAclCommand,\n systemRoot: string | null | undefined = process.env.SystemRoot,\n): Promise<void> {\n try {\n const powershellPath = resolveWindowsPowerShellPath(systemRoot);\n await run(\n powershellPath,\n [\n \"-NoLogo\",\n \"-NoProfile\",\n \"-NonInteractive\",\n \"-Command\",\n WINDOWS_OWNER_ONLY_DIRECTORY_ACL_SCRIPT,\n ],\n {\n env: {\n ...process.env,\n CRABLINE_PRIVATE_DIRECTORY_PATH: path.resolve(directoryPath),\n },\n windowsHide: true,\n },\n );\n } catch (error) {\n throw new Error(\n \"Could not apply and verify an owner-only Windows directory ACL; powershell.exe with Set-Acl is required.\",\n { cause: error },\n );\n }\n}\n\ntype FileIdentity = {\n device: bigint;\n inode: bigint;\n};\n\nasync function readHandleIdentity(handle: FileHandle): Promise<FileIdentity> {\n const stats = await handle.stat({ bigint: true });\n if (stats.ino <= 0n) {\n throw new Error(\"The filesystem did not provide a stable private file identity.\");\n }\n return {\n device: stats.dev,\n inode: stats.ino,\n };\n}\n\nasync function assertPathIdentity(filePath: string, expected: FileIdentity): Promise<void> {\n try {\n const stats = await fs.lstat(filePath, { bigint: true });\n if (\n stats.isFile() &&\n stats.nlink === 1n &&\n stats.dev === expected.device &&\n stats.ino === expected.inode\n ) {\n return;\n }\n } catch (error) {\n throw new Error(\"Private file path identity changed during publication.\", { cause: error });\n }\n throw new Error(\"Private file path identity changed during publication.\");\n}\n\ntype DirectoryIdentity = {\n device: bigint;\n inode: bigint;\n userId: bigint;\n};\n\nasync function readDirectoryHandleIdentity(handle: FileHandle): Promise<DirectoryIdentity> {\n const stats = await handle.stat({ bigint: true });\n if (!stats.isDirectory() || stats.ino <= 0n) {\n throw new Error(\"The filesystem did not provide a stable private directory identity.\");\n }\n return {\n device: stats.dev,\n inode: stats.ino,\n userId: stats.uid,\n };\n}\n\nasync function assertDirectoryPathIdentity(\n directoryPath: string,\n expected: DirectoryIdentity,\n): Promise<void> {\n try {\n const stats = await fs.lstat(directoryPath, { bigint: true });\n if (stats.isDirectory() && stats.dev === expected.device && stats.ino === expected.inode) {\n return;\n }\n } catch (error) {\n throw new Error(\"Private directory path identity changed during publication.\", {\n cause: error,\n });\n }\n throw new Error(\"Private directory path identity changed during publication.\");\n}\n\nexport type SecuredPrivateDirectory = {\n assertIdentityAt(directoryPath?: string): Promise<void>;\n directoryPath: string;\n};\n\nexport async function captureDirectoryIdentity(\n directoryPath: string,\n): Promise<SecuredPrivateDirectory> {\n const handle = await fs.open(directoryPath, \"r\");\n try {\n const identity = await readDirectoryHandleIdentity(handle);\n const secured: SecuredPrivateDirectory = {\n async assertIdentityAt(currentPath = directoryPath) {\n await assertDirectoryPathIdentity(currentPath, identity);\n },\n directoryPath,\n };\n await secured.assertIdentityAt();\n return secured;\n } finally {\n await handle.close();\n }\n}\n\nexport async function syncParentDirectory(\n filePath: string,\n platform: NodeJS.Platform = process.platform,\n): Promise<void> {\n if (platform === \"win32\") {\n return;\n }\n const handle = await fs.open(path.dirname(filePath), \"r\");\n try {\n await handle.sync();\n } finally {\n await handle.close();\n }\n}\n\nasync function syncParentAtAccessibleBoundary(\n filePath: string,\n syncParent: (filePath: string, platform?: NodeJS.Platform) => Promise<void>,\n platform?: NodeJS.Platform,\n): Promise<boolean> {\n try {\n await syncParent(filePath, platform);\n return true;\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code === \"EACCES\" || code === \"EPERM\") {\n return false;\n }\n throw error;\n }\n}\n\nasync function syncPathAncestry(\n filePath: string,\n syncParent: (filePath: string, platform?: NodeJS.Platform) => Promise<void>,\n platform?: NodeJS.Platform,\n firstCreatedDirectory?: string,\n): Promise<void> {\n const resolvedFilePath = path.resolve(filePath);\n let currentPath = resolvedFilePath;\n const syncThroughPath =\n firstCreatedDirectory === undefined ? undefined : path.resolve(firstCreatedDirectory);\n for (;;) {\n const mandatory = syncThroughPath !== undefined || currentPath === resolvedFilePath;\n if (mandatory) {\n await syncParent(currentPath, platform);\n } else if (!(await syncParentAtAccessibleBoundary(currentPath, syncParent, platform))) {\n return;\n }\n if (currentPath === syncThroughPath) {\n return;\n }\n const parentPath = path.dirname(currentPath);\n if (path.dirname(parentPath) === parentPath) {\n return;\n }\n currentPath = parentPath;\n }\n}\n\nexport async function removeSecuredPrivateDirectory(\n secured: SecuredPrivateDirectory,\n currentPath = secured.directoryPath,\n quarantineBaseName = path.basename(currentPath),\n): Promise<void> {\n if (path.basename(quarantineBaseName) !== quarantineBaseName || quarantineBaseName.length === 0) {\n throw new Error(\"Private directory quarantine basename is malformed.\");\n }\n const quarantinePath = path.join(\n path.dirname(currentPath),\n `.${quarantineBaseName}.${process.pid}.${randomUUID()}.remove`,\n );\n await secured.assertIdentityAt(currentPath);\n await fs.rename(currentPath, quarantinePath);\n await secured.assertIdentityAt(quarantinePath);\n await syncParentDirectory(quarantinePath);\n await fs.rm(quarantinePath, { force: true, recursive: true });\n await syncParentDirectory(quarantinePath);\n}\n\nexport async function securePrivateDirectory(\n directoryPath: string,\n options: {\n currentUserId?: number;\n platform?: NodeJS.Platform;\n secureWindowsDirectory?: (directoryPath: string) => Promise<void>;\n syncParent?: (filePath: string, platform?: NodeJS.Platform) => Promise<void>;\n } = {},\n): Promise<SecuredPrivateDirectory> {\n let created = false;\n try {\n await fs.mkdir(directoryPath, { mode: 0o700 });\n created = true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"EEXIST\") {\n throw error;\n }\n }\n\n const handle = await fs.open(directoryPath, \"r\");\n let handleOpen = true;\n const closeHandle = async () => {\n if (!handleOpen) {\n return;\n }\n handleOpen = false;\n await handle.close();\n };\n let identity: DirectoryIdentity;\n try {\n identity = await readDirectoryHandleIdentity(handle);\n } catch (error) {\n try {\n await closeHandle();\n } catch (closeError) {\n const aggregateError = new AggregateError(\n [error, closeError],\n \"Private directory identity verification failed and its handle could not be closed.\",\n );\n aggregateError.cause = error;\n throw aggregateError;\n }\n throw error;\n }\n const secured: SecuredPrivateDirectory = {\n async assertIdentityAt(currentPath = directoryPath) {\n await assertDirectoryPathIdentity(currentPath, identity);\n },\n directoryPath,\n };\n try {\n await secured.assertIdentityAt();\n if ((options.platform ?? process.platform) === \"win32\") {\n await (options.secureWindowsDirectory ?? applyOwnerOnlyWindowsDirectoryAcl)(directoryPath);\n } else {\n const currentUserId = options.currentUserId ?? process.geteuid?.();\n if (\n currentUserId === undefined ||\n !Number.isSafeInteger(currentUserId) ||\n currentUserId < 0 ||\n identity.userId !== BigInt(currentUserId)\n ) {\n throw new Error(\"Private directory must be owned by the current POSIX user.\");\n }\n await handle.chmod(0o700);\n }\n await secured.assertIdentityAt();\n const syncParent = options.syncParent ?? syncParentDirectory;\n if (created) {\n await syncParent(directoryPath, options.platform);\n } else {\n await syncParentAtAccessibleBoundary(directoryPath, syncParent, options.platform);\n }\n } catch (error) {\n let primaryError = error;\n try {\n await closeHandle();\n } catch (closeError) {\n const aggregateError = new AggregateError(\n [error, closeError],\n \"Private directory securing failed and its verification handle could not be closed.\",\n );\n aggregateError.cause = error;\n primaryError = aggregateError;\n }\n if (created) {\n try {\n await removeSecuredPrivateDirectory(secured);\n } catch (cleanupError) {\n const aggregateError = new AggregateError(\n [primaryError, cleanupError],\n `Private directory securing failed and rollback cleanup also failed: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n aggregateError.cause = primaryError;\n throw aggregateError;\n }\n }\n throw primaryError;\n } finally {\n await closeHandle();\n }\n\n return secured;\n}\n\nexport async function publishPrivateFileAtomically(\n filePath: string,\n contents: string,\n options: {\n afterRename?: (filePath: string) => Promise<void>;\n beforeRename?: (temporaryPath: string) => Promise<void>;\n platform?: NodeJS.Platform;\n removeTemporaryFile?: (temporaryPath: string) => Promise<void>;\n secureWindowsFile?: (temporaryPath: string) => Promise<void>;\n syncParent?: (filePath: string, platform?: NodeJS.Platform) => Promise<void>;\n } = {},\n): Promise<void> {\n const temporaryPath = path.join(\n path.dirname(filePath),\n `.${path.basename(filePath)}.${process.pid}.${randomUUID()}.tmp`,\n );\n const parentDirectory = path.resolve(path.dirname(filePath));\n const firstCreatedDirectory = await fs.mkdir(parentDirectory, { recursive: true });\n let handle: FileHandle | undefined;\n let publicationFailed = false;\n let primaryError: unknown;\n try {\n handle = await fs.open(temporaryPath, \"wx+\", 0o600);\n const identity = await readHandleIdentity(handle);\n if ((options.platform ?? process.platform) === \"win32\") {\n await (options.secureWindowsFile ?? applyOwnerOnlyWindowsAcl)(temporaryPath);\n } else {\n await handle.chmod(0o600);\n }\n\n await assertPathIdentity(temporaryPath, identity);\n await handle.writeFile(contents, \"utf8\");\n await handle.sync();\n await assertPathIdentity(temporaryPath, identity);\n await options.beforeRename?.(temporaryPath);\n await assertPathIdentity(temporaryPath, identity);\n await fs.rename(temporaryPath, filePath);\n await syncPathAncestry(\n filePath,\n options.syncParent ?? syncParentDirectory,\n options.platform,\n firstCreatedDirectory,\n );\n await options.afterRename?.(filePath);\n await assertPathIdentity(filePath, identity);\n } catch (error) {\n publicationFailed = true;\n primaryError = error;\n }\n\n const cleanupErrors: unknown[] = [];\n try {\n await handle?.close();\n } catch (error) {\n cleanupErrors.push(error);\n }\n try {\n await (\n options.removeTemporaryFile ??\n ((candidatePath: string) => fs.rm(candidatePath, { force: true }))\n )(temporaryPath);\n } catch (error) {\n cleanupErrors.push(error);\n }\n\n if (publicationFailed) {\n if (cleanupErrors.length > 0) {\n const primaryMessage =\n primaryError instanceof Error ? primaryError.message : String(primaryError);\n const aggregateError = new AggregateError(\n [primaryError, ...cleanupErrors],\n `${primaryMessage} Private temporary file cleanup also failed.`,\n );\n aggregateError.cause = primaryError;\n const primaryCode =\n typeof primaryError === \"object\" && primaryError !== null\n ? (primaryError as NodeJS.ErrnoException).code\n : undefined;\n if (primaryCode) {\n Object.assign(aggregateError, { code: primaryCode });\n }\n throw aggregateError;\n }\n throw primaryError;\n }\n if (cleanupErrors.length === 1) {\n throw cleanupErrors[0];\n }\n if (cleanupErrors.length > 1) {\n throw new AggregateError(cleanupErrors, \"Private temporary file publication cleanup failed.\");\n }\n}\n"]}