0.134.26
Fixed (MEDIUM-аудит: 8 находок группы 4.7 Updater/Sandbox, см. docs/audit/backend-2026-06.md §4.7)
- M-U-1
updater.SaveCurrentBinaryAsBackup+PerformBinaryRollback— атомарная запись через temp-файл +os.Rename+fsyncродительской директории. РанееO_TRUNCсразу затирал существующий backup, а сбой посредиio.Copyоставлял усечённый файл. НовыйatomicCopyFileпереиспользуется в обеих функциях. - M-U-2
updater.WritePendingFlag+WriteFailedFlag—os.WriteFileзаменён наwriteFileSync(атомарная запись + fsync) +fsyncDir(sync родительской директории). Без fsync флаг мог остаться в page-cache при kernel crash между записью и рестартом worker’а. - M-U-3
updater.setExecutable— добавлена проверкаstrings.HasSuffix(exe, ".old"). На Windows после selfupdate процесс работает вtarget.old; ранее мы случайно делали chmod устаревшего файла вместо нового. - M-U-4
updater.CompareVersions+IsValidVersion— добавленаnormalizeVersion(auto-prefixv). Раньше не-prefixed версии тихо считались равными (semver.Compare возвращал 0). Теперь"0.40.0"корректно сравнивается с"v0.39.0". - M-U-5
updater.ParseManifest—MinSupportedтеперь проверяется наv-префикс (какLatest). Ранее невалидныйmin_supported: "0.40.0"отключал upgrade-gate (semver.Compare возвращал 0, условие>0ложно → апгрейд проходил на слишком старую версию). - M-U-6
updater.Verify— убран hex-fallback. Теперь строго base64 (как пишетscripts/sign). Раньше fallback усложнял аудит и мог принять неожиданный формат от неподдерживаемого тулчейна. - M-U-7 (SKIPPED — operational) Ed25519 key rotation —
PublicKeys []ed25519.PublicKeyуже поддерживает несколько ключей (тестTestVerify_AcceptsAnyOfMultipleKeys). Добавление второго ключа — operational-процедура (genkey + deploy.sh), не код. - M-U-8
security.WrapCommand— при неизвестном backend теперьslog.Warnс указанием значения. Раньше молча возвращался nil, и команда запускалась без песочницы. Добавлен явныйcase SandboxNone: return nil(semantic clarity). - M-U-9
permissions.Warnings— добавлены 2 новых warning’а: (1)len(CustomAllowPatterns) > 0— bypasses defaultDeny; (2) один и тот же regex вCustomAllow+CustomDeny— allow перебивает deny, последний становится мёртвым кодом.
Tests
- Новые:
internal/updater/medium_audit_test.go—TestCompareVersions_NonVPrefix,TestParseManifest_RejectsBadMinSupported,TestParseManifest_AcceptsVPrefixedMinSupported,TestVerify_RejectsHexSignature,TestPendingFlagLifecycle_Atomic,TestPerformBinaryRollback_Atomic. - Новые:
internal/permissions/validate_test.go—TestWarnings_CustomAllowBypassesDefaultDeny,TestWarnings_CustomAllowAndDenyIntersect. - Новые:
internal/security/sandbox_test.go—TestWrapCommand_UnknownBackend.
Build / Tests
go test ./internal/...— все тесты проходят.go build— OK.