Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
41 changes: 29 additions & 12 deletions .github/regression.sh
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ elif is_truthy "${CI_BYRON_CLUSTER:-}"; then
export TESTNET_VARIANT="${CLUSTER_ERA:-conway}_slow"
fi

export CARDANO_NODE_SOCKET_PATH_CI="$WORKDIR/state-cluster0/bft1.socket"
CARDANO_NODE_SOCKET_PATH_CI="${CARDANO_NODE_SOCKET_PATH_CI:-$WORKDIR/state-cluster0/bft1.socket}"
export CARDANO_NODE_SOCKET_PATH_CI

# assume we run tests on testnet when `BOOTSTRAP_DIR` is set
if [ -n "${BOOTSTRAP_DIR:-}" ]; then
Expand Down Expand Up @@ -115,16 +116,25 @@ case "${CARDANO_CLI_REV:-}" in
esac

# setup cardano-node binaries
case "${NODE_REV:-}" in
"" | "none" )
NODE_REV=master
;;
esac
# shellcheck disable=SC1091
. .github/source_cardano_node.sh
cardano_bins_build_all "$NODE_REV" "${CARDANO_CLI_REV:-}"
PATH_PREPEND="$(cardano_bins_print_path_prepend "${CARDANO_CLI_REV:-}")${PATH_PREPEND}"
export PATH_PREPEND
if [ -n "${CARDANO_PREBUILT_DIR:-}" ]; then
# Pre-built binaries were baked into the image (e.g. for Antithesis).
# Skip all nix builds and point PATH_PREPEND at the pre-built directories.
_d="${CARDANO_PREBUILT_DIR}"
PATH_PREPEND="${_d}/cardano-node/bin:${_d}/cardano-submit-api/bin:${_d}/cardano-cli/bin:${_d}/bech32/bin:${PATH_PREPEND}"
export PATH_PREPEND
unset _d
else
case "${NODE_REV:-}" in
"" | "none" )
NODE_REV=master
;;
esac
# shellcheck disable=SC1091
. .github/source_cardano_node.sh
cardano_bins_build_all "$NODE_REV" "${CARDANO_CLI_REV:-}"
PATH_PREPEND="$(cardano_bins_print_path_prepend "${CARDANO_CLI_REV:-}")${PATH_PREPEND}"
export PATH_PREPEND
fi

# optimize nix store if running in GitHub Actions
if [ -n "${GITHUB_ACTIONS:-}" ]; then
Expand Down Expand Up @@ -254,7 +264,14 @@ nix develop --accept-flake-config .#testenv --command bash -c '

echo "::group::Python venv setup"
printf "start: %(%H:%M:%S)T\n" -1
. .github/setup_venv.sh clean
# When _VENV_DIR points to a pre-built venv (e.g. baked into the image for
# Antithesis), skip the `clean` flag so the existing venv is reused as-is
# without re-downloading packages.
if [ -n "${_VENV_DIR:-}" ] && [ -e "${_VENV_DIR}" ]; then
. .github/setup_venv.sh
else
. .github/setup_venv.sh clean
fi
echo "::endgroup::" # end group for "Python venv setup"

echo "::group::🧪 Testrun"
Expand Down
76 changes: 76 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Dockerfile for cardano-node-tests (Antithesis-compatible driver image)
#
# All heavy dependencies are baked in at image build time so the container
# runs without any network access (required by Antithesis environments).
#
# Build args:
# GIT_REVISION — git commit hash stored as $GIT_REVISION in the image
# NODE_REV — cardano-node git ref to pre-build (default: master)
#
# Build and push to GHCR before submitting to Antithesis:
# docker build -f docker/Dockerfile \
# --build-arg GIT_REVISION=$(git rev-parse HEAD) \
# --build-arg NODE_REV=master \
# -t ghcr.io/saratomaz/cardano-node-tests-antithesis:latest .
# docker push ghcr.io/saratomaz/cardano-node-tests-antithesis:latest

FROM nixos/nix:2.25.5

ARG GIT_REVISION
ARG NODE_REV=master

ENV GIT_REVISION=${GIT_REVISION}
# Store the baked-in node revision for reference at runtime.
ENV BAKED_NODE_REV=${NODE_REV}

# Configure Nix with IOG binary cache and required experimental features.
RUN mkdir -p /etc/nix && \
printf 'extra-substituters = https://cache.iog.io\n\
extra-trusted-public-keys = hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=\n\
experimental-features = nix-command flakes\n\
accept-flake-config = true\n' >> /etc/nix/nix.conf

WORKDIR /work
COPY . /work/

# Pre-build cardano-node, cardano-submit-api, cardano-cli, and bech32 into /opt/cardano/.
# NODE_REV is fixed at image build time — no network access is needed at runtime.
RUN mkdir -p /opt/cardano && \
nix build \
--accept-flake-config --no-write-lock-file \
"github://github.com/IntersectMBO/cardano-node?ref=${NODE_REV}#cardano-node" \
-o /opt/cardano/cardano-node && \
nix build \
--accept-flake-config --no-write-lock-file \
"github://github.com/IntersectMBO/cardano-node?ref=${NODE_REV}#cardano-submit-api" \
-o /opt/cardano/cardano-submit-api && \
nix build \
--accept-flake-config --no-write-lock-file \
"github://github.com/IntersectMBO/cardano-node?ref=${NODE_REV}#cardano-cli" \
-o /opt/cardano/cardano-cli && \
nix build \
--accept-flake-config --no-write-lock-file \
"github://github.com/IntersectMBO/cardano-node?ref=${NODE_REV}#bech32" \
-o /opt/cardano/bech32

# Pre-warm the testenv dev shell (pulls nixpkgs, postgres, uv, python313 into the
# nix store) and create the Python venv at /opt/tests-venv with all project
# dependencies installed. This is the same step regression.sh does at runtime
# but done here so no pip/uv network calls are needed in the Antithesis env.
RUN nix develop --accept-flake-config .#testenv --command \
bash -c 'python3 -m venv /opt/tests-venv --prompt tests-venv && \
. /opt/tests-venv/bin/activate && \
cd /work && \
uv sync --active --no-dev'

# Pre-warm the base dev shell (bash, coreutils, git, jq, …) so its store
# paths are cached and the regression.sh shebang resolves offline.
RUN nix develop --accept-flake-config .#base --command true

# Create the Antithesis test driver directory and install the entry-points.
# singleton_driver_* files are run once per test run by Antithesis.
RUN mkdir -p /opt/antithesis/test/v1/quickstart && \
cp /work/docker/antithesis_run.sh \
/opt/antithesis/test/v1/quickstart/singleton_driver_regression.sh && \
chmod +x /opt/antithesis/test/v1/quickstart/singleton_driver_regression.sh && \
chmod +x /work/docker/node_run.sh
13 changes: 13 additions & 0 deletions docker/Dockerfile.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Config image for Antithesis.
#
# Contains only the docker-compose.yaml that tells Antithesis how to run
# the services. Must be pushed to the Antithesis registry alongside the
# driver image.
#
# Build:
# docker build -f docker/Dockerfile.config \
# -t us-central1-docker.pkg.dev/<tenant>/antithesis/config:latest .
# docker push us-central1-docker.pkg.dev/<tenant>/antithesis/config:latest

FROM scratch
COPY docker/docker-compose.yaml /docker-compose.yaml
66 changes: 66 additions & 0 deletions docker/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Ignore unnecessary files during Docker build

# Git
.git/
.gitignore

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
*.egg-info/
dist/
build/
*.egg

# Virtual environments
.venv/
venv/
ENV/
env/

# Testing artifacts
run_workdir/
.artifacts/
.cli_coverage/
.reports/
allure-results/
allure-results.tar.xz
testrun-report.*
*.log
*.json.log

# IDE
.idea/
.vscode/
*.swp
*.swo
*~

# Nix
result
result-*

# Documentation
docs/_build/
*.md

# Temporary files
*.tmp
*.bak
.DS_Store

# Scripts output
scripts/destination/
scripts/destination_working/

# Coverage
.coverage
htmlcov/
cli_coverage.json
requirements_coverage.json

# CI specific
.bin/
90 changes: 90 additions & 0 deletions docker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Docker setup for cardano-node-tests (Antithesis)

This directory contains the driver image and compose files for submitting
`cardano-node-tests` to Antithesis.

## How it works

Antithesis environments have **no internet access** at runtime, so all
dependencies are baked into the image at build time:

- `Dockerfile` — builds the driver image. At build time it:
1. Pre-builds `cardano-node`, `cardano-submit-api`, `cardano-cli`, and
`bech32` from `NODE_REV` into `/opt/cardano/` via `nix build`.
2. Pre-warms the `testenv` dev shell and creates the Python venv at
`/opt/tests-venv/` with all project dependencies installed.
3. Pre-warms the `base` dev shell so the `regression.sh` shebang resolves
from the local nix store without network access.
4. Installs `antithesis_run.sh` as the Antithesis test driver at
`/opt/antithesis/test/v1/quickstart/singleton_driver_regression.sh`.

- `antithesis_run.sh` — container entrypoint that:
1. Forces nix into offline mode (`offline = true`).
2. Exports `CARDANO_PREBUILT_DIR=/opt/cardano` and `_VENV_DIR=/opt/tests-venv`
so `regression.sh` skips all downloads and uses the pre-built artefacts.
3. Emits the Antithesis `setup_complete` lifecycle signal.
4. Hands off to `.github/regression.sh`.

- `Dockerfile.config` — builds the Antithesis config image (`FROM scratch`)
containing only `docker-compose.yaml`.

- `docker-compose.yaml` — two services: `node` (cardano-node cluster) and
`driver` (pytest). Both share a `cluster-state` Docker volume so the
driver accesses the node sockets without going over the network. An HTTP
health check on port 8090 provides cross-container traffic that satisfies
the Antithesis "Containers joined the Antithesis network" property.

## Workflow

### 1. Build and push the driver image

```bash
docker build -f docker/Dockerfile \
--build-arg GIT_REVISION=$(git rev-parse HEAD) \
--build-arg NODE_REV=master \
-t ghcr.io/saratomaz/cardano-node-tests-antithesis:latest .

docker push ghcr.io/saratomaz/cardano-node-tests-antithesis:latest
```

`NODE_REV` is locked at build time — the same binaries are used every run
regardless of what is on the `master` branch when the container starts.

### 2. Build and push the config image

```bash
docker build -f docker/Dockerfile.config \
-t us-central1-docker.pkg.dev/<tenant>/antithesis/config:latest .

docker push us-central1-docker.pkg.dev/<tenant>/antithesis/config:latest
```

### 3. Validate locally (internet-connected build, isolated network at runtime)

```bash
docker compose -f docker/docker-compose.yaml config
docker compose -f docker/docker-compose.yaml up --build
```

To fully simulate the Antithesis no-internet constraint, run inside an
isolated network namespace on Linux:

```bash
unshare -n docker compose -f docker/docker-compose.yaml up
```

## Environment variables

`NODE_REV` is baked into the image at build time and must **not** be set at
runtime. All other variables are passed through docker-compose as before.

| Variable | Default | Description |
|-------------------|------------|------------------------------------------|
| `CARDANO_CLI_REV` | (built-in) | cardano-cli revision, empty = use node's |
| `DBSYNC_REV` | (disabled) | db-sync revision, empty = disabled |
| `RUN_TARGET` | `tests` | `tests`, `testpr`, or `testnets` |
| `MARKEXPR` | | pytest marker expression |
| `CLUSTERS_COUNT` | | number of local cluster instances |
| `CLUSTER_ERA` | | e.g. `conway` |
| `PROTOCOL_VERSION`| | e.g. `11` |
| `UTXO_BACKEND` | | e.g. `disk`, `mem` |
Loading