@actiondock/core 2.19.0 → 2.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/client/config.d.ts +17 -14
  2. package/dist/client/config.js +112 -14
  3. package/dist/client/index.d.ts +1 -1
  4. package/dist/client/index.js +1 -1
  5. package/dist/errors.d.ts +13 -1
  6. package/dist/errors.js +25 -0
  7. package/dist/execution/service.js +44 -10
  8. package/dist/execution/types.d.ts +3 -3
  9. package/dist/host/host.d.ts +20 -1
  10. package/dist/host/host.js +430 -66
  11. package/dist/host/types.d.ts +13 -1
  12. package/dist/index.d.ts +11 -3
  13. package/dist/index.js +5 -1
  14. package/dist/input/config-override.d.ts +5 -0
  15. package/dist/input/config-override.js +23 -0
  16. package/dist/input/input-resolver.d.ts +24 -7
  17. package/dist/input/input-resolver.js +73 -5
  18. package/dist/invocation/bindings.d.ts +53 -0
  19. package/dist/invocation/bindings.js +248 -0
  20. package/dist/invocation/policy.d.ts +5 -1
  21. package/dist/invocation/policy.js +16 -9
  22. package/dist/invocation/remote.d.ts +40 -0
  23. package/dist/invocation/remote.js +489 -0
  24. package/dist/invocation/types.d.ts +33 -0
  25. package/dist/invocation/types.js +11 -1
  26. package/dist/package/index.d.ts +2 -2
  27. package/dist/package/runtime.js +48 -15
  28. package/dist/platform/node.d.ts +6 -0
  29. package/dist/platform/node.js +59 -16
  30. package/dist/platform/types.d.ts +59 -1
  31. package/dist/process/command-executor.d.ts +35 -0
  32. package/dist/process/command-executor.js +326 -0
  33. package/dist/process/index.d.ts +1 -0
  34. package/dist/process/index.js +1 -0
  35. package/dist/process/process-driver.d.ts +19 -6
  36. package/dist/process/process-driver.js +223 -54
  37. package/dist/process/run-executor.js +101 -47
  38. package/dist/project/config-declarations.d.ts +61 -0
  39. package/dist/project/config-declarations.js +297 -0
  40. package/dist/project/dependencies.d.ts +92 -0
  41. package/dist/project/dependencies.js +543 -0
  42. package/dist/project/index.d.ts +8 -2
  43. package/dist/project/index.js +8 -2
  44. package/dist/project/init.js +2 -2
  45. package/dist/project/loader.js +19 -30
  46. package/dist/project/manifest.js +10 -0
  47. package/dist/project/package-manager.d.ts +40 -0
  48. package/dist/project/package-manager.js +224 -0
  49. package/dist/project/preparation.d.ts +8 -0
  50. package/dist/project/preparation.js +130 -0
  51. package/dist/project/transactions.d.ts +5 -1
  52. package/dist/project/transactions.js +35 -75
  53. package/dist/project/types.d.ts +30 -0
  54. package/dist/runtime/context.d.ts +27 -5
  55. package/dist/runtime/context.js +98 -26
  56. package/dist/runtime/env.js +15 -1
  57. package/dist/runtime/run-persistence.d.ts +1 -1
  58. package/dist/runtime/run-persistence.js +4 -3
  59. package/dist/runtime/standalone-commands.d.ts +2 -2
  60. package/dist/runtime/standalone-commands.js +113 -47
  61. package/dist/runtime/standalone-help.d.ts +1 -0
  62. package/dist/runtime/standalone-help.js +15 -9
  63. package/dist/runtime/standalone.js +2 -2
  64. package/dist/security/config-cipher.d.ts +54 -0
  65. package/dist/security/config-cipher.js +190 -0
  66. package/dist/security/config-key.d.ts +35 -0
  67. package/dist/security/config-key.js +469 -0
  68. package/dist/server/policy.d.ts +24 -107
  69. package/dist/server/policy.js +134 -291
  70. package/dist/server/routes/actions.js +10 -8
  71. package/dist/server/routes/common.d.ts +5 -20
  72. package/dist/server/routes/common.js +22 -58
  73. package/dist/server/routes/config.js +84 -7
  74. package/dist/server/routes/doctor.d.ts +1 -0
  75. package/dist/server/routes/doctor.js +4 -3
  76. package/dist/server/routes/info.js +100 -13
  77. package/dist/server/routes/playbooks.js +1 -3
  78. package/dist/server/routes/runs.js +96 -18
  79. package/dist/server/server.js +25 -53
  80. package/dist/server/types.d.ts +6 -6
  81. package/dist/service/factory.js +4 -0
  82. package/dist/service/remote.js +14 -29
  83. package/dist/service/types.d.ts +28 -5
  84. package/dist/service/types.js +8 -0
  85. package/dist/storage/config-value.d.ts +33 -0
  86. package/dist/storage/config-value.js +102 -0
  87. package/dist/storage/file-lock.js +35 -21
  88. package/dist/storage/index.d.ts +24 -2
  89. package/dist/storage/index.js +65 -2
  90. package/dist/storage/mask.d.ts +33 -6
  91. package/dist/storage/mask.js +298 -16
  92. package/dist/storage/migrations/index.d.ts +40 -0
  93. package/dist/storage/migrations/index.js +96 -0
  94. package/dist/storage/migrations/v2-to-v3.d.ts +16 -0
  95. package/dist/storage/migrations/v2-to-v3.js +116 -0
  96. package/dist/storage/sqlite-config.d.ts +62 -3
  97. package/dist/storage/sqlite-config.js +163 -9
  98. package/dist/storage/sqlite-driver.d.ts +5 -2
  99. package/dist/storage/sqlite-driver.js +24 -3
  100. package/dist/storage/sqlite-schema.d.ts +20 -2
  101. package/dist/storage/sqlite-schema.js +129 -132
  102. package/dist/storage/sqlite.d.ts +7 -2
  103. package/dist/storage/sqlite.js +64 -13
  104. package/dist/storage/types.d.ts +72 -4
  105. package/dist/storage/types.js +7 -2
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/package.json +2 -2
@@ -0,0 +1,102 @@
1
+ import { ActionDockError, CONFIG_DECRYPT_FAILED } from "../errors.js";
2
+ import { decryptConfigValue, encryptConfigValue, } from "../security/config-cipher.js";
3
+ import { isSecretConfigKey } from "./mask.js";
4
+ /**
5
+ * 对保护声明递归剥离脱敏无关信息。
6
+ *
7
+ * 仅保留结构(properties/additionalProperties/items)、类型与 secret
8
+ * 标记;严禁把 default、enum、env、description 等可能携带值的内容
9
+ * 写入保护元数据,即使信封整体已加密也保持最小化。
10
+ */
11
+ function sanitizeProtectionSchema(schema) {
12
+ const copy = {};
13
+ if (schema.type !== undefined)
14
+ copy.type = schema.type;
15
+ if (schema.secret !== undefined)
16
+ copy.secret = schema.secret;
17
+ if (schema.properties) {
18
+ copy.properties = Object.fromEntries(Object.entries(schema.properties).map(([name, child]) => [
19
+ name,
20
+ sanitizeProtectionSchema(child),
21
+ ]));
22
+ }
23
+ if (schema.additionalProperties !== undefined && typeof schema.additionalProperties === "object") {
24
+ copy.additionalProperties = sanitizeProtectionSchema(schema.additionalProperties);
25
+ }
26
+ if (schema.items !== undefined && typeof schema.items === "object") {
27
+ copy.items = sanitizeProtectionSchema(schema.items);
28
+ }
29
+ return copy;
30
+ }
31
+ /** 对单条保护声明剥离脱敏无关字段(保留 secret/type/schema 结构信息)。 */
32
+ function sanitizeProtectionDeclaration(item) {
33
+ const copy = {};
34
+ if (item.secret !== undefined)
35
+ copy.secret = item.secret;
36
+ if (item.type !== undefined)
37
+ copy.type = item.type;
38
+ if (item.schema)
39
+ copy.schema = sanitizeProtectionSchema(item.schema);
40
+ return copy;
41
+ }
42
+ /**
43
+ * 合并历史保护声明与当前敏感声明,绝不弱化保护强度。
44
+ *
45
+ * - 以规范化 JSON 作为去重标识,防止重复写入导致保护数组无界增长;
46
+ * - 当前声明中仅并入判定敏感的条目(非敏感声明不产生历史保护义务);
47
+ * - 合并结果为空时保守回退为整项敏感,保证密文行始终有脱敏依据。
48
+ */
49
+ export function mergeProtectionDeclarations(stored, current, key) {
50
+ const merged = [];
51
+ const seen = new Set();
52
+ const push = (item) => {
53
+ const sanitized = sanitizeProtectionDeclaration(item);
54
+ const identity = JSON.stringify(sanitized);
55
+ if (!seen.has(identity)) {
56
+ seen.add(identity);
57
+ merged.push(sanitized);
58
+ }
59
+ };
60
+ for (const item of stored ?? []) {
61
+ push(item);
62
+ }
63
+ for (const item of current) {
64
+ if (isSecretConfigKey(key, item)) {
65
+ push(item);
66
+ }
67
+ }
68
+ if (merged.length === 0) {
69
+ merged.push({ secret: true });
70
+ }
71
+ return merged;
72
+ }
73
+ /** 加密业务值与保护声明构成的完整信封,返回规范密文信封字符串。 */
74
+ export function encryptConfigEnvelope(value, protection, scope, key, material) {
75
+ const envelope = { value, protection: [...protection] };
76
+ return encryptConfigValue(envelope, scope, key, material);
77
+ }
78
+ /**
79
+ * 严格解密密文信封并校验负载形态。
80
+ *
81
+ * 信封负载必须为含 value 属性的对象;protection 省略或为声明对象数组。
82
+ * 任何不合规输入抛 CONFIG_DECRYPT_FAILED,绝不把密文降级当作明文返回。
83
+ */
84
+ export function decryptConfigEnvelope(ciphertext, scope, key, material) {
85
+ const payload = decryptConfigValue(ciphertext, scope, key, material);
86
+ if (payload === null ||
87
+ typeof payload !== "object" ||
88
+ Array.isArray(payload) ||
89
+ !Object.prototype.hasOwnProperty.call(payload, "value")) {
90
+ throw new ActionDockError(CONFIG_DECRYPT_FAILED, `Decrypted config payload for key '${key}' in scope '${scope}' is not a valid protection envelope`, { scope, key });
91
+ }
92
+ const envelope = payload;
93
+ if (envelope.protection !== undefined &&
94
+ (!Array.isArray(envelope.protection) ||
95
+ envelope.protection.some((item) => item === null || typeof item !== "object"))) {
96
+ throw new ActionDockError(CONFIG_DECRYPT_FAILED, `Decrypted protection metadata for config key '${key}' in scope '${scope}' is malformed`, { scope, key });
97
+ }
98
+ return {
99
+ value: envelope.value,
100
+ protection: envelope.protection ?? [],
101
+ };
102
+ }
@@ -292,6 +292,10 @@ function* acquireLockMachine(lockPath, options, isAsync) {
292
292
  isDir = s.isDirectory();
293
293
  }
