circle-ir 3.165.0 → 3.166.1
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/analysis/entry-point-detection.d.ts +28 -1
- package/dist/analysis/entry-point-detection.d.ts.map +1 -1
- package/dist/analysis/entry-point-detection.js +619 -13
- package/dist/analysis/entry-point-detection.js.map +1 -1
- package/dist/analysis/passes/interprocedural-pass.d.ts.map +1 -1
- package/dist/analysis/passes/interprocedural-pass.js +7 -1
- package/dist/analysis/passes/interprocedural-pass.js.map +1 -1
- package/dist/analysis/require-entry-path.d.ts +6 -2
- package/dist/analysis/require-entry-path.d.ts.map +1 -1
- package/dist/analysis/require-entry-path.js +88 -11
- package/dist/analysis/require-entry-path.js.map +1 -1
- package/dist/browser/circle-ir.js +435 -3
- package/package.json +1 -1
|
@@ -20148,9 +20148,28 @@ function methodIsSupertypeLifecycleEntryPoint(method, enclosingType) {
|
|
|
20148
20148
|
return false;
|
|
20149
20149
|
}
|
|
20150
20150
|
function classifyEntryPointTier(method, enclosingType, ctx) {
|
|
20151
|
-
const language = (ctx.language ?? "").toLowerCase();
|
|
20152
|
-
if (language !== "java") return "TIER_UNKNOWN";
|
|
20153
20151
|
if (!method) return "TIER_UNKNOWN";
|
|
20152
|
+
const language = (ctx.language ?? "").toLowerCase();
|
|
20153
|
+
switch (language) {
|
|
20154
|
+
case "java":
|
|
20155
|
+
return classifyJavaEntryPoint(method, enclosingType);
|
|
20156
|
+
case "python":
|
|
20157
|
+
return classifyPythonEntryPoint(method, enclosingType, ctx);
|
|
20158
|
+
case "javascript":
|
|
20159
|
+
case "typescript":
|
|
20160
|
+
case "tsx":
|
|
20161
|
+
case "jsx":
|
|
20162
|
+
return classifyJsTsEntryPoint(method, enclosingType, ctx);
|
|
20163
|
+
case "go":
|
|
20164
|
+
return classifyGoEntryPoint(method, enclosingType, ctx);
|
|
20165
|
+
case "bash":
|
|
20166
|
+
case "shell":
|
|
20167
|
+
return classifyBashEntryPoint(method, enclosingType, ctx);
|
|
20168
|
+
default:
|
|
20169
|
+
return "TIER_UNKNOWN";
|
|
20170
|
+
}
|
|
20171
|
+
}
|
|
20172
|
+
function classifyJavaEntryPoint(method, enclosingType) {
|
|
20154
20173
|
if (classShapeIsLibraryFacade(enclosingType)) {
|
|
20155
20174
|
return "TIER_3_LIBRARY_API";
|
|
20156
20175
|
}
|
|
@@ -20174,6 +20193,413 @@ function shouldGateInterproceduralParam(sourceType, enclosingMethod, enclosingTy
|
|
|
20174
20193
|
const tier = classifyEntryPointTier(enclosingMethod, enclosingType, ctx);
|
|
20175
20194
|
return tier === "TIER_3_LIBRARY_API";
|
|
20176
20195
|
}
|
|
20196
|
+
var POLYGLOT_LIBRARY_PATH_FRAGMENTS = [
|
|
20197
|
+
"/lib/",
|
|
20198
|
+
"/libapi/",
|
|
20199
|
+
"/libs/",
|
|
20200
|
+
"/utils/",
|
|
20201
|
+
"/util/",
|
|
20202
|
+
"/helpers/",
|
|
20203
|
+
"/helper/",
|
|
20204
|
+
"/interop/",
|
|
20205
|
+
"/vendor/",
|
|
20206
|
+
"/vendored/",
|
|
20207
|
+
"/node_modules/",
|
|
20208
|
+
"/dist/",
|
|
20209
|
+
"/build/",
|
|
20210
|
+
"/_internal/",
|
|
20211
|
+
"/__tests__/",
|
|
20212
|
+
"/tests/",
|
|
20213
|
+
"/test/",
|
|
20214
|
+
"/testing/",
|
|
20215
|
+
"/spec/",
|
|
20216
|
+
"/specs/",
|
|
20217
|
+
"/fixtures/",
|
|
20218
|
+
"/mocks/",
|
|
20219
|
+
"/__mocks__/"
|
|
20220
|
+
];
|
|
20221
|
+
var POLYGLOT_TEST_FILE_MARKERS = [
|
|
20222
|
+
".test.",
|
|
20223
|
+
".spec.",
|
|
20224
|
+
"_test.",
|
|
20225
|
+
"_spec.",
|
|
20226
|
+
".tests."
|
|
20227
|
+
];
|
|
20228
|
+
function pathLooksLikeLibraryOrTest(filePath) {
|
|
20229
|
+
if (!filePath) return false;
|
|
20230
|
+
const normalized = filePath.replace(/\\/g, "/").toLowerCase();
|
|
20231
|
+
const padded = `/${normalized}/`;
|
|
20232
|
+
for (const frag of POLYGLOT_LIBRARY_PATH_FRAGMENTS) {
|
|
20233
|
+
if (padded.includes(frag)) return true;
|
|
20234
|
+
}
|
|
20235
|
+
const slash = normalized.lastIndexOf("/");
|
|
20236
|
+
const base = slash >= 0 ? normalized.slice(slash + 1) : normalized;
|
|
20237
|
+
for (const marker of POLYGLOT_TEST_FILE_MARKERS) {
|
|
20238
|
+
if (base.includes(marker)) return true;
|
|
20239
|
+
}
|
|
20240
|
+
return false;
|
|
20241
|
+
}
|
|
20242
|
+
var PYTHON_TIER_1_DECORATOR_NAMES = /* @__PURE__ */ new Set([
|
|
20243
|
+
// Flask
|
|
20244
|
+
"route",
|
|
20245
|
+
"get",
|
|
20246
|
+
"post",
|
|
20247
|
+
"put",
|
|
20248
|
+
"delete",
|
|
20249
|
+
"patch",
|
|
20250
|
+
"options",
|
|
20251
|
+
"head",
|
|
20252
|
+
"before_request",
|
|
20253
|
+
"after_request",
|
|
20254
|
+
"errorhandler",
|
|
20255
|
+
"teardown_request",
|
|
20256
|
+
// FastAPI
|
|
20257
|
+
"websocket",
|
|
20258
|
+
"websocket_route",
|
|
20259
|
+
"api_route",
|
|
20260
|
+
"middleware",
|
|
20261
|
+
// Django
|
|
20262
|
+
"login_required",
|
|
20263
|
+
"csrf_exempt",
|
|
20264
|
+
"csrf_protect",
|
|
20265
|
+
"require_http_methods",
|
|
20266
|
+
"require_GET",
|
|
20267
|
+
"require_POST",
|
|
20268
|
+
"require_safe",
|
|
20269
|
+
"permission_required",
|
|
20270
|
+
"user_passes_test",
|
|
20271
|
+
"staff_member_required",
|
|
20272
|
+
"api_view",
|
|
20273
|
+
"action",
|
|
20274
|
+
"detail_route",
|
|
20275
|
+
"list_route",
|
|
20276
|
+
"renderer_classes",
|
|
20277
|
+
"authentication_classes",
|
|
20278
|
+
"permission_classes",
|
|
20279
|
+
// Click / Typer
|
|
20280
|
+
"command",
|
|
20281
|
+
"group",
|
|
20282
|
+
// Celery / RQ / dramatiq
|
|
20283
|
+
"task",
|
|
20284
|
+
"shared_task",
|
|
20285
|
+
"periodic_task",
|
|
20286
|
+
"actor",
|
|
20287
|
+
// aiohttp
|
|
20288
|
+
"view",
|
|
20289
|
+
// pytest fixtures ARE library callback surfaces (test framework calls
|
|
20290
|
+
// them), so we mark them TIER_1 too — a taint sink inside a fixture
|
|
20291
|
+
// is genuinely reachable when the test runs.
|
|
20292
|
+
"fixture"
|
|
20293
|
+
]);
|
|
20294
|
+
function classifyPythonEntryPoint(method, enclosingType, ctx) {
|
|
20295
|
+
if (pathLooksLikeLibraryOrTest(ctx.filePath)) {
|
|
20296
|
+
return "TIER_3_LIBRARY_API";
|
|
20297
|
+
}
|
|
20298
|
+
if (pythonDecoratorLooksTier1(method.annotations)) {
|
|
20299
|
+
return "TIER_1_ENTRY_POINT";
|
|
20300
|
+
}
|
|
20301
|
+
if (methodIsRuntimeRegistrationHandler(method, ctx.runtimeRegistrations)) {
|
|
20302
|
+
return "TIER_1_ENTRY_POINT";
|
|
20303
|
+
}
|
|
20304
|
+
if (method.name === "main" && !enclosingType) {
|
|
20305
|
+
return "TIER_1_ENTRY_POINT";
|
|
20306
|
+
}
|
|
20307
|
+
if (method.name === "main" && enclosingType && looksLikeModuleType(enclosingType)) {
|
|
20308
|
+
return "TIER_1_ENTRY_POINT";
|
|
20309
|
+
}
|
|
20310
|
+
if (method.name.startsWith("_") && !method.name.startsWith("__")) {
|
|
20311
|
+
return "TIER_3_LIBRARY_API";
|
|
20312
|
+
}
|
|
20313
|
+
return "TIER_UNKNOWN";
|
|
20314
|
+
}
|
|
20315
|
+
function pythonDecoratorLooksTier1(annotations) {
|
|
20316
|
+
if (!annotations || annotations.length === 0) return false;
|
|
20317
|
+
for (const raw of annotations) {
|
|
20318
|
+
let name2 = raw.replace(/^@/, "").replace(/[<(].*$/, "").trim();
|
|
20319
|
+
if (!name2) continue;
|
|
20320
|
+
const dot = name2.lastIndexOf(".");
|
|
20321
|
+
if (dot >= 0) name2 = name2.slice(dot + 1);
|
|
20322
|
+
if (PYTHON_TIER_1_DECORATOR_NAMES.has(name2)) return true;
|
|
20323
|
+
}
|
|
20324
|
+
return false;
|
|
20325
|
+
}
|
|
20326
|
+
function looksLikeModuleType(t) {
|
|
20327
|
+
return !t.extends && (!t.implements || t.implements.length === 0) && (!t.annotations || t.annotations.length === 0);
|
|
20328
|
+
}
|
|
20329
|
+
var JSTS_TIER_1_METHOD_DECORATORS = /* @__PURE__ */ new Set([
|
|
20330
|
+
// NestJS HTTP method decorators
|
|
20331
|
+
"Get",
|
|
20332
|
+
"Post",
|
|
20333
|
+
"Put",
|
|
20334
|
+
"Delete",
|
|
20335
|
+
"Patch",
|
|
20336
|
+
"Head",
|
|
20337
|
+
"Options",
|
|
20338
|
+
"All",
|
|
20339
|
+
// NestJS WebSocket
|
|
20340
|
+
"SubscribeMessage",
|
|
20341
|
+
"MessageBody",
|
|
20342
|
+
"ConnectedSocket",
|
|
20343
|
+
// NestJS microservices / event
|
|
20344
|
+
"EventPattern",
|
|
20345
|
+
"MessagePattern",
|
|
20346
|
+
"GrpcMethod",
|
|
20347
|
+
"GrpcStreamMethod",
|
|
20348
|
+
// Angular / other DI-registered handler hooks
|
|
20349
|
+
"HostListener"
|
|
20350
|
+
]);
|
|
20351
|
+
var JSTS_TIER_1_CLASS_DECORATORS = /* @__PURE__ */ new Set([
|
|
20352
|
+
"Controller",
|
|
20353
|
+
"RestController",
|
|
20354
|
+
"Resolver",
|
|
20355
|
+
"WebSocketGateway",
|
|
20356
|
+
"Gateway"
|
|
20357
|
+
]);
|
|
20358
|
+
var JSTS_TIER_1_MODULE_EXPORTS = /* @__PURE__ */ new Set([
|
|
20359
|
+
// AWS Lambda / Google Cloud Functions / Netlify / Vercel
|
|
20360
|
+
"handler",
|
|
20361
|
+
// Next.js App Router — HTTP method exports
|
|
20362
|
+
"GET",
|
|
20363
|
+
"POST",
|
|
20364
|
+
"PUT",
|
|
20365
|
+
"DELETE",
|
|
20366
|
+
"PATCH",
|
|
20367
|
+
"HEAD",
|
|
20368
|
+
"OPTIONS",
|
|
20369
|
+
// SvelteKit / Remix
|
|
20370
|
+
"load",
|
|
20371
|
+
"action",
|
|
20372
|
+
// Next.js middleware
|
|
20373
|
+
"middleware"
|
|
20374
|
+
]);
|
|
20375
|
+
function classifyJsTsEntryPoint(method, enclosingType, ctx) {
|
|
20376
|
+
if (pathLooksLikeLibraryOrTest(ctx.filePath)) {
|
|
20377
|
+
return "TIER_3_LIBRARY_API";
|
|
20378
|
+
}
|
|
20379
|
+
if (annotationsInclude(method.annotations, JSTS_TIER_1_METHOD_DECORATORS)) {
|
|
20380
|
+
return "TIER_1_ENTRY_POINT";
|
|
20381
|
+
}
|
|
20382
|
+
if (enclosingType && annotationsInclude(enclosingType.annotations, JSTS_TIER_1_CLASS_DECORATORS)) {
|
|
20383
|
+
return "TIER_1_ENTRY_POINT";
|
|
20384
|
+
}
|
|
20385
|
+
if (methodIsRuntimeRegistrationHandler(method, ctx.runtimeRegistrations)) {
|
|
20386
|
+
return "TIER_1_ENTRY_POINT";
|
|
20387
|
+
}
|
|
20388
|
+
if (JSTS_TIER_1_MODULE_EXPORTS.has(method.name) && (!enclosingType || looksLikeModuleType(enclosingType))) {
|
|
20389
|
+
return "TIER_1_ENTRY_POINT";
|
|
20390
|
+
}
|
|
20391
|
+
if (method.name === "main" && (!enclosingType || looksLikeModuleType(enclosingType))) {
|
|
20392
|
+
return "TIER_1_ENTRY_POINT";
|
|
20393
|
+
}
|
|
20394
|
+
return "TIER_UNKNOWN";
|
|
20395
|
+
}
|
|
20396
|
+
var GO_HTTP_REGISTRAR_METHODS = /* @__PURE__ */ new Set([
|
|
20397
|
+
// net/http
|
|
20398
|
+
"HandleFunc",
|
|
20399
|
+
"Handle",
|
|
20400
|
+
// gorilla/mux, chi, echo, gin
|
|
20401
|
+
"GET",
|
|
20402
|
+
"POST",
|
|
20403
|
+
"PUT",
|
|
20404
|
+
"DELETE",
|
|
20405
|
+
"PATCH",
|
|
20406
|
+
"HEAD",
|
|
20407
|
+
"OPTIONS",
|
|
20408
|
+
"Any",
|
|
20409
|
+
"Get",
|
|
20410
|
+
"Post",
|
|
20411
|
+
"Put",
|
|
20412
|
+
"Delete",
|
|
20413
|
+
"Patch",
|
|
20414
|
+
"Head",
|
|
20415
|
+
"Options",
|
|
20416
|
+
// gorilla/chi/gin sub-routers
|
|
20417
|
+
"Route",
|
|
20418
|
+
"Mount",
|
|
20419
|
+
"Method"
|
|
20420
|
+
]);
|
|
20421
|
+
var GO_HTTP_REGISTRAR_RECEIVERS = [
|
|
20422
|
+
"http",
|
|
20423
|
+
// net/http.HandleFunc
|
|
20424
|
+
"mux",
|
|
20425
|
+
// gorilla/mux
|
|
20426
|
+
"router",
|
|
20427
|
+
// chi/gin/gorilla common
|
|
20428
|
+
"r",
|
|
20429
|
+
// gin/chi convention
|
|
20430
|
+
"e",
|
|
20431
|
+
// echo convention
|
|
20432
|
+
"g",
|
|
20433
|
+
// gin group convention
|
|
20434
|
+
"app",
|
|
20435
|
+
// fiber convention
|
|
20436
|
+
"engine",
|
|
20437
|
+
// gin engine convention
|
|
20438
|
+
"srv",
|
|
20439
|
+
"server"
|
|
20440
|
+
];
|
|
20441
|
+
function classifyGoEntryPoint(method, enclosingType, ctx) {
|
|
20442
|
+
if (pathLooksLikeLibraryOrTest(ctx.filePath)) {
|
|
20443
|
+
return "TIER_3_LIBRARY_API";
|
|
20444
|
+
}
|
|
20445
|
+
if (ctx.filePath && ctx.filePath.toLowerCase().endsWith("_test.go")) {
|
|
20446
|
+
return "TIER_3_LIBRARY_API";
|
|
20447
|
+
}
|
|
20448
|
+
if (method.name === "main" && enclosingType?.package === "main") {
|
|
20449
|
+
return "TIER_1_ENTRY_POINT";
|
|
20450
|
+
}
|
|
20451
|
+
if (methodHasNetHttpHandlerSignature(method)) {
|
|
20452
|
+
return "TIER_1_ENTRY_POINT";
|
|
20453
|
+
}
|
|
20454
|
+
if (methodLooksLikeGrpcHandler(method, enclosingType)) {
|
|
20455
|
+
return "TIER_1_ENTRY_POINT";
|
|
20456
|
+
}
|
|
20457
|
+
if (methodIsRegisteredByGoHttpFramework(method, ctx.calls)) {
|
|
20458
|
+
return "TIER_1_ENTRY_POINT";
|
|
20459
|
+
}
|
|
20460
|
+
return "TIER_UNKNOWN";
|
|
20461
|
+
}
|
|
20462
|
+
function methodHasNetHttpHandlerSignature(method) {
|
|
20463
|
+
const params = method.parameters ?? [];
|
|
20464
|
+
if (params.length !== 2) return false;
|
|
20465
|
+
const p0 = normalizeGoType(params[0]?.type ?? "");
|
|
20466
|
+
const p1 = normalizeGoType(params[1]?.type ?? "");
|
|
20467
|
+
const p0IsWriter = p0.includes("http.ResponseWriter") || p0.endsWith("ResponseWriter");
|
|
20468
|
+
const p1IsRequest = p1.includes("http.Request") || p1.endsWith("*Request") || p1.endsWith("Request");
|
|
20469
|
+
return p0IsWriter && p1IsRequest;
|
|
20470
|
+
}
|
|
20471
|
+
function methodLooksLikeGrpcHandler(method, enclosingType) {
|
|
20472
|
+
if (!enclosingType) return false;
|
|
20473
|
+
const params = method.parameters ?? [];
|
|
20474
|
+
if (params.length < 2) return false;
|
|
20475
|
+
const p0 = normalizeGoType(params[0]?.type ?? "");
|
|
20476
|
+
if (!p0.includes("context.Context") && !p0.endsWith("Context")) return false;
|
|
20477
|
+
const typeName = enclosingType.name ?? "";
|
|
20478
|
+
if (!/(Server|Service|Handler)$/.test(typeName)) return false;
|
|
20479
|
+
return true;
|
|
20480
|
+
}
|
|
20481
|
+
function normalizeGoType(t) {
|
|
20482
|
+
return t.replace(/\s+/g, "").replace(/^\*+/, "");
|
|
20483
|
+
}
|
|
20484
|
+
function methodIsRegisteredByGoHttpFramework(method, calls) {
|
|
20485
|
+
if (!calls || calls.length === 0) return false;
|
|
20486
|
+
for (const call of calls) {
|
|
20487
|
+
if (!GO_HTTP_REGISTRAR_METHODS.has(call.method_name)) continue;
|
|
20488
|
+
const receiver = call.receiver ?? "";
|
|
20489
|
+
if (!goRegistrarReceiverMatches(receiver)) continue;
|
|
20490
|
+
const args2 = call.arguments ?? [];
|
|
20491
|
+
for (const arg of args2) {
|
|
20492
|
+
const expr = (arg.expression ?? arg.variable ?? arg.value ?? "").trim();
|
|
20493
|
+
if (!expr) continue;
|
|
20494
|
+
const short = expr.slice(expr.lastIndexOf(".") + 1);
|
|
20495
|
+
if (short === method.name) return true;
|
|
20496
|
+
}
|
|
20497
|
+
}
|
|
20498
|
+
return false;
|
|
20499
|
+
}
|
|
20500
|
+
function goRegistrarReceiverMatches(receiver) {
|
|
20501
|
+
const trimmed = receiver.trim();
|
|
20502
|
+
if (!trimmed) return false;
|
|
20503
|
+
for (const target of GO_HTTP_REGISTRAR_RECEIVERS) {
|
|
20504
|
+
if (trimmed === target) return true;
|
|
20505
|
+
if (trimmed.endsWith(`.${target}`)) return true;
|
|
20506
|
+
}
|
|
20507
|
+
return false;
|
|
20508
|
+
}
|
|
20509
|
+
var BASH_POSITIONAL_TOKENS = [
|
|
20510
|
+
"$1",
|
|
20511
|
+
"$2",
|
|
20512
|
+
"$3",
|
|
20513
|
+
"$4",
|
|
20514
|
+
"$5",
|
|
20515
|
+
"$6",
|
|
20516
|
+
"$7",
|
|
20517
|
+
"$8",
|
|
20518
|
+
"$9",
|
|
20519
|
+
"$@",
|
|
20520
|
+
"$*",
|
|
20521
|
+
"$#",
|
|
20522
|
+
"${1",
|
|
20523
|
+
"${2",
|
|
20524
|
+
"${3",
|
|
20525
|
+
"${@",
|
|
20526
|
+
"getopts"
|
|
20527
|
+
];
|
|
20528
|
+
var BASH_LIBRARY_FILENAME_PREFIXES = [
|
|
20529
|
+
"benign_",
|
|
20530
|
+
"safe_",
|
|
20531
|
+
"lib_",
|
|
20532
|
+
"common_",
|
|
20533
|
+
"helpers_",
|
|
20534
|
+
"_"
|
|
20535
|
+
];
|
|
20536
|
+
function classifyBashEntryPoint(method, enclosingType, ctx) {
|
|
20537
|
+
if (pathLooksLikeLibraryOrTest(ctx.filePath)) {
|
|
20538
|
+
return "TIER_3_LIBRARY_API";
|
|
20539
|
+
}
|
|
20540
|
+
if (bashFilenameLooksLikeLibrary(ctx.filePath)) {
|
|
20541
|
+
return "TIER_3_LIBRARY_API";
|
|
20542
|
+
}
|
|
20543
|
+
if (method.name === "main") {
|
|
20544
|
+
return "TIER_1_ENTRY_POINT";
|
|
20545
|
+
}
|
|
20546
|
+
if (methodConsumesPositionalArgs(method, ctx.calls)) {
|
|
20547
|
+
return "TIER_1_ENTRY_POINT";
|
|
20548
|
+
}
|
|
20549
|
+
if (enclosingType && looksLikeModuleType(enclosingType) && fileHasPositionalArgUse(ctx.calls)) {
|
|
20550
|
+
return "TIER_1_ENTRY_POINT";
|
|
20551
|
+
}
|
|
20552
|
+
return "TIER_UNKNOWN";
|
|
20553
|
+
}
|
|
20554
|
+
function bashFilenameLooksLikeLibrary(filePath) {
|
|
20555
|
+
if (!filePath) return false;
|
|
20556
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
20557
|
+
const slash = normalized.lastIndexOf("/");
|
|
20558
|
+
const base = (slash >= 0 ? normalized.slice(slash + 1) : normalized).toLowerCase();
|
|
20559
|
+
for (const prefix of BASH_LIBRARY_FILENAME_PREFIXES) {
|
|
20560
|
+
if (base.startsWith(prefix)) return true;
|
|
20561
|
+
}
|
|
20562
|
+
if (base.includes(".test.") || base.includes("_test.")) return true;
|
|
20563
|
+
return false;
|
|
20564
|
+
}
|
|
20565
|
+
function methodConsumesPositionalArgs(method, calls) {
|
|
20566
|
+
if (!calls || calls.length === 0) return false;
|
|
20567
|
+
for (const call of calls) {
|
|
20568
|
+
if (call.location.line < method.start_line) continue;
|
|
20569
|
+
if (call.location.line > method.end_line) continue;
|
|
20570
|
+
if (callHasPositionalToken(call)) return true;
|
|
20571
|
+
}
|
|
20572
|
+
return false;
|
|
20573
|
+
}
|
|
20574
|
+
function fileHasPositionalArgUse(calls) {
|
|
20575
|
+
if (!calls || calls.length === 0) return false;
|
|
20576
|
+
for (const call of calls) {
|
|
20577
|
+
if (callHasPositionalToken(call)) return true;
|
|
20578
|
+
}
|
|
20579
|
+
return false;
|
|
20580
|
+
}
|
|
20581
|
+
function callHasPositionalToken(call) {
|
|
20582
|
+
for (const arg of call.arguments ?? []) {
|
|
20583
|
+
const expr = arg.expression ?? arg.variable ?? arg.value ?? "";
|
|
20584
|
+
for (const tok of BASH_POSITIONAL_TOKENS) {
|
|
20585
|
+
if (expr.includes(tok)) return true;
|
|
20586
|
+
}
|
|
20587
|
+
}
|
|
20588
|
+
if (call.method_name === "getopts") return true;
|
|
20589
|
+
return false;
|
|
20590
|
+
}
|
|
20591
|
+
function methodIsRuntimeRegistrationHandler(method, regs) {
|
|
20592
|
+
if (!regs || regs.length === 0) return false;
|
|
20593
|
+
for (const reg of regs) {
|
|
20594
|
+
if (reg.kind !== "http_route" && reg.kind !== "decorator" && reg.kind !== "event_listener" && reg.kind !== "middleware") {
|
|
20595
|
+
continue;
|
|
20596
|
+
}
|
|
20597
|
+
const handlerName = reg.handler?.name;
|
|
20598
|
+
if (!handlerName) continue;
|
|
20599
|
+
if (handlerName === method.name) return true;
|
|
20600
|
+
}
|
|
20601
|
+
return false;
|
|
20602
|
+
}
|
|
20177
20603
|
|
|
20178
20604
|
// src/analysis/project-profile-transform.ts
|
|
20179
20605
|
var DOWNGRADE_ELIGIBLE_RULE_IDS = /* @__PURE__ */ new Set([
|
|
@@ -33145,7 +33571,13 @@ var InterproceduralPass = class {
|
|
|
33145
33571
|
source.type,
|
|
33146
33572
|
enclosing?.method,
|
|
33147
33573
|
enclosing?.type,
|
|
33148
|
-
{
|
|
33574
|
+
{
|
|
33575
|
+
language,
|
|
33576
|
+
types: graph.ir.types,
|
|
33577
|
+
filePath: graph.ir.meta.file,
|
|
33578
|
+
calls: graph.ir.calls,
|
|
33579
|
+
runtimeRegistrations: graph.ir.runtime_registrations ?? null
|
|
33580
|
+
}
|
|
33149
33581
|
)) {
|
|
33150
33582
|
continue;
|
|
33151
33583
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.166.1",
|
|
4
4
|
"description": "High-performance Static Application Security Testing (SAST) library for detecting security vulnerabilities through taint analysis",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|