Skip to content

sequentech/step

Repository files navigation

Sequent Voting Platform

Chat Build Status License REUSE Documentation

Sequent Voting Platform is an end-to-end verifiable, secure, and transparent online voting system. This monorepo contains the second generation of the platform, designed for real-world elections with strong cryptographic guarantees.

Key Features

  • End-to-end verifiability: Voters can verify their vote was recorded, tallied, and counted correctly
  • Privacy-preserving: Cryptographic mixnet ensures ballot secrecy while maintaining verifiability
  • Multi-tenant: Support for multiple organizations and simultaneous elections
  • Accessible: Web-based interfaces optimized for accessibility and usability
  • Auditable: Comprehensive tamper-evident logging of all system operations

Technology Stack

  • Hasura - GraphQL API layer
  • Rust - Cryptographic core and backend services
  • Keycloak - Identity and access management
  • PostgreSQL - Data persistence
  • React - Frontend user interfaces
  • ImmuDB - Tamper-evident audit logging

Getting Started

For comprehensive documentation, visit docs.sequentech.io.

Quick Start with Dev Containers

The fastest way to start developing is using VS Code Dev Containers or GitHub Codespaces:

  1. Clone this repository
  2. Open in VS Code with Dev Containers extension
  3. All services will start automatically

The development environment includes:

For detailed setup instructions, see the Documentation.

Manual Setup

If you prefer not to use Dev Containers:

  1. Install prerequisites: Rust, Node.js/Yarn, Docker, PostgreSQL
  2. Set up environment variables (see .env.example)
  3. Start services: docker compose up -d
  4. Run migrations: cd hasura && hasura migrate apply
  5. Start frontend: cd packages && yarn && yarn dev

See the Documentation for detailed instructions.

Repository Structure

.
├── .devcontainer/          # Dev container configuration
├── docs/docusaurus/        # Documentation site
├── hasura/                 # GraphQL schema, migrations, and metadata
├── packages/               # Monorepo packages (Cargo + Yarn workspace)
│   ├── admin-portal/       # Admin interface (React)
│   ├── voting-portal/      # Voter interface (React)
│   ├── braid/              # Cryptographic mixnet (Rust)
│   ├── sequent-core/       # Shared core libraries (Rust)
│   ├── ui-essentials/      # Shared UI components
│   └── ...                 # Other packages
└── README.md

The packages/ directory is both a Cargo workspace and a Yarn workspace, enabling code sharing between frontend (compiled to WebAssembly) and backend (native Rust).

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

This project is licensed under the AGPL-3.0-only license. See LICENSE for details.

Support


Developer Reference

For detailed developer documentation including advanced setup, architecture details, and troubleshooting, see the sections below or visit the complete documentation.

Docker services logs

We have configured the use of direnv and devenv in this dev container, and doing so in the devenv.nix file we configured the COMPOSE_PROJECT_NAME=step_devcontainer env variable for convenience and some utility packages automatically installed like ack or docker.

Given that, you can then for example watch the log output of the frontend docker compose service with:

docker compose logs -f frontend

And do the same for the other services. You could also do anything docker-compose allows for example list running commands withdocker compose ps.

With regards to the logs, we have configured in .vscode/tasks.json to automatically run docker compose logs on start up, for convenience.

Immudb

You can enter the Immudb web console at http://localhost:3325 and the user/pass is immudb:immudb.

Keycloak default realms

The deployment has 2 default Keycloak realms created by default, one for the default tenant and another for the default election event inside that tenant.

Those two realms are automatically imported into Keycloak in the Dev Containers from the .devcontainer/keycloak/import/ directory.

Additionally, each tenant and election event have an associated realm. In the Dev Containers, we use the same .devcontainer/keycloak/import/ files to be the templates for the creation of realms associated to a new tenant or a new election event. These realms are created if they don't exist when the keycloak container is started.

If you change the configuration of the default tenant realm and want to update it in .devcontainer/keycloak/import/ to be used for the default tenant and as a template for new tenants, you can export it running the following commands:

export REALM="tenant-90505c8a-23a9-4cdf-a26b-4e19f6a097d5"
cd /workspaces/step/.devcontainer
docker compose exec keycloak sh -c "/opt/keycloak/bin/kc.sh export --file /tmp/export.json --users same_file --realm ${REALM}"
docker compose exec keycloak sh -c 'cat /tmp/export.json' > keycloak/import/${REALM}.json

You can change REALM to be "tenant-90505c8a-23a9-4cdf-a26b-4e19f6a097d5-event-33f18502-a67c-4853-8333-a58630663559" to export and update the configuration of the default election event:

export REALM="tenant-90505c8a-23a9-4cdf-a26b-4e19f6a097d5-event-cd1397d3-d236-42b4-a019-49143b616e13"
cd /workspaces/step/.devcontainer
docker compose exec keycloak sh -c "/opt/keycloak/bin/kc.sh export --file /tmp/export.json --users same_file --realm ${REALM}"
docker compose exec keycloak sh -c 'cat /tmp/export.json' > keycloak/import/${REALM}.json

Whenever a realm is updated, there's a chance that the associated JWK used have changed. This JWK is used to verify the JWT that is received from keycloak. These keys are configured in S3/minio in the .devcontainer/minio/certs.json file via the logs.reset.minio helper docker service. If the keys changed and we don't update the keys serviced by minio/s3, then the admin-portal or the voting-booth might show some errors because this JWT verification fails.

To fix this issue, run the VS Code task logs.reset.minio which will:

  1. Fetch JWK certificates from Keycloak realms configured in .devcontainer/keycloak/import/
  2. Update the .devcontainer/minio/certs.json file with the combined certificates
  3. Rebuild and restart the MinIO configuration service
  4. Display the logs for verification

