cortex_job models¶
cortex_job.models
¶
Analyzer
¶
Bases: Model
name = models.CharField(max_length=50, unique=True, db_index=True)
class-attribute
instance-attribute
¶
weight = models.FloatField(default=0.2)
class-attribute
instance-attribute
¶
TIER_AUTHORITATIVE = 1
class-attribute
instance-attribute
¶
TIER_STRONG = 2
class-attribute
instance-attribute
¶
TIER_CONTEXTUAL = 3
class-attribute
instance-attribute
¶
TIER_CHOICES = [(TIER_AUTHORITATIVE, 'Authoritative'), (TIER_STRONG, 'Strong'), (TIER_CONTEXTUAL, 'Contextual')]
class-attribute
instance-attribute
¶
tier = models.PositiveSmallIntegerField(choices=TIER_CHOICES, default=TIER_CONTEXTUAL, db_index=True, help_text='Fixed trust classification. 1 = authoritative source, 3 = contextual/noisy.')
class-attribute
instance-attribute
¶
analyzer_cortex_id = models.CharField(max_length=50, unique=True, db_index=True)
class-attribute
instance-attribute
¶
is_active = models.BooleanField(default=True)
class-attribute
instance-attribute
¶
creation_date = models.DateTimeField(auto_now_add=True, db_index=True)
class-attribute
instance-attribute
¶
last_update = models.DateTimeField(auto_now=True)
class-attribute
instance-attribute
¶
AnalyzerReport
¶
Bases: Model
cortex_job_id = models.CharField(max_length=50, db_index=True)
class-attribute
instance-attribute
¶
type = models.CharField(max_length=50, db_index=True)
class-attribute
instance-attribute
¶
status = models.CharField(max_length=50, db_index=True)
class-attribute
instance-attribute
¶
analyzer = models.ForeignKey(Analyzer, on_delete=models.CASCADE, related_name='analyzer_reports')
class-attribute
instance-attribute
¶
url = models.ForeignKey(URL, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
domain = models.ForeignKey(Domain, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
mail = models.ForeignKey(MailAddress, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
hash = models.ForeignKey(Hash, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
file = models.ForeignKey(File, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
ip = models.ForeignKey(IP, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
mail_body = models.ForeignKey(MailBody, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
mail_header = models.ForeignKey(MailHeader, on_delete=models.CASCADE, related_name='analyzer_reports', null=True, blank=True)
class-attribute
instance-attribute
¶
level = models.CharField(max_length=50, db_index=True)
class-attribute
instance-attribute
¶
confidence = models.FloatField()
class-attribute
instance-attribute
¶
score = models.FloatField()
class-attribute
instance-attribute
¶
category = models.TextField(null=True, blank=True)
class-attribute
instance-attribute
¶
report_summary = models.JSONField()
class-attribute
instance-attribute
¶
report_taxonomy = models.JSONField()
class-attribute
instance-attribute
¶
report_full = models.JSONField()
class-attribute
instance-attribute
¶
enrichment = models.JSONField(null=True, blank=True, default=None)
class-attribute
instance-attribute
¶
screenshot_bucket = models.CharField(max_length=255, blank=True, default='')
class-attribute
instance-attribute
¶
screenshot_key = models.CharField(max_length=512, blank=True, default='', db_index=True)
class-attribute
instance-attribute
¶
creation_date = models.DateTimeField(auto_now_add=True, db_index=True)
class-attribute
instance-attribute
¶
last_update = models.DateTimeField(auto_now=True)
class-attribute
instance-attribute
¶
Meta
¶
ordering = ['-creation_date']
class-attribute
instance-attribute
¶
indexes = [models.Index(fields=['type', 'status', 'domain']), models.Index(fields=['type', 'status', 'url']), models.Index(fields=['type', 'status', 'ip']), models.Index(fields=['type', 'status', 'hash']), models.Index(fields=['type', 'status', 'mail']), models.Index(fields=['type', 'status', 'file']), models.Index(fields=['type', 'status', 'mail_body']), models.Index(fields=['type', 'status', 'mail_header'])]
class-attribute
instance-attribute
¶
set_category(categories)
¶
Store the report category as a comma-separated string.
get_category()
¶
Return the report categories as a list.
CaseAnalyzerJob
¶
Bases: Model
Per-case ledger of dispatched Cortex jobs.
One row per (case, cortex_job_id). Multiple cases may share the same cortex_job_id when a deduplicated artifact (file, URL, hash, etc.) is referenced by several cases: that's why this is a junction table and not an FK on AnalyzerReport.
Status mirrors AnalyzerReport.status but is per-case so we can answer 'which jobs is this case waiting on' without joining.
STATUS_WAITING = 'Waiting'
class-attribute
instance-attribute
¶
STATUS_INPROGRESS = 'InProgress'
class-attribute
instance-attribute
¶
STATUS_SUCCESS = 'Success'
class-attribute
instance-attribute
¶
STATUS_FAILURE = 'Failure'
class-attribute
instance-attribute
¶
STATUS_DELETED = 'Deleted'
class-attribute
instance-attribute
¶
STATUS_CHOICES = [(STATUS_WAITING, 'Waiting'), (STATUS_INPROGRESS, 'InProgress'), (STATUS_SUCCESS, 'Success'), (STATUS_FAILURE, 'Failure'), (STATUS_DELETED, 'Deleted')]
class-attribute
instance-attribute
¶
PENDING_STATUSES = (STATUS_WAITING, STATUS_INPROGRESS)
class-attribute
instance-attribute
¶
case = models.ForeignKey('case_handler.Case', on_delete=models.CASCADE, related_name='analyzer_jobs')
class-attribute
instance-attribute
¶
cortex_job_id = models.CharField(max_length=50)
class-attribute
instance-attribute
¶
analyzer = models.ForeignKey(Analyzer, on_delete=models.PROTECT, related_name='case_jobs')
class-attribute
instance-attribute
¶
analyzer_report = models.ForeignKey(AnalyzerReport, on_delete=models.SET_NULL, related_name='case_jobs', null=True, blank=True)
class-attribute
instance-attribute
¶
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=STATUS_INPROGRESS)
class-attribute
instance-attribute
¶
created_at = models.DateTimeField(auto_now_add=True)
class-attribute
instance-attribute
¶
completed_at = models.DateTimeField(null=True, blank=True)
class-attribute
instance-attribute
¶
Meta
¶
constraints = [models.UniqueConstraint(fields=['case', 'cortex_job_id'], name='uniq_case_cortexjob')]
class-attribute
instance-attribute
¶
indexes = [models.Index(fields=['cortex_job_id']), models.Index(fields=['case', 'status']), models.Index(fields=['status', 'created_at'])]
class-attribute
instance-attribute
¶
DerivedObservable
¶
Bases: Model
Provenance: an observable that an extractor analyzer surfaced from another observable's report, within one case. See docs/specs/2026-09-07-derived-observables-design.md.