github / github/codeql

Python: Inconsistent behaviour of the getAMember and getMember predicates

Open
#19,297 8 comments 0 reactions 0 assignees View on GitHub
question
Dominant language
CodeQL
Stars
10.1k
Forks
2.1k
Avg merge
2d 15h
Merged PRs (30d)
141

Description

Trying to access all nodes that represent an attribute of a Django subclass does not work as expected in https://github.com/HumanSignal/label-studio.

I am trying to detect a call to `AsyncMigrationStatus.objects` in the following block of code (https://github.com/HumanSignal/label-studio/blob/develop/label_studio/core/management/commands/show_async_migrations.py#L19):

```
def handle(self, *args, **options):
org = options['organization']
logger.debug(f"===> AsyncMigrationStatus for Organization {org if org > -1 else 'ALL'}")
if org == -1:
migrations = AsyncMigrationStatus.objects.all().order_by('project_id')
else:
migrations = AsyncMigrationStatus.objects.filter(project__organization_id=org)

for m in migrations:
logger.debug(f'{m.name} \t {m.created_at} \t Project <{m.project}> \t {m.status} \t {m.meta}')

logger.debug(f"===> AsyncMigrationStatus for Organization {org if org > -1 else 'ALL'} printed")
```

Using the following query:

```
import python
import semmle.python.frameworks.Django
import semmle.python.ApiGraphs

from API::Node n
where
n = PrivateDjango::DjangoImpl::DB::Models::Model::subclassRef().getAMember() and
select n, "this is a model attribute"
```

`AsyncMigrationStatus` is defined below (https://github.com/HumanSignal/label-studio/blob/develop/label_studio/core/models.py#L10):

```
class AsyncMigrationStatus(models.Model):
meta = JSONField(
'meta',
null=True,
default=dict,
help_text='Meta is for any params for migrations, e.g.: project, filter or error message.',
)

project = models.ForeignKey(
'projects.Project',
related_name='asyncmigrationstatus',
on_delete=models.CASCADE,
null=True,
help_text='Project ID for this migration',
)

name = models.TextField('migration_name', help_text='Migration name')

STATUS_STARTED = 'STARTED'
STATUS_IN_PROGRESS = 'IN PROGRESS'
STATUS_FINISHED = 'FINISHED'
STATUS_ERROR = 'ERROR'
STATUS_CHOICES = (
(STATUS_STARTED, 'Migration is started or queued.'),
(STATUS_IN_PROGRESS, 'Migration is in progress. Check meta for job_id or status.'),
(STATUS_FINISHED, 'Migration completed successfully.'),
(STATUS_ERROR, 'Migration completed with errors. Check meta for more info.'),
)
status = models.CharField(max_length=100, choices=STATUS_CHOICES, null=True, default=None)

created_at = models.DateTimeField(_('created at'), auto_now_add=True, help_text='Creation time')
updated_at = models.DateTimeField(_('updated at'), auto_now=True, help_text='Last updated time')

def __str__(self):
return f'(id={self.id}) ' + self.name + (' at project ' + str(self.project) if self.project else ''))
```

This query returns many results across the codebase but does not flag this specific statement, along with others.

I've tried many different approaches to understand the root cause of the issue without success. Please let me know if I am somehow misusing getAMember.

Below are my specs:
- codeQL CLI 2.21.0
- codeQL VSCode extension 1.17.2

Contributor guide

Open the contributing guide

Research direction

Start with the reproduced query using semmle.python.frameworks.Django and semmle.python.ApiGraphs, then compare getAMember with getMember for Django model attributes. Use the linked show_async_migrations.py and models.py examples as the reproduction case. Done means the predicate behavior is explained and the query consistently identifies the AsyncMigrationStatus.objects access.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.