Skip to content

[Representative Status] 135311: Log Details about POA Unauthorized Errors#27788

Merged
kristen-brown merged 4 commits intomasterfrom
135311/log-details-about-poa-403-errors
Apr 17, 2026
Merged

[Representative Status] 135311: Log Details about POA Unauthorized Errors#27788
kristen-brown merged 4 commits intomasterfrom
135311/log-details-about-poa-403-errors

Conversation

@kristen-brown
Copy link
Copy Markdown
Contributor

@kristen-brown kristen-brown commented Apr 16, 2026

Keep your PR as a Draft until it's ready for Platform review. A PR is ready for Platform review when it has a teammate approval and tests, linting, and settings checks pass CI. See these tips on how to avoid common delays in getting your PR merged.

Summary

  • This work is behind a feature toggle (flipper): NO
  • This PR updates the power_of_attorney Pundit policy to log the following user information when access is denied:
    1. The current LOA,
    2. Whether the user is LOA3 or not,
    3. Whether the ICN is present,
    4. And whether the Participant ID is present.
  • No PII or PHI will be logged.
  • The above information will be used to better inform next steps for reducing 403 errors in the Representative Status widget.
  • My team, the Accredited Representative Crew, owns the only controller that currently uses the power_of_attorney Pundit policy modified in this PR.

Related issue(s)

Testing done

  • New code is covered by unit tests
  • Prior to this change, there was no log emitted when a user was denied POA access by the Pundit policy.
  • To test, I ran the application locally alongside vets-website and tested the Representative Status widget and new logging.

Screenshots

N/A

What areas of the site does it impact?

This PR impacts the power_of_attorney Pundit policy, which is currently only used in the representation_management module.

Acceptance criteria

  • I fixed|updated|added unit tests and integration tests for each feature (if applicable).
  • No error nor warning in the console.
  • Events are being sent to the appropriate logging solution
  • Documentation has been updated (link to documentation) – N/A
  • No sensitive information (i.e. PII/credentials/internal URLs/etc.) is captured in logging, hardcoded, or specs
  • Feature/bug has a monitor built into Datadog (if applicable) – N/A
  • If app impacted requires authentication, did you login to a local build and verify all authenticated routes work as expected
  • I added a screenshot of the developed feature – N/A

Requested Feedback

No specific feedback requested for this PR.

@kristen-brown kristen-brown added representative-status-widget Benefits Representation Management product label ar-crew labels Apr 16, 2026
tfink419
tfink419 previously approved these changes Apr 16, 2026
Copy link
Copy Markdown
Contributor

@tfink419 tfink419 left a comment

Choose a reason for hiding this comment

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

Looks good

@kristen-brown kristen-brown marked this pull request as ready for review April 17, 2026 12:40
@kristen-brown kristen-brown requested review from a team as code owners April 17, 2026 12:40
Copilot AI review requested due to automatic review settings April 17, 2026 12:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances observability around 403 authorization failures for the Representative Status “Power of Attorney” endpoint by emitting structured logs from the PowerOfAttorneyPolicy when access is denied, along with unit test updates to validate the logging behavior.

Changes:

  • Add structured Rails.logger.info logging when PowerOfAttorneyPolicy#access? denies access.
  • Include LOA and presence signals for LOA3/ICN/participant_id in the denial log payload.
  • Update the policy spec to assert the new logging behavior for denial cases.

Reviewed changes

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

File Description
app/policies/power_of_attorney_policy.rb Adds a denial logging helper invoked when the policy denies access.
spec/policies/power_of_attorney_policy_spec.rb Extends unit tests to assert logging on denials and no logging on success.


it 'grants access' do
it 'grants access and does not log' do
expect(Rails.logger).not_to receive(:info)
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

expect(Rails.logger).not_to receive(:info) is very broad and can make this spec brittle if any unrelated info log happens during policy evaluation (now or in the future). It’s safer to assert specifically that the POA denial log is not emitted (e.g., not_to receive(:info).with('POA ACCESS DENIED', anything) or similar), while allowing other info logs to occur.

Suggested change
expect(Rails.logger).not_to receive(:info)
expect(Rails.logger).not_to receive(:info).with('POA ACCESS DENIED', anything)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated.

Comment on lines +15 to +20
def log_access_denied
Rails.logger.info('POA ACCESS DENIED',
loa: user.loa&.dig(:current),
loa3: user.loa3?,
icn: user.icn.present?,
participant_id: user.participant_id.present?)
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

log_access_denied unconditionally calls user.participant_id.present?. For LOA3 users where access is denied because user.icn is missing, the original access check short-circuits before touching participant_id, but the new logging will still evaluate it—this can trigger an MVI/MPI profile lookup just to populate a log field, adding latency/external dependency to an already-failing authorization path. Consider deriving the logged booleans from values already computed in access? (or only checking participant_id when icn is present), so denials due to missing ICN/LOA don’t incur an extra MPI call.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

@kristen-brown kristen-brown Apr 17, 2026

Choose a reason for hiding this comment

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

The MPI profile response is cached in Redis, so the point about incurring an extra MPI call isn't really accurate.

I think the changes recommended here would unnecessarily complicate the code, and they would also keep us from logging information that we want to know. If we didn't check the participant_id when icn isn't present, we wouldn't learn when a user has neither present, and that's one of the scenarios we're looking to learn about by adding this log.

Comment on lines +17 to +20
loa: user.loa&.dig(:current),
loa3: user.loa3?,
icn: user.icn.present?,
participant_id: user.participant_id.present?)
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

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

The log payload uses keys icn: and participant_id: but the values are booleans. In this codebase, presence booleans are typically logged with explicit *_present keys (e.g., icn_present, participant_id_present), which avoids confusion with logs that use icn/participant_id for the actual identifiers and makes it clear no PII is being emitted. Consider renaming these fields (and updating the spec expectations) to icn_present: and participant_id_present: (and optionally making loa more explicit, e.g., loa_current).

Suggested change
loa: user.loa&.dig(:current),
loa3: user.loa3?,
icn: user.icn.present?,
participant_id: user.participant_id.present?)
loa_current: user.loa&.dig(:current),
loa3: user.loa3?,
icn_present: user.icn.present?,
participant_id_present: user.participant_id.present?)

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated.

Copy link
Copy Markdown
Contributor

@tfink419 tfink419 left a comment

Choose a reason for hiding this comment

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

Still looks good. I have no preference for the log parameter names

@kristen-brown kristen-brown merged commit 4120ed0 into master Apr 17, 2026
42 of 46 checks passed
@kristen-brown kristen-brown deleted the 135311/log-details-about-poa-403-errors branch April 17, 2026 20:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ar-crew representative-status-widget Benefits Representation Management product label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants