@@ -8,6 +8,7 @@ import semmle.python.dataflow.new.RemoteFlowSources
8
8
import semmle.python.dataflow.new.TaintTracking
9
9
import semmle.python.ApiGraphs
10
10
import semmle.python.Concepts
11
+ import semmle.python.frameworks.SqlAlchemy
11
12
12
13
/**
13
14
* Provides models for the `gradio` PyPI package.
@@ -27,31 +28,74 @@ module Streamlit {
27
28
28
29
override string getSourceType ( ) { result = "Streamlit user input" }
29
30
}
31
+ /**
32
+ * The Streamlit SQLConnection class, which is used to create a connection to a SQL Database.
33
+ * Streamlit wraps around SQL Alchemy for most database functionality, and adds some on top of it, such as the `query` method.
34
+ * Streamlit can also connect to Snowflake and Snowpark databases, but the modeling is not the same, so we need to limit the scope to SQL databases.
35
+ * https://docs.streamlit.io/develop/api-reference/connections/st.connections.sqlconnection#:~:text=to%20data.-,st.connections.SQLConnection,-Streamlit%20Version
36
+ * We can connect to SQL databases for example with `import streamlit as st; conn = st.connection('pets_db', type='sql')`
37
+ */
38
+ private class StreamlitSQLConnection extends API:: CallNode {
39
+ StreamlitSQLConnection ( ) {
40
+ exists ( StringLiteral str , API:: CallNode n |
41
+ str .getText ( ) .matches ( "sql" )
42
+ and
43
+ n = API:: moduleImport ( "streamlit" ) .getMember ( "connection" ) .getACall ( )
44
+ and
45
+ DataFlow:: exprNode ( str ) .( DataFlow:: LocalSourceNode )
46
+ .flowsTo ( [ n .getArg ( 1 ) , n .getArgByName ( "type" ) ] )
47
+ and this = n
48
+ )
30
49
50
+ }
51
+ }
31
52
/**
32
- * The `query` call that can execute raw queries on a connection to a SQL/Sonwflake/Snowpark database.
53
+ * The `query` call that can execute raw queries on a connection to a SQL database.
33
54
* https://docs.streamlit.io/develop/api-reference/connections/st.connection
34
55
*/
35
56
private class QueryMethodCall extends DataFlow:: CallCfgNode , SqlExecution:: Range {
57
+
36
58
QueryMethodCall ( ) {
37
- this =
38
- API:: moduleImport ( "streamlit" )
39
- .getMember ( "connection" )
40
- .getReturn ( )
41
- .getMember ( "query" )
42
- .getACall ( )
59
+ exists ( StreamlitSQLConnection s |
60
+ this = s .getReturn ( ) .getMember ( "query" ) .getACall ( ) )
43
61
}
44
62
45
63
override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
46
64
}
47
- private class StreamlitConnection extends SqlAlchemy:: Connection:: InstanceSource {
48
- StreamlitConnection ( ) {
49
- this =
50
- API:: moduleImport ( "streamlit" )
51
- .getMember ( "connection" )
52
- .getReturn ( )
53
- .getMember ( "connect" )
54
- .getACall ( )
65
+
66
+
67
+ /**
68
+ * The Streamlit SQLConnection.connect() call, which returns a a new sqlalchemy.engine.Connection object.
69
+ * Streamlit creates a connection to a SQL database basing off SQL Alchemy, so we can reuse the models that we already have.
70
+ */
71
+ private class StreamlitSQLAlchemyConnection extends SqlAlchemy:: Connection:: InstanceSource {
72
+ StreamlitSQLAlchemyConnection ( ) {
73
+ exists ( StreamlitSQLConnection s |
74
+ this = s .getReturn ( ) .getMember ( "connect" ) .getACall ( ) )
75
+ }
76
+ }
77
+
78
+ /**
79
+ * The underlying SQLAlchemy Engine, accessed via `st.connection().engine`.
80
+ * Streamlit creates an engine to a SQL database basing off SQL Alchemy, so we can reuse the models that we already have.
81
+ */
82
+ private class StreamlitSQLAlchemyEngine extends SqlAlchemy:: Engine:: InstanceSource {
83
+ StreamlitSQLAlchemyEngine ( ) {
84
+ exists ( StreamlitSQLConnection s |
85
+ this = s .getReturn ( ) .getMember ( "engine" ) .asSource ( ) )
86
+ }
87
+ }
88
+
89
+ /**
90
+ * The SQLAlchemy Session, accessed via `st.connection().session`.
91
+ * Streamlit can create a session to a SQL database basing off SQL Alchemy, so we can reuse the models that we already have.
92
+ * For example, the modeling for `session` includes an `execute` method, which is used to execute raw SQL queries.
93
+ * https://docs.streamlit.io/develop/api-reference/connections/st.connections.sqlconnection#:~:text=SQLConnection.engine-,SQLConnection.session,-Streamlit%20Version
94
+ */
95
+ private class StreamlitSession extends SqlAlchemy:: Session:: InstanceSource {
96
+ StreamlitSession ( ) {
97
+ exists ( StreamlitSQLConnection s |
98
+ this = s .getReturn ( ) .getMember ( "session" ) .asSource ( ) )
55
99
}
56
100
}
57
101
}
0 commit comments