residoo 0.4.7 → 0.4.8
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/README.md +4 -4
- package/package.json +1 -1
- package/src/scan.js +46 -21
package/README.md
CHANGED
|
@@ -195,10 +195,10 @@ won't be built into the tool that writes it.
|
|
|
195
195
|
preview, never the real value, including in `--json` mode. A decoded or
|
|
196
196
|
rejoined secret is redacted exactly like a plain one.
|
|
197
197
|
- On an interactive terminal, prints who it is and where it lives before
|
|
198
|
-
scanning starts (`residoo v0.4.
|
|
198
|
+
scanning starts (`residoo v0.4.8 · find secrets your AI coding agent left
|
|
199
199
|
on disk` plus the repo URL), then a live spinner naming the current file
|
|
200
200
|
as it scans. Every report also opens with the exact version and timestamp
|
|
201
|
-
it was run with (`residoo v0.4.
|
|
201
|
+
it was run with (`residoo v0.4.8 · scanned 2026-01-01 12:00`; `--json`
|
|
202
202
|
carries the same as `residooVersion`/`scannedAt`), so a report pasted or
|
|
203
203
|
screenshotted later never leaves you guessing which build produced it.
|
|
204
204
|
When there are findings, the report closes with a "Next steps" pointer to
|
|
@@ -429,7 +429,7 @@ As a GitHub Action (this repository doubles as a composite action):
|
|
|
429
429
|
```yaml
|
|
430
430
|
steps:
|
|
431
431
|
- uses: actions/checkout@v4
|
|
432
|
-
- uses: dandovdub/residoo@v0.4.
|
|
432
|
+
- uses: dandovdub/residoo@v0.4.8
|
|
433
433
|
```
|
|
434
434
|
|
|
435
435
|
As a pre-commit hook:
|
|
@@ -437,7 +437,7 @@ As a pre-commit hook:
|
|
|
437
437
|
```yaml
|
|
438
438
|
repos:
|
|
439
439
|
- repo: https://github.com/dandovdub/residoo
|
|
440
|
-
rev: v0.4.
|
|
440
|
+
rev: v0.4.8
|
|
441
441
|
hooks:
|
|
442
442
|
- id: residoo
|
|
443
443
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "residoo",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
4
4
|
"description": "Find secrets leaking through your AI coding agent's session history. Zero network calls in the scan path, zero dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "CloudRoam (https://cloudroam.io)",
|
package/src/scan.js
CHANGED
|
@@ -641,26 +641,61 @@ async function scan({ sources, includeNoisy = false, includeSuppressed = false,
|
|
|
641
641
|
ref.verifiedDetail = result.detail;
|
|
642
642
|
}
|
|
643
643
|
};
|
|
644
|
+
const awsAvailable = pendingAwsVerifications.size === 0 || isAwsCliAvailable();
|
|
645
|
+
if (verify && anyPending) {
|
|
646
|
+
// One disclosure, not one per vendor: this used to print a full
|
|
647
|
+
// "this is a real network request..." paragraph for EACH vendor in
|
|
648
|
+
// turn, so a scan touching nine vendors put nine near-identical
|
|
649
|
+
// paragraphs on screen before any results — a wall of repeated
|
|
650
|
+
// boilerplate, caught live as bad UX. The safety-relevant fact (real
|
|
651
|
+
// outbound calls, using the exact matched value, one at a time) only
|
|
652
|
+
// needs saying once; per-vendor detail becomes a compact count table.
|
|
653
|
+
// Deliberately not gated on isTTY like the scan spinner: a script
|
|
654
|
+
// piping through a pager or into a log still needs this disclosure.
|
|
655
|
+
const rows = [];
|
|
656
|
+
if (pendingAwsVerifications.size > 0 && awsAvailable) {
|
|
657
|
+
rows.push(["AWS", pendingAwsVerifications.size]);
|
|
658
|
+
}
|
|
659
|
+
if (pendingPlanetScaleVerifications.size > 0) {
|
|
660
|
+
rows.push(["PlanetScale", pendingPlanetScaleVerifications.size]);
|
|
661
|
+
}
|
|
662
|
+
for (const [ruleId, byValue] of pendingSimpleVerifications) {
|
|
663
|
+
if (byValue.size === 0) continue;
|
|
664
|
+
// Vendor labels are consistently written "<Vendor>'s <endpoint
|
|
665
|
+
// description>" (see SIMPLE_VERIFY_VENDOR_LABEL above); take the
|
|
666
|
+
// part before "'s" rather than maintaining a second, parallel map
|
|
667
|
+
// of the same names.
|
|
668
|
+
const vendor = SIMPLE_VERIFY_VENDOR_LABEL[ruleId].split("'s ")[0];
|
|
669
|
+
rows.push([vendor, byValue.size]);
|
|
670
|
+
}
|
|
671
|
+
if (rows.length > 0) {
|
|
672
|
+
const width = Math.max(...rows.map(([label]) => label.length));
|
|
673
|
+
const table = rows.map(([label, count]) => ` ${label.padEnd(width)} ${count}`).join("\n");
|
|
674
|
+
process.stderr.write(
|
|
675
|
+
"residoo --verify: checking whether these credentials are still active. Real network " +
|
|
676
|
+
"calls, one per vendor's own API, using the exact value found in your transcript, one at " +
|
|
677
|
+
"a time. Nothing is cached or sent anywhere but the vendor that issued it.\n\n" +
|
|
678
|
+
table + "\n\n"
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
if (pendingAwsVerifications.size > 0 && !awsAvailable) {
|
|
682
|
+
process.stderr.write(
|
|
683
|
+
"residoo --verify: the aws CLI was not found on PATH, so the " +
|
|
684
|
+
`${pendingAwsVerifications.size} AWS credential(s) found in this scan could not be checked. ` +
|
|
685
|
+
"Install it (https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) to use --verify.\n"
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
644
689
|
if (verify && pendingAwsVerifications.size > 0) {
|
|
645
690
|
const applyPair = (refs, result) => {
|
|
646
691
|
for (const ref of refs) {
|
|
647
692
|
applyVerifyResult([ref.akiaFinding, ref.secretFinding], result);
|
|
648
693
|
}
|
|
649
694
|
};
|
|
650
|
-
if (!
|
|
651
|
-
process.stderr.write(
|
|
652
|
-
"residoo --verify: the aws CLI was not found on PATH, so the " +
|
|
653
|
-
`${pendingAwsVerifications.size} AWS credential(s) found in this scan could not be checked. ` +
|
|
654
|
-
"Install it (https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) to use --verify.\n"
|
|
655
|
-
);
|
|
695
|
+
if (!awsAvailable) {
|
|
656
696
|
const result = { status: "error", detail: "aws CLI not found on PATH" };
|
|
657
697
|
for (const { refs } of pendingAwsVerifications.values()) applyPair(refs, result);
|
|
658
698
|
} else {
|
|
659
|
-
process.stderr.write(
|
|
660
|
-
`residoo --verify: calling AWS sts:get-caller-identity for ${pendingAwsVerifications.size} ` +
|
|
661
|
-
"credential(s) found in this scan. This is a real network request to AWS, using the exact " +
|
|
662
|
-
"credential found in your transcript, one at a time.\n"
|
|
663
|
-
);
|
|
664
699
|
for (const [accessKeyValue, { secretValue, refs }] of pendingAwsVerifications) {
|
|
665
700
|
const result = verifyAwsCredential(accessKeyValue, secretValue);
|
|
666
701
|
applyPair(refs, result);
|
|
@@ -668,11 +703,6 @@ async function scan({ sources, includeNoisy = false, includeSuppressed = false,
|
|
|
668
703
|
}
|
|
669
704
|
}
|
|
670
705
|
if (verify && pendingPlanetScaleVerifications.size > 0) {
|
|
671
|
-
process.stderr.write(
|
|
672
|
-
`residoo --verify: calling PlanetScale's organizations endpoint for ${pendingPlanetScaleVerifications.size} ` +
|
|
673
|
-
"credential(s) found in this scan. This is a real network request to PlanetScale, using the exact " +
|
|
674
|
-
"credential found in your transcript, one at a time.\n"
|
|
675
|
-
);
|
|
676
706
|
for (const [secretValue, { idValue, refs }] of pendingPlanetScaleVerifications) {
|
|
677
707
|
const result = await verifyPlanetScaleToken(idValue, secretValue);
|
|
678
708
|
for (const ref of refs) applyVerifyResult([ref.secretFinding, ref.idFinding], result);
|
|
@@ -682,11 +712,6 @@ async function scan({ sources, includeNoisy = false, includeSuppressed = false,
|
|
|
682
712
|
for (const [ruleId, byValue] of pendingSimpleVerifications) {
|
|
683
713
|
if (byValue.size === 0) continue;
|
|
684
714
|
const verifyFn = SIMPLE_VERIFY_FNS[ruleId];
|
|
685
|
-
process.stderr.write(
|
|
686
|
-
`residoo --verify: calling ${SIMPLE_VERIFY_VENDOR_LABEL[ruleId]} for ${byValue.size} ` +
|
|
687
|
-
"token(s) found in this scan. This is a real network request, using the exact " +
|
|
688
|
-
"token found in your transcript, one at a time.\n"
|
|
689
|
-
);
|
|
690
715
|
for (const [value, { refs }] of byValue) {
|
|
691
716
|
const result = await verifyFn(value);
|
|
692
717
|
applyVerifyResult(refs, result);
|