@numa-tech/numa 1.13.1 → 1.13.2

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.
Files changed (38) hide show
  1. package/README.md +59 -5
  2. package/dist/application-onboarding/client.d.ts +37 -3
  3. package/dist/application-onboarding/client.js +31 -2
  4. package/dist/application-onboarding/client.js.map +1 -1
  5. package/dist/application-onboarding/commands.d.ts +2 -0
  6. package/dist/application-onboarding/commands.js +202 -6
  7. package/dist/application-onboarding/commands.js.map +1 -1
  8. package/dist/application-onboarding/schemas.d.ts +772 -0
  9. package/dist/application-onboarding/schemas.js +315 -3
  10. package/dist/application-onboarding/schemas.js.map +1 -1
  11. package/dist/cli.js +6 -1
  12. package/dist/cli.js.map +1 -1
  13. package/dist/command-catalog.js +154 -2
  14. package/dist/command-catalog.js.map +1 -1
  15. package/dist/gitops/schemas.js +2 -1
  16. package/dist/gitops/schemas.js.map +1 -1
  17. package/dist/jenkins-jobs/client.d.ts +319 -0
  18. package/dist/jenkins-jobs/client.js +136 -0
  19. package/dist/jenkins-jobs/client.js.map +1 -0
  20. package/dist/jenkins-jobs/commands.d.ts +6 -0
  21. package/dist/jenkins-jobs/commands.js +239 -0
  22. package/dist/jenkins-jobs/commands.js.map +1 -0
  23. package/dist/jenkins-jobs/schemas.d.ts +359 -0
  24. package/dist/jenkins-jobs/schemas.js +119 -0
  25. package/dist/jenkins-jobs/schemas.js.map +1 -0
  26. package/dist/publications/client.d.ts +181 -0
  27. package/dist/publications/client.js +147 -0
  28. package/dist/publications/client.js.map +1 -0
  29. package/dist/publications/commands.d.ts +8 -0
  30. package/dist/publications/commands.js +202 -0
  31. package/dist/publications/commands.js.map +1 -0
  32. package/dist/publications/scanner.d.ts +23 -0
  33. package/dist/publications/scanner.js +247 -0
  34. package/dist/publications/scanner.js.map +1 -0
  35. package/dist/publications/schemas.d.ts +164 -0
  36. package/dist/publications/schemas.js +90 -0
  37. package/dist/publications/schemas.js.map +1 -0
  38. package/package.json +4 -4
