Skip to content

Phase A.1: Security, authorization, and foundation hardening - #2

Merged
henter36 merged 17 commits into
mainfrom
phase-a1-security-hardening
Jul 19, 2026
Merged

Phase A.1: Security, authorization, and foundation hardening#2
henter36 merged 17 commits into
mainfrom
phase-a1-security-hardening

Conversation

@henter36

@henter36 henter36 commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Phase A.1 security hardening + correction round (scopes, audit, attachments, CI, history cleanup).
  • Credential fallbacks removed; TestAuth/Demo Seed fail-fast; privilege and attachment scope guards; immutable audit; Entra/frontend production gates.
  • Git history rewritten to remove historical SQL secret; CI secret rotated; gitleaks full-history clean.

Test plan

  • CI green on latest tip (secret-scan, backend unit+integration+migrations, frontend)
  • NuGet High/Critical gate + fail-closed self-test
  • Operators confirm local/shared SQL credential rotation where the historical password was reused

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Added Microsoft Entra ID authentication configuration and production checks.
    • Added permission-based access controls, user provisioning states, and scope-aware authorization.
    • Added health and readiness endpoints for database, storage, and authentication configuration.
    • Added safer attachment validation, scanning states, storage protection, and scoped access.
  • Bug Fixes
    • Prevented unauthorized users and out-of-scope records or attachments from being accessed.
    • Improved audit-log protection and sensitive data redaction.
  • Documentation
    • Updated setup, testing, authentication, and Phase A.1 security documentation.
  • Tests
    • Expanded backend and frontend security, authorization, authentication, and integration coverage.

henter36 and others added 5 commits July 19, 2026 10:36
Close critical production-security gaps before Phase B: remove credential fallbacks, fail-fast TestAuth/Demo Seed, privilege and scope guards, immutable audit, attachment isolation, Entra/frontend production gates, migrations, and mandatory CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
Harden attachment entity resolution and path containment, require Grant* permissions for Global/HQ assignment, restrict national audit to Global/HQ, fail-closed NuGet scanning, Entra startup validation, and expand unit/integration/frontend coverage.

Co-authored-by: Cursor <cursoragent@cursor.com>
Replace gitleaks-action push range scan with full-history detect, surface integration test failures instead of swallowing output, and wait for authenticated SQL readiness before tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
… tests.

Use WebHost UseSetting alongside in-memory configuration so ConnectionStrings:Baseera is available under minimal hosting during CI.

Co-authored-by: Cursor <cursoragent@cursor.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@sourcery-ai sourcery-ai Bot 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.

Sorry @henter36, your pull request is larger than the review limit of 150000 diff characters

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@henter36, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 13 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 86b36a27-4467-423b-b8ac-a0175fadbaad

📥 Commits

Reviewing files that changed from the base of the PR and between 6c8a49f and f25aef0.

📒 Files selected for processing (18)
  • .github/workflows/ci.yml
  • docs/phase-a1-completion-report.md
  • scripts/test-nuget-vuln-gate-fail-closed.sh
  • sonar-project.properties
  • src/backend/Baseera.Api/Health/HealthExtensions.cs
  • src/backend/Baseera.Api/Middleware/Middleware.cs
  • src/backend/Baseera.Application/Attachments/AttachmentRules.cs
  • src/backend/Baseera.Application/Identity/UserAdminService.cs
  • src/backend/Baseera.Application/Security/EnvironmentSecurityGuard.cs
  • src/backend/Baseera.Application/Security/PrivilegeGuard.cs
  • src/backend/Baseera.Infrastructure/Identity/CurrentUser.cs
  • src/backend/Baseera.Infrastructure/Persistence/Migrations/20260719073347_PhaseA1FilteredIndexesAndRestrict.cs
  • src/frontend/.env.production
  • src/frontend/scripts/check-production-auth.mjs
  • src/frontend/src/auth/authGuards.test.ts
  • src/frontend/src/auth/msalConfig.ts
  • src/frontend/src/auth/msalInit.test.ts
  • src/frontend/src/auth/msalInit.ts
