logshield-cli 0.3.4 → 0.3.6
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 +61 -0
- package/dist/cli/index.cjs +43 -136
- package/package.json +5 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v0.3.6
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- `--summary` output now correctly written to stderr (safe for piping & redirects)
|
|
8
|
+
|
|
9
|
+
### Improved
|
|
10
|
+
|
|
11
|
+
- CLI documentation clarity
|
|
12
|
+
- Blog and docs structure consistency
|
|
13
|
+
- Shared `styles.css` and `main.js` across site pages
|
|
14
|
+
|
|
15
|
+
### Notes
|
|
16
|
+
|
|
17
|
+
- No breaking changes
|
|
18
|
+
|
|
19
|
+
## v0.3.5
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Corrected CLI version injection in built CJS output
|
|
24
|
+
- Ensured published npm package reflects actual CLI version
|
|
25
|
+
|
|
26
|
+
### Improved
|
|
27
|
+
|
|
28
|
+
- Deterministic `--dry-run` report formatting (aligned, CI-safe)
|
|
29
|
+
- Dry-run output now strictly non-contextual and stdout-only
|
|
30
|
+
|
|
31
|
+
### Notes
|
|
32
|
+
|
|
33
|
+
- No engine or rule behavior changes
|
|
34
|
+
- Pure CLI/build correctness release
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## v0.3.4
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- README CI badge link on npmjs.com
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## v0.3.3
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
|
|
50
|
+
- `--dry-run` mode to detect secrets without modifying output
|
|
51
|
+
- CI-friendly detection workflow (`--dry-run --fail-on-detect`)
|
|
52
|
+
|
|
53
|
+
### Improved
|
|
54
|
+
|
|
55
|
+
- CLI UX consistency
|
|
56
|
+
- README documentation clarity
|
|
57
|
+
|
|
58
|
+
### Notes
|
|
59
|
+
|
|
60
|
+
- No breaking changes
|
|
61
|
+
- Engine behavior unchanged
|
package/dist/cli/index.cjs
CHANGED
|
@@ -9,9 +9,6 @@ var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
|
9
9
|
var __esm = (fn, res) => function __init() {
|
|
10
10
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
11
|
};
|
|
12
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
13
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
14
|
-
};
|
|
15
12
|
var __export = (target, all) => {
|
|
16
13
|
for (var name in all)
|
|
17
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -83,6 +80,42 @@ var init_writeOutput = __esm({
|
|
|
83
80
|
}
|
|
84
81
|
});
|
|
85
82
|
|
|
83
|
+
// src/cli/summary.ts
|
|
84
|
+
var summary_exports = {};
|
|
85
|
+
__export(summary_exports, {
|
|
86
|
+
printSummary: () => printSummary
|
|
87
|
+
});
|
|
88
|
+
function printSummary(matches) {
|
|
89
|
+
if (!matches || matches.length === 0) {
|
|
90
|
+
process.stderr.write("logshield: no redactions detected\n");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const counter = {};
|
|
94
|
+
for (const m of matches) {
|
|
95
|
+
counter[m.rule] = (counter[m.rule] || 0) + 1;
|
|
96
|
+
}
|
|
97
|
+
const entries = Object.entries(counter).map(([rule, count]) => ({ rule, count })).sort((a, b) => {
|
|
98
|
+
if (b.count !== a.count) return b.count - a.count;
|
|
99
|
+
return a.rule.localeCompare(b.rule);
|
|
100
|
+
});
|
|
101
|
+
const maxLen = Math.max(...entries.map((e) => e.rule.length));
|
|
102
|
+
const total = matches.length;
|
|
103
|
+
const label = total === 1 ? "redaction" : "redactions";
|
|
104
|
+
process.stderr.write(`logshield summary: ${total} ${label}
|
|
105
|
+
`);
|
|
106
|
+
for (const { rule, count } of entries) {
|
|
107
|
+
process.stderr.write(
|
|
108
|
+
` ${rule.padEnd(maxLen)} x${count}
|
|
109
|
+
`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
var init_summary = __esm({
|
|
114
|
+
"src/cli/summary.ts"() {
|
|
115
|
+
"use strict";
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
86
119
|
// src/engine/applyRules.ts
|
|
87
120
|
function applyRules(input, rules, ctx, matches) {
|
|
88
121
|
let output = input;
|
|
@@ -349,144 +382,14 @@ var init_sanitizeLog = __esm({
|
|
|
349
382
|
}
|
|
350
383
|
});
|
|
351
384
|
|
|
352
|
-
// src/cli/summary.ts
|
|
353
|
-
var require_summary = __commonJS({
|
|
354
|
-
"src/cli/summary.ts"() {
|
|
355
|
-
"use strict";
|
|
356
|
-
var { readInput: readInput3 } = (init_readInput(), __toCommonJS(readInput_exports));
|
|
357
|
-
var { writeOutput: writeOutput3 } = (init_writeOutput(), __toCommonJS(writeOutput_exports));
|
|
358
|
-
var { printSummary: printSummary2 } = require_summary();
|
|
359
|
-
var { sanitizeLog: sanitizeLog3 } = (init_sanitizeLog(), __toCommonJS(sanitizeLog_exports));
|
|
360
|
-
var rawArgs2 = process.argv.slice(2).map((arg) => arg === "-h" ? "--help" : arg);
|
|
361
|
-
function getVersion2() {
|
|
362
|
-
return true ? "0.3.2" : "unknown";
|
|
363
|
-
}
|
|
364
|
-
function printHelp2() {
|
|
365
|
-
process.stdout.write(`Usage: logshield scan [file]
|
|
366
|
-
|
|
367
|
-
Behavior:
|
|
368
|
-
- If a file is provided, LogShield reads from that file
|
|
369
|
-
- If input is piped, LogShield reads from STDIN automatically
|
|
370
|
-
- --stdin is optional and only needed for explicitness
|
|
371
|
-
|
|
372
|
-
Options:
|
|
373
|
-
--strict Aggressive redaction
|
|
374
|
-
--dry-run Preview redactions without modifying output
|
|
375
|
-
--stdin Force read from STDIN
|
|
376
|
-
--fail-on-detect Exit with code 1 if any redaction occurs
|
|
377
|
-
--json JSON output
|
|
378
|
-
--summary Print summary
|
|
379
|
-
--version Print version
|
|
380
|
-
--help Show help
|
|
381
|
-
`);
|
|
382
|
-
}
|
|
383
|
-
function parseArgs2(args) {
|
|
384
|
-
const flags = /* @__PURE__ */ new Set();
|
|
385
|
-
const positionals = [];
|
|
386
|
-
for (const arg of args) {
|
|
387
|
-
if (arg.startsWith("--")) {
|
|
388
|
-
flags.add(arg);
|
|
389
|
-
} else {
|
|
390
|
-
positionals.push(arg);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
return { flags, positionals };
|
|
394
|
-
}
|
|
395
|
-
function isStdinPiped2() {
|
|
396
|
-
return !process.stdin.isTTY;
|
|
397
|
-
}
|
|
398
|
-
function renderDryRunReport2(matches) {
|
|
399
|
-
if (matches.length === 0) {
|
|
400
|
-
process.stdout.write("[DRY RUN] No redactions detected.\n");
|
|
401
|
-
process.stdout.write("No output was modified.\n");
|
|
402
|
-
return;
|
|
403
|
-
}
|
|
404
|
-
const counts = /* @__PURE__ */ new Map();
|
|
405
|
-
for (const m of matches) {
|
|
406
|
-
counts.set(m.rule, (counts.get(m.rule) || 0) + 1);
|
|
407
|
-
}
|
|
408
|
-
process.stdout.write("[DRY RUN] Detected redactions:\n");
|
|
409
|
-
const maxLen = Math.max(
|
|
410
|
-
...Array.from(counts.keys()).map((k) => k.length)
|
|
411
|
-
);
|
|
412
|
-
for (const [rule, count] of counts.entries()) {
|
|
413
|
-
process.stdout.write(
|
|
414
|
-
` ${rule.padEnd(maxLen)} x${count}
|
|
415
|
-
`
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
process.stdout.write("\n");
|
|
419
|
-
process.stdout.write("No output was modified.\n");
|
|
420
|
-
process.stdout.write("Use without --dry-run to apply.\n");
|
|
421
|
-
}
|
|
422
|
-
async function main2() {
|
|
423
|
-
if (rawArgs2.length === 0 || rawArgs2.includes("--help")) {
|
|
424
|
-
printHelp2();
|
|
425
|
-
process.exit(0);
|
|
426
|
-
}
|
|
427
|
-
if (rawArgs2.includes("--version")) {
|
|
428
|
-
console.log(`logshield v${getVersion2()}`);
|
|
429
|
-
process.exit(0);
|
|
430
|
-
}
|
|
431
|
-
const { flags, positionals } = parseArgs2(rawArgs2);
|
|
432
|
-
const command = positionals[0];
|
|
433
|
-
if (command !== "scan") {
|
|
434
|
-
process.stdout.write("Unknown command\n");
|
|
435
|
-
process.exit(1);
|
|
436
|
-
}
|
|
437
|
-
const file = positionals[1];
|
|
438
|
-
const strict = flags.has("--strict");
|
|
439
|
-
const json = flags.has("--json");
|
|
440
|
-
const summary = flags.has("--summary");
|
|
441
|
-
const stdinFlag = flags.has("--stdin");
|
|
442
|
-
const failOnDetect = flags.has("--fail-on-detect");
|
|
443
|
-
const dryRun = flags.has("--dry-run");
|
|
444
|
-
const stdinAuto = isStdinPiped2();
|
|
445
|
-
const useStdin = stdinFlag || stdinAuto;
|
|
446
|
-
if (useStdin && file) {
|
|
447
|
-
process.stdout.write("Cannot read from both STDIN and file\n");
|
|
448
|
-
process.exit(1);
|
|
449
|
-
}
|
|
450
|
-
if (dryRun && json) {
|
|
451
|
-
process.stdout.write("--dry-run cannot be used with --json\n");
|
|
452
|
-
process.exit(1);
|
|
453
|
-
}
|
|
454
|
-
try {
|
|
455
|
-
const input = await readInput3(useStdin ? void 0 : file);
|
|
456
|
-
const result = sanitizeLog3(input, { strict });
|
|
457
|
-
if (dryRun) {
|
|
458
|
-
renderDryRunReport2(result.matches);
|
|
459
|
-
if (failOnDetect && result.matches.length > 0) {
|
|
460
|
-
process.exit(1);
|
|
461
|
-
}
|
|
462
|
-
process.exit(0);
|
|
463
|
-
}
|
|
464
|
-
writeOutput3(result, { json });
|
|
465
|
-
if (summary) {
|
|
466
|
-
printSummary2(result.matches);
|
|
467
|
-
}
|
|
468
|
-
if (failOnDetect && result.matches.length > 0) {
|
|
469
|
-
process.exit(1);
|
|
470
|
-
}
|
|
471
|
-
process.exit(0);
|
|
472
|
-
} catch (err) {
|
|
473
|
-
process.stdout.write(err?.message || "Unexpected error");
|
|
474
|
-
process.stdout.write("\n");
|
|
475
|
-
process.exit(2);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
main2();
|
|
479
|
-
}
|
|
480
|
-
});
|
|
481
|
-
|
|
482
385
|
// src/cli/index.ts
|
|
483
386
|
var { readInput: readInput2 } = (init_readInput(), __toCommonJS(readInput_exports));
|
|
484
387
|
var { writeOutput: writeOutput2 } = (init_writeOutput(), __toCommonJS(writeOutput_exports));
|
|
485
|
-
var { printSummary } =
|
|
388
|
+
var { printSummary: printSummary2 } = (init_summary(), __toCommonJS(summary_exports));
|
|
486
389
|
var { sanitizeLog: sanitizeLog2 } = (init_sanitizeLog(), __toCommonJS(sanitizeLog_exports));
|
|
487
390
|
var rawArgs = process.argv.slice(2).map((arg) => arg === "-h" ? "--help" : arg);
|
|
488
391
|
function getVersion() {
|
|
489
|
-
return true ? "0.3.
|
|
392
|
+
return true ? "0.3.6" : "unknown";
|
|
490
393
|
}
|
|
491
394
|
function printHelp() {
|
|
492
395
|
process.stdout.write(`Usage: logshield scan [file]
|
|
@@ -586,6 +489,10 @@ async function main() {
|
|
|
586
489
|
process.stdout.write("--dry-run cannot be used with --json\n");
|
|
587
490
|
process.exit(1);
|
|
588
491
|
}
|
|
492
|
+
if (json && summary) {
|
|
493
|
+
process.stdout.write("--summary cannot be used with --json\n");
|
|
494
|
+
process.exit(1);
|
|
495
|
+
}
|
|
589
496
|
try {
|
|
590
497
|
const input = await readInput2(useStdin ? void 0 : file);
|
|
591
498
|
const result = sanitizeLog2(input, { strict });
|
|
@@ -598,7 +505,7 @@ async function main() {
|
|
|
598
505
|
}
|
|
599
506
|
writeOutput2(result, { json });
|
|
600
507
|
if (summary) {
|
|
601
|
-
|
|
508
|
+
printSummary2(result.matches);
|
|
602
509
|
}
|
|
603
510
|
if (failOnDetect && result.matches.length > 0) {
|
|
604
511
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "logshield-cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"license": "ISC",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
@@ -9,14 +9,17 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
11
11
|
"README.md",
|
|
12
|
+
"CHANGELOG.md",
|
|
12
13
|
"LICENSE"
|
|
13
14
|
],
|
|
14
15
|
"scripts": {
|
|
15
16
|
"build": "node scripts/build-cli.cjs",
|
|
16
17
|
"build:web": "vite build --outDir dist-web",
|
|
18
|
+
"build:blog": "node scripts/build-blog.js",
|
|
17
19
|
"dev:web": "vite",
|
|
18
20
|
"pretest": "npm run build",
|
|
19
|
-
"test": "vitest"
|
|
21
|
+
"test": "vitest",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
20
23
|
},
|
|
21
24
|
"devDependencies": {
|
|
22
25
|
"@types/node": "^25.0.3",
|