-
-
Notifications
You must be signed in to change notification settings - Fork 264
feature/Implementation of management command. #2073
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
Changes from all commits
949afda
e28ebc5
038c71d
ff4df3b
d2fea99
b652e64
50127c3
4e11688
75dffda
df2f113
d85e0d5
d3bd32b
1365beb
41598c9
9199bd2
64ee6bb
e1c923b
8f4e3a4
021ec86
b7a7eac
79acaec
2748680
d5aed68
b886714
55bcf9d
1e20a06
9b3205d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,6 +108,8 @@ shell-db: | |
|
|
||
| sync-data: \ | ||
| update-data \ | ||
| owasp-update-project-health-metrics \ | ||
| owasp-update-project-health-scores \ | ||
| enrich-data \ | ||
| index-data | ||
|
|
||
|
|
@@ -133,6 +135,7 @@ update-data: \ | |
| github-update-related-organizations \ | ||
| github-update-users \ | ||
| owasp-aggregate-projects \ | ||
| owasp-sync-official-project-levels \ | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic behind this target should be a part of |
||
| owasp-update-events \ | ||
| owasp-sync-posts \ | ||
| owasp-update-sponsors \ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,10 @@ owasp-update-project-health-metrics: | |
| @echo "Updating OWASP project health metrics" | ||
| @CMD="python manage.py owasp_update_project_health_metrics" $(MAKE) exec-backend-command | ||
|
|
||
| owasp-sync-official-project-levels: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not right coupling decision. I suggested to implement the official project levels during the project data sync. The health metrics is the next step after data sync is done. |
||
| @echo "Syncing official OWASP project levels" | ||
| @CMD="python manage.py owasp_update_project_health_metrics --sync-official-levels-only" $(MAKE) exec-backend-command | ||
|
|
||
| owasp-update-project-health-requirements: | ||
| @echo "Updating OWASP project health requirements" | ||
| @CMD="python manage.py owasp_update_project_health_requirements" $(MAKE) exec-backend-command | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| """A command to detect and report project level compliance status.""" | ||
|
|
||
| import logging | ||
|
|
||
| from django.core.management.base import BaseCommand | ||
|
|
||
| from apps.owasp.models.project import Project | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| class Command(BaseCommand): | ||
| """Command to detect and report project level compliance status. | ||
|
|
||
| This is a reporting command only - it does not sync or update any data. | ||
| For data synchronization, use the main data pipeline: make sync-data | ||
|
|
||
| Architecture: | ||
| - Part 1: Official level syncing happens during 'make update-data' | ||
| - Part 2: Health scoring with compliance penalties happens during 'make sync-data' | ||
| - This command: Reporting and analysis only | ||
| """ | ||
|
|
||
| help = "Detect and report projects with non-compliant level assignments" | ||
|
|
||
| def add_arguments(self, parser): | ||
| """Add command line arguments.""" | ||
| parser.add_argument( | ||
| "--verbose", | ||
| action="store_true", | ||
| help="Enable verbose output showing all projects", | ||
| ) | ||
|
|
||
| def handle(self, *args, **options): | ||
| """Execute compliance detection and reporting.""" | ||
| verbose = options["verbose"] | ||
|
|
||
| self.stdout.write("Analyzing project level compliance status...") | ||
|
|
||
| # Get all active projects | ||
| active_projects = Project.objects.filter(is_active=True).select_related() | ||
|
|
||
| compliant_projects = [] | ||
| non_compliant_projects = [] | ||
|
|
||
| for project in active_projects: | ||
| if project.is_level_compliant: | ||
| compliant_projects.append(project) | ||
| if verbose: | ||
| self.stdout.write(f"✓ {project.name}: {project.level} (matches official)") | ||
| else: | ||
| non_compliant_projects.append(project) | ||
| self.stdout.write( | ||
| self.style.WARNING( | ||
| f"✗ {project.name}: Local={project.level}, " | ||
| f"Official={project.project_level_official}" | ||
| ) | ||
| ) | ||
|
|
||
| # Summary statistics | ||
| total_projects = len(active_projects) | ||
| compliant_count = len(compliant_projects) | ||
| non_compliant_count = len(non_compliant_projects) | ||
| compliance_rate = (compliant_count / total_projects * 100) if total_projects else 0.0 | ||
|
|
||
| self.stdout.write("\n" + "=" * 60) | ||
| self.stdout.write("PROJECT LEVEL COMPLIANCE SUMMARY") | ||
| self.stdout.write("=" * 60) | ||
| self.stdout.write(f"Total active projects: {total_projects}") | ||
| self.stdout.write(f"Compliant projects: {compliant_count}") | ||
| self.stdout.write(f"Non-compliant projects: {non_compliant_count}") | ||
| self.stdout.write(f"Compliance rate: {compliance_rate:.1f}%") | ||
|
|
||
| if non_compliant_count > 0: | ||
| warning_msg = f"WARNING: Found {non_compliant_count} non-compliant projects" | ||
| self.stdout.write(f"\n{self.style.WARNING(warning_msg)}") | ||
| penalty_msg = ( | ||
| "These projects will receive score penalties in the next health score update." | ||
| ) | ||
| self.stdout.write(penalty_msg) | ||
| else: | ||
| self.stdout.write(f"\n{self.style.SUCCESS('✓ All projects are level compliant!')}") | ||
|
|
||
| # Log summary for monitoring | ||
| logger.info( | ||
| "Project level compliance analysis completed", | ||
| extra={ | ||
| "total_projects": total_projects, | ||
| "compliant_projects": compliant_count, | ||
| "non_compliant_projects": non_compliant_count, | ||
| "compliance_rate": f"{compliance_rate:.1f}%", | ||
| }, | ||
| ) | ||
|
|
||
| # Check if official levels are populated | ||
| from apps.owasp.models.enums.project import ProjectLevel | ||
|
|
||
| default_level = ProjectLevel.OTHER | ||
| projects_without_official_level = sum( | ||
| 1 for project in active_projects if project.project_level_official == default_level | ||
| ) | ||
|
|
||
| if projects_without_official_level > 0: | ||
| info_msg = ( | ||
| f"INFO: {projects_without_official_level} projects have default official levels" | ||
| ) | ||
| self.stdout.write(f"\n{self.style.NOTICE(info_msg)}") | ||
| sync_msg = ( | ||
| "Run 'make update-data' to sync official levels, " | ||
| "then 'make sync-data' for scoring." | ||
| ) | ||
| self.stdout.write(sync_msg) |
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.
The health metric generation is a separate step, we should not mix them.