📝 Walkthrough

Walkthrough

This PR adds Phase A.1 security hardening across CI, backend authorization, environment and provisioning controls, attachment handling, persistence constraints, audit protection, integration tests, and frontend Entra authentication validation.

Changes

Phase A.1 hardening

Layer / File(s) Summary
CI, validation, and documentation
.github/workflows/ci.yml, .gitleaks.toml, scripts/*, README.md, docs/*
Adds pinned secret scanning, vulnerability gates, SQL readiness checks, frontend production-auth checks, and updated Phase A.1 setup and configuration documentation.
API authorization and runtime guards
src/backend/Baseera.Api/*, src/backend/Baseera.Api/Program.cs
Adds permission policies, route-level authorization, health endpoints, provisioning middleware, environment validation, and configurable migrations and seeding.
Application authorization and attachment controls
src/backend/Baseera.Application/*, src/backend/Baseera.Domain/Identity/*
Adds privilege and scope guards, provisioning states, attachment validation and path containment, permission constants, and stricter audit and user-management authorization.
Persistence, audit, and migrations
src/backend/Baseera.Infrastructure/*
Adds soft-delete filters, filtered indexes, restrictive foreign keys, append-only audit enforcement, guarded attachment storage, provisioning resolution, and EF migrations.
Backend hardening validation
src/backend/tests/*
Adds unit and integration coverage for authorization boundaries, provisioning states, attachment scanning and scope isolation, audit immutability, secret redaction, and startup guards.
Frontend authentication flow
src/frontend/*
Adds Entra production configuration checks, session-backed test auth gating, single-flight MSAL initialization, token refresh handling, and login-page validation.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • henter36/Baseera#1 — Implements overlapping Phase A.1 authorization, scope, attachment, audit, CI, and frontend authentication hardening.

Sequence Diagram(s)

sequenceDiagram
  participant LoginPage
  participant AuthProvider
  participant MSAL
  participant API
  LoginPage->>AuthProvider: loginEntra()
  AuthProvider->>MSAL: ensureMsalInitialized()
  AuthProvider->>MSAL: loginPopup() and acquireToken()
  AuthProvider->>API: request with access token
  API-->>AuthProvider: authenticated user or 401
  AuthProvider-->>LoginPage: refreshed auth state
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.47% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change set: Phase A.1 hardening across security, authorization, and project foundations.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch phase-a1-security-hardening

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.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request implements Phase A.1 security hardening and authorization improvements for the Baseera platform, including Entra ID integration, environment fail-fast guards, soft-delete filters, audit log immutability, attachment security (magic bytes and path guards), and privilege escalation checks. The review feedback highlights a bug in magic bytes validation that rejects small text files, a potential crash in React development mode due to duplicate MSAL initialization, and opportunities to improve performance by adopting asynchronous file I/O and SHA256 hashing.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/backend/Baseera.Application/Attachments/AttachmentRules.cs Outdated
Comment thread src/frontend/src/auth/AuthProvider.tsx
Comment thread src/frontend/src/auth/AuthProvider.tsx Outdated
Comment thread src/frontend/src/auth/AuthProvider.tsx Outdated
Comment thread src/backend/Baseera.Api/Health/HealthExtensions.cs Outdated
Comment thread src/backend/Baseera.Application/Attachments/AttachmentRules.cs Outdated
Comment thread src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs Outdated
henter36 and others added 4 commits July 19, 2026 11:23
Co-authored-by: Cursor <cursoragent@cursor.com>
Harden CI supply chain (least privilege, pinned gitleaks checksum, npm --ignore-scripts), refactor PrivilegeGuard/AttachmentService for complexity, and fix async SHA/health plus MSAL single-flight without weakening A.1 controls.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Unquoted gitleaks run args were parsed as multiple YAML scalars; use a block scalar so secret-scan can start.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs (1)

139-173: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Sensitive-permission check happens too late — audit log records a "successful" download for requests later denied, and a file stream can leak on audit failure.

Two related ordering problems in this method:

  1. EnsureEntityInScopeAsync/scan-status checks don't include the classification/sensitive-permission check. That check only happens afterward in AttachmentAppService.DownloadAsync (that file, Lines 47-52), by which point this method has already opened the file stream, written an audit "Download" entry, and called SaveChangesAsync. A caller without AttachmentsDownloadSensitive who requests a Confidential attachment gets a logged "successful" download in the audit trail even though the request is ultimately rejected and the stream is disposed unread.
  2. stream = await storage.OpenReadAsync(...) has no enclosing try/finally; if the subsequent audit.WriteAsync or db.SaveChangesAsync throws, the opened Stream is never disposed.

Moving the classification check up (this service already has currentUser injected) and writing the audit before opening the stream resolves both issues.

🔧 Suggested fix
         if (entity.ScanStatus is AttachmentScanStatus.PendingScan or AttachmentScanStatus.Quarantined or AttachmentScanStatus.Rejected)
         {
             throw new UnauthorizedAccessException("لا يمكن تنزيل المرفق قبل اكتمال الفحص الأمني بنجاح.");
         }
 
+        if (entity.Classification >= ClassificationLevel.Confidential &&
+            !currentUser.HasPermission(PermissionCodes.AttachmentsDownloadSensitive))
+        {
+            throw new UnauthorizedAccessException("يتطلب تنزيل هذا المرفق صلاحية حساسة.");
+        }
+
+        await audit.WriteAsync(new AuditEntry
+        {
+            Action = "Download",
+            Module = "Attachments",
+            EntityType = nameof(Attachment),
+            EntityId = entity.Id.ToString(),
+            IsSensitiveView = entity.Classification >= ClassificationLevel.Confidential,
+            NewValues = new { entity.OriginalFileName, entity.Classification, entity.ScanStatus }
+        }, cancellationToken);
+        await db.SaveChangesAsync(cancellationToken);
+
         Stream stream;
         try
         {
             stream = await storage.OpenReadAsync(entity.StoragePath, cancellationToken);
         }
         catch (FileNotFoundException)
         {
             throw new InvalidOperationException("تعذر استرجاع محتوى المرفق.");
         }
 
-        await audit.WriteAsync(new AuditEntry
-        {
-            Action = "Download",
-            Module = "Attachments",
-            EntityType = nameof(Attachment),
-            EntityId = entity.Id.ToString(),
-            IsSensitiveView = entity.Classification >= ClassificationLevel.Confidential,
-            NewValues = new { entity.OriginalFileName, entity.Classification, entity.ScanStatus }
-        }, cancellationToken);
-        await db.SaveChangesAsync(cancellationToken);
-
         return (entity, stream);

With this in place, AttachmentAppService.DownloadAsync's classification recheck becomes redundant defense-in-depth and could be simplified/removed there.

🤖 Prompt for 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.

In `@src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs` around
lines 139 - 173, Update AttachmentService.DownloadAsync to enforce the
classification-sensitive permission using the injected currentUser before any
audit or storage access, alongside EnsureEntityInScopeAsync and the scan-status
validation. Write and save the Download audit entry before calling
storage.OpenReadAsync, so denied requests are not audited as successful and
audit failures cannot leak a stream; retain the existing file-not-found
handling. Simplify or remove the redundant classification check in
AttachmentAppService.DownloadAsync.
🧹 Nitpick comments (4)
.github/workflows/ci.yml (1)

112-125: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid running integration tests twice.

Currently, the integration tests are executed twice—once for generating the result and once to parse the output for skipped tests. Integration tests are often slow and stateful. Instead, capture the output of the first run using tee and parse that file to fail the build if there are skipped tests.

♻️ Proposed refactoring
       - name: Integration tests
         run: |
           set -euo pipefail
           set +e
-          dotnet test src/backend/tests/Baseera.IntegrationTests -c Release --logger "console;verbosity=detailed"
-          status=$?
+          dotnet test src/backend/tests/Baseera.IntegrationTests -c Release --logger "console;verbosity=detailed" | tee test_output.log
+          status=$?
           set -e
           if [[ "$status" -ne 0 ]]; then
             exit "$status"
           fi
-          summary=$(dotnet test src/backend/tests/Baseera.IntegrationTests -c Release --no-build --verbosity quiet)
-          if echo "$summary" | grep -E 'Skipped:\s*[1-9]' >/dev/null; then
+          if grep -E 'Skipped:\s*[1-9]' test_output.log >/dev/null; then
             echo "Integration tests reported skips; failing CI" >&2
             exit 1
           fi
🤖 Prompt for 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.

In @.github/workflows/ci.yml around lines 112 - 125, Update the integration-test
shell block to run dotnet test only once, capturing its output with tee into a
temporary or workspace file while preserving the exit status. Parse that
captured output for skipped tests after the run, retain the existing failure
messages, and ensure either test failures or detected skips cause the job to
exit nonzero.
src/frontend/src/pages/LoginPage.tsx (1)

18-47: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Blank login page if mode is neither 'entra' nor test-allowed.

If getAuthMode() ever returns something other than 'entra' while isTestAuthAllowed() is false (e.g., a misconfigured non-production build with mode === 'test' but import.meta.env.DEV false), the user sees no login action and no explanatory message — none of the three conditional blocks render. This is presumably guarded by the production config-validation script, but there's no client-side fallback message for this state.

♻️ Optional fallback message
         {mode === 'entra' && !isTestAuthAllowed() && !configError && (
           <p className="muted">استخدم زر Entra لتسجيل الدخول. لا يتوفر وضع الاختبار في هذا البناء.</p>
         )}
+        {mode !== 'entra' && !isTestAuthAllowed() && !configError && (
+          <p className="error" role="alert">تعذر تحديد وضع تسجيل الدخول. تحقق من إعدادات البيئة.</p>
+        )}
🤖 Prompt for 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.

In `@src/frontend/src/pages/LoginPage.tsx` around lines 18 - 47, Add a client-side
fallback message in the LoginPage rendering for any authentication state where
mode is not 'entra' and isTestAuthAllowed() is false, ensuring the page never
renders blank. Keep the existing Entra and TestAuth controls unchanged, and make
the fallback explain that no supported login method is available.
src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs (1)

273-284: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider reusing the new UsersIncludingDeleted abstraction instead of manual IgnoreQueryFilters().

This bypasses all global query filters via IgnoreQueryFilters() and manually re-applies only !u.IsDeleted, duplicating what the newly-introduced IBaseeraDbContext.UsersIncludingDeleted (Abstractions.cs) appears intended for. Using that property here (if BaseeraDbContext implements the interface) would centralize the "bypass filters, re-check IsDeleted" logic in one place.

🤖 Prompt for 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.

In `@src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs` around
lines 273 - 284, The ResolveUserAccessAsync method manually bypasses all query
filters and rechecks IsDeleted; replace that query with the existing
UsersIncludingDeleted abstraction, preserving the entityId match, cancellation
token, and not-found behavior.
src/backend/tests/Baseera.IntegrationTests/BaseeraApiFactory.cs (1)

144-166: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

SeedUserWithPermissionsAsync mutates a shared Role's permissions, not a per-test grant.

Permissions are added directly to the Role row (roleCodes[0]), which is shared by every user assigned that role within the same test database/fixture instance. If multiple tests in the same class seed different users with the same role code but different extraPermissions, later grants leak into earlier-seeded users' effective permissions since they share the same Role. This is risky for exactly the kind of scope/permission isolation assertions this PR is adding (ScopeIsolationTests.cs, OrganizationalScopeServiceTests.cs).

Consider creating a dedicated role per invocation (e.g., a synthetic role code derived from subject) instead of mutating a shared, potentially-reused role.

🤖 Prompt for 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.

In `@src/backend/tests/Baseera.IntegrationTests/BaseeraApiFactory.cs` around lines
144 - 166, Update SeedUserWithPermissionsAsync to create or reuse a dedicated
synthetic role for each subject before applying extraPermissions, rather than
adding permissions to the shared roleCodes[0] role. Assign that per-invocation
role to the seeded user and add RolePermissions to it, ensuring users seeded
with different permissions cannot inherit grants from one another.
🤖 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 @.github/workflows/ci.yml:
- Around line 44-45: Fix the YAML syntax in the “Gitleaks full history” workflow
step by removing the unmatched quotes around the command or converting the run
value to a block scalar. Preserve the existing Gitleaks arguments and behavior.

In `@src/backend/Baseera.Api/Middleware/Middleware.cs`:
- Around line 96-98: Update the 403 response detail in the middleware’s
problem-details construction to replace the English “Provisioning” term with its
Arabic equivalent, keeping the rest of the Arabic user-facing message and status
unchanged.

In `@src/backend/Baseera.Application/Attachments/AttachmentRules.cs`:
- Around line 98-108: Update the header-reading logic in the attachment
validation method to fill the entire 8-byte buffer using ReadExactly or a loop,
rather than relying on one Stream.Read call. Perform the required-length check
only after reading until the buffer is full or the stream reaches EOF, while
preserving the existing short/corrupt file exception behavior.

In `@src/backend/Baseera.Application/Identity/UserAdminService.cs`:
- Around line 17-36: Update AssignScopeRequestValidator to require Reason to be
non-empty or non-whitespace in addition to its existing maximum-length rule, so
blank values fail through FluentValidation before AssignScopeAsync’s manual
check. Preserve the existing scope-shape validation and length limit.

In `@src/backend/Baseera.Infrastructure/Identity/CurrentUser.cs`:
- Around line 105-114: Update UserProvisioningService.ResolveAsync to avoid
saving bookkeeping fields on every authenticated request: throttle updates to
LastLoginAtUtc, DisplayNameAr, and Email, and handle
DbUpdateConcurrencyException from this non-critical SaveChangesAsync by ignoring
or logging it so the request still succeeds.

In `@src/frontend/.env.production`:
- Line 7: Update VITE_ENTRA_REDIRECT_URI in the production environment
configuration to use the deployed HTTPS origin, or leave it empty to fall back
to window.location.origin; do not retain the localhost HTTP value.
- Around line 4-6: Replace the all-zero Entra GUID values in
src/frontend/.env.production lines 4-6 with placeholders containing YOUR_ so
existing gates reject unreplaced configuration; update
src/frontend/scripts/check-production-auth.mjs lines 24-30 and
validateEntraEnv() in src/frontend/src/auth/msalConfig.ts lines 1-14 to also
reject all-zero GUID and 00000000-0000-... placeholder patterns, keeping
build-time and runtime validation consistent.

In `@src/frontend/src/auth/msalInit.ts`:
- Around line 15-25: Update ensureMsalInitialized so a rejected
instance.initialize() clears msalInitializationPromise before propagating the
failure, allowing subsequent callers to retry initialization. Preserve the
existing shared-promise behavior for concurrent callers and successful
initialization.

---

Outside diff comments:
In `@src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs`:
- Around line 139-173: Update AttachmentService.DownloadAsync to enforce the
classification-sensitive permission using the injected currentUser before any
audit or storage access, alongside EnsureEntityInScopeAsync and the scan-status
validation. Write and save the Download audit entry before calling
storage.OpenReadAsync, so denied requests are not audited as successful and
audit failures cannot leak a stream; retain the existing file-not-found
handling. Simplify or remove the redundant classification check in
AttachmentAppService.DownloadAsync.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 112-125: Update the integration-test shell block to run dotnet
test only once, capturing its output with tee into a temporary or workspace file
while preserving the exit status. Parse that captured output for skipped tests
after the run, retain the existing failure messages, and ensure either test
failures or detected skips cause the job to exit nonzero.

In `@src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs`:
- Around line 273-284: The ResolveUserAccessAsync method manually bypasses all
query filters and rechecks IsDeleted; replace that query with the existing
UsersIncludingDeleted abstraction, preserving the entityId match, cancellation
token, and not-found behavior.

In `@src/backend/tests/Baseera.IntegrationTests/BaseeraApiFactory.cs`:
- Around line 144-166: Update SeedUserWithPermissionsAsync to create or reuse a
dedicated synthetic role for each subject before applying extraPermissions,
rather than adding permissions to the shared roleCodes[0] role. Assign that
per-invocation role to the seeded user and add RolePermissions to it, ensuring
users seeded with different permissions cannot inherit grants from one another.

In `@src/frontend/src/pages/LoginPage.tsx`:
- Around line 18-47: Add a client-side fallback message in the LoginPage
rendering for any authentication state where mode is not 'entra' and
isTestAuthAllowed() is false, ensuring the page never renders blank. Keep the
existing Entra and TestAuth controls unchanged, and make the fallback explain
that no supported login method is available.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8143b3f8-b42b-4e44-a1ed-b2a1cff3b86e

📥 Commits

Reviewing files that changed from the base of the PR and between 7074c57 and 6c8a49f.

📒 Files selected for processing (68)
  • .github/workflows/ci.yml
  • .gitleaks.toml
  • README.md
  • docs/entra-id-configuration.md
  • docs/phase-a1-completion-report.md
  • docs/phase-a1-current-findings.md
  • scripts/check-nuget-vulnerabilities.sh
  • scripts/deploy-db.sql
  • scripts/test-nuget-vuln-gate-fail-closed.sh
  • src/backend/Baseera.Api/Auth/TestAuthHandler.cs
  • src/backend/Baseera.Api/Authorization/AuthorizationExtensions.cs
  • src/backend/Baseera.Api/Baseera.Api.csproj
  • src/backend/Baseera.Api/Endpoints/ApiEndpoints.cs
  • src/backend/Baseera.Api/Health/HealthExtensions.cs
  • src/backend/Baseera.Api/Middleware/Middleware.cs
  • src/backend/Baseera.Api/Program.cs
  • src/backend/Baseera.Api/appsettings.example.json
  • src/backend/Baseera.Api/appsettings.json
  • src/backend/Baseera.Application/Abstractions/Abstractions.cs
  • src/backend/Baseera.Application/Attachments/AttachmentAppService.cs
  • src/backend/Baseera.Application/Attachments/AttachmentRules.cs
  • src/backend/Baseera.Application/Attachments/StoragePathGuard.cs
  • src/backend/Baseera.Application/Audit/AuditQueryService.cs
  • src/backend/Baseera.Application/DependencyInjection/ApplicationServiceCollectionExtensions.cs
  • src/backend/Baseera.Application/Identity/UserAdminService.cs
  • src/backend/Baseera.Application/Organization/OrganizationService.cs
  • src/backend/Baseera.Application/Security/EnvironmentSecurityGuard.cs
  • src/backend/Baseera.Application/Security/OrganizationalScopeService.cs
  • src/backend/Baseera.Application/Security/PrivilegeGuard.cs
  • src/backend/Baseera.Domain/Identity/IdentityEntities.cs
  • src/backend/Baseera.Domain/Identity/UserProvisioningStatus.cs
  • src/backend/Baseera.Infrastructure/Attachments/AttachmentService.cs
  • src/backend/Baseera.Infrastructure/Audit/AuditService.cs
  • src/backend/Baseera.Infrastructure/DependencyInjection/InfrastructureServiceCollectionExtensions.cs
  • src/backend/Baseera.Infrastructure/Identity/CurrentUser.cs
  • src/backend/Baseera.Infrastructure/Persistence/BaseeraDbContext.cs
  • src/backend/Baseera.Infrastructure/Persistence/BaseeraDbContextFactory.cs
  • src/backend/Baseera.Infrastructure/Persistence/Configurations/EntityConfigurations.cs
  • src/backend/Baseera.Infrastructure/Persistence/DatabaseInitializer.cs
  • src/backend/Baseera.Infrastructure/Persistence/Migrations/20260719071930_PhaseA1Hardening.Designer.cs
  • src/backend/Baseera.Infrastructure/Persistence/Migrations/20260719071930_PhaseA1Hardening.cs
  • src/backend/Baseera.Infrastructure/Persistence/Migrations/20260719073347_PhaseA1FilteredIndexesAndRestrict.Designer.cs
  • src/backend/Baseera.Infrastructure/Persistence/Migrations/20260719073347_PhaseA1FilteredIndexesAndRestrict.cs
  • src/backend/Baseera.Infrastructure/Persistence/Migrations/BaseeraDbContextModelSnapshot.cs
  • src/backend/tests/Baseera.IntegrationTests/Baseera.IntegrationTests.csproj
  • src/backend/tests/Baseera.IntegrationTests/BaseeraApiFactory.cs
  • src/backend/tests/Baseera.IntegrationTests/PhaseA1HardeningIntegrationTests.cs
  • src/backend/tests/Baseera.IntegrationTests/ScopeIsolationTests.cs
  • src/backend/tests/Baseera.UnitTests/AttachmentPathAuditTests.cs
  • src/backend/tests/Baseera.UnitTests/AttachmentRulesTests.cs
  • src/backend/tests/Baseera.UnitTests/AttachmentStorageHealthCheckTests.cs
  • src/backend/tests/Baseera.UnitTests/AuditImmutabilityTests.cs
  • src/backend/tests/Baseera.UnitTests/AuditSecretRedactorTests.cs
  • src/backend/tests/Baseera.UnitTests/Baseera.UnitTests.csproj
  • src/backend/tests/Baseera.UnitTests/OrganizationalScopeServiceTests.cs
  • src/backend/tests/Baseera.UnitTests/PrivilegeProvisioningSoftDeleteTests.cs
  • src/backend/tests/Baseera.UnitTests/StartupGuardHostTests.cs
  • src/frontend/.env.production
  • src/frontend/package.json
  • src/frontend/scripts/check-production-auth.mjs
  • src/frontend/src/api/client.ts
  • src/frontend/src/auth/AuthProvider.tsx
  • src/frontend/src/auth/authGuards.test.ts
  • src/frontend/src/auth/msalConfig.ts
  • src/frontend/src/auth/msalInit.test.ts
  • src/frontend/src/auth/msalInit.ts
  • src/frontend/src/pages/LoginPage.test.tsx
  • src/frontend/src/pages/LoginPage.tsx

Comment thread .github/workflows/ci.yml Outdated
Comment thread src/backend/Baseera.Api/Middleware/Middleware.cs
Comment thread src/backend/Baseera.Application/Attachments/AttachmentRules.cs Outdated
Comment thread src/backend/Baseera.Application/Identity/UserAdminService.cs
Comment thread src/backend/Baseera.Infrastructure/Identity/CurrentUser.cs Outdated
Comment thread src/frontend/.env.production Outdated
Comment thread src/frontend/.env.production Outdated
Comment thread src/frontend/src/auth/msalInit.ts
henter36 and others added 8 commits July 19, 2026 12:12
Exclude Persistence/Migrations from copy-paste detection, make EnsureRoleRankAllowsGrant static, and clarify the NuGet fail-closed self-test success message.

Co-authored-by: Cursor <cursoragent@cursor.com>
…sed gates.

Exclude EF Persistence/Migrations from Sonar analysis, reject zero-GUID and non-HTTPS redirect placeholders, clear MSAL init cache on failure, and verify gitleaks against the official checksums file.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Extract shared foreign-key drop/add helpers and fix msalConfig placeholder typing so Sonar no longer fails on mirrored migration blocks.

Co-authored-by: Cursor <cursoragent@cursor.com>
Use ReadExactly for magic-byte headers, require non-empty scope Reason in FluentValidation, throttle login bookkeeping writes, and update the completion report after Sonar QG green.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Split ValidateMagicBytes and PersistLoginBookkeepingAsync so Sonar Critical S3776 smells on new code stay at or below 15.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@sonarqubecloud

Copy link
Copy Markdown

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.

1 participant