Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci(fuzz tests): graphql fuzz testing #3760

Draft
wants to merge 72 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
d65e435
hack(tests): add fuzz testing workflow
iainsproat Dec 30, 2024
e4bbf38
fixes
iainsproat Dec 30, 2024
a026354
Update path of binary
iainsproat Dec 30, 2024
e66d2c2
Update binary path again, and add names to steps
iainsproat Dec 30, 2024
3e18153
More path fixes, too much nesting
iainsproat Dec 30, 2024
c8b96e4
Add debugging output
iainsproat Dec 30, 2024
48b7d2f
it is case-sensitive fml
iainsproat Dec 30, 2024
ea36cd9
Restler documentation is inconsistent on the output dir and there are…
iainsproat Dec 30, 2024
8ea40b3
Now output the file content to allow configuration
iainsproat Dec 30, 2024
968e4e7
Attempt to run speckle-server and test the API
iainsproat Dec 30, 2024
45674f0
fix minio service
iainsproat Dec 30, 2024
bc4ca17
Fix paths for yarn
iainsproat Dec 30, 2024
95fbf4a
set cache dependency path
iainsproat Dec 30, 2024
b2ebd47
Add a yarn start to server package.json
iainsproat Dec 30, 2024
8686c00
Caching
iainsproat Dec 30, 2024
3d20d7a
configure env vars for fuzz test
iainsproat Dec 30, 2024
a030b22
Printing results
iainsproat Dec 30, 2024
272b9fa
caching was too agressive
iainsproat Dec 30, 2024
d0c0c60
overwrite minio entrypoint
iainsproat Dec 30, 2024
e19abdd
More bug fixing
iainsproat Dec 30, 2024
2460fb9
remove network alias
iainsproat Dec 30, 2024
6cba30d
Bump OpenAPI specification version and add servers property
iainsproat Dec 30, 2024
198a8cc
Override host when testing
iainsproat Dec 30, 2024
b76f20e
Swap to docker compose
iainsproat Dec 30, 2024
e68da6a
fix postgres creds
iainsproat Dec 30, 2024
c8002de
Wait for server to start running, and always print restler output
iainsproat Dec 30, 2024
fe446d5
Wait until server is responding
iainsproat Dec 30, 2024
ca46336
Do not fail on decoding of responses being unexpected unicode
iainsproat Dec 30, 2024
f09ce25
Two step creation of grammar
iainsproat Dec 31, 2024
62abdcb
Fix restler config
iainsproat Dec 31, 2024
7691195
Add more detail to OpenAPI specification
iainsproat Dec 31, 2024
1b7cd28
Update openapi specification and skip unimplemented endpoint
iainsproat Dec 31, 2024
ebbf332
Restler should be authenticated; seed the database with data
iainsproat Dec 31, 2024
0d3ac1c
sudo is required
iainsproat Dec 31, 2024
dbf2c07
Token file should match Restler format
iainsproat Dec 31, 2024
d0c8287
Fix seeding of database
iainsproat Dec 31, 2024
beb60ef
Run from docker image, not source
iainsproat Dec 31, 2024
5aab551
remove obsolete step
iainsproat Dec 31, 2024
0d5a1c5
fix migrations in pg dump backup
iainsproat Dec 31, 2024
ea22d5b
wait until server is ready
iainsproat Dec 31, 2024
b13b547
Fix token
iainsproat Dec 31, 2024
3d5a049
Update OpenAPI specification
iainsproat Jan 1, 2025
fb2a22d
Fix indentation of openapi spec
iainsproat Jan 1, 2025
7e2e079
Upload test results as an artifact
iainsproat Jan 2, 2025
2cda8d8
Attempt to improve test coverage
iainsproat Jan 2, 2025
c00c3bb
Print compile logs
iainsproat Jan 2, 2025
5791e5a
Cache the restler binary and do not attempt to save cache if cache hit
iainsproat Jan 2, 2025
1f6bb11
Attempt to fix dictionary
iainsproat Jan 2, 2025
6ff569b
Update OpenAPI specification
iainsproat Jan 2, 2025
5f86467
provide proper path to compiler
iainsproat Jan 2, 2025
080a478
Bust cache to retry building
iainsproat Jan 2, 2025
a3e17b8
feat(server): allow ratelimiting to be explicitly disabled
iainsproat Jan 2, 2025
d2d6210
Disable rate limiter in CI
iainsproat Jan 2, 2025
96bc9fc
Merge branch 'main' into iain/web-511-fuzz-test-speckle-server-rest-api
iainsproat Jan 2, 2025
a5f15ed
Merge branch 'iain/ratelimiter-can-be-explicitly-disabled' into iain/…
iainsproat Jan 2, 2025
c188fa9
Explicitly disable ratelimiter
iainsproat Jan 2, 2025
fef3198
More fixes to openapi specification
iainsproat Jan 2, 2025
ed09a8c
Remove caching
iainsproat Jan 2, 2025
49884b5
fix(server/blobstorage): handles errors with missing content-type header
iainsproat Jan 2, 2025
b56ba47
More openapi specification improvements
iainsproat Jan 2, 2025
29ee4f4
Provide default app Ids
iainsproat Jan 2, 2025
39efe09
Enhance OpenAPI specification
iainsproat Jan 3, 2025
f30b04e
ci(fuzz tests): graphql fuzz testing
iainsproat Jan 3, 2025
f1121a2
Merge branch 'main' into iain/web-512-fuzz-test-speckle-server-graphq…
iainsproat Jan 3, 2025
b9352c9
Tag is capitalized, just to be different from convention :fml:
iainsproat Jan 3, 2025
39b35b6
Poetry needs to be explicitly installed
iainsproat Jan 3, 2025
5c88e11
Use supported python version
iainsproat Jan 3, 2025
e814908
copy pasta error; poetry shell makes no sense in CI
iainsproat Jan 3, 2025
abb2a69
run graphqler using local path not global module
iainsproat Jan 3, 2025
77476b7
need to run python inside the poetry environment, such n00b
iainsproat Jan 3, 2025
d169bc3
Add graphqler configuration file
iainsproat Jan 3, 2025
c9eb9cf
Compile and fuzz in a single step
iainsproat Jan 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitguardian.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ secret:
name: setup/keycloak/speckle-realm.json - secret for dev keycloak
- match: 2e1b3675a4049cd39fe6db081735f747730969071528270800f00fa98720d198
name: setup/keycloak/speckle-realm.json - algorithm name
- match: 164797a0ebc32f504e2dbaf48bec77969456bc301829039b34dc6787a1f5b0f3
name: setup/fuzzer/token.txt - fuzz test token

