Skip to content

Bump the dotnet group with 18 updates#12

Closed
dependabot[bot] wants to merge 20 commits into
mainfrom
dependabot/nuget/dotnet-026c4b0cf3
Closed

Bump the dotnet group with 18 updates#12
dependabot[bot] wants to merge 20 commits into
mainfrom
dependabot/nuget/dotnet-026c4b0cf3

Conversation

@dependabot
Copy link
Copy Markdown

@dependabot dependabot Bot commented on behalf of github Jun 1, 2026

Updated coverlet.collector from 6.0.4 to 10.0.1.

Release notes

Sourced from coverlet.collector's releases.

10.0.1

Improvements

Fixed

  • Fix inconsistent paths in cobertura reports #​1723
  • Fix when using "is" with "and" in pattern matching, branch coverage is lower than normal #​1313
  • Fix Coverlet flagging a branch for an async functions finally block where none exists #​1337
  • Fix Coverlet Tracker Missing CompilerGeneratedAttribute #​1828

Maintenance

  • Add architecture docs and diagrams for all integrations #​1927
  • Update NuGet packages and .NET SDK versions #​1933

Diff between 10.0.0 and 10.0.1

10.0.0

Improvements

  • Unique Report Filenames (coverlet.MTP and AzDO) #​1866
  • Add --coverlet-file-prefix option for unique report files #​1869
  • Introduce .NET 10 support #​1823

Fixed

  • Fix [BUG] Wrong branch rate on IAsyncEnumerable for generic type #​1836
  • Fix [BUG] Missing Coverage after moving to MTP #​1843
  • Fix [BUG] No coverage reported when targeting .NET Framework with 8.0.1 #​1842
  • Fix [BUG] Behavior changes between MTP and Legacy (msbuild) #​1878
  • Fix [BUG] Coverlet.MTP - Unable to load coverlet.mtp.appsettings.json #​1880
  • Fix [BUG] Coverlet.Collector produces empty report when Mediator.SourceGenerator is referenced #​1718 by https://github.com/yusyd
  • Fix [BUG] Crash during instrumentation (Methods using LibraryImport/DllImport have no body) #​1762

Maintenance

  • Add comprehensive async method tests and documentation for issue #​1864
  • Replace Tmds.ExecFunction Package in coverlet.core.coverage.tests #​1833
  • Add net9.0 and net10.0 targets #​1822

Diff between 8.0.1 and 10.0.0

8.0.1

Fixed

  • Fix [BUG] TypeInitializationException when targeting .NET Framework #​1818
  • Fix [BUG] coverlet.MTP build fails with CS0400 due to developmentDependency=true #​1827

Improvements

  • Additional improvements needed for .NET Framework instrumentation type import #​1825

Diff between 8.0.0 and 8.0.1

8.0.0

Special Thanks: A huge thank you to @​Bertk for driving the majority of the work in this release! 🎉

Fixed

Improvements

  • Coverlet MTP extension feature #​1788
  • Generate SBOM for nuget packages #​1752
  • Use multi targets projects for coverlet.collector, coverlet.msbuild.tasks packages #​1742
  • Use .NET 8.0 target framework for coverlet.core and remove Newtonsoft.Json #​1733
  • Use latest System.CommandLine version #​1660
  • Upgraded minimum required .NET SDK and runtime to .NET 8.0 LTS (Long Term Support) (Breaking Change)
  • Use xunit.v3 for tests and example code

Diff between 6.0.4 and 8.0.0

Commits viewable in compare view.

Updated FluentAssertions from 7.2.0 to 8.10.0.

Release notes

Sourced from FluentAssertions's releases.

8.10.0

What's Changed

Improvements

Documentation

Others

Full Changelog: fluentassertions/fluentassertions@8.9.0...8.10.0

8.9.0

What's Changed

New features

Improvements

Fixes

Documentation

Others

8.8.0

What's Changed

New features

Improvements

Documentation

Others

Full Changelog: fluentassertions/fluentassertions@8.7.1...8.8.0

8.7.1

What's Changed

Others

Full Changelog: fluentassertions/fluentassertions@8.7.0...8.7.1

8.7.0

What's Changed

New features

Others

Full Changelog: fluentassertions/fluentassertions@8.6.0...8.7.0

8.6.0

What's Changed

Improvements

Others

New Contributors

Full Changelog: fluentassertions/fluentassertions@8.5.0...8.6.0

8.5.0

What's Changed

New features

Fixes

Others

Full Changelog: fluentassertions/fluentassertions@8.4.0...8.5.0

8.4.0

What's Changed

Improvements

Others

New Contributors

Full Changelog: fluentassertions/fluentassertions@8.3.0...8.4.0

8.3.0

What's Changed

Improvements

Others

Full Changelog: fluentassertions/fluentassertions@8.2.0...8.3.0

8.2.0

What's Changed

Improvements

Fixes

Others

Full Changelog: fluentassertions/fluentassertions@8.1.1...8.2.0

8.1.1

What's Changed

Fixes

Full Changelog: fluentassertions/fluentassertions@8.1.0...8.1.1

8.1.0

What's Changed

Improvements

Fixes

Documentation

Others

New Contributors

Full Changelog: fluentassertions/fluentassertions@8.0.1...8.1.0

8.0.1

What's Changed

Improvements

Others

Full Changelog: fluentassertions/fluentassertions@8.0.0...8.0.1

8.0.0

What's Changed

License change

Breaking Changes

New features

Improvements

8.0.0-rc.2

What's Changed

Fixes

Others

Full Changelog: fluentassertions/fluentassertions@8.0.0-rc.1...8.0.0-rc.2

8.0.0-rc.1

What's Changed

Breaking Changes

Fixes

Documentation

Others

8.0.0-alpha.1

What's Changed

Others

Full Changelog: fluentassertions/fluentassertions@7.0.0-alpha.6...8.0.0-alpha.1

7.2.2

What's Changed

Fixes

Building

Full Changelog: fluentassertions/fluentassertions@7.2.1...7.2.2

7.2.1

What's Changed

Fixes

Full Changelog: fluentassertions/fluentassertions@7.2.0...7.2.1

Commits viewable in compare view.

Updated FluentValidation from 12.0.0 to 12.1.1.

Release notes

Sourced from FluentValidation's releases.

12.1.0

Release notes

Please read the upgrade guide if you are moving from 11.x to 12.x

Changes in 12.1.0

  • Add Tamil language (#​2334)
  • Add Telugu language (#​2333)
  • Fixes to Japanese translations (#​2340)

Changes in 12.0.0

  • Drops support for netstandard2.0, netstandard2.1, .net 5, .net 6 and .net 7. Minimum supported platform is now .net 8.
  • Add support for dependent rules for custom rules (#​2170)
  • Removes deprecated DI extensions
  • Removes deprecated transform methods (#​2027)
  • Remove the ability to disable the root-model null check (#​2069)
  • Use Zomp.SyncMethodGenerator to clean up internal sync/async code paths and increase performance (#​2136)
  • Add Serbian (Cyrillic) language; rename existing Serbian to Serbian (Latin) (#​2283)

Downloads

Binaries can be downloaded from nuget:

Commits viewable in compare view.

Updated FluentValidation.DependencyInjectionExtensions from 12.0.0 to 12.1.1.

Release notes

Sourced from FluentValidation.DependencyInjectionExtensions's releases.

12.1.0

Release notes

Please read the upgrade guide if you are moving from 11.x to 12.x

Changes in 12.1.0

  • Add Tamil language (#​2334)
  • Add Telugu language (#​2333)
  • Fixes to Japanese translations (#​2340)

Changes in 12.0.0

  • Drops support for netstandard2.0, netstandard2.1, .net 5, .net 6 and .net 7. Minimum supported platform is now .net 8.
  • Add support for dependent rules for custom rules (#​2170)
  • Removes deprecated DI extensions
  • Removes deprecated transform methods (#​2027)
  • Remove the ability to disable the root-model null check (#​2069)
  • Use Zomp.SyncMethodGenerator to clean up internal sync/async code paths and increase performance (#​2136)
  • Add Serbian (Cyrillic) language; rename existing Serbian to Serbian (Latin) (#​2283)

Downloads

Binaries can be downloaded from nuget:

Commits viewable in compare view.

Updated Microsoft.AspNetCore.Authentication.JwtBearer from 10.0.0 to 10.0.8.

Release notes

Sourced from Microsoft.AspNetCore.Authentication.JwtBearer's releases.

No release notes found for this version range.

Commits viewable in compare view.

Updated Microsoft.AspNetCore.OpenApi from 10.0.0 to 10.0.8.

Release notes

Sourced from Microsoft.AspNetCore.OpenApi's releases.

No release notes found for this version range.

Commits viewable in compare view.

Updated Microsoft.EntityFrameworkCore from 10.0.0 to 10.0.8.

Release notes

Sourced from Microsoft.EntityFrameworkCore's releases.

No release notes found for this version range.

Commits viewable in compare view.

Updated Microsoft.EntityFrameworkCore.Relational from 10.0.0 to 10.0.4.

Release notes

Sourced from Microsoft.EntityFrameworkCore.Relational's releases.

No release notes found for this version range.

Commits viewable in compare view.

Updated Microsoft.Extensions.DependencyInjection.Abstractions from 10.0.0 to 10.0.8.

Release notes

Sourced from Microsoft.Extensions.DependencyInjection.Abstractions's releases.

No release notes found for this version range.

Commits viewable in compare view.

Updated Microsoft.Extensions.Hosting.Abstractions from 10.0.3 to 10.0.8.

Release notes

Sourced from Microsoft.Extensions.Hosting.Abstractions's releases.

No release notes found for this version range.

Commits viewable in compare view.

Updated Microsoft.IdentityModel.JsonWebTokens from 8.14.0 to 8.18.0.

Release notes

Sourced from Microsoft.IdentityModel.JsonWebTokens's releases.

8.18.0

New Features

  • Introduced a new interface IConfigurationEventHandlerContextAware<T> that provides context to the configuration event handler implementation, allowing it to optionally bypass a cache lookup. See PR #​3444.
  • Added Microsoft.IdentityModel.Dpop — a new package implementing DPoP (Demonstrating Proof-of-Possession) per RFC 9449. Provides both client-side and server-side proof validation with no System.Net.Http dependency. See PR #​3443.

8.17.0

Dependencies

  • Downgrade MicrosoftExtensionsLoggingAbstractionsVersion to 8.0.0 on .NET 10. See PR #​3435.

8.16.0

New Features

  • Add telemetry around signature validation. See PR #​3415 for details.

Fundamentals

  • Fix FileVersion format to use two-digit year and day of year. See PR #​3389 for details.

8.15.0

New Features

  • Add ECDsa support in X509SecurityKey and JsonWebKeyConverter.ConvertFromX509SecurityKey
    Extended X509SecurityKey and JsonWebKeyConverter.ConvertFromX509SecurityKey to support ECDSA keys.
    See PR #​2377 for details.

Bug Fixes

  • Sanitize logs to avoid leaking sensitive data
    Updated logging to sanitize sensitive values, reducing the risk of inadvertently exposing secrets or PII in logs.
    See PR #​3316 for details.
  • Optimize log sanitization with SearchValues
    Improved the performance of the log sanitization logic introduced earlier by using SearchValues, making sanitization more efficient in high-throughput scenarios.
    See PR #​3341 for details.
  • Update test for IDX10400
    Adjusted the IDX10400 test to align with the current behavior and error messaging.
    See PR #​3314 for details.

Fundamentals

  • Add supported algorithm tests
    Added new tests to validate the set of supported cryptographic algorithms, increasing confidence in algorithm coverage and compatibility.
    See PR #​3296 for details.
  • Migrate repository agent rules from .clinerules to agents.md
    Moved repository agent/AI-assist rules into markdown documentation to make them more visible and easier to maintain.
    See PR #​3313 for details.
  • Migrate Microsoft.IdentityModel.TestExtensions from Newtonsoft.Json to System.Text.Json
    Updated Microsoft.IdentityModel.TestExtensions to use System.Text.Json instead of Newtonsoft.Json, aligning tests with the runtime serialization stack.
    See PR #​3356 for details.
  • Disable code coverage comments
    Turned off automated code coverage comments on PRs to reduce noise while retaining coverage data elsewhere.
    See PR #​3349 for details.
  • Fix CodeQL alerts
    Addressed CodeQL-reported issues to improve security posture and static analysis cleanliness.
    See PR #​3364 for details.

.NET 10 / SDK and tooling updates

  • Building with .NET 10 preview / RC 1
    Updated the repository to build and test against .NET 10.0 preview/RC1, ensuring early compatibility with the upcoming runtime.
    See PRs #​3287, #​3357, and #​3358 for details.
  • Fix .NET 10 test execution consistency
    Ensured consistent use of the TargetNetNext parameter across build, test, and pack phases so .NET 10.0 tests execute reliably.
    See PR #​3337 for details.
  • Update project files and workflows for .NET 10.0 compatibility
    Adjusted project files and CI workflows to correctly target and run on .NET 10.0, including test and pack scenarios.
    See PR #​3363 for details.
  • Update .NET version to meet CG compliance
    Updated the .NET version references to be compliant with corporate governance (CG) requirements.
    See PR #​3353 for details.
  • Update Coverlet collector and test SDK
    • Bumped CoverletCollectorVersion to 6.0.4.
      See PR #​3333 for details.
    • Upgraded Microsoft.NET.Test.Sdk to a newer version for improved test reliability and tooling support.
      ... (truncated)

Commits viewable in compare view.

Updated Microsoft.IdentityModel.Tokens from 8.14.0 to 8.18.0.

Release notes

Sourced from Microsoft.IdentityModel.Tokens's releases.

8.18.0

New Features

  • Introduced a new interface IConfigurationEventHandlerContextAware<T> that provides context to the configuration event handler implementation, allowing it to optionally bypass a cache lookup. See PR #​3444.
  • Added Microsoft.IdentityModel.Dpop — a new package implementing DPoP (Demonstrating Proof-of-Possession) per RFC 9449. Provides both client-side and server-side proof validation with no System.Net.Http dependency. See PR #​3443.

8.17.0

Dependencies

  • Downgrade MicrosoftExtensionsLoggingAbstractionsVersion to 8.0.0 on .NET 10. See PR #​3435.

8.16.0

New Features

  • Add telemetry around signature validation. See PR #​3415 for details.

Fundamentals

  • Fix FileVersion format to use two-digit year and day of year. See PR #​3389 for details.

8.15.0

New Features

  • Add ECDsa support in X509SecurityKey and JsonWebKeyConverter.ConvertFromX509SecurityKey
    Extended X509SecurityKey and JsonWebKeyConverter.ConvertFromX509SecurityKey to support ECDSA keys.
    See PR #​2377 for details.

Bug Fixes

  • Sanitize logs to avoid leaking sensitive data
    Updated logging to sanitize sensitive values, reducing the risk of inadvertently exposing secrets or PII in logs.
    See PR #​3316 for details.
  • Optimize log sanitization with SearchValues
    Improved the performance of the log sanitization logic introduced earlier by using SearchValues, making sanitization more efficient in high-throughput scenarios.
    See PR #​3341 for details.
  • Update test for IDX10400
    Adjusted the IDX10400 test to align with the current behavior and error messaging.
    See PR #​3314 for details.

Fundamentals

  • Add supported algorithm tests
    Added new tests to validate the set of supported cryptographic algorithms, increasing confidence in algorithm coverage and compatibility.
    See PR #​3296 for details.
  • Migrate repository agent rules from .clinerules to agents.md
    Moved repository agent/AI-assist rules into markdown documentation to make them more visible and easier to maintain.
    See PR #​3313 for details.
  • Migrate Microsoft.IdentityModel.TestExtensions from Newtonsoft.Json to System.Text.Json
    Updated Microsoft.IdentityModel.TestExtensions to use System.Text.Json instead of Newtonsoft.Json, aligning tests with the runtime serialization stack.
    See PR #​3356 for details.
  • Disable code coverage comments
    Turned off automated code coverage comments on PRs to reduce noise while retaining coverage data elsewhere.
    See PR #​3349 for details.
  • Fix CodeQL alerts
    Addressed CodeQL-reported issues to improve security posture and static analysis cleanliness.
    See PR #​3364 for details.

.NET 10 / SDK and tooling updates

  • Building with .NET 10 preview / RC 1
    Updated the repository to build and test against .NET 10.0 preview/RC1, ensuring early compatibility with the upcoming runtime.
    See PRs #​3287, #​3357, and #​3358 for details.
  • Fix .NET 10 test execution consistency
    Ensured consistent use of the TargetNetNext parameter across build, test, and pack phases so .NET 10.0 tests execute reliably.
    See PR #​3337 for details.
  • Update project files and workflows for .NET 10.0 compatibility
    Adjusted project files and CI workflows to correctly target and run on .NET 10.0, including test and pack scenarios.
    See PR #​3363 for details.
  • Update .NET version to meet CG compliance
    Updated the .NET version references to be compliant with corporate governance (CG) requirements.
    See PR #​3353 for details.
  • Update Coverlet collector and test SDK
    • Bumped CoverletCollectorVersion to 6.0.4.
      See PR #​3333 for details.
    • Upgraded Microsoft.NET.Test.Sdk to a newer version for improved test reliability and tooling support.
      ... (truncated)

Commits viewable in compare view.

Updated Microsoft.NET.Test.Sdk from 17.14.1 to 18.6.0.

Release notes

Sourced from Microsoft.NET.Test.Sdk's releases.

18.6.0

What's Changed

Changes to tests and infra

Description has been truncated

Summary by CodeRabbit

Release Notes

  • New Features

    • Admin portal for company onboarding and management (create, list, activate/suspend companies)
    • Vendor platform with fleet management (add/list buses) and trip scheduling (create, list, cancel trips)
    • Complete customer booking flow with seat selection, hold management, and secure checkout
    • Payment webhook handling with development simulation endpoints
    • Booking history viewer ("My Bookings")
    • Refresh token rotation and HttpOnly cookie security
  • Infrastructure & Deployment

    • Automated CI/CD pipelines with GitHub Actions
    • Docker containerization for API and web services
    • Health check endpoints (liveness and readiness probes)
    • Automated dependency and security scanning
  • Security & Auth

    • JWT tokens now include company context for multi-tenant isolation
    • Improved production configuration validation
    • Rate limiting policies for admin, vendor, and webhook endpoints

kashkoool and others added 20 commits May 31, 2026 21:47
…e, bounded trip search

check-performance-server pass (adapted from NestJS/Prisma checklist to ASP.NET Core):
- H1 Brotli+Gzip response compression (verified at runtime: Content-Encoding negotiated)
- H3 app-level 30s request timeout (UseRequestTimeouts)
- H4 CORS preflight cached 24h (SetPreflightMaxAge)
- DB1 SearchTrips bounded with Take(100)

Also lands the pending check-security hardening if not already committed (proxy-aware
real client IP, named rate-limit tiers, API CSP + COOP, StartupGuards, webhook format gate).

Build 0 errors, 21 unit tests green, boots healthy with compression negotiated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… (multi-tenant)

Increment 3 - the actors trips/booking depend on, with tenant isolation enforced
at the data layer (the rebuild fixes the old system's company_id leak risk).

Admin (AdminOnly policy = Admin/SuperAdmin):
- POST /api/admin/companies (onboard, starts Pending) + paginated list (status filter)
- activate / suspend a company
- create the vendor-manager login bound to a company

Vendor (VendorOnly policy = VendorManager; every handler scopes to the caller's company_id):
- POST/GET /api/vendor/buses (fleet CRUD, unique bus number per company)
- POST/GET /api/vendor/trips (schedule on own bus; seat count taken from the bus)
- POST /api/vendor/trips/{id}/cancel

Cross-cutting:
- company_id stamped on the JWT (vendor accounts) -> ICurrentUser resolves it from claims;
  vendor handlers bake company_id into the EF where-clause (IDOR-safe: another tenant's
  id is 404, never a 403 oracle).
- ITokenService/IIdentityService extended to carry company; role-based authz policies wired.
- Pagination helper (PagedResult/PageRequest, limit hard-capped at 100) reused by all lists.
- Tests: +9 unit (PageRequest clamping) = 30 green; +VendorTenancyTests integration
  (cross-tenant 404, no fleet leakage, customer->vendor = 403) [needs Docker to run].

Build 0 errors, 30 unit green, boots healthy (vendor endpoint 401 unauthenticated).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ness rules

Fixes from a 3-angle read-only audit (business-logic, security, DB/edge-cases).

Security:
- Booking flow IDOR closed: /api/bookings/* and /api/payments/checkout now require login;
  the booking binds to the JWT identity (email/owner), never the request body. GetTicket +
  StartCheckout scope by customer_email in the where-clause (foreign id -> 404, no oracle).
- AllowedHosts locked to an explicit host list (no *); StartupGuards rejects * in prod
  and now flags dev_only/dev_sandbox/integration-tests placeholder secrets.
- Payment webhook: dedicated rate-limit tier (60/min) + body read as raw bytes (HMAC matches
  the signed bytes, no StreamReader encoding ambiguity).
- Headers: X-Permitted-Cross-Domain-Policies: none; explicit 2-year HSTS + IncludeSubDomains.

Validation caps:
- HoldSeats <= 10 seats, CreateBooking <= 10 passengers (+ name MaxLength); SearchTrips gains
  a validator (origin/destination required, <= 120 chars) wired into the endpoint.

Database integrity:
- FK constraints between all domain tables (trip->company/bus, seat_hold->trip,
  seat_assignment->trip, booking->trip, payment->booking, bus->company) with Restrict/Cascade
  delete behavior. New migration AddForeignKeys.
- Npgsql CommandTimeout(30) + EnableRetryOnFailure(3).
- Integration tests now MigrateAsync (not EnsureCreated) so migrations + FKs are exercised.

Business rules:
- Suspended-company enforcement: SearchTrips filters to active companies; HoldSeats rejects a
  suspended trip; ScheduleTrip rejects scheduling for a suspended company.
- ScheduleTrip rejects past-date departures.
- CancelTrip cleans up in one transaction: releases active holds, cancels pending bookings,
  counts confirmed bookings (refund flow deferred) and returns the impact.
- Webhook/sweeper race: ConsumeOnConfirmation tolerates a just-expired hold (payment is
  authoritative; the unique seat_assignment constraint is the real double-sell guard).

Deferred (tracked): payment refund gateway flow (needs a real provider).

Build 0 errors, 35 unit tests green (+5), boots healthy: booking/vendor/checkout -> 401
unauthenticated, search validation -> 400, security headers present.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds StartupGuardsTests covering each production-config guard: committed
placeholder secrets, wildcard AllowedHosts, missing proxy hops, and a
non-TLS DB connection all block prod boot; Development skips the checks
and a fully valid prod config passes. References the Api project so the
pure config-validation function is reachable from the unit test project.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ooking confirmation

Surfaced by running the integration suite against real Postgres for the
first time (it previously used EnsureCreated, which masked both):

1. InitialSchema built the seat_hold filtered unique index with
   filter "consumed = false", but the column is created as "Consumed"
   (EF quotes identifiers, so Postgres stores it case-sensitively). The
   unquoted name folds to lowercase and the index build fails with
   42703, so MigrateAsync could never apply the first migration. Quote
   the identifier to match the column.

2. Domain aggregates assign their own Guid identity in the Entity base
   constructor, but EF treated the keys as store-generated. A new child
   attached to an already-tracked aggregate — a SeatAssignment created
   during booking confirmation, where the Booking was loaded first — was
   then mistaken for an existing row and issued as an UPDATE, which
   affected 0 rows and threw DbUpdateConcurrencyException, 500-ing the
   payment webhook (the core money path). A model convention marks every
   Entity-derived Guid key ValueGeneratedNever so EF inserts such
   graph-discovered entities. No schema change (the columns have no DB
   default); SyncClientGeneratedKeys is the resulting no-op migration
   that keeps the model snapshot in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A browser SPA keeps the access token in memory and must never hold the
long-lived refresh token in JS-reachable storage. Register/login/refresh
now also set the refresh token in an HttpOnly + Secure + SameSite=Strict
cookie scoped to /api/auth; refresh and logout read it from there
(body still accepted first for API/native clients and the existing
tests). CORS gains AllowCredentials (valid only with the explicit origin
list already configured) so the cookie flows cross-origin. Secure is
relaxed only in Development so the cookie still works over plain-HTTP
ng serve / TestServer; production stays Secure.

Also makes the rate-limit permit counts config-driven (production
defaults unchanged) — TestServer has no real client IP so every request
shares one bucket; the integration host raises the limits to exercise
the auth/booking flow rather than the limiter. A new integration test
proves refresh works from the cookie alone, rotates, detects reuse, and
that logout clears the cookie.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
500s still return a generic ProblemDetails in production (no internal
leakage), but in Development the handler now includes the exception
message, type, failing EF entries, and stack — the integration test
runner doesn't capture the server console, so this is what makes a 500
debuggable. The booking webhook test now asserts the response body on
failure instead of a bare EnsureSuccessStatusCode, so the cause is
visible directly in the test output.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ings

The customer web app needs a "My Bookings" view, but the API only
exposed hold/create/ticket. Adds a login-required list endpoint backed
by ListMyBookingsHandler: a single join query (no N+1), scoped to the
caller's email from the JWT so a customer only ever sees their own
bookings, newest first, bounded to 100 rows. Integration test proves a
customer sees their booking and never another customer's.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Sandbox gateway returns a fake hosted-checkout URL that isn't a real
page, and only the backend holds the webhook secret, so a browser can't
complete a payment on its own. POST /api/payments/dev/simulate (mapped
ONLY in Development) signs a webhook payload server-side and runs it
through the real ProcessPaymentWebhookHandler, so the customer app can
drive pay -> confirm -> ticket end-to-end locally. It is never mapped in
production, so there's no way to forge a confirmation there.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ing journey

The first frontend: a standalone, lazy-routed SPA that drives the whole
customer flow against the existing API — register/login, search trips,
hold seats with a live 10-minute countdown, enter passengers, create the
booking, pay (sandbox-simulated in dev, gateway hand-off in prod), and
view the QR ticket plus a My-bookings list.

Security per the token model we agreed on:
- access token in memory only (a signal) — never web storage
- refresh token used only via the HttpOnly cookie; the app silently
  restores the session from it at startup and on a 401 (single-flight
  refresh + one retry, then redirect to login)
- requests carry withCredentials so the cookie flows; errors map from
  ProblemDetails to a toast (401s are left to the auth interceptor)

Tooling: Tailwind v4 (build-time CSS), a dev proxy so /api is same-origin
with ng serve, per-environment apiBaseUrl, ESLint (angular-eslint) clean,
and a production build within budget. README covers how to run it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…0.0.8

The existing transitive pin sat at 10.0.0, but that build is itself
flagged by NU1903 for two high-severity advisories (GHSA-37gx-xxp4-5rgx,
GHSA-w3x6-4m5h-cxqf) — the earlier pin only moved off 9.0.0, not onto a
fixed build. 10.0.8 is the patched servicing release; central transitive
pinning forces it across every project, and the restore is now warning-
free. (The app does no XML signing/SAML, so the vulnerable path was never
reachable — this is defense-in-depth and a clean scan.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds LayeringTests: reflection over assembly references that fails the
build if an inner layer takes a real dependency on an outer one — Domain
must depend on nothing, Application must not depend on Infrastructure or
Api. A positive anchor (Application DOES depend on Domain) proves the
check observes real references, so the guards can't pass vacuously. This
turns the inward-only dependency rule from a code-review convention into
an automated guarantee. No new package — System.Reflection only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…oint

The dev-only /api/payments/dev/simulate endpoint injected the concrete
SandboxPaymentGateway (Infrastructure) and called ComputeSignature — the
one spot where the Api layer reached past an Application abstraction into
a concrete Infrastructure type. Introduce IPaymentWebhookSigner (an
Application seam), implement it on SandboxPaymentGateway, and inject the
interface in the endpoint, dropping the Infrastructure import. The Api
now depends only on Application abstractions, like every other endpoint.
Integration test drives the endpoint end-to-end (pay -> confirm) through
the new seam.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The strategic docs lived only in the parent folder, so a developer in
the repo had no statement of how the code is organized or the rules that
keep it changeable. ARCHITECTURE.md names the approach (Clean
Architecture, the inward Dependency Rule, SOLID — esp. Open/Closed and
Dependency-Inversion, separation of concerns) with a layer diagram and
the conventions for extending safely, and points at LayeringTests as the
enforcement. README covers build/test/run and links it all together.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Orchestrators need a dependency-free liveness probe and a deep readiness
probe. /health now runs zero checks (200 if the process is up), so a slow
or booting database can never cause a restart loop; /health/ready runs a
"ready"-tagged DatabaseHealthCheck (one cheap EXISTS query via the
Application abstraction) to gate traffic until the DB is reachable.
Integration tests cover both.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…l stack

Multi-stage, non-root images verified to build and run together:
- API (mcr.microsoft.com/dotnet/aspnet:10.0): publishes the app and a
  self-contained EF migrations bundle (./efbundle) run as a one-off
  before startup, never from the app. Build context is the repo root so
  it sees the shared props + .editorconfig (the latter carries the
  analyzer config that exempts EF-generated migrations from CA1861 —
  without it the Release build fails on generated code).
- Web (nginxinc/nginx-unprivileged): serves the Angular bundle, SPA
  fallback, long-cache for fingerprinted assets, and proxies /api to the
  API so the SameSite=Strict refresh cookie stays same-origin.
- docker-compose wires postgres (healthcheck) -> migrator (applies
  migrations, exits 0) -> api (waits healthy) -> web. Smoke-tested:
  liveness/readiness 200, search proxied through nginx returns from
  Postgres, and register sets the HttpOnly rt cookie end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- ci.yml (PR + push): backend build (warnings-as-errors) + unit/
  integration tests (Testcontainers Postgres on the runner), frontend
  build + ESLint, Docker build smoke for both images, gitleaks secret
  scan.
- deploy.yml (push to main): build + push transport-api / transport-web
  images to GHCR, tagged by commit SHA + latest. No external cloud
  account or long-lived secrets — uses the built-in GITHUB_TOKEN.
- codeql.yml: SAST for C# and TypeScript (security-and-quality).
- dependency-review.yml: blocks PRs adding vulnerable / disallowed-
  license dependencies.
- scorecard.yml: OpenSSF supply-chain score + badge.
- dependabot.yml: weekly updates for NuGet (CPM), npm, Actions, Docker.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Documents the compose workflow, the two images, every GitHub Actions
workflow, the production config StartupGuards requires (TLS DB, real
signing key, TrustedHops, explicit AllowedHosts), the migration/rollback
strategy, the liveness-vs-readiness probe wiring, and deploy targets
(VPS/compose, Azure Container Apps, AWS ECS/App Runner). README links to
it and shows the one-line `docker compose up`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps coverlet.collector from 6.0.4 to 10.0.1
Bumps FluentAssertions from 7.2.0 to 8.10.0
Bumps FluentValidation from 12.0.0 to 12.1.1
Bumps FluentValidation.DependencyInjectionExtensions from 12.0.0 to 12.1.1
Bumps Microsoft.AspNetCore.Authentication.JwtBearer from 10.0.0 to 10.0.8
Bumps Microsoft.AspNetCore.OpenApi from 10.0.0 to 10.0.8
Bumps Microsoft.EntityFrameworkCore from 10.0.0 to 10.0.8
Bumps Microsoft.EntityFrameworkCore.Relational from 10.0.0 to 10.0.4
Bumps Microsoft.Extensions.DependencyInjection.Abstractions from 10.0.0 to 10.0.8
Bumps Microsoft.Extensions.Hosting.Abstractions from 10.0.3 to 10.0.8
Bumps Microsoft.IdentityModel.JsonWebTokens from 8.14.0 to 8.18.0
Bumps Microsoft.IdentityModel.Tokens from 8.14.0 to 8.18.0
Bumps Microsoft.NET.Test.Sdk from 17.14.1 to 18.6.0
Bumps Npgsql.EntityFrameworkCore.PostgreSQL from 10.0.0 to 10.0.2
Bumps Scalar.AspNetCore from 2.10.0 to 2.14.14
Bumps StackExchange.Redis from 2.9.25 to 2.13.17
Bumps Testcontainers.PostgreSql from 4.7.0 to 4.12.0
Bumps xunit.runner.visualstudio from 3.1.4 to 3.1.5

---
updated-dependencies:
- dependency-name: coverlet.collector
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dotnet
- dependency-name: FluentAssertions
  dependency-version: 8.10.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dotnet
- dependency-name: FluentValidation
  dependency-version: 12.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: FluentValidation.DependencyInjectionExtensions
  dependency-version: 12.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: Microsoft.AspNetCore.Authentication.JwtBearer
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Microsoft.AspNetCore.OpenApi
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Microsoft.EntityFrameworkCore
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Microsoft.Extensions.DependencyInjection.Abstractions
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Microsoft.Extensions.Hosting.Abstractions
  dependency-version: 10.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Microsoft.IdentityModel.JsonWebTokens
  dependency-version: 8.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: Microsoft.IdentityModel.Tokens
  dependency-version: 8.18.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: Microsoft.NET.Test.Sdk
  dependency-version: 18.6.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: dotnet
- dependency-name: Microsoft.EntityFrameworkCore.Relational
  dependency-version: 10.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Npgsql.EntityFrameworkCore.PostgreSQL
  dependency-version: 10.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
- dependency-name: Scalar.AspNetCore
  dependency-version: 2.14.14
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: StackExchange.Redis
  dependency-version: 2.13.17
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: Testcontainers.PostgreSql
  dependency-version: 4.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: dotnet
- dependency-name: xunit.runner.visualstudio
  dependency-version: 3.1.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: dotnet
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file .NET Pull requests that update .NET code labels Jun 1, 2026
@kashkoool
Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

Adds admin/vendor APIs, auth refresh via HttpOnly cookie, rate limiting, health checks, and exception details in development. Enforces booking/payment ownership, adds EF FK mappings and migrations, introduces CI/CD workflows and deploys Docker images. Adds a full Angular customer SPA with auth, search, booking, payment (sandbox), tickets, and tests.

Changes

End-to-end platform expansion

Layer / File(s) Summary
Full-stack feature, infra, and web integration
src/**, tests/**, .github/workflows/*, docker-compose.yml, web/customer/**, docs/configs
Implements security/middleware, admin/vendor endpoints, booking/payment ownership, EF FK/migrations, CI/CD/deploy, Dockerfiles, and a new Angular SPA covering auth, booking, payment, tickets, with comprehensive tests and docs.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

✨ 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 dependabot/nuget/dotnet-026c4b0cf3
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch dependabot/nuget/dotnet-026c4b0cf3

Copy link
Copy Markdown

@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: 11

Caution

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

⚠️ Outside diff range comments (1)
tests/TransportPlatform.IntegrationTests/ApiFactory.cs (1)

24-26: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix obsolete PostgreSqlBuilder constructor to unblock the CI pipeline.

The parameterless PostgreSqlBuilder() constructor is obsolete. Pass the image directly to the constructor instead of chaining .WithImage().

🔧 Proposed fix
-    private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder()
-        .WithImage("postgres:17-alpine")
-        .Build();
+    private readonly PostgreSqlContainer _postgres = new PostgreSqlBuilder("postgres:17-alpine")
+        .Build();
🤖 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 `@tests/TransportPlatform.IntegrationTests/ApiFactory.cs` around lines 24 - 26,
The PostgreSqlBuilder is being constructed with the obsolete parameterless ctor
plus .WithImage(); update the _postgres field initialization to pass the image
string into the PostgreSqlBuilder constructor instead (i.e. use new
PostgreSqlBuilder("postgres:17-alpine")...) and then call .Build(); locate the
PostgreSqlBuilder usage in the ApiFactory class (the private readonly
PostgreSqlContainer _postgres field) and replace the current chained
.WithImage(...) call with the image passed to the constructor.
🧹 Nitpick comments (5)
DEPLOYMENT.md (1)

57-60: ⚡ Quick win

Add language specification to fenced code block.

The fenced code block should specify a language for proper syntax highlighting and linting compliance.

📝 Proposed fix
-```
+```text
 ghcr.io/<owner>/transport-api:<sha>   ghcr.io/<owner>/transport-api:latest
 ghcr.io/<owner>/transport-web:<sha>   ghcr.io/<owner>/transport-web:latest
</details>

As per coding guidelines (static analysis: markdownlint-cli2 flagged MD040 fenced-code-language).

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @DEPLOYMENT.md around lines 57 - 60, The fenced code block that lists the
ghcr.io image tags lacks a language specifier and triggers markdownlint MD040;
update the opening fence from totext (or another appropriate language
such as bash/sh) for the code block containing the lines
"ghcr.io//transport-api: ..." and
"ghcr.io//transport-web: ..." so the block declares its language for
proper syntax highlighting and linter compliance.


</details>

</blockquote></details>
<details>
<summary>web/customer/src/app/features/tickets/ticket.ts (1)</summary><blockquote>

`90-92`: _💤 Low value_

**Consider user feedback for QR generation failures.**

When QR code generation fails (line 92), the error is silently swallowed by setting `qr` to `null`. While the ticket information remains visible, users won't know why the QR code is missing. Consider logging the error or showing a brief message (e.g., "QR code unavailable") to improve user experience.



<details>
<summary>💬 Proposed enhancement</summary>

```diff
         toDataURL(ticket.qrPayload, { margin: 1, width: 176 })
           .then((url) => this.qr.set(url))
-          .catch(() => this.qr.set(null));
+          .catch((err) => {
+            console.error('Failed to generate QR code:', err);
+            this.qr.set(null);
+          });
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/customer/src/app/features/tickets/ticket.ts` around lines 90 - 92, The QR
generation promise currently swallows errors by setting this.qr to null in the
catch block; update the catch to both log the error (e.g., console.error or
process/logger) and set a user-visible fallback state so the UI can show "QR
code unavailable" (add or use a field like this.qrError or set this.qrMessage)
instead of silently nulling; specifically modify the
toDataURL(...).then(...).catch(...) flow (referencing toDataURL and this.qr.set)
to log the caught error and set a clear fallback flag/message the ticket
component can render.
```

</details>

</blockquote></details>
<details>
<summary>web/customer/src/app/features/tickets/my-bookings.ts (1)</summary><blockquote>

`61-69`: _⚡ Quick win_

**Surface load failures to the user.**

On error the component only clears `loading`, leaving the empty-state ("You have no bookings yet.") to render even when the request actually failed — misleading for a user who does have bookings. Consider showing a toast (a `ToastService` already exists in the app) or an inline error state.


<details>
<summary>♻️ Example</summary>

```diff
-      error: () => this.loading.set(false),
+      error: () => {
+        this.loading.set(false);
+        this.toast.error('Could not load your bookings. Please try again.');
+      },
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/customer/src/app/features/tickets/my-bookings.ts` around lines 61 - 69,
The error handler in ngOnInit currently only clears loading after calling
api.myBookings(), leaving bookings empty and showing the "no bookings" state
instead of surfacing failures; update the subscribe error callback to surface
the failure to the user (use the existing ToastService to show an error toast or
set an inline error state) and still clear loading; specifically, modify the
error handler for api.myBookings() to call ToastService.show/error (or set an
error signal on this component) and avoid calling bookings.set([]) so real
empty-state vs error is distinguishable while keeping loading.set(false).
```

</details>

</blockquote></details>
<details>
<summary>src/TransportPlatform.Application/Abstractions/ITokenService.cs (1)</summary><blockquote>

`15-15`: _⚡ Quick win_

**`ITokenService.IssueAsync(companyId)` propagation is complete in-repo (no call-site/implementation mismatch remains).**

- `JwtTokenService.IssueAsync(..., Guid? companyId, ...)` threads `companyId` into `CreateAccessToken`, which adds `company_id` only when non-null.
- `LoginHandler` and `RegisterHandler` both pass `user.CompanyId` into `tokens.IssueAsync(...)`.
- Refresh rotation uses `RefreshAsync` and fetches `user.CompanyId` from the DB (doesn’t call `IssueAsync`).
- Optional: expand the `IssueAsync` XML doc to explicitly mention the optional company context included in the token.

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
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/TransportPlatform.Application/Abstractions/ITokenService.cs` at line 15,
Update the XML documentation on ITokenService.IssueAsync to explicitly state
that the companyId parameter is optional and, when provided, will be embedded
into the issued access token as the "company_id" claim (this aligns with
JwtTokenService.CreateAccessToken behavior and the usage in
LoginHandler/RegisterHandler; RefreshAsync reads company from DB instead of
calling IssueAsync). Keep the signature unchanged but add a clear remark
describing the optional company context and its effect on the token.
```

</details>

</blockquote></details>
<details>
<summary>tests/TransportPlatform.IntegrationTests/VendorTenancyTests.cs (1)</summary><blockquote>

`108-121`: _💤 Low value_

**Redundant first vendor-manager registration.**

The first `RegisterVendorManagerAsync` (lines 109-111) registers a manager (`m-{guid}`@example.com``) whose credentials are never used — only the second registration (`login-{guid}`@example.com``) is logged in. The first call just adds an unused user row. Consider dropping it and registering only the login account.


<details>
<summary>♻️ Proposed simplification</summary>

```diff
         companyId = company.Id;
-
-            var identity = scope.ServiceProvider.GetRequiredService<IIdentityService>();
-            await identity.RegisterVendorManagerAsync(
-                $"m-{Guid.NewGuid():N}`@example.com`", "Str0ng!Passw0rd", "Mgr", companyId);
         }
 
-        // Log the manager in via the real endpoint so the token carries the company_id claim.
-        // (Re-seed the email so we know the credentials.)
+        // Register a manager via the real seam so we know the credentials, then log in
+        // via the endpoint so the token carries the company_id claim.
         var managerEmail = $"login-{Guid.NewGuid():N}`@example.com`";
```
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

```
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/TransportPlatform.IntegrationTests/VendorTenancyTests.cs` around lines
108 - 121, Remove the redundant initial call to RegisterVendorManagerAsync that
creates the unused "m-{guid}`@example.com`" user; keep only the second
registration that seeds managerEmail and is subsequently logged in so the token
carries the company_id claim. Locate the first RegisterVendorManagerAsync
invocation (the one using $"m-{Guid.NewGuid():N}`@example.com`") and delete that
block, ensuring the remaining scope that registers managerEmail, uses identity
from scope.ServiceProvider.GetRequiredService<IIdentityService>(), and passes
companyId remains unchanged.
```

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

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 22-88: The workflow uses mutable tags (e.g., actions/checkout@v4,
    actions/setup-dotnet@v4, actions/setup-node@v4, docker/setup-buildx-action@v3,
    docker/build-push-action@v6, gitleaks/gitleaks-action@v2); replace each uses:
    reference with the corresponding immutable commit SHA for that release (keep a
    trailing comment like “# v4” to indicate the tag), e.g. change
    actions/checkout@v4 to actions/checkout@ # v4, and do the same for
    actions/setup-dotnet, actions/setup-node, docker/setup-buildx-action,
    docker/build-push-action and gitleaks/gitleaks-action in this file; then apply
    the same SHA-pinning fix to the other workflow files (codeql.yml,
    dependency-review.yml, deploy.yml) and run the workflow lint/CI to ensure no
    syntax changes.

In @.github/workflows/scorecard.yml:

  • Around line 23-34: Replace the mutable GitHub Actions tags with immutable
    commit SHAs for the three referenced actions to prevent unexpected changes:
    update the three "uses" entries (actions/checkout@v4,
    ossf/scorecard-action@v2.4.0, github/codeql-action/upload-sarif@v3) to their
    corresponding commit SHAs from each action's repository (fetch the latest
    known-good commit SHA from the upstream repo or release tag and substitute it),
    ensuring you keep the same inputs (persist-credentials,
    results_file/results_format/publish_results, sarif_file/category) unchanged;
    verify the workflow runs and update the SHAs in the workflow file accordingly.

In @ARCHITECTURE.md:

  • Line 65: The documentation contains a self-referential link to
    "../ARCHITECTURE.md" inside ARCHITECTURE.md which creates a circular reference;
    update the link target or remove it: locate the link string "../ARCHITECTURE.md"
    in ARCHITECTURE.md and either replace it with the correct external architecture
    document (or section anchor) it was meant to reference, or delete the link if
    redundant so the file no longer points to itself.

In @src/TransportPlatform.Api/Security/StartupGuards.cs:

  • Around line 46-48: The current check uses allowedHosts.Trim() == "" or "" and
    misses cases where the semicolon-separated list contains "
    " (e.g.,
    "localhost;"); update the validation that populates problems by splitting
    allowedHosts on ';', trimming each entry, and if any entry is "" or equals "
    "
    add the same error message; locate the check that references the allowedHosts
    variable in StartupGuards (the block that calls problems.Add(...)) and replace
    it with per-entry validation so any wildcard entry in the list is flagged.

In @src/TransportPlatform.Application/Fleet/AddBus.cs:

  • Around line 33-41: Narrow the catch in AddBusHandler so we only translate
    Postgres unique-violation errors for the (CompanyId, BusNumber) index to
    ConflictException: in the catch (DbUpdateException) around await
    db.SaveChangesAsync(ct) inspect the exception's InnerException (and possibly its
    InnerException) via reflection — check the type name for "PostgresException" (or
    similar) and read the "SqlState" property; only when SqlState == "23505" and, if
    available, the constraint/index name matches "IX_bus_CompanyId_BusNumber" should
    you throw new ConflictException("bus.number_taken", ...); otherwise rethrow the
    original DbUpdateException so unrelated DB errors are not masked. Ensure you
    reference AddBusHandler / SaveChangesAsync and perform the reflection-based
    checks to avoid adding a direct Npgsql dependency.

In @src/TransportPlatform.Application/Trips/ScheduleTrip.cs:

  • Around line 19-44: Add a cross-field validation to ensure ArrivalUtc is
    strictly after DepartureUtc by updating ScheduleTripValidator to include a
    RuleFor(x => x.ArrivalUtc).GreaterThan(x => x.DepartureUtc) with a clear error
    message; also add a defensive check in ScheduleTripHandler (after computing
    companyId and before persisting) that throws
    ConflictException("trip.invalid_times", "Arrival must be after departure.") if
    command.ArrivalUtc <= command.DepartureUtc to prevent invalid persisted records.

In
@src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.cs:

  • Around line 8-21: The migration class SyncClientGeneratedKeys has empty
    Up/Down but its name implies it changes key-generation behavior; either make it
    explicit snapshot-only or implement the intended schema changes. If this is
    intended as a snapshot-only migration, rename the class/file to something like
    SyncClientModelSnapshot or add a clear header comment in SyncClientGeneratedKeys
    describing it contains no schema operations and only records model conventions;
    update any migration history comment as needed. If instead it should change
    client-generated-key metadata, implement the schema operations in the Up/Down
    using MigrationBuilder (e.g., AlterColumn calls with the appropriate Npgsql
    value-generation annotations such as
    Npgsql:ValueGenerationStrategy/ValueGeneratedOnAdd or ValueGeneratedNever) and
    ensure the ApplicationDbContextModelSnapshot reflects the same ValueGenerated
    settings; update the migration name to match the real intent if you add
    operations.

In @tests/TransportPlatform.UnitTests/TransportPlatform.UnitTests.csproj:

  • Around line 24-25: The unit test project TransportPlatform.UnitTests is
    incorrectly referencing the Api layer (ProjectReference to
    TransportPlatform.Api) which violates the LayeringTests rule; remove that
    ProjectReference and resolve tests by either: (A) moving the StartupGuards
    implementation into the Application layer and update tests to reference
    StartupGuards from Application, or (B) create a new TransportPlatform.Api.Tests
    project and move Api-specific tests for StartupGuards there (leaving
    TransportPlatform.UnitTests free of Api references), or (C) move LayeringTests
    into a dedicated architecture test project that references all layers for
    reflection-based validation and keep TransportPlatform.UnitTests restricted to
    non-Api layers; update test project references and namespaces accordingly and
    ensure LayeringTests no longer fails.

In @web/customer/src/app/app.ts:

  • Around line 67-69: The logout() method's subscription lacks an error handler;
    update logout() so the call to this.auth.logout().subscribe includes both a
    success and an error callback (and/or a complete handler) so failures are
    handled: on success call this.router.navigate(['/login']), on error log the
    error and surface a user-facing message (use your notification service or
    fallback alert) and decide whether to still call
    this.router.navigate(['/login']) to avoid leaving the UI in an inconsistent
    state; modify the subscription on the this.auth.logout() call accordingly.

In @web/customer/src/app/core/toast/toast.ts:

  • Around line 9-28: The container div that renders the toast list (the element
    with class "fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2") must be a
    live region so screen readers announce new toasts; add an appropriate aria-live
    value (e.g., "polite" or "assertive"), role (e.g., "status"), and
    aria-atomic="true" to that container so messages from toasts.toasts() are
    surfaced; keep existing usage of toast.message and toasts.dismiss(toast.id)
    unchanged.

In @web/customer/src/app/features/trips/search.ts:

  • Around line 143-145: The today() helper uses UTC via toISOString() which
    yields the wrong local date for many users; update the today() method in
    search.ts (the private today() function) to build the "YYYY-MM-DD" string from
    the local date parts using date.getFullYear(), date.getMonth()+1 and
    date.getDate(), zero-pad month/day to two digits, and return that formatted
    local-date string instead of slicing toISOString().

Outside diff comments:
In @tests/TransportPlatform.IntegrationTests/ApiFactory.cs:

  • Around line 24-26: The PostgreSqlBuilder is being constructed with the
    obsolete parameterless ctor plus .WithImage(); update the _postgres field
    initialization to pass the image string into the PostgreSqlBuilder constructor
    instead (i.e. use new PostgreSqlBuilder("postgres:17-alpine")...) and then call
    .Build(); locate the PostgreSqlBuilder usage in the ApiFactory class (the
    private readonly PostgreSqlContainer _postgres field) and replace the current
    chained .WithImage(...) call with the image passed to the constructor.

Nitpick comments:
In @DEPLOYMENT.md:

  • Around line 57-60: The fenced code block that lists the ghcr.io image tags
    lacks a language specifier and triggers markdownlint MD040; update the opening
    fence from totext (or another appropriate language such as bash/sh) for
    the code block containing the lines "ghcr.io//transport-api: ..."
    and "ghcr.io//transport-web: ..." so the block declares its language
    for proper syntax highlighting and linter compliance.

In @src/TransportPlatform.Application/Abstractions/ITokenService.cs:

  • Line 15: Update the XML documentation on ITokenService.IssueAsync to
    explicitly state that the companyId parameter is optional and, when provided,
    will be embedded into the issued access token as the "company_id" claim (this
    aligns with JwtTokenService.CreateAccessToken behavior and the usage in
    LoginHandler/RegisterHandler; RefreshAsync reads company from DB instead of
    calling IssueAsync). Keep the signature unchanged but add a clear remark
    describing the optional company context and its effect on the token.

In @tests/TransportPlatform.IntegrationTests/VendorTenancyTests.cs:

  • Around line 108-121: Remove the redundant initial call to
    RegisterVendorManagerAsync that creates the unused "m-{guid}@example.com" user;
    keep only the second registration that seeds managerEmail and is subsequently
    logged in so the token carries the company_id claim. Locate the first
    RegisterVendorManagerAsync invocation (the one using
    $"m-{Guid.NewGuid():N}@example.com") and delete that block, ensuring the
    remaining scope that registers managerEmail, uses identity from
    scope.ServiceProvider.GetRequiredService(), and passes
    companyId remains unchanged.

In @web/customer/src/app/features/tickets/my-bookings.ts:

  • Around line 61-69: The error handler in ngOnInit currently only clears loading
    after calling api.myBookings(), leaving bookings empty and showing the "no
    bookings" state instead of surfacing failures; update the subscribe error
    callback to surface the failure to the user (use the existing ToastService to
    show an error toast or set an inline error state) and still clear loading;
    specifically, modify the error handler for api.myBookings() to call
    ToastService.show/error (or set an error signal on this component) and avoid
    calling bookings.set([]) so real empty-state vs error is distinguishable while
    keeping loading.set(false).

In @web/customer/src/app/features/tickets/ticket.ts:

  • Around line 90-92: The QR generation promise currently swallows errors by
    setting this.qr to null in the catch block; update the catch to both log the
    error (e.g., console.error or process/logger) and set a user-visible fallback
    state so the UI can show "QR code unavailable" (add or use a field like
    this.qrError or set this.qrMessage) instead of silently nulling; specifically
    modify the toDataURL(...).then(...).catch(...) flow (referencing toDataURL and
    this.qr.set) to log the caught error and set a clear fallback flag/message the
    ticket component can render.

</details>

<details>
<summary>🪄 Autofix (Beta)</summary>

Fix all unresolved CodeRabbit comments on this PR:

- [ ] <!-- {"checkboxId": "4b0d0e0a-96d7-4f10-b296-3a18ea78f0b9"} --> Push a commit to this branch (recommended)
- [ ] <!-- {"checkboxId": "ff5b1114-7d8c-49e6-8ac1-43f82af23a33"} --> Create a new PR with the fixes

</details>

---

<details>
<summary>ℹ️ Review info</summary>

<details>
<summary>⚙️ Run configuration</summary>

**Configuration used**: Path: .coderabbit.yaml

**Review profile**: CHILL

**Plan**: Pro

**Run ID**: `83d4ede3-92f8-4066-be3a-a8bc99b0ac90`

</details>

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between c4ca81b9355df876446e92cbd164814e698d4a79 and a3f53f00ad7a1e7d39310c8ae8fa7e848d3809bb.

</details>

<details>
<summary>⛔ Files ignored due to path filters (5)</summary>

* `src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601083811_AddForeignKeys.Designer.cs` is excluded by `!**/Migrations/*.Designer.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.Designer.cs` is excluded by `!**/Migrations/*.Designer.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs` is excluded by `!**/Migrations/*ModelSnapshot.cs`
* `web/customer/package-lock.json` is excluded by `!**/package-lock.json`, `!**/package-lock.json`
* `web/customer/public/favicon.ico` is excluded by `!**/*.ico`

</details>

<details>
<summary>📒 Files selected for processing (125)</summary>

* `.dockerignore`
* `.env.example`
* `.github/dependabot.yml`
* `.github/workflows/ci.yml`
* `.github/workflows/codeql.yml`
* `.github/workflows/dependency-review.yml`
* `.github/workflows/deploy.yml`
* `.github/workflows/scorecard.yml`
* `.gitignore`
* `ARCHITECTURE.md`
* `DEPLOYMENT.md`
* `Directory.Packages.props`
* `README.md`
* `docker-compose.yml`
* `src/TransportPlatform.Api/Dockerfile`
* `src/TransportPlatform.Api/Endpoints/AdminEndpoints.cs`
* `src/TransportPlatform.Api/Endpoints/AuthEndpoints.cs`
* `src/TransportPlatform.Api/Endpoints/BookingEndpoints.cs`
* `src/TransportPlatform.Api/Endpoints/PaymentEndpoints.cs`
* `src/TransportPlatform.Api/Endpoints/TripEndpoints.cs`
* `src/TransportPlatform.Api/Endpoints/VendorEndpoints.cs`
* `src/TransportPlatform.Api/Health/DatabaseHealthCheck.cs`
* `src/TransportPlatform.Api/Identity/HttpCurrentUser.cs`
* `src/TransportPlatform.Api/Middleware/GlobalExceptionHandler.cs`
* `src/TransportPlatform.Api/Program.cs`
* `src/TransportPlatform.Api/Security/RateLimitPolicies.cs`
* `src/TransportPlatform.Api/Security/RefreshCookie.cs`
* `src/TransportPlatform.Api/Security/StartupGuards.cs`
* `src/TransportPlatform.Api/appsettings.json`
* `src/TransportPlatform.Application/Abstractions/IIdentityService.cs`
* `src/TransportPlatform.Application/Abstractions/IPaymentWebhookSigner.cs`
* `src/TransportPlatform.Application/Abstractions/ITokenService.cs`
* `src/TransportPlatform.Application/Booking/CreateBooking.cs`
* `src/TransportPlatform.Application/Booking/GetTicket.cs`
* `src/TransportPlatform.Application/Booking/HoldSeats.cs`
* `src/TransportPlatform.Application/Booking/ListMyBookings.cs`
* `src/TransportPlatform.Application/Common/AuthorizationPolicies.cs`
* `src/TransportPlatform.Application/Common/ICurrentUser.cs`
* `src/TransportPlatform.Application/Common/PagedResult.cs`
* `src/TransportPlatform.Application/Companies/CompanyDtos.cs`
* `src/TransportPlatform.Application/Companies/CreateCompany.cs`
* `src/TransportPlatform.Application/Companies/CreateCompanyManager.cs`
* `src/TransportPlatform.Application/Companies/ListCompanies.cs`
* `src/TransportPlatform.Application/Companies/SetCompanyStatus.cs`
* `src/TransportPlatform.Application/DependencyInjection.cs`
* `src/TransportPlatform.Application/Fleet/AddBus.cs`
* `src/TransportPlatform.Application/Fleet/BusDto.cs`
* `src/TransportPlatform.Application/Fleet/ListBuses.cs`
* `src/TransportPlatform.Application/Identity/Login.cs`
* `src/TransportPlatform.Application/Identity/Register.cs`
* `src/TransportPlatform.Application/Payments/ProcessPaymentWebhook.cs`
* `src/TransportPlatform.Application/Payments/StartCheckout.cs`
* `src/TransportPlatform.Application/Trips/CancelTrip.cs`
* `src/TransportPlatform.Application/Trips/ListVendorTrips.cs`
* `src/TransportPlatform.Application/Trips/ScheduleTrip.cs`
* `src/TransportPlatform.Application/Trips/SearchTrips.cs`
* `src/TransportPlatform.Application/Trips/TripDto.cs`
* `src/TransportPlatform.Domain/Booking/SeatHold.cs`
* `src/TransportPlatform.Infrastructure/DependencyInjection.cs`
* `src/TransportPlatform.Infrastructure/Identity/IdentityService.cs`
* `src/TransportPlatform.Infrastructure/Identity/JwtTokenService.cs`
* `src/TransportPlatform.Infrastructure/Payments/SandboxPaymentGateway.cs`
* `src/TransportPlatform.Infrastructure/Persistence/ApplicationDbContext.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Configurations/BookingConfiguration.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Configurations/BusConfiguration.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Configurations/PaymentConfiguration.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Configurations/SeatAssignmentConfiguration.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Configurations/SeatHoldConfiguration.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Configurations/TripConfiguration.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Migrations/20260530203237_InitialSchema.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601083811_AddForeignKeys.cs`
* `src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.cs`
* `tests/TransportPlatform.IntegrationTests/ApiFactory.cs`
* `tests/TransportPlatform.IntegrationTests/AuthFlowTests.cs`
* `tests/TransportPlatform.IntegrationTests/BookingFlowTests.cs`
* `tests/TransportPlatform.IntegrationTests/ConcurrencyTests.cs`
* `tests/TransportPlatform.IntegrationTests/HealthTests.cs`
* `tests/TransportPlatform.IntegrationTests/VendorTenancyTests.cs`
* `tests/TransportPlatform.UnitTests/Api/StartupGuardsTests.cs`
* `tests/TransportPlatform.UnitTests/Application/PageRequestTests.cs`
* `tests/TransportPlatform.UnitTests/Application/ValidatorTests.cs`
* `tests/TransportPlatform.UnitTests/Architecture/LayeringTests.cs`
* `tests/TransportPlatform.UnitTests/TransportPlatform.UnitTests.csproj`
* `web/customer/.dockerignore`
* `web/customer/.editorconfig`
* `web/customer/.gitignore`
* `web/customer/.postcssrc.json`
* `web/customer/.vscode/extensions.json`
* `web/customer/.vscode/launch.json`
* `web/customer/.vscode/tasks.json`
* `web/customer/Dockerfile`
* `web/customer/README.md`
* `web/customer/angular.json`
* `web/customer/eslint.config.js`
* `web/customer/nginx.conf`
* `web/customer/package.json`
* `web/customer/proxy.conf.json`
* `web/customer/src/app/app.config.ts`
* `web/customer/src/app/app.routes.ts`
* `web/customer/src/app/app.spec.ts`
* `web/customer/src/app/app.ts`
* `web/customer/src/app/core/api/api.service.ts`
* `web/customer/src/app/core/auth/auth.guard.ts`
* `web/customer/src/app/core/auth/auth.interceptor.ts`
* `web/customer/src/app/core/auth/auth.service.ts`
* `web/customer/src/app/core/booking-flow.ts`
* `web/customer/src/app/core/http/error.interceptor.ts`
* `web/customer/src/app/core/models.ts`
* `web/customer/src/app/core/toast/toast.service.ts`
* `web/customer/src/app/core/toast/toast.ts`
* `web/customer/src/app/features/auth/login.ts`
* `web/customer/src/app/features/auth/register.ts`
* `web/customer/src/app/features/booking/booking.ts`
* `web/customer/src/app/features/payment/pay.ts`
* `web/customer/src/app/features/tickets/my-bookings.ts`
* `web/customer/src/app/features/tickets/ticket.ts`
* `web/customer/src/app/features/trips/search.ts`
* `web/customer/src/environments/environment.development.ts`
* `web/customer/src/environments/environment.ts`
* `web/customer/src/index.html`
* `web/customer/src/main.ts`
* `web/customer/src/styles.css`
* `web/customer/tsconfig.app.json`
* `web/customer/tsconfig.json`
* `web/customer/tsconfig.spec.json`

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment thread .github/workflows/ci.yml
Comment on lines +22 to +88
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '10.0.x'
- name: Restore
run: dotnet restore
- name: Build (warnings are errors)
run: dotnet build --no-restore --configuration Release
# ubuntu-latest has a running Docker daemon, so the Testcontainers integration tests
# (real Postgres) run here too — unit + integration.
- name: Test
run: dotnet test --no-build --configuration Release --verbosity normal

frontend:
name: frontend (build + lint)
runs-on: ubuntu-latest
defaults:
run:
working-directory: web/customer
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: npm
cache-dependency-path: web/customer/package-lock.json
- run: npm ci
- name: Build (fails the budget if the bundle grows too large)
run: npm run build
- name: Lint
run: npx ng lint

docker-build:
name: docker build smoke (no push)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: API image
uses: docker/build-push-action@v6
with:
context: .
file: src/TransportPlatform.Api/Dockerfile
push: false
pull: true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Web image
uses: docker/build-push-action@v6
with:
context: web/customer
file: web/customer/Dockerfile
push: false
pull: true
cache-from: type=gha
cache-to: type=gha,mode=max

gitleaks:
name: secret scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the latest commit SHA for actions/checkout v4 release tag?

💡 Result:

The latest commit SHA for the actions/checkout v4 release tag is: fd084cde189b7b76ec305d52e27be545a0172823 [1] This SHA is shown as the commit underlying the repository ref/tag v4 (the “actions/checkout at v4” view resolves to that commit). [1][2]

Citations:


Pin actions to immutable commit SHAs.

In .github/workflows/ci.yml, uses: references are tag-pinned (mutable), e.g. actions/checkout@v4 resolves to fd084cde189b7b76ec305d52e27be545a0172823. Pin every action to an immutable commit SHA (Dependabot can keep the SHA updated while preserving a # v4 version comment).

Apply the same pinning approach to the other workflows too (e.g., codeql.yml, dependency-review.yml, deploy.yml).
As per coding guidelines: .github/workflows/** must use "pinned actions".

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 22-22: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 42-42: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 58-58: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 83-85: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 42-42: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 43-43: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 58-58: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 59-59: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 61-61: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 70-70: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 83-83: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 86-86: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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 22 - 88, The workflow uses mutable
tags (e.g., actions/checkout@v4, actions/setup-dotnet@v4, actions/setup-node@v4,
docker/setup-buildx-action@v3, docker/build-push-action@v6,
gitleaks/gitleaks-action@v2); replace each uses: reference with the
corresponding immutable commit SHA for that release (keep a trailing comment
like “# v4” to indicate the tag), e.g. change actions/checkout@v4 to
actions/checkout@<sha> # v4, and do the same for actions/setup-dotnet,
actions/setup-node, docker/setup-buildx-action, docker/build-push-action and
gitleaks/gitleaks-action in this file; then apply the same SHA-pinning fix to
the other workflow files (codeql.yml, dependency-review.yml, deploy.yml) and run
the workflow lint/CI to ensure no syntax changes.

Comment on lines +23 to +34
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: ossf/scorecard-action@v2.4.0
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
category: scorecard
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Fetch the commit SHAs for the tags currently in use

echo "actions/checkout@v4:"
gh api repos/actions/checkout/git/ref/tags/v4 --jq '.object.sha' 2>/dev/null || echo "Use: gh api repos/actions/checkout/commits/v4 --jq '.sha'"

echo ""
echo "ossf/scorecard-action@v2.4.0:"
gh api repos/ossf/scorecard-action/git/ref/tags/v2.4.0 --jq '.object.sha' 2>/dev/null || echo "Check releases page"

echo ""
echo "github/codeql-action/upload-sarif@v3:"
gh api repos/github/codeql-action/git/ref/tags/v3 --jq '.object.sha' 2>/dev/null || echo "Check releases page"

Repository: kashkoool/Transport

Length of output: 277


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the relevant part of the workflow to confirm the exact `uses:` lines/versions
sed -n '1,120p' .github/workflows/scorecard.yml | nl -ba | sed -n '1,120p'

Repository: kashkoool/Transport

Length of output: 106


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Print with line numbers using awk (since `nl` isn't available)
awk '{printf "%4d:%s\n", NR, $0}' .github/workflows/scorecard.yml | sed -n '1,160p'

Repository: kashkoool/Transport

Length of output: 1096


Pin GitHub Actions workflow uses: to commit SHAs (avoid mutable tags).

Mutable tags are used at:

  • actions/checkout@v4
  • ossf/scorecard-action@v2.4.0
  • github/codeql-action/upload-sarif@v3
Suggested change
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
         with:
           persist-credentials: false
-      - uses: ossf/scorecard-action@v2.4.0
+      - uses: ossf/scorecard-action@ff5dd8929f96a8a4dc67d13f32b8c75057829621 # v2.4.0
         with:
           results_file: results.sarif
           results_format: sarif
           publish_results: true
-      - uses: github/codeql-action/upload-sarif@v3
+      - uses: github/codeql-action/upload-sarif@fee9466b8957867761f2d78f922ab084e3e2dd17 # v3
         with:
           sarif_file: results.sarif
           category: scorecard
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: ossf/scorecard-action@v2.4.0
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
category: scorecard
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false
- uses: ossf/scorecard-action@ff5dd8929f96a8a4dc67d13f32b8c75057829621 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
publish_results: true
- uses: github/codeql-action/upload-sarif@fee9466b8957867761f2d78f922ab084e3e2dd17 # v3
with:
sarif_file: results.sarif
category: scorecard
🧰 Tools
🪛 zizmor (1.25.2)

[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 26-26: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)


[error] 31-31: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 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/scorecard.yml around lines 23 - 34, Replace the mutable
GitHub Actions tags with immutable commit SHAs for the three referenced actions
to prevent unexpected changes: update the three "uses" entries
(actions/checkout@v4, ossf/scorecard-action@v2.4.0,
github/codeql-action/upload-sarif@v3) to their corresponding commit SHAs from
each action's repository (fetch the latest known-good commit SHA from the
upstream repo or release tag and substitute it), ensuring you keep the same
inputs (persist-credentials, results_file/results_format/publish_results,
sarif_file/category) unchanged; verify the workflow runs and update the SHAs in
the workflow file accordingly.

Comment thread ARCHITECTURE.md

Higher-level context lives alongside the repo:

- [../ARCHITECTURE.md](../ARCHITECTURE.md) — module map, bounded contexts, migration plan
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Self-referential link in documentation.

Line 65 links to ../ARCHITECTURE.md from within ARCHITECTURE.md itself, which creates a circular reference. This likely should point to a different architecture document or be removed.

🤖 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 `@ARCHITECTURE.md` at line 65, The documentation contains a self-referential
link to "../ARCHITECTURE.md" inside ARCHITECTURE.md which creates a circular
reference; update the link target or remove it: locate the link string
"../ARCHITECTURE.md" in ARCHITECTURE.md and either replace it with the correct
external architecture document (or section anchor) it was meant to reference, or
delete the link if redundant so the file no longer points to itself.

Comment on lines +46 to +48
var allowedHosts = config["AllowedHosts"] ?? string.Empty;
if (allowedHosts.Trim() is "" or "*")
problems.Add("AllowedHosts must be an explicit host allow-list in production (not '*'), to prevent host-header injection.");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print the relevant section
sed -n '1,120p' src/TransportPlatform.Api/Security/StartupGuards.cs | nl -ba | sed -n '1,120p'

# Show the exact lines around the referenced snippet (lines 30-80)
nl -ba src/TransportPlatform.Api/Security/StartupGuards.cs | sed -n '30,90p'

# Search for AllowedHosts usage across the repo
rg -n "AllowedHosts" -S . || true

# Search for where StartupGuards is called/used
rg -n "StartupGuards" -S src || true

Repository: kashkoool/Transport

Length of output: 106


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/TransportPlatform.Api/Security/StartupGuards.cs"

# Print file with line numbers around the suspected area
cat -n "$FILE" | sed -n '35,80p'

# Show entire file only if it's small; otherwise just key sections
wc -l "$FILE"

# Search for how AllowedHosts is used
rg -n "AllowedHosts" -S . || true

# Search for host filtering usage
rg -n "HostFiltering|UseHostFiltering|Host header|host-header|HostHeader" -S . || true

# Search for StartupGuards usage
rg -n "StartupGuards" -S src || true

Repository: kashkoool/Transport

Length of output: 2861


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/TransportPlatform.Api/Security/StartupGuards.cs"
TESTS="tests/TransportPlatform.UnitTests/Api/StartupGuardsTests.cs"
DEPLOY="DEPLOYMENT.md"
ENVEX=".env.example"

echo "---- StartupGuards.cs (full) ----"
cat -n "$FILE" | sed -n '1,140p'

echo "---- StartupGuardsTests.cs ----"
cat -n "$TESTS" | sed -n '1,120p'

echo "---- DEPLOYMENT.md (AllowedHosts section) ----"
rg -n "AllowedHosts" "$DEPLOY" && sed -n '60,95p' "$DEPLOY"

echo "---- .env.example (AllowedHosts line) ----"
rg -n "^AllowedHosts=" "$ENVEX" && sed -n '35,60p' "$ENVEX"

Repository: kashkoool/Transport

Length of output: 9092


🌐 Web query:

ASP.NET Core AllowedHosts semicolon list wildcard "*" allows all hosts HostFiltering

💡 Result:

In ASP.NET Core Host Filtering (Kestrel HostFiltering middleware), the AllowedHosts value is a semicolon-delimited list of host names (no port numbers) [1]. A top-level wildcard "" in that list allows all non-empty Host headers (i.e., it matches any host as long as the Host header is not empty) [2]. So, using something like: AllowedHosts="" …means the Host Filtering middleware will allow requests for any non-empty host value [2]. Note: if you need to allow empty/missing Host headers as well, that is controlled separately by the AllowEmptyHosts option (default true) [3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the API csproj and print TargetFramework(s)
fd -a "TransportPlatform.Api*.csproj" -t f . | head -n 20 | cat

CSJ=$(fd -a "TransportPlatform.Api*.csproj" -t f . | head -n 1)
echo "Using: $CSJ"
cat "$CSJ" | rg -n "TargetFramework|TargetFrameworks" || true

Repository: kashkoool/Transport

Length of output: 218


🏁 Script executed:

#!/bin/bash
set -euo pipefail

CSJ="src/TransportPlatform.Api/TransportPlatform.Api.csproj"
cat -n "$CSJ" | sed -n '1,160p'

Repository: kashkoool/Transport

Length of output: 1430


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for Directory.Build.props/targets
ls -la

fd -a "Directory.Build.props" -t f . | cat || true
fd -a "Directory.Build.targets" -t f . | cat || true

# Print any such files with line numbers
for f in $(fd -a "Directory.Build.props" -t f .); do
  echo "---- $f ----"
  cat -n "$f" | sed -n '1,200p'
done

for f in $(fd -a "Directory.Build.targets" -t f .); do
  echo "---- $f ----"
  cat -n "$f" | sed -n '1,200p'
done

# Search repo for TargetFramework definitions in props/props files
rg -n "TargetFrameworks?|LangVersion|TrimEntries" -S . || true

Repository: kashkoool/Transport

Length of output: 4272


Guard should flag * anywhere inside AllowedHosts (semicolon list), not only when the whole value is *. Current check only rejects when AllowedHosts.Trim() is exactly "" or "*", so a value like localhost;* can slip through; ASP.NET Core host filtering treats an entry equal to * as allow-all.

🛡️ Proposed fix to validate each host entry
-        var allowedHosts = config["AllowedHosts"] ?? string.Empty;
-        if (allowedHosts.Trim() is "" or "*")
-            problems.Add("AllowedHosts must be an explicit host allow-list in production (not '*'), to prevent host-header injection.");
+        var allowedHosts = (config["AllowedHosts"] ?? string.Empty)
+            .Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+        if (allowedHosts.Length == 0 || allowedHosts.Any(h => h == "*"))
+            problems.Add("AllowedHosts must be an explicit host allow-list in production (not '*'), to prevent host-header injection.");
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var allowedHosts = config["AllowedHosts"] ?? string.Empty;
if (allowedHosts.Trim() is "" or "*")
problems.Add("AllowedHosts must be an explicit host allow-list in production (not '*'), to prevent host-header injection.");
var allowedHosts = (config["AllowedHosts"] ?? string.Empty)
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (allowedHosts.Length == 0 || allowedHosts.Any(h => h == "*"))
problems.Add("AllowedHosts must be an explicit host allow-list in production (not '*'), to prevent host-header injection.");
🤖 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/TransportPlatform.Api/Security/StartupGuards.cs` around lines 46 - 48,
The current check uses allowedHosts.Trim() == "" or "*" and misses cases where
the semicolon-separated list contains "*" (e.g., "localhost;*"); update the
validation that populates problems by splitting allowedHosts on ';', trimming
each entry, and if any entry is "" or equals "*" add the same error message;
locate the check that references the allowedHosts variable in StartupGuards (the
block that calls problems.Add(...)) and replace it with per-entry validation so
any wildcard entry in the list is flagged.

Comment on lines +33 to +41
try
{
await db.SaveChangesAsync(ct);
}
catch (DbUpdateException)
{
// Unique index on (company_id, bus_number).
throw new ConflictException("bus.number_taken", "A bus with this number already exists in your fleet.");
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the unique index on buses (company_id, bus_number) in EF configuration/migrations.
rg -nP -C3 '(HasIndex|IsUnique|bus_number|BusNumber)' --type=cs -g '*Bus*'

Repository: kashkoool/Transport

Length of output: 6778


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Check whether Application (or whole repo) references Npgsql/PostgresException/SqlState handling
rg -n --hidden --no-ignore -S "Npgsql\.|PostgresException|SqlState\s*[:=]|23505" . \
  --glob '!**/bin/**' --glob '!**/obj/**'

# 2) Check for DbUpdateException catch mappings elsewhere
rg -n --hidden --no-ignore -S "catch\s*\(\s*DbUpdateException" src \
  --glob '!**/bin/**' --glob '!**/obj/**'

# 3) Inspect BusConfiguration index name / and migration index name for uniqueness
rg -n --hidden --no-ignore -S "IX_bus_CompanyId_BusNumber|HasIndex\(b\s*=>\s*new\s*\{[^}]*CompanyId[^}]*BusNumber" \
  src/TransportPlatform.Infrastructure/Persistence/Configurations/BusConfiguration.cs \
  src/TransportPlatform.Infrastructure/Persistence/Migrations -g '*.cs'

# 4) Check csproj package references (Npgsql)
rg -n --hidden --no-ignore -S "PackageReference[^\\n]*Npgsql|Npgsql" src --glob '*.csproj'

Repository: kashkoool/Transport

Length of output: 2128


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find any usage of PostgresException/Npgsql.PostgresException/SqlState in the whole repo
rg -n --hidden --no-ignore -S "Npgsql\.PostgresException|PostgresException|SqlState\s*[:=]|23505" src --glob '*.cs'

# 2) Show the current DbUpdateException catch blocks in the handlers called out
for f in \
  src/TransportPlatform.Application/Companies/CreateCompany.cs \
  src/TransportPlatform.Application/Booking/CreateBooking.cs \
  src/TransportPlatform.Application/Fleet/AddBus.cs \
  src/TransportPlatform.Application/Booking/HoldSeats.cs
do
  echo "---- $f ----"
  # print around the catch block
  rg -n -C3 "catch\s*\(\s*DbUpdateException" "$f"
done

# 3) Check AddBus.cs usings / references to see if Application currently uses Npgsql types
sed -n '1,80p' src/TransportPlatform.Application/Fleet/AddBus.cs

# 4) Check Application project references (does Application.csproj reference Npgsql?).
cat src/TransportPlatform.Application/TransportPlatform.Application.csproj

Repository: kashkoool/Transport

Length of output: 45


🏁 Script executed:

#!/bin/bash
set +euo pipefail

# 1) Look for any PostgresException/Npgsql.PostgresException/SqlState usage in repo
rg -n --hidden --no-ignore -S "Npgsql\.PostgresException|PostgresException|SqlState\s*[:=]|23505" src --glob '*.cs' || true

# 2) Dump the relevant DbUpdateException catch blocks with context
for f in \
  src/TransportPlatform.Application/Companies/CreateCompany.cs \
  src/TransportPlatform.Application/Booking/CreateBooking.cs \
  src/TransportPlatform.Application/Fleet/AddBus.cs \
  src/TransportPlatform.Application/Booking/HoldSeats.cs
do
  echo "---- $f ----"
  rg -n -C6 "catch\s*\(\s*DbUpdateException" "$f" || true
done

# 3) Inspect AddBus.cs usings (first ~60 lines)
sed -n '1,90p' src/TransportPlatform.Application/Fleet/AddBus.cs

# 4) Inspect Application csproj (package refs)
cat src/TransportPlatform.Application/TransportPlatform.Application.csproj

Repository: kashkoool/Transport

Length of output: 4426


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect CreateBooking.cs further around the DbUpdateException catch
sed -n '70,140p' src/TransportPlatform.Application/Booking/CreateBooking.cs

# Search for any existing pattern of inspecting InnerException/details in the application layer
rg -n --hidden --no-ignore -S "InnerException|GetType\(\)\.FullName|SqlState|constraint|unique index|23505" src/TransportPlatform.Application --glob '*.cs'

Repository: kashkoool/Transport

Length of output: 2231


Narrow DbUpdateException handling in src/TransportPlatform.Application/Fleet/AddBus.cs to only the unique-violation for (CompanyId, BusNumber)

AddBusHandler currently maps all DbUpdateExceptions to ConflictException("bus.number_taken", ...), which can misreport unrelated DB failures. The uniqueness is enforced by a unique index on { CompanyId, BusNumber } (IX_bus_CompanyId_BusNumber), so catch only Postgres unique violations (SQLSTATE 23505) by inspecting the inner exception (via type-name/reflection, since TransportPlatform.Application doesn’t reference Npgsql) and rethrow otherwise.

🤖 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/TransportPlatform.Application/Fleet/AddBus.cs` around lines 33 - 41,
Narrow the catch in AddBusHandler so we only translate Postgres unique-violation
errors for the (CompanyId, BusNumber) index to ConflictException: in the catch
(DbUpdateException) around await db.SaveChangesAsync(ct) inspect the exception's
InnerException (and possibly its InnerException) via reflection — check the type
name for "PostgresException" (or similar) and read the "SqlState" property; only
when SqlState == "23505" and, if available, the constraint/index name matches
"IX_bus_CompanyId_BusNumber" should you throw new
ConflictException("bus.number_taken", ...); otherwise rethrow the original
DbUpdateException so unrelated DB errors are not masked. Ensure you reference
AddBusHandler / SaveChangesAsync and perform the reflection-based checks to
avoid adding a direct Npgsql dependency.

Comment on lines +8 to +21
public partial class SyncClientGeneratedKeys : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{

}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{

}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for references to SyncClientGeneratedKeys or client-generated key handling

# Check for related configuration or domain changes around the migration date
rg -n "ValueGenerated|ClientSetValue|SyncClientGeneratedKeys" \
  --type=cs \
  -g '!**/Migrations/**' \
  -C3

# Check if there are any recent changes to entity configurations that might relate to key generation
fd -e cs -t f "Configuration.cs$" \
  --exec rg -l "HasKey|ValueGeneratedNever|ValueGeneratedOnAdd" {}

Repository: kashkoool/Transport

Length of output: 2877


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Show the migration file content (lines ~8-60)
mig="src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.cs"
if [ -f "$mig" ]; then
  echo "=== $mig ==="
  nl -ba "$mig" | sed -n '1,120p'
else
  echo "Missing file: $mig" >&2
fi

# 2) Locate the EF Core model snapshot file(s)
echo "=== ModelSnapshot files ==="
fd -e cs -t f "*ModelSnapshot*.cs" src/TransportPlatform.Infrastructure/Persistence/Migrations -a || true
fd -e cs -t f "*ModelSnapshot*.cs" src/TransportPlatform.Infrastructure -a || true

# 3) Search for references to the migration name anywhere in repo (incl. migrations & snapshots)
echo "=== References to SyncClientGeneratedKeys ==="
rg -n "SyncClientGeneratedKeys" -S --hidden || true

# 4) In the model snapshot, check for ValueGenerated.Never / ValueGeneratedNever patterns
#    (EF Core snapshots usually contain "ValueGeneratedNever" / "ValueGenerated.Never" annotations)
snap="$(fd -e cs -t f "*ModelSnapshot*.cs" src/TransportPlatform.Infrastructure/Persistence/Migrations -a | head -n 1 || true)"
echo "=== Using snapshot: ${snap:-<none>} ==="
if [ -n "$snap" ] && [ -f "$snap" ]; then
  rg -n "ValueGeneratedNever|ValueGenerated\.Never|ValueGenerated\s*=\s*ValueGenerated\.Never" "$snap" || true
  echo "=== Nearby for ValueGeneratedNever (context) ==="
  rg -n "ValueGeneratedNever|ValueGenerated\.Never" "$snap" -C2 || true
else
  echo "No snapshot file found to inspect." >&2
fi

# 5) Search migrations folder for any other empty migrations or related pattern "ValueGenerated"
echo "=== Migrations mentioning ValueGenerated ==="
rg -n "ValueGeneratedNever|ValueGenerated\.Never|ValueGenerated" src/TransportPlatform.Infrastructure/Persistence/Migrations -S || true

Repository: kashkoool/Transport

Length of output: 234


🏁 Script executed:

#!/bin/bash
set -euo pipefail

mig="src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.cs"

# 1) Show the migration file content
if [ -f "$mig" ]; then
  echo "=== $mig ==="
  cat -n "$mig" | sed -n '1,200p'
else
  echo "Missing file: $mig" >&2
fi

# 2) Locate the EF Core model snapshot file(s)
echo "=== ModelSnapshot files ==="
snapshots="$(fd -e cs -t f "*ModelSnapshot*.cs" src/TransportPlatform.Infrastructure/Persistence/Migrations src/TransportPlatform.Infrastructure 2>/dev/null || true)"
if [ -n "$snapshots" ]; then
  echo "$snapshots"
else
  echo "<none found>"
fi

# 3) Search for references to the migration name anywhere in repo
echo "=== References to SyncClientGeneratedKeys ==="
rg -n "SyncClientGeneratedKeys" -S --hidden || true

# 4) Inspect the first snapshot file (if any)
snap="$(echo "$snapshots" | head -n 1 || true)"
echo "=== Using snapshot: ${snap:-<none>} ==="
if [ -n "$snap" ] && [ -f "$snap" ]; then
  rg -n "ValueGeneratedNever|ValueGenerated\.Never|ValueGenerated\s*=\s*ValueGenerated\.Never" "$snap" || true
  echo "=== Nearby context (ValueGeneratedNever) ==="
  rg -n "ValueGeneratedNever|ValueGenerated\.Never" "$snap" -C2 || true
else
  echo "No snapshot file found to inspect."
fi

# 5) Search migrations folder for any other empty migrations or ValueGenerated usage
echo "=== Migrations mentioning ValueGenerated ==="
rg -n "ValueGeneratedNever|ValueGenerated\.Never|ValueGenerated" src/TransportPlatform.Infrastructure/Persistence/Migrations -S || true

Repository: kashkoool/Transport

Length of output: 9315


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="src/TransportPlatform.Infrastructure/Persistence/Migrations"
snap="src/TransportPlatform.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs"

# 1) Confirm snapshot file listing
echo "=== ModelSnapshot files (fd) ==="
fd -e cs -t f "*ModelSnapshot*.cs" "$base" "$base/.." 2>/dev/null || true

# 2) Show migration designer header for SyncClientGeneratedKeys
mig_designer="$base/20260601100642_SyncClientGeneratedKeys.Designer.cs"
echo "=== $mig_designer (head) ==="
if [ -f "$mig_designer" ]; then
  sed -n '1,140p' "$mig_designer" | cat -n
else
  echo "Missing: $mig_designer" >&2
fi

# 3) Search inside the SyncClientGeneratedKeys designer for any operations/snapshot changes
echo "=== References inside SyncClientGeneratedKeys.Designer.cs ==="
if [ -f "$mig_designer" ]; then
  rg -n "ValueGeneratedNever|ValueGenerated\.Never|ValueGeneratedOnAdd|Client|GeneratedKeys|SyncClient" "$mig_designer" || true
fi

# 4) Inspect ApplicationDbContextModelSnapshot for ValueGeneratedNever / Never
echo "=== $snap (relevant search) ==="
if [ -f "$snap" ]; then
  rg -n "ValueGeneratedNever|ValueGenerated\.Never" "$snap" || true
  echo "=== Nearby for ValueGeneratedNever (first 3 hits) ==="
  rg -n "ValueGeneratedNever|ValueGenerated\.Never" "$snap" -C2 | head -n 120 || true
fi

# 5) Check whether this migration is effectively a snapshot-only migration:
#    EF migrations often have empty Up/Down when there are only model snapshot annotations.
#    So look for any schema operations in migration designer (typically absent).
echo "=== Schema operations mentions inside SyncClientGeneratedKeys.Designer.cs ==="
if [ -f "$mig_designer" ]; then
  rg -n "AlterColumn|CreateTable|DropTable|AddColumn|DropColumn|CreateIndex|DropIndex|AddForeignKey|DropForeignKey" "$mig_designer" || true
fi

Repository: kashkoool/Transport

Length of output: 6830


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="src/TransportPlatform.Infrastructure/Persistence/Migrations"
mig_designer="$base/20260601100642_SyncClientGeneratedKeys.Designer.cs"
snap="src/TransportPlatform.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs"

echo "=== Keywords in SyncClientGeneratedKeys.Designer.cs ==="
if [ -f "$mig_designer" ]; then
  rg -n "ClientGenerated|GeneratedKeys|SyncClientGeneratedKeys|ValueGeneratedNever|ValueGenerated\.Never|ValueGeneratedOnAdd|UseIdentityByDefaultColumns|UseIdentityByDefaultColumn|ClientSetValue" "$mig_designer" || true
else
  echo "Missing: $mig_designer" >&2
fi

echo "=== Keywords in ApplicationDbContextModelSnapshot.cs ==="
if [ -f "$snap" ]; then
  rg -n "ClientGenerated|GeneratedKeys|SyncClientGeneratedKeys|ValueGeneratedNever|ValueGenerated\.Never|UseIdentityByDefaultColumns|ClientSetValue" "$snap" || true
else
  echo "Missing: $snap" >&2
fi

echo "=== Repo-wide presence of ValueGeneratedNever ==="
rg -n "ValueGeneratedNever|ValueGenerated\.Never" -S --hidden --glob '!**/bin/**' --glob '!**/obj/**' || true

Repository: kashkoool/Transport

Length of output: 1280


🏁 Script executed:

#!/bin/bash
set -euo pipefail

base="src/TransportPlatform.Infrastructure/Persistence/Migrations"
snap="src/TransportPlatform.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs"
mig_designer="$base/20260601100642_SyncClientGeneratedKeys.Designer.cs"

# A) Inspect counts/presence of ValueGeneratedNever/ValueGenerated.OnAdd in snapshot
echo "=== Snapshot: ValueGeneratedNever presence ==="
rg -n "ValueGeneratedNever|ValueGenerated\.Never" "$snap" || echo "<none>"

echo "=== Snapshot: ValueGenerated occurrences (first 50 hits) ==="
rg -n "ValueGenerated" "$snap" | head -n 50 || true

# B) Inspect whether snapshot changed around client-generated keys by searching for 'ValueGeneratedOnAdd' vs 'Identity'
echo "=== Snapshot: UseIdentityByDefaultColumns usage ==="
rg -n "UseIdentityByDefaultColumns|UseIdentityByDefaultColumn" "$snap" || true

# C) Inspect other migrations for empty Up/Down patterns (non-designer .cs files)
echo "=== Other migrations with empty Up/Down ==="
rg -n --type=cs "partial class .* : Migration|protected override void Up|protected override void Down" "$base" | head -n 50 || true

# Heuristic: find migration files whose Up/Down bodies are empty (up to first brace block)
echo "=== Heuristic: migrations where Up() is empty and Down() is empty ==="
python3 - <<'PY'
import re, subprocess, os, pathlib, json
base="src/TransportPlatform.Infrastructure/Persistence/Migrations"
files=subprocess.check_output(["bash","-lc",f"fd -e cs -t f '{base}/*.cs' {base} 2>/dev/null || true"]).decode().splitlines()
# The command above may not work as intended; fallback with repo-wide search for Migration suffix.
if not files:
    out=subprocess.check_output(["bash","-lc",f"fd -e cs -t f '*Migration*.cs' {base} 2>/dev/null || true"]).decode().splitlines()
    files=out
pattern_up=re.compile(r"protected\s+override\s+void\s+Up\s*\(\s*MigrationBuilder\s+\w+\s*\)\s*\{\s*\n\s*\}",re.M)
pattern_down=re.compile(r"protected\s+override\s+void\s+Down\s*\(\s*MigrationBuilder\s+\w+\s*\)\s*\{\s*\n\s*\}",re.M)

empty=[]
for p in files:
    p=str(p)
    if p.endswith(".Designer.cs"): 
        continue
    try:
        txt=pathlib.Path(p).read_text(encoding="utf-8", errors="ignore")
    except Exception:
        continue
    if pattern_up.search(txt) and pattern_down.search(txt):
        empty.append(p)
print("\n".join(empty) if empty else "<none found>")
PY

# D) Sanity-check designer for operations: any CreateTable/AlterTable/etc
echo "=== Migration designer: schema operations mentions ==="
rg -n "CreateTable|AlterColumn|AddColumn|DropColumn|CreateIndex|DropIndex|AddForeignKey|DropForeignKey|DropTable" "$mig_designer" || echo "<none>"

Repository: kashkoool/Transport

Length of output: 3152


🏁 Script executed:

#!/bin/bash
set -euo pipefail
base="src/TransportPlatform.Infrastructure/Persistence/Migrations"
mig_designer="$base/20260601100642_SyncClientGeneratedKeys.Designer.cs"
snap="src/TransportPlatform.Infrastructure/Persistence/Migrations/ApplicationDbContextModelSnapshot.cs"

echo "=== SyncClientGeneratedKeys.Designer.cs: look for client-generated-key metadata ==="
rg -n "ClientSetValue|ValueGeneratedNever|ValueGenerated\.Never|GeneratedKeys|ClientGenerated" "$mig_designer" || echo "<none found>"

echo "=== ApplicationDbContextModelSnapshot.cs: look for client-generated-key metadata ==="
rg -n "ClientSetValue|ValueGeneratedNever|ValueGenerated\.Never|GeneratedKeys|ClientGenerated" "$snap" || echo "<none found>"

echo "=== SyncClientGeneratedKeys.Designer.cs: check for any modelBuilder annotations that could change conventions only ==="
rg -n "HasAnnotation\\(|UseIdentityByDefaultColumns|UseIdentityByDefaultColumn" "$mig_designer" || true

Repository: kashkoool/Transport

Length of output: 904


🏁 Script executed:

#!/bin/bash
set -euo pipefail
base="src/TransportPlatform.Infrastructure/Persistence/Migrations"

python3 - <<'PY'
import pathlib, re
base=pathlib.Path("src/TransportPlatform.Infrastructure/Persistence/Migrations")
files=[p for p in base.glob("*.cs") if not p.name.endswith(".Designer.cs")]
up_re=re.compile(r"protected\s+override\s+void\s+Up\s*\(\s*MigrationBuilder\s+\w+\s*\)\s*\{\s*\}", re.M)
down_re=re.compile(r"protected\s+override\s+void\s+Down\s*\(\s*MigrationBuilder\s+\w+\s*\)\s*\{\s*\}", re.M)

empty=[]
for p in files:
    txt=p.read_text(encoding="utf-8", errors="ignore")
    if up_re.search(txt) and down_re.search(txt):
        empty.append(p.name)
print("\n".join(sorted(empty)) if empty else "<none>")
PY

Repository: kashkoool/Transport

Length of output: 105


Confirm SyncClientGeneratedKeys is intentionally snapshot-only (and not misnamed).
In src/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.cs (empty Up/Down), the migration’s designer contains no schema operations and only reflects convention/model-building (e.g., NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns / ValueGeneratedOnAdd). The current ApplicationDbContextModelSnapshot.cs also shows no ValueGeneratedNever/client-generated-key metadata. If this migration is meant to “sync client-generated keys”, add an explanation or rename it so the intent matches what actually changes.

🤖 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/TransportPlatform.Infrastructure/Persistence/Migrations/20260601100642_SyncClientGeneratedKeys.cs`
around lines 8 - 21, The migration class SyncClientGeneratedKeys has empty
Up/Down but its name implies it changes key-generation behavior; either make it
explicit snapshot-only or implement the intended schema changes. If this is
intended as a snapshot-only migration, rename the class/file to something like
SyncClientModelSnapshot or add a clear header comment in SyncClientGeneratedKeys
describing it contains no schema operations and only records model conventions;
update any migration history comment as needed. If instead it should change
client-generated-key metadata, implement the schema operations in the Up/Down
using MigrationBuilder (e.g., AlterColumn calls with the appropriate Npgsql
value-generation annotations such as
Npgsql:ValueGenerationStrategy/ValueGeneratedOnAdd or ValueGeneratedNever) and
ensure the ApplicationDbContextModelSnapshot reflects the same ValueGenerated
settings; update the migration name to match the real intent if you add
operations.

Comment on lines +24 to +25
<!-- For StartupGuards (a pure config-validation function that lives in the Api layer). -->
<ProjectReference Include="..\..\src\TransportPlatform.Api\TransportPlatform.Api.csproj" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Unit test project references Api layer, contradicting the layering tests.

The unit test project now references the Api layer to test StartupGuards. This creates an architectural inconsistency: the same test project that enforces "Application must not depend on Api" (via LayeringTests.cs) now itself depends on Api.

Consider one of these alternatives:

  • Move StartupGuards to the Application layer if it's pure validation logic with no HTTP concerns
  • Create a separate TransportPlatform.Api.Tests project for Api-specific unit tests
  • Move LayeringTests to a dedicated architecture test project that references all layers solely for reflection-based validation
🤖 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 `@tests/TransportPlatform.UnitTests/TransportPlatform.UnitTests.csproj` around
lines 24 - 25, The unit test project TransportPlatform.UnitTests is incorrectly
referencing the Api layer (ProjectReference to TransportPlatform.Api) which
violates the LayeringTests rule; remove that ProjectReference and resolve tests
by either: (A) moving the StartupGuards implementation into the Application
layer and update tests to reference StartupGuards from Application, or (B)
create a new TransportPlatform.Api.Tests project and move Api-specific tests for
StartupGuards there (leaving TransportPlatform.UnitTests free of Api
references), or (C) move LayeringTests into a dedicated architecture test
project that references all layers for reflection-based validation and keep
TransportPlatform.UnitTests restricted to non-Api layers; update test project
references and namespaces accordingly and ensure LayeringTests no longer fails.

Comment on lines +67 to +69
protected logout(): void {
this.auth.logout().subscribe(() => this.router.navigate(['/login']));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add error handling to logout().

The logout subscription lacks an error handler. If the logout request fails (network error, API failure), the user receives no feedback and navigation doesn't occur, leaving the UI in an inconsistent state.

🛡️ Proposed fix
 protected logout(): void {
-  this.auth.logout().subscribe(() => this.router.navigate(['/login']));
+  this.auth.logout().subscribe({
+    next: () => this.router.navigate(['/login']),
+    error: () => {
+      // Even on error, navigate to login (local state is cleared regardless)
+      this.router.navigate(['/login']);
+    }
+  });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
protected logout(): void {
this.auth.logout().subscribe(() => this.router.navigate(['/login']));
}
protected logout(): void {
this.auth.logout().subscribe({
next: () => this.router.navigate(['/login']),
error: () => {
// Even on error, navigate to login (local state is cleared regardless)
this.router.navigate(['/login']);
}
});
}
🤖 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 `@web/customer/src/app/app.ts` around lines 67 - 69, The logout() method's
subscription lacks an error handler; update logout() so the call to
this.auth.logout().subscribe includes both a success and an error callback
(and/or a complete handler) so failures are handled: on success call
this.router.navigate(['/login']), on error log the error and surface a
user-facing message (use your notification service or fallback alert) and decide
whether to still call this.router.navigate(['/login']) to avoid leaving the UI
in an inconsistent state; modify the subscription on the this.auth.logout() call
accordingly.

Comment on lines +9 to +28
<div class="fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2">
@for (toast of toasts.toasts(); track toast.id) {
<div
class="flex items-start gap-3 rounded-lg px-4 py-3 text-sm shadow-lg ring-1 ring-black/5"
[class.bg-emerald-600]="toast.kind === 'success'"
[class.bg-rose-600]="toast.kind === 'error'"
[class.bg-slate-800]="toast.kind === 'info'"
>
<span class="flex-1 text-white">{{ toast.message }}</span>
<button
type="button"
class="text-white/70 hover:text-white"
(click)="toasts.dismiss(toast.id)"
aria-label="Dismiss"
>
</button>
</div>
}
</div>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a live region so screen readers announce toasts.

The toast stack is rendered as plain divs, so dynamically added notifications aren't announced to assistive technology. Add aria-live (and an appropriate role) to the container so messages are surfaced.

♿ Proposed fix
-    <div class="fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2">
+    <div
+      class="fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2"
+      role="status"
+      aria-live="polite"
+    >
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div class="fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2">
@for (toast of toasts.toasts(); track toast.id) {
<div
class="flex items-start gap-3 rounded-lg px-4 py-3 text-sm shadow-lg ring-1 ring-black/5"
[class.bg-emerald-600]="toast.kind === 'success'"
[class.bg-rose-600]="toast.kind === 'error'"
[class.bg-slate-800]="toast.kind === 'info'"
>
<span class="flex-1 text-white">{{ toast.message }}</span>
<button
type="button"
class="text-white/70 hover:text-white"
(click)="toasts.dismiss(toast.id)"
aria-label="Dismiss"
>
</button>
</div>
}
</div>
<div
class="fixed bottom-4 right-4 z-50 flex w-80 flex-col gap-2"
role="status"
aria-live="polite"
>
`@for` (toast of toasts.toasts(); track toast.id) {
<div
class="flex items-start gap-3 rounded-lg px-4 py-3 text-sm shadow-lg ring-1 ring-black/5"
[class.bg-emerald-600]="toast.kind === 'success'"
[class.bg-rose-600]="toast.kind === 'error'"
[class.bg-slate-800]="toast.kind === 'info'"
>
<span class="flex-1 text-white">{{ toast.message }}</span>
<button
type="button"
class="text-white/70 hover:text-white"
(click)="toasts.dismiss(toast.id)"
aria-label="Dismiss"
>
</button>
</div>
}
</div>
🤖 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 `@web/customer/src/app/core/toast/toast.ts` around lines 9 - 28, The container
div that renders the toast list (the element with class "fixed bottom-4 right-4
z-50 flex w-80 flex-col gap-2") must be a live region so screen readers announce
new toasts; add an appropriate aria-live value (e.g., "polite" or "assertive"),
role (e.g., "status"), and aria-atomic="true" to that container so messages from
toasts.toasts() are surfaced; keep existing usage of toast.message and
toasts.dismiss(toast.id) unchanged.

Comment on lines +143 to +145
private today(): string {
return new Date().toISOString().slice(0, 10);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

today() uses the UTC date, not the user's local date.

new Date().toISOString() converts to UTC before slicing, so for users whose local time differs from UTC the default date can be off by one day (e.g. evening in the Americas resolves to tomorrow). Build the string from local date parts instead.

🐛 Proposed fix
   private today(): string {
-    return new Date().toISOString().slice(0, 10);
+    const now = new Date();
+    const month = `${now.getMonth() + 1}`.padStart(2, '0');
+    const day = `${now.getDate()}`.padStart(2, '0');
+    return `${now.getFullYear()}-${month}-${day}`;
   }
🤖 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 `@web/customer/src/app/features/trips/search.ts` around lines 143 - 145, The
today() helper uses UTC via toISOString() which yields the wrong local date for
many users; update the today() method in search.ts (the private today()
function) to build the "YYYY-MM-DD" string from the local date parts using
date.getFullYear(), date.getMonth()+1 and date.getDate(), zero-pad month/day to
two digits, and return that formatted local-date string instead of slicing
toISOString().

@kashkoool
Copy link
Copy Markdown
Owner

Closing: stale after a history rewrite (all commit SHAs changed), so this diff is no longer valid. Dependabot will recreate a correct PR against the new main on its next run.

@kashkoool kashkoool closed this Jun 1, 2026
@dependabot @github
Copy link
Copy Markdown
Author

dependabot Bot commented on behalf of github Jun 1, 2026

This pull request was built based on a group rule. Closing it will not ignore any of these versions in future pull requests.

To ignore these dependencies, configure ignore rules in dependabot.yml

@dependabot dependabot Bot deleted the dependabot/nuget/dotnet-026c4b0cf3 branch June 1, 2026 18:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file .NET Pull requests that update .NET code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant