<commit_before>module JSMESS ( admin
              , staffOwned
              , swapFile
              , DataSize ) where

import Propellor
import System.Directory
import System.Posix.Files
import Utility.FileMode
import qualified Utility.DataUnits as DataUnits
import qualified Propellor.Property.File as File
import qualified Propellor.Property.Ssh as Ssh
import qualified Propellor.Property.User as User
import qualified Propellor.Property.Sudo as Sudo
import qualified Propellor.Property.Fstab as Fstab

foldi            :: (a -> a -> a) -> a -> [a] -> a
foldi f z []     = z
foldi f z (x:xs) = f x (foldi f z (pairs f xs))

pairs            :: (a -> a -> a) -> [a] -> [a]
pairs f (x:y:t)  = f x y : pairs f t
pairs f t        = t

admin :: User -> [Ssh.PubKeyText] -> Property DebianLike
admin u@(User n) ks = propertyList ("admin user " ++ n) $ props
    & User.accountFor u
    & User.hasGroup u (Group "staff")
    & Sudo.enabledFor u
    & foldi (before) (RevertableProperty doNothing doNothing) (map (Ssh.authorizedKey u) ks)
    & foldi (before) (RevertableProperty doNothing doNothing) (map (Ssh.authorizedKey (User "root")) ks)

staffOwned :: FilePath -> Property UnixLike
staffOwned path = propertyList ("path "++ path ++" is owned by staff") $ props
    & File.dirExists path
    & File.ownerGroup path (User "root") (Group "staff")
    & File.mode path (combineModes (readModes ++ executeModes ++
                                    [ ownerWriteMode
                                    , groupWriteMode
                                    , setGroupIDMode
                                    ]))

-- | A string that will be parsed to get a data size.
--
-- Examples: "100 megabytes" or "0.5tb"
type DataSize = String

swapFile :: FilePath -> DataSize -> Property Linux
swapFile path size = propertyList ("has a swap file at "++ path) $ props
    & check (not <$> doesFileExist path)
        (propSize size
          (\bytes -> combineProperties ("create swap file at "++ path) $ props
                       & cmdProperty "fallocate" [ "-l", (show bytes)
                                                 , path ] `assume` MadeChange
                       & cmdProperty "mkswap" [ path ] `assume` MadeChange))
    & Fstab.mounted "swap" path "swap" mempty
      `onChange` (cmdProperty "swapon" [ path ] `assume` MadeChange)
  where propSize :: DataSize -> (Integer -> Property UnixLike) -> Property UnixLike
        propSize sz f = case DataUnits.readSize DataUnits.memoryUnits sz of<commit_msg>propellor spin<commit_after>module JSMESS ( admin
              , staffOwned
              , swapFile
              , DataSize ) where

import Propellor
import System.Directory
import System.Posix.Files
import Utility.FileMode
import qualified Utility.DataUnits as DataUnits
import qualified Propellor.Property.File as File
import qualified Propellor.Property.Ssh as Ssh
import qualified Propellor.Property.User as User
import qualified Propellor.Property.Sudo as Sudo
import qualified Propellor.Property.Fstab as Fstab

foldi            :: (a -> a -> a) -> a -> [a] -> a
foldi f z []     = z
foldi f z (x:xs) = f x (foldi f z (pairs f xs))

pairs            :: (a -> a -> a) -> [a] -> [a]
pairs f (x:y:t)  = f x y : pairs f t
pairs f t        = t

admin :: User -> [Ssh.PubKeyText] -> Property DebianLike
admin u@(User n) ks = propertyList ("admin user " ++ n) $ props
    & User.accountFor u
    & User.hasGroup u (Group "staff")
    & Sudo.enabledFor u
    & foldi (before) (RevertableProperty doNothing doNothing) (map (Ssh.authorizedKey u) ks)
    & foldi (before) (RevertableProperty doNothing doNothing) (map (Ssh.authorizedKey (User "root")) ks)

staffOwned :: FilePath -> Property UnixLike
staffOwned path = propertyList ("path "++ path ++" is owned by staff") $ props
    & File.dirExists path
    & File.ownerGroup path (User "root") (Group "staff")
    & File.mode path (combineModes (readModes ++ executeModes ++
                                    [ ownerWriteMode
                                    , groupWriteMode
                                    , setGroupIDMode
                                    ]))

-- | A string that will be parsed to get a data size.
--
-- Examples: "100 megabytes" or "0.5tb"
type DataSize = String

swapFile :: FilePath -> DataSize -> Property Linux
swapFile path size = propertyList ("has a swap file at "++ path) $ props
    & check (not <$> doesFileExist path)
        (propSize size
          (\bytes -> combineProperties ("create swap file at "++ path) $ props
                       & cmdProperty "fallocate" [ "-l", (show bytes)
                                                 , path ] `assume` MadeChange
                       & cmdProperty "mkswap" [ path ] `assume` MadeChange
                       & File.mode path (combineModes [ ownerReadMode, ownerWriteMode ])))
    & Fstab.mounted "swap" path "swap" mempty
      `onChange` (cmdProperty "swapon" [ path ] `assume` MadeChange)
  where propSize :: DataSize -> (Integer -> Property UnixLike) -> Property UnixLike
        propSize sz f = case DataUnits.readSize DataUnits.memoryUnits sz of
{'fraction_non_alphanumeric': 0.10617911615174032, 'fraction_numerical': 0.0019554165037152915, 'mean_word_length': 2.2210327455919394, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5636502', 'n_tokens_mistral': 1498, 'n_tokens_neox': 1472, 'n_words': 499}