synta 0.1.12

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# Deployment Guide

<!-- toc -->
<!-- /toc -->

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

| Group | Jobs |
|-------|------|
| 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

| RPM | Contents |
|-----|---------|
| `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

1. Bump the `%global version` in each `*.spec.in`.
2. Re-run `make sources` to re-vendor the updated `Cargo.lock`.
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