Feature/gitea deployment workflow #1
+32
@@ -85,3 +85,35 @@ Also recorded for Operations: **DEV-05** — keys are stored unencrypted at rest
|
|||||||
No failures occurred during generation.
|
No failures occurred during generation.
|
||||||
|
|
||||||
**Not verifiable at this stage**: the composed startup path (`MigrateCoreDatabase` against a real database, and both hosts actually starting) requires SQL Server. Carried to the phase-level Build and Test stage.
|
**Not verifiable at this stage**: the composed startup path (`MigrateCoreDatabase` against a real database, and both hosts actually starting) requires SQL Server. Carried to the phase-level Build and Test stage.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Follow-up found in local testing (2026-07-28)
|
||||||
|
|
||||||
|
Starting both hosts after U2 produced, on the master:
|
||||||
|
|
||||||
|
```
|
||||||
|
CryptographicException: The key {2ad1bf17-...} was not found in the key ring
|
||||||
|
at ApiKeyProtector.Unprotect
|
||||||
|
at CmsInstanceService.VerifyIntegrityAsync
|
||||||
|
```
|
||||||
|
|
||||||
|
**Not a defect in this unit — it is this unit's change meeting data written before it.** The stored
|
||||||
|
`MasterCmsInstances.ApiKey` had been encrypted under the old file-based key ring in
|
||||||
|
`%LOCALAPPDATA%\ASP.NET\DataProtection-Keys`; both databases now hold their own freshly generated
|
||||||
|
single key, which cannot decrypt it. The key ring working correctly is precisely why the old key is
|
||||||
|
not found.
|
||||||
|
|
||||||
|
**The gap this unit left**: no one-time path for ciphertext that predates the move. Recorded as
|
||||||
|
**ASM-08** in `requirements.md`. Confirmed with the user on 2026-07-28 that the CMS is not deployed
|
||||||
|
anywhere yet, so the first deploy meets an empty database and no migration is shipped. If that ever
|
||||||
|
stops being true, U6 must not deploy until either the affected rows are cleared and the instances
|
||||||
|
re-registered, or this unit gains a fallback that reads the old ring and re-encrypts.
|
||||||
|
|
||||||
|
Resolved locally by deleting the one stale row on each side and re-registering the slave.
|
||||||
|
|
||||||
|
**Worth noting for U4's alerting**: the two sides fail differently. `Modules.Master/ApiKeyProtector`
|
||||||
|
lets the exception escape, while `Modules.Availability/MasterApiKeyProtector` catches it and returns
|
||||||
|
null, so the slave reports "master API key rejected" instead. That is exactly the ambiguity U4's
|
||||||
|
`MasterApiKeyRejected` event documents — an intruder, **or** an unreadable key ring — occurring in
|
||||||
|
practice.
|
||||||
|
|||||||
+3
-2
@@ -335,6 +335,7 @@ DEV-01…04 are **pre-existing or cost-driven** and none is introduced by this f
|
|||||||
| ASM-05 | The existing Umami instance at `analytics.slpsoftware.nl` remains available and its script origin can be added to the CSP. | FR-16, FR-18. | Umami setup gains host work, as in the reference project. |
|
| ASM-05 | The existing Umami instance at `analytics.slpsoftware.nl` remains available and its script origin can be added to the CSP. | FR-16, FR-18. | Umami setup gains host work, as in the reference project. |
|
||||||
| ASM-06 | One Sentry project with environment tags is acceptable for both backend and frontend events of this CMS. | D-19. | Split into more projects; only configuration changes. |
|
| ASM-06 | One Sentry project with environment tags is acceptable for both backend and frontend events of this CMS. | D-19. | Split into more projects; only configuration changes. |
|
||||||
| ASM-07 | Existing Gitea secrets for the Pi (`PI_MAIN_*` in the reference project) can be reused or replicated for this repository. | FR-02. | New secrets are created; documented in FR-23. |
|
| ASM-07 | Existing Gitea secrets for the Pi (`PI_MAIN_*` in the reference project) can be reused or replicated for this repository. | FR-02. | New secrets are created; documented in FR-23. |
|
||||||
|
| ASM-08 | **No environment holds API keys encrypted under the old file-based key ring.** Confirmed by the user on 2026-07-28: the CMS is not deployed anywhere yet, so the first deploy of U2 meets an empty database. U2 therefore ships **no** one-time re-encryption path for pre-existing ciphertext. | U2 moved the Data Protection key ring from the filesystem into the database. Ciphertext written under the old ring cannot be decrypted by the new one — it fails with `The key {id} was not found in the key ring`. Observed locally on 2026-07-28 against rows written before U2, and resolved by deleting and re-registering. | **U6 must not deploy** until either the affected rows are cleared and the instances re-registered, or U2 gains a migration that reads the old ring as a fallback and re-encrypts. This is a silent, destructive failure of master/slave communication — exactly the class NFR-02 exists to prevent. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -353,9 +354,9 @@ DEV-01…04 are **pre-existing or cost-driven** and none is introduced by this f
|
|||||||
|
|
||||||
This feature turns a manually deployed modular-monolith CMS into one with an automated, auditable pipeline, on hosting where nothing can be configured server-side.
|
This feature turns a manually deployed modular-monolith CMS into one with an automated, auditable pipeline, on hosting where nothing can be configured server-side.
|
||||||
|
|
||||||
**24 functional requirements, 10 non-functional requirements, 32 traced decisions, 7 assumptions, 2 remaining open items, 4 documented security deviations.**
|
**24 functional requirements, 10 non-functional requirements, 32 traced decisions, 8 assumptions, 2 remaining open items, 4 documented security deviations.**
|
||||||
|
|
||||||
*(FR-24 added and OPEN-02 closed at Application Design on 2026-07-27. OPEN-01 closed at NFR Design on 2026-07-28.)*
|
*(FR-24 added and OPEN-02 closed at Application Design on 2026-07-27. OPEN-01 closed at NFR Design on 2026-07-28. ASM-08 added on 2026-07-28 after the key-ring migration gap surfaced in local testing.)*
|
||||||
|
|
||||||
The three requirements that carry the most risk if implemented carelessly:
|
The three requirements that carry the most risk if implemented carelessly:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user