@mrciphersmith/keryx 0.3.20 → 0.3.21
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/dist/cli.js +73 -16
- package/dist/core.js +37 -12
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9080,6 +9080,24 @@ var init_config = __esm(() => {
|
|
|
9080
9080
|
});
|
|
9081
9081
|
|
|
9082
9082
|
// src/security/detect/entropy.ts
|
|
9083
|
+
function isAdjacentLabel(content, start) {
|
|
9084
|
+
const before = lastLineOf(content.slice(Math.max(0, start - LABEL_WINDOW), start));
|
|
9085
|
+
if (ADJACENT_LABEL.test(before)) {
|
|
9086
|
+
return true;
|
|
9087
|
+
}
|
|
9088
|
+
if (before.trim().length > 0) {
|
|
9089
|
+
return false;
|
|
9090
|
+
}
|
|
9091
|
+
const lineStart = content.lastIndexOf(`
|
|
9092
|
+
`, start - 1);
|
|
9093
|
+
if (lineStart < 0) {
|
|
9094
|
+
return false;
|
|
9095
|
+
}
|
|
9096
|
+
const prevLineStart = content.lastIndexOf(`
|
|
9097
|
+
`, lineStart - 1) + 1;
|
|
9098
|
+
const prevLine = content.slice(prevLineStart, lineStart);
|
|
9099
|
+
return CONTINUATION_LABEL_LINE_RE.test(prevLine);
|
|
9100
|
+
}
|
|
9083
9101
|
function isHexBlob(value) {
|
|
9084
9102
|
return HEX_BLOB.test(value) && /[a-f]/i.test(value);
|
|
9085
9103
|
}
|
|
@@ -9279,12 +9297,19 @@ function looksSecretShapedIn(text) {
|
|
|
9279
9297
|
return secretShapedCandidatesIn(text).length > 0;
|
|
9280
9298
|
}
|
|
9281
9299
|
function labelledPieceQualifies(piece) {
|
|
9282
|
-
const base = bareShapeQualifies(piece);
|
|
9283
|
-
if (base.qualifies) {
|
|
9284
|
-
return { entropy: base.entropy };
|
|
9285
|
-
}
|
|
9286
9300
|
if (isAllowShapedValue(piece)) {
|
|
9287
|
-
return { entropy:
|
|
9301
|
+
return { entropy: shannonEntropy(piece) };
|
|
9302
|
+
}
|
|
9303
|
+
if (isHexBlob(piece)) {
|
|
9304
|
+
return { entropy: shannonEntropy(piece) };
|
|
9305
|
+
}
|
|
9306
|
+
if (!/[0-9]/.test(piece) && !/[+=]/.test(piece)) {
|
|
9307
|
+
return null;
|
|
9308
|
+
}
|
|
9309
|
+
const withoutSeparators = piece.replace(/[-_.+]/g, "");
|
|
9310
|
+
const entropy = shannonEntropy(withoutSeparators.length > 0 ? withoutSeparators : piece);
|
|
9311
|
+
if (entropy >= 3.6) {
|
|
9312
|
+
return { entropy };
|
|
9288
9313
|
}
|
|
9289
9314
|
return null;
|
|
9290
9315
|
}
|
|
@@ -9323,9 +9348,9 @@ function detectEntropy(content) {
|
|
|
9323
9348
|
if (urlSpans.some((u) => start < u.end && end > u.start)) {
|
|
9324
9349
|
continue;
|
|
9325
9350
|
}
|
|
9326
|
-
const
|
|
9327
|
-
if (
|
|
9328
|
-
matches.push(buildMatch(start, end, value, entropy));
|
|
9351
|
+
const found = labelledPieceQualifies(value);
|
|
9352
|
+
if (found !== null) {
|
|
9353
|
+
matches.push(buildMatch(start, end, value, found.entropy));
|
|
9329
9354
|
}
|
|
9330
9355
|
}
|
|
9331
9356
|
TOKEN.lastIndex = 0;
|
|
@@ -9340,8 +9365,7 @@ function detectEntropy(content) {
|
|
|
9340
9365
|
if (matches.some((existing) => start < existing.end && end > existing.start)) {
|
|
9341
9366
|
continue;
|
|
9342
9367
|
}
|
|
9343
|
-
|
|
9344
|
-
if (!ADJACENT_LABEL.test(before)) {
|
|
9368
|
+
if (!isAdjacentLabel(content, start)) {
|
|
9345
9369
|
continue;
|
|
9346
9370
|
}
|
|
9347
9371
|
const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
|
|
@@ -9363,9 +9387,10 @@ function detectEntropy(content) {
|
|
|
9363
9387
|
}
|
|
9364
9388
|
return matches.sort((a, b) => a.start - b.start);
|
|
9365
9389
|
}
|
|
9366
|
-
var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), ADJACENT_LABEL, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, TAG_MAX_LETTER_RUN = 8, SLUG_HEX_TAIL_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
|
|
9390
|
+
var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), FILLER_WORDS = "is|was|set|to|the|value|now", ADJACENT_LABEL, CONTINUATION_LABEL_LINE_RE, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, TAG_MAX_LETTER_RUN = 8, SLUG_HEX_TAIL_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
|
|
9367
9391
|
var init_entropy = __esm(() => {
|
|
9368
|
-
ADJACENT_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]
|
|
9392
|
+
ADJACENT_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]*` + `(?:\\s+(?:${caseless(FILLER_WORDS)})){0,2}` + `["']?\\s*[:=]?\\s*["']?$`);
|
|
9393
|
+
CONTINUATION_LABEL_LINE_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]*["']?\\s*[:=]?\\s*\\\\\\s*$`);
|
|
9369
9394
|
LABEL_ASSIGNMENT_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${SENSITIVE_LABEL_WORDS})[A-Za-z0-9_-]*"?\\s*=\\s*"?([A-Za-z0-9+/_=-]{6,})`, "gi");
|
|
9370
9395
|
TOKEN = /[A-Za-z0-9+/=_-]{20,}(?:\.[A-Za-z0-9+/=_-]{6,})*/g;
|
|
9371
9396
|
TOKEN_HEAD = /^[A-Za-z0-9+/=_-]+/;
|
|
@@ -18093,7 +18118,7 @@ var package_default;
|
|
|
18093
18118
|
var init_package = __esm(() => {
|
|
18094
18119
|
package_default = {
|
|
18095
18120
|
name: "@mrciphersmith/keryx",
|
|
18096
|
-
version: "0.3.
|
|
18121
|
+
version: "0.3.21",
|
|
18097
18122
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
18098
18123
|
private: false,
|
|
18099
18124
|
publishConfig: {
|
|
@@ -129152,6 +129177,37 @@ function createSystemWebWorkerRunner() {
|
|
|
129152
129177
|
|
|
129153
129178
|
// src/harness/web/outbound-secret.ts
|
|
129154
129179
|
init_service4();
|
|
129180
|
+
var HEX32_FRAGMENT = "[0-9a-f]{32}";
|
|
129181
|
+
var SHA40_FRAGMENT = "[0-9a-f]{40}";
|
|
129182
|
+
var GIST_HEX32_PATH_RE = new RegExp(`^/(?:[^/]+/)?(${HEX32_FRAGMENT})/?$`, "i");
|
|
129183
|
+
var GITHUB_COMMIT_OR_BLOB_PATH_RE = new RegExp(`/(?:commit|blob)/(${SHA40_FRAGMENT})(?:/|$)`, "i");
|
|
129184
|
+
var GITLAB_COMMIT_PATH_RE = new RegExp(`/-/commit/(${SHA40_FRAGMENT})(?:/|$)`, "i");
|
|
129185
|
+
function knownPublicIdentifierIn(url) {
|
|
129186
|
+
const host = url.hostname.toLowerCase();
|
|
129187
|
+
if (host === "gist.github.com") {
|
|
129188
|
+
return GIST_HEX32_PATH_RE.exec(url.pathname)?.[1] ?? null;
|
|
129189
|
+
}
|
|
129190
|
+
if (host === "github.com") {
|
|
129191
|
+
return GITHUB_COMMIT_OR_BLOB_PATH_RE.exec(url.pathname)?.[1] ?? null;
|
|
129192
|
+
}
|
|
129193
|
+
if (host === "gitlab.com") {
|
|
129194
|
+
return GITLAB_COMMIT_PATH_RE.exec(url.pathname)?.[1] ?? null;
|
|
129195
|
+
}
|
|
129196
|
+
return null;
|
|
129197
|
+
}
|
|
129198
|
+
function stripKnownPublicIdentifier(text) {
|
|
129199
|
+
let url;
|
|
129200
|
+
try {
|
|
129201
|
+
url = new URL(text);
|
|
129202
|
+
} catch {
|
|
129203
|
+
return text;
|
|
129204
|
+
}
|
|
129205
|
+
const identifier = knownPublicIdentifierIn(url);
|
|
129206
|
+
if (identifier === null) {
|
|
129207
|
+
return text;
|
|
129208
|
+
}
|
|
129209
|
+
return text.replace(identifier, "0".repeat(identifier.length));
|
|
129210
|
+
}
|
|
129155
129211
|
function safeDecodeComponent(value) {
|
|
129156
129212
|
try {
|
|
129157
129213
|
return decodeURIComponent(value);
|
|
@@ -129195,13 +129251,14 @@ function anyComponentLooksSecret(text) {
|
|
|
129195
129251
|
return false;
|
|
129196
129252
|
}
|
|
129197
129253
|
function containsOutboundSecret(text) {
|
|
129198
|
-
|
|
129254
|
+
const scanText = stripKnownPublicIdentifier(text);
|
|
129255
|
+
if (detectSecrets(scanText).length > 0) {
|
|
129199
129256
|
return true;
|
|
129200
129257
|
}
|
|
129201
|
-
if (isEntropyBackendEnabled() && detectEntropy(
|
|
129258
|
+
if (isEntropyBackendEnabled() && detectEntropy(scanText).length > 0) {
|
|
129202
129259
|
return true;
|
|
129203
129260
|
}
|
|
129204
|
-
return anyComponentLooksSecret(
|
|
129261
|
+
return anyComponentLooksSecret(scanText);
|
|
129205
129262
|
}
|
|
129206
129263
|
async function recordOutboundSecretFinding(cwd, tool, subject) {
|
|
129207
129264
|
try {
|
package/dist/core.js
CHANGED
|
@@ -4029,6 +4029,24 @@ var init_config2 = __esm(() => {
|
|
|
4029
4029
|
});
|
|
4030
4030
|
|
|
4031
4031
|
// src/security/detect/entropy.ts
|
|
4032
|
+
function isAdjacentLabel(content, start) {
|
|
4033
|
+
const before = lastLineOf(content.slice(Math.max(0, start - LABEL_WINDOW), start));
|
|
4034
|
+
if (ADJACENT_LABEL.test(before)) {
|
|
4035
|
+
return true;
|
|
4036
|
+
}
|
|
4037
|
+
if (before.trim().length > 0) {
|
|
4038
|
+
return false;
|
|
4039
|
+
}
|
|
4040
|
+
const lineStart = content.lastIndexOf(`
|
|
4041
|
+
`, start - 1);
|
|
4042
|
+
if (lineStart < 0) {
|
|
4043
|
+
return false;
|
|
4044
|
+
}
|
|
4045
|
+
const prevLineStart = content.lastIndexOf(`
|
|
4046
|
+
`, lineStart - 1) + 1;
|
|
4047
|
+
const prevLine = content.slice(prevLineStart, lineStart);
|
|
4048
|
+
return CONTINUATION_LABEL_LINE_RE.test(prevLine);
|
|
4049
|
+
}
|
|
4032
4050
|
function isHexBlob(value) {
|
|
4033
4051
|
return HEX_BLOB.test(value) && /[a-f]/i.test(value);
|
|
4034
4052
|
}
|
|
@@ -4228,12 +4246,19 @@ function looksSecretShapedIn(text) {
|
|
|
4228
4246
|
return secretShapedCandidatesIn(text).length > 0;
|
|
4229
4247
|
}
|
|
4230
4248
|
function labelledPieceQualifies(piece) {
|
|
4231
|
-
const base = bareShapeQualifies(piece);
|
|
4232
|
-
if (base.qualifies) {
|
|
4233
|
-
return { entropy: base.entropy };
|
|
4234
|
-
}
|
|
4235
4249
|
if (isAllowShapedValue(piece)) {
|
|
4236
|
-
return { entropy:
|
|
4250
|
+
return { entropy: shannonEntropy(piece) };
|
|
4251
|
+
}
|
|
4252
|
+
if (isHexBlob(piece)) {
|
|
4253
|
+
return { entropy: shannonEntropy(piece) };
|
|
4254
|
+
}
|
|
4255
|
+
if (!/[0-9]/.test(piece) && !/[+=]/.test(piece)) {
|
|
4256
|
+
return null;
|
|
4257
|
+
}
|
|
4258
|
+
const withoutSeparators = piece.replace(/[-_.+]/g, "");
|
|
4259
|
+
const entropy = shannonEntropy(withoutSeparators.length > 0 ? withoutSeparators : piece);
|
|
4260
|
+
if (entropy >= 3.6) {
|
|
4261
|
+
return { entropy };
|
|
4237
4262
|
}
|
|
4238
4263
|
return null;
|
|
4239
4264
|
}
|
|
@@ -4272,9 +4297,9 @@ function detectEntropy(content) {
|
|
|
4272
4297
|
if (urlSpans.some((u) => start < u.end && end > u.start)) {
|
|
4273
4298
|
continue;
|
|
4274
4299
|
}
|
|
4275
|
-
const
|
|
4276
|
-
if (
|
|
4277
|
-
matches.push(buildMatch(start, end, value, entropy));
|
|
4300
|
+
const found = labelledPieceQualifies(value);
|
|
4301
|
+
if (found !== null) {
|
|
4302
|
+
matches.push(buildMatch(start, end, value, found.entropy));
|
|
4278
4303
|
}
|
|
4279
4304
|
}
|
|
4280
4305
|
TOKEN.lastIndex = 0;
|
|
@@ -4289,8 +4314,7 @@ function detectEntropy(content) {
|
|
|
4289
4314
|
if (matches.some((existing) => start < existing.end && end > existing.start)) {
|
|
4290
4315
|
continue;
|
|
4291
4316
|
}
|
|
4292
|
-
|
|
4293
|
-
if (!ADJACENT_LABEL.test(before)) {
|
|
4317
|
+
if (!isAdjacentLabel(content, start)) {
|
|
4294
4318
|
continue;
|
|
4295
4319
|
}
|
|
4296
4320
|
const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
|
|
@@ -4312,9 +4336,10 @@ function detectEntropy(content) {
|
|
|
4312
4336
|
}
|
|
4313
4337
|
return matches.sort((a, b) => a.start - b.start);
|
|
4314
4338
|
}
|
|
4315
|
-
var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), ADJACENT_LABEL, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, TAG_MAX_LETTER_RUN = 8, SLUG_HEX_TAIL_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
|
|
4339
|
+
var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), FILLER_WORDS = "is|was|set|to|the|value|now", ADJACENT_LABEL, CONTINUATION_LABEL_LINE_RE, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, TAG_MAX_LETTER_RUN = 8, SLUG_HEX_TAIL_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
|
|
4316
4340
|
var init_entropy = __esm(() => {
|
|
4317
|
-
ADJACENT_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]
|
|
4341
|
+
ADJACENT_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]*` + `(?:\\s+(?:${caseless(FILLER_WORDS)})){0,2}` + `["']?\\s*[:=]?\\s*["']?$`);
|
|
4342
|
+
CONTINUATION_LABEL_LINE_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]*["']?\\s*[:=]?\\s*\\\\\\s*$`);
|
|
4318
4343
|
LABEL_ASSIGNMENT_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${SENSITIVE_LABEL_WORDS})[A-Za-z0-9_-]*"?\\s*=\\s*"?([A-Za-z0-9+/_=-]{6,})`, "gi");
|
|
4319
4344
|
TOKEN = /[A-Za-z0-9+/=_-]{20,}(?:\.[A-Za-z0-9+/=_-]{6,})*/g;
|
|
4320
4345
|
TOKEN_HEAD = /^[A-Za-z0-9+/=_-]+/;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.21",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|