• Joined on 2025-11-02

rust-arch-test-kit (0.3.0)

Published 2026-02-17 21:26:35 +01:00 by mat

Installation

[registry]
default = "gitea"

[registries.gitea]
index = "sparse+" # Sparse index
# index = "" # Git

[net]
git-fetch-with-cli = true
cargo add rust-arch-test-kit@0.3.0

About this package

Architecture test assertions for Rust projects

rust-arch-test-kit

Shared architecture test engine published to the Gitea Cargo registry at git.mialemrobicnic.pl.

Each consumer adds the crate as a dev-dependency from the Gitea registry and keeps policy in architecture-test.toml.

Installation

Add the Gitea registry to .cargo/config.toml:

[registries.gitea]
index = "sparse+https://git.mialemrobicnic.pl/api/packages/mat/cargo/"

Add the dependency to your project's Cargo.toml:

[dev-dependencies]
rust-arch-test-kit = { version = "0.1.0", registry = "gitea" }

Then run architecture tests via tests/architecture.rs.

Authentication (local development)

Cargo needs a token to pull from the private Gitea registry. Use Bitwarden CLI to keep the token out of files.

  1. Store your Gitea API token in Bitwarden as an item named gitea-cargo-token (use the password field).

  2. Add to your ~/.zshrc:

# Gitea Cargo registry auth (loaded from Bitwarden)
export CARGO_REGISTRIES_GITEA_TOKEN="Bearer $(bw get password 'gitea-cargo-token' 2>/dev/null)"
  1. Reload your shell:
source ~/.zshrc

Note: bw get requires an unlocked session. If the token is empty, unlock first:

export BW_SESSION="$(bw unlock --raw)"
source ~/.zshrc

For CI (Gitea Actions), the workflow uses secrets.REGISTRY_PASS — no extra setup needed.


Quick workflow (every architecture change)

  1. Change Rust code.
  2. Update the project architecture-test.toml (if boundaries/API/dependencies changed).
  3. Run architecture tests:
    • cargo test --test architecture
  4. If you changed this kit itself, also run:
    • cd rust-arch-test-kit && cargo test
  5. Push to main/main2 to publish a new version to Gitea.

Where to edit

  • Engine logic: rust-arch-test-kit/src/lib.rs
  • Engine behavior tests: rust-arch-test-kit/tests/rules.rs
  • Project policy:
    • agent-dev-tools/agent-cli/architecture-test.toml
    • voice-tools/voice-lib/architecture-test.toml
  • Project test entrypoint:
    • agent-dev-tools/agent-cli/tests/architecture.rs
    • voice-tools/voice-lib/tests/architecture.rs

Rule types (typed configuration)

Use [[rules]] with type = "...".

forbid_dependency

Blocks internal module dependency direction.

[[rules]]
type = "forbid_dependency"
from = ["core"]
forbid = ["tauri"]

allow_dependencies

Allowlist-style internal module dependencies.

[[rules]]
type = "allow_dependencies"
from = ["application"]
allow = ["domain", "shared"]

no_cycles

Fails when dependency cycle exists across selected top-level modules.

[[rules]]
type = "no_cycles"
modules = ["commands", "config", "projects"]

If modules is omitted/empty, it checks all discovered modules.

public_api_allowlist

Restricts public modules/re-exports from lib.rs / main.rs.

[[rules]]
type = "public_api_allowlist"
allowed = ["core", "tauri"]

forbid_external_crates

Blocks usage of specific external crates from selected modules.

[[rules]]
type = "forbid_external_crates"
from = ["core"]
forbid = ["tauri", "tauri_plugin_*"]

feature_boundary

Enforces feature-gated module boundaries.

[[rules]]
type = "feature_boundary"
feature = "tauri"
gated_modules = ["tauri"]
allowed_from = ["root", "tauri"]

Checks:

  • selected modules may only be used by allowed modules
  • selected module declarations in root files are guarded by cfg(feature = "...")

manifest_integrity

Checks package-level policy from Cargo.toml.

[[rules]]
type = "manifest_integrity"
require_publish = false
forbidden_dependencies = ["tauri"]
required_features = ["tauri"]

Pattern matching rules

Patterns support:

  • exact match: "core"
  • wildcard all: "*"
  • prefix match: "tauri*"

Applies to module names and dependency names in rule fields.


Dependency graph visualization

Generate a visual dependency graph from the same config used by architecture tests.

use rust_arch_test_kit::dependency_graph;
use std::path::Path;

let graph = dependency_graph(Path::new("architecture-test.toml")).unwrap();

// Graphviz DOT output
println!("{}", graph.to_dot());

// Mermaid output
println!("{}", graph.to_mermaid());

The returned DependencyGraph contains:

  • modules — all discovered top-level modules
  • internal_edges — module-to-module dependencies (crate::*)
  • external_edges — module-to-external-crate dependencies
  • violations — edges that violate configured rules (Vec<EdgeViolation>)

Violation edges are rendered as red/dashed in DOT and dashed arrows (-.->) in Mermaid. External crates appear in a separate cluster/subgraph.

Edge-level rules that produce violations: forbid_dependency, allow_dependencies, no_cycles, forbid_external_crates, feature_boundary. Node-level rules (public_api_allowlist, manifest_integrity) do not produce graph violations.


Important model limitation

The analyzer currently works on top-level module boundaries:

  • internal dependency = first segment after crate::
  • file ownership = first folder under src/ (or root file stem)

Example: crate::core::asr_client::HttpAsrClient is treated as dependency on core.

Design policies should therefore be expressed at top-level module granularity.


Adding a new module (maintenance checklist)

When adding module X in a project:

  1. Add module in code (mod/pub mod) and file structure.
  2. Decide boundary direction:
    • add/update forbid_dependency (or allow_dependencies) rules.
  3. Add module to cycle checks if it should stay acyclic (no_cycles).
  4. If X is public from root (pub mod or pub use), update public_api_allowlist.
  5. If X is feature-gated:
    • guard declaration in root file with #[cfg(feature = "...")]
    • update/add feature_boundary
    • ensure feature exists in Cargo.toml (manifest_integrity.required_features).
  6. Run architecture test for that project.

Adding new public API (maintenance checklist)

When exposing new public API from root:

  1. Add pub mod ... or pub use ... in lib.rs/main.rs.
  2. Update public_api_allowlist.allowed.
  3. Ensure exported module does not violate dependency rules.
  4. Run architecture test.

If exposure is temporary/experimental, keep it behind a feature and enforce via feature_boundary.


Extending this kit with a new rule type

  1. Add variant in TypedRuleConfig.
  2. Implement checker function.
  3. Wire it in apply_rule.
  4. Add focused fixture test in rust-arch-test-kit/tests/rules.rs.
  5. Run cargo test in rust-arch-test-kit.

Do not add project-specific behavior in the engine. Keep project differences in TOML config.


Current project notes

  • agent-dev-tools/agent-cli has an existing orchestration <-> sessions cycle, so its no_cycles rule currently targets foundational modules only.

Keep these intentional constraints explicit in config comments when they change.

Dependencies

ID Version
serde ^1
syn ^2
toml ^0.8
walkdir ^2.5
tempfile ^3.24.0
Details
Cargo
2026-02-17 21:26:35 +01:00
44
MIT
17 KiB
Assets (1)
Versions (3) View all
0.3.0 2026-02-17
0.2.0 2026-02-17
0.1.0 2026-02-15