Skip to content

CodeQL 3: fix: close CodeQL correctness alerts#191

Open
rlorenzo wants to merge 4 commits into
mainfrom
codeql/3-correctness
Open

CodeQL 3: fix: close CodeQL correctness alerts#191
rlorenzo wants to merge 4 commits into
mainfrom
codeql/3-correctness

Conversation

@rlorenzo
Copy link
Copy Markdown
Contributor

@rlorenzo rlorenzo commented May 13, 2026

Summary

Closes ~30 CodeQL alerts across three correctness rule families. Each fix needs per-site judgment, so they're consolidated here rather than split - the reviewer mental model is the same throughout.

cs/virtual-call-in-constructor (5)

Sealed three DTO/model classes whose copy-constructors trip the rule by assigning to virtual properties:

  • CMSFile (web/Areas/CMS/Models/CMSFile.cs) - partialsealed partial
  • StudentClassYear (web/Models/Students/StudentClassYear.cs) - also drops virtual on properties declared on the now-sealed class
  • RoleTemplateSimplified (web/Areas/RAPS/Models/RoleTemplateSimplified.cs) - same

Safety check: none of the three are inherited from in C#, none are Substitute.For<...> in tests, and there is no UseLazyLoadingProxies() call anywhere in the project so EF doesn't need them non-sealed.

cs/unsafe-year-construction (4)

  • web/Areas/Effort/Services/PercentRolloverService.cs - added ArgumentOutOfRangeException.ThrowIfLessThan(year, 1) / ThrowIfGreaterThan(year, 9998) at the top of GetRolloverPreviewAsync (year comes from HTTP). Replaced new DateTime(year + 1, 6, 30, …) with june30Start.AddYears(1).
  • web/Classes/Utilities/AcademicYearHelper.cs::GetAcademicYearStart - construct July of date.Year first, then .AddYears(-1) if needed, instead of new DateTime(date.Year - 1, …).

cs/constant-condition (21)

Removed redundant null-propagation that the analyzer can already prove dead:

  • PercentageService.cs:309 - dropped type != null && after the IsValid guard already eliminated the null case.
  • Program.cs SetAwsCredentials - hoisted AccessKeyId / SecretAccessKey / RegionEndpoint element lookups into locals (one each) so the duplicated ?. chains and the redundant second RegionEndpoint lookup go away.
  • HomeController.cs:150,322 - replaced protector?.Protect(...) and successNode?.Element(...) with the non-null form inside their guarded blocks.
  • CompetencyController.cs:139 - removed the unreachable CompetencyId == null || <= 0 check that runs after FindAsync already confirmed the record exists and after competencyId != competency.CompetencyId was rejected.
  • AssessmentController.cs:300 - student?.StudentInfostudent.StudentInfo inside the student == null || short-circuit.
  • test/CTS/AssessmentControllerTest.cs:261 - result?.StatusCoderesult.StatusCode inside if (result != null).
  • RAPSAuditService.cs:148 - auditLog?.auditLog. (foreach variable cannot be null).
  • RoleTemplatesController.cs:189-190 - drop user?. after the if (user == null) return null; guard.
  • RAPSController.cs:51,56 - restructured the two if (rapsIdx != null && rapsIdx > -1 && path?.Count > …) blocks into a single outer null-and-bounds check that lifts the path null check up.
  • AuditRow.cs:27-28 - dbAudit?.Encounter?. / dbAudit.Encounter?.Student?. chains collapsed inside the surrounding non-null guard.

Context

