@clear-capabilities/agentic-security-scanner 0.145.0 → 0.147.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.
- package/CHANGELOG.md +139 -0
- package/bin/agentic-security.js +3508 -69
- package/dist/1122.index.js +702 -0
- package/dist/{301.index.js → 1301.index.js} +2 -2
- package/dist/1379.index.js +591 -0
- package/dist/{444.index.js → 1444.index.js} +2 -2
- package/dist/{660.index.js → 1660.index.js} +2 -2
- package/dist/{700.index.js → 1700.index.js} +2 -2
- package/dist/{905.index.js → 1905.index.js} +3 -3
- package/dist/{920.index.js → 1920.index.js} +3 -3
- package/dist/{238.index.js → 2238.index.js} +3 -3
- package/dist/{271.index.js → 2271.index.js} +2 -2
- package/dist/{985.index.js → 2376.index.js} +1260 -340
- package/dist/2432.index.js +793 -0
- package/dist/2659.index.js +93 -0
- package/dist/{826.index.js → 2826.index.js} +2 -2
- package/dist/{830.index.js → 2830.index.js} +2 -2
- package/dist/2923.index.js +298 -0
- package/dist/{1.index.js → 3001.index.js} +5 -5
- package/dist/{117.index.js → 3117.index.js} +3 -3
- package/dist/3180.index.js +307 -0
- package/dist/3276.index.js +117 -0
- package/dist/{415.index.js → 3415.index.js} +2 -2
- package/dist/{499.index.js → 3499.index.js} +2 -2
- package/dist/3518.index.js +450 -0
- package/dist/{526.index.js → 3526.index.js} +5 -5
- package/dist/{736.index.js → 3736.index.js} +4 -4
- package/dist/{839.index.js → 3839.index.js} +4 -4
- package/dist/{113.index.js → 4113.index.js} +5 -5
- package/dist/{265.index.js → 4265.index.js} +2 -2
- package/dist/{384.index.js → 4384.index.js} +3 -3
- package/dist/4547.index.js +268 -0
- package/dist/4863.index.js +422 -0
- package/dist/{970.index.js → 4970.index.js} +2 -2
- package/dist/5051.index.js +770 -0
- package/dist/{144.index.js → 5144.index.js} +5 -5
- package/dist/{333.index.js → 5333.index.js} +3 -3
- package/dist/5343.index.js +185 -0
- package/dist/5350.index.js +866 -0
- package/dist/5561.index.js +436 -0
- package/dist/{637.index.js → 5637.index.js} +3 -3
- package/dist/{449.index.js → 5830.index.js} +2 -2
- package/dist/6626.index.js +532 -0
- package/dist/6662.index.js +297 -0
- package/dist/{675.index.js → 6675.index.js} +5 -5
- package/dist/{730.index.js → 6730.index.js} +6 -6
- package/dist/6829.index.js +225 -0
- package/dist/6944.index.js +130 -0
- package/dist/{178.index.js → 7178.index.js} +3 -3
- package/dist/{227.index.js → 7227.index.js} +2 -2
- package/dist/7310.index.js +520 -0
- package/dist/{552.index.js → 7552.index.js} +4 -4
- package/dist/7709.index.js +78 -0
- package/dist/8218.index.js +160 -0
- package/dist/{476.index.js → 8476.index.js} +4 -4
- package/dist/{513.index.js → 8513.index.js} +5 -5
- package/dist/{520.index.js → 8520.index.js} +2 -2
- package/dist/{718.index.js → 8718.index.js} +2 -2
- package/dist/{752.index.js → 8752.index.js} +2 -2
- package/dist/8846.index.js +100 -0
- package/dist/{435.index.js → 9091.index.js} +560 -189
- package/dist/{207.index.js → 9207.index.js} +2 -2
- package/dist/{220.index.js → 9220.index.js} +2 -2
- package/dist/9390.index.js +163 -0
- package/dist/{503.index.js → 9503.index.js} +2 -2
- package/dist/{801.index.js → 9801.index.js} +2 -2
- package/dist/{824.index.js → 9824.index.js} +2 -2
- package/dist/agentic-security.mjs +16 -16
- package/dist/agentic-security.mjs.sha256 +1 -1
- package/dist/compliance-frameworks/hipaa-security-rule.json +3 -2
- package/package.json +12 -5
- package/src/dataflow/CLAUDE.md +1 -1
- package/src/dataflow/catalog.js +42 -0
- package/src/dataflow/orm-write-catalog.js +175 -0
- package/src/engine.js +92 -1
- package/src/ir/CLAUDE.md +1 -0
- package/src/ir/chrome-probe.mjs +150 -0
- package/src/ir/parser-js.js +94 -7
- package/src/lineage/CLAUDE.md +1203 -0
- package/src/lineage/DESIGN_DESTINATION_RESOLVER.md +156 -0
- package/src/lineage/DESIGN_GRAPH_BUILDER.md +938 -0
- package/src/lineage/DESIGN_HANDLING_ANALYZER.md +355 -0
- package/src/lineage/DESIGN_INTRAPROCEDURAL.md +628 -0
- package/src/lineage/DESIGN_PATH_PROVENANCE.md +3451 -0
- package/src/lineage/DESIGN_QUEUE_DETAIL.md +120 -0
- package/src/lineage/DESIGN_REGISTRIES.md +880 -0
- package/src/lineage/DESIGN_STORE_DETAIL.md +143 -0
- package/src/lineage/DESIGN_TRANSIT_PROTECTION.md +245 -0
- package/src/lineage/classification.js +56 -0
- package/src/lineage/coverage.js +658 -0
- package/src/lineage/cross-repo-link.js +107 -0
- package/src/lineage/dataflow-graph.schema.json +184 -0
- package/src/lineage/decision-story.js +206 -0
- package/src/lineage/drift-policy.js +279 -0
- package/src/lineage/driver.js +135 -0
- package/src/lineage/engine.js +992 -0
- package/src/lineage/export-briefing.js +628 -0
- package/src/lineage/export-csv.js +62 -0
- package/src/lineage/export-json.js +238 -0
- package/src/lineage/export-privacy.js +258 -0
- package/src/lineage/federation-loader.js +111 -0
- package/src/lineage/field-identity.js +78 -0
- package/src/lineage/fixtures/build-flagship-fixture.mjs +272 -0
- package/src/lineage/fixtures/flagship-graph.json +1453 -0
- package/src/lineage/flow-grade.js +221 -0
- package/src/lineage/governance-edit.js +169 -0
- package/src/lineage/graph-builder.js +1114 -0
- package/src/lineage/graph-diff.js +431 -0
- package/src/lineage/graph-snapshot.js +180 -0
- package/src/lineage/handling-analyzer.js +168 -0
- package/src/lineage/ids.js +349 -0
- package/src/lineage/impact-assessment.js +76 -0
- package/src/lineage/impact-engine.js +268 -0
- package/src/lineage/index.js +281 -0
- package/src/lineage/language-coverage-tiers.js +58 -0
- package/src/lineage/obligation-mapping.js +126 -0
- package/src/lineage/obligation-predicates.js +235 -0
- package/src/lineage/observation-adapters.js +282 -0
- package/src/lineage/observation-correlation.js +622 -0
- package/src/lineage/observation-store.js +497 -0
- package/src/lineage/path-query.js +410 -0
- package/src/lineage/path-store.js +400 -0
- package/src/lineage/protection.js +53 -0
- package/src/lineage/recipient-profile.js +192 -0
- package/src/lineage/recipient-registry.js +394 -0
- package/src/lineage/redact-graph.js +224 -0
- package/src/lineage/remediation.js +417 -0
- package/src/lineage/resolve-destination.js +91 -0
- package/src/lineage/runtime-observation.js +464 -0
- package/src/lineage/scenario-diff.js +84 -0
- package/src/lineage/scenario-engine.js +251 -0
- package/src/lineage/scenario.js +101 -0
- package/src/lineage/schema.js +167 -0
- package/src/lineage/sink-registry.js +427 -0
- package/src/lineage/source-registry.js +357 -0
- package/src/lineage/source-seeding.js +212 -0
- package/src/lineage/summaries.js +590 -0
- package/src/lineage/transform-catalog.js +397 -0
- package/src/lineage/transit-protection.js +150 -0
- package/src/lineage/validate.js +285 -0
- package/src/mcp/CLAUDE.md +7 -1
- package/src/mcp/dataflow-tools.js +160 -0
- package/src/mcp/server.js +1 -1
- package/src/mcp/tools.js +2 -1
- package/src/pipeline/scan-health.js +19 -1
- package/src/posture/CLAUDE.md +19 -0
- package/src/posture/artifact-registry.js +52 -0
- package/src/posture/auditor-walkthrough.js +76 -0
- package/src/posture/compliance-frameworks/hipaa-security-rule.json +3 -2
- package/src/posture/obligation-evidence-pack.js +202 -0
- package/src/posture/remediation-ledger.js +337 -0
- package/src/server/CLAUDE.md +47 -0
- package/src/server/graph-loader.js +141 -0
- package/src/server/http-server.js +325 -0
- package/src/server/routes.js +129 -0
- package/src/server/security.js +111 -0
- package/src/server/static-assets.js +139 -0
- package/dist/11.index.js +0 -353
- package/dist/259.index.js +0 -975
- package/dist/317.index.js +0 -300
- package/dist/609.index.js +0 -741
- package/dist/838.index.js +0 -152
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export const id =
|
|
2
|
-
export const ids = [
|
|
1
|
+
export const id = 5144;
|
|
2
|
+
export const ids = [5144];
|
|
3
3
|
export const modules = {
|
|
4
4
|
|
|
5
5
|
/***/ 5144:
|
|
@@ -65,7 +65,7 @@ const LEGAL_HOLD_FILE = 'legal-holds.json';
|
|
|
65
65
|
|
|
66
66
|
function _loadRaw(scanRoot) {
|
|
67
67
|
let fp;
|
|
68
|
-
try { fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__
|
|
68
|
+
try { fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.statePath)(scanRoot, LEGAL_HOLD_FILE); } catch { return []; }
|
|
69
69
|
let raw;
|
|
70
70
|
try { raw = node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(fp, 'utf8'); } catch { return []; }
|
|
71
71
|
try {
|
|
@@ -135,7 +135,7 @@ function addLegalHold(scanRoot, { artifact, owner, reason, expires_at } = {}) {
|
|
|
135
135
|
const hold = { artifact, owner, reason, expires_at: expires_at || null, created_at: new Date().toISOString() };
|
|
136
136
|
const holds = _loadRaw(scanRoot);
|
|
137
137
|
holds.push(hold);
|
|
138
|
-
const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__
|
|
138
|
+
const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.statePath)(scanRoot, LEGAL_HOLD_FILE);
|
|
139
139
|
if (!(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__/* .safeWriteState */ .Ep)(fp, JSON.stringify(holds, null, 2) + '\n')) {
|
|
140
140
|
return { ok: false, reason: 'state writes are disabled (--no-state) or this is not a safe state directory' };
|
|
141
141
|
}
|
|
@@ -151,7 +151,7 @@ function removeLegalHold(scanRoot, artifact) {
|
|
|
151
151
|
const remaining = holds.filter(h => !(h && h.artifact === artifact));
|
|
152
152
|
const removedCount = holds.length - remaining.length;
|
|
153
153
|
if (removedCount > 0) {
|
|
154
|
-
const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__
|
|
154
|
+
const fp = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__.statePath)(scanRoot, LEGAL_HOLD_FILE);
|
|
155
155
|
(0,_state_dir_js__WEBPACK_IMPORTED_MODULE_1__/* .safeWriteState */ .Ep)(fp, JSON.stringify(remaining, null, 2) + '\n');
|
|
156
156
|
}
|
|
157
157
|
return removedCount;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export const id =
|
|
2
|
-
export const ids = [
|
|
1
|
+
export const id = 5333;
|
|
2
|
+
export const ids = [5333];
|
|
3
3
|
export const modules = {
|
|
4
4
|
|
|
5
5
|
/***/ 5333:
|
|
@@ -182,7 +182,7 @@ async function applyScaUpgrade({ scanRoot, finding, runTests = true }) {
|
|
|
182
182
|
// we can restore on test failure. node_modules / vendor dirs are NOT
|
|
183
183
|
// backed up (too big); they'll be rebuilt by re-running the install on
|
|
184
184
|
// restore.
|
|
185
|
-
const stateDir = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_6__
|
|
185
|
+
const stateDir = (0,_state_dir_js__WEBPACK_IMPORTED_MODULE_6__.statePath)(scanRoot, 'sca-upgrade-history');
|
|
186
186
|
node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(stateDir, { recursive: true });
|
|
187
187
|
const upgradeId = node_crypto__WEBPACK_IMPORTED_MODULE_3__.randomBytes(8).toString('hex');
|
|
188
188
|
const backups = {};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export const id = 5343;
|
|
2
|
+
export const ids = [5343];
|
|
3
|
+
export const modules = {
|
|
4
|
+
|
|
5
|
+
/***/ 5343:
|
|
6
|
+
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
7
|
+
|
|
8
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
9
|
+
/* harmony export */ proposeGovernanceEdit: () => (/* binding */ proposeGovernanceEdit)
|
|
10
|
+
/* harmony export */ });
|
|
11
|
+
/* harmony import */ var _recipient_registry_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6703);
|
|
12
|
+
// governance-edit.js — M5 deliverable #5 (PRD line 1324's 5-part write
|
|
13
|
+
// contract: preview, validation, backup/version guard, confirmation,
|
|
14
|
+
// audit event). A CLI-only workflow for proposing a validated,
|
|
15
|
+
// reviewable edit to recipient-profiles.json — the one governance
|
|
16
|
+
// config file this codebase already has real, tested per-entry
|
|
17
|
+
// validation for (isValidRecipientConfigEntry, recipient-registry.js).
|
|
18
|
+
//
|
|
19
|
+
// Deliberately narrower than the PRD's own richer "interactive review/
|
|
20
|
+
// approve UI" vision — the HTTP-server-side interactive write surface
|
|
21
|
+
// (new routes, CSRF protection, a write-authorization mechanism beyond
|
|
22
|
+
// the existing read-only session token) is real, separately-scoped
|
|
23
|
+
// future work, not attempted here. See this sub-project's own scoping
|
|
24
|
+
// doc for the full reasoning: no PRD acceptance criterion gates this
|
|
25
|
+
// deliverable at all, and every M4/M5 deliverable this session has
|
|
26
|
+
// shipped has been CLI-first with zero UI/HTTP-write work.
|
|
27
|
+
//
|
|
28
|
+
// This module is pure — no file I/O, no fs access. The CLI layer
|
|
29
|
+
// (bin/agentic-security.js's cmdGovernancePropose) owns reading the
|
|
30
|
+
// current file, writing the backup, writing the new content, and
|
|
31
|
+
// calling auditCall.
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// Validates the top-level `{recipients: {...}}` container shape — used
|
|
36
|
+
// for BOTH the current on-disk config and the --patch file. A patch is
|
|
37
|
+
// user input the command's whole job is to validate, so it gets no
|
|
38
|
+
// tolerant degradation (fixes I2/I3: previously a patch missing
|
|
39
|
+
// `recipients` entirely, or with `recipients` as an array, degraded
|
|
40
|
+
// silently to an empty no-op write). The CURRENT config gets the same
|
|
41
|
+
// check for a different reason: if its top-level shape is unrecognized
|
|
42
|
+
// (e.g. a typo'd `Recipients` key), the tool must refuse rather than
|
|
43
|
+
// silently treating "no recognizable data" as "start from empty" and
|
|
44
|
+
// overwriting whatever WAS there (this was B1's second live repro —
|
|
45
|
+
// the whole file being replaced under a misspelled key).
|
|
46
|
+
function _validateContainerShape(recipients, label) {
|
|
47
|
+
if (recipients === undefined) {
|
|
48
|
+
return [{ key: '(top-level)', message: `${label} is missing a "recipients" object` }];
|
|
49
|
+
}
|
|
50
|
+
if (recipients === null || typeof recipients !== 'object' || Array.isArray(recipients)) {
|
|
51
|
+
return [{ key: '(top-level)', message: `${label}'s "recipients" must be a plain object, not ${Array.isArray(recipients) ? 'an array' : recipients === null ? 'null' : typeof recipients}` }];
|
|
52
|
+
}
|
|
53
|
+
const errors = [];
|
|
54
|
+
for (const key of Object.keys(recipients)) {
|
|
55
|
+
if (key.length === 0) errors.push({ key, message: `${label} contains an empty-string recipient key, which is never valid` });
|
|
56
|
+
if (key === '__proto__') errors.push({ key, message: `${label} contains a "__proto__" recipient key, which is never valid` });
|
|
57
|
+
}
|
|
58
|
+
return errors;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function _validateEntries(patchRecipients) {
|
|
62
|
+
const errors = [];
|
|
63
|
+
for (const [key, entry] of Object.entries(patchRecipients)) {
|
|
64
|
+
if (entry === null) continue; // explicit deletion marker, not a config entry
|
|
65
|
+
if (!(0,_recipient_registry_js__WEBPACK_IMPORTED_MODULE_0__/* .isValidRecipientConfigEntry */ .cw)(entry)) {
|
|
66
|
+
errors.push({ key, message: `recipient "${key}" is not a valid recipient-profile-shaped config entry` });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return errors;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// RFC-7396-style merge patch at the recipient-key level: a non-null
|
|
73
|
+
// patch value REPLACES that key's entire entry; a null value DELETES
|
|
74
|
+
// it; a key the patch never mentions is left untouched. This is the
|
|
75
|
+
// fix for a real data-loss bug (found by this task's own review,
|
|
76
|
+
// live-reproduced): the prior design treated `patch.recipients` as
|
|
77
|
+
// the ENTIRE new recipients object, so omitting a key silently
|
|
78
|
+
// deleted it — a reasonable operator adding one vendor had no reason
|
|
79
|
+
// to expect every other vendor's compliance facts to vanish.
|
|
80
|
+
function _mergeRecipients(currentRecipients, patchRecipients) {
|
|
81
|
+
const merged = { ...currentRecipients };
|
|
82
|
+
for (const [key, value] of Object.entries(patchRecipients)) {
|
|
83
|
+
if (value === null) delete merged[key];
|
|
84
|
+
else merged[key] = value;
|
|
85
|
+
}
|
|
86
|
+
return merged;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Canonical (key-order-independent) JSON serialization for change
|
|
90
|
+
// detection — mirrors ids.js's own _canon precedent. A hand-authored
|
|
91
|
+
// patch file has no reason to preserve the stored config's own key
|
|
92
|
+
// order, so a raw JSON.stringify comparison would spuriously flag a
|
|
93
|
+
// semantically-unchanged recipient as "changed" (found by the task
|
|
94
|
+
// review, reproduced live). Arrays keep their own order (order is
|
|
95
|
+
// semantically meaningful there — e.g. subprocessorChain); only OBJECT
|
|
96
|
+
// key order is normalized.
|
|
97
|
+
function _canonicalize(value) {
|
|
98
|
+
if (Array.isArray(value)) return value.map(_canonicalize);
|
|
99
|
+
if (value && typeof value === 'object') {
|
|
100
|
+
const sorted = {};
|
|
101
|
+
for (const key of Object.keys(value).sort()) sorted[key] = _canonicalize(value[key]);
|
|
102
|
+
return sorted;
|
|
103
|
+
}
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function _diffRecipients(currentRecipients, patchRecipients) {
|
|
108
|
+
const added = [];
|
|
109
|
+
const removed = [];
|
|
110
|
+
const changed = [];
|
|
111
|
+
const currentKeys = new Set(Object.keys(currentRecipients));
|
|
112
|
+
for (const [key, value] of Object.entries(patchRecipients)) {
|
|
113
|
+
if (value === null) {
|
|
114
|
+
if (currentKeys.has(key)) removed.push(key);
|
|
115
|
+
// deleting a key that never existed is a no-op, not reported
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (!currentKeys.has(key)) { added.push(key); continue; }
|
|
119
|
+
if (JSON.stringify(_canonicalize(currentRecipients[key])) !== JSON.stringify(_canonicalize(value))) {
|
|
120
|
+
changed.push({ key, before: currentRecipients[key], after: value });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
added.sort();
|
|
124
|
+
removed.sort();
|
|
125
|
+
changed.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0));
|
|
126
|
+
return { added, removed, changed };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Propose a patch to a recipient-profiles.json-shaped config. Pure,
|
|
131
|
+
* never throws, never touches the filesystem. `currentConfig`/`patch`
|
|
132
|
+
* are both expected to be `{recipients: {...}}`-shaped — a malformed
|
|
133
|
+
* top-level shape on EITHER side (missing `recipients`, `recipients`
|
|
134
|
+
* not a plain object, or an empty-string/`__proto__` recipient key) is
|
|
135
|
+
* a validation failure (`valid: false`, `merged: null`), never a
|
|
136
|
+
* silent empty-object fallback. The stored config gets this treatment
|
|
137
|
+
* so an unrecognized shape (e.g. a typo'd top-level key) refuses to
|
|
138
|
+
* write rather than being silently treated as "nothing here yet" and
|
|
139
|
+
* overwritten; the patch gets it because it is user input the command's
|
|
140
|
+
* whole job is to validate.
|
|
141
|
+
*
|
|
142
|
+
* `patch.recipients` is an RFC-7396-style JSON MERGE PATCH against
|
|
143
|
+
* `currentConfig.recipients`, keyed at the recipient level — never a
|
|
144
|
+
* full replacement of the whole object: a key present with a non-null
|
|
145
|
+
* value REPLACES that key's entire entry (never deep-merged within
|
|
146
|
+
* itself); a key present with value `null` DELETES it (the only way to
|
|
147
|
+
* remove a recipient); a key the patch never mentions is left
|
|
148
|
+
* untouched in the merged result. Every OTHER top-level key on the
|
|
149
|
+
* current config (e.g. `$schema`, `version`) is preserved verbatim into
|
|
150
|
+
* `merged` — only `recipients` itself is merged.
|
|
151
|
+
*
|
|
152
|
+
* Returns `{valid, errors, diff, merged}` — `diff`/`merged` are always
|
|
153
|
+
* computed when both container shapes are valid, even when `valid` is
|
|
154
|
+
* false due to a per-entry error, so an operator can see what they
|
|
155
|
+
* attempted before fixing a validation error. `merged` is `null` only
|
|
156
|
+
* when there is no safe merge base to compute (a container-shape
|
|
157
|
+
* failure on either side). `merged`, when non-null, is the full
|
|
158
|
+
* config-shaped result the caller should write — never the raw patch.
|
|
159
|
+
*/
|
|
160
|
+
function proposeGovernanceEdit(currentConfig, patch) {
|
|
161
|
+
const currentContainerErrors = _validateContainerShape(currentConfig?.recipients, 'the current config file');
|
|
162
|
+
const patchContainerErrors = _validateContainerShape(patch?.recipients, 'the --patch file');
|
|
163
|
+
if (currentContainerErrors.length || patchContainerErrors.length) {
|
|
164
|
+
return {
|
|
165
|
+
valid: false,
|
|
166
|
+
errors: [...currentContainerErrors, ...patchContainerErrors],
|
|
167
|
+
diff: { added: [], removed: [], changed: [] },
|
|
168
|
+
merged: null,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const currentRecipients = currentConfig.recipients;
|
|
172
|
+
const patchRecipients = patch.recipients;
|
|
173
|
+
const entryErrors = _validateEntries(patchRecipients);
|
|
174
|
+
const diff = _diffRecipients(currentRecipients, patchRecipients);
|
|
175
|
+
const mergedRecipients = _mergeRecipients(currentRecipients, patchRecipients);
|
|
176
|
+
// Preserve every OTHER top-level key from the current config verbatim
|
|
177
|
+
// (e.g. $schema, version) — only `recipients` itself is merged.
|
|
178
|
+
const merged = { ...(currentConfig && typeof currentConfig === 'object' ? currentConfig : {}), recipients: mergedRecipients };
|
|
179
|
+
return { valid: entryErrors.length === 0, errors: entryErrors, diff, merged };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
/***/ })
|
|
184
|
+
|
|
185
|
+
};
|