Skip to content

Commit efd084d

Browse files
committed
Print warning on group permissions check for VRF instead of failing to start the node.
1 parent c75741e commit efd084d

File tree

7 files changed

+73
-67
lines changed

7 files changed

+73
-67
lines changed

cardano-node/cardano-node.cabal

+2
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ test-suite cardano-node-test
265265
, cardano-protocol-tpraos
266266
, cardano-node
267267
, cardano-slotting
268+
, contra-tracer
268269
, directory
269270
, filepath
270271
, hedgehog
@@ -279,6 +280,7 @@ test-suite cardano-node-test
279280
, ouroboros-network-api
280281
, strict-sop-core
281282
, text
283+
, trace-dispatcher
282284
, transformers
283285
, vector
284286
, yaml

cardano-node/src/Cardano/Node/Configuration/POM.hs

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,14 @@ import Ouroboros.Consensus.Node (NodeDatabasePaths (..))
4545
import qualified Ouroboros.Consensus.Node as Consensus (NetworkP2PMode (..))
4646
import Ouroboros.Consensus.Node.Genesis (GenesisConfig, GenesisConfigFlags,
4747
defaultGenesisConfigFlags, mkGenesisConfig)
48-
import qualified Ouroboros.Network.Diffusion.Configuration as Ouroboros
49-
import Ouroboros.Network.Mux (ForkPolicy, noBindForkPolicy, responderForkPolicy)
50-
import qualified Ouroboros.Network.PeerSelection.Governor as PeerSelection
5148
import Ouroboros.Consensus.Storage.LedgerDB.Args (QueryBatchSize (..))
5249
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots (NumOfDiskSnapshots (..),
5350
SnapshotInterval (..))
5451
import Ouroboros.Consensus.Storage.LedgerDB.V1.Args (FlushFrequency (..))
5552
import Ouroboros.Network.Diffusion.Configuration as Configuration
53+
import qualified Ouroboros.Network.Diffusion.Configuration as Ouroboros
54+
import Ouroboros.Network.Mux (ForkPolicy, noBindForkPolicy, responderForkPolicy)
55+
import qualified Ouroboros.Network.PeerSelection.Governor as PeerSelection
5656

5757
import Control.Concurrent (getNumCapabilities)
5858
import Control.Monad (unless, void, when)

cardano-node/src/Cardano/Node/Run.hs

+33-45
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ module Cardano.Node.Run
2323
) where
2424

2525
import Cardano.Api (File (..), FileDirection (..))
26+
import Cardano.Api.Internal.Error (displayError)
2627
import qualified Cardano.Api as Api
2728
import System.Random (randomIO)
2829

@@ -58,7 +59,7 @@ import Cardano.Node.Tracing.StateRep (NodeState (NodeKernelOnline))
5859
import Cardano.Node.Tracing.Tracers.NodeVersion (getNodeVersion)
5960
import Cardano.Node.Tracing.Tracers.Startup (getStartupInfo)
6061
import Cardano.Node.Types
61-
import Cardano.Prelude (FatalError (..), bool, (:~:) (..))
62+
import Cardano.Prelude (FatalError (..), bool, (:~:) (..), stderr, )
6263
import Cardano.Tracing.Config (TraceOptions (..), TraceSelection (..))
6364
import Cardano.Tracing.Tracers
6465

