zlh-grind/SESSION_LOG/2026-02-28-modrinth-install-integration.md

155 lines
3.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 2026-02-28 Modrinth Install + Full Mod Lifecycle
**Type:** Foundational Architecture + Implementation
**Status:** Full mod lifecycle complete, file browser next
---
## Completed
### API
Implemented full mod lifecycle routes:
```
GET /api/game/mods/search?q=&vmid=
GET /api/game/servers/:id/mods
POST /api/game/servers/:id/mods/install
PATCH /api/game/servers/:id/mods/:modId
DELETE /api/game/servers/:id/mods/:modId
```
All routes:
- `requireAuth`
- Enforce container ownership
- Enforce `ctype === "game"`
- Forward to agent with timeout + `502`/`504` mapping
### Resolver
- Loader normalization fixed (`neoforge` / `fabric` / `forge` / `quilt`)
- `.jar`-only enforcement
- Host allowlist: `cdn.modrinth.com`
- Publish-date safe sorting
- SHA512 preferred (fallback to SHA1)
### Agent
Mod install flow:
- Accepts direct Modrinth artifact URL
- Validates:
- HTTPS only
- Allowed host (`cdn.modrinth.com`, `artifacts.zerolaghub.com`)
- Max size 200MB
- SHA256 hash
- Writes to `<serverRoot>/mods`
- Enables via filename convention
- Soft delete moves to `<serverRoot>/mods-removed`
- Enable/disable via rename: `.jar``.jar.disabled`
### Frontend
- Mod search drawer implemented
- Installed mods panel implemented
- Installed flag merged into search results (heuristic matching)
- Install button functional
- Enable / disable functional
- Delete functional
- Toast notifications added
---
## Current System Behavior
Filesystem is source of truth.
No database persistence for:
- Mod install history
- Modrinth project ID mapping
Installed matching is heuristic based on:
- Slug
- Filename
- Name
Soft delete retains file permanently in `/mods-removed`. No retention policy implemented (intentional).
---
## Known Architectural Tradeoffs
- No deterministic Modrinth project ID persistence yet
- Installed detection is best-effort heuristic
- No install queue
- No auto-update logic
---
## Security Controls In Place
**Agent level:**
- HTTPS-only downloads
- Host allowlist enforcement
- Redirect limit (max 3)
- 200MB hard cap
- SHA256 verification
- Filename sanitization (`[a-zA-Z0-9.+\-]` — `+` added for Modrinth filenames)
- Duplicate prevention
- Ownership enforcement (`minecraft:minecraft`)
- Temp file cleanup on failure
- Controlled mod directory write path
- Cache invalidation after every mutation
**API level:**
- Auth + ownership enforcement
- VMID validation
- Timeout protection with `AbortController`
- Resolver filtering (loader + version + stability)
- Correct payload contract to agent
---
## Payload Contract (API → Agent)
```json
{
"source": "modrinth",
"download_url": "...",
"filename": "...",
"sha512": "..."
}
```
Engine metadata format (corrected this session):
```
engineType = "neoforge" (not "minecraft")
engineVersion = "1.21.4" (not "neoforge-1.21.4")
```
---
## Remaining Issues
### Response Corruption (Needs Verification)
One early `curl` output appeared corrupted. Reproduce before wiring portal:
```bash
curl -sSl -D headers.txt -o body.txt ...
```
### API Error Mapping Refinement
- `"mod already exists"` should return `409` (currently `502`)
---
## Next Steps
1. Reproduce and resolve response corruption issue
2. Tighten API error mapping (`409` for duplicate)
3. Wire install endpoint to portal UI
4. Begin file browser (see `OPEN_THREADS.md`)