Skip to content

Commit fb6b77f

Browse files
committed
Fix #11: reject quoted timestamps instead of silently parsing as null
1 parent 62184bb commit fb6b77f

5 files changed

Lines changed: 52 additions & 1 deletion

File tree

app/Foliage/Meta.hs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ where
3232

3333
import Control.Applicative ((<|>))
3434
import Control.Monad (void)
35+
import Control.Monad.State (modify)
36+
import Data.HashMap.Strict qualified as HashMap
3537
import Data.List (sortOn)
3638
import Data.Maybe (fromMaybe)
3739
import Data.Ord (Down (Down))
@@ -138,7 +140,7 @@ data PackageVersionSpec = PackageVersionSpec
138140
sourceMetaCodec :: TomlCodec PackageVersionSpec
139141
sourceMetaCodec =
140142
PackageVersionSpec
141-
<$> Toml.dioptional (timeCodec "timestamp")
143+
<$> optionalTimeCodec "timestamp"
142144
.= packageVersionTimestamp
143145
<*> packageSourceCodec
144146
.= packageVersionSource
@@ -200,3 +202,38 @@ withDefault :: (Eq a) => a -> TomlCodec a -> TomlCodec a
200202
withDefault d c = (fromMaybe d <$> Toml.dioptional c) .= f
201203
where
202204
f a = if a == d then Nothing else Just a
205+
206+
{- | Codec for a maybe-missing time value.
207+
208+
Note this is different from dioptional timeCodec. With dioptional timeCodec,
209+
if the user writes
210+
timestamp = '2022-08-22T10:38:45Z'
211+
rather than
212+
timestamp = 2022-08-22T10:38:45Z
213+
the timestamp will parse as Nothing because it won't match the zoneTime
214+
type and it is not an error because it is optional.
215+
216+
We use a handrolled version of match (matchMaybe) to make it work.
217+
218+
See discussions at
219+
1. https://github.com/input-output-hk/foliage/issues/11
220+
2. https://github.com/input-output-hk/foliage/pull/57
221+
3. https://github.com/kowainik/tomland/issues/223
222+
-}
223+
optionalTimeCodec :: Toml.Key -> TomlCodec (Maybe UTCTime)
224+
optionalTimeCodec key =
225+
Toml.dimap (fmap $ utcToZonedTime utc) (fmap zonedTimeToUTC) $ matchMaybe Toml._ZonedTime key
226+
227+
matchMaybe :: forall a. Toml.TomlBiMap a Toml.AnyValue -> Toml.Key -> TomlCodec (Maybe a)
228+
matchMaybe bimap key = Toml.Codec input output
229+
where
230+
input :: Toml.TomlEnv (Maybe a)
231+
input toml = case HashMap.lookup key (Toml.tomlPairs toml) of
232+
Nothing -> pure Nothing
233+
Just anyVal -> pure <$> Toml.whenLeftBiMapError key (Toml.backward bimap anyVal) pure
234+
235+
output :: Maybe a -> Toml.TomlState (Maybe a)
236+
output Nothing = pure Nothing
237+
output (Just a) = do
238+
anyVal <- Toml.eitherToTomlState $ Toml.forward bimap a
239+
Just a <$ modify (Toml.insertKeyAnyVal key anyVal)

foliage.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ executable foliage
5757
ed25519 >=0.0.5.0 && <0.1,
5858
filepath >=1.4.2.1 && <1.6,
5959
hackage-security >=0.6.2.1 && <0.7,
60+
mtl >=2.2 && <2.4,
6061
network-uri >=2.6.4.1 && <2.8,
6162
optparse-applicative >=0.17.0.0 && <0.20,
6263
shake >=0.19.6 && <0.20,
@@ -66,6 +67,7 @@ executable foliage
6667
time >=1.9.3 && <1.16,
6768
time-compat >=1.9.6.1 && <1.10,
6869
tomland >=1.3.3.1 && <1.4,
70+
unordered-containers >=0.2 && <0.3,
6971
vector >=0.13.0.0 && <0.14,
7072
with-utf8 >=1.0.2.3 && <1.2,
7173
zlib >=0.6.2.3 && <0.8,

tests/Tests.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE LambdaCase #-}
22

33
import Codec.Archive.Tar.Entry (GenEntry (entryContent, entryTime), GenEntryContent (NormalFile))
4+
import Control.Exception (SomeException, try)
45
import Data.ByteString.Lazy qualified as BL
56
import Foliage.Tests.Tar
67
import Foliage.Tests.Utils
@@ -68,4 +69,12 @@ main = do
6869

6970
step "Running checks"
7071
doesFileExist "_repo/foliage/packages.json" @? "foliage/packages.json does not exist"
72+
, ---
73+
testCaseSteps "rejects quoted timestamp in meta.toml" $ \step ->
74+
inTemporaryDirectoryWithFixture "tests/fixtures/bad-timestamp" $ do
75+
step "Building repository (expecting failure)"
76+
result <- try @SomeException (callCommand "foliage build --no-signatures")
77+
case result of
78+
Left _ -> pure ()
79+
Right _ -> assertFailure "foliage build should have failed on a quoted timestamp"
7180
]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
url = "file:tarballs/pkg-a-2.3.4.5.tar.gz"
2+
timestamp = '2022-03-29T06:19:50+00:00'
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../simple/tarballs

0 commit comments

Comments
 (0)