@@ -123,7 +124,7 @@ import Ouroboros.Network.Subscription (DnsSubscriptionTarget (..),
123124

124125
import Control.Concurrent (killThread, mkWeakThreadId, myThreadId, getNumCapabilities)
125126
import Control.Concurrent.Class.MonadSTM.Strict
126-
import Control.Exception (try, IOException)
127+
import Control.Exception (try, Exception, IOException)
127128
import qualified Control.Exception as Exception
128129
import Control.Monad (forM, forM_, unless, void, when)
129130
import Control.Monad.Class.MonadThrow (MonadThrow (..))
@@ -153,6 +154,7 @@ import Network.HostName (getHostName)
153154
import Network.Socket (Socket)
154155
import System.Directory (canonicalizePath, createDirectoryIfMissing, makeAbsolute)
155156
import System.Environment (lookupEnv)
157+
import System.IO (hPutStrLn)
156158
#ifdef UNIX
157159
import GHC.Weak (deRefWeak)
158160
import System.Posix.Files
@@ -185,34 +187,24 @@ runNode cmdPc = do
185187

186188
putStrLn $ "Node configuration: " <> show nc
187189

188-
case shelleyVRFFile $ ncProtocolFiles nc of
189-
Just vrfFp -> do vrf <- runExceptT $ checkVRFFilePermissions (File vrfFp)
190-
case vrf of
191-
Left err -> Exception.throwIO err
192-
Right () ->
193-
pure ()
194-
Nothing -> pure ()
195-
196-
eitherSomeProtocol <- runExceptT $ mkConsensusProtocol
197-
(ncProtocolConfig nc)
198-
-- TODO: Convert ncProtocolFiles to Maybe as relay nodes
199-
-- don't need these.
200-
(Just $ ncProtocolFiles nc)
201-
202-
p :: SomeConsensusProtocol <-
203-
case eitherSomeProtocol of
204-
Left err -> Exception.throwIO err
205-
Right p -> pure p
206-
207-
let networkMagic :: Api.NetworkMagic =
208-
case p of
209-
SomeConsensusProtocol _ runP ->
210-
let ProtocolInfo { pInfoConfig } = fst $ Api.protocolInfo @IO runP
211-
in getNetworkMagic $ Consensus.configBlock pInfoConfig
212-
213-
case p of
214-
SomeConsensusProtocol blockType runP ->
215-
handleNodeWithTracers cmdPc nc p networkMagic blockType runP
190+
case ncProtocolFiles nc of
191+
ProtocolFilepaths{shelleyVRFFile=Just vrfFp} ->
192+
runThrowExceptT $
193+
checkVRFFilePermissions stdoutTracer (File vrfFp)
194+
_ -> pure ()
195+
196+
consensusProtocol <-
197+
runThrowExceptT $
198+
mkConsensusProtocol
199+
(ncProtocolConfig nc)
200+
-- TODO: Convert ncProtocolFiles to Maybe as relay nodes
201+
-- don't need these.
202+
(Just $ ncProtocolFiles nc)
203+
204+
handleNodeWithTracers cmdPc nc consensusProtocol
205+
206+
runThrowExceptT :: Exception e => ExceptT e IO a -> IO a
207+
runThrowExceptT act = runExceptT act >>= either Exception.throwIO pure
216208

217209
-- | Workaround to ensure that the main thread throws an async exception on
218210
-- receiving a SIGTERM signal.
@@ -233,17 +225,13 @@ installSigTermHandler = do
233225
return ()
234226

235227
handleNodeWithTracers
236-
:: ( TraceConstraints blk
237-
, Api.Protocol IO blk
238-
)
239-
=> PartialNodeConfiguration
228+
:: PartialNodeConfiguration
240229
-> NodeConfiguration
241230
-> SomeConsensusProtocol
242-
-> Api.NetworkMagic
243-
-> Api.BlockType blk
244-
-> Api.ProtocolInfoArgs blk
245231
-> IO ()
246-
handleNodeWithTracers cmdPc nc0 p networkMagic blockType runP = do
232+
handleNodeWithTracers cmdPc nc0 p@(SomeConsensusProtocol blockType runP) = do
233+
let ProtocolInfo{pInfoConfig} = fst $ Api.protocolInfo @IO runP
234+
networkMagic :: Api.NetworkMagic = getNetworkMagic $ Consensus.configBlock pInfoConfig
247235
-- This IORef contains node kernel structure which holds node kernel.
248236
-- Used for ledger queries and peer connection status.
249237
nodeKernelData <- mkNodeKernelData
@@ -913,17 +901,17 @@ canonDbPath NodeConfiguration{ncDatabaseFile = nodeDatabaseFps} =
913901

914902
-- | Make sure the VRF private key file is readable only
915903
-- by the current process owner the node is running under.
916-
checkVRFFilePermissions :: File content direction -> ExceptT VRFPrivateKeyFilePermissionError IO ()
904+
checkVRFFilePermissions :: Tracer IO String -> File content direction -> ExceptT VRFPrivateKeyFilePermissionError IO ()
917905
#ifdef UNIX
918-
checkVRFFilePermissions (File vrfPrivKey) = do
906+
checkVRFFilePermissions tracer (File vrfPrivKey) = do
919907
fs <- liftIO $ getFileStatus vrfPrivKey
920908
let fm = fileMode fs
921909
-- Check the the VRF private key file does not give read/write/exec permissions to others.
922-
when (hasOtherPermissions fm)
923-
(left $ OtherPermissionsExist vrfPrivKey)
910+
when (hasOtherPermissions fm) $
911+
left $ OtherPermissionsExist vrfPrivKey
924912
-- Check the the VRF private key file does not give read/write/exec permissions to any group.
925-
when (hasGroupPermissions fm)
926-
(left $ GroupPermissionsExist vrfPrivKey)
913+
when (hasGroupPermissions fm) $
914+
liftIO $ traceWith tracer $ ("WARNING: " <>) . displayError $ GroupPermissionsExist vrfPrivKey
927915
where
928916
hasPermission :: FileMode -> FileMode -> Bool
929917
hasPermission fModeA fModeB = fModeA `intersectFileModes` fModeB /= nullFileMode
@@ -934,7 +922,7 @@ checkVRFFilePermissions (File vrfPrivKey) = do
934922
hasGroupPermissions :: FileMode -> Bool
935923
hasGroupPermissions fm' = fm' `hasPermission` groupModes
936924
#else
937-
checkVRFFilePermissions (File vrfPrivKey) = do
925+
checkVRFFilePermissions _ (File vrfPrivKey) = do
938926
attribs <- liftIO $ getFileAttributes vrfPrivKey
939927
-- https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea
940928
-- https://docs.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants

cardano-node/src/Cardano/Node/Types.hs

+2-3
Original file line numberDiff line numberDiff line change
@@ -477,10 +477,9 @@ renderVRFPrivateKeyFilePermissionError err =
477477
OtherPermissionsExist fp ->
478478
"VRF private key file at: " <> Text.pack fp
479479
<> " has \"other\" file permissions. Please remove all \"other\" file permissions."
480-
481480
GroupPermissionsExist fp ->
482481
"VRF private key file at: " <> Text.pack fp
483-
<> "has \"group\" file permissions. Please remove all \"group\" file permissions."
482+
<> " has \"group\" file permissions. Please remove all \"group\" file permissions."
484483
GenericPermissionsExist fp ->
485484
"VRF private key file at: " <> Text.pack fp
486-
<> "has \"generic\" file permissions. Please remove all \"generic\" file permissions."
485+
<> " has \"generic\" file permissions. Please remove all \"generic\" file permissions."

cardano-node/test/Test/Cardano/Node/FilePermissions.hs

+30-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{-# LANGUAGE CPP #-}
22
{-# LANGUAGE DataKinds #-}
33
{-# LANGUAGE OverloadedStrings #-}
4+
{-# LANGUAGE PackageImports #-}
45

56
{-# OPTIONS_GHC -Wno-unused-imports #-}
67
{-# LANGUAGE TypeApplications #-}
@@ -14,7 +15,10 @@ module Test.Cardano.Node.FilePermissions
1415
) where
1516

1617
import Control.Monad.Except
18+
import "contra-tracer" Control.Tracer
19+
import Control.Tracer.Arrow
1720
import Data.Foldable
21+
import Data.IORef
1822
import System.Directory (removeFile)
1923

2024
import Cardano.Api
@@ -31,21 +35,21 @@ import Data.Function (const, ($), (.))
3135
import qualified Data.List as L
3236
import Data.Maybe (Maybe (..))
3337
import Data.Semigroup (Semigroup (..))
34-
import Hedgehog (Property, PropertyT, property, success)
35-
import qualified Hedgehog
38+
import Hedgehog
3639
import Hedgehog.Internal.Property (Group (..), failWith)
3740
import System.IO (FilePath, IO)
3841
import Text.Show (Show (..))
42+
import Cardano.Node.Types (VRFPrivateKeyFilePermissionError (..))
3943

4044
#ifdef UNIX
41-
import Cardano.Node.Types (VRFPrivateKeyFilePermissionError (..))
4245

4346
import System.Posix.Files
4447
import System.Posix.IO (closeFd, createFile)
4548
import System.Posix.Types (FileMode)
4649

4750
import Control.Exception (bracket)
48-
import Hedgehog (Gen, classify, forAll)
51+
import Hedgehog
52+
import Hedgehog.Extras
4953
import qualified Hedgehog.Gen as Gen
5054
#endif
5155

@@ -56,10 +60,10 @@ prop_createVRFFileWithOwnerPermissions :: Property
5660
prop_createVRFFileWithOwnerPermissions =
5761
property $ do
5862
let vrfSign = "vrf-signing-key"
59-
vrfSkey <- liftIO $ generateSigningKey AsVrfKey
63+
vrfSkey <- evalIO $ generateSigningKey AsVrfKey
6064
createFileWithOwnerPermissions vrfSign vrfSkey
6165

62-
fResult <- liftIO . runExceptT $ checkVRFFilePermissions vrfSign
66+
fResult <- evalIO . runExceptT $ checkVRFFilePermissions nullTracer vrfSign
6367
case fResult of
6468
Left err -> failWith Nothing $ show err
6569
Right () -> liftIO (removeFile (unFile vrfSign)) >> success
@@ -84,7 +88,7 @@ prop_sanityCheck_checkVRFFilePermissions =
8488
correctResult <-
8589
liftIO $ bracket (createFile (unFile vrfPrivateKeyCorrect) correctPermission)
8690
(\h -> closeFd h >> removeFile (unFile vrfPrivateKeyCorrect))
87-
(const . liftIO . runExceptT $ checkVRFFilePermissions vrfPrivateKeyCorrect)
91+
(const . liftIO . runExceptT $ checkVRFFilePermissions nullTracer vrfPrivateKeyCorrect)
8892
case correctResult of
8993
Left err ->
9094
failWith Nothing $ "checkVRFFilePermissions should not have failed with error: "
@@ -105,7 +109,7 @@ prop_sanityCheck_checkVRFFilePermissions =
105109
setFileMode (unFile vrfPrivateKeyOther) $ createPermissions oPermissions
106110
return h)
107111
(\h -> closeFd h >> removeFile (unFile vrfPrivateKeyOther))
108-
(const .liftIO . runExceptT $ checkVRFFilePermissions vrfPrivateKeyOther)
112+
(const .liftIO . runExceptT $ checkVRFFilePermissions nullTracer vrfPrivateKeyOther)
109113
case otherResult of
110114
Left (OtherPermissionsExist _) -> success
111115
Left err ->
@@ -120,6 +124,7 @@ prop_sanityCheck_checkVRFFilePermissions =
120124
classify "VRF File has one group permission" $ length gPermissions == 1
121125
classify "VRF File has two group permissions" $ length gPermissions == 2
122126
classify "VRF File has three group permissions" $ length gPermissions == 3
127+
(capturingTracer, messagesIor) <- mkCapturingTracer
123128
groupResult <-
124129
-- Creating a file with group permissions appears to not work
125130
-- it instead creates a file with owner permissions. Therefore we must
@@ -128,14 +133,19 @@ prop_sanityCheck_checkVRFFilePermissions =
128133
setFileMode (unFile vrfPrivateKeyGroup) $ createPermissions gPermissions
129134
return h)
130135
(\h -> closeFd h >> removeFile (unFile vrfPrivateKeyGroup))
131-
(const . liftIO . runExceptT $ checkVRFFilePermissions vrfPrivateKeyGroup)
136+
(const . liftIO . runExceptT $ checkVRFFilePermissions capturingTracer vrfPrivateKeyGroup)
132137
case groupResult of
133-
Left (GroupPermissionsExist _) -> success
138+
Left (GroupPermissionsExist _) -> do
139+
note_ "Group permissions check should not fail"
140+
failure
134141
Left err ->
135142
failWith Nothing $ "checkVRFFilePermissions should not have failed with error: "
136143
<> show err
137-
Right () ->
138-
failWith Nothing "This should have failed as Group permissions exist"
144+
Right () -> do
145+
messages <- evalIO $ readIORef messagesIor
146+
["WARNING: VRF private key file at: vrf-private-key-group has \"group\" file permissions. Please remove all \"group\" file permissions."]
147+
=== messages
148+
139149

140150
createPermissions :: [FileMode] -> FileMode
141151
createPermissions = foldl' unionFileModes (ownerReadMode `unionFileModes` ownerWriteMode)
@@ -151,13 +161,20 @@ genOtherPermissions =
151161
let oPermissions = [otherReadMode, otherWriteMode, otherExecuteMode]
152162
in do subSeq <- Gen.filter (not . L.null) $ Gen.subsequence oPermissions
153163
Gen.frequency [(3, return oPermissions), (12, return subSeq)]
164+
165+
mkCapturingTracer :: MonadIO m => m (Tracer IO String, IORef [String])
166+
mkCapturingTracer = do
167+
messages <- liftIO $ newIORef []
168+
let registerMessage :: String -> IO ()
169+
registerMessage msg = atomicModifyIORef messages (\msgs -> (msgs <> [msg], ()))
170+
pure (Tracer registerMessage, messages)
154171
#endif
155172

156173
-- -----------------------------------------------------------------------------
157174

158175
tests :: IO Bool
159176
tests =
160-
Hedgehog.checkParallel $ Group "Test.Cardano.Node.FilePermissons"
177+
checkParallel $ Group "Test.Cardano.Node.FilePermissons"
161178
#ifdef UNIX
162179
[ ("prop_createVRFFileWithOwnerPermissions", prop_createVRFFileWithOwnerPermissions)
163180
, ("prop_sanityCheck_checkVRFFilePermissions", prop_sanityCheck_checkVRFFilePermissions)

cardano-node/test/Test/Cardano/Node/POM.hs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@ import Cardano.Node.Handlers.Shutdown
1515
import Cardano.Node.Types
1616
import Cardano.Tracing.Config (PartialTraceOptions (..), defaultPartialTraceConfiguration,
1717
partialTraceSelectionToEither)
18+
import Ouroboros.Cardano.Network.Diffusion.Configuration (defaultNumberOfBigLedgerPeers)
1819
import Ouroboros.Consensus.Node (NodeDatabasePaths (..))
1920
import qualified Ouroboros.Consensus.Node as Consensus (NetworkP2PMode (..))
2021
import Ouroboros.Consensus.Node.Genesis (disableGenesisConfig)
22+
import Ouroboros.Consensus.Storage.LedgerDB.Args
2123
import Ouroboros.Consensus.Storage.LedgerDB.Snapshots (NumOfDiskSnapshots (..),
2224
SnapshotInterval (..))
23-
import Ouroboros.Consensus.Storage.LedgerDB.Args
2425
import Ouroboros.Network.Block (SlotNo (..))
2526
import Ouroboros.Network.Diffusion.Configuration (ConsensusMode (..))
2627
import Ouroboros.Network.NodeToNode (AcceptedConnectionsLimit (..),
@@ -33,7 +34,6 @@ import Data.Text (Text)
3334
import Hedgehog (Property, discover, withTests, (===))
3435
import qualified Hedgehog
3536
import Hedgehog.Internal.Property (evalEither, failWith)
36-
import Ouroboros.Cardano.Network.Diffusion.Configuration (defaultNumberOfBigLedgerPeers)
3737

3838

3939
-- This is a simple test to check that the POM technique is working as intended.

cardano-testnet/test/cardano-testnet-test/files/calculatePlutusScriptCost.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
"lovelaceCost": 34,
88
"scriptHash": "186e32faa80a26810392fda6d559c7ed4721a65ce1c9d4ef3e1c87b4"
99
}
10-
]
10+
]

0 commit comments

Comments
 (0)