No description
Find a file
2026-05-27 15:48:32 -06:00
management Initial CMMC audit plugin 2026-05-27 15:47:47 -06:00
migrations Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
.gitignore Initial CMMC audit plugin 2026-05-27 15:47:47 -06:00
__init__.py Initial Commit 2026-05-27 14:45:29 -06:00
admin.py Initial Commit 2026-05-27 14:45:29 -06:00
admin_audit.py Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
allocation_workflow_audit.py Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
apps.py Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
backfill.py Initial Commit 2026-05-27 14:45:29 -06:00
middleware.py Initial Commit 2026-05-27 14:45:29 -06:00
models.py Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
project_review_audit.py Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
README.md Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
resolvers.py Initial Commit 2026-05-27 14:45:29 -06:00
signals.py Rename audit internals to cmmc_audit 2026-05-27 15:48:32 -06:00
tests.py Initial Commit 2026-05-27 14:45:29 -06:00
utils.py Initial Commit 2026-05-27 14:45:29 -06:00

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_review and Project.requires_review are fields on coldfront.core.project.models.Project. Project.needs_review is 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 a ProjectReview with status Pending and clears Project.force_review.
  • Staff completion is handled directly by ProjectReviewCompleteView.get() at /project/project-review-complete/<project_review_pk>/. It changes the ProjectReview status to Completed.
  • Staff request-for-updates is implemented as ProjectReviewEmailView; it sends email but does not change ProjectReview status.
  • There are no custom ColdFront project-review signals in this checkout.

Implemented semantic audit events:

  • project_review_forced: emitted when Project.force_review changes from false to true.
  • project_review_submitted: emitted from the PI/manager review submission view after a ProjectReview is created.
  • project_review_completed: emitted from the staff completion view after status changes to Completed.
  • project_review_status_changed: emitted for non-workflow ProjectReview.status changes, 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 to Renewal Requested without 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.