summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.json16
-rw-r--r--lib/CheckMap.hs13
-rw-r--r--lib/LintConfig.hs163
-rw-r--r--lib/Properties.hs68
-rw-r--r--lib/Uris.hs90
-rw-r--r--server/Server.hs22
-rw-r--r--server/Worker.hs22
-rw-r--r--src/Main.hs9
-rw-r--r--src/Version.hs2
9 files changed, 222 insertions, 183 deletions
diff --git a/config.json b/config.json
index 1ccb0a5..35e89e9 100644
--- a/config.json
+++ b/config.json
@@ -6,13 +6,13 @@
"MaxLintLevel":"Fatal",
"DontCopyAssets":false,
"UriSchemas": {
- "world": {
- "scope" : ["map"],
- "substs" : {
- }
- },
- "https": {
- "scope" : [ "website", "audio" ]
- }
+ "https:": [
+ {
+ "scope" : [ "website", "audio" ]
+ },
+ {
+ "scope" : [ "script" ],
+ "allowed" : [ "scripts.world.di.c3voc.de" ]
+ }]
}
}
diff --git a/lib/CheckMap.hs b/lib/CheckMap.hs
index 9e3027c..8611f03 100644
--- a/lib/CheckMap.hs
+++ b/lib/CheckMap.hs
@@ -10,6 +10,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE RecordWildCards #-}
-- | Module that contains the high-level checking functions
module CheckMap (loadAndLintMap, MapResult(..), ResultKind(..), Optional,shrinkMapResult) where
@@ -28,7 +29,7 @@ import Badges (Badge)
import Data.Tiled (Layer (layerLayers, layerName),
Tiledmap (tiledmapLayers, tiledmapTilesets),
loadTiledmap)
-import LintConfig (LintConfig (configAssemblyTag), LintConfig')
+import LintConfig (LintConfig', LintConfig (..))
import LintWriter (LintResult, invertLintResult,
resultToAdjusted, resultToBadges,
resultToDeps, resultToLints, resultToOffers,
@@ -111,11 +112,12 @@ loadAndLintMap config path depth = loadTiledmap path <&> \case
-- | lint a loaded map
runLinter :: Bool -> LintConfig' -> Tiledmap -> Int -> MapResult Full
-runLinter isMain config tiledmap depth = MapResult
+runLinter isMain config@LintConfig{..} tiledmap depth = MapResult
{ mapresultLayer = invertThing layer
, mapresultTileset = invertThing tileset
, mapresultGeneral =
- ([Hint Error "main.json should link back to the lobby" | isMain && not (any linksLobby layerDeps)])
+ [Hint Warning "main.json should link back to the lobby"
+ | isMain && not (any linksLobby layerDeps)]
<> lintsToHints (resultToLints generalResult)
, mapresultDepends = resultToDeps generalResult
<> layerDeps
@@ -127,9 +129,10 @@ runLinter isMain config tiledmap depth = MapResult
}
where
linksLobby = \case
- MapLink link -> "/@/rc3_21/lobby" `T.isPrefixOf` link
+ MapLink link ->
+ ("/@/"<>configEventSlug<>"/lobby") `T.isPrefixOf` link
|| configAssemblyTag config == "lobby"
- _ -> False
+ _ -> False
layerDeps = concatMap resultToDeps layer
layer = checkLayerRec config depth (V.toList $ tiledmapLayers tiledmap)
tileset = checkThing tiledmapTilesets checkTileset
diff --git a/lib/LintConfig.hs b/lib/LintConfig.hs
index 11a8122..b0fa3b0 100644
--- a/lib/LintConfig.hs
+++ b/lib/LintConfig.hs
@@ -1,19 +1,21 @@
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Module that deals with handling config options
-module LintConfig (LintConfig(..), LintConfig', patchConfig) where
+module LintConfig (LintConfig(..), LintConfig', ConfigKind (..), patchConfig,stuffConfig,feedConfig) where
import Universum
-import qualified Universum.Unsafe as Unsafe
import Data.Aeson (FromJSON (parseJSON), Options (..),
defaultOptions, eitherDecode)
@@ -28,38 +30,51 @@ import Uris (SchemaSet,
Substitution (DomainSubstitution))
import WithCli.Pure (Argument (argumentType, parseArgument))
-type family HKD f a where
- HKD Identity a = a
- HKD f a = f a
-data LintConfig f = LintConfig
- { configScriptInject :: HKD f (Maybe Text)
+
+data ConfigKind = Complete | Basic | Skeleton | Patch
+
+-- | a field that must be given in configs for both server & standalone linter
+type family ConfigField (f::ConfigKind) a where
+ ConfigField Patch a = Maybe a
+ ConfigField _ a = a
+
+-- | a field that must be given for the standalone linter, but not the server
+-- (usually because the server will infer them from its own config)
+type family StandaloneField (f :: ConfigKind) a where
+ StandaloneField Complete a = a
+ StandaloneField Skeleton a = a
+ StandaloneField _ a = Maybe a
+
+-- | a field specific to a single world / assembly
+type family WorldField (f :: ConfigKind) a where
+ WorldField Complete a = a
+ WorldField _ a = Maybe a
+
+data LintConfig (f :: ConfigKind) = LintConfig
+ { configScriptInject :: ConfigField f (Maybe Text)
-- ^ Link to Script that should be injected
- , configAssemblyTag :: HKD f Text
+ , configAssemblyTag :: WorldField f Text
-- ^ Assembly name (used for jitsiRoomAdminTag)
- , configAssemblies :: HKD f [Text]
+ , configAssemblies :: StandaloneField f [Text]
-- ^ list of all assembly slugs (used to lint e.g. world:// links)
- , configMaxLintLevel :: HKD f Level
+ , configEventSlug :: StandaloneField f Text
+ -- ^ slug of this event (used e.g. to resolve world:// links)
+ , configMaxLintLevel :: ConfigField f Level
-- ^ Maximum warn level allowed before the lint fails
- , configDontCopyAssets :: HKD f Bool
+ , configDontCopyAssets :: ConfigField f Bool
-- ^ Don't copy map assets (mostly useful for development)
- , configAllowScripts :: HKD f Bool
+ , configAllowScripts :: ConfigField f Bool
-- ^ Allow defining custom scripts in maps
- , configUriSchemas :: HKD f SchemaSet
+ , configUriSchemas :: ConfigField f SchemaSet
} deriving (Generic)
-type LintConfig' = LintConfig Identity
+type LintConfig' = LintConfig Complete
--- TODO: should probably find a way to write these constraints nicer ...
-deriving instance
- ( Show (HKD a (Maybe Text))
- , Show (HKD a Text)
- , Show (HKD a Level)
- , Show (HKD a [Text])
- , Show (HKD a Bool)
- , Show (HKD a SchemaSet)
- )
- => Show (LintConfig a)
+deriving instance Show (LintConfig Complete)
+deriving instance Show (LintConfig Skeleton)
+deriving instance Show (LintConfig Patch)
+instance NFData (LintConfig Basic)
aesonOptions :: Options
aesonOptions = defaultOptions
@@ -68,23 +83,13 @@ aesonOptions = defaultOptions
, fieldLabelModifier = drop 6
}
-instance
- ( FromJSON (HKD a (Maybe Text))
- , FromJSON (HKD a [Text])
- , FromJSON (HKD a Text)
- , FromJSON (HKD a Level)
- , FromJSON (HKD a Bool)
- , FromJSON (HKD a SchemaSet)
- )
- => FromJSON (LintConfig a)
- where
- parseJSON = genericParseJSON aesonOptions
+instance FromJSON (LintConfig Complete) where
+ parseJSON = genericParseJSON aesonOptions
--- need to define this one extra, since Aeson will not make
--- Maybe fields optional if the type isn't given explicitly.
---
--- Whoever said instances had confusing semantics?
-instance {-# Overlapping #-} FromJSON (LintConfig Maybe) where
+instance FromJSON (LintConfig Patch) where
+ parseJSON = genericParseJSON aesonOptions
+
+instance FromJSON (LintConfig Basic) where
parseJSON = genericParseJSON aesonOptions
@@ -118,30 +123,66 @@ instance GPatch i o
-- abstract, I just wanted to play around with higher kinded types for
-- a bit.
patch ::
- ( Generic (f Maybe)
- , Generic (f Identity)
- , GPatch (Rep (f Identity))
- (Rep (f Maybe))
+ ( Generic (f Patch)
+ , Generic (f Complete)
+ , GPatch (Rep (f Complete))
+ (Rep (f Patch))
)
- => f Identity
- -> f Maybe
- -> f Identity
+ => f Complete
+ -> f Patch
+ -> f Complete
patch x y = to (gappend (from x) (from y))
-patchConfig :: LintConfig Identity -> Maybe (LintConfig Maybe) -> LintConfig Identity
-patchConfig config p = config'
- { configUriSchemas = ("world", assemblysubsts) : configUriSchemas config'}
- where config' = case p of
- Just p -> patch config p
- Nothing -> config
- assemblysubsts =
- DomainSubstitution (M.fromList generated) scope
- where generated = (\slug -> (slug, "/@/rc3_21/"<>slug)) <$> configAssemblies config'
- scope = (\(DomainSubstitution _ s) -> s)
- . snd . Unsafe.head
- . filter ((==) "world" . fst)
- $ configUriSchemas config'
-
+patchConfig
+ :: LintConfig Complete
+ -> Maybe (LintConfig Patch)
+ -> LintConfig Complete
+patchConfig config p = expandWorlds config'
+ where
+ config' = case p of
+ Just p -> patch config p
+ Nothing -> config
+
+
+-- | feed a basic server config
+feedConfig
+ :: LintConfig Basic
+ -> [Text]
+ -> Text
+ -> LintConfig Skeleton
+feedConfig LintConfig{..} worlds eventslug = expandWorlds $
+ LintConfig
+ { configAssemblies = worlds
+ , configEventSlug = eventslug
+ , .. }
+
+-- | stuff a
+stuffConfig :: LintConfig Skeleton -> Text -> LintConfig Complete
+stuffConfig LintConfig{..} assemblyslug =
+ LintConfig
+ { configAssemblyTag = assemblyslug
+ , ..}
+
+class HasWorldList (a :: ConfigKind)
+instance HasWorldList 'Complete
+instance HasWorldList 'Skeleton
+
+-- kinda sad that ghc can't solve these contraints automatically,
+-- though i guess it also makes sense …
+expandWorlds
+ :: ( ConfigField a SchemaSet ~ SchemaSet
+ , StandaloneField a [Text] ~ [Text]
+ , StandaloneField a Text ~ Text
+ , HasWorldList a)
+ => LintConfig a -> LintConfig a
+expandWorlds config = config { configUriSchemas = configUriSchemas' }
+ where
+ configUriSchemas' =
+ M.insert "world:" [assemblysubsts] (configUriSchemas config)
+ assemblysubsts =
+ DomainSubstitution (M.fromList generated) ["map"]
+ where generated = configAssemblies config
+ <&> \slug -> (slug, "/@/"<>configEventSlug config<>"/"<>slug)
instance (FromJSON (LintConfig a)) => Argument (LintConfig a) where
parseArgument str =
diff --git a/lib/Properties.hs b/lib/Properties.hs
index 63cea1f..b937534 100644
--- a/lib/Properties.hs
+++ b/lib/Properties.hs
@@ -15,7 +15,7 @@ module Properties (checkMap, checkTileset, checkLayer) where
import Universum hiding (intercalate, isPrefixOf)
-import Data.Text (intercalate, isInfixOf, isPrefixOf)
+import Data.Text (intercalate, isPrefixOf)
import qualified Data.Text as T
import Data.Tiled (Layer (..), Object (..), Property (..),
PropertyValue (..), Tile (..),
@@ -42,8 +42,7 @@ import LintWriter (LintWriter, adjust, askContext,
import Paths (PathResult (..), RelPath (..),
getExtension, isOldStyle, parsePath)
import Types (Dep (Link, Local, LocalMap, MapLink))
-import Uris (SubstError (..), applySubsts,
- extractDomain, parseUri)
+import Uris (SubstError (..), applySubsts)
@@ -140,12 +139,9 @@ checkMapProperty p@(Property name _) = case name of
-- "canonical" form, but allowing that here so that multiple
-- scripts can be used by one map
_ | T.toLower name == "script" ->
- unwrapString p $ \str ->
- unless (checkIsRc3Url str &&
- not ( "/../" `isInfixOf` str) &&
- not ( "%" `isInfixOf` str) &&
- not ( "@" `isInfixOf` str))
- $ forbid "only scripts hosted on static.rc3.world are allowed."
+ unwrapURI (Proxy @"script") p
+ (dependsOn . Link)
+ (const $ forbid "scripts loaded from local files are disallowed")
| name `elem` ["jitsiRoom", "playAudio", "openWebsite"
, "url", "exitUrl", "silent", "getBadge"]
-> complain $ "property " <> name
@@ -342,11 +338,6 @@ checkObjectGroupProperty (Property name _) = case name of
\not the object layer."
_ -> warn $ "unknown property " <> prettyprint name <> " for objectgroup layers"
-checkIsRc3Url :: Text -> Bool
-checkIsRc3Url text= case extractDomain text of
- Nothing -> False
- Just domain -> do
- domain == "https://static.rc3.world"
-- | Checks a single (custom) property of a "normal" tile layer
@@ -405,7 +396,8 @@ checkTileThing removeExits p@(Property name _value) = case name of
unwrapURI (Proxy @"map") p
(\link -> do
assemblyslug <- lintConfig configAssemblyTag
- case T.stripPrefix ("/@/rc3_21/"<>assemblyslug<>"/") link of
+ eventslug <- lintConfig configEventSlug
+ case T.stripPrefix ("/@/"<>eventslug<>"/"<>assemblyslug<>"/") link of
Nothing -> do
dependsOn (MapLink link)
setProperty "exitUrl" link
@@ -424,8 +416,8 @@ checkTileThing removeExits p@(Property name _value) = case name of
let ext = getExtension path in
if | isOldStyle path ->
complain "Old-Style inter-repository links (using {<placeholder>}) \
- \cannot be used at rC3 2021; please use world:// instead \
- \(see howto.rc3.world)."
+ \cannot be used at divoc bb3; please use world:// instead \
+ \(see https://di.c3voc.de/howto:world)."
| ext == "tmx" ->
complain "Cannot use .tmx map format; use Tiled's json export instead."
| ext /= "json" ->
@@ -471,22 +463,21 @@ checkTileThing removeExits p@(Property name _value) = case name of
, "jitsiroomadmintag", "jitsiinterfaceconfig"
, "openwebsitepolicy", "allowapi" ]
-> forbidProperty name
- -- the openWebsite Api can only be allowed if the website is on static.rc3.world
- | T.toLower name == "openwebsiteallowapi"
- -> do
- properties <- askContext <&> getProperties
- unless (all (\(Property name value) -> case value of
- StrProp str -> name /= "openWebsite" || checkIsRc3Url str
- _ -> True
- ) properties)
- $ complain "\"openWebsiteAllowApi\" can only be used with websites hosted \
- \on https://static.rc3.world"
| name `elem` [ "openWebsite", "openTab" ] -> do
uselessEmptyLayer
- suggestProperty $ Property "openWebsiteTrigger" (StrProp "onaction")
- unwrapURI (Proxy @"website") p
- (dependsOn . Link)
- (const $ forbid "accessing local html files is disallowed.")
+ suggestProperty $ Property "openWebsiteTrigger" "onaction"
+
+ properties <- askContext <&> getProperties
+ let isScript = any (\(Property name _) ->
+ T.toLower name == "openwebsiteallowapi")
+ properties
+ if isScript
+ then unwrapURI (Proxy @"script") p
+ (dependsOn . Link)
+ (const $ forbid "accessing local html files is disallowed")
+ else unwrapURI (Proxy @"website") p
+ (dependsOn . Link)
+ (const $ forbid "accessing local html files is disallowed.")
| otherwise ->
when (not removeExits || name `notElem` [ "collides", "name", "tilesetCopyright" ]) $ do
warnUnknown p knownTileLayerProperites
@@ -634,11 +625,6 @@ setProperty name value = adjust $ \ctxt ->
$ \ps -> Just $ Property name (asProperty value) : filter sameName ps
where sameName (Property name' _) = name /= name'
-removeProperty :: HasProperties ctxt => Text -> LintWriter ctxt
-removeProperty name = adjust $ \ctxt ->
- flip adjustProperties ctxt
- $ \ps -> Just $ filter (\(Property name' _) -> name' /= name) ps
-
naiveEscapeProperty :: HasProperties a => Property -> LintWriter a
naiveEscapeProperty prop@(Property name _) =
unwrapString prop (setProperty name . naiveEscapeHTML)
@@ -691,7 +677,9 @@ unwrapBadgeToken str f = case parseToken str of
Nothing -> complain "invalid badge token."
--- | unwraps a URI
+-- | unwraps a link, giving two cases:
+-- - the link might be an (allowed) remote URI
+-- - the link might be relative to this map (i.e. just a filepath)
unwrapURI :: (KnownSymbol s, HasProperties a)
=> Proxy s
-> Property
@@ -715,12 +703,12 @@ unwrapURI sym p@(Property name _) f g = unwrapString p $ \link -> do
DomainDoesNotExist domain -> "The domain " <> domain <> " does not exist; \
\please make sure it is spelled correctly."
SchemaDoesNotExist schema ->
- "the URI schema " <> schema <> ":// cannot be used."
+ "the URI schema " <> schema <> "// cannot be used."
WrongScope schema allowed ->
- "the URI schema " <> schema <> ":// cannot be used in property \
+ "the URI schema " <> schema <> "// cannot be used in property \
\\"" <> name <> "\"; allowed "
<> (if length allowed == 1 then "is " else "are ")
- <> intercalate ", " (fmap (<> "://") allowed) <> "."
+ <> intercalate ", " (map (<> "//") allowed) <> "."
VarsDisallowed -> "extended API links are disallowed in links"
diff --git a/lib/Uris.hs b/lib/Uris.hs
index 596c272..40ea43e 100644
--- a/lib/Uris.hs
+++ b/lib/Uris.hs
@@ -1,9 +1,10 @@
-{-# LANGUAGE DataKinds #-}
-{-# LANGUAGE DeriveAnyClass #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE LambdaCase #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE DataKinds #-}
+{-# LANGUAGE DeriveAnyClass #-}
+{-# LANGUAGE DeriveGeneric #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TypeApplications #-}
-- | Functions to deal with uris and custom uri schemes
module Uris where
@@ -16,7 +17,8 @@ import Data.Aeson (FromJSON (..), Options (..),
import qualified Data.Map.Strict as M
import qualified Data.Text as T
import GHC.TypeLits (KnownSymbol, symbolVal)
-import Network.URI (URI (..), URIAuth (..), parseURI)
+import Network.URI (URI (..), URIAuth (..), parseURI,
+ uriToString)
import qualified Network.URI.Encode as URI
data Substitution =
@@ -24,7 +26,7 @@ data Substitution =
| DomainSubstitution { substs :: Map Text Text, scope :: [String] }
| Allowed { scope :: [String], allowed :: [Text] }
| Unrestricted { scope :: [String] }
- deriving (Generic, Show)
+ deriving (Generic, Show, NFData)
instance FromJSON Substitution where
@@ -33,30 +35,23 @@ instance FromJSON Substitution where
, rejectUnknownFields = True
}
-type SchemaSet = Map Text Substitution
+type SchemaSet = Map Text [Substitution]
-extractDomain :: Text -> Maybe Text
-extractDomain url =
- case parseUri url of
- Nothing -> Nothing
- Just (_,domain,_) -> Just domain
-
-
-
-
-parseUri :: Text -> Maybe (Text, Text, Text)
-parseUri uri =
- case parseURI (toString uri) of
+-- | deconstruct a URI into a triple of [schema:]//[domain]/[tail...],
+-- and a normalised version of the same URI
+parseUri :: Text -> Maybe (Text, Text, Text, Text)
+parseUri raw =
+ case parseURI (toString raw) of
Nothing -> Nothing
- Just parsedUri -> case uriAuthority parsedUri of
+ Just uri@URI{..} -> case uriAuthority of
Nothing -> Nothing
- -- https:
- Just uriAuth -> Just (T.replace (fromString ":") (fromString "") (fromString (uriScheme parsedUri )),
- -- //anonymous@ www.haskell.org :42
- fromString(uriUserInfo uriAuth++uriRegName uriAuth ++ uriPort uriAuth),
- -- /ghc ?query #frag
- fromString(uriPath parsedUri ++ uriQuery parsedUri ++ uriFragment parsedUri))
+ Just URIAuth {..} -> Just
+ ( fromString uriScheme
+ , fromString $ uriUserInfo <> uriRegName <> uriPort
+ , fromString $ uriPath <> uriQuery <> uriFragment
+ , fromString $ uriToString id uri ""
+ )
data SubstError =
@@ -66,41 +61,46 @@ data SubstError =
| IsBlocked
| DomainIsBlocked [Text]
| VarsDisallowed
+ | WrongScope Text [Text]
-- ^ This link's schema exists, but cannot be used in this scope.
-- The second field contains a list of schemas that may be used instead.
- | WrongScope Text [Text]
deriving (Eq, Ord) -- errors are ordered so we can show more specific ones
applySubsts :: KnownSymbol s
=> Proxy s -> SchemaSet -> Text -> Either SubstError Text
applySubsts s substs uri = do
- when (T.isInfixOf (toText "{{") uri || T.isInfixOf (toText "}}") uri)
+ when (T.isInfixOf "{{" uri || T.isInfixOf "}}" uri)
$ Left VarsDisallowed
- parts@(schema, _, _) <- note NotALink $ parseUri uri
+ parts@(schema, _, _, _) <- maybeToRight NotALink $ parseUri uri
- let rule = M.lookup schema substs
+ let rules = filter (elem thisScope . scope) . concat $ M.lookup schema substs
- case map (applySubst parts) rule of
- Nothing -> Left (SchemaDoesNotExist schema)
- Just result -> result
+ case nonEmpty $ map (applySubst parts) rules of
+ Nothing -> Left (SchemaDoesNotExist schema)
+ Just result -> minimum result
where
- note = maybeToRight
- applySubst (schema, domain, rest) rule = do
+ thisScope = symbolVal s
+ applySubst (schema, domain, rest, uri) rule = do
+
+ -- is this scope applicable?
unless (symbolVal s `elem` scope rule)
$ Left (WrongScope schema
- (map fst . filter (elem (symbolVal s) . scope . snd) $ toPairs substs))
+ $ map fst -- make list of available uri schemes
+ . filter (any (elem thisScope . scope) . snd)
+ $ toPairs substs)
+
case rule of
DomainSubstitution table _ -> do
- prefix <- note (DomainDoesNotExist (schema <> toText "://" <> domain))
- $ M.lookup domain table
+ prefix <- case M.lookup domain table of
+ Nothing -> Left (DomainDoesNotExist (schema <> "//" <> domain))
+ Just a -> Right a
pure (prefix <> rest)
Prefixed {..}
| domain `elem` blocked -> Left IsBlocked
- | domain `elem` allowed || toText "streamproxy.rc3.world" `T.isSuffixOf` domain -> Right uri
+ | domain `elem` allowed -> Right uri
| otherwise -> Right (prefix <> URI.encodeText uri)
- Allowed _ domains -> if domain `elem` domains
- || toText "streamproxy.rc3.world" `T.isSuffixOf` domain
- then Right uri
- else Left (DomainIsBlocked domains)
+ Allowed _ allowlist
+ | domain `elem` allowlist -> Right uri
+ | otherwise -> Left (DomainIsBlocked allowlist)
Unrestricted _ -> Right uri
diff --git a/server/Server.hs b/server/Server.hs
index 779509d..da2e73d 100644
--- a/server/Server.hs
+++ b/server/Server.hs
@@ -47,7 +47,8 @@ import Data.Either.Extra (mapLeft)
import Data.Functor.Contravariant (contramap)
import qualified Data.Map.Strict as M
import Lens.Micro.Platform (at, ix, makeLenses, traverseOf)
-import LintConfig (LintConfig')
+import LintConfig (ConfigKind (..), LintConfig,
+ feedConfig)
import Servant (FromHttpApiData)
import Servant.Client (BaseUrl, parseBaseUrl)
import qualified Text.Show as TS
@@ -89,7 +90,7 @@ toSha ref = Sha1
data Org (loaded :: Bool) = Org
{ orgSlug :: Text
- , orgLintconfig :: ConfigRes loaded LintConfig'
+ , orgLintconfig :: ConfigRes loaded (LintConfig Skeleton)
, orgEntrypoint :: FilePath
, orgGeneration :: Int
, orgRepos :: [RemoteRef]
@@ -97,7 +98,8 @@ data Org (loaded :: Bool) = Org
, orgWebdir :: Text
} deriving (Generic)
-instance NFData LintConfig' => NFData (Org True)
+instance NFData (LintConfig Skeleton) => NFData (Org True)
+deriving instance Show (LintConfig Skeleton) => Show (Org True)
-- | Orgs are compared via their slugs only
-- TODO: the server should probably refuse to start if two orgs have the
@@ -176,11 +178,15 @@ loadConfig path = do
Left err -> error $ prettyTomlDecodeErrors err
where
loadOrg :: Org False -> IO (Org True)
- loadOrg org = do
- lintconfig <- eitherDecodeFileStrict' (orgLintconfig org) >>= \case
- Right c -> pure c
- Left err -> error $ show err
- pure $ org { orgLintconfig = lintconfig }
+ loadOrg org@Org{..} = do
+ lintconfig <-
+ eitherDecodeFileStrict' orgLintconfig >>= \case
+ Right (c :: LintConfig Basic) -> pure c
+ Left err -> error $ show err
+ let config = org { orgLintconfig =
+ feedConfig lintconfig (map reponame orgRepos) orgSlug }
+ print config
+ pure config
data RealtimeMsg = RelintPending | Reload
deriving (Generic, ToJSON)
diff --git a/server/Worker.hs b/server/Worker.hs
index 8b3903c..a5fab58 100644
--- a/server/Worker.hs
+++ b/server/Worker.hs
@@ -22,12 +22,12 @@ import qualified Data.Text as T
import qualified Data.UUID as UUID
import qualified Data.UUID.V4 as UUID
import Fmt ((+|), (|+))
+import LintConfig (stuffConfig)
import Server (Config, JobStatus (..),
Org (..),
RealtimeMsg (RelintPending, Reload),
- RemoteRef (reporef, repourl),
- ServerState, adjustedPath,
- getJobStatus,
+ RemoteRef (..), ServerState,
+ adjustedPath, getJobStatus,
newRealtimeChannel,
setJobStatus, tmpdir, toSha)
import System.Directory (doesDirectoryExist)
@@ -63,6 +63,7 @@ runJob config Job {..} done = do
handle whoops
$ finally (lint workdir) (cleanup workdir)
where
+ lintConfig = stuffConfig (orgLintconfig jobOrg) (reponame jobRef)
lint workdir = do
maybeRealtime <- getJobStatus done (orgSlug jobOrg) (toSha jobRef) >>= \case
Nothing -> pure Nothing
@@ -80,9 +81,9 @@ runJob config Job {..} done = do
-- TODO: these calls fail for dumb http, add some fallback!
(callgit gitdir
[ "fetch", "origin", toString ref, "--depth", "1" ])
- (callgit gitdir
- [ "clone", toString ref, "--bare"
- , "--depth", "1", "-b", toString ref])
+ (callProcess "git"
+ [ "clone", toString url, "--bare"
+ , "--depth", "1", "-b", toString ref, gitdir])
rev <- map T.strip -- git returns a newline here
$ readgit' gitdir ["rev-parse", toString ref]
@@ -90,10 +91,10 @@ runJob config Job {..} done = do
callgit gitdir [ "worktree", "add", "--force", workdir, toString ref ]
- res <- recursiveCheckDir (orgLintconfig jobOrg) workdir (orgEntrypoint jobOrg)
+ res <- recursiveCheckDir lintConfig workdir (orgEntrypoint jobOrg)
>>= evaluateNF
- writeAdjustedRepository (orgLintconfig jobOrg) workdir (toString outPath) res
+ writeAdjustedRepository lintConfig workdir (toString outPath) res
>>= runStdoutLoggingT . \case
ExitSuccess ->
logInfoN $ "linted map "+| (show jobRef :: Text) |+"."
@@ -126,7 +127,6 @@ runJob config Job {..} done = do
url = repourl jobRef
ref = reporef jobRef
- callgit = callgit'
gitdir = view tmpdir config </> toString hashedname
hashedname = T.map escapeSlash url
where escapeSlash = \case { '/' -> '-'; a -> a }
@@ -137,8 +137,8 @@ readgit' dir args = map toText $
print args
readProcess "git" ([ "-C", toString dir ] <> args) ""
-callgit' :: MonadIO m => FilePath -> [String] -> m ()
-callgit' dir args =
+callgit :: MonadIO m => FilePath -> [String] -> m ()
+callgit dir args =
liftIO $ do
print args
callProcess "git" ([ "-C", toString dir ] <> args)
diff --git a/src/Main.hs b/src/Main.hs
index b2002bf..9628e1e 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE LambdaCase #-}
@@ -15,9 +16,9 @@ import Data.Aeson.Encode.Pretty (encodePretty)
import Data.Aeson.KeyMap (coercionToHashMap)
import WithCli (HasArguments, withCli)
-import CheckDir (recursiveCheckDir, resultIsFatal, DirResult (dirresultGraph))
-import Control.Monad (when)
-import LintConfig (LintConfig (..), patchConfig)
+import CheckDir (recursiveCheckDir, resultIsFatal)
+import LintConfig (ConfigKind (..), LintConfig (..),
+ patchConfig)
import System.Exit (ExitCode (ExitFailure))
import Types (Level (..))
import Util (printPretty)
@@ -40,7 +41,7 @@ data Options = Options
-- ^ path to write the (possibly adjusted) maps to after linting
, configFile :: Maybe FilePath
-- ^ path to a config file. Currently required.
- , config :: Maybe (LintConfig Maybe)
+ , config :: Maybe (LintConfig Patch)
-- ^ a "patch" for the configuration file
, version :: Bool
, dot :: Bool
diff --git a/src/Version.hs b/src/Version.hs
index 2ec1537..e62c9b8 100644
--- a/src/Version.hs
+++ b/src/Version.hs
@@ -9,7 +9,7 @@ import qualified Language.Haskell.TH as TH
import System.Process (readProcess)
version :: String
-version = "walint rc3 2021 (" <>
+version = "walint divoc bb3 2022 (" <>
$(do
hash <- liftIO $ catchAny (readProcess "git" ["rev-parse", "HEAD"] "")
(\_ -> pure "[unknown]")