294
294
  catch { }
295
+ // 所有权仲裁:陈旧目录在守卫独占保护下不可能被他人新建,可直接接管;
296
+ // 陈旧单文件被 unlink 后存在创建间隙,仅当本回收者亲自 mkdir 成功才可宣称所有权,
297
+ // 否则主锁已被他人在守卫外真实创建,严禁覆盖现存元数据或删除赢家
298
+ let mainLockClaimable = isDir;
295
299
  if (!isDir) {
296
300
  try {
297
301
  yield (d) => d.unlink(lockPath);
@@ -299,35 +303,45 @@ function* acquireLockMachine(lockPath, options, isAsync) {
299
303
  catch { }
300
304
  try {
301
305
  yield (d) => d.mkdir(lockPath, { mode: 0o700 });
306
+ mainLockClaimable = true;
302
307
  }
303
308
  catch (err) {
304
309
  if (err.code !== "EEXIST")
305
310
  throw err;
306
311
  }
312
+ if (!mainLockClaimable && !isAsync) {
313
+ // 同步语义:主锁已被他人真实创建,当轮快速失败,不得向调用方泄露原始 EEXIST
314
+ if (options?.createLockError) {
315
+ throw options.createLockError(`Lock '${lockPath}' is currently held by another active process`);
316
+ }
317
+ throw new ActionDockError(STORAGE_BUSY, `Lock '${lockPath}' is currently held by another active process`);
318
+ }
307
319
  }
308
- // 在接管守卫独占保护下写入并核验元数据,杜绝外部并发读取到残余陈旧元数据
309
- token = randomUUID();
310
- metadata = {
311
- pid: process.pid,
312
- createdAt: clock.now().toISOString(),
313
- ...options?.metadata,
314
- token,
315
- };
316
- const metaPath = join(lockPath, LOCK_METADATA_FILE);
317
- const tmpPath = join(lockPath, `meta.tmp.${process.pid}.${randomUUID().slice(0, 8)}`);
318
- yield (d) => d.writeFile(tmpPath, JSON.stringify(metadata, null, 2), { mode: 0o600 });
319
- yield (d) => d.rename(tmpPath, metaPath);
320
- const raw = yield (d) => d.readFile(metaPath, "utf-8");
321
- const verify = JSON.parse(raw);
322
- if (verify?.token !== token) {
323
- if (options?.createLockError) {
324
- throw options.createLockError(`Failed to verify acquired lock ownership in '${lockPath}'`);
320
+ if (mainLockClaimable) {
321
+ // 在接管守卫独占保护下写入并核验元数据,杜绝外部并发读取到残余陈旧元数据
322
+ token = randomUUID();
323
+ metadata = {
324
+ pid: process.pid,
325
+ createdAt: clock.now().toISOString(),
326
+ ...options?.metadata,
327
+ token,
328
+ };
329
+ const metaPath = join(lockPath, LOCK_METADATA_FILE);
330
+ const tmpPath = join(lockPath, `meta.tmp.${process.pid}.${randomUUID().slice(0, 8)}`);
331
+ yield (d) => d.writeFile(tmpPath, JSON.stringify(metadata, null, 2), { mode: 0o600 });
332
+ yield (d) => d.rename(tmpPath, metaPath);
333
+ const raw = yield (d) => d.readFile(metaPath, "utf-8");
334
+ const verify = JSON.parse(raw);
335
+ if (verify?.token !== token) {
336
+ if (options?.createLockError) {
337
+ throw options.createLockError(`Failed to verify acquired lock ownership in '${lockPath}'`);
338
+ }
339
+ throw new ActionDockError(STORAGE_BUSY, `Failed to verify acquired lock ownership in '${lockPath}'`);
325
340
  }
326
- throw new ActionDockError(STORAGE_BUSY, `Failed to verify acquired lock ownership in '${lockPath}'`);
341
+ activeLockPaths.add(resolvedPath);
342
+ acquired = true;
343
+ reclaimMetadataWritten = true;
327
344
  }
328
- activeLockPaths.add(resolvedPath);
329
- acquired = true;
330
- reclaimMetadataWritten = true;
331
345
  }
332
346
  finally {
333
347
  try {
@@ -1,4 +1,6 @@
1
- import type { RuntimeStorage } from "./types.js";
1
+ import type { ConfigItemDefinition } from "../project/types.js";
2
+ import { type RedactResult } from "./mask.js";
3
+ import type { ConfigSnapshot, RuntimeStorage } from "./types.js";
2
4
  export { DataDirLock, type DataDirLockInfo, isProcessAlive, } from "./data-dir-lock.js";
3
5
  export * from "./clock.js";
4
6
  export { NodeSqliteDriver } from "./sqlite-driver.js";
@@ -34,7 +36,7 @@ export declare function resolveDatabasePath(packageId: string, options?: {
34
36
  * 执行宿主路径应传入 recoverOrphans: true 或后续显式调用 recoverDeadSessionRuns。
35
37
  *
36
38
  * @param packageId 目标 Package ID
37
- * @param options 存储配置参数(支持 dataDir, inMemory, customHome, recoverOrphans)
39
+ * @param options 存储配置参数(支持 dataDir, inMemory, customHome, recoverOrphans, configDeclarations)
38
40
  */
39
41
  export declare function createStorage(packageId: string, options?: {
40
42
  projectRoot?: string;
@@ -43,6 +45,7 @@ export declare function createStorage(packageId: string, options?: {
43
45
  customHome?: string;
44
46
  recoverOrphans?: boolean;
45
47
  retentionPolicy?: import("./types.js").RunsRetentionPolicy;
48
+ configDeclarations?: readonly Record<string, ConfigItemDefinition>[];
46
49
  }): RuntimeStorage;
47
50
  /**
48
51
  * 解析全局共享数据库(global.db)文件的绝对路径。
@@ -70,4 +73,23 @@ export declare function createGlobalStorage(customHomeOrOptions?: string | {
70
73
  customHome?: string;
71
74
  dataDir?: string;
72
75
  inMemory?: boolean;
76
+ configDeclarations?: readonly Record<string, ConfigItemDefinition>[];
73
77
  }, dataDirArg?: string): RuntimeStorage;
78
+ /**
79
+ * 读取配置值与配套历史保护声明的原子快照。
80
+ *
81
+ * 优先使用存储的 getConfigSnapshot 单次 SELECT 配对读取值与保护规则,
82
+ * 消除先读值后读保护之间行被并发删除或改写造成的错配竞态;
83
+ * 存储未提供快照能力(如 MemoryStorage 或外部旧实现)时回退为
84
+ * 原值读取加可选保护读取的既有配对行为。
85
+ */
86
+ export declare function readConfigWithProtection(storage: RuntimeStorage, key: string): ConfigSnapshot | undefined;
87
+ /**
88
+ * 依据当前声明与历史保护声明合并脱敏管理视图配置值。
89
+ *
90
+ * 仅在存在历史保护声明(值曾按敏感声明加密写入)时使用:当前声明与历史
91
+ * 保护声明合并后取脱敏并集;合并后仍未产生任何脱敏结果时保守隐藏整项,
92
+ * 杜绝加密值因声明变更或跨宿主加载差异重新外泄明文。
93
+ * 无历史保护时由调用方沿用各自既有脱敏原语,保持行为不变。
94
+ */
95
+ export declare function redactConfigValueWithProtection(value: unknown, items: readonly ConfigItemDefinition[], protection: readonly ConfigItemDefinition[] | undefined): RedactResult;
@@ -1,7 +1,9 @@
1
1
  import { join, relative, resolve } from "node:path";
2
2
  import { assertValidPackageId, getActionDockHome, isPathOutsideBoundary } from "../utils/index.js";
3
3
  import { ActionDockError, PATH_TRAVERSAL } from "../errors.js";
4
+ import { createConfigKeyProvider } from "../security/config-key.js";
4
5
  import { SqliteRuntimeStorage } from "./sqlite.js";
6
+ import { redactConfigValueForDeclarations } from "./mask.js";
5
7
  export { DataDirLock, isProcessAlive, } from "./data-dir-lock.js";
6
8
  export * from "./clock.js";
7
9
  export { NodeSqliteDriver } from "./sqlite-driver.js";
@@ -56,7 +58,7 @@ export function resolveDatabasePath(packageId, options = {}) {
56
58
  * 执行宿主路径应传入 recoverOrphans: true 或后续显式调用 recoverDeadSessionRuns。
57
59
  *
58
60
  * @param packageId 目标 Package ID
59
- * @param options 存储配置参数(支持 dataDir, inMemory, customHome, recoverOrphans)
61
+ * @param options 存储配置参数(支持 dataDir, inMemory, customHome, recoverOrphans, configDeclarations)
60
62
  */
61
63
  export function createStorage(packageId, options = {}) {
62
64
  const dbPath = resolveDatabasePath(packageId, options);
@@ -65,6 +67,17 @@ export function createStorage(packageId, options = {}) {
65
67
  packageId,
66
68
  recoverOrphans: options.recoverOrphans,
67
69
  retentionPolicy: options.retentionPolicy,
70
+ ...(options.configDeclarations?.length ? { configDeclarations: options.configDeclarations } : {}),
71
+ // 持久化库统一注入懒加载密钥提供器:密钥与数据库共享同一有效 dataDir/customHome 域;
72
+ // 内存库不注入,由存储内部使用随机内存密钥,确保内存运行不触碰宿主密钥源
73
+ ...(dbPath !== ":memory:"
74
+ ? {
75
+ configKeyProvider: createConfigKeyProvider({
76
+ customHome: options.customHome,
77
+ dataDir: options.dataDir,
78
+ }),
79
+ }
80
+ : {}),
68
81
  });
69
82
  }
70
83
  /**
@@ -94,10 +107,12 @@ export function createGlobalStorage(customHomeOrOptions, dataDirArg) {
94
107
  let customHome;
95
108
  let dataDir;
96
109
  let inMemory = false;
110
+ let configDeclarations;
97
111
  if (typeof customHomeOrOptions === "object" && customHomeOrOptions !== null) {
98
112
  customHome = customHomeOrOptions.customHome;
99
113
  dataDir = customHomeOrOptions.dataDir;
100
114
  inMemory = Boolean(customHomeOrOptions.inMemory);
115
+ configDeclarations = customHomeOrOptions.configDeclarations;
101
116
  }
102
117
  else {
103
118
  customHome = customHomeOrOptions;
@@ -107,5 +122,53 @@ export function createGlobalStorage(customHomeOrOptions, dataDirArg) {
107
122
  return new SqliteRuntimeStorage({ dbPath: ":memory:", packageId: "__global__" });
108
123
  }
109
124
  const dbPath = resolveGlobalDatabasePath({ dataDir, customHome });
110
- return new SqliteRuntimeStorage({ dbPath, packageId: "__global__" });
125
+ return new SqliteRuntimeStorage({
126
+ dbPath,
127
+ packageId: "__global__",
128
+ configKeyProvider: createConfigKeyProvider({ customHome, dataDir }),
129
+ ...(configDeclarations?.length ? { configDeclarations } : {}),
130
+ });
131
+ }
132
+ /**
133
+ * 读取配置值与配套历史保护声明的原子快照。
134
+ *
135
+ * 优先使用存储的 getConfigSnapshot 单次 SELECT 配对读取值与保护规则,
136
+ * 消除先读值后读保护之间行被并发删除或改写造成的错配竞态;
137
+ * 存储未提供快照能力(如 MemoryStorage 或外部旧实现)时回退为
138
+ * 原值读取加可选保护读取的既有配对行为。
139
+ */
140
+ export function readConfigWithProtection(storage, key) {
141
+ if (typeof storage.getConfigSnapshot === "function") {
142
+ return storage.getConfigSnapshot(key);
143
+ }
144
+ const value = storage.getConfig(key);
145
+ if (value === undefined) {
146
+ return undefined;
147
+ }
148
+ if (typeof storage.getConfigProtection === "function") {
149
+ const protection = storage.getConfigProtection(key);
150
+ return protection !== undefined ? { value, protection } : { value };
151
+ }
152
+ return { value };
153
+ }
154
+ /**
155
+ * 依据当前声明与历史保护声明合并脱敏管理视图配置值。
156
+ *
157
+ * 仅在存在历史保护声明(值曾按敏感声明加密写入)时使用:当前声明与历史
158
+ * 保护声明合并后取脱敏并集;合并后仍未产生任何脱敏结果时保守隐藏整项,
159
+ * 杜绝加密值因声明变更或跨宿主加载差异重新外泄明文。
160
+ * 无历史保护时由调用方沿用各自既有脱敏原语,保持行为不变。
161
+ */
162
+ export function redactConfigValueWithProtection(value, items, protection) {
163
+ if (protection === undefined) {
164
+ return redactConfigValueForDeclarations(value, [...items]);
165
+ }
166
+ const merged = [...items, ...protection];
167
+ const result = redactConfigValueForDeclarations(value, merged);
168
+ if (!result.secret) {
169
+ return value === undefined
170
+ ? { value: undefined, secret: true, redactedPaths: [] }
171
+ : { value: undefined, secret: true, redactedPaths: [""] };
172
+ }
173
+ return result;
111
174
  }
@@ -1,10 +1,8 @@
1
+ import type { JsonValue } from "@actiondock/sdk";
1
2
  import type { ConfigItemDefinition } from "../project/types.js";
2
3
  /**
3
- * 检查指定配置项是否为敏感数据(密码、私钥、Token、密钥等)。
4
- *
5
- * 判定逻辑:
6
- * 严格依据配置项元数据属性判定:若声明了 `secret: true`,直接判定为敏感数据;否则不视为敏感数据。
7
- * 不进行基于正则或键名的自动探测,由开发者显式配置驱动。
4
+ * 检查指定配置项是否为敏感数据(顶层 secret: true 或模式中嵌套 secret: true)。
5
+ * 不进行基于正则或键名的自动探测,调用方若涉及模板应先解析具体声明项。
8
6
  *
9
7
  * @param _key 配置键名(保留入参以兼容契约)
10
8
  * @param declaredItem 项目中声明的配置元数据(可选)
@@ -17,9 +15,38 @@ export declare function isSecretConfigKey(_key?: string, declaredItem?: ConfigIt
17
15
  * @returns 掩码脱敏后的安全展示字符串
18
16
  */
19
17
  export declare function maskSecretValue(value: unknown): string;
18
+ /**
19
+ * 配置值脱敏安全视图产物。
20
+ */
21
+ export interface RedactResult {
22
+ /** 脱敏后的数据值(顶层敏感时为 undefined) */
23
+ value: JsonValue | undefined;
24
+ /** 是否包含敏感信息或发生了保守脱敏 */
25
+ secret: boolean;
26
+ /** 发生脱敏替换的字段路径集合(标准 JSON Pointer 格式) */
27
+ redactedPaths: string[];
28
+ }
29
+ /**
30
+ * 依据单项配置声明对配置值执行纯函数脱敏处理。
31
+ *
32
+ * @param value 待脱敏的配置原始数据值
33
+ * @param item 对应的单项配置定义元数据
34
+ */
35
+ export declare function redactConfigValue(value: unknown, item?: ConfigItemDefinition): RedactResult;
36
+ /** 根据可信隐藏路径应用幂等掩码,绝不把远端提供的路径本身当成已脱敏的证据。 */
37
+ export declare function redactConfigValueAtPaths(value: unknown, paths: string[]): RedactResult;
38
+ /**
39
+ * 依据跨包多重声明对配置值执行合并脱敏处理(取脱敏路径并集,祖先路径覆盖子路径)。
40
+ *
41
+ * @param value 待脱敏的配置原始数据值
42
+ * @param items 各相关包分别解析得到的配置声明集合
43
+ */
44
+ export declare function redactConfigValueForDeclarations(value: unknown, items: ConfigItemDefinition[]): RedactResult;
20
45
  /**
21
46
  * 对配置定义字典进行脱敏处理:
22
- * 针对声明为 secret: true 的项,剥离其 default 默认值,不返回敏感默认值。
47
+ * - 针对外层 secret: true 或嵌套包含敏感字段的项,剥离其 default 默认值,避免敏感默认值泄露或误用于执行;
48
+ * - 针对模式中敏感节点的 enum 约束列表进行清洗,杜绝约束文本泄露秘密;
49
+ * - 仅返回安全副本,严禁修改清单原始数据。
23
50
  *
24
51
  * @param config 声明的配置定义字典
25
52
  */