version: 2
146 changes: 146 additions & 0 deletions .github/workflows/graphql-api-fuzzer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
name: GraphQL API Fuzz Test

on:
workflow_dispatch:
# schedule:
# - cron: "15 4 3 * *" # Run at 4:15am on the 3rd of every month
pull_request:
paths:
- '.github/workflows/graphql-api-fuzzer.yml'
- 'setup/fuzzer-graphql/**/*'
- 'setup/fuzzer/docker-compose-speckle.yml'
- 'setup/fuzzer/speckle.backup.sql'

env:
PYTHON_VERSION: '3.12'
GRAPHQLER_VERSION: '2.3.6'

jobs:
graphql-fuzzer:
name: Fuzz test speckle-server Graphql API
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- uses: actions/checkout@v4
name: Checkout speckle-server
with:
path: 'speckle-server'

- uses: actions/checkout@v4
name: Checkout Graphqler Fuzzer
with:
repository: omar2535/GraphQLer
ref: V${{ env.GRAPHQLER_VERSION }}
path: 'graphqler-fuzzer' # The path to clone the repository within the {{ github.workspace }} directory

- name: Install poetry
run: pipx install poetry

- name: Set up Python ${{ env.PYTHON_VERSION }}
uses: actions/setup-python@v4
with:
python-version: ${{ env.PYTHON_VERSION }}
cache: 'poetry'
cache-dependency-path: ${{ github.workspace }}/graphqler-fuzzer/poetry.lock

- name: Install dependencies with Poetry
working-directory: ${{ github.workspace }}/graphqler-fuzzer
run: |
poetry install

