Skip to content

Commit da672c2

Browse files
committed
refactor(threatmodel): move ThreatModel from mockchain to testing-interface
- Move ThreatModel modules from convex-mockchain to new namespace Convex.ThreatModel in testing-interface - Update convex-testing-interface.cabal with new modules and dependencies - Update test imports to use new namespace
1 parent 31953bc commit da672c2

File tree

8 files changed

+139
-21
lines changed

8 files changed

+139
-21
lines changed

src/coin-selection/test/Spec.hs

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,21 @@ import Convex.Class (
4444
MonadDatumQuery (queryDatumFromHash),
4545
MonadMockchain,
4646
getTxById,
47+
getTxs,
4748
getUtxo,
4849
setReward,
4950
setUtxo,
5051
singleUTxO,
5152
)
53+
import Convex.Class qualified
5254
import Convex.CoinSelection (
5355
BalanceTxError,
5456
ChangeOutputPosition (TrailingChange),
5557
keyWitnesses,
5658
publicKeyCredential,
5759
)
5860
import Convex.MockChain (
61+
MockchainT,
5962
ValidationError (..),
6063
evalMockchain0IO,
6164
failedTransactions,
@@ -72,7 +75,7 @@ import Convex.MockChain.Defaults qualified as Defaults
7275
import Convex.MockChain.Gen qualified as Gen
7376
import Convex.MockChain.Staking (registerPool)
7477
import Convex.MockChain.Utils (
75-
Options (coverageRef),
78+
Options (Options, coverageRef, params),
7679
defaultOptions,
7780
mockchainFails,
7881
mockchainFailsWithOptions,
@@ -88,11 +91,21 @@ import Convex.NodeParams (
8891
)
8992
import Convex.Query (balancePaymentCredentials)
9093
import Convex.TestingInterface (
94+
Actions (Actions),
9195
RunOptions (mcOptions),
9296
TestingInterface (..),
9397
defaultRunOptions,
9498
propRunActionsWithOptions,
9599
)
100+
import Convex.ThreatModel (
101+
ThreatModel,
102+
ThreatModelEnv (..),
103+
counterexampleTM,
104+
ensure,
105+
getTxOutputs,
106+
paragraph,
107+
runThreatModel,
108+
)
96109
import Convex.Utils (failOnError, inBabbage)
97110
import Convex.Utils.String (unsafeAssetName, unsafeTxId)
98111
import Convex.Utxos qualified as Utxos
@@ -120,6 +133,7 @@ import Scripts qualified
120133
import Scripts.PingPong qualified as PingPong
121134
import System.Exit (ExitCode)
122135
import Test.QuickCheck.Gen qualified as Gen
136+
import Test.QuickCheck.Monadic (monadicIO, monitor, run)
123137
import Test.Tasty (
124138
TestTree,
125139
defaultMain,
@@ -129,6 +143,7 @@ import Test.Tasty.HUnit (Assertion, testCase)
129143
import Test.Tasty.QuickCheck (
130144
Property,
131145
classify,
146+
counterexample,
132147
testProperty,
133148
)
134149
import Test.Tasty.QuickCheck qualified as QC
@@ -291,6 +306,85 @@ instance TestingInterface PingPongModel where
291306

292307
monitoring _state _action prop = prop
293308

309+
{- | A simple threat model that demonstrates the integration pattern.
310+
311+
This threat model checks basic transaction properties. It serves as an
312+
example of how to integrate ThreatModel with TestingInterface.
313+
314+
NOTE: For proper threat model testing of output protection:
315+
1. The UTxO set should be captured at each transaction submission time
316+
(not at the end of all transactions, as done here for simplicity)
317+
2. Only transactions with script inputs should be tested for output protection
318+
(since only then does a validator run that could enforce the output)
319+
320+
The DoubleSatisfaction threat model from the library is designed for more
321+
sophisticated scenarios where you need to test that scripts properly protect
322+
their outputs from being redirected.
323+
-}
324+
basicThreatModel :: ThreatModel ()
325+
basicThreatModel = do
326+
-- Get transaction outputs to verify we can access transaction data
327+
outputs <- getTxOutputs
328+
-- Skip empty transactions (shouldn't happen, but be defensive)
329+
ensure (not $ null outputs)
330+
-- Log information about the transaction being tested
331+
counterexampleTM $
332+
paragraph
333+
[ "Transaction has"
334+
, show (length outputs)
335+
, "outputs."
336+
]
337+
-- This trivially passes - it demonstrates the integration pattern
338+
-- For real threat models, you would use shouldValidate/shouldNotValidate
339+
-- to check specific security properties
340+
pure ()
341+
342+
{- | Property test that runs PingPong actions and then checks a
343+
threat model against all submitted transactions.
344+
345+
This demonstrates how to integrate threat models with TestingInterface.
346+
-}
347+
propPingPongWithThreatModel :: RunOptions -> Actions PingPongModel -> Property
348+
propPingPongWithThreatModel opts (Actions actions) = monadicIO $ do
349+
let Options{params} = mcOptions opts
350+
351+
-- Run the mockchain and collect transactions
352+
result <- run $ runMockchain0IOWith Wallet.initialUTxOs params $ do
353+
-- Execute all actions
354+
_ <- foldMActions (initialState @PingPongModel) actions
355+
-- Collect submitted transactions
356+
txs <- Convex.Class.getTxs
357+
-- Get the current UTxO set
358+
ledgerUtxo <- Convex.Class.getUtxo
359+
pure (txs, ledgerUtxo)
360+
361+
case result of
362+
((txs, ledgerUtxo), _finalState) -> do
363+
-- Convert ledger UTxO to cardano-api UTxO
364+
let utxo = fromLedgerUTxO C.shelleyBasedEra ledgerUtxo
365+
pparams' = params ^. ledgerProtocolParameters
366+
367+
-- Create ThreatModelEnv for each transaction
368+
let envs =
369+
[ ThreatModelEnv
370+
{ currentTx = tx
371+
, currentUTxOs = utxo
372+
, pparams = pparams'
373+
}
374+
| tx <- txs
375+
]
376+
377+
-- Run the basic threat model
378+
-- This demonstrates the integration pattern
379+
monitor (counterexample $ "Tested " ++ show (length txs) ++ " transactions")
380+
pure $ runThreatModel basicThreatModel envs
381+
where
382+
foldMActions :: PingPongModel -> [Action PingPongModel] -> MockchainT C.ConwayEra IO PingPongModel
383+
foldMActions s [] = pure s
384+
foldMActions s (a : as) = do
385+
perform s a
386+
foldMActions (nextState s a) as
387+
294388
main :: IO ()
295389
main = do
296390
ref <- newIORef mempty
@@ -409,6 +503,9 @@ tests ref =
409503
, testProperty
410504
"Property-based test with TestingInterface"
411505
(propRunActionsWithOptions @PingPongModel runOpts)
506+
, testProperty
507+
"Property-based test with ThreatModel integration"
508+
(propPingPongWithThreatModel runOpts)
412509
]
413510
]
414511
, testGroup

src/mockchain/convex-mockchain.cabal

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,6 @@ library
4242
Convex.MockChain.Coverage
4343
Convex.MockChain.Defaults
4444
Convex.MockChain.Gen
45-
Convex.MockChain.ThreatModel
46-
Convex.MockChain.ThreatModel.Cardano.Api
47-
Convex.MockChain.ThreatModel.DoubleSatisfaction
48-
Convex.MockChain.ThreatModel.Pretty
49-
Convex.MockChain.ThreatModel.TxModifier
5045
Convex.MockChain.Utils
5146

5247
hs-source-dirs: lib

src/testing-interface/convex-testing-interface.cabal

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,42 @@ common lang
3939

4040
library
4141
import: lang
42-
exposed-modules: Convex.TestingInterface
42+
exposed-modules:
43+
Convex.TestingInterface
44+
Convex.ThreatModel
45+
Convex.ThreatModel.Cardano.Api
46+
Convex.ThreatModel.DoubleSatisfaction
47+
Convex.ThreatModel.Pretty
48+
Convex.ThreatModel.TxModifier
49+
4350
hs-source-dirs: lib
4451
build-depends:
4552
, base >=4.14.0
53+
, bytestring
4654
, cardano-api
4755
, containers
4856
, convex-mockchain
4957
, convex-wallet
5058
, mtl
5159
, QuickCheck
5260
, transformers
61+
62+
-- cardano dependencies for ThreatModel
63+
build-depends:
64+
, cardano-ledger-allegra
65+
, cardano-ledger-alonzo
66+
, cardano-ledger-api
67+
, cardano-ledger-babbage
68+
, cardano-ledger-binary
69+
, cardano-ledger-conway
70+
, cardano-ledger-core
71+
, cardano-slotting
72+
, cardano-strict-containers
73+
, ouroboros-consensus
74+
, ouroboros-consensus-cardano
75+
, plutus-ledger-api
76+
, plutus-tx
77+
, pretty
78+
, sop-extras
79+
, text
80+
, time

src/mockchain/lib/Convex/MockChain/ThreatModel.hs renamed to src/testing-interface/lib/Convex/ThreatModel.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
3232
For a more complex example see "Test.QuickCheck.ThreatModel.DoubleSatisfaction".
3333
-}
34-
module Convex.MockChain.ThreatModel (
34+
module Convex.ThreatModel (
3535
-- * Transaction modifiers
3636

3737
-- ** Types
@@ -141,9 +141,9 @@ import Test.QuickCheck
141141
import Text.PrettyPrint hiding ((<>))
142142
import Text.Printf
143143

144-
import Convex.MockChain.ThreatModel.Cardano.Api
145-
import Convex.MockChain.ThreatModel.Pretty
146-
import Convex.MockChain.ThreatModel.TxModifier
144+
import Convex.ThreatModel.Cardano.Api
145+
import Convex.ThreatModel.Pretty
146+
import Convex.ThreatModel.TxModifier
147147

148148
{- $cardanoHelpers
149149
Some convenience functions making it easier to work with Cardano API.

src/mockchain/lib/Convex/MockChain/ThreatModel/Cardano/Api.hs renamed to src/testing-interface/lib/Convex/ThreatModel/Cardano/Api.hs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{-# LANGUAGE LambdaCase #-}
44
{-# LANGUAGE TypeApplications #-}
55

6-
module Convex.MockChain.ThreatModel.Cardano.Api where
6+
module Convex.ThreatModel.Cardano.Api where
77

88
import Cardano.Api
99

@@ -12,7 +12,6 @@ import Cardano.Ledger.Alonzo.Scripts qualified as Ledger
1212
import Cardano.Ledger.Alonzo.TxBody qualified as Ledger
1313
import Cardano.Ledger.Alonzo.TxWits qualified as Ledger
1414
import Cardano.Ledger.Api.Tx.Body qualified as Ledger
15-
import Cardano.Ledger.Babbage.TxBody qualified as Ledger
1615
import Cardano.Ledger.Conway.Scripts qualified as Conway
1716
import Cardano.Ledger.Conway.TxBody qualified as Conway
1817
import Cardano.Ledger.Keys (WitVKey (..), coerceKeyRole, hashKey)

src/mockchain/lib/Convex/MockChain/ThreatModel/DoubleSatisfaction.hs renamed to src/testing-interface/lib/Convex/ThreatModel/DoubleSatisfaction.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
{-# LANGUAGE OverloadedStrings #-}
22

3-
module Convex.MockChain.ThreatModel.DoubleSatisfaction (
3+
module Convex.ThreatModel.DoubleSatisfaction (
44
doubleSatisfaction,
55
) where
66

77
import Data.ByteString (ByteString)
88
import PlutusTx.Builtins (toBuiltin)
99

10-
import Convex.MockChain.ThreatModel
10+
import Convex.ThreatModel
1111

1212
safeScript :: SimpleScript
1313
safeScript = RequireAllOf [] -- TODO: this is not the right script!

src/mockchain/lib/Convex/MockChain/ThreatModel/Pretty.hs renamed to src/testing-interface/lib/Convex/ThreatModel/Pretty.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{-# LANGUAGE GADTs #-}
22
{-# LANGUAGE RecordWildCards #-}
33

4-
module Convex.MockChain.ThreatModel.Pretty where
4+
module Convex.ThreatModel.Pretty where
55

66
import Cardano.Api hiding (Doc, (<+>))
77

@@ -21,8 +21,8 @@ import GHC.Exts (toList)
2121
import Text.PrettyPrint.HughesPJClass hiding ((<>))
2222
import Text.Printf
2323

24-
import Convex.MockChain.ThreatModel.Cardano.Api
25-
import Convex.MockChain.ThreatModel.TxModifier
24+
import Convex.ThreatModel.Cardano.Api
25+
import Convex.ThreatModel.TxModifier
2626

2727
{- | Format a list of strings as a paragraph. The structure of the list is not considered other than
2828
inserting whitespace between consecutive elements. Use with

src/mockchain/lib/Convex/MockChain/ThreatModel/TxModifier.hs renamed to src/testing-interface/lib/Convex/ThreatModel/TxModifier.hs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55
{-# LANGUAGE ViewPatterns #-}
66
{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
77

8-
module Convex.MockChain.ThreatModel.TxModifier where
8+
module Convex.ThreatModel.TxModifier where
99

1010
import Cardano.Api
1111
import Cardano.Ledger.Alonzo.TxBody qualified as Ledger
1212
import Cardano.Ledger.Alonzo.TxWits qualified as Ledger
1313
import Cardano.Ledger.Api.Era qualified as Ledger
14-
import Cardano.Ledger.Babbage.TxBody qualified as Ledger
1514
import Cardano.Ledger.Binary qualified as CBOR
1615
import Cardano.Ledger.Conway.Scripts qualified as Conway
1716
import Cardano.Ledger.Conway.TxBody qualified as Conway
@@ -24,7 +23,7 @@ import Data.Maybe.Strict
2423
import Data.Sequence.Strict qualified as Seq
2524
import Data.Set qualified as Set
2625

27-
import Convex.MockChain.ThreatModel.Cardano.Api
26+
import Convex.ThreatModel.Cardano.Api
2827

2928
-- | A transaction output paired with its index in the transaction.
3029
data Output = Output

0 commit comments

Comments
 (0)