Files
admin/_docs/02_document/tests/traceability-matrix.md
T
Oleksandr Bezdieniezhnykh 3a925b9b0f
ci/woodpecker/push/01-test Pipeline failed
ci/woodpecker/push/02-build-push unknown status
refactor: remove obsolete resource download and installer endpoints
- Deleted the `POST /resources/get/{dataFolder?}` and `GET /resources/get-installer` endpoints as part of the architectural shift towards simplified resource management.
- Removed associated methods and configurations, including `ResourcesService.GetEncryptedResource`, `ResourcesService.GetInstaller`, and related properties in `ResourcesConfig`.
- Cleaned up environment variables and configuration files to reflect the removal of installer-related settings.
- Eliminated the `GetResourceRequest` DTO and its validator, along with the `WrongResourceName` error code.
- Updated documentation to clarify the changes in resource handling and the retirement of per-user file encryption.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 04:17:55 +03:00

140 lines
12 KiB
Markdown

# Traceability Matrix
## Acceptance Criteria Coverage
| AC ID | Acceptance Criterion | Test IDs | Coverage |
|-------|---------------------|----------|----------|
| AC-1 | Valid login returns JWT | FT-P-01, NFT-PERF-01, NFT-RES-01, NFT-RES-LIM-04 | Covered |
| AC-2 | Unknown email returns code 10 | FT-N-01 | Covered |
| AC-3 | Wrong password returns code 30 | FT-N-02 | Covered |
| AC-4 | JWT lifetime 4 hours | FT-P-03, NFT-SEC-04 | Covered |
| AC-5 | Email min 8 chars | FT-P-02, FT-N-03 | Covered |
| AC-6 | Email format validation | FT-P-02, FT-N-04 | Covered |
| AC-7 | Password min 8 chars | FT-P-02, FT-N-08 | Covered |
| AC-8 | Duplicate email returns code 20 | FT-N-07 | Covered |
| AC-9 | Only ApiAdmin can manage users | FT-P-06, FT-P-07, FT-P-11, FT-P-12, FT-P-13, NFT-SEC-02, NFT-SEC-06 | Covered |
| AC-10 | First hardware check stores | FT-P-04, NFT-RES-03 | Covered |
| AC-11 | Subsequent hardware check validates | FT-P-05, NFT-RES-03 | Covered |
| AC-12 | Hardware mismatch returns code 40 | FT-N-06 | Covered |
| AC-13 | Max upload 200 MB | FT-P-08, NFT-RES-LIM-01, NFT-RES-LIM-02, NFT-PERF-03 | Covered |
| AC-14 | AES-256-CBC encryption | FT-P-09, FT-P-10, NFT-PERF-02, NFT-PERF-03, NFT-RES-LIM-03 | Covered |
| AC-15 | Encrypt-decrypt round-trip | FT-P-10 | Covered |
| AC-16 | Empty file upload returns code 70 | FT-N-05 | Covered |
| AC-17 | SHA-384 password hashing | NFT-SEC-03 | Covered |
| AC-18 | All non-login endpoints require auth | FT-P-09, NFT-SEC-01, NFT-RES-02, NFT-RES-LIM-04 | Covered |
| AC-19 | Encryption key derived from email+password+hw | FT-P-10, NFT-SEC-05 | Covered |
## Restrictions Coverage
| Restriction ID | Restriction | Test IDs | Coverage |
|---------------|-------------|----------|----------|
| RESTRICT-SW-01 | .NET 10.0 runtime | All tests (implicit — Docker build uses .NET 10.0) | Covered |
| RESTRICT-SW-02 | PostgreSQL database | All DB tests (implicit — docker-compose uses PostgreSQL) | Covered |
| RESTRICT-SW-03 | Max request body 200 MB | NFT-RES-LIM-01, NFT-RES-LIM-02 | Covered |
| RESTRICT-SW-04 | JWT HMAC-SHA256 signing | FT-P-03, NFT-SEC-04 | Covered |
| RESTRICT-HW-01 | ARM64 target architecture | — | NOT COVERED — CI builds ARM64; tests run on dev x64 host |
| RESTRICT-ENV-01 | Secrets via env vars | All tests (implicit — docker-compose passes env vars) | Covered |
| RESTRICT-ENV-02 | CORS admin.azaion.com | — | NOT COVERED — CORS is browser-enforced, not testable at API level |
| RESTRICT-OP-01 | Serilog logging | — | NOT COVERED — log output verification not in scope |
## Coverage Summary
| Category | Total Items | Covered | Not Covered | Coverage % |
|----------|-----------|---------|-------------|-----------|
| Acceptance Criteria (baseline) | 19 | 19 | 0 | 100% |
| Acceptance Criteria (cycle 1) | 24 | 24 | 0 | 100% |
| Acceptance Criteria (cycle 2) | 6 | 6 | 0 | 100% |
| Restrictions | 8 | 5 | 3 | 63% |
| **Total** | **57** | **54** | **3** | **95%** |
## Uncovered Items Analysis
| Item | Reason Not Covered | Risk | Mitigation |
|------|-------------------|------|-----------|
| RESTRICT-HW-01 (ARM64) | Tests run on x64 dev/CI host; cross-architecture testing requires ARM hardware | Low — .NET runtime handles arch differences; no arch-specific code in application | CI builds ARM64 image; manual smoke test on target device |
| RESTRICT-ENV-02 (CORS) | CORS is enforced by browsers, not by server-to-server HTTP calls | Low — CORS policy is declarative in Program.cs | Visual inspection of CORS configuration in code |
| RESTRICT-OP-01 (Logging) | Log output format/content verification adds complexity without proportional value | Low — Serilog configuration is declarative | Code review of Serilog setup |
## Cycle 1 Additions (2026-05-13) — AZ-513, AZ-196, AZ-183, AZ-197
Appended during the existing-code cycle 1 Test-Spec Sync (autodev Step 12). Cycle 1 ACs are namespaced by their tracker ID to avoid colliding with the baseline AC-1..AC-19 numbering above.
### AZ-513 — Detection Classes CRUD
| AC ID | Acceptance Criterion | Test IDs | Coverage |
|-------|---------------------|----------|----------|
| AZ-513 AC-1 | POST /classes creates a class | FT-P-14 | Covered |
| AZ-513 AC-2 | POST /classes requires ApiAdmin authorization | FT-N-09 | Covered |
| AZ-513 AC-3 | PATCH /classes/{id} updates an existing class (full body) | FT-P-15 | Covered |
| AZ-513 AC-4 | PATCH /classes/{id} accepts partial body (partial-merge) | FT-P-16 | Covered |
| AZ-513 AC-5 | PATCH /classes/{id} returns 404 for unknown id | FT-N-10 | Covered |
| AZ-513 AC-6 | PATCH /classes/{id} requires ApiAdmin authorization | FT-N-11 | Covered |
| AZ-513 AC-7 | DELETE /classes/{id} removes a class | FT-P-17 | Covered |
| AZ-513 AC-8 | DELETE /classes/{id} returns 404 for unknown id | FT-N-12 | Covered |
| AZ-513 AC-9 | DELETE /classes/{id} requires ApiAdmin authorization | FT-N-13 | Covered |
| AZ-513 AC-10 | UI add/delete/edit affordances work end-to-end | — | Cross-workspace (ui/ e2e harness) — out of scope for this workspace |
### AZ-196 — Device Auto-Registration
| AC ID | Acceptance Criterion | Test IDs | Coverage |
|-------|---------------------|----------|----------|
| AZ-196 AC-1 | First device gets serial azj-0000 (shape: serial / email / 32-hex password) | FT-P-18 | Covered |
| AZ-196 AC-2 | Sequential numbering on subsequent calls | FT-P-19 | Covered |
| AZ-196 AC-3 | Persisted user has Role=CompanionPC, IsEnabled=true | FT-P-20 | Covered (verified via successful login → role-gated behaviour) |
| AZ-196 AC-4 | Returned plaintext password is hashed (SHA-384) in DB, not stored plaintext | FT-P-20 | Covered (verified via successful login round-trip) |
| AZ-196 AC-5 | Requires ApiAdmin authorization | FT-N-14 | Covered |
### AZ-183 — Resources OTA Update Check (REVERTED post-cycle-1)
The OTA Update Check & Publish feature shipped in cycle 1 was reverted later the same day after the security audit (finding F-1: `/get-update` disclosed plaintext per-resource encryption keys to any authenticated caller; the OTA delivery model itself was deemed obsolete in the target architecture). The endpoints, service, entity, table, request DTOs, response DTO, cache key, master-key config field, and the e2e test class `ResourceUpdateTests` were all removed.
| AC ID | Acceptance Criterion | Test IDs | Status |
|-------|---------------------|----------|--------|
| AZ-183 AC-1 | Resources table created with required columns | — | **Reverted** — table dropped from migration set (`env/db/05_resources.sql` deleted) |
| AZ-183 AC-2 | POST /get-update returns newer resources | ~~FT-P-21~~ | **Reverted** — endpoint and test deleted |
| AZ-183 AC-3 | POST /get-update returns empty when device already current | ~~FT-P-22~~ | **Reverted** — endpoint and test deleted |
| AZ-183 AC-4 | Memory cache avoids DB pressure under 2000-device polling | — | **Reverted** — cache key removed |
| AZ-183 AC-5 | Cache invalidated on CI/CD publish | ~~FT-P-23~~ | **Reverted** — endpoint and test deleted |
### AZ-197 — Hardware-Binding Removal
| AC ID | Acceptance Criterion | Test IDs | Coverage |
|-------|---------------------|----------|----------|
| AZ-197 AC-1 | Resource download works without `Hardware` field | FT-P-09 / FT-P-10 (legacy bodies retained; wire shape now omits the field) | Covered (e2e `ResourceTests` updated by AZ-197 batch 6) |
| AZ-197 AC-2 | `PUT /users/hardware/set` and `POST /resources/check` return 404 | FT-N-15 | Covered |
| AZ-197 AC-3 | `Security.GetApiEncryptionKey` signature simplified to (email, password) | — | Internal signature — covered by `Azaion.Test/SecurityTest` unit tests, not blackbox |
| AZ-197 AC-4 | `HardwareBindingTests` removed; no remaining test asserts code 40 / hardware-hash binding | — | Build/CI invariant — verified by test-suite enumeration |
| AZ-197 AC-5 | Resource calls in remaining tests do not send `Hardware` | — | Build/CI invariant — verified by source review during AZ-197 batch 6 |
| AZ-197 AC-6 | `ExceptionEnum` no longer carries `HardwareIdMismatch` / `BadHardware` | — | Build/CI invariant — verified by enum read |
| AZ-197 AC-7 | `dotnet build` is clean (no new warnings) | — | Build invariant |
| AZ-197 AC-8 | Test suite passes (excluding deleted `HardwareBindingTests`) | All e2e tests + `Azaion.Test` | Covered by Step 11 Run Tests (48/48 e2e + 2/2 unit, 2026-05-13) |
### Obsoleted Baseline Entries (superseded by AZ-197)
The matrix rows below are kept for ID stability but no longer reflect production behaviour. They are superseded by the AZ-197 entries above and by FT-N-15 in `blackbox-tests.md`. Do NOT regenerate or delete these in cycle-update mode — wait for a full `/test-spec` rerun.
| Legacy Matrix Row | Status |
|-------------------|--------|
| AC-10 (First hardware check stores) | Obsoleted by AZ-197 — endpoint removed |
| AC-11 (Subsequent hardware check validates) | Obsoleted by AZ-197 — endpoint removed |
| AC-12 (Hardware mismatch returns code 40) | Obsoleted by AZ-197 — `ExceptionEnum` value removed |
| AC-19 (Encryption key derived from email+password+hw) | Partially obsoleted — derivation is now `email + password` only |
## Cycle 2 Cleanup (2026-05-14) — Obsolete Resource Endpoints Removed
The encrypted-download and installer-download endpoints were removed as obsolete. Affected matrix rows below are kept for ID stability but the underlying behaviour is gone; they are superseded by FT-N-16 in `blackbox-tests.md`.
| Removed surface | Endpoint(s) | Affected legacy entries | Status |
|-----------------|-------------|-------------------------|--------|
| Per-user encrypted resource download | `POST /resources/get/{dataFolder?}` | AC-14 (AES-256-CBC encryption), AC-15 (round-trip), AC-19 (key derivation), FT-P-09, FT-P-10 | **Reverted** — endpoint deleted; `Security.GetApiEncryptionKey` / `EncryptTo` / `DecryptTo` and `ResourcesService.GetEncryptedResource` deleted; `GetResourceRequest` DTO deleted; e2e tests `Encrypted_download_returns_octet_stream_and_non_empty_body` and `Encryption_round_trip_decrypt_matches_original_bytes` deleted from `ResourceTests.cs`; e2e test `Per_user_encryption_produces_distinct_ciphertext_for_same_file` deleted from `SecurityTests.cs`; `Azaion.Test/SecurityTest.cs` deleted (and the now-empty `Azaion.Test` project removed from the solution). |
| Installer download (production + staging) | `GET /resources/get-installer`, `GET /resources/get-installer/stage` | AC-23 (latest installer), `ResourcesConfig.SuiteInstallerFolder` / `SuiteStageInstallerFolder` references | **Reverted** — endpoints deleted; `ResourcesService.GetInstaller` deleted; both config properties removed from `appsettings.json`, `.env.example`, `secrets/staging.public.env`, `secrets/production.public.env`, and `docker-compose.test.yml`. No e2e tests had been written for these endpoints, so no tests required removal. |
| AC ID | Acceptance Criterion | Test IDs | Coverage |
|-------|---------------------|----------|----------|
| Cycle-2 AC-1 | `POST /resources/get/{dataFolder?}` returns 404 | FT-N-16 | Covered |
| Cycle-2 AC-2 | `GET /resources/get-installer` returns 404 | FT-N-16 | Covered |
| Cycle-2 AC-3 | `GET /resources/get-installer/stage` returns 404 | FT-N-16 | Covered |
| Cycle-2 AC-4 | `ExceptionEnum` no longer carries `WrongResourceName` (50); the gap is preserved | — | Build/CI invariant — verified by enum read |
| Cycle-2 AC-5 | `Azaion.Test` project no longer in solution; build is clean | — | Build invariant — `dotnet build Azaion.AdminApi.sln` clean post-cleanup |
| Cycle-2 AC-6 | E2E suite passes after the test deletions above | All e2e tests | Covered by Step 11 Run Tests post-cleanup (2026-05-14) |