@@ -0,0 +1,202 @@
1
+ import process from "node:process";
2
+ import { loadAppConfig } from "../app-config.js";
3
+ import { loadConfig } from "../config.js";
4
+ import { RepositoryError, sanitizeRepositoryOutput } from "../repositories/errors.js";
5
+ import { ProjectPublicationClient } from "./client.js";
6
+ import { publicationScanSummary, scanProjectPublication } from "./scanner.js";
7
+ const SAFE_IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:+%~-]*$/u;
8
+ const SAFE_REQUEST_ID = /^[A-Za-z0-9][A-Za-z0-9._:/+-]*$/u;
9
+ const PLAN_HASH = /^[0-9a-f]{64}$/u;
10
+ function stableIdentifier(value, label) {
11
+ const trimmed = value?.trim() ?? "";
12
+ if (!trimmed || trimmed.length > 256 || !SAFE_IDENTIFIER.test(trimmed) || /%(?![0-9A-Fa-f]{2})/u.test(trimmed)) {
13
+ throw new RepositoryError(`${label} must be a stable identifier.`, "PUBLICATION_CLI_INPUT_INVALID");
14
+ }
15
+ return trimmed;
16
+ }
17
+ function requestId(value, label) {
18
+ const trimmed = value?.trim() ?? "";
19
+ if (!trimmed || trimmed.length > 200 || !SAFE_REQUEST_ID.test(trimmed)) {
20
+ throw new RepositoryError(`${label} must be 1-200 safe opaque characters.`, "PUBLICATION_IDEMPOTENCY_INVALID");
21
+ }
22
+ return trimmed;
23
+ }
24
+ function planHash(value) {
25
+ const trimmed = value?.trim() ?? "";
26
+ if (!PLAN_HASH.test(trimmed)) {
27
+ throw new RepositoryError("plan-hash must be the exact lower-case SHA-256 returned by the server.", "PUBLICATION_PLAN_HASH_MISMATCH");
28
+ }
29
+ return trimmed;
30
+ }
31
+ function integer(value, label, fallback, maximum) {
32
+ if (value == null)
33
+ return fallback;
34
+ const parsed = Number(value);
35
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed > maximum) {
36
+ throw new RepositoryError(`${label} must be an integer between 0 and ${maximum}.`, "PUBLICATION_CLI_INPUT_INVALID");
37
+ }
38
+ return parsed;
39
+ }
40
+ function requireYes(value) {
41
+ if (!value) {
42
+ throw new RepositoryError("Mutation requires --yes after reviewing the immutable publication plan.", "PUBLICATION_CONFIRMATION_REQUIRED");
43
+ }
44
+ }
45
+ function snakeCase(key) {
46
+ return key.replace(/([a-z0-9])([A-Z])/gu, "$1_$2").toLowerCase();
47
+ }
48
+ function stableOutput(value) {
49
+ const safe = sanitizeRepositoryOutput(value);
50
+ if (Array.isArray(safe))
51
+ return safe.map(stableOutput);
52
+ if (safe && typeof safe === "object") {
53
+ return Object.fromEntries(Object.entries(safe).map(([key, item]) => [snakeCase(key), stableOutput(item)]));
54
+ }
55
+ return safe;
56
+ }
57
+ async function jsonEnabled(command) {
58
+ const configured = await loadAppConfig();
59
+ return Boolean(command.optsWithGlobals().json || configured.output === "json");
60
+ }
61
+ async function output(command, payload, textValue) {
62
+ if (await jsonEnabled(command))
63
+ process.stdout.write(`${JSON.stringify(stableOutput(payload), null, 2)}\n`);
64
+ else
65
+ process.stdout.write(`${String(sanitizeRepositoryOutput(textValue))}\n`);
66
+ }
67
+ function addExamples(command, examples, notes = []) {
68
+ const noteSection = notes.length ? `\n说明:\n${notes.map((item) => ` - ${item}`).join("\n")}\n` : "";
69
+ return command.addHelpText("after", `${noteSection}\nExamples:\n${examples.map((item) => ` ${item}`).join("\n")}\n`);
70
+ }
71
+ function runLine(run) {
72
+ return `${String(run.runNo ?? "-")}\t${String(run.state ?? "UNKNOWN")}\t${String(run.stepCode ?? "-")}\t${String(run.errorCode ?? "-")}`;
73
+ }
74
+ export function registerPublicationCommands(program, dependencies = {}) {
75
+ const client = () => dependencies.clientFactory?.() ?? new ProjectPublicationClient(loadConfig());
76
+ const scan = dependencies.scan ?? scanProjectPublication;
77
+ const publication = program.command("publication")
78
+ .description("通过 Project Publication Control Plane 发布已有本地 Git 历史")
79
+ .addHelpText("after", `
80
+ 安全边界:
81
+ scan 只读取 clean Git HEAD 的 index/tree,不读取未跟踪文件,也不输出文件内容。
82
+ plan 把受限 UTF-8 bundle 发送给 DevOps;SCM credential 只由服务端解析。
83
+ apply 使用不可变 planHash 与 Idempotency-Key;不会触发 Jenkins build 或部署。
84
+ `);
85
+ addExamples(publication.command("scan")
86
+ .description("本地只读扫描 clean Git tree,输出无内容的 manifest/digest")
87
+ .option("--source <directory>", "Git worktree 根目录", ".")
88
+ .action(async (options, command) => {
89
+ const result = await scan(options.source);
90
+ const safe = publicationScanSummary(result);
91
+ await output(command, { ok: true, scan: safe }, `${safe.sourceRevision}\t${safe.sourceTreeDigest}\t${safe.fileCount} files\t${safe.totalBytes} bytes`);
92
+ }), ["numa publication scan --source ./code-index --json"], [
93
+ "DIRTY_WORKTREE、symlink/special file、凭据路径、非 UTF-8、NUL 或超限内容会 fail-closed。"
94
+ ]);
95
+ const plan = publication.command("plan").description("创建绑定本地 tree digest 的不可变 publication plan");
96
+ addExamples(plan.command("create")
97
+ .description("扫描 clean HEAD 并创建服务端计划;不写远端 Git")
98
+ .requiredOption("--source <directory>", "Git worktree 根目录")
99
+ .requiredOption("--repository-key <key>", "已由 Repository Control Plane 管理的仓库")
100
+ .requiredOption("--commit-message <message>", "受审提交消息,1-500字符")
101
+ .requiredOption("--client-request-id <id>", "稳定请求 ID")
102
+ .requiredOption("--idempotency-key <key>", "必须与 client-request-id 完全相同")
103
+ .action(async (options, command) => {
104
+ const clientRequestId = requestId(options.clientRequestId, "client-request-id");
105
+ const idempotencyKey = requestId(options.idempotencyKey, "idempotency-key");
106
+ if (clientRequestId !== idempotencyKey) {
107
+ throw new RepositoryError("idempotency-key must exactly match client-request-id.", "PUBLICATION_IDEMPOTENCY_INVALID");
108
+ }
109
+ const commitMessage = options.commitMessage.trim();
110
+ if (!commitMessage || commitMessage.length > 500 || /[\u0000-\u001f\u007f]/u.test(commitMessage)) {
111
+ throw new RepositoryError("commit-message must be 1-500 printable characters.", "PUBLICATION_CLI_INPUT_INVALID");
112
+ }
113
+ const source = await scan(options.source);
114
+ const result = await client().createPlan({
115
+ clientRequestId,
116
+ repositoryKey: stableIdentifier(options.repositoryKey, "repository-key"),
117
+ sourceRevision: source.sourceRevision,
118
+ sourceTreeDigest: source.sourceTreeDigest,
119
+ clean: true,
120
+ commitMessage,
121
+ files: source.requestFiles
122
+ }, idempotencyKey);
123
+ await output(command, { ok: true, plan: result }, `${result.planNo}\t${result.state}\t${result.planHash}\t${result.blockers.length} blocker(s)`);
124
+ }), [
125
+ "numa publication plan create --source ./code-index --repository-key codeup-numa:143926:code-index --commit-message 'feat: publish code-index source' --client-request-id publish-code-index-d510f0f6 --idempotency-key publish-code-index-d510f0f6 --json"
126
+ ], ["请求会携带受限 bundle,但 CLI 输出和错误不会回显 contentBase64。"]);
127
+ addExamples(plan.command("get")
128
+ .description("读取不可变 publication plan")
129
+ .argument("<plan-no>", "plan number")
130
+ .action(async (identifier, _options, command) => {
131
+ const result = await client().getPlan(stableIdentifier(identifier, "plan-no"));
132
+ await output(command, { ok: true, plan: result }, `${result.planNo}\t${result.state}\t${result.planHash}`);
133
+ }), ["numa publication plan get ppub_01 --json"]);
134
+ addExamples(publication.command("apply")
135
+ .description("显式执行已审阅 plan;不触发 build/deploy")
136
+ .requiredOption("--plan-no <number>", "服务端 plan 编号")
137
+ .requiredOption("--plan-hash <hash>", "服务端返回的精确 plan hash")
138
+ .requiredOption("--client-request-id <id>", "稳定请求 ID")
139
+ .requiredOption("--idempotency-key <key>", "必须与 client-request-id 完全相同")
140
+ .option("--yes", "确认写入远端 Git")
141
+ .action(async (options, command) => {
142
+ requireYes(options.yes);
143
+ const clientRequestId = requestId(options.clientRequestId, "client-request-id");
144
+ const idempotencyKey = requestId(options.idempotencyKey, "idempotency-key");
145
+ if (clientRequestId !== idempotencyKey) {
146
+ throw new RepositoryError("idempotency-key must exactly match client-request-id.", "PUBLICATION_IDEMPOTENCY_INVALID");
147
+ }
148
+ const planNo = stableIdentifier(options.planNo, "plan-no");
149
+ const expectedHash = planHash(options.planHash);
150
+ const current = await client().getPlan(planNo);
151
+ if (current.planHash !== expectedHash) {
152
+ throw new RepositoryError("The supplied plan-hash does not match the current server plan.", "PUBLICATION_PLAN_HASH_MISMATCH");
153
+ }
154
+ if (current.state !== "READY" || current.blockers.length > 0) {
155
+ throw new RepositoryError("The publication plan is not READY or contains blockers.", "PUBLICATION_PLAN_NOT_READY", undefined, undefined, current.blockers);
156
+ }
157
+ const result = await client().createRun({ planNo, planHash: expectedHash, clientRequestId }, idempotencyKey);
158
+ await output(command, { ok: true, run: result }, runLine(result));
159
+ }), [
160
+ "numa publication apply --plan-no ppub_01 --plan-hash <64hex> --client-request-id publish-code-index-d510f0f6 --idempotency-key publish-code-index-d510f0f6 --yes --json"
161
+ ]);
162
+ addExamples(publication.command("status")
163
+ .description("按 runNo 或原 clientRequestId 查询/恢复 publication run")
164
+ .argument("[run-no]", "run number")
165
+ .option("--client-request-id <id>", "结果未知时使用原稳定请求 ID")
166
+ .action(async (runNo, options, command) => {
167
+ if (Boolean(runNo) === Boolean(options.clientRequestId)) {
168
+ throw new RepositoryError("Provide exactly one of run-no or --client-request-id.", "PUBLICATION_CLI_INPUT_INVALID");
169
+ }
170
+ const result = runNo
171
+ ? await client().getRun(stableIdentifier(runNo, "run-no"))
172
+ : await client().resolveRun(requestId(options.clientRequestId, "client-request-id"));
173
+ await output(command, { ok: true, run: result }, runLine(result));
174
+ }), [
175
+ "numa publication status ppubrun_01 --json",
176
+ "numa publication status --client-request-id publish-code-index-d510f0f6 --json"
177
+ ]);
178
+ addExamples(publication.command("events")
179
+ .description("按单调 sequence 查询 publication 运行事件")
180
+ .argument("<run-no>", "run number")
181
+ .option("--after-sequence <number>", "只返回该 sequence 之后的事件", "0")
182
+ .option("--limit <number>", "1-200", "100")
183
+ .action(async (runNo, options, command) => {
184
+ const result = await client().events(stableIdentifier(runNo, "run-no"), integer(options.afterSequence, "after-sequence", 0, Number.MAX_SAFE_INTEGER), integer(options.limit, "limit", 100, 200));
185
+ await output(command, { ok: true, events: result }, result.items.map((event) => `${event.sequenceNo}\t${event.eventType}\t${event.state ?? "-"}`).join("\n") || "没有新事件");
186
+ }), ["numa publication events ppubrun_01 --after-sequence 0 --json"]);
187
+ for (const action of ["retry", "reconcile"]) {
188
+ addExamples(publication.command(action)
189
+ .description(action === "retry" ? "重试服务端判定可恢复的 publication run" : "调和结果未知或崩溃窗口中的 publication run")
190
+ .argument("<run-no>", "run number")
191
+ .requiredOption("--idempotency-key <key>", "稳定恢复请求 ID")
192
+ .option("--yes", "确认恢复动作")
193
+ .action(async (runNo, options, command) => {
194
+ requireYes(options.yes);
195
+ const result = action === "retry"
196
+ ? await client().retry(stableIdentifier(runNo, "run-no"), requestId(options.idempotencyKey, "idempotency-key"))
197
+ : await client().reconcile(stableIdentifier(runNo, "run-no"), requestId(options.idempotencyKey, "idempotency-key"));
198
+ await output(command, { ok: true, run: result }, runLine(result));
199
+ }), [`numa publication ${action} ppubrun_01 --idempotency-key ${action}-ppubrun-01 --yes --json`]);
200
+ }
201
+ }
202
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/publications/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { PublicationPlanRequest } from "./schemas.js";
2
+ export declare const PUBLICATION_MAX_FILES = 1024;
3
+ export declare const PUBLICATION_MAX_FILE_BYTES: number;
4
+ export declare const PUBLICATION_MAX_TOTAL_BYTES: number;
5
+ export interface PublicationScanResult {
6
+ schemaVersion: 1;
7
+ sourceRoot: string;
8
+ sourceRevision: string;
9
+ sourceTreeDigest: string;
10
+ clean: true;
11
+ fileCount: number;
12
+ totalBytes: number;
13
+ executableFileCount: number;
14
+ manifest: Array<{
15
+ path: string;
16
+ mode: "100644" | "100755";
17
+ size: number;
18
+ sha256: string;
19
+ }>;
20
+ requestFiles: PublicationPlanRequest["files"];
21
+ }
22
+ export declare function scanProjectPublication(sourceDirectory: string): Promise<PublicationScanResult>;
23
+ export declare function publicationScanSummary(scan: PublicationScanResult): Omit<PublicationScanResult, "requestFiles" | "sourceRoot">;
@@ -0,0 +1,247 @@
1
+ import { execFile, spawn } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import { realpath } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { RepositoryError } from "../repositories/errors.js";
6
+ export const PUBLICATION_MAX_FILES = 1024;
7
+ export const PUBLICATION_MAX_FILE_BYTES = 1024 * 1024;
8
+ export const PUBLICATION_MAX_TOTAL_BYTES = 8 * 1024 * 1024;
9
+ function publicationFailure(message, code, details) {
10
+ throw new RepositoryError(message, code, undefined, undefined, details);
11
+ }
12
+ function runGitBuffer(root, args, maxBuffer = PUBLICATION_MAX_FILE_BYTES + 4096) {
13
+ return new Promise((resolve, reject) => {
14
+ execFile("git", ["-C", root, ...args], { encoding: "buffer", maxBuffer }, (error, stdout, stderr) => {
15
+ if (error) {
16
+ const safe = Buffer.isBuffer(stderr) ? stderr.toString("utf8").trim().slice(0, 500) : "";
17
+ reject(new RepositoryError(safe ? `Git inspection failed: ${safe}` : "Git inspection failed.", "PUBLICATION_GIT_INSPECTION_FAILED"));
18
+ return;
19
+ }
20
+ resolve(Buffer.isBuffer(stdout) ? stdout : Buffer.from(stdout));
21
+ });
22
+ });
23
+ }
24
+ async function runGitText(root, args, maxBuffer = 1024 * 1024) {
25
+ return (await runGitBuffer(root, args, maxBuffer)).toString("utf8");
26
+ }
27
+ function normalizedPath(raw) {
28
+ const value = raw.normalize("NFC");
29
+ if (!value || value !== raw || value.includes("\\") || value.startsWith("/") || value.includes("\0") || /[\u0000-\u001f\u007f]/u.test(value)) {
30
+ return publicationFailure("Publication contains a non-canonical path.", "PUBLICATION_PATH_REJECTED", { path: raw });
31
+ }
32
+ const segments = value.split("/");
33
+ if (segments.some((segment) => !segment || segment === "." || segment === ".." || segment.toLowerCase() === ".git")) {
34
+ return publicationFailure("Publication contains a forbidden path segment.", "PUBLICATION_PATH_REJECTED", { path: value });
35
+ }
36
+ return value;
37
+ }
38
+ function rejectsSensitivePath(filePath) {
39
+ const base = path.posix.basename(filePath).toLowerCase();
40
+ if (base === ".env")
41
+ return true;
42
+ if (base.startsWith(".env.") && !/^\.env\.(?:example|sample|template)$/u.test(base))
43
+ return true;
44
+ if (/^(?:id_rsa|id_dsa|id_ecdsa|id_ed25519)$/u.test(base))
45
+ return true;
46
+ if (/\.(?:pem|key|p12|pfx|jks|keystore)$/u.test(base))
47
+ return true;
48
+ if (/^(?:credentials|docker-config\.json|\.npmrc|\.pypirc)$/u.test(base))
49
+ return true;
50
+ return filePath.toLowerCase() === ".docker/config.json";
51
+ }
52
+ function parseTree(raw) {
53
+ const entries = [];
54
+ const folded = new Map();
55
+ for (const record of raw.toString("utf8").split("\0")) {
56
+ if (!record)
57
+ continue;
58
+ const match = /^(\d+) (\S+) ([0-9a-f]{40,64})\t(.+)$/u.exec(record);
59
+ if (!match)
60
+ publicationFailure("Git returned an invalid tree entry.", "PUBLICATION_FILE_TYPE_REJECTED");
61
+ const [, rawMode, type, objectId, rawPath] = match;
62
+ if (type !== "blob" || (rawMode !== "100644" && rawMode !== "100755")) {
63
+ publicationFailure("Publication supports only regular 100644 and 100755 Git blobs.", "PUBLICATION_FILE_TYPE_REJECTED", {
64
+ path: rawPath, mode: rawMode, type
65
+ });
66
+ }
67
+ const safePath = normalizedPath(rawPath);
68
+ if (rejectsSensitivePath(safePath)) {
69
+ publicationFailure("Publication contains a credential-like file path.", "PUBLICATION_SECRET_REJECTED", { path: safePath });
70
+ }
71
+ const caseKey = safePath.toLocaleLowerCase("en-US");
72
+ const previous = folded.get(caseKey);
73
+ if (previous && previous !== safePath) {
74
+ publicationFailure("Publication contains case-folding path collisions.", "PUBLICATION_PATH_REJECTED", {
75
+ paths: [previous, safePath]
76
+ });
77
+ }
78
+ folded.set(caseKey, safePath);
79
+ entries.push({ mode: rawMode, objectId, path: safePath });
80
+ }
81
+ entries.sort((left, right) => left.path < right.path ? -1 : left.path > right.path ? 1 : 0);
82
+ if (entries.length < 1 || entries.length > PUBLICATION_MAX_FILES) {
83
+ publicationFailure(`Publication must contain 1-${PUBLICATION_MAX_FILES} tracked files.`, "PUBLICATION_BUNDLE_LIMIT_EXCEEDED", { fileCount: entries.length });
84
+ }
85
+ return entries;
86
+ }
87
+ function utf8RoundTrip(content) {
88
+ if (content.includes(0))
89
+ return false;
90
+ const decoded = content.toString("utf8");
91
+ return Buffer.from(decoded, "utf8").equals(content);
92
+ }
93
+ function placeholderValue(raw) {
94
+ let value = raw.trim().replace(/[,;]$/u, "").trim();
95
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
96
+ value = value.slice(1, -1).trim();
97
+ }
98
+ const normalized = value.toLowerCase();
99
+ if (["", "null", "none", "blank"].includes(normalized))
100
+ return true;
101
+ return ["${", "$(", "{{", "<", "[", "example", "sample", "test", "dummy", "redacted", "changeme", "xxx", "your_", "replace", "never-print", "not-a-real", "fixture", "sentinel"]
102
+ .some((prefix) => normalized.startsWith(prefix));
103
+ }
104
+ function containsConcreteSecret(filePath, content) {
105
+ const text = content.toString("utf8");
106
+ if (/-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/u.test(text))
107
+ return true;
108
+ if (/\bgh[pousr]_[A-Za-z0-9_]{20,}/u.test(text))
109
+ return true;
110
+ if (/\bLTAI[A-Za-z0-9]{12,}/u.test(text))
111
+ return true;
112
+ if (/(?:^|[^A-Za-z0-9_-])eyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}(?:$|[^A-Za-z0-9_-])/u.test(text))
113
+ return true;
114
+ const assignment = /^\s*["']?(?:password|passwd|client_secret|access_token|refresh_token|api_key|access_key|secret_key|token)["']?\s*[:=]\s*(.*?)\s*$/iu;
115
+ const configLike = /(?:^|\/)\.env(?:\.[^/]+)?$/iu.test(filePath)
116
+ || /\.(?:conf|ini|properties|toml|yaml|yml)$/iu.test(filePath);
117
+ if (!configLike)
118
+ return false;
119
+ return text.split(/\r?\n/u).some((line) => {
120
+ const match = assignment.exec(line);
121
+ if (!match)
122
+ return false;
123
+ let value = match[1] ?? "";
124
+ value = value.trim().replace(/[,;]$/u, "").trim();
125
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
126
+ value = value.slice(1, -1).trim();
127
+ }
128
+ return value.length >= 6 && !placeholderValue(value);
129
+ });
130
+ }
131
+ function readBlobs(root, entries) {
132
+ return new Promise((resolve, reject) => {
133
+ const child = spawn("git", ["-C", root, "cat-file", "--batch"], { stdio: ["pipe", "pipe", "pipe"] });
134
+ const stdout = [];
135
+ const stderr = [];
136
+ let stdoutBytes = 0;
137
+ child.stdout.on("data", (chunk) => {
138
+ stdoutBytes += chunk.length;
139
+ if (stdoutBytes > PUBLICATION_MAX_TOTAL_BYTES + PUBLICATION_MAX_FILES * 128) {
140
+ child.kill();
141
+ return;
142
+ }
143
+ stdout.push(chunk);
144
+ });
145
+ child.stderr.on("data", (chunk) => {
146
+ if (stderr.reduce((size, item) => size + item.length, 0) < 4096)
147
+ stderr.push(chunk);
148
+ });
149
+ child.once("error", () => reject(new RepositoryError("Git blob inspection failed.", "PUBLICATION_GIT_INSPECTION_FAILED")));
150
+ child.once("close", (code) => {
151
+ if (code !== 0) {
152
+ reject(new RepositoryError(`Git blob inspection failed${stderr.length ? `: ${Buffer.concat(stderr).toString("utf8").trim().slice(0, 500)}` : "."}`, stdoutBytes > PUBLICATION_MAX_TOTAL_BYTES + PUBLICATION_MAX_FILES * 128
153
+ ? "PUBLICATION_BUNDLE_LIMIT_EXCEEDED" : "PUBLICATION_GIT_INSPECTION_FAILED"));
154
+ return;
155
+ }
156
+ try {
157
+ const batch = Buffer.concat(stdout);
158
+ const contents = [];
159
+ let offset = 0;
160
+ for (const entry of entries) {
161
+ const newline = batch.indexOf(0x0a, offset);
162
+ if (newline < 0)
163
+ publicationFailure("Git returned an incomplete blob header.", "PUBLICATION_GIT_INSPECTION_FAILED");
164
+ const header = batch.subarray(offset, newline).toString("ascii");
165
+ const match = /^([0-9a-f]{40,64}) blob (\d+)$/u.exec(header);
166
+ if (!match || match[1] !== entry.objectId) {
167
+ publicationFailure("Git returned a mismatched blob identity.", "PUBLICATION_GIT_INSPECTION_FAILED", { path: entry.path });
168
+ }
169
+ const size = Number(match[2]);
170
+ const start = newline + 1;
171
+ const end = start + size;
172
+ if (!Number.isSafeInteger(size) || end >= batch.length || batch[end] !== 0x0a) {
173
+ publicationFailure("Git returned an invalid blob frame.", "PUBLICATION_GIT_INSPECTION_FAILED", { path: entry.path });
174
+ }
175
+ contents.push(batch.subarray(start, end));
176
+ offset = end + 1;
177
+ }
178
+ if (offset !== batch.length)
179
+ publicationFailure("Git returned unexpected blob data.", "PUBLICATION_GIT_INSPECTION_FAILED");
180
+ resolve(contents);
181
+ }
182
+ catch (error) {
183
+ reject(error);
184
+ }
185
+ });
186
+ child.stdin.end(`${entries.map((entry) => entry.objectId).join("\n")}\n`, "ascii");
187
+ });
188
+ }
189
+ export async function scanProjectPublication(sourceDirectory) {
190
+ const requestedRoot = await realpath(path.resolve(sourceDirectory));
191
+ const topLevel = (await runGitText(requestedRoot, ["rev-parse", "--show-toplevel"])).trim();
192
+ const sourceRoot = await realpath(topLevel);
193
+ if (sourceRoot !== requestedRoot) {
194
+ publicationFailure("Publication source must be the Git worktree root.", "PUBLICATION_PATH_REJECTED", {
195
+ requestedRoot, sourceRoot
196
+ });
197
+ }
198
+ const dirty = await runGitBuffer(sourceRoot, ["status", "--porcelain=v1", "-z", "--untracked-files=all"], 8 * 1024 * 1024);
199
+ if (dirty.length > 0) {
200
+ publicationFailure("The Git worktree is dirty. Commit the intended source explicitly, then create a fresh publication plan.", "PUBLICATION_SOURCE_DIRTY");
201
+ }
202
+ const sourceRevision = (await runGitText(sourceRoot, ["rev-parse", "HEAD"])).trim().toLowerCase();
203
+ if (!/^[0-9a-f]{40,64}$/u.test(sourceRevision)) {
204
+ publicationFailure("Git HEAD is not a supported immutable revision.", "PUBLICATION_GIT_INSPECTION_FAILED");
205
+ }
206
+ const entries = parseTree(await runGitBuffer(sourceRoot, ["ls-tree", "-r", "-z", "--full-tree", sourceRevision], 16 * 1024 * 1024));
207
+ const blobs = await readBlobs(sourceRoot, entries);
208
+ const manifest = [];
209
+ const requestFiles = [];
210
+ let totalBytes = 0;
211
+ for (const [index, entry] of entries.entries()) {
212
+ const content = blobs[index];
213
+ if (!content || content.length > PUBLICATION_MAX_FILE_BYTES || !utf8RoundTrip(content)) {
214
+ publicationFailure("Publication files must be UTF-8 text without NUL and within the per-file limit.", "PUBLICATION_CONTENT_REJECTED", { path: entry.path, size: content?.length ?? null });
215
+ }
216
+ if (containsConcreteSecret(entry.path, content)) {
217
+ publicationFailure("Publication contains content matching a concrete credential pattern.", "PUBLICATION_SECRET_REJECTED", { path: entry.path });
218
+ }
219
+ totalBytes += content.length;
220
+ if (totalBytes > PUBLICATION_MAX_TOTAL_BYTES) {
221
+ publicationFailure("Publication exceeds the total decoded bundle limit.", "PUBLICATION_BUNDLE_LIMIT_EXCEEDED", {
222
+ totalBytes, maximum: PUBLICATION_MAX_TOTAL_BYTES
223
+ });
224
+ }
225
+ const sha256 = createHash("sha256").update(content).digest("hex");
226
+ manifest.push({ path: entry.path, mode: entry.mode, size: content.length, sha256 });
227
+ requestFiles.push({ path: entry.path, mode: entry.mode, contentBase64: content.toString("base64") });
228
+ }
229
+ const sourceTreeDigest = createHash("sha256").update(JSON.stringify(manifest), "utf8").digest("hex");
230
+ return {
231
+ schemaVersion: 1,
232
+ sourceRoot,
233
+ sourceRevision,
234
+ sourceTreeDigest,
235
+ clean: true,
236
+ fileCount: manifest.length,
237
+ totalBytes,
238
+ executableFileCount: manifest.filter((entry) => entry.mode === "100755").length,
239
+ manifest,
240
+ requestFiles
241
+ };
242
+ }
243
+ export function publicationScanSummary(scan) {
244
+ const { requestFiles: _files, sourceRoot: _root, ...safe } = scan;
245
+ return safe;
246
+ }
247
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/publications/scanner.ts"],"names":[],"mappings":"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"}