Executable.hs (4764B)
1 -- Authenticated executable loading. Object references establish kind and content; 2 -- only a module export supplies an ABI. Failures are IO errors, not process exits. 3 module ContentStore.Executable 4 ( loadVerifiedManifest, loadVerifiedExport, loadVerifiedExportWith 5 , loadVerifiedExports, loadVerifiedExportSelection, loadExecutableObject ) where 6 7 import ContentStore.Object 8 import ContentStore.Filesystem (getObject) 9 import ContentStore.Arboricx (treeTermDomain, decodeTreeTermShared) 10 import ContentStore.Indexed 11 import ContentStore.Alias (ObjectRef(..)) 12 import Module.Manifest 13 import qualified Runtime as Tree 14 import qualified Data.Text as T 15 import Control.Exception (evaluate) 16 import Control.Monad (forM, unless) 17 18 loadVerifiedManifest :: StorePath -> T.Text -> IO ModuleManifest 19 loadVerifiedManifest store manifestHash = do 20 either (fail . ("Invalid module manifest hash: " ++)) pure 21 (textToHashBytes manifestHash) 22 manifestPayload <- getObject store manifestHash >>= maybe 23 (fail $ "Module manifest not found in store: " ++ T.unpack manifestHash) pure 24 unless (hashObject manifestDomain manifestPayload == manifestHash) $ 25 fail "Module manifest digest mismatch" 26 manifest <- either (fail . ("Invalid module manifest: " ++)) pure 27 (decodeManifest manifestPayload) 28 pure manifest 29 30 loadVerifiedExport :: StorePath -> T.Text -> T.Text -> IO (ObjectHash, Tree.T) 31 loadVerifiedExport = loadVerifiedExportWith (const $ pure ()) 32 33 loadVerifiedExportWith :: (String -> IO ()) -> StorePath -> T.Text -> T.Text -> IO (ObjectHash, Tree.T) 34 loadVerifiedExportWith sample store manifestHash name = do 35 manifest <- loadVerifiedManifest store manifestHash 36 sample "manifest-verified" 37 loadManifestExport sample store manifest name 38 39 loadVerifiedExports :: StorePath -> T.Text -> IO [(String, Tree.T)] 40 loadVerifiedExports store pin = do 41 exports <- loadVerifiedExportSelection store pin Nothing 42 pure [(T.unpack name, term) | (name, term) <- exports] 43 44 -- Nothing selects the complete interface in manifest order. An explicit list 45 -- loads only those names, in caller order; unrelated export objects stay unread. 46 loadVerifiedExportSelection :: StorePath -> T.Text -> Maybe [T.Text] -> IO [(T.Text, Tree.T)] 47 loadVerifiedExportSelection store pin selection = do 48 manifest <- loadVerifiedManifest store pin 49 let sample = const $ pure () 50 case selection of 51 Nothing -> forM (moduleManifestExports manifest) $ \ex -> do 52 (_, term) <- loadModuleExport sample store ex 53 pure (moduleExportName ex, term) 54 Just names -> forM names $ \name -> do 55 (_, term) <- loadManifestExport sample store manifest name 56 pure (name, term) 57 58 -- Internal: the manifest must have passed authentication and decoding above. 59 loadManifestExport :: (String -> IO ()) -> StorePath -> ModuleManifest -> T.Text -> IO (ObjectHash, Tree.T) 60 loadManifestExport sample store manifest name = do 61 let matches = filter ((== name) . moduleExportName) 62 (moduleManifestExports manifest) 63 ex <- case matches of 64 [single] -> pure single 65 [] -> fail $ "Module export not found: " ++ T.unpack name 66 _ -> fail $ "Duplicate module export: " ++ T.unpack name 67 loadModuleExport sample store ex 68 69 loadModuleExport :: (String -> IO ()) -> StorePath -> ModuleExport -> IO (ObjectHash, Tree.T) 70 loadModuleExport sample store ex = do 71 let ref = moduleExportObject ex 72 unless (moduleExportAbi ex == "arboricx.abi.tree.v1") $ 73 fail $ "Unsupported module export ABI: " ++ T.unpack (moduleExportAbi ex) 74 term <- loadExecutableObjectWith sample store ref 75 pure (objectRefHash ref, term) 76 77 loadExecutableObject :: StorePath -> ObjectRef -> IO Tree.T 78 loadExecutableObject = loadExecutableObjectWith (const $ pure ()) 79 80 loadExecutableObjectWith :: (String -> IO ()) -> StorePath -> ObjectRef -> IO Tree.T 81 loadExecutableObjectWith sample store ref = do 82 domain <- if objectRefKind ref == unDomain treeTermDomain 83 then pure treeTermDomain 84 else if objectRefKind ref == unDomain indexedTreeDomain 85 then pure indexedTreeDomain 86 else fail $ "Unsupported module export object kind: " ++ T.unpack (objectRefKind ref) 87 either (fail . ("Invalid executable tree hash: " ++)) pure 88 (textToHashBytes $ objectRefHash ref) 89 treePayload <- getObject store (objectRefHash ref) >>= maybe 90 (fail $ "Executable tree not found: " ++ T.unpack (objectRefHash ref)) pure 91 sample "executable-read" 92 unless (hashObject domain treePayload == objectRefHash ref) $ 93 fail "Executable tree digest mismatch" 94 sample "executable-digest-verified" 95 term <- either (fail . ("Invalid executable tree: " ++)) pure 96 ((if domain == indexedTreeDomain then decodeIndexedTree else decodeTreeTermShared) treePayload) 97 _ <- evaluate term 98 sample "executable-decoded" 99 pure term 100