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

3.3 KiB
Raw Blame History

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)

{
  "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:

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)