This repository was archived by the owner on May 24, 2026. It is now read-only.
Commit bb1394b
Three follow-up hardening items from the PR #377 consensus review
(5-model review squad). The core risk: `Save()` swallowed all exceptions
silently, `File.Exists()` was used as a proxy for write success, and
migration failures were invisible.
## Changes
### 1. `Save()` returns `bool` (MODERATE — data-loss prevention)
`Save()` now returns `true` on successful write, `false` on any
exception. Callers that ignore the return value are unaffected (backward
compatible — `void` callers still compile).
The Keychain cleanup in `RecoverSecretsFromSecureStorage` is now gated
on `Save()`'s return value instead of `File.Exists(SettingsPath)`:
```csharp
// Before — weak proxy: old file can exist even if this Save() failed
settings.Save();
if (File.Exists(SettingsPath)) { /* delete keychain entries */ }
// After — direct success signal
bool saved = settings.Save();
if (saved) { /* delete keychain entries */ }
```
This prevents data loss when `Save()` fails (disk full, permissions
error) but an older settings file already exists on disk.
### 2. Migration failures logged (LOW — observability)
The outer `catch {}` in `RecoverSecretsFromSecureStorage` now captures
the exception and:
- Writes to `Debug.WriteLine` for IDE output
- Appends to `~/.polypilot/crash.log` matching the existing crash-log
convention
Previously, a partial migration failure was completely silent — no
diagnostic trace.
### 3. Sync-over-async comment (LOW — documentation)
`ReadSecureStorage` now has a doc comment explaining the intentional
`Task.Run(...).GetAwaiter().GetResult()` pattern: it avoids
`SynchronizationContext` deadlock, runs only during the one-time
migration on `Load()`, and the tradeoff is acceptable vs. making
`Load()` async.
## Tests
- **Unit tests**: 3 new tests for `Save()` return value behavior
(`Save_ReturnsTrue_OnSuccess`, `Save_ReturnsFalse_OnFailure`,
`Save_ReturnsFalse_WhenPathIsReadOnly`)
- **Integration test**: `SettingsPersistenceTests` — navigates to
Settings page, verifies it renders correctly
- All 3579 unit tests pass ✅
- Integration tests build successfully ✅
## Files Changed
| File | Change |
|------|--------|
| `PolyPilot/Models/ConnectionSettings.cs` | `Save()` → `bool`,
migration logging, sync-over-async doc |
| `PolyPilot.Tests/ConnectionSettingsTests.cs` | 3 new tests for Save()
return value |
| `PolyPilot.IntegrationTests/SettingsPersistenceTests.cs` | New
integration test for Settings page |
- Fixes #379
> [!WARNING]
> <details>
> <summary><strong>⚠️ Firewall blocked 1 domain</strong></summary>
>
> The following domain was blocked by the firewall during workflow
execution:
>
> - `192.0.2.1`
>
> To allow these domains, add them to the `network.allowed` list in your
workflow frontmatter:
>
> ```yaml
> network:
> allowed:
> - defaults
> - "192.0.2.1"
> ```
>
> See [Network
Configuration](https://github.github.com/gh-aw/reference/network/) for
more information.
>
> </details>
> Generated by [Agent
Fix](https://github.com/PureWeen/PolyPilot/actions/runs/25066485519/agentic_workflow)
for issue #379 · ● 15.6M ·
[◷](https://github.com/search?q=repo%3APureWeen%2FPolyPilot+%22gh-aw-workflow-id%3A+agent-fix%22&type=pullrequests)
<!-- gh-aw-agentic-workflow: Agent Fix, engine: copilot, model:
claude-opus-4.6, id: 25066485519, workflow_id: agent-fix, run:
https://github.com/PureWeen/PolyPilot/actions/runs/25066485519 -->
<!-- gh-aw-workflow-id: agent-fix -->
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: copilot-agentic-workflow[bot] <224017+copilot-agentic-workflow[bot]@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0b210c7 commit bb1394b
3 files changed
Lines changed: 178 additions & 8 deletions
File tree
- PolyPilot.IntegrationTests
- PolyPilot.Tests
- PolyPilot/Models
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
585 | 585 | | |
586 | 586 | | |
587 | 587 | | |
| 588 | + | |
| 589 | + | |
| 590 | + | |
| 591 | + | |
| 592 | + | |
| 593 | + | |
| 594 | + | |
| 595 | + | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
| 650 | + | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
| 660 | + | |
| 661 | + | |
| 662 | + | |
| 663 | + | |
| 664 | + | |
| 665 | + | |
| 666 | + | |
| 667 | + | |
| 668 | + | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
588 | 685 | | |
589 | 686 | | |
590 | 687 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
323 | 323 | | |
324 | 324 | | |
325 | 325 | | |
326 | | - | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
327 | 331 | | |
328 | 332 | | |
329 | 333 | | |
| |||
336 | 340 | | |
337 | 341 | | |
338 | 342 | | |
| 343 | + | |
339 | 344 | | |
340 | | - | |
| 345 | + | |
341 | 346 | | |
342 | 347 | | |
343 | 348 | | |
344 | 349 | | |
345 | 350 | | |
346 | 351 | | |
347 | 352 | | |
348 | | - | |
| 353 | + | |
| 354 | + | |
349 | 355 | | |
350 | 356 | | |
351 | 357 | | |
| |||
372 | 378 | | |
373 | 379 | | |
374 | 380 | | |
375 | | - | |
| 381 | + | |
376 | 382 | | |
377 | 383 | | |
378 | | - | |
379 | | - | |
380 | | - | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
381 | 388 | | |
382 | 389 | | |
383 | 390 | | |
| |||
388 | 395 | | |
389 | 396 | | |
390 | 397 | | |
391 | | - | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
392 | 411 | | |
393 | 412 | | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
394 | 420 | | |
395 | 421 | | |
396 | 422 | | |
| |||
0 commit comments