secure-web/backend/websites/migrations/0001_initial.py

113 lines
8.6 KiB
Python

# Generated by Django 5.2.9 on 2025-12-08 03:33
import django.core.validators
import django.db.models.deletion
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Website',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for the website', primary_key=True, serialize=False)),
('url', models.URLField(help_text='The normalized URL of the website', max_length=2048, unique=True, validators=[django.core.validators.URLValidator(schemes=['http', 'https'])])),
('domain', models.CharField(db_index=True, help_text='The domain extracted from the URL', max_length=255)),
('created_at', models.DateTimeField(auto_now_add=True, help_text='When the website was first added')),
('last_scanned_at', models.DateTimeField(blank=True, help_text='When the website was last scanned', null=True)),
],
options={
'db_table': 'websites',
'ordering': ['-created_at'],
'indexes': [models.Index(fields=['domain'], name='websites_domain_9fabc6_idx'), models.Index(fields=['-last_scanned_at'], name='websites_last_sc_15be22_idx')],
},
),
migrations.CreateModel(
name='Scan',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='Unique identifier for the scan', primary_key=True, serialize=False)),
('status', models.CharField(choices=[('pending', 'Pending'), ('running', 'Running'), ('done', 'Completed'), ('failed', 'Failed'), ('partial', 'Partially Completed')], db_index=True, default='pending', help_text='Current status of the scan', max_length=20)),
('celery_task_id', models.CharField(blank=True, help_text='Celery task ID for tracking', max_length=255, null=True)),
('created_at', models.DateTimeField(auto_now_add=True, help_text='When the scan was created')),
('started_at', models.DateTimeField(blank=True, help_text='When the scan started running', null=True)),
('completed_at', models.DateTimeField(blank=True, help_text='When the scan completed', null=True)),
('performance_score', models.IntegerField(blank=True, help_text='Lighthouse performance score (0-100)', null=True)),
('accessibility_score', models.IntegerField(blank=True, help_text='Lighthouse accessibility score (0-100)', null=True)),
('seo_score', models.IntegerField(blank=True, help_text='Lighthouse SEO score (0-100)', null=True)),
('best_practices_score', models.IntegerField(blank=True, help_text='Lighthouse best practices score (0-100)', null=True)),
('security_score', models.IntegerField(blank=True, help_text='Computed security score based on issues (0-100)', null=True)),
('overall_score', models.IntegerField(blank=True, help_text='Overall health score (0-100)', null=True)),
('error_message', models.TextField(blank=True, help_text='Error message if scan failed', null=True)),
('raw_lighthouse_data', models.JSONField(blank=True, help_text='Raw Lighthouse report data', null=True)),
('raw_zap_data', models.JSONField(blank=True, help_text='Raw OWASP ZAP report data', null=True)),
('raw_playwright_data', models.JSONField(blank=True, help_text='Raw Playwright analysis data', null=True)),
('raw_headers_data', models.JSONField(blank=True, help_text='Raw HTTP headers analysis data', null=True)),
('website', models.ForeignKey(help_text='The website that was scanned', on_delete=django.db.models.deletion.CASCADE, related_name='scans', to='websites.website')),
],
options={
'db_table': 'scans',
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='Metric',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(db_index=True, help_text="Name of the metric (e.g., 'first_contentful_paint_ms')", max_length=100)),
('display_name', models.CharField(help_text='Human-readable name for display', max_length=200)),
('value', models.FloatField(help_text='Numeric value of the metric')),
('unit', models.CharField(choices=[('ms', 'Milliseconds'), ('s', 'Seconds'), ('bytes', 'Bytes'), ('kb', 'Kilobytes'), ('mb', 'Megabytes'), ('score', 'Score (0-1)'), ('percent', 'Percentage'), ('count', 'Count')], help_text='Unit of measurement', max_length=20)),
('source', models.CharField(choices=[('lighthouse', 'Google Lighthouse'), ('owasp_zap', 'OWASP ZAP'), ('playwright', 'Playwright'), ('header_check', 'HTTP Header Check'), ('tls_check', 'TLS/SSL Check')], help_text='Tool that provided this metric', max_length=30)),
('score', models.FloatField(blank=True, help_text='Lighthouse score for this metric (0-1)', null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('scan', models.ForeignKey(help_text='The scan that measured this metric', on_delete=django.db.models.deletion.CASCADE, related_name='metrics', to='websites.scan')),
],
options={
'db_table': 'metrics',
'ordering': ['name'],
'indexes': [models.Index(fields=['scan', 'name'], name='metrics_scan_id_c4cc62_idx'), models.Index(fields=['source'], name='metrics_source_71e403_idx')],
'constraints': [models.UniqueConstraint(fields=('scan', 'name'), name='unique_metric_per_scan')],
},
),
migrations.CreateModel(
name='Issue',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('category', models.CharField(choices=[('performance', 'Performance'), ('security', 'Security'), ('headers', 'HTTP Headers'), ('tls', 'TLS/SSL'), ('cors', 'CORS'), ('accessibility', 'Accessibility'), ('seo', 'SEO'), ('best_practices', 'Best Practices'), ('content', 'Content'), ('resources', 'Resources')], db_index=True, help_text='Category of the issue', max_length=30)),
('severity', models.CharField(choices=[('critical', 'Critical'), ('high', 'High'), ('medium', 'Medium'), ('low', 'Low'), ('info', 'Informational')], db_index=True, help_text='Severity level of the issue', max_length=20)),
('tool', models.CharField(choices=[('lighthouse', 'Google Lighthouse'), ('owasp_zap', 'OWASP ZAP'), ('playwright', 'Playwright'), ('header_check', 'HTTP Header Check'), ('tls_check', 'TLS/SSL Check')], help_text='Tool that detected this issue', max_length=30)),
('title', models.CharField(help_text='Brief title of the issue', max_length=500)),
('description', models.TextField(help_text='Detailed description of the issue')),
('affected_url', models.URLField(blank=True, help_text='Specific URL affected by this issue', max_length=2048, null=True)),
('remediation', models.TextField(blank=True, help_text='Suggested fix or remediation', null=True)),
('raw_data', models.JSONField(blank=True, help_text='Raw data from the scanner for this issue', null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('scan', models.ForeignKey(help_text='The scan that found this issue', on_delete=django.db.models.deletion.CASCADE, related_name='issues', to='websites.scan')),
],
options={
'db_table': 'issues',
'ordering': ['severity', '-created_at'],
'indexes': [models.Index(fields=['scan', 'category'], name='issues_scan_id_e7f389_idx'), models.Index(fields=['scan', 'severity'], name='issues_scan_id_c92ffd_idx'), models.Index(fields=['tool'], name='issues_tool_78d942_idx')],
},
),
migrations.AddIndex(
model_name='scan',
index=models.Index(fields=['status'], name='scans_status_dc5ad7_idx'),
),
migrations.AddIndex(
model_name='scan',
index=models.Index(fields=['-created_at'], name='scans_created_7db2e5_idx'),
),
migrations.AddIndex(
model_name='scan',
index=models.Index(fields=['website', '-created_at'], name='scans_website_6dae4d_idx'),
),
]