residoo 0.4.10 → 0.4.12
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 +241 -449
- package/package.json +1 -1
- package/src/cli.js +12 -10
- package/src/color.js +36 -0
- package/src/patterns.js +39 -0
- package/src/report.js +26 -24
- package/src/rotation.js +50 -0
- package/src/scan.js +148 -16
- package/src/verify.js +77 -1
package/src/verify.js
CHANGED
|
@@ -305,6 +305,24 @@ function verifyGithubToken(token, opts) {
|
|
|
305
305
|
// dozens of apparent matches inside an unrelated real file that just
|
|
306
306
|
// happened to contain a lot of embedded base64 data. See patterns.js's own
|
|
307
307
|
// comment on flyio_bearer_token for the measured false-positive rate.
|
|
308
|
+
//
|
|
309
|
+
// A second, independent research pass (11 candidate vendors, each
|
|
310
|
+
// researched and then adversarially cross-checked by a separate reviewer
|
|
311
|
+
// before being trusted) added three more: Neon (verifyNeonKey), MongoDB
|
|
312
|
+
// Atlas Service Account credentials (verifyMongoDbAtlasCredential, a third
|
|
313
|
+
// paired vendor alongside AWS and PlanetScale), and PostHog
|
|
314
|
+
// (verifyPostHogKey). The other eight were rejected, each for a documented,
|
|
315
|
+
// vendor-specific reason rather than lack of trying:
|
|
316
|
+
// - Clerk, Auth0, Upstash, Turso, Railway, Segment, Algolia: no
|
|
317
|
+
// distinguishing, documented credential prefix could be confirmed from
|
|
318
|
+
// the vendor's own current docs (some have a prefix on one credential
|
|
319
|
+
// type but no working verify endpoint for it, or a prefix that isn't
|
|
320
|
+
// actually vendor-specific enough to trust).
|
|
321
|
+
// - Convex: the researcher's own first pass recommended adding it, but
|
|
322
|
+
// the adversarial reviewer refuted that recommendation on independent
|
|
323
|
+
// re-checking of the same sources — the exact reason this project runs
|
|
324
|
+
// research and verification as two separate, disagreeing passes rather
|
|
325
|
+
// than trusting one agent's first read of the docs.
|
|
308
326
|
|
|
309
327
|
function huggingfaceUrl() { return process.env.RESIDOO_TEST_HUGGINGFACE_API_URL || "https://huggingface.co/api/whoami-v2"; }
|
|
310
328
|
function sendgridUrl() { return process.env.RESIDOO_TEST_SENDGRID_API_URL || "https://api.sendgrid.com/v3/scopes"; }
|
|
@@ -428,6 +446,64 @@ function verifyPlanetScaleToken(id, secret, opts) {
|
|
|
428
446
|
return verifyByStatusCode("PlanetScale", planetscaleUrl(), () => ({ Authorization: `${id}:${secret}` }), opts);
|
|
429
447
|
}
|
|
430
448
|
|
|
449
|
+
function mongodbAtlasUrl() { return process.env.RESIDOO_TEST_MONGODB_ATLAS_API_URL || "https://cloud.mongodb.com/api/oauth/token"; }
|
|
450
|
+
/**
|
|
451
|
+
* MongoDB Atlas Service Account credentials: also a paired credential (like
|
|
452
|
+
* AWS and PlanetScale), but the actual verify call is an OAuth2 client-
|
|
453
|
+
* credentials token exchange, not a plain bearer-token GET -- POST, Basic-
|
|
454
|
+
* auth-encoded clientId:clientSecret, grant_type=client_credentials in the
|
|
455
|
+
* body -- so it needs its own function rather than verifyByStatusCode,
|
|
456
|
+
* which is GET-only.
|
|
457
|
+
*
|
|
458
|
+
* A bare 403 is NOT treated as "invalid" here: MongoDB Atlas's own docs
|
|
459
|
+
* confirm it also returns 403 when the caller's IP isn't on the service
|
|
460
|
+
* account's access list, which says nothing about whether the credential
|
|
461
|
+
* itself is still alive -- the same "real but out of scope" ambiguity
|
|
462
|
+
* GitLab/CircleCI/Airtable get elsewhere via activeExtra, except MongoDB
|
|
463
|
+
* signals it in the response BODY, not a separate status code. Only the
|
|
464
|
+
* documented invalid_client body is treated as a genuine "this credential
|
|
465
|
+
* is dead" signal; every other 403 stays "error", never a false "invalid" --
|
|
466
|
+
* the false-negative-in-the-dangerous-direction failure this whole module
|
|
467
|
+
* exists to avoid.
|
|
468
|
+
*/
|
|
469
|
+
async function verifyMongoDbAtlasCredential(clientId, clientSecret, { fetchFn = fetch, timeoutMs = DEFAULT_TIMEOUT_MS } = {}) {
|
|
470
|
+
let res;
|
|
471
|
+
try {
|
|
472
|
+
res = await fetchFn(mongodbAtlasUrl(), {
|
|
473
|
+
method: "POST",
|
|
474
|
+
headers: {
|
|
475
|
+
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`,
|
|
476
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
477
|
+
},
|
|
478
|
+
body: "grant_type=client_credentials",
|
|
479
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
480
|
+
});
|
|
481
|
+
} catch (e) {
|
|
482
|
+
return { status: "error", detail: `could not reach MongoDB Atlas (${sanitizeDetail(e && e.message)})` };
|
|
483
|
+
}
|
|
484
|
+
if (res.status === 200) return { status: "active", detail: "MongoDB Atlas accepted this service account" };
|
|
485
|
+
let body = null;
|
|
486
|
+
try {
|
|
487
|
+
body = await res.json();
|
|
488
|
+
} catch {
|
|
489
|
+
// Non-JSON body: fall through to the generic error below.
|
|
490
|
+
}
|
|
491
|
+
if (res.status === 403 && body && body.error === "invalid_client") {
|
|
492
|
+
return { status: "invalid", detail: "MongoDB Atlas rejected this service account (invalid_client)" };
|
|
493
|
+
}
|
|
494
|
+
return { status: "error", detail: `could not verify: HTTP ${res.status} from MongoDB Atlas` };
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function neonUrl() { return process.env.RESIDOO_TEST_NEON_API_URL || "https://console.neon.tech/api/v2/projects"; }
|
|
498
|
+
function verifyNeonKey(key, opts) {
|
|
499
|
+
return verifyByStatusCode("Neon", neonUrl(), () => ({ Authorization: `Bearer ${key}` }), opts);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function posthogUrl() { return process.env.RESIDOO_TEST_POSTHOG_API_URL || "https://us.posthog.com/api/users/@me/"; }
|
|
503
|
+
function verifyPostHogKey(key, opts) {
|
|
504
|
+
return verifyByStatusCode("PostHog", posthogUrl(), () => ({ Authorization: `Bearer ${key}` }), opts);
|
|
505
|
+
}
|
|
506
|
+
|
|
431
507
|
function vercelUrl() { return process.env.RESIDOO_TEST_VERCEL_API_URL || "https://api.vercel.com/v2/user"; }
|
|
432
508
|
function verifyVercelToken(token, opts) {
|
|
433
509
|
return verifyByStatusCode("Vercel", vercelUrl(), () => ({ Authorization: `Bearer ${token}` }), opts);
|
|
@@ -557,5 +633,5 @@ module.exports = {
|
|
|
557
633
|
verifyCircleciToken, verifyAirtableToken, verifyCloudflareToken, verifyHerokuKey,
|
|
558
634
|
verifyNetlifyToken, verifyLinearKey, verifyTelegramToken, verifyDiscordWebhook,
|
|
559
635
|
verifyPlanetScaleToken, verifyVercelToken, verifyCerebrasKey, verifyRenderKey,
|
|
560
|
-
verifyFlyioBearerToken,
|
|
636
|
+
verifyFlyioBearerToken, verifyMongoDbAtlasCredential, verifyNeonKey, verifyPostHogKey,
|
|
561
637
|
};
|