@mrciphersmith/keryx 0.3.19 → 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 +137 -24
- package/dist/core.js +101 -20
- 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
|
}
|
|
@@ -9091,8 +9109,24 @@ function lastLineOf(before) {
|
|
|
9091
9109
|
`);
|
|
9092
9110
|
return newline < 0 ? before : before.slice(newline + 1);
|
|
9093
9111
|
}
|
|
9112
|
+
function isPlainCasedWord(letters) {
|
|
9113
|
+
return /^[a-z]+$/.test(letters) || /^[A-Z]+$/.test(letters) || /^[A-Z][a-z]*$/.test(letters);
|
|
9114
|
+
}
|
|
9094
9115
|
function isSingleTransitionTag(segment) {
|
|
9095
|
-
|
|
9116
|
+
const letterThenDigit = /^([A-Za-z]+)([0-9]+)$/.exec(segment);
|
|
9117
|
+
if (letterThenDigit !== null) {
|
|
9118
|
+
const letters = letterThenDigit[1];
|
|
9119
|
+
return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
|
|
9120
|
+
}
|
|
9121
|
+
const digitThenLetter = /^([0-9]+)([A-Za-z]+)$/.exec(segment);
|
|
9122
|
+
if (digitThenLetter !== null) {
|
|
9123
|
+
const letters = digitThenLetter[2];
|
|
9124
|
+
return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
|
|
9125
|
+
}
|
|
9126
|
+
return false;
|
|
9127
|
+
}
|
|
9128
|
+
function isSlugHexTail(segment) {
|
|
9129
|
+
return SLUG_HEX_TAIL_RE.test(segment);
|
|
9096
9130
|
}
|
|
9097
9131
|
function isWordSlug(value) {
|
|
9098
9132
|
const segments = value.split(/[-_]/);
|
|
@@ -9100,15 +9134,25 @@ function isWordSlug(value) {
|
|
|
9100
9134
|
return false;
|
|
9101
9135
|
}
|
|
9102
9136
|
let words = 0;
|
|
9103
|
-
for (
|
|
9104
|
-
const
|
|
9137
|
+
for (let i = 0;i < segments.length; i += 1) {
|
|
9138
|
+
const segment = segments[i];
|
|
9105
9139
|
const isDigits = /^[0-9]+$/.test(segment);
|
|
9106
|
-
if (
|
|
9107
|
-
|
|
9140
|
+
if (isDigits) {
|
|
9141
|
+
continue;
|
|
9108
9142
|
}
|
|
9109
|
-
if (
|
|
9110
|
-
|
|
9143
|
+
if (isPlainCasedWord(segment)) {
|
|
9144
|
+
if (segment.length >= 3) {
|
|
9145
|
+
words += 1;
|
|
9146
|
+
}
|
|
9147
|
+
continue;
|
|
9111
9148
|
}
|
|
9149
|
+
if (isSingleTransitionTag(segment)) {
|
|
9150
|
+
continue;
|
|
9151
|
+
}
|
|
9152
|
+
if (i === segments.length - 1 && isSlugHexTail(segment)) {
|
|
9153
|
+
continue;
|
|
9154
|
+
}
|
|
9155
|
+
return false;
|
|
9112
9156
|
}
|
|
9113
9157
|
return words >= 1;
|
|
9114
9158
|
}
|
|
@@ -9252,6 +9296,36 @@ function secretShapedCandidatesIn(text) {
|
|
|
9252
9296
|
function looksSecretShapedIn(text) {
|
|
9253
9297
|
return secretShapedCandidatesIn(text).length > 0;
|
|
9254
9298
|
}
|
|
9299
|
+
function labelledPieceQualifies(piece) {
|
|
9300
|
+
if (isAllowShapedValue(piece)) {
|
|
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 };
|
|
9313
|
+
}
|
|
9314
|
+
return null;
|
|
9315
|
+
}
|
|
9316
|
+
function firstQualifyingSlashPiece(head) {
|
|
9317
|
+
let offset = 0;
|
|
9318
|
+
for (const piece of head.split("/")) {
|
|
9319
|
+
if (piece.length > 0) {
|
|
9320
|
+
const found = labelledPieceQualifies(piece);
|
|
9321
|
+
if (found !== null) {
|
|
9322
|
+
return { offset, length: piece.length, entropy: found.entropy };
|
|
9323
|
+
}
|
|
9324
|
+
}
|
|
9325
|
+
offset += piece.length + 1;
|
|
9326
|
+
}
|
|
9327
|
+
return null;
|
|
9328
|
+
}
|
|
9255
9329
|
function detectEntropy(content) {
|
|
9256
9330
|
const matches = [];
|
|
9257
9331
|
const urlSpans = findUrlSpans(content);
|
|
@@ -9274,9 +9348,9 @@ function detectEntropy(content) {
|
|
|
9274
9348
|
if (urlSpans.some((u) => start < u.end && end > u.start)) {
|
|
9275
9349
|
continue;
|
|
9276
9350
|
}
|
|
9277
|
-
const
|
|
9278
|
-
if (
|
|
9279
|
-
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));
|
|
9280
9354
|
}
|
|
9281
9355
|
}
|
|
9282
9356
|
TOKEN.lastIndex = 0;
|
|
@@ -9291,26 +9365,32 @@ function detectEntropy(content) {
|
|
|
9291
9365
|
if (matches.some((existing) => start < existing.end && end > existing.start)) {
|
|
9292
9366
|
continue;
|
|
9293
9367
|
}
|
|
9294
|
-
|
|
9295
|
-
const { qualifies, entropy } = bareShapeQualifies(head);
|
|
9296
|
-
if (!qualifies) {
|
|
9368
|
+
if (!isAdjacentLabel(content, start)) {
|
|
9297
9369
|
continue;
|
|
9298
9370
|
}
|
|
9299
|
-
const
|
|
9300
|
-
if (
|
|
9371
|
+
const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
|
|
9372
|
+
if (head.includes("/")) {
|
|
9373
|
+
const piece = firstQualifyingSlashPiece(head);
|
|
9374
|
+
if (piece === null) {
|
|
9375
|
+
continue;
|
|
9376
|
+
}
|
|
9377
|
+
const pieceStart = start + piece.offset;
|
|
9378
|
+
const pieceEnd = pieceStart + piece.length;
|
|
9379
|
+
matches.push(buildMatch(pieceStart, pieceEnd, content.slice(pieceStart, pieceEnd), piece.entropy));
|
|
9301
9380
|
continue;
|
|
9302
9381
|
}
|
|
9303
|
-
|
|
9382
|
+
const found = labelledPieceQualifies(head);
|
|
9383
|
+
if (found === null) {
|
|
9304
9384
|
continue;
|
|
9305
9385
|
}
|
|
9306
|
-
matches.push(buildMatch(start, end, value, entropy));
|
|
9386
|
+
matches.push(buildMatch(start, end, value, found.entropy));
|
|
9307
9387
|
}
|
|
9308
9388
|
return matches.sort((a, b) => a.start - b.start);
|
|
9309
9389
|
}
|
|
9310
|
-
var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`),
|
|
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;
|
|
9311
9391
|
var init_entropy = __esm(() => {
|
|
9312
|
-
|
|
9313
|
-
|
|
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*$`);
|
|
9314
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");
|
|
9315
9395
|
TOKEN = /[A-Za-z0-9+/=_-]{20,}(?:\.[A-Za-z0-9+/=_-]{6,})*/g;
|
|
9316
9396
|
TOKEN_HEAD = /^[A-Za-z0-9+/=_-]+/;
|
|
@@ -9318,6 +9398,7 @@ var init_entropy = __esm(() => {
|
|
|
9318
9398
|
FULL_GIT_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
9319
9399
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
9320
9400
|
INTEGRITY_RE = /^(?:sha256|sha512)-[A-Za-z0-9+/]+=*$/;
|
|
9401
|
+
SLUG_HEX_TAIL_RE = /^[0-9a-f]{10,16}$/i;
|
|
9321
9402
|
URL_SPAN_RE = /\bhttps?:\/\/[^\s<>"'\\]+/g;
|
|
9322
9403
|
URL_TRAILING_PUNCTUATION_RE = /[.,;:!?)\]}]$/;
|
|
9323
9404
|
});
|
|
@@ -18037,7 +18118,7 @@ var package_default;
|
|
|
18037
18118
|
var init_package = __esm(() => {
|
|
18038
18119
|
package_default = {
|
|
18039
18120
|
name: "@mrciphersmith/keryx",
|
|
18040
|
-
version: "0.3.
|
|
18121
|
+
version: "0.3.21",
|
|
18041
18122
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
18042
18123
|
private: false,
|
|
18043
18124
|
publishConfig: {
|
|
@@ -129096,6 +129177,37 @@ function createSystemWebWorkerRunner() {
|
|
|
129096
129177
|
|
|
129097
129178
|
// src/harness/web/outbound-secret.ts
|
|
129098
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
|
+
}
|
|
129099
129211
|
function safeDecodeComponent(value) {
|
|
129100
129212
|
try {
|
|
129101
129213
|
return decodeURIComponent(value);
|
|
@@ -129139,13 +129251,14 @@ function anyComponentLooksSecret(text) {
|
|
|
129139
129251
|
return false;
|
|
129140
129252
|
}
|
|
129141
129253
|
function containsOutboundSecret(text) {
|
|
129142
|
-
|
|
129254
|
+
const scanText = stripKnownPublicIdentifier(text);
|
|
129255
|
+
if (detectSecrets(scanText).length > 0) {
|
|
129143
129256
|
return true;
|
|
129144
129257
|
}
|
|
129145
|
-
if (isEntropyBackendEnabled() && detectEntropy(
|
|
129258
|
+
if (isEntropyBackendEnabled() && detectEntropy(scanText).length > 0) {
|
|
129146
129259
|
return true;
|
|
129147
129260
|
}
|
|
129148
|
-
return anyComponentLooksSecret(
|
|
129261
|
+
return anyComponentLooksSecret(scanText);
|
|
129149
129262
|
}
|
|
129150
129263
|
async function recordOutboundSecretFinding(cwd, tool, subject) {
|
|
129151
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
|
}
|
|
@@ -4040,8 +4058,24 @@ function lastLineOf(before) {
|
|
|
4040
4058
|
`);
|
|
4041
4059
|
return newline < 0 ? before : before.slice(newline + 1);
|
|
4042
4060
|
}
|
|
4061
|
+
function isPlainCasedWord(letters) {
|
|
4062
|
+
return /^[a-z]+$/.test(letters) || /^[A-Z]+$/.test(letters) || /^[A-Z][a-z]*$/.test(letters);
|
|
4063
|
+
}
|
|
4043
4064
|
function isSingleTransitionTag(segment) {
|
|
4044
|
-
|
|
4065
|
+
const letterThenDigit = /^([A-Za-z]+)([0-9]+)$/.exec(segment);
|
|
4066
|
+
if (letterThenDigit !== null) {
|
|
4067
|
+
const letters = letterThenDigit[1];
|
|
4068
|
+
return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
|
|
4069
|
+
}
|
|
4070
|
+
const digitThenLetter = /^([0-9]+)([A-Za-z]+)$/.exec(segment);
|
|
4071
|
+
if (digitThenLetter !== null) {
|
|
4072
|
+
const letters = digitThenLetter[2];
|
|
4073
|
+
return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
|
|
4074
|
+
}
|
|
4075
|
+
return false;
|
|
4076
|
+
}
|
|
4077
|
+
function isSlugHexTail(segment) {
|
|
4078
|
+
return SLUG_HEX_TAIL_RE.test(segment);
|
|
4045
4079
|
}
|
|
4046
4080
|
function isWordSlug(value) {
|
|
4047
4081
|
const segments = value.split(/[-_]/);
|
|
@@ -4049,15 +4083,25 @@ function isWordSlug(value) {
|
|
|
4049
4083
|
return false;
|
|
4050
4084
|
}
|
|
4051
4085
|
let words = 0;
|
|
4052
|
-
for (
|
|
4053
|
-
const
|
|
4086
|
+
for (let i = 0;i < segments.length; i += 1) {
|
|
4087
|
+
const segment = segments[i];
|
|
4054
4088
|
const isDigits = /^[0-9]+$/.test(segment);
|
|
4055
|
-
if (
|
|
4056
|
-
|
|
4089
|
+
if (isDigits) {
|
|
4090
|
+
continue;
|
|
4057
4091
|
}
|
|
4058
|
-
if (
|
|
4059
|
-
|
|
4092
|
+
if (isPlainCasedWord(segment)) {
|
|
4093
|
+
if (segment.length >= 3) {
|
|
4094
|
+
words += 1;
|
|
4095
|
+
}
|
|
4096
|
+
continue;
|
|
4060
4097
|
}
|
|
4098
|
+
if (isSingleTransitionTag(segment)) {
|
|
4099
|
+
continue;
|
|
4100
|
+
}
|
|
4101
|
+
if (i === segments.length - 1 && isSlugHexTail(segment)) {
|
|
4102
|
+
continue;
|
|
4103
|
+
}
|
|
4104
|
+
return false;
|
|
4061
4105
|
}
|
|
4062
4106
|
return words >= 1;
|
|
4063
4107
|
}
|
|
@@ -4201,6 +4245,36 @@ function secretShapedCandidatesIn(text) {
|
|
|
4201
4245
|
function looksSecretShapedIn(text) {
|
|
4202
4246
|
return secretShapedCandidatesIn(text).length > 0;
|
|
4203
4247
|
}
|
|
4248
|
+
function labelledPieceQualifies(piece) {
|
|
4249
|
+
if (isAllowShapedValue(piece)) {
|
|
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 };
|
|
4262
|
+
}
|
|
4263
|
+
return null;
|
|
4264
|
+
}
|
|
4265
|
+
function firstQualifyingSlashPiece(head) {
|
|
4266
|
+
let offset = 0;
|
|
4267
|
+
for (const piece of head.split("/")) {
|
|
4268
|
+
if (piece.length > 0) {
|
|
4269
|
+
const found = labelledPieceQualifies(piece);
|
|
4270
|
+
if (found !== null) {
|
|
4271
|
+
return { offset, length: piece.length, entropy: found.entropy };
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
offset += piece.length + 1;
|
|
4275
|
+
}
|
|
4276
|
+
return null;
|
|
4277
|
+
}
|
|
4204
4278
|
function detectEntropy(content) {
|
|
4205
4279
|
const matches = [];
|
|
4206
4280
|
const urlSpans = findUrlSpans(content);
|
|
@@ -4223,9 +4297,9 @@ function detectEntropy(content) {
|
|
|
4223
4297
|
if (urlSpans.some((u) => start < u.end && end > u.start)) {
|
|
4224
4298
|
continue;
|
|
4225
4299
|
}
|
|
4226
|
-
const
|
|
4227
|
-
if (
|
|
4228
|
-
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));
|
|
4229
4303
|
}
|
|
4230
4304
|
}
|
|
4231
4305
|
TOKEN.lastIndex = 0;
|
|
@@ -4240,26 +4314,32 @@ function detectEntropy(content) {
|
|
|
4240
4314
|
if (matches.some((existing) => start < existing.end && end > existing.start)) {
|
|
4241
4315
|
continue;
|
|
4242
4316
|
}
|
|
4243
|
-
|
|
4244
|
-
const { qualifies, entropy } = bareShapeQualifies(head);
|
|
4245
|
-
if (!qualifies) {
|
|
4317
|
+
if (!isAdjacentLabel(content, start)) {
|
|
4246
4318
|
continue;
|
|
4247
4319
|
}
|
|
4248
|
-
const
|
|
4249
|
-
if (
|
|
4320
|
+
const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
|
|
4321
|
+
if (head.includes("/")) {
|
|
4322
|
+
const piece = firstQualifyingSlashPiece(head);
|
|
4323
|
+
if (piece === null) {
|
|
4324
|
+
continue;
|
|
4325
|
+
}
|
|
4326
|
+
const pieceStart = start + piece.offset;
|
|
4327
|
+
const pieceEnd = pieceStart + piece.length;
|
|
4328
|
+
matches.push(buildMatch(pieceStart, pieceEnd, content.slice(pieceStart, pieceEnd), piece.entropy));
|
|
4250
4329
|
continue;
|
|
4251
4330
|
}
|
|
4252
|
-
|
|
4331
|
+
const found = labelledPieceQualifies(head);
|
|
4332
|
+
if (found === null) {
|
|
4253
4333
|
continue;
|
|
4254
4334
|
}
|
|
4255
|
-
matches.push(buildMatch(start, end, value, entropy));
|
|
4335
|
+
matches.push(buildMatch(start, end, value, found.entropy));
|
|
4256
4336
|
}
|
|
4257
4337
|
return matches.sort((a, b) => a.start - b.start);
|
|
4258
4338
|
}
|
|
4259
|
-
var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`),
|
|
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;
|
|
4260
4340
|
var init_entropy = __esm(() => {
|
|
4261
|
-
|
|
4262
|
-
|
|
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*$`);
|
|
4263
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");
|
|
4264
4344
|
TOKEN = /[A-Za-z0-9+/=_-]{20,}(?:\.[A-Za-z0-9+/=_-]{6,})*/g;
|
|
4265
4345
|
TOKEN_HEAD = /^[A-Za-z0-9+/=_-]+/;
|
|
@@ -4267,6 +4347,7 @@ var init_entropy = __esm(() => {
|
|
|
4267
4347
|
FULL_GIT_SHA_RE = /^[0-9a-f]{40}$/i;
|
|
4268
4348
|
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
4269
4349
|
INTEGRITY_RE = /^(?:sha256|sha512)-[A-Za-z0-9+/]+=*$/;
|
|
4350
|
+
SLUG_HEX_TAIL_RE = /^[0-9a-f]{10,16}$/i;
|
|
4270
4351
|
URL_SPAN_RE = /\bhttps?:\/\/[^\s<>"'\\]+/g;
|
|
4271
4352
|
URL_TRAILING_PUNCTUATION_RE = /[.,;:!?)\]}]$/;
|
|
4272
4353
|
});
|
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": {
|