Skip to content

Commit 5249e84

Browse files
committed
JS: Type track spanner model
1 parent d225715 commit 5249e84

File tree

4 files changed

+77
-22
lines changed

4 files changed

+77
-22
lines changed

javascript/ql/src/semmle/javascript/frameworks/SQL.qll

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -439,25 +439,79 @@ private module Spanner {
439439
result = DataFlow::moduleMember("@google-cloud/spanner", "Spanner")
440440
}
441441

442-
/**
443-
* Gets a node that refers to an instance of the `Database` class.
444-
*/
442+
/** Gets a data flow node referring to the result of `Spanner()` or `new Spanner()`. */
443+
private DataFlow::SourceNode spannerNew(DataFlow::TypeTracker t) {
444+
t.start() and
445+
result = spanner().getAnInvocation()
446+
or
447+
exists(DataFlow::TypeTracker t2 |
448+
result = spannerNew(t2).track(t2, t)
449+
)
450+
}
451+
452+
/** Gets a data flow node referring to the result of `Spanner()` or `new Spanner()`. */
453+
DataFlow::SourceNode spannerNew() {
454+
result = spannerNew(DataFlow::TypeTracker::end())
455+
}
456+
457+
/** Gets a data flow node referring to the result of `.instance()`. */
458+
private DataFlow::SourceNode instance(DataFlow::TypeTracker t) {
459+
t.start() and
460+
result = spannerNew().getAMethodCall("instance")
461+
or
462+
exists(DataFlow::TypeTracker t2 |
463+
result = instance(t2).track(t2, t)
464+
)
465+
}
466+
467+
/** Gets a data flow node referring to the result of `.instance()`. */
468+
DataFlow::SourceNode instance() {
469+
result = instance(DataFlow::TypeTracker::end())
470+
}
471+
472+
/** Gets a node that refers to an instance of the `Database` class. */
473+
private DataFlow::SourceNode database(DataFlow::TypeTracker t) {
474+
t.start() and
475+
result = instance().getAMethodCall("database")
476+
or
477+
exists(DataFlow::TypeTracker t2 |
478+
result = database(t2).track(t2, t)
479+
)
480+
}
481+
482+
/** Gets a node that refers to an instance of the `Database` class. */
445483
DataFlow::SourceNode database() {
446-
result = spanner().getAnInvocation().getAMethodCall("instance").getAMethodCall("database")
484+
result = database(DataFlow::TypeTracker::end())
447485
}
448486

449-
/**
450-
* Gets a node that refers to an instance of the `v1.SpannerClient` class.
451-
*/
452-
DataFlow::SourceNode v1SpannerClient() {
487+
/** Gets a node that refers to an instance of the `v1.SpannerClient` class. */
488+
private DataFlow::SourceNode v1SpannerClient(DataFlow::TypeTracker t) {
489+
t.start() and
453490
result = spanner().getAPropertyRead("v1").getAPropertyRead("SpannerClient").getAnInstantiation()
491+
or
492+
exists(DataFlow::TypeTracker t2 |
493+
result = v1SpannerClient(t2).track(t2, t)
494+
)
454495
}
455496

456-
/**
457-
* Gets a node that refers to a transaction object.
458-
*/
497+
/** Gets a node that refers to an instance of the `v1.SpannerClient` class. */
498+
DataFlow::SourceNode v1SpannerClient() {
499+
result = v1SpannerClient(DataFlow::TypeTracker::end())
500+
}
501+
502+
/** Gets a node that refers to a transaction object. */
503+
private DataFlow::SourceNode transaction(DataFlow::TypeTracker t) {
504+
t.start() and
505+
result = database().getAMethodCall("runTransaction").getABoundCallbackParameter(0, 1)
506+
or
507+
exists(DataFlow::TypeTracker t2 |
508+
result = transaction(t2).track(t2, t)
509+
)
510+
}
511+
512+
/** Gets a node that refers to a transaction object. */
459513
DataFlow::SourceNode transaction() {
460-
result = database().getAMethodCall("runTransaction").getCallback(0).getParameter(1)
514+
result = transaction(DataFlow::TypeTracker::end())
461515
}
462516

463517
/**
@@ -481,9 +535,7 @@ private module Spanner {
481535
*/
482536
class DatabaseRunCall extends SqlExecution {
483537
DatabaseRunCall() {
484-
exists(string run | run = "run" or run = "runPartitionedUpdate" or run = "runStream" |
485-
this = database().getAMethodCall(run)
486-
)
538+
this = database().getAMethodCall(["run", "runPartitionedUpdate", "runStream"])
487539
}
488540
}
489541

@@ -492,9 +544,7 @@ private module Spanner {
492544
*/
493545
class TransactionRunCall extends SqlExecution {
494546
TransactionRunCall() {
495-
exists(string run | run = "run" or run = "runStream" or run = "runUpdate" |
496-
this = transaction().getAMethodCall(run)
497-
)
547+
this = transaction().getAMethodCall(["run", "runStream", "runUpdate"])
498548
}
499549
}
500550

@@ -503,9 +553,7 @@ private module Spanner {
503553
*/
504554
class ExecuteSqlCall extends SqlExecution {
505555
ExecuteSqlCall() {
506-
exists(string exec | exec = "executeSql" or exec = "executeStreamingSql" |
507-
this = v1SpannerClient().getAMethodCall(exec)
508-
)
556+
this = v1SpannerClient().getAMethodCall(["executeSql", "executeStreamingSql"])
509557
}
510558

511559
override DataFlow::Node getAQueryArgument() {

javascript/ql/test/library-tests/frameworks/SQL/SqlString.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,6 @@
3939
| spanner.js:18:16:18:25 | "SQL code" |
4040
| spanner.js:19:16:19:34 | { sql: "SQL code" } |
4141
| spanner.js:19:23:19:32 | "SQL code" |
42+
| spannerImport.js:4:8:4:17 | "SQL code" |
4243
| sqlite.js:7:8:7:45 | "UPDATE ... id = ?" |
4344
| sqliteImport.js:2:8:2:44 | "UPDATE ... id = ?" |

javascript/ql/test/library-tests/frameworks/SQL/spanner.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ db.runTransaction((err, tx) => {
1717
tx.runStream({ sql: "SQL code" });
1818
tx.runUpdate("SQL code");
1919
tx.runUpdate({ sql: "SQL code" });
20-
});
20+
});
21+
22+
exports.instance = instance;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const { instance } = require('./spanner');
2+
const db = instance.database('db');
3+
4+
db.run("SQL code", (err, rows) => {});

0 commit comments

Comments
 (0)