engineering-memory 1.11.0 → 1.11.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "engineering-memory",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.1",
|
|
4
4
|
"description": "Installs the Engineering Memory skill and its local MCP bridge. Sign in after installing; your organization and project are resolved from your account.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -1019,16 +1019,26 @@ export class BridgeService {
|
|
|
1019
1019
|
if (!run || typeof run.id !== 'string')
|
|
1020
1020
|
throw refuse('The inspection response has no run identity.', 'memory.sync_status');
|
|
1021
1021
|
if (run.state === 'inventory' || run.state === 'planning') {
|
|
1022
|
-
for (let offset = 0; offset < snapshot.files.length;
|
|
1023
|
-
const page =
|
|
1022
|
+
for (let offset = 0; offset < snapshot.files.length;) {
|
|
1023
|
+
const page = {
|
|
1024
1024
|
projectId: input.projectId,
|
|
1025
1025
|
runId: run.id,
|
|
1026
|
-
files:
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1026
|
+
files: [],
|
|
1027
|
+
};
|
|
1028
|
+
let bytes = Buffer.byteLength(JSON.stringify(page));
|
|
1029
|
+
while (offset < snapshot.files.length && page.files.length < 1000) {
|
|
1030
|
+
const file = snapshot.files[offset];
|
|
1031
|
+
const addedBytes = Buffer.byteLength(JSON.stringify(file)) + (page.files.length ? 1 : 0);
|
|
1032
|
+
if (page.files.length && bytes + addedBytes > 64 * 1024)
|
|
1033
|
+
break;
|
|
1034
|
+
page.files.push(file);
|
|
1035
|
+
bytes += addedBytes;
|
|
1036
|
+
offset += 1;
|
|
1037
|
+
}
|
|
1038
|
+
assertSafeToPersist(cleanJson(page));
|
|
1029
1039
|
await this.dependencies.client.request('/memory/sync/inventory', {
|
|
1030
1040
|
method: 'POST',
|
|
1031
|
-
body: page,
|
|
1041
|
+
body: cleanJson(page),
|
|
1032
1042
|
});
|
|
1033
1043
|
}
|
|
1034
1044
|
await this.dependencies.client.request('/memory/sync/inventory', {
|
|
@@ -6,6 +6,22 @@ import { sha256, stableStringify } from '../utilities/hash.js';
|
|
|
6
6
|
const sensitiveKeyPattern = /(authorization|password|passcode|secret|token|cookie|email|phone|mobile|customer|account|user.?id|user.?name)/i;
|
|
7
7
|
const emailPattern = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i;
|
|
8
8
|
const phonePattern = /\+\d[\d ()-]{7,}\d/;
|
|
9
|
+
const repositoryPathFields = new Set([
|
|
10
|
+
'path',
|
|
11
|
+
'paths',
|
|
12
|
+
'originalPath',
|
|
13
|
+
'changedPaths',
|
|
14
|
+
'pathPatterns',
|
|
15
|
+
'evidencePaths',
|
|
16
|
+
]);
|
|
17
|
+
const iosAssetScalePathPattern = /^(?:[\p{L}\p{N}_. -]+\/)*[\p{L}\p{N}_. -]+\.xcassets\/[\p{L}\p{N}_. -]+\.(?:appiconset|imageset)\/[\p{L}\p{N}_. -]+@[123]x\.(?:png|jpe?g)$/iu;
|
|
18
|
+
function emailScanValue(value, key) {
|
|
19
|
+
if (!repositoryPathFields.has(key) ||
|
|
20
|
+
!iosAssetScalePathPattern.test(value) ||
|
|
21
|
+
value.split('/').some((part) => part === '.' || part === '..'))
|
|
22
|
+
return value;
|
|
23
|
+
return value.replace(/@[123]x(?=\.(?:png|jpe?g)$)/i, '');
|
|
24
|
+
}
|
|
9
25
|
const bearerPattern = /\bbearer\s+[a-z0-9._~-]+/i;
|
|
10
26
|
const jwtPattern = /\beyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\b/;
|
|
11
27
|
const privateKeyPattern = /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/;
|
|
@@ -155,7 +171,7 @@ export function assertSafeToPersist(value, key = '') {
|
|
|
155
171
|
throw new Error(`Sensitive field cannot be persisted: ${key}`);
|
|
156
172
|
}
|
|
157
173
|
if (typeof value === 'string') {
|
|
158
|
-
if (emailPattern.test(value) ||
|
|
174
|
+
if (emailPattern.test(emailScanValue(value, key)) ||
|
|
159
175
|
phonePattern.test(value) ||
|
|
160
176
|
bearerPattern.test(value) ||
|
|
161
177
|
jwtPattern.test(value) ||
|
|
@@ -199,13 +215,13 @@ export function redactForCache(value) {
|
|
|
199
215
|
return null;
|
|
200
216
|
}
|
|
201
217
|
}
|
|
202
|
-
function redactValue(value) {
|
|
218
|
+
function redactValue(value, key = '') {
|
|
203
219
|
if (typeof value === 'string') {
|
|
204
|
-
assertSafeToPersist(value);
|
|
220
|
+
assertSafeToPersist(value, key);
|
|
205
221
|
return value;
|
|
206
222
|
}
|
|
207
223
|
if (Array.isArray(value)) {
|
|
208
|
-
return value.map((entry) => redactValue(entry));
|
|
224
|
+
return value.map((entry) => redactValue(entry, key));
|
|
209
225
|
}
|
|
210
226
|
if (value !== null && typeof value === 'object') {
|
|
211
227
|
const result = {};
|
|
@@ -213,7 +229,7 @@ function redactValue(value) {
|
|
|
213
229
|
if (sensitiveKeyPattern.test(key)) {
|
|
214
230
|
continue;
|
|
215
231
|
}
|
|
216
|
-
result[key] = redactValue(entry);
|
|
232
|
+
result[key] = redactValue(entry, key);
|
|
217
233
|
}
|
|
218
234
|
return result;
|
|
219
235
|
}
|