@xenosystem/agent-cli 0.5.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +157 -0
- package/dist/index.js +6820 -0
- package/dist/metafile-esm.json +1 -0
- package/native/xeno-pty/prebuilds/PROVENANCE.md +69 -0
- package/native/xeno-pty/prebuilds/darwin-arm64/manifest.json +18 -0
- package/native/xeno-pty/prebuilds/darwin-arm64/xeno_pty.node +0 -0
- package/native/xeno-pty/prebuilds/darwin-x64/manifest.json +18 -0
- package/native/xeno-pty/prebuilds/darwin-x64/xeno_pty.node +0 -0
- package/native/xeno-pty/prebuilds/linux-arm64/manifest.json +18 -0
- package/native/xeno-pty/prebuilds/linux-arm64/xeno_pty.node +0 -0
- package/native/xeno-pty/prebuilds/linux-x64/manifest.json +18 -0
- package/native/xeno-pty/prebuilds/linux-x64/xeno_pty.node +0 -0
- package/native/xeno-pty/prebuilds/win32-x64/manifest.json +18 -0
- package/native/xeno-pty/prebuilds/win32-x64/xeno_pty.node +0 -0
- package/native/xeno-pty/trusted-keys.json +4 -0
- package/ownership/CLEAN_ROOM_CONTRIBUTOR_GUIDE.md +63 -0
- package/ownership/audit.mjs +727 -0
- package/ownership/containment-reviewer-trusted-keys.json +4 -0
- package/ownership/containment-trusted-keys.json +4 -0
- package/ownership/evidence/PROPRIETARY-COMMAND-1/implementation-record.md +77 -0
- package/ownership/evidence/PROPRIETARY-COMMAND-1/provenance-review.md +51 -0
- package/ownership/evidence/PROPRIETARY-MEDIA-1/implementation-record.md +131 -0
- package/ownership/evidence/PROPRIETARY-MEDIA-1/provenance-review.md +50 -0
- package/ownership/evidence/PROPRIETARY-PTY-1/implementation-record.md +86 -0
- package/ownership/evidence/PROPRIETARY-PTY-1/provenance-review.md +52 -0
- package/ownership/evidence/PROPRIETARY-RUNTIME-1/implementation-record.md +68 -0
- package/ownership/evidence/PROPRIETARY-RUNTIME-1/provenance-review.md +32 -0
- package/ownership/evidence/PROPRIETARY-TOOLCHAIN-1/implementation-record.md +53 -0
- package/ownership/evidence/PROPRIETARY-TOOLCHAIN-1/provenance-review.md +32 -0
- package/ownership/evidence/PROPRIETARY-UI-1/implementation-record.md +96 -0
- package/ownership/evidence/PROPRIETARY-UI-1/provenance-review.md +46 -0
- package/ownership/ownership-policy.json +232 -0
- package/ownership/ownership-policy.schema.json +192 -0
- package/ownership/templates/clean-room-implementation-record.md +70 -0
- package/ownership/templates/provenance-review.md +51 -0
- package/package.json +77 -0
- package/scripts/install.ps1 +18 -0
- package/scripts/install.sh +18 -0
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Keep this package-local file byte-identical in SDK and CLI release artifacts.
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
import {
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
readdirSync,
|
|
10
|
+
writeFileSync,
|
|
11
|
+
} from "node:fs";
|
|
12
|
+
import { builtinModules } from "node:module";
|
|
13
|
+
import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
14
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
|
+
|
|
16
|
+
const CLASSIFICATIONS = new Set([
|
|
17
|
+
"xeno-owned",
|
|
18
|
+
"platform-api",
|
|
19
|
+
"external-runtime",
|
|
20
|
+
"build-only",
|
|
21
|
+
"test-oracle",
|
|
22
|
+
"temporary-runtime",
|
|
23
|
+
"forbidden",
|
|
24
|
+
]);
|
|
25
|
+
const LEVELS = ["pre-P1", "P1", "P2", "P3", "P4"];
|
|
26
|
+
const SOURCE_EXTENSIONS = new Set([".js", ".jsx", ".mjs", ".cjs", ".ts", ".tsx"]);
|
|
27
|
+
const NATIVE_EXTENSIONS = new Set([".node", ".dll", ".so", ".dylib", ".exe"]);
|
|
28
|
+
const SOURCE_SKIP_DIRECTORIES = new Set([".git", "coverage", "dist", "node_modules", "release"]);
|
|
29
|
+
const LEGACY_NODE_BUILTINS = new Set(builtinModules.map((name) => name.replace(/^node:/, "")));
|
|
30
|
+
|
|
31
|
+
function parseJson(path) {
|
|
32
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function sha256(value) {
|
|
36
|
+
return createHash("sha256").update(value).digest("hex");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function requireString(value, label, errors) {
|
|
40
|
+
if (typeof value !== "string" || value.trim().length === 0) errors.push(`${label} must be a non-empty string`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function requireStringArray(value, label, errors) {
|
|
44
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((entry) => typeof entry !== "string" || entry.length === 0)) {
|
|
45
|
+
errors.push(`${label} must be a non-empty string array`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function validateOwnershipPolicy(policy) {
|
|
50
|
+
const errors = [];
|
|
51
|
+
if (!policy || typeof policy !== "object" || Array.isArray(policy)) return ["policy must be an object"];
|
|
52
|
+
if (policy.schemaVersion !== 1) errors.push("schemaVersion must be 1");
|
|
53
|
+
requireString(policy.policyId, "policyId", errors);
|
|
54
|
+
if (!Number.isInteger(policy.policyRevision) || policy.policyRevision < 1) errors.push("policyRevision must be a positive integer");
|
|
55
|
+
requireString(policy.canonicalLocation, "canonicalLocation", errors);
|
|
56
|
+
if (!LEVELS.includes(policy.enforcedLevel)) errors.push(`unsupported enforcedLevel: ${policy.enforcedLevel}`);
|
|
57
|
+
if (!LEVELS.includes(policy.targetLevel) || policy.targetLevel === "pre-P1") errors.push(`unsupported targetLevel: ${policy.targetLevel}`);
|
|
58
|
+
requireStringArray(policy.xenoPackagePrefixes, "xenoPackagePrefixes", errors);
|
|
59
|
+
if (!policy.repositories || typeof policy.repositories !== "object") {
|
|
60
|
+
errors.push("repositories must be an object");
|
|
61
|
+
} else {
|
|
62
|
+
for (const [id, repository] of Object.entries(policy.repositories)) {
|
|
63
|
+
requireString(repository?.label, `repositories.${id}.label`, errors);
|
|
64
|
+
requireStringArray(repository?.manifestPaths, `repositories.${id}.manifestPaths`, errors);
|
|
65
|
+
requireStringArray(repository?.sourceRoots, `repositories.${id}.sourceRoots`, errors);
|
|
66
|
+
if (repository?.additionalOwnedSourceRoots !== undefined) {
|
|
67
|
+
requireStringArray(repository.additionalOwnedSourceRoots, `repositories.${id}.additionalOwnedSourceRoots`, errors);
|
|
68
|
+
}
|
|
69
|
+
requireString(repository?.reportDirectory, `repositories.${id}.reportDirectory`, errors);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for (const field of ["runtimeComponents", "builtinComponents", "platformBoundaries", "testOracles", "capabilityGates", "forbiddenPackages"]) {
|
|
73
|
+
if (!Array.isArray(policy[field])) errors.push(`${field} must be an array`);
|
|
74
|
+
}
|
|
75
|
+
for (const field of ["runtimeComponents", "builtinComponents", "platformBoundaries", "testOracles"]) {
|
|
76
|
+
for (const [index, component] of (policy[field] ?? []).entries()) {
|
|
77
|
+
requireString(component?.name, `${field}[${index}].name`, errors);
|
|
78
|
+
if (!CLASSIFICATIONS.has(component?.classification)) errors.push(`${field}[${index}] has an invalid classification`);
|
|
79
|
+
requireStringArray(component?.usedBy, `${field}[${index}].usedBy`, errors);
|
|
80
|
+
requireString(component?.replacement, `${field}[${index}].replacement`, errors);
|
|
81
|
+
requireString(component?.expiresAtMilestone, `${field}[${index}].expiresAtMilestone`, errors);
|
|
82
|
+
if (component?.artifactPathPrefixes !== undefined) {
|
|
83
|
+
requireStringArray(component.artifactPathPrefixes, `${field}[${index}].artifactPathPrefixes`, errors);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (policy.developmentPolicy?.classification !== "build-only") {
|
|
88
|
+
errors.push("developmentPolicy.classification must be build-only");
|
|
89
|
+
}
|
|
90
|
+
for (const field of ["guide", "implementationRecordTemplate", "provenanceReviewTemplate"]) {
|
|
91
|
+
requireString(policy.cleanRoomProtocol?.[field], `cleanRoomProtocol.${field}`, errors);
|
|
92
|
+
}
|
|
93
|
+
if (!["engineering-draft", "counsel-approved"].includes(policy.cleanRoomProtocol?.status)) {
|
|
94
|
+
errors.push("cleanRoomProtocol.status must be engineering-draft or counsel-approved");
|
|
95
|
+
}
|
|
96
|
+
if (typeof policy.cleanRoomProtocol?.counselApprovalRequired !== "boolean") {
|
|
97
|
+
errors.push("cleanRoomProtocol.counselApprovalRequired must be boolean");
|
|
98
|
+
}
|
|
99
|
+
for (const [index, gate] of (policy.capabilityGates ?? []).entries()) {
|
|
100
|
+
requireString(gate?.id, `capabilityGates[${index}].id`, errors);
|
|
101
|
+
if (!LEVELS.includes(gate?.requiredFor) || gate.requiredFor === "pre-P1") {
|
|
102
|
+
errors.push(`capabilityGates[${index}] has an invalid requiredFor level`);
|
|
103
|
+
}
|
|
104
|
+
if (typeof gate?.achieved !== "boolean") errors.push(`capabilityGates[${index}].achieved must be boolean`);
|
|
105
|
+
requireString(gate?.evidence, `capabilityGates[${index}].evidence`, errors);
|
|
106
|
+
}
|
|
107
|
+
return errors;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function packageNameFromLockPath(lockPath, entry) {
|
|
111
|
+
if (typeof entry.name === "string" && entry.name.length > 0) return entry.name;
|
|
112
|
+
const normalized = lockPath.replace(/\\/g, "/");
|
|
113
|
+
const marker = "/node_modules/";
|
|
114
|
+
const last = normalized.includes(marker)
|
|
115
|
+
? normalized.slice(normalized.lastIndexOf(marker) + marker.length)
|
|
116
|
+
: normalized.startsWith("node_modules/")
|
|
117
|
+
? normalized.slice("node_modules/".length)
|
|
118
|
+
: "";
|
|
119
|
+
if (!last) return undefined;
|
|
120
|
+
const segments = last.split("/");
|
|
121
|
+
return segments[0]?.startsWith("@") ? `${segments[0]}/${segments[1]}` : segments[0];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function packageNameFromSpecifier(specifier) {
|
|
125
|
+
if (specifier.startsWith("node:")) return specifier;
|
|
126
|
+
if (specifier.startsWith("@")) return specifier.split("/").slice(0, 2).join("/");
|
|
127
|
+
return specifier.split("/")[0];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function isBareSpecifier(specifier) {
|
|
131
|
+
return !specifier.startsWith(".") && !specifier.startsWith("/") && !/^[A-Za-z]:[\\/]/.test(specifier);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function walkSourceFiles(root, output) {
|
|
135
|
+
if (!existsSync(root)) return;
|
|
136
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
137
|
+
if (entry.isDirectory()) {
|
|
138
|
+
if (!SOURCE_SKIP_DIRECTORIES.has(entry.name)) walkSourceFiles(join(root, entry.name), output);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (entry.isFile() && SOURCE_EXTENSIONS.has(extname(entry.name))) output.push(join(root, entry.name));
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function walkArtifactFiles(root, output) {
|
|
146
|
+
if (!existsSync(root)) return;
|
|
147
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
148
|
+
const path = join(root, entry.name);
|
|
149
|
+
if (entry.isDirectory()) {
|
|
150
|
+
walkArtifactFiles(path, output);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (entry.isFile()) output.push(path);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function isWithin(candidate, parent) {
|
|
158
|
+
const path = relative(parent, candidate);
|
|
159
|
+
return path === "" || (!path.startsWith("..") && !isAbsolute(path));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function packageRootForInstallation(root, label) {
|
|
163
|
+
const segments = label.split("/");
|
|
164
|
+
return join(root, "node_modules", ...segments);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function artifactDistRoots(root, repositoryId, repository, installation) {
|
|
168
|
+
if (installation) return [join(packageRootForInstallation(root, repository.label), "dist")];
|
|
169
|
+
return repositoryId === "cli"
|
|
170
|
+
? [join(root, "apps", "xeno-agent-cli", "dist")]
|
|
171
|
+
: [join(root, "dist")];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function ownedBundleInput(root, repository, input) {
|
|
175
|
+
const candidate = resolve(root, input);
|
|
176
|
+
return [...repository.sourceRoots, ...(repository.additionalOwnedSourceRoots ?? [])]
|
|
177
|
+
.some((sourceRoot) => isWithin(candidate, resolve(root, sourceRoot)));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function bundleOutputsByInput(metafile) {
|
|
181
|
+
const outputs = new Map();
|
|
182
|
+
for (const [outputPath, output] of Object.entries(metafile.outputs ?? {})) {
|
|
183
|
+
for (const [inputPath, contribution] of Object.entries(output.inputs ?? {})) {
|
|
184
|
+
const current = outputs.get(inputPath) ?? [];
|
|
185
|
+
current.push({ path: outputPath, bytesInOutput: contribution.bytesInOutput ?? 0 });
|
|
186
|
+
outputs.set(inputPath, current);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return outputs;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function collectArtifactComponents(root, repositoryId, repository, policy, installation) {
|
|
193
|
+
const components = [];
|
|
194
|
+
const violations = [];
|
|
195
|
+
const distRoots = artifactDistRoots(root, repositoryId, repository, installation);
|
|
196
|
+
const bundleFiles = [];
|
|
197
|
+
for (const distRoot of distRoots) {
|
|
198
|
+
const files = [];
|
|
199
|
+
walkArtifactFiles(distRoot, files);
|
|
200
|
+
bundleFiles.push(...files.filter((path) => /^metafile-(?:esm|cjs|iife)\.json$/i.test(path.split(/[\\/]/).at(-1) ?? "")));
|
|
201
|
+
}
|
|
202
|
+
if (bundleFiles.length === 0) {
|
|
203
|
+
violations.push("artifact audit found no esbuild metafile; build with bundle provenance enabled before auditing");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
for (const metafilePath of bundleFiles) {
|
|
207
|
+
let metafile;
|
|
208
|
+
try {
|
|
209
|
+
metafile = parseJson(metafilePath);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
violations.push(`invalid bundle metafile ${relative(root, metafilePath)}: ${error instanceof Error ? error.message : String(error)}`);
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
const outputs = bundleOutputsByInput(metafile);
|
|
215
|
+
for (const [inputPath, input] of Object.entries(metafile.inputs ?? {})) {
|
|
216
|
+
const packageName = packageNameFromLockPath(inputPath, {});
|
|
217
|
+
const result = packageName
|
|
218
|
+
? classify(policy, packageName, "bundle-input")
|
|
219
|
+
: ownedBundleInput(root, repository, inputPath)
|
|
220
|
+
? { classification: "xeno-owned", policy: undefined }
|
|
221
|
+
: { classification: "unclassified", policy: undefined };
|
|
222
|
+
components.push({
|
|
223
|
+
id: `bundle:${relative(root, metafilePath).replace(/\\/g, "/")}:${inputPath}`,
|
|
224
|
+
name: packageName ?? inputPath,
|
|
225
|
+
scope: "bundle-input",
|
|
226
|
+
classification: result.classification,
|
|
227
|
+
path: inputPath,
|
|
228
|
+
evidencePath: relative(root, metafilePath).replace(/\\/g, "/"),
|
|
229
|
+
sourceBytes: input.bytes,
|
|
230
|
+
outputs: outputs.get(inputPath) ?? [],
|
|
231
|
+
replacement: result.policy?.replacement,
|
|
232
|
+
expiresAtMilestone: result.policy?.expiresAtMilestone,
|
|
233
|
+
});
|
|
234
|
+
if (result.classification === "unclassified" || result.classification === "forbidden") {
|
|
235
|
+
violations.push(`${inputPath} is ${result.classification} in production bundle evidence`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const ownPackageRoot = installation
|
|
241
|
+
? packageRootForInstallation(root, repository.label)
|
|
242
|
+
: repositoryId === "cli"
|
|
243
|
+
? join(root, "apps", "xeno-agent-cli")
|
|
244
|
+
: root;
|
|
245
|
+
const nativeRoots = installation
|
|
246
|
+
? [join(root, "node_modules")]
|
|
247
|
+
: repositoryId === "cli"
|
|
248
|
+
? [...distRoots, join(root, "apps", "xeno-agent-cli", "native")]
|
|
249
|
+
: [...distRoots, join(root, "native")];
|
|
250
|
+
const nativeFiles = [];
|
|
251
|
+
for (const nativeRoot of nativeRoots) {
|
|
252
|
+
const files = [];
|
|
253
|
+
walkArtifactFiles(nativeRoot, files);
|
|
254
|
+
nativeFiles.push(...files.filter((path) =>
|
|
255
|
+
NATIVE_EXTENSIONS.has(extname(path).toLowerCase())
|
|
256
|
+
|| artifactComponentPolicy(policy, relative(ownPackageRoot, path)),
|
|
257
|
+
));
|
|
258
|
+
}
|
|
259
|
+
for (const nativePath of nativeFiles) {
|
|
260
|
+
const relativePath = relative(root, nativePath).replace(/\\/g, "/");
|
|
261
|
+
const artifactPolicy = artifactComponentPolicy(policy, relative(ownPackageRoot, nativePath));
|
|
262
|
+
const packageName = packageNameFromLockPath(relativePath, {});
|
|
263
|
+
const result = artifactPolicy
|
|
264
|
+
? { classification: artifactPolicy.classification, policy: artifactPolicy }
|
|
265
|
+
: packageName
|
|
266
|
+
? classify(policy, packageName, "native-artifact")
|
|
267
|
+
: isWithin(nativePath, ownPackageRoot)
|
|
268
|
+
? { classification: "xeno-owned", policy: undefined }
|
|
269
|
+
: { classification: "unclassified", policy: undefined };
|
|
270
|
+
components.push({
|
|
271
|
+
id: `native:${relativePath}`,
|
|
272
|
+
name: artifactPolicy?.name ?? packageName ?? relativePath,
|
|
273
|
+
scope: "native-artifact",
|
|
274
|
+
classification: result.classification,
|
|
275
|
+
path: relativePath,
|
|
276
|
+
sha256: sha256(readFileSync(nativePath)),
|
|
277
|
+
replacement: result.policy?.replacement,
|
|
278
|
+
expiresAtMilestone: result.policy?.expiresAtMilestone,
|
|
279
|
+
});
|
|
280
|
+
if (result.classification === "unclassified" || result.classification === "forbidden") {
|
|
281
|
+
violations.push(`${relativePath} is ${result.classification} as a native artifact`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return { components, violations, bundleMetafiles: bundleFiles.length, nativeArtifacts: nativeFiles.length };
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function collectSourceSpecifiers(root, sourceRoots) {
|
|
288
|
+
const files = [];
|
|
289
|
+
for (const sourceRoot of sourceRoots) walkSourceFiles(join(root, sourceRoot), files);
|
|
290
|
+
const findings = [];
|
|
291
|
+
const patterns = [
|
|
292
|
+
/^\s*(?:import|export)\s+(?:type\s+)?(?:[^;\n]*?\s+from\s+)?["']([^"']+)["']/gm,
|
|
293
|
+
/^[^"'`\/]*\bimport\s*\(\s*["']([^"']+)["']\s*\)/gm,
|
|
294
|
+
/^[^"'`\/]*\brequire\s*\(\s*["']([^"']+)["']\s*\)/gm,
|
|
295
|
+
];
|
|
296
|
+
for (const path of files) {
|
|
297
|
+
const text = readFileSync(path, "utf8");
|
|
298
|
+
for (const pattern of patterns) {
|
|
299
|
+
pattern.lastIndex = 0;
|
|
300
|
+
for (let match = pattern.exec(text); match; match = pattern.exec(text)) {
|
|
301
|
+
const specifier = match[1];
|
|
302
|
+
if (!specifier || !isBareSpecifier(specifier)) continue;
|
|
303
|
+
findings.push({
|
|
304
|
+
specifier,
|
|
305
|
+
name: packageNameFromSpecifier(specifier),
|
|
306
|
+
path: relative(root, path).replace(/\\/g, "/"),
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return findings;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function componentPolicy(policy, name) {
|
|
315
|
+
return [...policy.runtimeComponents, ...policy.builtinComponents, ...(policy.testOracles ?? [])]
|
|
316
|
+
.find((component) => component.name === name);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function artifactComponentPolicy(policy, path) {
|
|
320
|
+
const normalized = path.replace(/\\/g, "/");
|
|
321
|
+
return [...policy.runtimeComponents, ...policy.builtinComponents]
|
|
322
|
+
.find((component) => (component.artifactPathPrefixes ?? []).some((prefix) => {
|
|
323
|
+
const normalizedPrefix = prefix.replace(/^\/+|\/+$/g, "");
|
|
324
|
+
return normalized === normalizedPrefix
|
|
325
|
+
|| normalized.startsWith(`${normalizedPrefix}/`)
|
|
326
|
+
|| normalized.includes(`/${normalizedPrefix}/`);
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function isForbidden(policy, name) {
|
|
331
|
+
return policy.forbiddenPackages.some((forbidden) => name === forbidden || name.startsWith(`${forbidden}-`));
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function classify(policy, name, scope) {
|
|
335
|
+
if (isForbidden(policy, name)) return { classification: "forbidden", policy: undefined };
|
|
336
|
+
if (policy.xenoPackagePrefixes.some((prefix) => name.startsWith(prefix))) {
|
|
337
|
+
return { classification: "xeno-owned", policy: undefined };
|
|
338
|
+
}
|
|
339
|
+
if ((name.startsWith("node:") || LEGACY_NODE_BUILTINS.has(name)) && !componentPolicy(policy, name)) {
|
|
340
|
+
return { classification: "external-runtime", policy: { replacement: "standalone-runtime-decision", expiresAtMilestone: "PROPRIETARY-RUNTIME-1" } };
|
|
341
|
+
}
|
|
342
|
+
if (scope === "development") return { classification: policy.developmentPolicy.classification, policy: undefined };
|
|
343
|
+
const matched = componentPolicy(policy, name);
|
|
344
|
+
return matched
|
|
345
|
+
? { classification: matched.classification, policy: matched }
|
|
346
|
+
: { classification: "unclassified", policy: undefined };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function directDeclarations(root, repository) {
|
|
350
|
+
const declarations = [];
|
|
351
|
+
for (const manifestPath of repository.manifestPaths) {
|
|
352
|
+
const absolute = join(root, manifestPath);
|
|
353
|
+
if (!existsSync(absolute)) continue;
|
|
354
|
+
const manifest = parseJson(absolute);
|
|
355
|
+
for (const [field, scope] of [
|
|
356
|
+
["dependencies", "runtime"],
|
|
357
|
+
["optionalDependencies", "runtime-optional"],
|
|
358
|
+
["peerDependencies", "peer"],
|
|
359
|
+
["devDependencies", "development"],
|
|
360
|
+
]) {
|
|
361
|
+
for (const [name, requested] of Object.entries(manifest[field] ?? {})) {
|
|
362
|
+
declarations.push({ name, requested, scope, manifestPath, field });
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return declarations;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function determineAchievedLevel(policy, components, violations) {
|
|
370
|
+
if (violations.length > 0 || components.some((component) => component.classification === "temporary-runtime" || component.classification === "forbidden")) {
|
|
371
|
+
return "pre-P1";
|
|
372
|
+
}
|
|
373
|
+
const levels = ["P1", "P2", "P3", "P4"];
|
|
374
|
+
let achieved = "pre-P1";
|
|
375
|
+
for (const level of levels) {
|
|
376
|
+
const required = policy.capabilityGates.filter((gate) => LEVELS.indexOf(gate.requiredFor) <= LEVELS.indexOf(level));
|
|
377
|
+
if (required.every((gate) => gate.achieved)) achieved = level;
|
|
378
|
+
else break;
|
|
379
|
+
}
|
|
380
|
+
return achieved;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function summarizeCounts(components, key) {
|
|
384
|
+
const counts = {};
|
|
385
|
+
for (const component of components) counts[component[key]] = (counts[component[key]] ?? 0) + 1;
|
|
386
|
+
return Object.fromEntries(Object.entries(counts).sort(([left], [right]) => left.localeCompare(right)));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function renderMarkdown(report) {
|
|
390
|
+
const runtimeExceptions = report.components.filter((component) =>
|
|
391
|
+
["runtime", "runtime-optional", "peer", "source-import", "builtin"].includes(component.scope) &&
|
|
392
|
+
!["xeno-owned", "platform-api"].includes(component.classification),
|
|
393
|
+
);
|
|
394
|
+
const lines = [
|
|
395
|
+
"# Ownership Inventory",
|
|
396
|
+
"",
|
|
397
|
+
`Generated: ${report.generatedAt}`,
|
|
398
|
+
"",
|
|
399
|
+
`Repository: \`${report.repository.label}\``,
|
|
400
|
+
"",
|
|
401
|
+
`Policy: \`${report.policy.id}\` revision ${report.policy.revision} (SHA-256 \`${report.policy.sha256}\`)`,
|
|
402
|
+
"",
|
|
403
|
+
`Achieved level: **${report.achievedLevel}**`,
|
|
404
|
+
"",
|
|
405
|
+
`Target level: **${report.policy.targetLevel}**`,
|
|
406
|
+
"",
|
|
407
|
+
"## Scope Summary",
|
|
408
|
+
"",
|
|
409
|
+
"| Scope | Count |",
|
|
410
|
+
"| --- | ---: |",
|
|
411
|
+
...Object.entries(report.countsByScope).map(([scope, count]) => `| ${scope} | ${count} |`),
|
|
412
|
+
"",
|
|
413
|
+
"## Classification Summary",
|
|
414
|
+
"",
|
|
415
|
+
"| Classification | Count |",
|
|
416
|
+
"| --- | ---: |",
|
|
417
|
+
...Object.entries(report.countsByClassification).map(([classification, count]) => `| ${classification} | ${count} |`),
|
|
418
|
+
"",
|
|
419
|
+
"## Non-Xeno Runtime Boundaries",
|
|
420
|
+
"",
|
|
421
|
+
...(runtimeExceptions.length === 0
|
|
422
|
+
? ["None."]
|
|
423
|
+
: [
|
|
424
|
+
"| Component | Scope | Classification | Version/request | Replacement milestone |",
|
|
425
|
+
"| --- | --- | --- | --- | --- |",
|
|
426
|
+
...runtimeExceptions.map((component) =>
|
|
427
|
+
`| \`${component.name}\` | ${component.scope} | ${component.classification} | ${component.version ?? component.requested ?? "-"} | ${component.expiresAtMilestone ?? "-"} |`,
|
|
428
|
+
),
|
|
429
|
+
]),
|
|
430
|
+
"",
|
|
431
|
+
"## Violations",
|
|
432
|
+
"",
|
|
433
|
+
...(report.violations.length === 0 ? ["None."] : report.violations.map((violation) => `- ${violation}`)),
|
|
434
|
+
"",
|
|
435
|
+
];
|
|
436
|
+
return lines.join("\n");
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const REPORT_PARTITIONS = [
|
|
440
|
+
{
|
|
441
|
+
id: "runtime",
|
|
442
|
+
title: "Runtime ownership",
|
|
443
|
+
include: (component) => ["runtime", "runtime-optional", "peer", "source-import", "builtin"].includes(component.scope),
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
id: "development",
|
|
447
|
+
title: "Development ownership",
|
|
448
|
+
include: (component) => component.scope === "development",
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
id: "test-oracles",
|
|
452
|
+
title: "Test-oracle ownership",
|
|
453
|
+
include: (component) => component.scope === "test-oracle" || component.classification === "test-oracle",
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
id: "platform",
|
|
457
|
+
title: "Platform boundaries",
|
|
458
|
+
include: (component) => component.scope === "platform",
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
id: "artifacts",
|
|
462
|
+
title: "Bundle and native artifacts",
|
|
463
|
+
include: (component) => component.scope === "bundle-input" || component.scope === "native-artifact",
|
|
464
|
+
},
|
|
465
|
+
];
|
|
466
|
+
|
|
467
|
+
function partitionReport(report, partition) {
|
|
468
|
+
const components = report.components.filter(partition.include);
|
|
469
|
+
return {
|
|
470
|
+
generatedAt: report.generatedAt,
|
|
471
|
+
partition: partition.id,
|
|
472
|
+
title: partition.title,
|
|
473
|
+
repository: report.repository,
|
|
474
|
+
policy: report.policy,
|
|
475
|
+
achievedLevel: report.achievedLevel,
|
|
476
|
+
componentCount: components.length,
|
|
477
|
+
countsByScope: summarizeCounts(components, "scope"),
|
|
478
|
+
countsByClassification: summarizeCounts(components, "classification"),
|
|
479
|
+
components,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function renderPartitionMarkdown(partition) {
|
|
484
|
+
const lines = [
|
|
485
|
+
`# ${partition.title}`,
|
|
486
|
+
"",
|
|
487
|
+
`Generated: ${partition.generatedAt}`,
|
|
488
|
+
"",
|
|
489
|
+
`Repository: \`${partition.repository.label}\``,
|
|
490
|
+
"",
|
|
491
|
+
`Policy: \`${partition.policy.id}\` revision ${partition.policy.revision}`,
|
|
492
|
+
"",
|
|
493
|
+
`Achieved level: **${partition.achievedLevel}**`,
|
|
494
|
+
"",
|
|
495
|
+
`Component count: **${partition.componentCount}**`,
|
|
496
|
+
"",
|
|
497
|
+
"| Component | Scope | Classification | Version/request | Evidence |",
|
|
498
|
+
"| --- | --- | --- | --- | --- |",
|
|
499
|
+
...partition.components.map((component) =>
|
|
500
|
+
`| \`${component.name}\` | ${component.scope} | ${component.classification} | ${component.version ?? component.requested ?? "-"} | \`${component.evidencePath ?? component.path ?? "-"}\` |`,
|
|
501
|
+
),
|
|
502
|
+
"",
|
|
503
|
+
];
|
|
504
|
+
return lines.join("\n");
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export function auditOwnership(options) {
|
|
508
|
+
const root = resolve(options.root);
|
|
509
|
+
const policyPath = resolve(options.policyPath);
|
|
510
|
+
const policyText = readFileSync(policyPath, "utf8");
|
|
511
|
+
const policy = JSON.parse(policyText);
|
|
512
|
+
const policyErrors = validateOwnershipPolicy(policy);
|
|
513
|
+
if (policyErrors.length > 0) throw new Error(`Ownership policy validation failed:\n- ${policyErrors.join("\n- ")}`);
|
|
514
|
+
const repository = policy.repositories[options.repositoryId];
|
|
515
|
+
if (!repository) throw new Error(`Ownership policy does not define repository ${options.repositoryId}`);
|
|
516
|
+
const lockPath = join(root, "package-lock.json");
|
|
517
|
+
if (!existsSync(lockPath)) throw new Error(`Ownership audit requires ${lockPath}`);
|
|
518
|
+
const lock = parseJson(lockPath);
|
|
519
|
+
if (lock.lockfileVersion !== 3 || !lock.packages || typeof lock.packages !== "object") {
|
|
520
|
+
throw new Error("Ownership audit requires an npm lockfileVersion 3 packages map");
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const components = [];
|
|
524
|
+
const violations = [];
|
|
525
|
+
const evidenceRoot = options.installation
|
|
526
|
+
? packageRootForInstallation(root, repository.label)
|
|
527
|
+
: options.repositoryId === "cli"
|
|
528
|
+
? join(root, "apps", "xeno-agent-cli")
|
|
529
|
+
: root;
|
|
530
|
+
for (const path of [
|
|
531
|
+
policy.cleanRoomProtocol.guide,
|
|
532
|
+
policy.cleanRoomProtocol.implementationRecordTemplate,
|
|
533
|
+
policy.cleanRoomProtocol.provenanceReviewTemplate,
|
|
534
|
+
]) {
|
|
535
|
+
if (!existsSync(join(evidenceRoot, path))) violations.push(`required clean-room evidence file is missing: ${path}`);
|
|
536
|
+
}
|
|
537
|
+
const seenDeclarations = new Set();
|
|
538
|
+
for (const [lockEntryPath, entry] of Object.entries(lock.packages)) {
|
|
539
|
+
if (entry.link === true) continue;
|
|
540
|
+
const name = packageNameFromLockPath(lockEntryPath, entry);
|
|
541
|
+
if (!name) continue;
|
|
542
|
+
if (options.installation && lockEntryPath === "") continue;
|
|
543
|
+
const scope = entry.dev === true ? "development" : entry.optional === true ? "runtime-optional" : "runtime";
|
|
544
|
+
const result = classify(policy, name, scope);
|
|
545
|
+
const component = {
|
|
546
|
+
id: `lock:${lockEntryPath || "."}`,
|
|
547
|
+
name,
|
|
548
|
+
version: entry.version,
|
|
549
|
+
license: entry.license,
|
|
550
|
+
scope,
|
|
551
|
+
classification: result.classification,
|
|
552
|
+
path: lockEntryPath || ".",
|
|
553
|
+
installed: lockEntryPath === "" ? true : existsSync(join(root, lockEntryPath)),
|
|
554
|
+
replacement: result.policy?.replacement,
|
|
555
|
+
expiresAtMilestone: result.policy?.expiresAtMilestone,
|
|
556
|
+
};
|
|
557
|
+
components.push(component);
|
|
558
|
+
seenDeclarations.add(`${scope}:${name}`);
|
|
559
|
+
if (component.classification === "unclassified" || component.classification === "forbidden") {
|
|
560
|
+
violations.push(`${name}${component.version ? `@${component.version}` : ""} is ${component.classification} in ${scope}`);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (!options.installation) {
|
|
565
|
+
for (const declaration of directDeclarations(root, repository)) {
|
|
566
|
+
const effectiveScope = declaration.scope === "peer" ? "peer" : declaration.scope;
|
|
567
|
+
if (seenDeclarations.has(`${effectiveScope}:${declaration.name}`)) continue;
|
|
568
|
+
const result = classify(policy, declaration.name, effectiveScope);
|
|
569
|
+
components.push({
|
|
570
|
+
id: `manifest:${declaration.manifestPath}:${declaration.field}:${declaration.name}`,
|
|
571
|
+
name: declaration.name,
|
|
572
|
+
requested: declaration.requested,
|
|
573
|
+
scope: effectiveScope,
|
|
574
|
+
classification: result.classification,
|
|
575
|
+
path: declaration.manifestPath,
|
|
576
|
+
installed: false,
|
|
577
|
+
replacement: result.policy?.replacement,
|
|
578
|
+
expiresAtMilestone: result.policy?.expiresAtMilestone,
|
|
579
|
+
});
|
|
580
|
+
if (result.classification === "unclassified" || result.classification === "forbidden") {
|
|
581
|
+
violations.push(`${declaration.name}@${declaration.requested} is ${result.classification} in ${effectiveScope}`);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
const sourceSeen = new Set();
|
|
586
|
+
for (const finding of collectSourceSpecifiers(root, repository.sourceRoots)) {
|
|
587
|
+
const key = `${finding.name}:${finding.path}`;
|
|
588
|
+
if (sourceSeen.has(key)) continue;
|
|
589
|
+
sourceSeen.add(key);
|
|
590
|
+
const result = classify(policy, finding.name, "source-import");
|
|
591
|
+
components.push({
|
|
592
|
+
id: `source:${finding.path}:${finding.name}`,
|
|
593
|
+
name: finding.name,
|
|
594
|
+
specifier: finding.specifier,
|
|
595
|
+
scope: "source-import",
|
|
596
|
+
classification: result.classification,
|
|
597
|
+
path: finding.path,
|
|
598
|
+
installed: undefined,
|
|
599
|
+
replacement: result.policy?.replacement,
|
|
600
|
+
expiresAtMilestone: result.policy?.expiresAtMilestone,
|
|
601
|
+
});
|
|
602
|
+
if (result.classification === "unclassified" || result.classification === "forbidden") {
|
|
603
|
+
violations.push(`${finding.specifier} is ${result.classification} in source ${finding.path}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
let artifactEvidence = { enabled: false, bundleMetafiles: 0, nativeArtifacts: 0 };
|
|
609
|
+
if (options.artifacts) {
|
|
610
|
+
const artifacts = collectArtifactComponents(root, options.repositoryId, repository, policy, options.installation);
|
|
611
|
+
components.push(...artifacts.components);
|
|
612
|
+
violations.push(...artifacts.violations);
|
|
613
|
+
artifactEvidence = {
|
|
614
|
+
enabled: true,
|
|
615
|
+
bundleMetafiles: artifacts.bundleMetafiles,
|
|
616
|
+
nativeArtifacts: artifacts.nativeArtifacts,
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
for (const builtin of policy.builtinComponents) {
|
|
621
|
+
if (!builtin.usedBy.includes(options.repositoryId)) continue;
|
|
622
|
+
components.push({
|
|
623
|
+
id: `builtin:${builtin.name}`,
|
|
624
|
+
name: builtin.name,
|
|
625
|
+
scope: "builtin",
|
|
626
|
+
classification: builtin.classification,
|
|
627
|
+
replacement: builtin.replacement,
|
|
628
|
+
expiresAtMilestone: builtin.expiresAtMilestone,
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
for (const boundary of policy.platformBoundaries) {
|
|
632
|
+
if (!boundary.usedBy.includes(options.repositoryId)) continue;
|
|
633
|
+
components.push({
|
|
634
|
+
id: `platform:${boundary.name}`,
|
|
635
|
+
name: boundary.name,
|
|
636
|
+
scope: "platform",
|
|
637
|
+
classification: boundary.classification,
|
|
638
|
+
replacement: boundary.replacement,
|
|
639
|
+
expiresAtMilestone: boundary.expiresAtMilestone,
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const uniqueViolations = [...new Set(violations)].sort();
|
|
644
|
+
const achievedLevel = determineAchievedLevel(policy, components, uniqueViolations);
|
|
645
|
+
if (LEVELS.indexOf(achievedLevel) < LEVELS.indexOf(policy.enforcedLevel)) {
|
|
646
|
+
uniqueViolations.push(`achieved level ${achievedLevel} is below enforced level ${policy.enforcedLevel}`);
|
|
647
|
+
}
|
|
648
|
+
const report = {
|
|
649
|
+
generatedAt: new Date().toISOString(),
|
|
650
|
+
repository: { id: options.repositoryId, label: repository.label, root },
|
|
651
|
+
policy: {
|
|
652
|
+
id: policy.policyId,
|
|
653
|
+
revision: policy.policyRevision,
|
|
654
|
+
sha256: sha256(policyText),
|
|
655
|
+
canonicalLocation: policy.canonicalLocation,
|
|
656
|
+
enforcedLevel: policy.enforcedLevel,
|
|
657
|
+
targetLevel: policy.targetLevel,
|
|
658
|
+
},
|
|
659
|
+
achievedLevel,
|
|
660
|
+
countsByScope: summarizeCounts(components, "scope"),
|
|
661
|
+
countsByClassification: summarizeCounts(components, "classification"),
|
|
662
|
+
violations: uniqueViolations,
|
|
663
|
+
capabilityGates: policy.capabilityGates,
|
|
664
|
+
artifactEvidence,
|
|
665
|
+
components: components.sort((left, right) => left.scope.localeCompare(right.scope) || left.name.localeCompare(right.name) || left.id.localeCompare(right.id)),
|
|
666
|
+
};
|
|
667
|
+
|
|
668
|
+
if (options.write) {
|
|
669
|
+
const reportDirectory = join(root, repository.reportDirectory);
|
|
670
|
+
mkdirSync(reportDirectory, { recursive: true });
|
|
671
|
+
writeFileSync(join(reportDirectory, "ownership-inventory.json"), `${JSON.stringify(report, null, 2)}\n`, "utf8");
|
|
672
|
+
writeFileSync(join(reportDirectory, "ownership-inventory.md"), renderMarkdown(report), "utf8");
|
|
673
|
+
for (const definition of REPORT_PARTITIONS) {
|
|
674
|
+
const partition = partitionReport(report, definition);
|
|
675
|
+
writeFileSync(join(reportDirectory, `ownership-${definition.id}.json`), `${JSON.stringify(partition, null, 2)}\n`, "utf8");
|
|
676
|
+
writeFileSync(join(reportDirectory, `ownership-${definition.id}.md`), renderPartitionMarkdown(partition), "utf8");
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
return report;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function parseArguments(argv) {
|
|
683
|
+
const options = {
|
|
684
|
+
root: process.cwd(),
|
|
685
|
+
repositoryId: undefined,
|
|
686
|
+
policyPath: join(dirname(fileURLToPath(import.meta.url)), "ownership-policy.json"),
|
|
687
|
+
write: false,
|
|
688
|
+
installation: false,
|
|
689
|
+
json: false,
|
|
690
|
+
artifacts: false,
|
|
691
|
+
};
|
|
692
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
693
|
+
const arg = argv[index];
|
|
694
|
+
if (arg === "--repo") options.repositoryId = argv[++index];
|
|
695
|
+
else if (arg === "--root") options.root = argv[++index];
|
|
696
|
+
else if (arg === "--policy") options.policyPath = argv[++index];
|
|
697
|
+
else if (arg === "--write") options.write = true;
|
|
698
|
+
else if (arg === "--installation") options.installation = true;
|
|
699
|
+
else if (arg === "--json") options.json = true;
|
|
700
|
+
else if (arg === "--artifacts") options.artifacts = true;
|
|
701
|
+
else throw new Error(`Unknown ownership audit argument: ${arg}`);
|
|
702
|
+
}
|
|
703
|
+
if (!options.repositoryId) throw new Error("Usage: node ownership/audit.mjs --repo <sdk|cli> [--root path] [--write] [--installation] [--artifacts] [--json]");
|
|
704
|
+
return options;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
async function main() {
|
|
708
|
+
const options = parseArguments(process.argv.slice(2));
|
|
709
|
+
const report = auditOwnership(options);
|
|
710
|
+
if (options.json) process.stdout.write(`${JSON.stringify(report)}\n`);
|
|
711
|
+
else {
|
|
712
|
+
console.log(
|
|
713
|
+
`Ownership audit: ${report.repository.label} achieved ${report.achievedLevel}; ` +
|
|
714
|
+
`target ${report.policy.targetLevel}; ${report.components.length} component records; ` +
|
|
715
|
+
`${report.violations.length} violation(s).`,
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
if (report.violations.length > 0) process.exitCode = 1;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
const invokedPath = process.argv[1] ? pathToFileURL(resolve(process.argv[1])).href : undefined;
|
|
722
|
+
if (invokedPath === import.meta.url) {
|
|
723
|
+
main().catch((error) => {
|
|
724
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
725
|
+
process.exitCode = 1;
|
|
726
|
+
});
|
|
727
|
+
}
|