- name: Deploy dependencies (docker compose)
run: |
docker compose --file ${{ github.workspace }}/speckle-server/docker-compose-deps.yml up --detach

- name: Seed the database
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends postgresql-client
PGPASSWORD=speckle psql -h 127.0.0.1 -U speckle -d speckle -p 5432 -w < ${{ github.workspace }}/speckle-server/setup/fuzzer/speckle.backup.sql

- name: Deploy speckle-server (docker compose)
working-directory: ${{ github.workspace }}
timeout-minutes: 1
run: |
docker compose --file ${{ github.workspace }}/speckle-server/setup/fuzzer/docker-compose-speckle.yml up --detach
until curl --output /dev/null --silent --head --fail http://127.0.0.1:3000/readiness; do
echo "Waiting a further 3 seconds for speckle-server to start..."
sleep 3
done

# - name: Restore cached Graphqler configuration
# id: cache-config-restore
# uses: actions/cache/restore@v4
# with:
# path: |
# ${{ github.workspace }}/graphqlerConfig
# key: graphqler-config-${{ github.sha }}

# - name: Generate Graphqler config from Graphql server
# if: steps.cache-config-restore.outputs.cache-hit != 'true'
# working-directory: ${{ github.workspace }}/graphqler-fuzzer
# run: |
# poetry run python ./graphqler --mode compile --url http://127.0.0.1:3000/graphql --path ${{ github.workspace }}/graphqlerOutput

# - name: Print the Graphqler configuration
# run: |
# ls -la ${{ github.workspace }} || true
# ls -la ${{ github.workspace }}/graphqlerOutput || true
# ls -la ${{ github.workspace }}/graphqlerOutput/compiled || true
# echo ""
# echo "############################################"
# echo "# Engine settings #"
# echo "# To customize, copy and save this file to #"
# echo "# setup/fuzzer/settings.graphqler.json #"
# echo "############################################"
# echo ""
# cat ${{ github.workspace }}/graphqlerOutput/compiled/engine_settings.json
# - name: Save Graphqler Config
# if: steps.cache-config-restore.outputs.cache-hit != 'true'
# id: cache-config-save
# uses: actions/cache/save@v4
# with:
# path: |
# ${{ github.workspace }}/graphqlerOutput
# key: ${{ steps.cache-config-restore.outputs.cache-primary-key }}

- name: Run Graphqler fuzz test
working-directory: ${{ github.workspace }}/graphqler-fuzzer
run: |
poetry run python ./graphqler --mode run --url http://127.0.0.1:3000/graphql --path ${{ github.workspace }}/graphqlerOutput --auth 'Bearer 103b2cf86168ec87fc6ec88978455667feb0f08d12' --config ${{ github.workspace }}/speckle-server/setup/fuzzer/config.graphqler.toml

- name: Print the results
if: always()
run: |
ls -la ${{ github.workspace }}/graphqlerOutput
ls -la ${{ github.workspace }}/graphqlerOutput/logs || true
echo ""
echo "############################################"
echo "# Status.txt #"
echo "############################################"
echo ""
cat ${{ github.workspace }}/graphqlerOutput/stats.txt || true
echo ""
echo "############################################"
echo "# ./logs/fuzzer.log #"
echo "############################################"
echo ""
cat ${{ github.workspace }}/logs/fuzzer.log || true

- uses: actions/upload-artifact@v4
name: Store the Test output
if: always()
with:
name: fuzz-test-graphql-api-output
path: ${{ github.workspace }}/graphqlerOutput
if-no-files-found: error
retention-days: 5
overwrite: true

