Skip to content

Commit 90f064a

Browse files
authored
Merge pull request #361 from crytic/dev-medusa-ci
Add medusa tests to CI
2 parents 0036656 + dcb2651 commit 90f064a

File tree

6 files changed

+385
-0
lines changed

6 files changed

+385
-0
lines changed

.github/workflows/medusa.yml

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
name: Run Medusa tests
2+
3+
on:
4+
push:
5+
paths:
6+
- ".github/workflows/medusa.yml"
7+
- "program-analysis/echidna/**/*.sol"
8+
- "program-analysis/echidna/**/*.yml"
9+
branches:
10+
- master
11+
pull_request:
12+
paths:
13+
- ".github/workflows/medusa.yml"
14+
- "program-analysis/echidna/**/*.sol"
15+
- "program-analysis/echidna/**/*.yml"
16+
schedule:
17+
# run CI every day even if no PRs/merges occur
18+
- cron: "0 12 * * *"
19+
20+
jobs:
21+
tests:
22+
name: ${{ matrix.name }}
23+
continue-on-error: ${{ matrix.flaky == true }}
24+
runs-on: ubuntu-22.04
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
include:
29+
- name: Exercise 1
30+
workdir: program-analysis/echidna/exercises/exercise1/
31+
files: solution.sol
32+
contract: TestToken
33+
outcome: failure
34+
expected: 'echidna_test_balance()\" failed after the following call sequence'
35+
- name: Exercise 2
36+
workdir: program-analysis/echidna/exercises/exercise2/
37+
files: solution.sol
38+
contract: TestToken
39+
outcome: failure
40+
expected: 'echidna_no_transfer()\" failed after the following call sequence'
41+
- name: Exercise 3
42+
workdir: program-analysis/echidna/exercises/exercise3/
43+
files: solution.sol
44+
contract: TestToken
45+
outcome: failure
46+
expected: 'echidna_test_balance()\" failed after the following call sequence'
47+
- name: Exercise 4
48+
workdir: program-analysis/echidna/exercises/exercise4/
49+
files: solution.sol
50+
contract: TestToken
51+
outcome: failure
52+
expected: 'transfer(address,uint256)\" resulted in an assertion failure after the following call sequence:'
53+
# - name: Exercise 5
54+
# workdir: dvdefi/
55+
# files: .
56+
# config: naivereceiver.yaml
57+
# crytic-args: --hardhat-ignore-compile
58+
# contract: NaiveReceiverEchidna
59+
# outcome: failure
60+
# expected: 'echidna_test_contract_balance:\s*failed'
61+
# - name: Exercise 6
62+
# workdir: dvdefi/
63+
# files: .
64+
# config: unstoppable.yaml
65+
# crytic-args: --hardhat-ignore-compile
66+
# contract: UnstoppableEchidna
67+
# outcome: failure
68+
# expected: 'echidna_testFlashLoan:\s*failed'
69+
# - name: Exercise 7
70+
# workdir: dvdefi/
71+
# files: .
72+
# config: sideentrance.yaml
73+
# crytic-args: --hardhat-ignore-compile
74+
# contract: SideEntranceEchidna
75+
# outcome: failure
76+
# expected: 'testPoolBalance():\s*failed'
77+
- name: TestToken
78+
workdir: program-analysis/echidna/example/
79+
files: testtoken.sol
80+
contract: TestToken
81+
outcome: failure
82+
expected: 'echidna_balance_under_1000()\" failed after the following call sequence'
83+
- name: Multi
84+
workdir: program-analysis/echidna/example/
85+
files: multi.sol
86+
contract: C
87+
config: filter.yaml
88+
outcome: failure
89+
expected: 'echidna_state4()\" failed after the following call sequence'
90+
- name: Assert
91+
workdir: program-analysis/echidna/example/
92+
files: assert.sol
93+
config: assert.yaml
94+
contract: Incrementor
95+
outcome: failure
96+
expected: 'inc(uint256)\" resulted in an assertion failure after the following call sequence'
97+
- name: PopsicleBroken
98+
workdir: program-analysis/echidna/example/
99+
files: PopsicleBroken.sol
100+
solc-version: 0.8.4
101+
contract: PopsicleBroken
102+
outcome: failure
103+
expected: 'PopsicleBroken.totalBalanceAfterTransferIsPreserved(address,uint256)\" resulted in an assertion failure after the following call sequence'
104+
- name: PopsicleFixed
105+
workdir: program-analysis/echidna/example/
106+
files: PopsicleFixed.sol
107+
solc-version: 0.8.4
108+
contract: PopsicleFixed
109+
outcome: success
110+
expected: '\[PASSED\] Assertion Test: PopsicleFixed.totalBalanceAfterTransferIsPreserved(address,uint256)'
111+
- name: TestDepositWithPermit
112+
workdir: program-analysis/echidna/example/
113+
files: TestDepositWithPermit.sol
114+
solc-version: 0.8.0
115+
config: testdeposit.yaml
116+
contract: TestDepositWithPermit
117+
outcome: success
118+
expected: '\[PASSED\] Assertion Test: TestDepositWithPermit.testERC20PermitDeposit(uint256)'
119+
# - name: MultiABI
120+
# workdir: program-analysis/echidna/example/
121+
# files: allContracts.sol
122+
# solc-version: 0.8.0
123+
# config: allContracts.yaml
124+
# contract: EchidnaTest
125+
# outcome: failure
126+
# expected: 'test_flag_is_false():\s*failed'
127+
128+
steps:
129+
- name: Checkout repository
130+
uses: actions/checkout@v4
131+
132+
- name: Checkout Damn Vulnerable DeFi solutions
133+
uses: actions/checkout@v4
134+
if: startsWith(matrix.workdir, 'dvdefi')
135+
with:
136+
repository: crytic/damn-vulnerable-defi-echidna
137+
ref: solutions
138+
path: ${{ matrix.workdir }}
139+
140+
- name: Set up Nodejs
141+
uses: actions/setup-node@v3
142+
if: startsWith(matrix.workdir, 'dvdefi')
143+
with:
144+
node-version: 16
145+
146+
- name: Install dependencies and compile
147+
if: startsWith(matrix.workdir, 'dvdefi')
148+
run: |
149+
yarn install --frozen-lockfile
150+
npx hardhat compile --force
151+
working-directory: ${{ matrix.workdir }}
152+
153+
- name: Go setup
154+
uses: actions/setup-go@v4
155+
with:
156+
go-version: "^1.18.1"
157+
158+
- name: Install medusa
159+
run: |
160+
git clone https://github.com/crytic/medusa.git
161+
cd medusa
162+
go build -o medusa -v .
163+
go install -v .
164+
sudo cp medusa /usr/bin
165+
pip install crytic-compile solc-select
166+
167+
- name: Run Medusa
168+
continue-on-error: true
169+
working-directory: ${{ matrix.workdir }}
170+
run: |
171+
solc-select install ${{ matrix.solc-version || '0.8.0' }}
172+
solc-select use ${{ matrix.solc-version || '0.8.0' }}
173+
medusa fuzz --compilation-target ${{ matrix.files }} --target-contracts ${{ matrix.contract }} --no-color --test-limit 100000 --config medusa.json > ${{ matrix.files }}.out || true
174+
175+
- name: Verify that the output is correct
176+
working-directory: ${{ matrix.workdir }}
177+
run: |
178+
if grep -q "${{ matrix.expected }}" "${{ matrix.files }}.out"; then
179+
echo "Output matches"
180+
else
181+
echo "Output mismatch. Expected something matching '${{ matrix.expected }}'. Got the following:"
182+
cat "${{ matrix.files }}.out"
183+
exit 1
184+
fi
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"fuzzing": {
3+
"workers": 10,
4+
"workerResetLimit": 50,
5+
"timeout": 0,
6+
"testLimit": 0,
7+
"callSequenceLength": 100,
8+
"corpusDirectory": "",
9+
"coverageEnabled": true,
10+
"targetContracts": [],
11+
"targetContractsBalances": [],
12+
"constructorArgs": {},
13+
"deployerAddress": "0x30000",
14+
"senderAddresses": ["0x10000", "0x20000", "0x30000"],
15+
"blockNumberDelayMax": 60480,
16+
"blockTimestampDelayMax": 604800,
17+
"blockGasLimit": 125000000,
18+
"transactionGasLimit": 12500000,
19+
"testing": {
20+
"stopOnFailedTest": true,
21+
"stopOnFailedContractMatching": false,
22+
"stopOnNoTests": true,
23+
"testAllContracts": false,
24+
"traceAll": false,
25+
"assertionTesting": {
26+
"enabled": true,
27+
"testViewMethods": false,
28+
"panicCodeConfig": {
29+
"failOnCompilerInsertedPanic": false,
30+
"failOnAssertion": true,
31+
"failOnArithmeticUnderflow": false,
32+
"failOnDivideByZero": false,
33+
"failOnEnumTypeConversionOutOfBounds": false,
34+
"failOnIncorrectStorageAccess": false,
35+
"failOnPopEmptyArray": false,
36+
"failOnOutOfBoundsArrayAccess": false,
37+
"failOnAllocateTooMuchMemory": false,
38+
"failOnCallUninitializedVariable": false
39+
}
40+
},
41+
"propertyTesting": {
42+
"enabled": true,
43+
"testPrefixes": ["echidna_"]
44+
},
45+
"optimizationTesting": {
46+
"enabled": false,
47+
"testPrefixes": ["optimize_"]
48+
}
49+
},
50+
"chainConfig": {
51+
"codeSizeCheckDisabled": true,
52+
"cheatCodes": {
53+
"cheatCodesEnabled": true,
54+
"enableFFI": false
55+
}
56+
}
57+
},
58+
"compilation": {
59+
"platform": "crytic-compile",
60+
"platformConfig": {
61+
"target": ".",
62+
"solcVersion": "",
63+
"exportDirectory": "",
64+
"args": []
65+
}
66+
},
67+
"logging": {
68+
"level": "info",
69+
"logDirectory": "",
70+
"noColor": false
71+
}
72+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"fuzzing": {
3+
"testing": {
4+
"propertyTesting": {
5+
"enabled": true,
6+
"testPrefixes": ["echidna_"]
7+
}
8+
}
9+
},
10+
"compilation": {
11+
"platform": "crytic-compile",
12+
"platformConfig": {
13+
"target": ".",
14+
"solcVersion": "",
15+
"exportDirectory": "",
16+
"args": []
17+
}
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"fuzzing": {
3+
"testing": {
4+
"propertyTesting": {
5+
"enabled": true,
6+
"testPrefixes": ["echidna_"]
7+
}
8+
}
9+
},
10+
"compilation": {
11+
"platform": "crytic-compile",
12+
"platformConfig": {
13+
"target": ".",
14+
"solcVersion": "",
15+
"exportDirectory": "",
16+
"args": []
17+
}
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"fuzzing": {
3+
"testing": {
4+
"propertyTesting": {
5+
"enabled": true,
6+
"testPrefixes": ["echidna_"]
7+
}
8+
}
9+
},
10+
"compilation": {
11+
"platform": "crytic-compile",
12+
"platformConfig": {
13+
"target": ".",
14+
"solcVersion": "",
15+
"exportDirectory": "",
16+
"args": []
17+
}
18+
}
19+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
{
2+
"fuzzing": {
3+
"workers": 10,
4+
"workerResetLimit": 50,
5+
"timeout": 0,
6+
"testLimit": 0,
7+
"callSequenceLength": 100,
8+
"corpusDirectory": "",
9+
"coverageEnabled": true,
10+
"targetContracts": [],
11+
"targetContractsBalances": [],
12+
"constructorArgs": {},
13+
"deployerAddress": "0x30000",
14+
"senderAddresses": ["0x10000", "0x20000", "0x30000"],
15+
"blockNumberDelayMax": 60480,
16+
"blockTimestampDelayMax": 604800,
17+
"blockGasLimit": 125000000,
18+
"transactionGasLimit": 12500000,
19+
"testing": {
20+
"stopOnFailedTest": true,
21+
"stopOnFailedContractMatching": false,
22+
"stopOnNoTests": true,
23+
"testAllContracts": false,
24+
"traceAll": false,
25+
"assertionTesting": {
26+
"enabled": true,
27+
"testViewMethods": false,
28+
"panicCodeConfig": {
29+
"failOnCompilerInsertedPanic": false,
30+
"failOnAssertion": true,
31+
"failOnArithmeticUnderflow": false,
32+
"failOnDivideByZero": false,
33+
"failOnEnumTypeConversionOutOfBounds": false,
34+
"failOnIncorrectStorageAccess": false,
35+
"failOnPopEmptyArray": false,
36+
"failOnOutOfBoundsArrayAccess": false,
37+
"failOnAllocateTooMuchMemory": false,
38+
"failOnCallUninitializedVariable": false
39+
}
40+
},
41+
"propertyTesting": {
42+
"enabled": true,
43+
"testPrefixes": ["property_"]
44+
},
45+
"optimizationTesting": {
46+
"enabled": true,
47+
"testPrefixes": ["optimize_"]
48+
}
49+
},
50+
"chainConfig": {
51+
"codeSizeCheckDisabled": true,
52+
"cheatCodes": {
53+
"cheatCodesEnabled": true,
54+
"enableFFI": false
55+
}
56+
}
57+
},
58+
"compilation": {
59+
"platform": "crytic-compile",
60+
"platformConfig": {
61+
"target": ".",
62+
"solcVersion": "",
63+
"exportDirectory": "",
64+
"args": []
65+
}
66+
},
67+
"logging": {
68+
"level": "info",
69+
"logDirectory": "",
70+
"noColor": false
71+
}
72+
}

0 commit comments

Comments
 (0)