NOTE: that this is a task that is useful only for developers: when you execute it, the certificates from other election events will be removed from certs.json so you will need to re-create the election events.

Add Hasura migrations/changes

If you want to make changes to hasura, or if you want the Hasura console to automatically add migrations to the code, first run this project in Codespaces and open it in VS Code Desktop (not from the web). Then, in your local machine ensure that the graphql-engine server name is aliased to 127.0.0.1 in /etc/hosts, or else this won't work.

Then run the following commands to run the console in port 9695:

cd /workspaces/step/hasura/
hasura console --endpoint "http://graphql-engine:8080" --admin-secret "admin"

Then open http://localhost:9695 on the browser and make the changes you need. Those changes will be tracked with file changes on the Github Codespaces, then commit the changes.

Note that you can insert rows as a migration by clicking on the This is a migration option at the bottom of the Insert Row form.

Note: if the browser doesn't load correctly at http://localhost:9695, try opening the port 9693 in VS Code.

ui-essentials

Contains all the components used across the various portals i.e admin, voting, ballot etc. Has storybook configured for component documentation and easy update of existing components or building new ones

To start storybook,

cd /workspaces/step/packages/
yarn storybook:ui-essentials

After updating any component in ui-essentials, run the following commands to build the current state.

cd /workspaces/step/packages/
yarn prettify:fix:ui-essentials && yarn build:ui-essentials

This is done to allow portals to fetch and use the latest versions of components

Update graphql JSON schema

The file packages/admin-portal/graphql.schema.json contains the GraphQL/Hasura schema. If the schema changes you might need to update this file by running the VS Code task update.graphql.

It might be the case that for example if you added some new field to an existing table, you will have to update some graphql query in packages/windmill/src/graphql/ directory and the corresponding boilerplate code in packages/windmill/src/hasura/. Otherwise the build might fail.

Creating Trustees

By default the trustees in this repo are configured to use a predefined configuration/ set of keys. This is useful for development because these trustees are also added to the hasura/postgres database. This configuration is set using the TRUSTEE_CONFIG environment paramenter in the docker-compose.yml file.

However if you want the trustees to generate their own unique public/private keys and configuration this is is what you need to do:

First unset the TRUSTEE_CONFIG environment variable or set it to a file path that doesn't exist. Then, when the trustee docker container is up, get the keys from the trustee:

docker exec -it trustee1 cat /opt/braid/trustee.toml | grep pk

Which will give a result similar to:

signing_key_pk = "YqYrRVXmPhBsWwwCgsOfw15RwUqZP9EhwmxuHKU5E8k"

Then add the trustee in the admin portal with the key, in this case YqYrRVXmPhBsWwwCgsOfw15RwUqZP9EhwmxuHKU5E8k.

Running Trustees

To run the windmill task generator (beat), use the VS Code task logs.restart.beat.

To run the trustees, use the VS Code task logs.restart.trustees.

## Common issues

Yarn build unexpectedly returns exit code 143

You run out of memory. Run in a bigger codespace or stop some service before proceeding. You can stop for example the frontend with docker compose stop frontend

I changed my Dockerfile or my docker-compose.yml. Can I relaunch it without rebuilding the whole Dev Container?

Yes you can. For example, if you need to apply a new DockerFile o docker-compose.yml config just for the frontend service, you can do the following:

# First rebuild the service from the Dockerfile as indicated in the
# docker-compose.yml, then relaunch just the frontend service
docker compose build frontend && docker compose up -d --no-deps frontend

The hasura schema changed or I want to add a query/mutation to the voting-portal/admin-portal

Add the query/mutation to the packages/voting-portal/src/queries/ folder and then run yarn generate from the packages/ folder to update the types. Similarly, run yarn generate:admin-portal to update the types of the admin-portal if you need it.

The voting portal will not load any elections

It's possible you find that the voting portal is not loading any elections, and that inspecting it further, the Hasura/Graphql POST gives an error similar to field not found in type: 'query_root'. This is possibly because you're connecting to the wrong instance of Hasura. Possibly, you're running VS Code with Codespaces and a local Hasura client as well, so the container port is being forwarded to a different port than 8080.

You get the root does not exist or hasura doesn't start, volumes don't mount

This is a nasty error that we need to further investigate and fix. Typically start happening after the codespace has been stopped and restarted a few times. Currently the only fix we have is.. committing and pushing all your changes to your branch and starting a new codespace.

The disk/codespace runs out of space

Clean the disk with:

docker system prune --all --force
nix-collect-garbage
cargo clean

Fix starting/restarting containers

If you see an error when starting/restarting a container, remove the .docker folder:

rm -rf /home/vscode/.docker/

Commiting with git

Unfortunately commiting with git doesn't work from the devcontainer. To commit to git, ssh into the instance and cd into the step folder, then commit using git.

Can't build sequent-core

If you're getting a permission error when building sequent-core, do:

sudo mkdir /workspaces/step/packages/target
sudo chown vscode:vscode /workspaces/step/packages/target -R

Can't rebuild containers

If you're getting an error of this kind

vscode ➜ /workspaces/step (main) $ devenv shell
• Building shell ...
• Using Cachix: devenv
thread 'main' panicked at /tmp/nix-build-devenv-1.4.0.drv-0/source/devenv/src/cnix.rs:157:40:
to resolve gc_root: Os { code: 2, kind: NotFound, message: "No such file or directory" }
...

when running in the terminal devenv shell or in the Rebuild Container vscode task. This can happen when devenv version was updated but the cache wasn´t, try:

  1. Remove folders step/.direnv and step/.devenv.
  2. Then run Rebuild Container Without Cache.

About

Sequent Step - Secure Online Voting platform by Sequent Tech

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 13