Third in the CodeQL N: cleanup series (after #189, #190).

Test plan

  • npm run test - 1946 backend + 749 frontend passing
  • npm run verify:build - clean (0 errors)
  • npm run lint - passing on changed files
  • CodeQL workflow on this PR shows the ~30 listed alerts closed

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

PR hardens null-safety by consolidating nullable-conditional patterns into explicit non-null assertions where control flow guarantees non-nullability. Also seals model classes, removes EF virtual modifiers, adopts factory-method pattern for RoleTemplateSimplified, changes CompetencyController duplicate-detection behavior to include the current competency, and improves validation logic in services and utilities.

Changes

Null-safety assertions and code quality improvements

Layer / File(s) Summary
Test and assertion null-safety hardening
test/CTS/AssessmentControllerTest.cs, web/Areas/CTS/Controllers/AssessmentController.cs
Test assertion and early validation patterns made non-null-safe where control flow guarantees non-nullability.
Controller method null-safety refactoring
web/Controllers/HomeController.cs, web/Areas/RAPS/Controllers/RAPSController.cs
HomeController methods replace nullable-propagation with explicit non-null assertions; RAPSController refactors index-checking using pattern matching.
Model visibility and structure updates
web/Areas/CMS/Models/CMSFile.cs, web/Models/Students/StudentClassYear.cs
CMSFile and StudentClassYear are sealed; StudentClassYear navigation properties remove virtual modifiers to disable EF lazy-loading.
CompetencyController duplicate detection logic change
web/Areas/CTS/Controllers/CompetencyController.cs
Request payload CompetencyId validation removed; duplicate-detection no longer excludes the current competency from the duplicate set.
Factory pattern adoption and view simplification
web/Areas/RAPS/Models/RoleTemplateSimplified.cs, web/Areas/RAPS/Controllers/RoleTemplatesController.cs
RoleTemplateSimplified converts from constructor to static FromRoleTemplate factory; callers updated and GetRoleTemplateApplyPreview removes placeholder fallback values.
Service null-safety and validation improvements
web/Areas/CTS/Models/AuditRow.cs, web/Areas/Effort/Services/PercentageService.cs, web/Areas/RAPS/Services/RAPSAuditService.cs
AuditRow, PercentageService, and RAPSAuditService replace nullable-conditional access with direct property access or null-forgiving operators.
Utility improvements and parameter validation
web/Areas/Effort/Services/PercentRolloverService.cs, web/Classes/Utilities/AcademicYearHelper.cs, web/Program.cs
PercentRolloverService adds year range validation; AcademicYearHelper refactors July anchor computation; Program.cs simplifies AWS credential parsing with local variables and reflection.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 64.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately summarizes the main change: closing CodeQL correctness alerts across multiple files. It's specific and directly reflects the PR's primary purpose.
Description check ✅ Passed Description thoroughly explains the changes, organized by CodeQL rule family with specifics about which files were modified and why. It's directly related to the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codeql/3-correctness

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread web/Areas/RAPS/Controllers/RAPSController.cs Fixed
Comment thread web/Program.cs Fixed
@codecov-commenter
Copy link
Copy Markdown

Bundle Report

Bundle size has no change ✅

Comment thread web/Areas/RAPS/Controllers/RAPSController.cs Fixed
Comment thread web/Program.cs Fixed
@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented May 13, 2026

Codecov Report

❌ Patch coverage is 24.48980% with 37 lines in your changes missing coverage. Please review.
✅ Project coverage is 43.02%. Comparing base (38de1ad) to head (57e3771).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
web/Program.cs 0.00% 10 Missing ⚠️
web/Areas/RAPS/Controllers/RAPSController.cs 0.00% 9 Missing ⚠️
.../Areas/RAPS/Controllers/RoleTemplatesController.cs 0.00% 5 Missing ⚠️
web/Models/Students/StudentClassYear.cs 0.00% 4 Missing ⚠️
web/Areas/CTS/Models/AuditRow.cs 0.00% 3 Missing ⚠️
web/Areas/RAPS/Services/RAPSAuditService.cs 0.00% 3 Missing ⚠️
web/Controllers/HomeController.cs 0.00% 2 Missing ⚠️
web/Areas/CTS/Controllers/AssessmentController.cs 0.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #191      +/-   ##
==========================================
+ Coverage   42.96%   43.02%   +0.05%     
==========================================
  Files         877      877              
  Lines       51468    51471       +3     
  Branches     4802     4798       -4     
==========================================
+ Hits        22113    22143      +30     
+ Misses      28831    28803      -28     
- Partials      524      525       +1     
Flag Coverage Δ
backend 43.10% <24.48%> (+0.05%) ⬆️
frontend 41.34% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

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

Three rule families consolidated into one PR because each fix needs
per-site judgment rather than mechanical replacement.

cs/virtual-call-in-constructor (5): seal CMSFile, StudentClassYear,
RoleTemplateSimplified — none are inherited from in C# and none are
mocked; project has no UseLazyLoadingProxies so EF doesn't need them
non-sealed. Drops `virtual` on properties newly declared inside the
now-sealed classes.

cs/unsafe-year-construction (4): in PercentRolloverService, bound the
HTTP-derived year parameter with ArgumentOutOfRangeException and use
.AddYears(1) instead of `new DateTime(year+1, ...)` for the target
end date. In AcademicYearHelper.GetAcademicYearStart, build the July
date first then .AddYears(-1) instead of subtracting from .Year before
constructing.

cs/constant-condition (21): remove redundant null-propagation that
the analyzer can already prove dead — `?.` chains after `!= null`
guards, an unreachable CompetencyId range check after the FindAsync
record-existence check, and a duplicated `RegionEndpoint` element
lookup in SetAwsCredentials. RAPSController null-flow was restructured
to lift the path null check up.
@rlorenzo rlorenzo force-pushed the codeql/3-correctness branch from b0b03a6 to 7b95293 Compare May 13, 2026 08:35
These were flagged by the ReSharper PR-scoped gate as new warnings on
lines my CodeQL 3 fix touched:

- CMSFile.cs: drop redundant 'partial' modifier (PartialTypeWithSinglePart)
- RAPSController.cs: 'is int idx' on int? -> 'is { } idx'
  (ConvertTypeCheckPatternToNullCheck)
- RoleTemplatesController.cs: drop '??' fallbacks; both properties are
  declared non-null (NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract)
- Program.cs: drop redundant 'Amazon.' qualifier on RegionEndpoint
  (RedundantNameQualifier)
- RoleTemplateSimplified.cs: convert Roles setter to 'init' so the
  getter has a clear owner (UnusedAutoPropertyAccessor.Global)
@rlorenzo rlorenzo force-pushed the codeql/3-correctness branch from 7b95293 to 53b6eef Compare May 13, 2026 09:30
@rlorenzo
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/Areas/RAPS/Controllers/RoleTemplatesController.cs`:
- Around line 45-49: Replace the explicit loop and mutable list plumbing by
projecting dbRoleTemplates into the simplified DTO: use a LINQ Select that calls
RoleTemplateSimplified.FromRoleTemplate for each rt on dbRoleTemplates and
materialize to a List (assign to roleTemplates) instead of creating
roleTemplates and using foreach + Add.

In `@web/Areas/RAPS/Models/RoleTemplateSimplified.cs`:
- Around line 22-31: Replace the manual mapping inside
RoleTemplateSimplified.FromRoleTemplate by delegating to a Mapperly-generated
mapper: change the implementation to call
RoleTemplateSimplifiedMapper.ToSimplified(rt), and add a new static partial
mapper type named RoleTemplateSimplifiedMapper decorated with
[Mapper(RequiredMappingStrategy = RequiredMappingStrategy.None)] that declares a
partial method ToSimplified(RoleTemplate source) returning
RoleTemplateSimplified so Mapperly can generate the mapping.

In `@web/Program.cs`:
- Around line 558-565: The lookup can return null for unknown names; replace the
reflection-based lookup with RegionEndpoint.GetBySystemName(regionValue) (or try
both regionValue and a PascalCase variant) and if that returns null either set
profile.Region = RegionEndpoint.USWest1 as a safe default or throw a
FormatException; update the code around regionValue/profile.Region to use
RegionEndpoint.GetBySystemName(regionValue) and handle a null result explicitly
(throwing FormatException or assigning the default).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 501d2df3-d7b5-44d5-a105-53874a3f7b1b

📥 Commits

Reviewing files that changed from the base of the PR and between 5949e52 and 53b6eef.

📒 Files selected for processing (15)
  • test/CTS/AssessmentControllerTest.cs
  • web/Areas/CMS/Models/CMSFile.cs
  • web/Areas/CTS/Controllers/AssessmentController.cs
  • web/Areas/CTS/Controllers/CompetencyController.cs
  • web/Areas/CTS/Models/AuditRow.cs
  • web/Areas/Effort/Services/PercentRolloverService.cs
  • web/Areas/Effort/Services/PercentageService.cs
  • web/Areas/RAPS/Controllers/RAPSController.cs
  • web/Areas/RAPS/Controllers/RoleTemplatesController.cs
  • web/Areas/RAPS/Models/RoleTemplateSimplified.cs
  • web/Areas/RAPS/Services/RAPSAuditService.cs
  • web/Classes/Utilities/AcademicYearHelper.cs
  • web/Controllers/HomeController.cs
  • web/Models/Students/StudentClassYear.cs
  • web/Program.cs
💤 Files with no reviewable changes (1)
  • web/Areas/CTS/Controllers/CompetencyController.cs

Comment thread web/Areas/RAPS/Controllers/RoleTemplatesController.cs Outdated
Comment thread web/Areas/RAPS/Models/RoleTemplateSimplified.cs
Comment thread web/Program.cs Outdated
@rlorenzo rlorenzo force-pushed the codeql/3-correctness branch 3 times, most recently from c92bfb2 to 46c06c2 Compare May 13, 2026 16:49
rlorenzo added 2 commits May 13, 2026 09:52
- RoleTemplatesController.GetRoleTemplates: replace foreach + Add with
  .Select(...).ToList() to match the project's LINQ conventions.
- Program.cs SetAwsCredentials: trim the RegionEndpoint value, look it
  up with BindingFlags.IgnoreCase, and fall back to USWest1 when the
  name is non-empty but does not match any known region (previously
  left profile.Region as null).
Two unit tests for the static factory introduced by codeql/3:

- FromRoleTemplate_MapsScalarsAndFlattensRoles: verifies the scalar
  properties and the nested RoleTemplateRoles -> Roles flattening
  via Role.RoleId / Role.FriendlyName.
- FromRoleTemplate_EmptyRoles_ReturnsEmptyCollection: ensures the
  Roles initializer does not depend on a non-empty source collection.

Gives the constructor-to-factory conversion a regression net.
@rlorenzo rlorenzo force-pushed the codeql/3-correctness branch from 46c06c2 to 57e3771 Compare May 13, 2026 16:52
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