@@ -8,6 +8,7 @@ import semmle.python.dataflow.new.RemoteFlowSources
88import semmle.python.dataflow.new.TaintTracking
99import semmle.python.ApiGraphs
1010import semmle.python.Concepts
11+ import semmle.python.frameworks.SqlAlchemy
1112
1213/**
1314 * Provides models for the `gradio` PyPI package.
@@ -27,31 +28,74 @@ module Streamlit {
2728
2829 override string getSourceType ( ) { result = "Streamlit user input" }
2930 }
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+ )
3049
50+ }
51+ }
3152 /**
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.
3354 * https://docs.streamlit.io/develop/api-reference/connections/st.connection
3455 */
3556 private class QueryMethodCall extends DataFlow:: CallCfgNode , SqlExecution:: Range {
57+
3658 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 ( ) )
4361 }
4462
4563 override DataFlow:: Node getSql ( ) { result in [ this .getArg ( 0 ) , this .getArgByName ( "sql" ) ] }
4664 }
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 ( ) )
5599 }
56100 }
57101}
0 commit comments