diff --git a/devdocs/modernization/NET10-PORT.md b/devdocs/modernization/NET10-PORT.md index 5d2fd6d2..21a873aa 100644 --- a/devdocs/modernization/NET10-PORT.md +++ b/devdocs/modernization/NET10-PORT.md @@ -85,7 +85,7 @@ them. Items touching those three areas carry more weight here than they did in S - [x] **BouncyCastle.** Already `BouncyCastle.Cryptography` 2.3.1 (`AyaNova.csproj:28`) with MailKit/MimeKit 4.5.0; no `Portable.BouncyCastle` in the graph. Version bump only: now 2.7.0, moved together with MailKit 4.18.1, as in Sockeye. The Sockeye note about `PemReader` and PKCS#1 key pairs does not apply: AyaNova reads a public key (see the licence gate) - [x] **Swashbuckle 10 / OpenAPI.NET 2.** Done: all six `Swashbuckle.AspNetCore*` 6.5.0 → 10.3.1 (Sockeye: 10.2.3), explicit `Microsoft.OpenApi` reference removed (now 2.7.5 transitively), and the three code changes below. Applies. `Microsoft.OpenApi.Models` merged into `Microsoft.OpenApi`: `using` at `Startup.cs:15` and `ConfigureSwaggerOptions.cs:6`. Bearer requirement (`Startup.cs:235-244`) becomes `c.AddSecurityRequirement(document => new OpenApiSecurityRequirement { [new OpenApiSecuritySchemeReference("Bearer", document)] = [] })`. Remove the explicit `Microsoft.OpenApi` 1.6.14 reference (`AyaNova.csproj:47`) - [x] **NLog 6.** Done: NLog and NLog.Web.AspNetCore 6.2.2; `ArchiveNumbering` removed; **`ArchiveFileName` kept and `ArchiveSuffixFormat = "-{0}"` added** (`Program.cs`); log viewer sorts archives by file date, newest first. Tested in a scratch program and on the server, against a folder seeded with NLog 5 archives `-0` to `-8`: without `ArchiveFileName`, NLog 6 writes straight into numbered files (no `log-ayanova.txt`) and appends to the old `-8`; with it but no suffix format, archives become `log-ayanova_NN.txt` (NLog 6 ignores `{#}`) and the old `-0` to `-8` are never deleted. Sockeye 8.1.0 ships that second form. With both settings: `log-ayanova.txt` stays current, archives are `log-ayanova-N.txt` as the manual (`docs/.../ops-log.md`) says, numbering continues after the old files, and the old files are cleaned up. `NLogBuilder.ConfigureNLog` is already replaced (`Program.cs:206`, `LogManager.Setup().LoadConfiguration`). `ArchiveNumbering = Rolling` (`Program.cs:136`) is gone in 6. Archive numbers keep incrementing and the un-numbered file is always current. **The log viewer sorts by file name as a string** (`LogFilesController.cs:120`, `OrderByDescending(z => z)`), so `-10` sorts after `-2`. Fix the sort in the same commit -- [ ] **Newtonsoft.Json.** `Mvc.NewtonsoftJson` 10.x sets a 13.0.3 floor (NU1605). Already resolves 13.0.3 transitively; add it as a direct reference +- [x] **Newtonsoft.Json.** `Mvc.NewtonsoftJson` 10.x sets a 13.0.3 floor (NU1605). Already resolved 13.0.3 transitively; now a direct reference at 13.0.4 (current; Sockeye pins 13.0.3) - [ ] **JwtBearer 10.x.** The IdentityModel part is n/a: it resolves 7.1.2, not the vulnerable 6.10.0 - [x] **SMTP.** n/a: `util/Mailer.cs` already uses MailKit's `SmtpClient` (`:1`, `:84`); no `System.Net.Mail` - [x] **PuppeteerSharp 17 → 25.x.** Reporting is AyaNova's main Puppeteer surface (`biz/ReportBiz.cs`). Done: 25.15.0 (Sockeye: 25.12.0); compiles with no API changes; launch arguments fixed (below). Downloads Chrome for Testing 155 (was 124). The download location and failure handling are separate section 3 items @@ -94,8 +94,8 @@ them. Items touching those three areas carry more weight here than they did in S - The default download is Chrome for Testing, into `Chrome/` and `ChromeHeadlessShell/` beside the app. AyaNova 8.2.0 already moved from Chromium to Chrome to follow Puppeteer's default, so the browser choice is settled - [x] Launch arguments must be separate array elements. Fixed: defaults are `new[] { "--no-sandbox" }` (`--headless` dropped, `LaunchOptions.Headless` already adds it, as in Sockeye); the customer setting is split on whitespace. A customer value containing a quoted argument with spaces would now be split; none is known. **Browser default locale:** the old `--headless` argument ran Chrome's old headless mode, which takes its default language from the OS (en-CA → Chrome's en-GB, day-first); current Chrome headless always defaults to en-US. Report scripts that format without a locale (stock sample report 80 calls `toLocaleDateString()` bare) switched from 22/10/2026 to 10/22/2026. Fixed by adding `--lang=` unless the customer setting already has a `--lang`; skipped when the server culture is invariant. Stock helpers in `ay-report.js` pass the client's language explicitly and were never affected. **Both paths were wrong:** the defaults are one element `"--headless --no-sandbox "` (`ReportBiz.cs:812`, `:829`), and `AYANOVA_REPORT_RENDER_BROWSER_PARAMS` is passed whole as one element (`:819-822`) - AppArmor restricts unprivileged user namespaces on Ubuntu 24.04+, which affects the Chrome sandbox -- [ ] Remaining packages to current releases. MailKit 4.5.0 carried a moderate advisory (NU1902); on `net10.0` the audit also reported high-severity NU1903 for `MimeKit` 4.5.0 and transitive `System.Security.Cryptography.Pkcs` 8.0.0. **Mail done:** MailKit/MimeKit 4.18.1, BouncyCastle 2.7.0, and `System.Security.Cryptography.Pkcs` 10.0.13 pinned directly (MimeKit only requires 10.0.0, which has advisories). `dotnet list package --vulnerable --include-transitive`: none. After the upgrade, check what still pulls in `System.Text.Json` 5.0.2 -- [ ] Warnings: CA2022 done with `ReadAtLeast(bytes, bytes.Length, throwOnEndOfStream: false)` rather than `ReadExactly`, which would throw on a short file on the licence path; ASP0019 still to do. Was: CA2022 → `ReadExactly` at `FileUtil.cs:875` (**licence build-date path**: covered by the licence gate); ASP0019 → header indexer instead of `Headers.Append` at `Startup.cs:514` +- [x] Remaining packages to current releases. **Done:** Bogus 35.5.1 → 35.6.5 (evaluation seeder), jose-jwt 5.0.0 → 5.3.0 (login tokens), QRCoder 1.5.1 → 1.8.1 (2FA setup QR). `dotnet list package --outdated`: nothing; `--vulnerable --include-transitive`: none. MailKit 4.5.0 carried a moderate advisory (NU1902); on `net10.0` the audit also reported high-severity NU1903 for `MimeKit` 4.5.0 and transitive `System.Security.Cryptography.Pkcs` 8.0.0. **Mail done:** MailKit/MimeKit 4.18.1, BouncyCastle 2.7.0, and `System.Security.Cryptography.Pkcs` 10.0.13 pinned directly (MimeKit only requires 10.0.0, which has advisories). `dotnet list package --vulnerable --include-transitive`: none. After the upgrade, check what still pulls in `System.Text.Json` 5.0.2 +- [x] Warnings: CA2022 done with `ReadAtLeast(bytes, bytes.Length, throwOnEndOfStream: false)` rather than `ReadExactly`, which would throw on a short file on the licence path. ASP0019: n/a. It flags `Headers.Add` and recommends `Append` or the indexer; `Startup.cs` already uses `Append` and no ASP0019 warning is reported (the line below had it backwards). Was: CA2022 → `ReadExactly` at `FileUtil.cs:875` (**licence build-date path**: covered by the licence gate); ASP0019 → header indexer instead of `Headers.Append` at `Startup.cs:514` - [x] **MiniProfiler. Present, not absent. Removed** (John's decision, as in Sockeye `6dd2b09`): both packages, `AddMemoryCache`/`AddMiniProfiler`/`UseMiniProfiler`, the `/profiler/results` download-token workaround in the auth middleware, the unused `using` in `ReportBiz.cs`, three commented-out `using` lines, and the credit in `docs/.../appendix-os-credits.md`. Client: `ops-profile.vue` and its route remain, but the menu entry was already commented out (`initialize.js:785`) and the page was retired after the beta (`changelog.md:519`); John may remove them. Was: `MiniProfiler.AspNetCore.Mvc` and `.EntityFrameworkCore` 4.3.8 (`AyaNova.csproj:48-49`); `AddMiniProfiler(...).AddEntityFramework()` (`Startup.cs:62-74`); auth workaround for `/profiler/results` (`Startup.cs:393-441`); `UseMiniProfiler()` (`Startup.cs:530`); `using StackExchange.Profiling.Internal` (`ReportBiz.cs:14`). Nothing in `raven-client`. Keep and upgrade, or remove: see Open questions - [x] **BinaryFormatter.** n/a: not used anywhere in `server/AyaNova` - [x] **`System.GC.Server`.** n/a: not set, so the Web SDK default (`true`) stays. On one vCPU the runtime uses workstation GC anyway, and DATAS keeps server GC lean since .NET 9 @@ -104,7 +104,7 @@ them. Items touching those three areas carry more weight here than they did in S ## 2. Configuration behaviour to check - [x] **URL binding precedence.** n/a: `UseUrls(ServerBootConfig.AYANOVA_USE_URLS)` (`Program.cs:340`), read from `config.json`, environment and command line (`Program.cs:38`, `ServerBootConfig.cs:167-170`). The documented `AYANOVA_USE_URLS` is the one that wins over `ASPNETCORE_URLS`; a command-line `--urls` still overrides it through `UseConfiguration` (`Program.cs:341`) -- [ ] **Logging providers.** No journal flood: `Program.cs:348` calls `ClearProviders()` before `UseNLog()`. `appsettings.json:4-13` still sets the Debug and Console providers to `Trace`, with no effect today. Fix the levels in the repo +- [x] **Logging providers.** `appsettings.json` Debug and Console levels `Trace` → `Warning`. `appsettings.Development.json` left: only read when `ASPNETCORE_ENVIRONMENT=Development`, which nothing sets. No journal flood: `Program.cs:348` calls `ClearProviders()` before `UseNLog()`. `appsettings.json:4-13` still sets the Debug and Console providers to `Trace`, with no effect today. Fix the levels in the repo - [x] **Data Protection keys.** n/a: nothing uses Data Protection; authentication is JWT only (`Startup.cs:278-302`) ## 3. Fixes found through Sockeye (each its own commit) @@ -205,3 +205,4 @@ Found during the port, out of scope. One line each. | 2026-10-22 | Asp.Versioning 8.1.0 → 10.2.1, explicit `.AddMvc()` | Builds; new warnings AV0015/AV0016 left (see section 1) besides CA2022. `swagger.json` identical to the Swashbuckle 10 document (315 paths, 462 operations, 137 schemas, 0 differences). `api/v8/…`, `api/v8.0/…` and `?api-version=8.0` return 200 with `api-supported-versions: 8.0`; `api/v9/…` returns 404 (8.1 response for v9 not checked). Integration suite = baseline | | 2026-10-22 | MiniProfiler removed | Builds (only AV0015/AV0016/CA2022). No `StackExchange.Profiling`/`MiniProfiler`/`AY_PROFILER` left in the server. `/profiler/results-index` now gets the client app's `index.html` fallback like any unknown path; unauthenticated API call still 401. Integration suite = baseline | | 2026-10-22 | CA2022: `FileUtil.GetLinkerTimestampUtc` reads with `ReadAtLeast` | CA2022 gone (only AV0015/AV0016 left). Licence gate 730/730 incl. build-timestamp and `MExBB` checks; per-row outcomes identical to the first .NET 10 run (389 ok / 337 rejected for this build). Server boots and accepts the (trial) licence | +| 2026-10-22 | Bogus 35.6.5, jose-jwt 5.3.0, QRCoder 1.8.1, Newtonsoft.Json 13.0.4 direct; `appsettings.json` levels; ASP0019 n/a | Builds (only AV0015/AV0016). All packages current, none vulnerable. Login JWT still `HS256` and accepted on every authenticated call; `GET auth/totp` returns a valid 183×183 QR PNG and leaves 2FA disabled. Integration suite = baseline. Bogus (evaluation seeder) compiled only: running the seeder replaces the test data | diff --git a/server/AyaNova/AyaNova.csproj b/server/AyaNova/AyaNova.csproj index fd46fc0e..b396e62f 100644 --- a/server/AyaNova/AyaNova.csproj +++ b/server/AyaNova/AyaNova.csproj @@ -24,15 +24,17 @@ - + - + + + @@ -50,7 +52,7 @@ - +