| management | ||
| migrations | ||
| .gitignore | ||
| __init__.py | ||
| admin.py | ||
| admin_audit.py | ||
| allocation_workflow_audit.py | ||
| apps.py | ||
| backfill.py | ||
| middleware.py | ||
| models.py | ||
| project_review_audit.py | ||
| README.md | ||
| resolvers.py | ||
| signals.py | ||
| tests.py | ||
| utils.py | ||
CMMC Audit Plugin
The in-tree package is named coldfront.plugins.cmmc_audit, the Django app label remains cmmc_audit for migration compatibility, and the user-facing Django admin label is CMMC Audit.
This plugin records append-only operational evidence for ColdFront workflows. It keeps raw forensic data such as old_values, new_values, target type/id, request path, IP address, source, and source id while adding CMMC-oriented admin columns for reviewers.
Evidence Coverage
AC evidence:
- Project membership changes: users added, removed, activated, and role changes.
- Project archival, deletion, status changes, and PI changes.
- PI and admin privilege changes.
- Allocation requests, approvals/status changes, renewals, and disable/revoke outcomes.
- Direct allocation renewal requests from
AllocationRenewView.post().
AU evidence:
- Append-only audit events with event time, actor, request path, IP address, and target.
- Generic Django admin add/change/delete actions.
- Project review submission/completion/status changes.
- Best-effort historical reconstruction from Django admin logs and selected ColdFront history tables.
CM evidence:
- Resource creation, update, and deletion.
- Resource changes preserve raw old/new values for configuration review.
Project Review Workflow Coverage
Discovered ColdFront project review hooks:
Project.force_reviewandProject.requires_revieware fields oncoldfront.core.project.models.Project.Project.needs_reviewis computed; it returns true when the project is forced, when annual review is enabled and required, and when the project is older than the review interval.- PI/manager submission is handled directly by
ProjectReviewView.post()at/project/<pk>/review/. It creates aProjectReviewwith statusPendingand clearsProject.force_review. - Staff completion is handled directly by
ProjectReviewCompleteView.get()at/project/project-review-complete/<project_review_pk>/. It changes theProjectReviewstatus toCompleted. - Staff request-for-updates is implemented as
ProjectReviewEmailView; it sends email but does not changeProjectReviewstatus. - There are no custom ColdFront project-review signals in this checkout.
Implemented semantic audit events:
project_review_forced: emitted whenProject.force_reviewchanges from false to true.project_review_submitted: emitted from the PI/manager review submission view after aProjectReviewis created.project_review_completed: emitted from the staff completion view after status changes toCompleted.project_review_status_changed: emitted for non-workflowProjectReview.statuschanges, such as admin/manual edits.
Allocation workflow hooks:
- Allocation request/approval/disable events use ColdFront allocation signals where available.
- Direct allocation renewal requests are captured by wrapping
AllocationRenewView.post()because that view changes status toRenewal Requestedwithout emitting an allocation change request signal.
Limitations
- Historical reconstruction is best effort. It cannot perfectly reconstruct user intent, free-form comments, IP addresses, request paths, or actions that were not stored in existing Django admin logs or ColdFront history tables.
- Django admin log reconstruction does not invent old/new values. When direction is unknown, messages say so explicitly.
- Annual review due state is computed by
Project.needs_review; no database write or signal is emitted when a project merely becomes due by age. - Request-for-updates email does not alter review state, so it is not logged as a review status event.
- Slurm partition restrictions and external account-disable actions are only captured if represented by ColdFront resource/allocation changes in this first pass.
- The plugin wraps selected review view methods at runtime to avoid modifying ColdFront core.
Historical Reconstruction
Historical reconstruction is implemented as an explicit management command. It is never run at startup or from AppConfig.ready().
Recommended sequence:
python manage.py backfill_cmmc_audit --dry-run
python manage.py backfill_cmmc_audit --commit
The command records a BackfillRun named initial_historical_backfill when committed. A second --commit exits cleanly after a completed run. Use --commit --force to rerun; duplicate protection checks source, source_id, and action, so previously reconstructed events are skipped.
Reconstructed entries are marked with is_reconstructed=True, keep the original event time when available, and include source/source_id for forensic traceability. Django admin log entries use source='django_admin_log'. ColdFront history entries use source='coldfront_history'.
Audit rows are append-only and the backfill command does not rewrite existing reconstructed rows. During development testing, reset only the reconstructed rows and run marker before backfilling again if you need to validate changed reconstruction output:
from coldfront.plugins.cmmc_audit.models import AuditEvent, BackfillRun
AuditEvent.objects.filter(is_reconstructed=True).delete()
BackfillRun.objects.filter(name="initial_historical_backfill").delete()
The command reconstructs:
- Generic admin add/change/delete events from
django.contrib.admin.models.LogEntry. - Conservative semantic admin-log events for PI status changes with unknown direction, project deletion, project user role changes, and resource create/change/delete.
- Selected ColdFront history events when adjacent records expose clear old/new state: project archival/status/PI changes, allocation status changes, allocation end-date increases, project user role changes, and resource create/change/delete.
Development Validation
Smoke tests should use Django's test database or an explicit rollback/cleanup block. Do not leave fixture users, projects, resources, allocations, or audit rows in a normal development database; those rows appear in the same evidence table as real operational events.