# Deployment Guide
This guide covers building, packaging, and publishing Synta across its three
distribution channels: the Rust `crates.io` registry, the Python `PyPI` package,
and Fedora/RHEL RPM packages. It also documents the CI pipeline that gates
every merge.
---
## CI Pipeline
Synta uses GitHub Actions (`.github/workflows/ci.yml`). The same checks can
be run locally via `./contrib/ci/local-ci.sh`.
### Gate: every pull request
| Build | `build` (debug + release + cbuild) |
| Lint | `fmt`, `clippy` (`-D warnings`), `ruff`, `toc`, `lint-workflows` |
| Documentation | `doc`, `doc-c`, `doc-rust`, `doc-python` |
| Tests | `test`, `c-test`, `python-test`, `test-codegen`, `test-certificate`, `test-krb5`, `test-mtc`, `test-limbo`, `test-serde` |
| Benchmarks | `bench` (compile-only, no regression gate) |
All jobs must be green before a PR can be merged.
### Running CI locally
```bash
# Full suite (mirrors CI exactly)
./contrib/ci/local-ci.sh all
# Only linting and formatting
./contrib/ci/local-ci.sh fmt clippy ruff
# Only tests
./contrib/ci/local-ci.sh test python-test c-test
# Keep CI artefacts separate from your incremental build
CARGO_TARGET_DIR=/tmp/synta-ci ./contrib/ci/local-ci.sh all
```
---
## Building from Source
### Rust library
```bash
# Debug build (all crates)
cargo build --workspace
# Release build
cargo build --release --workspace
# Only the core parser
cargo build -p synta
# Only the PKI crate
cargo build -p synta-certificate
```
### C shared library (`libcsynta`)
Requires `cargo-c` (`cargo install cargo-c`):
```bash
cargo cbuild --release -p synta-ffi
# Produces:
# target/<triple>/release/libcsynta.so.0
# include/synta.h
# csynta.pc
```
### Python extension
Requires `maturin` (`pip install maturin`) and Python 3.8+:
```bash
cd synta-python
maturin build --release
# Produces a wheel in target/wheels/
# For development (editable install in current venv):
maturin develop
```
### NSS backend
To build with the NSS crypto backend instead of OpenSSL, install
`libnss3-dev` (Debian/Ubuntu) or `nss-devel` (Fedora/RHEL) and pass
the feature flags:
```bash
cargo build --no-default-features --features nss -p synta-ffi
cargo build --no-default-features --features nss -p synta-certificate
```
---
## HSM / PKCS#11 Key Storage
`BackendPrivateKey::from_pkcs11_uri()` loads private keys from any PKCS#11
token — hardware HSMs, smart cards, or software tokens — without extracting
key material into process memory. Signing operations are delegated to the
token for the full lifetime of the `BackendPrivateKey`.
> **Note:** `BackendPrivateKey::pkcs8_der` is always empty for HSM-backed keys.
> Never attempt to serialise an HSM key via `pkcs8_der`.
### OpenSSL backend setup
The OpenSSL backend (`--features openssl`) uses `OSSL_STORE_open_ex` with the
process-default libctx. The `pkcs11-provider` OpenSSL provider must be
configured before any call to `from_pkcs11_uri`.
1. **Install the provider.**
On Fedora/RHEL:
```bash
sudo dnf install openssl-pkcs11
```
On Debian/Ubuntu, install `libpkcs11-provider` or build from source.
2. **Create an `openssl.cnf` that loads the provider.**
```ini
openssl_conf = openssl_init
[openssl_init]
providers = provider_sect
[provider_sect]
default = default_sect
pkcs11 = pkcs11_sect
[default_sect]
activate = 1
[pkcs11_sect]
module = /usr/lib64/ossl-modules/pkcs11.so
activate = 1
```
3. **Point the process at the configuration file** before calling any
`synta-certificate` code:
```bash
export OPENSSL_CONF=/etc/synta/openssl.cnf
```
4. **Use the URI.** No URI attributes are mandatory for the OpenSSL backend,
but including `token=`, `object=`, and `type=private` avoids ambiguity:
```
pkcs11:token=<label>;object=<key-label>;type=private?pin-value=<pin>
```
### NSS backend setup
The NSS backend (`--features nss`) uses `PK11_ListPrivKeysInSlot` (exported
from `libnss3.so` since NSS 3.4). Both `token=` and `object=` URI attributes
are **mandatory** for the NSS backend.
1. **Install NSS tools.**
On Fedora/RHEL:
```bash
sudo dnf install nss-tools
```
On Debian/Ubuntu: `sudo apt install libnss3-tools`
2. **Create an NSS database.**
```bash
mkdir -p /etc/synta/nssdb
certutil -N -d /etc/synta/nssdb --empty-password
```
3. **Register the PKCS#11 module.**
```bash
modutil -dbdir /etc/synta/nssdb \
-add MyHSM \
-libfile /path/to/hsm.so \
-force
```
4. **Initialize NSS** with the database in your application before calling any
`synta-certificate` code. The exact call depends on your integration, but
the database path passed to `NSS_Init` must match the directory used above.
5. **Use the URI.** Both `token=` and `object=` are mandatory:
```
pkcs11:token=<label>;object=<key-label>;type=private?pin-value=<pin>
```
### Example using kryoptic (software token for testing)
[kryoptic](https://github.com/latchset/kryoptic) is a pure-Rust PKCS#11
software token useful for local development and CI testing.
```bash
# Initialize token
pkcs11-tool --module libkryoptic_pkcs11.so --init-token \
--label MyToken --so-pin sopin
pkcs11-tool --module libkryoptic_pkcs11.so --init-pin \
--token-label MyToken --so-pin sopin --pin 1234
# Generate an EC key pair (prime256v1)
pkcs11-tool --module libkryoptic_pkcs11.so --keypairgen \
--key-type EC:prime256v1 \
--label cakey --usage-sign \
--token-label MyToken --pin 1234
# The URI to pass to from_pkcs11_uri:
# pkcs11:token=MyToken;object=cakey;type=private?pin-value=1234
```
See [testing-guide.md](testing-guide.md#pkcs11--hsm-integration-test-kryoptic)
for the full integration test instructions.
---
## Publishing Rust Crates to crates.io
The `contrib/release/release.py` script automates the full release cycle.
### Phase 1 — Prepare
```bash
# Preview changelog + version bump to 0.2.0 (no writes)
./contrib/release/release.py 0.2.0
# Commit changelogs, bump versions, and tag
./contrib/release/release.py --do-run 0.2.0
```
This creates a release commit, updates `Cargo.toml` versions in all crates,
and generates a git tag. Open a PR so the changelog commit can be reviewed
before publishing.
### Phase 2 — Publish
After the PR is merged:
```bash
./contrib/release/release.py --publish
```
Crates are published in dependency order (defined in `contrib/release/publish-order`):
```
synta
synta-derive
synta-codegen
synta-certificate
synta-krb5
synta-mtc
synta-x509-verification
```
`synta-ffi`, `synta-python*`, `synta-bench`, `synta-fuzz`, and `synta-tools`
are **not** published to crates.io (`publish = false` in their `Cargo.toml`).
---
## Fedora / RHEL RPM Packaging
RPM spec files live in `contrib/packages/`. There are two flavours:
- `synta.spec.in` — the monolithic workspace spec (used historically)
- `rust-synta*.spec.in` — per-crate specs following the Fedora Rust Packaging Guidelines
### Prerequisites
```bash
sudo dnf install git cargo rpmbuild rpmlint cbindgen cargo-c \
python3-devel python3-pip
# For mock builds:
sudo dnf install mock
sudo usermod -aG mock $USER # then log out and back in
```
### Building RPMs
```bash
cd contrib/packages
# 1. Prepare source tarballs and vendor archive
make sources
# 2. Build SRPM
make srpm
# 3. Test-build in a mock Fedora chroot
make mock
# 4. Check spec for policy issues
rpmlint *.spec
```
### Binary packages produced
| `libcsynta` | C FFI shared library (`libcsynta.so.0`) |
| `libcsynta-devel` | C header (`synta.h`) and pkg-config file |
| `python3-synta` | Python extension (PyO3 ABI3-compatible, Python ≥ 3.8) |
| `rust-synta-devel` | Core crate sources in the system Cargo registry |
| `rust-synta-certificate-devel` | X.509 / PKI crate sources |
| `rust-synta-krb5-devel` | Kerberos V5 crate sources |
| `rust-synta-derive-devel` | Derive proc-macro crate sources |
| `rust-synta-codegen-devel` | ASN.1-to-Rust generator crate sources |
| `rust-synta-mtc-devel` | Merkle Tree Certificates crate sources |
| `rust-synta-x509-verification-devel` | RFC 5280 path validation crate sources |
### Updating for a new release
The `Version:` field in `synta.spec.in` and `python3-synta.spec.in` is bumped
automatically by `contrib/release/release.py` as part of every version bump;
no manual edits to the spec templates are needed before running the release script.
After `release.py` has committed and tagged the new version:
1. Re-run `make sources` to re-vendor the updated `Cargo.lock`.
2. Add a `%changelog` entry to each `*.spec.in` for this release.
3. Build and test with `make mock`.
4. Submit the updated spec files to the Fedora package repository.
---
## Python Package (PyPI)
The Python package is built via `maturin` and published to PyPI as `synta`.
```bash
cd synta-python
# Build a release wheel for the current platform
maturin build --release
# Build ABI3 universal wheels (requires zig for cross-compilation):
maturin build --release --zig
# Publish to PyPI (requires API token in MATURIN_PYPI_TOKEN or ~/.pypirc)
maturin publish
```
The wheel targets Python ≥ 3.8 via PyO3's `abi3` feature. The
`[tool.maturin]` section in `synta-python/pyproject.toml` configures the
module name, features, and ABI version.
---
## Versioning Policy
Synta follows [Semantic Versioning](https://semver.org/):
- All publishable crates share the same version number (currently `0.1.x`).
- The `[Unreleased]` section of `CHANGELOG.md` accumulates changes on the
working branch.
- A version bump creates a `vX.Y.Z` git tag and publishes all changed crates.
During the `0.1.x` series, minor breaking changes to internal or C ABI types
(such as `SyntaByteArray` layout changes) are allowed because the crate
version is below `1.0`.
---
## See Also
- [Contributing](contribution.md) — development workflow, CI job reference
- [Testing Guide](testing-guide.md) — how to run and write tests
- [Codebase Summary](codebase-summary.md) — crate inventory
- [System Architecture](system-architecture.md) — build system integration diagram