- name: Print Docker Compose logs
if: always()
run: |
docker compose --file ${{ github.workspace }}/speckle-server/docker-compose-deps.yml logs
docker compose --file ${{ github.workspace }}/speckle-server/setup/fuzzer/docker-compose-speckle.yml logs
3 changes: 2 additions & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"migrate": "yarn cli db migrate",
"migrate:test": "cross-env NODE_ENV=test ts-node ./modules/cli/index.js db migrate",
"gqlgen": "graphql-codegen --config codegen.yml",
"gqlgen:watch": "graphql-codegen --config codegen.yml --watch \"assets/**/*.graphql\""
"gqlgen:watch": "graphql-codegen --config codegen.yml --watch \"assets/**/*.graphql\"",
"start": "cross-env NODE_ENV=production LOG_PRETTY=true node ./bin/ts-www"
},
"dependencies": {
"@apollo/client": "^3.7.0",
Expand Down
44 changes: 44 additions & 0 deletions setup/fuzzer/config.graphqler.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Configuration

# For debugging purposes
DEBUG = false

# For clairvoyance
WORDLIST_PATH = "static/wordlist.txt"

# For the resolver
MAX_LEVENSHTEIN_THRESHOLD = 20 # A very high threshold, we could probably lower this, but this almost guarantees us to find a matching object name - ID

# For the linker
GRAPH_VISUALIZATION_OUTPUT = "dependency_graph.png"

# For materializers
MAX_OBJECT_CYCLES = 3
MAX_OUTPUT_SELECTOR_DEPTH = 3
HARD_CUTOFF_DEPTH = 20
MAX_INPUT_DEPTH = 20

# For using GraphQLer in different modes
USE_OBJECTS_BUCKET = true # This mode is for when we want to use the objects bucket
USE_DEPENDENCY_GRAPH = true # This mode is for when we want to use DFS through the dependency graph
NO_DATA_COUNT_AS_SUCCESS = false # This mode is for when we want to count no data in the data object as a success or failure

# For fuzzing
ALLOW_DELETION_OF_OBJECTS = false # This mode is for when we want to allow the deletion of objects from the objects bucket when coming across a DELETE mutation success
MAX_FUZZING_ITERATIONS = 5
MAX_TIME = 180 # in seconds
SKIP_MAXIMAL_PAYLOADS = false # This mode is for when we want to skip the maximal payloads
SKIP_DOS_ATTACKS = true # This mode is for when we want to skip the DoS check
SKIP_INJECTION_ATTACKS = false # This mode is for when we want to skip the injection check
SKIP_MISC_ATTACKS = false # This mode is for when we want to skip the miscellaneous attacks

# For each request
REQUEST_TIMEOUT = 30 # in seconds
TIME_BETWEEN_REQUESTS = 0.001 # in seconds

# For custom skipping specific nodes"""
SKIP_NODES = []

# Put custom headers here
[CUSTOM_HEADERS]
Accept = "application/json"
53 changes: 53 additions & 0 deletions setup/fuzzer/docker-compose-speckle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
version: '2.4'
services:
speckle-server:
platform: linux/amd64
image: speckle/speckle-server:latest
restart: always
ports:
- '0.0.0.0:3000:3000'
healthcheck:
test:
- CMD
- /nodejs/bin/node
- -e
- "try { require('node:http').request({headers: {'Content-Type': 'application/json'}, port:3000, hostname:'127.0.0.1', path:'/readiness', method: 'GET', timeout: 2000 }, (res) => { body = ''; res.on('data', (chunk) => {body += chunk;}); res.on('end', () => {process.exit(res.statusCode != 200 || body.toLowerCase().includes('error'));}); }).end(); } catch { process.exit(1); }"
interval: 10s
timeout: 10s
retries: 3
start_period: 90s
environment:
PORT: 3000

CANONICAL_URL: 'http://127.0.0.1:3000'
SESSION_SECRET: '-> FILL IN <-'

REDIS_URL: 'redis://redis:6379'

USE_FRONTEND_2: true
FRONTEND_ORIGIN: 'http://127.0.0.1:8081'

ENABLE_FE2_MESSAGING: false

POSTGRES_URL: 'postgres'
POSTGRES_USER: 'speckle'
POSTGRES_PASSWORD: 'speckle'
POSTGRES_DB: 'speckle'

S3_ENDPOINT: 'http://minio:9000'
S3_ACCESS_KEY: 'minioadmin'
S3_SECRET_KEY: 'minioadmin'
S3_BUCKET: 'speckle-server'
S3_CREATE_BUCKET: 'true'

EMAIL: false

DISABLE_NOTIFICATIONS_CONSUMPTION: true
STRATEGY_LOCAL: true
RATELIMITER_ENABLED: false
networks:
- speckle-server_default

networks:
speckle-server_default:
external: true
Loading
Loading