- Deleted the deploy.cmd script as it was no longer needed. - Updated Dockerfile to include curl for health checks and added a non-root user for improved security. - Modified health check command to use curl for better reliability. - Adjusted docker-compose.test.yml to reflect changes in health check configuration. - Cleaned up appsettings.json and removed unused configuration properties. - Removed Resource entity and related requests from the codebase as part of the architectural shift. - Updated documentation to reflect the removal of hardware binding and related endpoints. Co-authored-by: Cursor <cursoragent@cursor.com>
4.9 KiB
Resource Management
Cycle 1 (2026-05-13) note — AZ-197 removed the
Hardwarefield fromGetResourceRequestand removedCheckResourceRequestandPOST /resources/checkentirely. AZ-183 introduced an OTA update path (POST /get-update,POST /resources/publish,IResourceUpdateService,Resourceentity,resourcestable,ResourcesConfig.EncryptionMasterKey) but it was reverted later the same day after the security audit (finding F-1) — the OTA delivery model itself was deemed obsolete. The component is now back to filesystem-backed storage only.
1. High-Level Overview
Purpose: filesystem-backed storage — upload, list, download (per-user AES-encrypted), folder clearing, installer distribution. Owned by IResourcesService.
Architectural Pattern: a single service over the local filesystem. No DB access, no cache.
Upstream dependencies: Data Layer (ResourcesConfig), Authentication & Security (encryption via Security.EncryptTo).
Downstream consumers: Admin API (resource endpoints).
2. Internal Interfaces
Interface: IResourcesService
| Method | Input | Output | Async | Error Types |
|---|---|---|---|---|
GetInstaller |
bool isStage |
(string?, Stream?) |
No | None (returns nulls if not found) |
GetEncryptedResource |
string? dataFolder, string fileName, string key, CancellationToken |
Stream |
Yes | FileNotFoundException |
SaveResource |
string? dataFolder, IFormFile data, CancellationToken |
void | Yes | BusinessException(NoFileProvided) |
ListResources |
string? dataFolder, string? search, CancellationToken |
IEnumerable<string> |
Yes | DirectoryNotFoundException |
ClearFolder |
string? dataFolder |
void | No | None |
Input DTO:
GetResourceRequest (post-AZ-197):
Password: string (required, min 8 chars)
FileName: string (required, not empty)
// Hardware field removed by AZ-197.
// CheckResourceRequest — REMOVED by AZ-197.
// GetUpdateRequest, PublishResourceRequest — added by AZ-183, removed in the post-cycle-1 revert.
3. External API Specification
N/A — exposed through Admin API.
4. Data Access Patterns
ResourcesService is filesystem-only — no DB access, no cache.
| Source | Service | Pattern |
|---|---|---|
Filesystem (ResourcesConfig.ResourcesFolder) |
ResourcesService |
Direct read/write/delete |
Storage Estimates
- Filesystem: AI models, DLLs, installers — potentially hundreds of MB per file.
5. Implementation Details
State Management: stateless — reads/writes directly to filesystem.
Key Dependencies: none beyond BCL (System.IO).
Error Handling Strategy:
SaveResourcethrowsBusinessException(NoFileProvided)for null uploads.- Missing files/directories throw standard .NET I/O exceptions.
ClearFoldersilently returns if directory doesn't exist.GetInstallerreturns(null, null)tuple if installer file is not found.
6. Extensions and Helpers
| Helper | Purpose | Used By |
|---|---|---|
Security.EncryptTo |
AES stream encryption | GetEncryptedResource |
Security.GetApiEncryptionKey(email, password) |
Per-user key derivation (post-AZ-197 — no hardware component) | Admin API (before calling GetEncryptedResource) |
7. Caveats & Edge Cases
Known limitations (security-audit findings):
- F-2 (High) — no path traversal protection:
dataFolderparameter is concatenated directly withResourcesFolder. A maliciousdataFolderlike../../etccould access arbitrary filesystem paths. Filed as separate ticket. SaveResourcedeletes existing file before writing — no versioning or backup.GetEncryptedResourceloads the entire encrypted file into aMemoryStream— memory-intensive for large files.ListResourceswraps a synchronousDirectoryInfo.GetFilesinTask.FromResult— not truly async.
Performance bottlenecks:
- Full file encryption to memory before streaming response: memory usage scales with file size.
ClearFolderiterates and deletes files synchronously.
8. Dependency Graph
Must be implemented after: Data Layer (ResourcesConfig), Authentication & Security (encryption).
Can be implemented in parallel with: User Management.
Blocks: Admin API.
9. Logging Strategy
| Log Level | When | Example |
|---|---|---|
| INFO | Successful file save | Resource {data.FileName} Saved Successfully |
Log format: string interpolation via Serilog (security audit F-12 hygiene item: convert to structured form).
Log storage: console + rolling file (via Serilog configured in Program.cs).
Modules Covered
Services/ResourcesServiceCommon/Requests/GetResourceRequest(post-AZ-197 — noCheckResourceRequest, noHardwarefield)Common/Configs/ResourcesConfig(theEncryptionMasterKeyfield added by AZ-183 was removed in the post-cycle-1 revert)