fix(gba-validator): downgrade library-signature reject to warning under helper trust (fixes #7)#8
Closed
terafin wants to merge 1 commit into
Conversation
…er helper trust The GBA validator requires saves to carry one of the standard library signature strings (EEPROM_V / SRAM_V / FLASH_V / FLASH1M_V / FLASH512_V) or an AGB cartridge header. This assumption breaks for **RetroArch's libretro-mGBA core** (the default GBA emulator on Steam Deck / RetroDECK), which does NOT embed those signatures — confirmed against both an EA Sports title (007 - Everything or Nothing) AND a canonical mGBA-targeted save (Pokemon Emerald), neither of which contains any library footer. Net effect today: every legitimately-saved GBA file from a RetroDECK / Steam Deck user is rejected with `HTTP 422 - "gba raw save is missing a validated payload signature"`. See issue joeblack2k#7 for full evidence. Fix --- Add `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When set AND all of `detection.Evidence.HelperTrusted` + non-empty `rom_sha1` + non-blank payload hold, the signature check downgrades from reject to warning. The warning surfaces in the inspection record so operators can see the relaxation was applied. Anonymous uploads, uploads without rom_sha1, and blank payloads continue to reject as before. Set the flag on the GBA profile only. Other systems (Gameboy / NES / SNES / NDS) are unaffected. Trust rationale --------------- The advisory downgrade only fires under all three conditions simultaneously: 1. HelperTrusted — the request came over the authenticated helper channel and the helper explicitly asserted the system slug. 2. rom_sha1 present — the helper computed the ROM hash from a local ROM file (not strictly verifiable backend-side but a meaningful signal of provenance). 3. Non-blank payload — rules out freshly-erased FLASH chips and truly-empty save buffers. Random anonymous garbage cannot reach this path. Buggy or malicious clients still fail #1 unless they hold a valid app password. Tests ----- `gba_signature_advisory_test.go` covers: - Regression guard: signature PRESENT — accepted, no advisory warning - The fix: signature missing + helper trust + rom_sha1 + non-blank — accepted with warning - Security guard: signature missing + helper trust but no rom_sha1 — REJECTED - Security guard: signature missing + rom_sha1 but no helper trust — REJECTED - Security guard: blank payload under helper trust — REJECTED Full package test suite (15s) passes cleanly with no other regressions. Fixes joeblack2k#7 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b79223f to
8c3a7e9
Compare
Author
terafin
added a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 8, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
terafin
added a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 8, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 9, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 9, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 9, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 10, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 10, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 11, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 12, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 12, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
intarweb-sync-bot Bot
pushed a commit
to intarweb/RetroSaveManager
that referenced
this pull request
Jun 12, 2026
… rtc) Two related libretro-vs-standalone validator gaps in one batch — both fix real data-loss paths reported by SGM-Helper users on Steam Deck (RetroDECK) and SS1 (libretro cores), both stay strict for anonymous uploads, both ship with happy-path + regression-guard tests. ## Part 1 — GBA library-signature advisory under helper trust (was PR joeblack2k#8, fixes joeblack2k#7) Standalone mGBA / VBA-M write a library version footer (`EEPROM_V`, `SRAM_V`, `FLASH_V`, `FLASH1M_V`, `FLASH512_V`) into the .srm. RetroArch's libretro-mGBA core does NOT — confirmed across both EA Sports games (007 - Everything or Nothing, header `3500DNOB`) and canonical mGBA-targeted titles (Pokemon Emerald, sparse FRAM data). RSM's `hasGBASignature()` rejects every libretro GBA save → HTTP 422. Adds `SignatureAdvisoryWithHelperTrust bool` to `strictRawSaveValidationProfile`. When true, a failing `RequireSignature` check is downgraded from reject → warning IFF (a) `HelperTrusted` AND (b) `rom_sha1` present AND (c) payload non-blank. Anonymous uploads or uploads without `rom_sha1` still hard-reject. GBA's profile opts in. NES / SNES / Master System / Genesis are unchanged because their `RequireSignature` is nil (no signature required at all). ## Part 2 — Game Boy .rtc sidecar size validation (was PR joeblack2k#9) RetroArch / libretro Game Boy cores write a small `.rtc` sidecar next to the canonical `.srm` for cartridges with real-time clock state (Pokemon Crystal, Pokemon Gold/Silver, Harvest Moon GBC). Observed sizes 8–48 bytes. The strict gameboy raw-save profile's `AllowedSizes` only listed canonical SRAM sizes (512..65536), so every `.rtc` upload rejected with "game boy raw save size N is not recognized" → silent data loss for clock state. Adds optional `AllowedSizesByExt map[string]func(int) bool` to `strictRawSaveValidationProfile`. When the incoming extension matches a registered predicate, that predicate replaces the canonical size-set check for that extension only. Other extensions fall through to `AllowedSizes` unchanged. Gameboy opts in for `.rtc` with `1..=64` bytes. `.sav` / `.srm` / `.ram` / `.gme` still validate against `strictRawGBSizes` exactly as before — scoped relaxation, not a blanket loosening. ## Tests - `TestNormalizeSaveInputAcceptsLibretroGBASaveUnderHelperTrust` — accepts libretro GBA save without library footer when HelperTrusted + rom_sha1 - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutHelperTrust` — regression guard: anonymous upload still rejected - `TestNormalizeSaveInputRejectsLibretroGBASaveWithoutROMSHA1` — same - `TestNormalizeSaveInputRejectsBlankLibretroGBASave` — blank payload still rejected even under helper trust - `TestNormalizeSaveInputAcceptsTinyGameBoyRTCFile` — accepts 8/13/32/48/64 byte gameboy `.rtc` payloads - `TestNormalizeSaveInputRejectsTinyGameBoySRMFile` — regression guard: 8-byte `.srm` still rejected, proves relaxation is `.rtc`-scoped - `TestNormalizeSaveInputRejectsOversizedGameBoyRTCFile` — 65-byte `.rtc` rejected with new per-ext message ## Scope - Only GBA opts into `SignatureAdvisoryWithHelperTrust`; only gameboy opts into `AllowedSizesByExt`. Every other system's behavior is byte-identical to before. - Pre-existing trust / blank / executable-payload / text-noise checks still run — only the size predicate and signature requirement get the per-extension / per-trust-context overrides. Consolidates and supersedes PR joeblack2k#8 (GBA advisory) + PR joeblack2k#9 (gameboy .rtc). Both are scanner.rs/validator-relaxation fixes from the same lens (libretro-vs-standalone format gaps). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🤖 Generated with Claude Code