@hasna/logs 0.3.28 → 0.3.30
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/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
runJob,
|
|
9
9
|
structuredLogToEntry,
|
|
10
10
|
validateStructuredLogReferences
|
|
11
|
-
} from "../index-
|
|
11
|
+
} from "../index-k9w7zfsv.js";
|
|
12
12
|
import {
|
|
13
13
|
PACKAGE_VERSION,
|
|
14
14
|
createPage,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
searchTestReports,
|
|
31
31
|
summarizeLogs,
|
|
32
32
|
validateUniversalEventInput
|
|
33
|
-
} from "../index-
|
|
33
|
+
} from "../index-mx0f61s2.js";
|
|
34
34
|
import {
|
|
35
35
|
getStorageStatus,
|
|
36
36
|
storagePull,
|
|
@@ -237,7 +237,7 @@ async function fireAlert(db, rule, count) {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
// src/lib/ingest.ts
|
|
240
|
-
import { randomBytes } from "crypto";
|
|
240
|
+
import { createHash, randomBytes } from "crypto";
|
|
241
241
|
|
|
242
242
|
// src/lib/event-bus.ts
|
|
243
243
|
class LogEventBus {
|
|
@@ -508,9 +508,26 @@ function readPositiveInt(name, fallback) {
|
|
|
508
508
|
|
|
509
509
|
// src/lib/redaction.ts
|
|
510
510
|
var REDACTED = "[REDACTED]";
|
|
511
|
-
var SENSITIVE_KEY = /(?:authorization|cookie|set-cookie|api[_-]?key|token|secret|password|passwd|pwd|private[_-]?key|access[_-]?token|refresh[_-]?token|session[_-]?secret|client[_-]?secret)/i;
|
|
512
|
-
var SENSITIVE_FLAG = /^(?:authorization|auth|api[-_]?key|token|secret|password|passwd|pwd|private[-_]?key|access[-_]?token|refresh[-_]?token|session[-_]?secret|client[-_]?secret)$/i;
|
|
513
|
-
var SENSITIVE_FLAG_NAME = /(?:authorization|api[-_]?key|token|secret|password|passwd|pwd|private[-_]?key|access[-_]?token|refresh[-_]?token|session[-_]?secret|client[-_]?secret)/i;
|
|
511
|
+
var SENSITIVE_KEY = /(?:authorization|cookie|set-cookie|credentials?\b|api[_-]?key|token|secret|password|passwd|pwd|private[_-]?key|access[_-]?token|refresh[_-]?token|session[_-]?secret|client[_-]?(?:secret|credentials?))/i;
|
|
512
|
+
var SENSITIVE_FLAG = /^(?:authorization|auth|credentials?|api[-_]?key|token|secret|password|passwd|pwd|private[-_]?key|access[-_]?token|refresh[-_]?token|session[-_]?secret|client[-_]?(?:secret|credentials?))$/i;
|
|
513
|
+
var SENSITIVE_FLAG_NAME = /(?:authorization|credentials?\b|api[-_]?key|token|secret|password|passwd|pwd|private[-_]?key|access[-_]?token|refresh[-_]?token|session[-_]?secret|client[-_]?(?:secret|credentials?))/i;
|
|
514
|
+
var LOG_ENTRY_REDACTABLE_TOP_LEVEL_FIELDS = [
|
|
515
|
+
"id",
|
|
516
|
+
"source_event_id",
|
|
517
|
+
"service",
|
|
518
|
+
"machine_id",
|
|
519
|
+
"repo_id",
|
|
520
|
+
"app_id",
|
|
521
|
+
"process_id",
|
|
522
|
+
"run_id",
|
|
523
|
+
"trace_id",
|
|
524
|
+
"span_id",
|
|
525
|
+
"parent_span_id",
|
|
526
|
+
"session_id",
|
|
527
|
+
"release_id",
|
|
528
|
+
"environment",
|
|
529
|
+
"agent"
|
|
530
|
+
];
|
|
514
531
|
var STRING_PATTERNS = [
|
|
515
532
|
{
|
|
516
533
|
label: "openlogs_canary",
|
|
@@ -564,12 +581,12 @@ var STRING_PATTERNS = [
|
|
|
564
581
|
},
|
|
565
582
|
{
|
|
566
583
|
label: "secret_assignment",
|
|
567
|
-
pattern:
|
|
568
|
-
replacement: (
|
|
584
|
+
pattern: /(?<![?&])\b(credentials?|api[_-]?key|token|secret|password|passwd|pwd|access[_-]?token|refresh[_-]?token|client[_-]?(?:secret|credentials?))\s*[:=]\s*("[^"]*"|'[^']*'|[^\s,;&}]+)/gi,
|
|
585
|
+
replacement: (match, key, value) => isKnownNonSecretCredentialAssignment(key, value) ? match : `${key}=${REDACTED}`
|
|
569
586
|
},
|
|
570
587
|
{
|
|
571
588
|
label: "secret_flag_argument",
|
|
572
|
-
pattern: /(--[A-Za-z0-9._-]*(?:authorization|api[-_]?key|token|secret|password|passwd|pwd|private[-_]?key|access[-_]?token|refresh[-_]?token|session[-_]?secret|client[-_]?secret)[A-Za-z0-9._-]*\s+)(?:"[^"]*"|'[^']*'|[^\s,;&}]+)/gi,
|
|
589
|
+
pattern: /(--[A-Za-z0-9._-]*(?:authorization|credentials?(?!ed)|api[-_]?key|token|secret|password|passwd|pwd|private[-_]?key|access[-_]?token|refresh[-_]?token|session[-_]?secret|client[-_]?(?:secret|credentials?(?!ed)))[A-Za-z0-9._-]*\s+)(?:"[^"]*"|'[^']*'|[^\s,;&}]+)/gi,
|
|
573
590
|
replacement: (_match, prefix) => `${prefix}${REDACTED}`
|
|
574
591
|
},
|
|
575
592
|
{
|
|
@@ -579,13 +596,21 @@ var STRING_PATTERNS = [
|
|
|
579
596
|
},
|
|
580
597
|
{
|
|
581
598
|
label: "secret_query_param",
|
|
582
|
-
pattern: /([?&](?:api[_-]?key|token|secret|password|passwd|pwd|access[_-]?token|refresh[_-]?token|auth|code)=)[^&#\s]+/gi,
|
|
599
|
+
pattern: /([?&](?:credentials?|api[_-]?key|token|secret|password|passwd|pwd|access[_-]?token|refresh[_-]?token|client[_-]?credentials?|auth|code)=)[^&#\s]+/gi,
|
|
583
600
|
replacement: (_match, prefix) => `${prefix}${REDACTED}`
|
|
584
601
|
}
|
|
585
602
|
];
|
|
586
603
|
function redactLogEntry(entry) {
|
|
587
604
|
const reports = [];
|
|
588
605
|
const next = { ...entry };
|
|
606
|
+
for (const field of LOG_ENTRY_REDACTABLE_TOP_LEVEL_FIELDS) {
|
|
607
|
+
const value = entry[field];
|
|
608
|
+
if (typeof value !== "string")
|
|
609
|
+
continue;
|
|
610
|
+
const result = redactString(value, field);
|
|
611
|
+
next[field] = result.value;
|
|
612
|
+
reports.push(result.report);
|
|
613
|
+
}
|
|
589
614
|
if (typeof entry.message === "string") {
|
|
590
615
|
const result = redactString(entry.message, "message");
|
|
591
616
|
next.message = result.value;
|
|
@@ -622,11 +647,13 @@ function redactString(input, path = "$") {
|
|
|
622
647
|
for (const { label, pattern, replacement } of STRING_PATTERNS) {
|
|
623
648
|
let matched = false;
|
|
624
649
|
output = output.replace(pattern, (...args) => {
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if (
|
|
628
|
-
|
|
629
|
-
|
|
650
|
+
const original = args[0] ?? "";
|
|
651
|
+
const next = typeof replacement === "function" ? replacement(original, ...args.slice(1)) : replacement;
|
|
652
|
+
if (next !== original) {
|
|
653
|
+
matched = true;
|
|
654
|
+
replacements += 1;
|
|
655
|
+
}
|
|
656
|
+
return next;
|
|
630
657
|
});
|
|
631
658
|
if (matched)
|
|
632
659
|
fields.push(`${path}:${label}`);
|
|
@@ -669,7 +696,7 @@ function redactValue(input, path = "$", depth = 0) {
|
|
|
669
696
|
const reports = [];
|
|
670
697
|
for (const [key, value] of Object.entries(input)) {
|
|
671
698
|
const childPath = `${path}.${key}`;
|
|
672
|
-
if (
|
|
699
|
+
if (shouldRedactSensitiveKeyValue(key, value)) {
|
|
673
700
|
values[key] = REDACTED;
|
|
674
701
|
reports.push({ applied: true, fields: [childPath], replacements: 1 });
|
|
675
702
|
continue;
|
|
@@ -705,6 +732,24 @@ function isSensitiveFlag(value) {
|
|
|
705
732
|
return false;
|
|
706
733
|
return SENSITIVE_FLAG.test(normalized) || SENSITIVE_FLAG_NAME.test(normalized) || SENSITIVE_KEY.test(normalized.replace(/-/g, "_"));
|
|
707
734
|
}
|
|
735
|
+
function shouldRedactSensitiveKeyValue(key, value) {
|
|
736
|
+
if (value === null || value === undefined)
|
|
737
|
+
return false;
|
|
738
|
+
if (!SENSITIVE_KEY.test(key))
|
|
739
|
+
return false;
|
|
740
|
+
return !isKnownNonSecretCredentialMode(key, value);
|
|
741
|
+
}
|
|
742
|
+
function isKnownNonSecretCredentialMode(key, value) {
|
|
743
|
+
return key.toLowerCase() === "credentials" && typeof value === "string" && isKnownFetchCredentialMode(value);
|
|
744
|
+
}
|
|
745
|
+
function isKnownNonSecretCredentialAssignment(key, value) {
|
|
746
|
+
return key.toLowerCase() === "credentials" && isKnownFetchCredentialMode(value);
|
|
747
|
+
}
|
|
748
|
+
function isKnownFetchCredentialMode(value) {
|
|
749
|
+
const trimmed = value.trim();
|
|
750
|
+
const unquoted = trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'") ? trimmed.slice(1, -1) : trimmed;
|
|
751
|
+
return /^(?:include|omit|same-origin)$/i.test(unquoted);
|
|
752
|
+
}
|
|
708
753
|
|
|
709
754
|
// src/lib/ingest.ts
|
|
710
755
|
var ERROR_LEVELS = new Set(["warn", "error", "fatal"]);
|
|
@@ -712,7 +757,8 @@ function ingestLog(db, entry) {
|
|
|
712
757
|
return withEventStoreLock(db, () => ingestLogLocked(db, entry));
|
|
713
758
|
}
|
|
714
759
|
function ingestLogLocked(db, entry) {
|
|
715
|
-
const
|
|
760
|
+
const eventIdRedaction = typeof entry.id === "string" ? redactString(entry.id, "id") : null;
|
|
761
|
+
const eventId = entry.id ? eventIdRedaction?.report.applied ? createRedactedEventId(entry.id) : entry.id : createEventId();
|
|
716
762
|
const existing = db.prepare("SELECT * FROM logs WHERE id = ?").get(eventId);
|
|
717
763
|
if (existing)
|
|
718
764
|
return existing;
|
|
@@ -730,6 +776,14 @@ function ingestLogLocked(db, entry) {
|
|
|
730
776
|
};
|
|
731
777
|
const redacted = redactLogEntry(normalized);
|
|
732
778
|
const safeEntry = redacted.value;
|
|
779
|
+
if (eventIdRedaction?.report.applied) {
|
|
780
|
+
const report = mergeRedactionReports(eventIdRedaction.report, redacted.report);
|
|
781
|
+
safeEntry.metadata = {
|
|
782
|
+
...safeEntry.metadata ?? {},
|
|
783
|
+
redaction: redactionMetadata(report)
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
const safeSourceEventId = safeEntry.source_event_id ?? null;
|
|
733
787
|
const identity = extractIdentity(safeEntry);
|
|
734
788
|
const envelope = createLogEnvelope(safeEntry, eventId, eventTime, ingestTime, identity);
|
|
735
789
|
const write = appendRawEvent(db, envelope);
|
|
@@ -758,7 +812,7 @@ function ingestLogLocked(db, entry) {
|
|
|
758
812
|
indexRawEvent(db, {
|
|
759
813
|
event_id: eventId,
|
|
760
814
|
schema_version: envelope.schema_version,
|
|
761
|
-
source_event_id:
|
|
815
|
+
source_event_id: safeSourceEventId,
|
|
762
816
|
event_type: envelope.type,
|
|
763
817
|
event_time: eventTime,
|
|
764
818
|
ingest_time: ingestTime,
|
|
@@ -898,6 +952,10 @@ function stringMetadata(metadata, key) {
|
|
|
898
952
|
function createEventId() {
|
|
899
953
|
return randomBytes(16).toString("hex");
|
|
900
954
|
}
|
|
955
|
+
function createRedactedEventId(value) {
|
|
956
|
+
const digest = createHash("sha256").update(value).digest("hex").slice(0, 32);
|
|
957
|
+
return `log_redacted_${digest}`;
|
|
958
|
+
}
|
|
901
959
|
|
|
902
960
|
// src/lib/package-meta.ts
|
|
903
961
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -1282,7 +1340,7 @@ function clampNonNegativeInt2(value, fallback) {
|
|
|
1282
1340
|
}
|
|
1283
1341
|
|
|
1284
1342
|
// src/lib/universal-ingest.ts
|
|
1285
|
-
import { createHash, randomBytes as randomBytes2 } from "crypto";
|
|
1343
|
+
import { createHash as createHash2, randomBytes as randomBytes2 } from "crypto";
|
|
1286
1344
|
var UNIVERSAL_EVENT_TYPES = [
|
|
1287
1345
|
"log",
|
|
1288
1346
|
"exception",
|
|
@@ -1802,7 +1860,7 @@ function normalizeIsoTime(value, field) {
|
|
|
1802
1860
|
function deterministicSourceEventId(source, sourceEventId) {
|
|
1803
1861
|
if (!sourceEventId)
|
|
1804
1862
|
return;
|
|
1805
|
-
const digest =
|
|
1863
|
+
const digest = createHash2("sha256").update(source).update("\x00").update(sourceEventId).digest("hex").slice(0, 32);
|
|
1806
1864
|
return `evt_src_${digest}`;
|
|
1807
1865
|
}
|
|
1808
1866
|
function compactObject(value) {
|
package/dist/mcp/index.js
CHANGED
package/dist/server/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
startScheduler,
|
|
9
9
|
structuredLogPayloadToEntries,
|
|
10
10
|
validateStructuredLogReferences
|
|
11
|
-
} from "../index-
|
|
11
|
+
} from "../index-k9w7zfsv.js";
|
|
12
12
|
import {
|
|
13
13
|
countLogs
|
|
14
14
|
} from "../index-gcd14q2f.js";
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
updateAlertRule,
|
|
51
51
|
updateProject,
|
|
52
52
|
validateUniversalEventInput
|
|
53
|
-
} from "../index-
|
|
53
|
+
} from "../index-mx0f61s2.js";
|
|
54
54
|
import {
|
|
55
55
|
getDb,
|
|
56
56
|
getIssue,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/logs",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.30",
|
|
4
4
|
"description": "Log aggregation + browser script + headless page scanner + performance monitoring for AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,7 +19,10 @@
|
|
|
19
19
|
"logs-mcp": "./dist/mcp/index.js",
|
|
20
20
|
"logs-serve": "./dist/server/index.js"
|
|
21
21
|
},
|
|
22
|
-
"files": [
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"dashboard/dist"
|
|
25
|
+
],
|
|
23
26
|
"scripts": {
|
|
24
27
|
"build": "rm -rf dist && bun build src/cli/index.ts src/mcp/index.ts src/server/index.ts src/index.ts src/storage.ts --outdir dist --target bun --splitting --external playwright --external playwright-core --external electron --external chromium-bidi --external lighthouse",
|
|
25
28
|
"build:dashboard": "cd dashboard && bun run build",
|