nova-cache 0.8.0.0 → 0.9.0.0
raw patch · 4 files changed
+42/−23 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- NovaCache.Xz: XzLimits :: Word64 -> Word64 -> XzLimits
- NovaCache.Xz: XzMemoryOverBound :: Word64 -> XzError
- NovaCache.Xz: XzOutputOverBound :: Word64 -> XzError
- NovaCache.Xz: XzStreamError :: String -> XzError
- NovaCache.Xz: [xzMaxDecoderMemoryBytes] :: XzLimits -> Word64
- NovaCache.Xz: [xzMaxOutputBytes] :: XzLimits -> Word64
- NovaCache.Xz: data XzError
- NovaCache.Xz: data XzLimits
- NovaCache.Xz: decompress :: XzLimits -> ByteString -> Either XzError ByteString
- NovaCache.Xz: defaultXzDecoderMemoryBytes :: Word64
- NovaCache.Xz: instance GHC.Internal.Classes.Eq NovaCache.Xz.XzError
- NovaCache.Xz: instance GHC.Internal.Classes.Eq NovaCache.Xz.XzLimits
- NovaCache.Xz: instance GHC.Internal.Exception.Type.Exception NovaCache.Xz.XzError
- NovaCache.Xz: instance GHC.Internal.Show.Show NovaCache.Xz.XzError
- NovaCache.Xz: instance GHC.Internal.Show.Show NovaCache.Xz.XzLimits
- NovaCache.Xz: withXzSource :: XzLimits -> IO ByteString -> (IO ByteString -> IO a) -> IO a
Files
- CHANGELOG.md +4/−0
- README.md +3/−3
- nova-cache.cabal +30/−16
- src/NovaCache/Xz.hs +5/−4
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Changelog +## Unreleased++- **`NovaCache.Xz` moves to the public `nova-cache:xz` sublibrary; the `xz` flag is gone.** A dependency's flag cannot be set from a consumer's `.cabal` file, so reaching the decoder forced a mirrored flag plus a matching `constraints: nova-cache +xz` in every downstream - two knobs that had to agree and that the solver could not see. `build-depends: nova-cache:xz` now expresses the need directly, and consumers without it still never build the bundled liblzma, keeping the 0.5.0.0 lesson. Builds that passed `-f xz` drop the flag and add the dependency; the module and its API are unchanged.+ ## 0.8.0.0 - 2026-08-20 - **Bounded xz decompression returns: the new `NovaCache.Xz`, behind a manual, off-by-default `xz` flag.** 0.5.0.0 removed xz support for having no consumer; foreign-cache substitution (cache.nixos.org serves `.nar.xz`) is the consumer, and the decoder comes back shaped for untrusted input. The consumer knows the narinfo's declared NarSize before decompressing, so `decompress` takes that bound and fails past it - a small compressed input cannot expand to arbitrary memory ahead of the hash check - and the decoder's own state is capped too (`xzMaxDecoderMemoryBytes`; the dictionary size is an attacker-chosen number read from the stream header, and upstream passes no limit there). `withXzSource` decompresses a chunk source into a chunk source under the same limits, pairing with streaming NAR consumption. Concatenated streams decode as one output, matching upstream's `LZMA_CONCATENATED` decoder. The `lzma-static` dependency bundles liblzma's C sources, so the flag needs no system library on any platform - and it stays off by default anyway: the 0.5.0.0 lesson was a compression dependency nobody asked for in every install.
README.md view
@@ -54,8 +54,8 @@ -- Stream a tree's NAR and hash it in one pass; the archive never -- exists in memory. The parsing side is NovaCache.NAR.Stream, a--- chunk-fed event machine, and the xz flag adds decompression--- bounded by a narinfo's declared NarSize.+-- chunk-fed event machine, and the nova-cache:xz sublibrary adds+-- decompression bounded by a narinfo's declared NarSize. narHash <- withNarSource defaultCaseHack path $ \pull -> let go ctx = do chunk <- pull@@ -116,7 +116,7 @@ cabal test ``` -Optional flags: `--flag server` builds the cache server; `--flag xz` builds the bounded xz decoder (liblzma is bundled - no system library needed). Requires GHC 9.14+ and cabal-install 3.10+.+Optional extras: `--flag server` builds the cache server, and the public `nova-cache:xz` sublibrary carries the bounded xz decoder (liblzma is bundled - no system library needed) - consumers depend on it with `build-depends: nova-cache:xz`. Requires GHC 9.14+ and cabal-install 3.10+. ---
nova-cache.cabal view
@@ -1,12 +1,13 @@ cabal-version: 3.0 name: nova-cache-version: 0.8.0.0+version: 0.9.0.0 synopsis: Pure-first Nix binary cache protocol library description: A pure-first library implementing the Nix binary cache protocol - nix-base32, NAR serialization (whole-tree and streaming), narinfo- parsing, Ed25519 signing, store path handling, content validation,- and bounded xz decompression - with an optional WAI server.+ parsing, Ed25519 signing, store path handling, and content+ validation - with an optional WAI server, and bounded xz+ decompression as the public @nova-cache:xz@ sublibrary. license: Apache-2.0 license-file: LICENSE@@ -29,11 +30,6 @@ default: False manual: True -flag xz- description: Build NovaCache.Xz, bounded xz decompression (lzma-static bundles liblzma; no system library)- default: False- manual: True- library exposed-modules: NovaCache.Base32@@ -63,11 +59,27 @@ , vector >= 0.12 && < 0.14 , wai >= 3.2 && < 3.3 -- if flag(xz)- exposed-modules: NovaCache.Xz- build-depends: lzma-static >= 5.2.5 && < 5.3+ hs-source-dirs: src+ default-language: Haskell2010+ default-extensions:+ BangPatterns+ OverloadedStrings+ ghc-options:+ -Wall+ -Wcompat+ -Wincomplete-record-updates+ -Wincomplete-uni-patterns +-- The bounded xz decoder as a solver-visible opt-in: a consumer that+-- substitutes foreign caches writes build-depends: nova-cache:xz and+-- gets the module; everyone else never builds lzma-static's bundled+-- liblzma. This replaces the manual xz flag - a dependency's flag+-- cannot be set from a consumer's .cabal file, which forced mirror+-- flags and matching constraints downstream (nova-nix#27) - while+-- keeping the 0.5.0.0 lesson: xz stays out of the default install.+library xz+ visibility: public+ exposed-modules: NovaCache.Xz hs-source-dirs: src default-language: Haskell2010 default-extensions:@@ -79,6 +91,11 @@ -Wincomplete-record-updates -Wincomplete-uni-patterns + build-depends:+ base >= 4.22 && < 5+ , bytestring >= 0.11 && < 0.13+ , lzma-static >= 5.2.5 && < 5.3+ executable nova-cache-server if !flag(server) buildable: False@@ -124,9 +141,6 @@ , wai-extra >= 3.1 && < 3.2 test-suite nova-cache-xz-test- if !flag(xz)- buildable: False- type: exitcode-stdio-1.0 main-is: XzTest.hs hs-source-dirs: test@@ -138,7 +152,7 @@ build-depends: base >= 4.22 && < 5 , bytestring >= 0.11 && < 0.13- , nova-cache+ , nova-cache:xz source-repository head type: git
src/NovaCache/Xz.hs view
@@ -14,13 +14,14 @@ -- Concatenated streams decode as one output, matching upstream's -- @LZMA_CONCATENATED@ decoder in libutil's compression sink. ----- This module builds only under the @xz@ cabal flag. The+-- This module lives in the public @nova-cache:xz@ sublibrary. The -- @lzma-static@ dependency bundles liblzma's C sources, so no system -- library is needed on any platform - but it is still an extra C -- build that consumers without foreign-cache needs should not pay--- for, and a default-on compression flag broke downstream installs--- once already (0.5.0.0). The flag is manual and off by default;--- consumers that substitute from foreign caches turn it on.+-- for, and a default-on compression dependency broke downstream+-- installs once already (0.5.0.0). Consumers that substitute from+-- foreign caches depend on @nova-cache:xz@; everyone else never+-- builds it. module NovaCache.Xz ( XzLimits (..), defaultXzDecoderMemoryBytes,