Skip to content

feat: Audit instrumentation for Browse & Request approval flows - #271

Open
shravani-sonata-gottapu wants to merge 2 commits into
mainfrom
shravai/ENT-12028
Open

feat: Audit instrumentation for Browse & Request approval flows#271
shravani-sonata-gottapu wants to merge 2 commits into
mainfrom
shravai/ENT-12028

Conversation

@shravani-sonata-gottapu

Copy link
Copy Markdown
Contributor

JIRA
ENT-12028 : https://2u-internal.atlassian.net/browse/ENT-12028

Description:
Instruments the Browse & Request (B&R) approval flows in enterprise-access to write LearnerContentAssignmentAction audit rows for admin approvals and their resulting allocation/reallocation. Every approval call generates its own correlation ID and reuses it across the row(s) it produces: for a single approval this links the APPROVED row to its ALLOCATED/REALLOCATED row; for approve-all it also ties together every approved request in that batch. Each row captures the reviewing admin as actor_lms_user_id with actor_type=admin, and records the originating request UUID in metadata.

Changes:
Learner credit request approval flow :
Updated the single approval endpoint (POST /api/v1/learner-credit-requests/approve/) to write an APPROVED action row followed by an ALLOCATED or REALLOCATED action row for the approved request. Both rows capture the reviewer as the acting admin, actor_type=admin, and the originating request UUID in metadata, sharing one correlation ID.

Bulk approval flow :
Updated the approve-all endpoint (POST /api/v1/learner-credit-requests/approve-all/) to write the same APPROVED + ALLOCATED/REALLOCATED row pair for each approved request. A single correlation ID is generated per approve-all call and shared across every row written for that batch, for traceability.

Audit source tracking:
Added and threaded new AssignmentSources values through the approval call chain (subsidy_request.api → subsidy_access_policy.api/models → content_assignments.api):

browse_request_approve for individual approvals
browse_request_approve_all for bulk approvals
Audit row helper
Added create_assignment_action in content_assignments/api.py as a shared helper for persisting a single audit action row (actor, actor_type, source, metadata) so both the approval path and the allocation path write consistent rows.

Tests :
Added and updated coverage for:
Single approvals producing APPROVED plus ALLOCATED/REALLOCATED action rows, with reviewer attribution (actor_lms_user_id), actor_type=admin, and request UUID present in metadata
Bulk approvals writing one action-row pair per approved request, sharing one correlation ID across the batch
A fresh correlation ID being generated per approval call (distinct across separate calls)
Correct source values recorded for single vs. bulk approval flows
SubsidyAccessPolicy.approve / validate_and_allocate / allocate_assignment_for_requests passing actor_lms_user_id, source, and correlation_id through correctly

@shravani-sonata-gottapu
shravani-sonata-gottapu requested a review from a team as a code owner August 18, 2026 13:49
Copilot AI lite review requested due to automatic review settings August 18, 2026 13:49
@codecov

codecov Bot commented Aug 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.66%. Comparing base (54d4349) to head (749e8df).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #271      +/-   ##
==========================================
+ Coverage   87.64%   87.66%   +0.02%     
==========================================
  Files         157      157              
  Lines       13450    13477      +27     
  Branches     1303     1308       +5     
==========================================
+ Hits        11788    11815      +27     
  Misses       1359     1359              
  Partials      303      303              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds audit instrumentation to the Browse & Request (B&R) learner credit approval flows so that admin approvals and the resulting allocation/reallocation write LearnerContentAssignmentAction rows with consistent attribution, source, request UUID metadata, and per-call correlation IDs for traceability across batched approvals.

Changes:

  • Threaded actor_lms_user_id, source, and correlation_id through subsidy_request.api → subsidy_access_policy.api/models → content_assignments.api.
  • Added creation of APPROVED assignment action rows during approval, and ALLOCATED/REALLOCATED assignment action rows during allocation.
  • Added/updated tests to validate correlation ID reuse across approve-all batches and correct action attribution/metadata.

Critical issues (must address):

  • create_assignment_action() currently writes action rows with completed_at unset and actor_type hard-coded to ADMIN, which can misattribute system-triggered actions and produces inconsistent audit data.
  • Current call flow writes allocation action rows before approved action rows, which contradicts the PR description’s “APPROVED followed by ALLOCATED/REALLOCATED” ordering.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
enterprise_access/apps/subsidy_request/tests/test_api.py Extends approval tests to assert APPROVED action rows and correlation-id sharing for bulk approvals.
enterprise_access/apps/subsidy_request/api.py Threads source/correlation_id through approval flow and writes APPROVED assignment action rows.
enterprise_access/apps/subsidy_access_policy/tests/test_models.py Updates expectations for new passthrough args to allocate_assignment_for_requests.
enterprise_access/apps/subsidy_access_policy/models.py Adds passthrough parameters to SubsidyAccessPolicy.approve() and forwards them to allocation.
enterprise_access/apps/subsidy_access_policy/api.py Adds passthrough parameters to validate_and_allocate() and forwards them to policy approval.
enterprise_access/apps/content_assignments/tests/test_api.py Adds tests asserting ALLOCATED/REALLOCATED action rows and correlation-id behavior.
enterprise_access/apps/content_assignments/api.py Adds create_assignment_action() helper and writes allocation action rows during allocate_assignment_for_requests().
enterprise_access/apps/api/v1/views/browse_and_request.py Generates a fresh correlation ID per approve / approve-all request and passes appropriate AssignmentSources.
enterprise_access/apps/api/v1/tests/test_browse_and_request_views.py Adds view-level assertions for source propagation and correlation-id generation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread enterprise_access/apps/content_assignments/api.py Outdated
Comment thread enterprise_access/apps/content_assignments/api.py
Comment thread enterprise_access/apps/subsidy_request/api.py Outdated
Copilot AI review requested due to automatic review settings August 20, 2026 15:43

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

enterprise_access/apps/content_assignments/api.py:692

  • Mapping assignments back to requests keys by (lms_user_id, course_id). If multiple requests are processed for users without an lms_user_id (supported elsewhere in this module), the key becomes (None, course_id) for all of them and the dict will collide, potentially associating the wrong assignment (and wrong audit action metadata) to a request. Consider falling back to learner_email/user.email when lms_user_id is None to keep keys unique.
        assignments_by_learner_and_course = {
            (asg.lms_user_id, asg.content_key): asg for asg in all_affected_assignments
        }

Comment on lines +121 to +135
def build_assignment_action(
assignment,
action_type,
actor_lms_user_id,
source,
correlation_id=None,
extra_metadata=None,
):
"""
Returns an unsaved ``LearnerContentAssignmentAction`` for the given assignment.

Callers are responsible for persisting the returned instance, typically via
``LearnerContentAssignmentAction.objects.bulk_create()`` alongside other action
rows so that call order determines write order.
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants