case 4690 - CA2022: read the PE header with ReadAtLeast for the licence build date

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 19:39:11 -07:00
parent 76dab8d865
commit 77b825a064
2 changed files with 5 additions and 2 deletions

View File

@@ -95,7 +95,7 @@ them. Items touching those three areas carry more weight here than they did in S
- [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=<server CultureInfo.CurrentCulture>` 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 → `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`
- [ ] 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] **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
@@ -204,3 +204,4 @@ Found during the port, out of scope. One line each.
| 2026-10-22 | John's visual check of the PuppeteerSharp 25 PDFs; `--lang` fix | Identical apart from report 80: date month/day flipped (default locale, see section 1). Probe of Chrome 124/155 with each argument set confirmed the cause. With `--lang=<server culture>`: John confirmed report 80 shows 22/10/2026 again; 22/22 render, page counts = PuppeteerSharp 17, launch arguments logged as `--no-sandbox --lang=en-CA`. Integration suite: 95 passed, 3 failed: the two known plus `FormCustom.FormCustomUpdate`, which the server log shows was the `FormFieldReference` start-up race again (`Vendor is not valid` at the first form-field use after boot; see Deferred), not this change. **Never render reports 81 (sends real email via the server's SMTP settings) or 86 (writes to the work order) in tests**; 81 ran three times on 2026-10-22 and caused bounces |
| 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 |

View File

@@ -872,7 +872,9 @@ namespace AyaNova.Util
using (var file = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
file.Read(bytes, 0, bytes.Length);
//CA2022: a single Read may return fewer bytes than asked for, this keeps reading until full or end of file and never throws
//(used for the licence build date check so a short read must not become an exception)
file.ReadAtLeast(bytes, bytes.Length, throwOnEndOfStream: false);
}
var headerPos = BitConverter.ToInt32(bytes, peHeaderOffset);