Skip to content

Validate the scope object belongs to the job's project in post-processing tasks #1345

Description

@mihow

Summary

Post-processing tasks (the small size filter, and the class masking coming in #999) accept a scope identifier — occurrence_id or source_image_collection_id — in their config and operate on the matching rows. The task confirms the scope object exists, but not that it belongs to the project the job runs under. Today the only trigger is the Django admin, restricted to superusers, so this is a latent gap rather than an exploitable bug. It is worth closing before a less-privileged trigger surface (the deferred REST API) lands.

Where

  • ami/ml/post_processing/small_size_filter.py_scoped_detections() does Occurrence.objects.filter(pk=...).exists() with no project check.
  • ami/ml/post_processing/class_masking.py (lands with Let admins mask classifier predictions to a species list #999) — the occurrence scope uses the same .exists()-only pattern.
  • The task's run() has no project context wired in today; the job's project would need to be threaded in to validate against it.

Why it matters

The admin action derives the job's project from the selected row, so in the admin flow the scope object and the project are consistent by construction. The task itself, though, trusts whatever occurrence_id / source_image_collection_id sits in Job.params. A job created by another path — a future REST endpoint, a management command, or hand-edited params — could point the scope at an object in a different project, and the task would process it without complaint. That is a cross-project write gap once a non-superuser trigger exists.

Proposed direction (to discuss)

  • Thread the job's project into the task (it already holds self.job) and assert the scope object's project matches, raising a clear error otherwise; or
  • Resolve the scope queryset through the project (e.g. project.occurrences.filter(pk=...)) so a mismatch yields a not-found result and the existing error path fires.
  • Add a test: an occurrence/collection from project B with a job on project A should make the task raise.

Deferred from #1289 (scaffolding) and #999 (class masking) — both ship the .exists()-only check. Surfaced during the #1289 pre-merge review.

Metadata

Metadata

Assignees

No one assigned

    Labels

    post-processingPost-processing task framework and tasks: size filter, class masking, rank rollup, tracking

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions