Bump the dotnet group with 18 updates#12
Conversation
…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>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
📝 WalkthroughWalkthroughAdds 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. ChangesEnd-to-end platform expansion
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
|
There was a problem hiding this comment.
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 winFix obsolete
PostgreSqlBuilderconstructor 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 winAdd 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.mdaround 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 fromtotext (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 fromtotext (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 -->
| - 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 }} |
There was a problem hiding this comment.
🧩 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:
- 1: https://github.com/actions/checkout/tree/fd084cde189b7b76ec305d52e27be545a0172823
- 2: https://github.com/actions/checkout/tree/v4
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.
| - 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 |
There was a problem hiding this comment.
🧩 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@v4ossf/scorecard-action@v2.4.0github/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.
| - 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.
|
|
||
| Higher-level context lives alongside the repo: | ||
|
|
||
| - [../ARCHITECTURE.md](../ARCHITECTURE.md) — module map, bounded contexts, migration plan |
There was a problem hiding this comment.
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.
| 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."); |
There was a problem hiding this comment.
🧩 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 || trueRepository: 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 || trueRepository: 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:
- 1: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/host-filtering?view=aspnetcore-10.0
- 2: https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.hostfiltering.hostfilteringoptions.allowedhosts?view=aspnetcore-10.0
- 3: https://github.com/dotnet/aspnetcore/blob/3f1acb59718cadf111a0a796681e3d3509bb3381/src/Middleware/HostFiltering/src/HostFilteringOptions.cs
🏁 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" || trueRepository: 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 . || trueRepository: 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.
| 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.
| 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."); | ||
| } |
There was a problem hiding this comment.
🧩 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.csprojRepository: 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.csprojRepository: 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.
| public partial class SyncClientGeneratedKeys : Migration | ||
| { | ||
| /// <inheritdoc /> | ||
| protected override void Up(MigrationBuilder migrationBuilder) | ||
| { | ||
|
|
||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override void Down(MigrationBuilder migrationBuilder) | ||
| { | ||
|
|
||
| } | ||
| } |
There was a problem hiding this comment.
🧩 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 || trueRepository: 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 || trueRepository: 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
fiRepository: 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/**' || trueRepository: 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" || trueRepository: 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>")
PYRepository: 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.
| <!-- For StartupGuards (a pure config-validation function that lives in the Api layer). --> | ||
| <ProjectReference Include="..\..\src\TransportPlatform.Api\TransportPlatform.Api.csproj" /> |
There was a problem hiding this comment.
🛠️ 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
StartupGuardsto the Application layer if it's pure validation logic with no HTTP concerns - Create a separate
TransportPlatform.Api.Testsproject for Api-specific unit tests - Move
LayeringTeststo 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.
| protected logout(): void { | ||
| this.auth.logout().subscribe(() => this.router.navigate(['/login'])); | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| <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> |
There was a problem hiding this comment.
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.
| <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.
| private today(): string { | ||
| return new Date().toISOString().slice(0, 10); | ||
| } |
There was a problem hiding this comment.
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().
|
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. |
|
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 |
Updated coverlet.collector from 6.0.4 to 10.0.1.
Release notes
Sourced from coverlet.collector's releases.
10.0.1
Improvements
Fixed
Maintenance
Diff between 10.0.0 and 10.0.1
10.0.0
Improvements
--coverlet-file-prefixoption for unique report files #1869Fixed
Maintenance
Diff between 8.0.1 and 10.0.0
8.0.1
Fixed
Improvements
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
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
Span<T>,ReadOnlySpan<T>,Memory<T>andReadOnlyMemory<T>by @dennisdoomen in Add support for Span<T>, ReadOnlySpan<T>, Memory<T> and ReadOnlyMemory<T> fluentassertions/fluentassertions#3172Improvements
BeEquivalentToby @Copilot in Allow excluding all properties by type from BeEquivalentTo fluentassertions/fluentassertions#3115BeEquivalentToby @dennisdoomen in Improve reporting the differences between differently sized collections in BeEquivalentTo fluentassertions/fluentassertions#3133ThrowandWhichby @dennisdoomen in Improve reporting the subject when chaining Throw and Which fluentassertions/fluentassertions#3160HaveMillisecond/NotHaveMillisecondassertion methods forDateTimeandDateTimeOffsetby @Copilot in Add HaveMillisecond/NotHaveMillisecond assertion methods for DateTime and DateTimeOffset fluentassertions/fluentassertions#3164BeEqualToandNotBeEqualToas collection assertion aliases by @Copilot in AddBeEqualToandNotBeEqualToas collection assertion aliases fluentassertions/fluentassertions#3166Fixes
Documentation
Others
==or!=when comparing Nullable against constants by @jnyrup in Use==or!=when comparing Nullable<T> against constants fluentassertions/fluentassertions#3129string.Createby @jnyrup in Create polyfill forstring.Createfluentassertions/fluentassertions#3130UnassignedGetOnlyAutoPropertyforNode.GetHashCodeby @jnyrup in SuppressUnassignedGetOnlyAutoPropertyforNode.GetHashCodefluentassertions/fluentassertions#3138NonReadonlyMemberInGetHashCodeby @jnyrup in UseNonReadonlyMemberInGetHashCodefluentassertions/fluentassertions#3140paramNameparameter by @jnyrup in Use compiler-generatedparamNameparameter fluentassertions/fluentassertions#3143When_concurrently_getting_equality_strategy_it_should_not_throwby @jnyrup in FixWhen_concurrently_getting_equality_strategy_it_should_not_throwfluentassertions/fluentassertions#3144... (truncated)
8.8.0
What's Changed
New features
Improvements
Documentation
configparameter by @jnyrup in Add docs forconfigparameter fluentassertions/fluentassertions#3104Others
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
DisableImplicitNuGetFallbackFolderby @jnyrup in SetDisableImplicitNuGetFallbackFolderfluentassertions/fluentassertions#3095Full Changelog: fluentassertions/fluentassertions@8.6.0...8.7.0
8.6.0
What's Changed
Improvements
Value.ThatMatchesandValue.ThatSatisfiesby @dennisdoomen in Add support for inline assertions using Value.ThatMatches and Value.ThatSatisfies fluentassertions/fluentassertions#3076Others
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
StringSyntaxannotations by @jnyrup in RestoreStringSyntaxannotations fluentassertions/fluentassertions#3033Others
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
OrEqualTomethods by @IT-VBFK in Remove obsoleteOrEqualTomethods fluentassertions/fluentassertions#2269SpacesPerIndentionLevelby @jnyrup in RemoveSpacesPerIndentionLevelfluentassertions/fluentassertions#2281AllSatisfyto succeed on empty collections by @jnyrup in ChangeAllSatisfyto succeed on empty collections fluentassertions/fluentassertions#2321ForConstrainttoIAssertionScopeby @IT-VBFK in AddForConstrainttoIAssertionScopefluentassertions/fluentassertions#2324OnlyContainto succeed on empty collections by @IT-VBFK in ChangeOnlyContainto succeed on empty collections fluentassertions/fluentassertions#2350NSpec3by @ITaluone in Drop support forNSpec3fluentassertions/fluentassertions#2356NotThrow[After]toActionAssertionsby @jnyrup in Move non-genericNotThrow[After]toActionAssertionsfluentassertions/fluentassertions#2371EquivalencyAssertionOptionstoEquivalencyOptionsby @vbreuss in RenameEquivalencyAssertionOptionstoEquivalencyOptionsfluentassertions/fluentassertions#2414WithoutMatchingRulesandWithoutSelectionRuleswhile usingBeEquivalentToby @vbreuss in Allow fluently callingWithoutMatchingRulesandWithoutSelectionRuleswhile usingBeEquivalentTofluentassertions/fluentassertions#2457SubsequentOrderingAssertionsby @vbreuss in Simplify inheritance ofSubsequentOrderingAssertionsfluentassertions/fluentassertions#2439RespectingRuntimeTypesandRespectingDeclaredTypesto better clarify their purpose by @dennisdoomen in RenamedRespectingRuntimeTypesandRespectingDeclaredTypesto better clarify their purpose fluentassertions/fluentassertions#2866HttpResponseMessageassertions by @ITaluone in Remove support forHttpResponseMessageassertions fluentassertions/fluentassertions#2909New features
NotBeIn(DateTimeKind)DateTimeassertion by @IT-VBFK in Add missingNotBeIn(DateTimeKind)DateTimeassertion fluentassertions/fluentassertions#2536EquivalencyOptionsin string assertions by @vbreuss in Allow specifyingEquivalencyOptionsin string assertions fluentassertions/fluentassertions#2413Improvements
TypeMemberReflectorby @jnyrup in OptimizeTypeMemberReflectorfluentassertions/fluentassertions#2320AssertionScopes to chain their context by @dennisdoomen in Allow nestedAssertionScopes to chain their context fluentassertions/fluentassertions#2607... (truncated)
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
RespectingRuntimeTypesandRespectingDeclaredTypesto better clarify their purpose by @dennisdoomen in RenamedRespectingRuntimeTypesandRespectingDeclaredTypesto better clarify their purpose fluentassertions/fluentassertions#2866HttpResponseMessageassertions by @ITaluone in Remove support forHttpResponseMessageassertions fluentassertions/fluentassertions#2909Fixes
Documentation
Others
... (truncated)
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
"{}"is used as a dictionary key by @dennisdoomen in Backport bug fixes to v7 fluentassertions/fluentassertions#3173WithTracingis safe when used withBeEquivalentToglobally by @dennisdoomen in Backport bug fixes to v7 fluentassertions/fluentassertions#3173AssertionResultSetfixes from fluentassertions#3100 by @jnyrup in Backport bug fixes to v7 fluentassertions/fluentassertions#3173Building
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
Changes in 12.0.0
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
Changes in 12.0.0
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
IConfigurationEventHandlerContextAware<T>that provides context to the configuration event handler implementation, allowing it to optionally bypass a cache lookup. See PR #3444.8.17.0
Dependencies
8.16.0
New Features
Fundamentals
8.15.0
New Features
X509SecurityKeyandJsonWebKeyConverter.ConvertFromX509SecurityKeyExtended
X509SecurityKeyandJsonWebKeyConverter.ConvertFromX509SecurityKeyto support ECDSA keys.See PR #2377 for details.
Bug Fixes
Updated logging to sanitize sensitive values, reducing the risk of inadvertently exposing secrets or PII in logs.
See PR #3316 for details.
SearchValuesImproved 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.
IDX10400Adjusted the
IDX10400test to align with the current behavior and error messaging.See PR #3314 for details.
Fundamentals
Added new tests to validate the set of supported cryptographic algorithms, increasing confidence in algorithm coverage and compatibility.
See PR #3296 for details.
.clinerulestoagents.mdMoved repository agent/AI-assist rules into markdown documentation to make them more visible and easier to maintain.
See PR #3313 for details.
Microsoft.IdentityModel.TestExtensionsfrom Newtonsoft.Json to System.Text.JsonUpdated
Microsoft.IdentityModel.TestExtensionsto useSystem.Text.Jsoninstead ofNewtonsoft.Json, aligning tests with the runtime serialization stack.See PR #3356 for details.
Turned off automated code coverage comments on PRs to reduce noise while retaining coverage data elsewhere.
See PR #3349 for details.
Addressed CodeQL-reported issues to improve security posture and static analysis cleanliness.
See PR #3364 for details.
.NET 10 / SDK and tooling updates
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.
Ensured consistent use of the
TargetNetNextparameter across build, test, and pack phases so .NET 10.0 tests execute reliably.See PR #3337 for details.
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.
Updated the .NET version references to be compliant with corporate governance (CG) requirements.
See PR #3353 for details.
CoverletCollectorVersionto 6.0.4.See PR #3333 for details.
Microsoft.NET.Test.Sdkto 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
IConfigurationEventHandlerContextAware<T>that provides context to the configuration event handler implementation, allowing it to optionally bypass a cache lookup. See PR #3444.8.17.0
Dependencies
8.16.0
New Features
Fundamentals
8.15.0
New Features
X509SecurityKeyandJsonWebKeyConverter.ConvertFromX509SecurityKeyExtended
X509SecurityKeyandJsonWebKeyConverter.ConvertFromX509SecurityKeyto support ECDSA keys.See PR #2377 for details.
Bug Fixes
Updated logging to sanitize sensitive values, reducing the risk of inadvertently exposing secrets or PII in logs.
See PR #3316 for details.
SearchValuesImproved 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.
IDX10400Adjusted the
IDX10400test to align with the current behavior and error messaging.See PR #3314 for details.
Fundamentals
Added new tests to validate the set of supported cryptographic algorithms, increasing confidence in algorithm coverage and compatibility.
See PR #3296 for details.
.clinerulestoagents.mdMoved repository agent/AI-assist rules into markdown documentation to make them more visible and easier to maintain.
See PR #3313 for details.
Microsoft.IdentityModel.TestExtensionsfrom Newtonsoft.Json to System.Text.JsonUpdated
Microsoft.IdentityModel.TestExtensionsto useSystem.Text.Jsoninstead ofNewtonsoft.Json, aligning tests with the runtime serialization stack.See PR #3356 for details.
Turned off automated code coverage comments on PRs to reduce noise while retaining coverage data elsewhere.
See PR #3349 for details.
Addressed CodeQL-reported issues to improve security posture and static analysis cleanliness.
See PR #3364 for details.
.NET 10 / SDK and tooling updates
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.
Ensured consistent use of the
TargetNetNextparameter across build, test, and pack phases so .NET 10.0 tests execute reliably.See PR #3337 for details.
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.
Updated the .NET version references to be compliant with corporate governance (CG) requirements.
See PR #3353 for details.
CoverletCollectorVersionto 6.0.4.See PR #3333 for details.
Microsoft.NET.Test.Sdkto 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
Infrastructure & Deployment
Security & Auth