-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Python: Model Django REST framework #7016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
QLDocs check complains about these:
I guess I should just go ahead and write QLDocs for them ... |
this is just pure Django project for now, (and very much a copy of the one in `django-v2-v3`), to make it easier to see the changes needed to set up Django REST framework.
I had to make the Django and PrivateDjango modeling non-private :O
Had to expose even more things, and had to make the `DjangoRouteHandler` modeling more flexible so I could extend the char-pred in a different file.
Added internal helper `.qll` file as well
78c748b
to
83389be
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally looks good.
I caught this in the doc:
Any APIException exceptions will be caught and mediated into appropriate responses.
Could that lead to unintended exposure of information?
The rest framework also seems to provide some rich routing capabilities, but I am happy to postpone any modelling of these until it has been established as impactful.
python/ql/lib/semmle/python/frameworks/internal/SubclassFinder.qll
Outdated
Show resolved
Hide resolved
*/ | ||
private class ModeledApiViewClasses extends Django::Views::View::ModeledSubclass { | ||
ModeledApiViewClasses() { | ||
this = API::moduleImport("rest_framework").getMember("views").getMember("APIView") or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this pass the autoformatter? I would have thought that the or
should be on its own line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was a bit surprised the first time I saw this as well, but apparently there are 2 accepts way of using or:
foo()
or
bar()
or
baz()
or
foo() or
bar() or
baz()
Slightly embarrassingly I had problems getting the quick-eval SubclassFinder query to output \n
without tripping up the extension, so that why I ended up with this way of doing this (which is certainly non-standard for the python CodeQL code)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also note that the autoformatter runs as part of our tests, so it would complain if the formatting was wrong
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer that it generated code that looked more familiar, but if it is legal, we can fix the aesthetics later. (Indeed I was confused about the autoformat check not firing..)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ask and you shall receive 😊
/** | ||
* Holds if `newModelFullyQualified` describes either a new subclass, or a new alias, belonging to `spec` that we should include in our automated modeling. | ||
* This new element is defined by `ast`, which is defined at `loc` in the module `mod`. | ||
*/ | ||
query predicate newModel( | ||
FindSubclassesSpec spec, string newModelFullyQualified, AstNode ast, Module mod, Location loc | ||
) { | ||
( | ||
newSubclass(spec, newModelFullyQualified, ast, mod, loc) | ||
or | ||
newDirectAlias(spec, newModelFullyQualified, ast, mod, loc) | ||
or | ||
newImportStar(spec, newModelFullyQualified, ast, mod, _, _, loc) | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like this predicate to be moved up. I found myself reding this first and its constituents later (even though they all interdepend given the recursion). I would say just below FindSubclassesSpecz
(so currently to line 50).
concat(string newModelFullyQualified | | ||
newModel(any(MySpec spec), newModelFullyQualified, _, _, _) | ||
| | ||
fullyQualifiedToAPIGraphPath(newModelFullyQualified), " or this = API::" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If only newModelFullyQualified
were an API ::Node
, so you could just use toString
...
// inherint problem with API graphs is that there doesn't need to exist a result for all | ||
// the stuff we have already modeled... as an example, the following query has no | ||
// results when evaluated against Django | ||
// | ||
// select API::moduleImport("django") | ||
// .getMember("contrib") | ||
// .getMember("admin") | ||
// .getMember("views") | ||
// .getMember("main") | ||
// .getMember("ChangeListSearchForm") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the explanation for why you need to build strings? Could it be moved up and elaborated into such an argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes. I've tried to highlight that now. Please add a suggestion if what I did was not sufficient :blush
Good find 👍 I'll take a look |
Co-authored-by: yoff <lerchedahl@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One small suggestion, otherwise looks good. Nice work, including the exceptions 👍
result = this.getArgByName("detail") | ||
} | ||
|
||
// How to support the `headers` argument here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is that even honoured when an exception is raised?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was a bad copy-paste, I have fixed that up
// --------------------------------------------------------------------------- | ||
// Implementation below | ||
// --------------------------------------------------------------------------- | ||
// | ||
// inherent problem with API graphs is that there doesn't need to exist a result for | ||
// all the stuff we have already modeled... as an example, the following query has no | ||
// results when evaluated against a django/django DB | ||
// | ||
// select API::moduleImport("django") | ||
// .getMember("contrib") | ||
// .getMember("admin") | ||
// .getMember("views") | ||
// .getMember("main") | ||
// .getMember("ChangeListSearchForm") | ||
// | ||
// therefore we use fully qualified names to capture new classes/new aliases. | ||
// | ||
// note that this implementation was originally created to help with automatically | ||
// modeling packages in mind, and was just copied for this purpose. See | ||
// https://github.com/github/codeql/pull/5632 for more discussion. I wanted to get | ||
// this into the codeql-repo, so it could be of use when modeling 3rd party libraries, | ||
// and save some manual effort. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rewrite it slightly:
// --------------------------------------------------------------------------- | |
// Implementation below | |
// --------------------------------------------------------------------------- | |
// | |
// inherent problem with API graphs is that there doesn't need to exist a result for | |
// all the stuff we have already modeled... as an example, the following query has no | |
// results when evaluated against a django/django DB | |
// | |
// select API::moduleImport("django") | |
// .getMember("contrib") | |
// .getMember("admin") | |
// .getMember("views") | |
// .getMember("main") | |
// .getMember("ChangeListSearchForm") | |
// | |
// therefore we use fully qualified names to capture new classes/new aliases. | |
// | |
// note that this implementation was originally created to help with automatically | |
// modeling packages in mind, and was just copied for this purpose. See | |
// https://github.com/github/codeql/pull/5632 for more discussion. I wanted to get | |
// this into the codeql-repo, so it could be of use when modeling 3rd party libraries, | |
// and save some manual effort. | |
// --------------------------------------------------------------------------- | |
// Implementation below | |
// --------------------------------------------------------------------------- | |
// We are looking to find all subclassed of the already modelled classes, and | |
// ideally we would identify an `API::Node` for each (then `toString` would give | |
// the API path). | |
// | |
// However, an inherent problem with API graphs is that there doesn't need to exist a result for | |
// all the stuff we have already modeled... as an example, the following query has no | |
// results when evaluated against a django/django DB | |
// | |
// select API::moduleImport("django") | |
// .getMember("contrib") | |
// .getMember("admin") | |
// .getMember("views") | |
// .getMember("main") | |
// .getMember("ChangeListSearchForm") | |
// | |
// Therefore we use fully qualified names to capture new classes/new aliases, and transform these | |
// into API paths, see `fullyQualifiedToAPIGraphPath`. | |
// | |
// Further automation is planned her, see | |
// https://github.com/github/codeql/pull/5632 for more discussion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't fully agree, but have rewritten based on your suggestion 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
No description provided.