diff --git a/app/Main.hs b/app/Main.hs index 9b25457..a7d87c4 100755 --- a/app/Main.hs +++ b/app/Main.hs @@ -11,9 +11,9 @@ import Control.Monad.IO.Class (MonadIO, liftIO) import Data.Aeson (FromJSON, (.:)) import Data.Aeson.Types (parseMaybe) import Data.Bifunctor (first) -import Data.HashMap.Strict (HashMap, lookupDefault, mapMaybe) +import Data.HashMap.Strict (HashMap) import Data.List (nubBy) -import Data.Text (Text, pack, unpack) +import Data.Text (unpack) import Network.Connection (TLSSettings(..)) import Network.HTTP.Client (defaultManagerSettings, ManagerSettings (managerConnCount)) import Network.HTTP.Conduit (Manager, newManager, mkManagerSettings) @@ -40,19 +40,22 @@ import qualified System.Exit as Exit import Config (Options(..), parseOptions, unMilliSeconds, LogLevel(..), readConfigFromEnvFiles, getOptionsValue, Validated, Completed) +import KeyMap (KeyMap) import SecretsFile (Secret(..), SFError(..), readSecretsFile) +import qualified KeyMap as KM + -- | Make a HTTP URL path from a secret. This is the path that Vault expects. secretRequestPath :: MountInfo -> Secret -> String secretRequestPath (MountInfo mountInfo) secret = "/v1/" <> sMount secret <> foo <> sPath secret where - foo = case lookupDefault KV1 (pack $ sMount secret <> "/") mountInfo of + foo = case KM.lookupDefault KV1 (KM.fromString $ sMount secret <> "/") mountInfo of KV1 -> "/" KV2 -> "/data/" type EnvVar = (String, String) -data MountInfo = MountInfo (HashMap Text EngineType) +data MountInfo = MountInfo (KeyMap EngineType) deriving (Show) data Context @@ -153,7 +156,7 @@ instance FromJSON MountInfo where _ -> fail "expected a KV type")) in Aeson.withObject "MountResp" $ \obj -> - pure $ MountInfo (mapMaybe (\v -> parseMaybe getType v) obj) + pure $ MountInfo (KM.mapMaybe (\v -> parseMaybe getType v) obj) -- | Error modes of this program. -- diff --git a/nix/haskell-dependencies.nix b/nix/haskell-dependencies.nix index 54bbeff..e702e7f 100644 --- a/nix/haskell-dependencies.nix +++ b/nix/haskell-dependencies.nix @@ -19,6 +19,7 @@ haskellPackages: megaparsec optparse-applicative parser-combinators + quickcheck-instances retry text unix diff --git a/nix/haskell-overlay.nix b/nix/haskell-overlay.nix new file mode 100644 index 0000000..e786385 --- /dev/null +++ b/nix/haskell-overlay.nix @@ -0,0 +1,3 @@ +self: super: { + hashable = super.hashable_1_4_0_2; +} diff --git a/nix/nixpkgs-pinned.nix b/nix/nixpkgs-pinned.nix index e796aba..3b49a1f 100644 --- a/nix/nixpkgs-pinned.nix +++ b/nix/nixpkgs-pinned.nix @@ -8,7 +8,7 @@ let sources = import ./sources.nix; nixpkgs = import sources.nixpkgs { - overlays = overlays; + overlays = [(import ./overlay.nix)] ++ overlays; config = { imports = [ config ]; }; diff --git a/nix/overlay.nix b/nix/overlay.nix new file mode 100644 index 0000000..34759fc --- /dev/null +++ b/nix/overlay.nix @@ -0,0 +1,6 @@ +self: super: +let + haskellOverlay = import ./haskell-overlay.nix; +in { + Ghc902Packages = super.haskell.packages.ghc902.extend haskellOverlay; +} diff --git a/nix/sources.json b/nix/sources.json index 2ece6b3..873235c 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -5,10 +5,10 @@ "homepage": "", "owner": "NixOS", "repo": "nixpkgs", - "rev": "65f4c39a40e6ed4343dd94017c3ed81f416cd3b4", - "sha256": "0l09dbz9rx3id5blpj5mkzvn5fgycnpqxz30mbxgxrrmxvrgkf76", + "rev": "d08394e7cd5c7431a1e8f53b7f581e74ee909548", + "sha256": "04s6ajl82zgxic20ymcz8b9a8sr14p7c69f1axvagypcmjnqz47i", "type": "tarball", - "url": "https://github.com/NixOS/nixpkgs/archive/65f4c39a40e6ed4343dd94017c3ed81f416cd3b4.tar.gz", + "url": "https://github.com/NixOS/nixpkgs/archive/d08394e7cd5c7431a1e8f53b7f581e74ee909548.tar.gz", "url_template": "https://github.com///archive/.tar.gz" }, "static-haskell-nix": { diff --git a/nix/sources.nix b/nix/sources.nix index b796fff..41af0c6 100644 --- a/nix/sources.nix +++ b/nix/sources.nix @@ -31,8 +31,10 @@ let if spec ? branch then "refs/heads/${spec.branch}" else if spec ? tag then "refs/tags/${spec.tag}" else abort "In git source '${name}': Please specify `ref`, `tag` or `branch`!"; + submodules = if spec ? submodules then spec.submodules else false; in - builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; }; + builtins.fetchGit { url = spec.repo; inherit (spec) rev; inherit ref; } + // (if builtins.compareVersions builtins.nixVersion "2.4" >= 0 then { inherit submodules; } else {}); fetch_local = spec: spec.path; @@ -98,7 +100,10 @@ let saneName = stringAsChars (c: if isNull (builtins.match "[a-zA-Z0-9]" c) then "_" else c) name; ersatz = builtins.getEnv "NIV_OVERRIDE_${saneName}"; in - if ersatz == "" then drv else ersatz; + if ersatz == "" then drv else + # this turns the string into an actual Nix path (for both absolute and + # relative paths) + if builtins.substring 0 1 ersatz == "/" then /. + ersatz else /. + builtins.getEnv "PWD" + "/${ersatz}"; # Ports of functions for older nix versions diff --git a/nix/stack-shell.nix b/nix/stack-shell.nix index 0cf05ff..1d82f69 100644 --- a/nix/stack-shell.nix +++ b/nix/stack-shell.nix @@ -11,7 +11,7 @@ in # bundled with all the dependencies listed in `haskell-dependencies.nix`. # This allows us to have stack use the dependencies from nixpkgs, # instead of fetching them itself. - ghc = nixpkgs.haskell.packages.ghc865.ghcWithPackages getDependencies; + ghc = nixpkgs.Ghc902Packages.ghcWithPackages getDependencies; buildInputs = with nixpkgs; [ glibcLocales ]; diff --git a/nix/vaultenv-static.nix b/nix/vaultenv-static.nix index e8f7692..d699e18 100644 --- a/nix/vaultenv-static.nix +++ b/nix/vaultenv-static.nix @@ -35,7 +35,7 @@ let # This has to match the compiler used in the Stackage snapshot. # Update this when the Stackage snapshot changes the version of # GHC it uses. - compiler = "ghc865"; + compiler = "ghc902"; # Pin versions of static-haskell-nix and nixpkgs. sources = import ./sources.nix; diff --git a/package.yaml b/package.yaml index 9672448..ea5bc72 100644 --- a/package.yaml +++ b/package.yaml @@ -55,3 +55,4 @@ tests: - hspec-expectations - directory - QuickCheck + - quickcheck-instances diff --git a/src/KeyMap.hs b/src/KeyMap.hs new file mode 100644 index 0000000..26d2bf7 --- /dev/null +++ b/src/KeyMap.hs @@ -0,0 +1,25 @@ +-- | KeyMap, extending Aeson.KeyMap to support replacing HashMap. +module KeyMap + ( KeyMap + , lookupDefault + , lookup + , mapMaybe + , fromList + , toList + + , Key + , fromText + , toText + , fromString + , toString + ) where + +import Data.Aeson.Key (Key, fromText, toText, fromString, toString) +import Data.Aeson.KeyMap (KeyMap, mapMaybe, fromList, toList) +import Data.Maybe (fromMaybe) + +import qualified Data.Aeson.KeyMap as KM + +-- | lookupDefault for KeyMap based on lookupDefault from HashMap. +lookupDefault :: v -> Key -> KeyMap v -> v +lookupDefault d k km = fromMaybe d $ KM.lookup k km diff --git a/stack.yaml b/stack.yaml index 82ab628..96cfa8f 100644 --- a/stack.yaml +++ b/stack.yaml @@ -2,7 +2,7 @@ # compiler used in this Stackage snapshot. # This value has a companion file named `stack-static-build.yaml`, used for static builds. # When updating this resolver, update that file as well. -resolver: ghc-8.6.5 +resolver: ghc-9.0.2 packages: - "." diff --git a/test/KeyMapSpec.hs b/test/KeyMapSpec.hs new file mode 100644 index 0000000..fa2ac79 --- /dev/null +++ b/test/KeyMapSpec.hs @@ -0,0 +1,25 @@ +{-# LANGUAGE ScopedTypeVariables #-} + +module KeyMapSpec where + +import Data.Text (Text) +import Test.Hspec +import Test.QuickCheck +import Test.QuickCheck.Instances () + +import qualified Data.HashMap.Internal.Strict as HM + +import qualified KeyMap as KM + +mapFirst :: (a->b) -> [(a,c)] -> [(b,c)] +mapFirst _ [] = [] +mapFirst f ((x,y) : rest) = (f x, y) : mapFirst f rest + +spec :: SpecWith () +spec = + describe "KeyMap" $ do + it "lookupDefault matches the HashMap implementation" $ + property $ \((fallback :: Text), key, mapping) -> + let keyMapValue = KM.lookupDefault fallback (KM.fromText key) (KM.fromList $ mapFirst KM.fromText mapping) + hashMapValue = HM.lookupDefault fallback key (HM.fromList mapping) + in keyMapValue `shouldBe` hashMapValue