Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .cf-studio/config/rules/infrastructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Use this when changing build tooling, CI, linting, releases, or dependency polic
## Tooling
- Use `Makefile` targets as the main local automation surface. Evidence: `Makefile:120-173`, `Makefile:218-320`
- Preserve fast PR Clippy and deeper validation split. Evidence: `Makefile:224-246`
- Keep custom Dylint rules aligned with architecture categories. Evidence: `tools/dylint_lints/README.md:16-70`
- Keep custom architecture lints aligned with architecture categories. Run via `cargo gears lint` (lints live in the `cargo-gears` CLI tool).

## CI and Releases
- Preserve cross-OS test matrix and DB integration jobs. Evidence: `.github/workflows/ci.yml:85-220`
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/gear-creator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Create files in this order (each layer builds on the previous):

1. `cargo build -p <gear-crate>` — must compile
2. `cargo clippy -p <gear-crate>` — no warnings
3. `make dylint` — architecture lints pass
3. `cargo gears lint` — architecture lints pass
4. `cargo test -p <gear-crate>` — tests pass

## Workflow: Edit an existing gear
Expand Down
43 changes: 13 additions & 30 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -392,44 +392,30 @@ jobs:
fail_ci_if_error: false
token: ${{ secrets.CODECOV_TOKEN }} # Uncomment if required for private repos

dylint:
Comment thread
maurolacy marked this conversation as resolved.
name: Dylint Tests
lint:
name: Architecture Lints (cargo gears lint)
runs-on: ubuntu-latest
env:
RUSTUP_TOOLCHAIN: nightly-2026-04-16
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Install Rust nightly toolchain
uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # nightly
with:
toolchain: ${{ env.RUSTUP_TOOLCHAIN }}
components: llvm-tools-preview,rustc-dev

- name: Set Rust nightly for Dylint temp builds
run: rustup override set ${{ env.RUSTUP_TOOLCHAIN }} --path /tmp

- name: Install nextest
uses: taiki-e/install-action@6ef672efc2b5aabc787a9e94baf4989aa02a97df # v2.70.3
with:
tool: nextest

- name: Install cargo-dylint and dylint-link from source
run: cargo install --locked cargo-dylint dylint-link
persist-credentials: false

- name: Install protoc
uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Run dylint tests
env:
RUSTFLAGS: "-C debuginfo=0"
run: make dylint-test
- name: Install Rust stable toolchain
uses: dtolnay/rust-toolchain@5b842231ba77f5c045dba54ac5560fed2db780e2 # stable
with:
toolchain: stable

- name: Run dylint on all crates
run: make dylint
- name: Install cargo-gears
run: cargo install --locked cargo-gears
Comment on lines +414 to +415

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Pin the cargo-gears version.

The cargo-gears tool is currently installed dynamically without pinning a specific version. Consequently, the latest published version will be downloaded on every run. This can cause unexpected CI or local build failures if a newly published release of cargo-gears introduces breaking CLI changes or new, stricter architecture lints that the repository currently violates.

  • .github/workflows/ci.yml#L414-L415: update the command to pin a specific version, e.g., cargo install --locked cargo-gears@<version>, to guarantee determinism in the pipeline.
  • Makefile#L141: pin the exact same version here to ensure that developers' local environments identically match the CI behavior.
📍 Affects 2 files
  • .github/workflows/ci.yml#L414-L415 (this comment)
  • Makefile#L141-L141
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 414 - 415, Pin cargo-gears to an
explicit version in the installation command at .github/workflows/ci.yml lines
414-415, and apply the exact same version to the cargo-gears installation
command in Makefile line 141. Preserve the existing --locked behavior so CI and
local development use identical, deterministic tool versions.


- name: Run architecture lints
run: cargo gears lint --dylint

shear:
name: Unused Deps (cargo-shear)
Expand All @@ -453,13 +439,10 @@ jobs:
toolchain: ${{ env.RUSTUP_TOOLCHAIN }}
components: llvm-tools-preview,rustc-dev

- name: Install dylint-link from source
run: cargo install --locked dylint-link

- name: Install cargo-shear
uses: taiki-e/install-action@6ef672efc2b5aabc787a9e94baf4989aa02a97df # v2.70.3
with:
tool: cargo-shear@1.13.1

- name: cargo shear (workspace root + tools/dylint_lints)
- name: cargo shear (workspace root)
run: make shear
69 changes: 63 additions & 6 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,64 @@ make coverage-unit # Run only unit tests with code coverage
make coverage-e2e-local # Run only e2e tests with code coverage
```

### 2.5. Run Fuzzing Tests (Recommended)
### 2.5. Architecture Lints

Architecture lints enforce design boundaries at compile time (DTO placement, domain-layer isolation, contract-layer purity, versioned REST paths, etc.). The lint rules themselves live in the [`cargo-gears` CLI](https://github.com/constructorfabric/cargo-gears); this repository only configures which rules to run and their parameters.

#### Running lints locally

```bash
# Run architecture lints (requires cargo-gears installed via `make setup`)
make dylint

# Equivalent direct invocation
cargo gears lint --dylint
```

Architecture lints also run as part of `make safety` and in the CI pipeline.

#### Configuration files

| File | Purpose |
|------|---------|
| [`Gears.toml`](./Gears.toml) | Top-level manifest: enables/disables the dylint pass, lists rules to **skip** (pre-existing violations not yet fixed) |
| [`dylint.toml`](./dylint.toml) | Rule-specific parameters: allow-lists, thresholds, path exclusions |

#### Adopting a new lint rule in this repository

When a new architecture lint is added to `cargo-gears`, the following steps bring it into `gears-rust`:

1. **Update `cargo-gears`** — install the version that includes the new rule (`cargo install cargo-gears` or pin a specific version).
2. **Run `make dylint`** — see if the new rule produces violations in the current codebase.
3. **Fix or exclude** — either fix all violations, or (for large-scale migrations) add the rule to the `skip` list in `Gears.toml` and/or add path exclusions in `dylint.toml` while tracking the clean-up.
4. **Commit configuration changes** — include `Gears.toml` / `dylint.toml` updates in your PR alongside any code fixes.

> For instructions on **authoring** a new lint rule, see the [Adding a New Lint Rule](https://github.com/constructorfabric/cargo-gears/blob/main/crates/cargo-gears-lints/README.md#adding-a-new-lint-rule) guide in the `cargo-gears` repository.

#### Example: skipping a rule with pre-existing violations

In `Gears.toml`, add the rule ID to the `skip` list:

```toml
[apps.gears-rust.dev.lint.dylint]
enabled = true
skip = [
"de0504_client_versioning", # not yet addressed
"de1101_tests_in_separate_files", # migration in progress
]
```

In `dylint.toml`, use `excluded_paths` for per-rule path-level granularity:

```toml
[cargo-gears-lints]
excluded_paths = [
"libs/toolkit",
"gears/approval-service",
]
```

### 2.6. Run Fuzzing Tests (Recommended)

Before submitting changes to parsers or validation logic, run fuzzing:

Expand Down Expand Up @@ -152,7 +209,7 @@ export RUST_BACKTRACE=full
```


### 2.6. Sign Your Commits (DCO)
### 2.7. Sign Your Commits (DCO)

This project uses the Developer Certificate of Origin (DCO) version 1.1.
- The DCO text is included in `guidelines/DNA/DCO.txt` (Version 1.1). This is the current and widely adopted version; please keep it as 1.1.
Expand All @@ -172,7 +229,7 @@ git config --global format.signoff true
```


### 2.7. Commit Changes
### 2.8. Commit Changes

Follow a structured commit message format:

Expand Down Expand Up @@ -230,7 +287,7 @@ New functionality development:
- Prefer soft-deletion for entities; provide hard-deletion with retention routines
- Include unit tests (and integration tests when relevant)

### 2.8. Push and Create PR
### 2.9. Push and Create PR

```bash
git push origin feature/your-feature-name
Expand Down Expand Up @@ -276,7 +333,7 @@ Brief description of the changes made.
Closes #issue_number
```

### 2.9. Review Process
### 2.10. Review Process

1. **Automated checks** must pass (CI/CD pipeline)
2. **At least one approval** from maintainer required
Expand All @@ -289,7 +346,7 @@ Merge Strategy:
- **Rebase and merge** for simple fixes
- **Merge commit** for release branches

### 2.10. Local PR Review with Constructor Studio
### 2.11. Local PR Review with Constructor Studio

After pushing your PR and waiting for the cloud AI bots (CodeRabbit, Qodo, etc.) to complete their reviews, run a local Constructor Studio review to catch additional issues
before requesting human review:
Expand Down
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ members = [
exclude = ["tools/fuzz"]
resolver = "3"

# Note: dylint_lints is a separate workspace for custom linters
# See tools/dylint_lints/README.md for usage instructions

[workspace.lints.rust]
deprecated = "warn"
non_ascii_idents = "forbid"
Expand Down
25 changes: 25 additions & 0 deletions Gears.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Gears manifest. Used by `cargo gears` CLI for linting and other tasks.
# See https://github.com/constructorfabric/cargo-gears for documentation.

[apps.gears-rust.dev]
config = "lint.yml"
gears = []

Comment on lines +4 to +7

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the location of lint.yml
fd lint.yml

Repository: constructorfabric/gears-rust

Length of output: 182


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the manifest entry and the code that loads its config path
git ls-files 'Gears.toml' 'config/lint.yml' | sed -n '1,20p'
echo '--- Gears.toml ---'
cat -n Gears.toml
echo '--- search for config path handling ---'
rg -n 'config\s*=|lint\.yml|Gears\.toml|cargo-gears|manifest' -S .

Repository: constructorfabric/gears-rust

Length of output: 50385


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the manifest and any path resolution logic for the config field
cat -n Gears.toml
echo '---'
rg -n 'config\s*=|config path|resolve.*config|manifest.*path|from_manifest|PathBuf::from|canonicalize' -S .

Repository: constructorfabric/gears-rust

Length of output: 50385


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- repo files around manifest/gear config ---'
git ls-files | rg '(^|/)(Gears\.toml|Cargo\.toml|.*gear.*|.*manifest.*|.*config.*|src/|crates/)' | head -n 200

echo '--- Gears.toml ---'
cat -n Gears.toml

echo '--- find Rust files mentioning Gears.toml or config field ---'
rg -n --glob '!**/target/**' --glob '!**/*.min.*' --glob '!**/dist/**' --glob '!**/build/**' \
  'Gears\.toml|config\s*=|lint\.yml|cargo-gears|manifest' \
  src .github crates . 2>/dev/null | head -n 200

Repository: constructorfabric/gears-rust

Length of output: 11482


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- repo files around manifest/gear config ---'
git ls-files | rg '(^|/)(Gears\.toml|Cargo\.toml|.*gear.*|.*manifest.*|.*config.*|src/|crates/)' | head -n 200

echo '--- Gears.toml ---'
cat -n Gears.toml

echo '--- find Rust files mentioning Gears.toml or config field ---'
rg -n --glob '!**/target/**' --glob '!**/*.min.*' --glob '!**/dist/**' --glob '!**/build/**' \
  'Gears\.toml|config\s*=|lint\.yml|cargo-gears|manifest' \
  src crates .github 2>/dev/null | head -n 200

Repository: constructorfabric/gears-rust

Length of output: 11482


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'top-level files:\n'
git ls-files | awk -F/ 'NF==1{print}' | sort

printf '\npossible source files:\n'
git ls-files | rg '^(src|crates|apps)/.*\.(rs|toml)$' | head -n 200

printf '\nmanifest-related files:\n'
git ls-files | rg 'Gears\.toml|lint\.yml|Cargo\.toml|manifest' | head -n 200

Repository: constructorfabric/gears-rust

Length of output: 5038


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- exact references to lint.yml / Gears.toml in tracked source ---'
git ls-files '*.rs' '*.toml' | xargs rg -n --no-messages 'Gears\.toml|lint\.yml|config\s*=' | head -n 200

Repository: constructorfabric/gears-rust

Length of output: 22926


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- Rust files mentioning manifest/config logic ---'
git ls-files '*.rs' | xargs rg -n --no-messages 'Gears\.toml|config\s*=|lint\.yml|PathBuf|manifest|toml' | head -n 200

echo '--- tree of likely source roots ---'
fd -t f -d 2 . .

Repository: constructorfabric/gears-rust

Length of output: 20649


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search only Rust sources for manifest/config handling.
rg -n --glob '*.rs' --glob '!**/target/**' \
  'Gears\.toml|config\s*=|lint\.yml|PathBuf::from|canonicalize|manifest' \
  .

Repository: constructorfabric/gears-rust

Length of output: 50385


Point config at config/lint.yml. config = "lint.yml" points at the manifest root, but the file lives under config/, so loading will fail if the path is resolved from Gears.toml.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Gears.toml` around lines 4 - 7, Update the config value in the
[apps.gears-rust.dev] manifest entry from the repository-root-relative lint.yml
path to config/lint.yml, preserving the existing gears configuration.

[apps.gears-rust.dev.lint]
fmt = false # already handled by `make fmt`
clippy = false # already handled by `make clippy`

[apps.gears-rust.dev.lint.dylint]
enabled = true
# Remove entries as violations are fixed or cargo-gears-lints is updated.
skip = [
# New lint not yet addressed in this repo.
"de0504_client_versioning",
# Path exclusion logic in cargo-gears-lints uses "modules/" prefix but this
# repo uses "gears/". Skipped until cargo-gears-lints adds "gears/" support.
"de1101_tests_in_separate_files",
# Scope broadened from /contract/ to /domain/ in cargo-gears-lints.
# Pre-existing code in domain/ layers needs migration.
"de0101_no_serde_in_contract",
"de0102_no_toschema_in_contract",
]
54 changes: 16 additions & 38 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ setup: .setup-stamp
cargo install lychee
cargo install cargo-geiger
cargo install cargo-deny
cargo install cargo-dylint
cargo install dylint-link
cargo install cargo-gears
cargo install cargo-fuzz
cargo install cargo-hack
cargo install gts-validator
Expand All @@ -161,7 +160,15 @@ setup: .setup-stamp
@echo "Setup complete. All tools installed."
@touch .setup-stamp

# -------- Checks --------
# -------- Gear naming validation --------

.PHONY: validate-gear-names

## Validate gear folder names follow kebab-case convention
validate-gear-names:
@$(PYTHON) tools/scripts/validate_gear_names.py

# -------- Code safety checks --------
#
# Tool Comparison - What Each Tool Checks:
# +-------------+----------------------------------------------------------------------+
Expand Down Expand Up @@ -195,22 +202,13 @@ setup: .setup-stamp
# | | - Missing documentation warnings |
# | | - Ensures clean compilation across all targets and features |
# +-------------+----------------------------------------------------------------------+
# | dylint | - Project-specific architectural conventions (custom lints) |
# | | - DTO declaration and placement (only in api/rest folders) |
# | | - DTO isolation (no references from domain/contract layers) |
# | | - API endpoint versioning requirements (e.g., /users/v1/users) |
# | | - Contract layer purity (no serde, HTTP types, or ToSchema) |
# | | - Layer separation and dependency rules enforcement |
# | | - Use 'make dylint-list' to see all available custom lints |
# +-------------+----------------------------------------------------------------------+

.PHONY: fmt clippy clippy-deep lychee docs-preview kani geiger safety lint dylint dylint-list dylint-test shear gts-docs cfs-ensure cfs-repair cfs-validate cfs-validate-kits cfs-validate-kit-local cfs-spec-coverage

# Check code formatting
fmt:
$(call check_rustup_component,rustfmt)
cargo fmt --all --check
cargo fmt --all --check --manifest-path tools/dylint_lints/Cargo.toml

CFS ?= cfs
CFS_PIPX_SPEC ?= git+https://github.com/constructorfabric/studio.git
Expand Down Expand Up @@ -248,7 +246,7 @@ clippy-deep:
# Run markdown checks with 'lychee'
lychee:
$(call check_tool,lychee)
lychee --exclude-path 'docs/web-docs' docs examples tools/dylint_lints guidelines
lychee --exclude-path 'docs/web-docs' docs examples guidelines

## Validate internal links in web-docs.
# The web-docs pages use Starlight route-relative links (e.g. ../foo/) that only
Expand Down Expand Up @@ -291,34 +289,15 @@ gts-docs:
install-tools:
@command -v cargo-nextest >/dev/null 2>&1 || cargo install --locked cargo-nextest

## List all custom project compliance lints (see tools/dylint_lints/README.md)
Comment thread
maurolacy marked this conversation as resolved.
dylint-list:
@cd tools/dylint_lints && \
DYLINT_LIBS=$$(find target/release -maxdepth 1 \( -name "libde*@*.so" -o -name "libde*@*.dylib" -o -name "de*@*.dll" \) -type f | sort -u); \
if [ -z "$$DYLINT_LIBS" ]; then \
echo "ERROR: No dylint libraries found. Run 'make dylint' first to build them."; \
exit 1; \
fi; \
for lib in $$DYLINT_LIBS; do \
echo "=== $$lib ==="; \
cargo dylint list --lib-path "$$lib"; \
done

## Test dylint lints on UI test cases (compile and verify violations)
dylint-test: install-tools
@cd tools/dylint_lints && cargo nextest run

# Run project compliance dylint lints on the workspace (see `make dylint-list`)
# Run architecture lints via cargo-gears (see Gears.toml for configuration).
dylint:
$(call check_tool,cargo-dylint)
$(call check_tool,dylint-link)
cargo dylint --all --workspace
$(call check_tool,cargo-gears)
cargo gears lint --dylint

# Check for unused dependencies with cargo-shear.
shear:
$(call check_tool,cargo-shear)
cargo +nightly-2026-04-16 shear --expand --deny-warnings
cd tools/dylint_lints && cargo shear --expand --deny-warnings

# Run all code safety checks
safety: clippy kani lint dylint # geiger
Expand Down Expand Up @@ -432,7 +411,6 @@ dev-fmt:
## Auto-fix clippy warnings
dev-clippy:
cargo clippy --workspace --all-targets --all-features --fix --allow-dirty
@cd tools/dylint_lints && cargo clippy --all-targets --workspace

# Auto-fix formatting and clippy warnings
dev: dev-fmt dev-clippy dev-test
Expand Down Expand Up @@ -825,14 +803,14 @@ oop-example:
cargo run --bin cf-gears-example-server --features oop-example,users-info-example,static-authn,static-authz,static-tenants,static-credstore -- --config config/quickstart.yaml run

# Run all quality checks
check: .setup-stamp fmt cfs-validate clippy lychee security dylint-test dylint gts-docs test
check: .setup-stamp fmt cfs-validate clippy lychee security dylint gts-docs test

ci_test: fmt clippy

ci_docs: lychee gts-docs

# Run CI pipeline locally, requires docker
ci: fmt clippy test-no-macros test-macros test-db deny test-users-info-pg lychee gts-docs dylint dylint-test
ci: fmt clippy test-no-macros test-macros test-db deny test-users-info-pg lychee gts-docs dylint

## Build the cf-gears-example-server release binary using a toolchain from the rust-toolchain.toml
.cargo-build:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ See also:

**Engineering principles:**
- **Spec-Driven Development**: [Specification templates](docs/spec-templates/README.md) (PRD, Design, ADR, Feature) define what gets built *before* code is written. Every gear is well documented.
- **Shift Left**: Custom [dylint](tools/dylint_lints/) architectural lints enforce design rules at compile time, alongside Clippy, [tests](#testing), fuzzing, and security audits in CI
- **Shift Left**: Custom architecture lints (via `cargo gears lint`) enforce design rules at compile time, alongside Clippy, [tests](#testing), fuzzing, and security audits in CI
- **Quality First**: 90%+ test coverage target with unit, integration, E2E, performance, and security testing
- **Core in Rust**: Compile-time safety, deep static analysis including project-specific lints, so more issues are prevented before review/runtime
- **Monorepo**: All the core gears and contracts in one place for atomic refactors, consistent tooling/CI, and realistic local build + E2E testing
Expand Down Expand Up @@ -145,7 +145,7 @@ See [TOOLKIT UNIFIED SYSTEM](docs/toolkit_unified_system/README.md) and [TOOLKIT

Gears apply defense-in-depth security across the entire development lifecycle — from Rust's compile-time safety guarantees and custom architectural lints, through compile-time tenant isolation and PDP/PEP authorization enforcement, to continuous fuzzing, dependency auditing, and automated security scanning in CI.

See **[Security Overview](docs/security/SECURITY.md)** for the full breakdown, including: Secure ORM with compile-time tenant scoping, authentication/authorization architecture (NIST SP 800-162 PDP/PEP model), 90+ Clippy deny-level rules, custom dylint architectural lints, cargo-deny advisory checks, ClusterFuzzLite continuous fuzzing, CodeQL/Scorecard/Snyk/Aikido scanners, and AI-powered PR review bots.
See **[Security Overview](docs/security/SECURITY.md)** for the full breakdown, including: Secure ORM with compile-time tenant scoping, authentication/authorization architecture (NIST SP 800-162 PDP/PEP model), 90+ Clippy deny-level rules, custom architecture lints (via `cargo gears lint`), cargo-deny advisory checks, ClusterFuzzLite continuous fuzzing, CodeQL/Scorecard/Snyk/Aikido scanners, and AI-powered PR review bots.

## FIPS 140-3 support

Expand Down
2 changes: 2 additions & 0 deletions config/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Minimal config file required by the Gears manifest for linting.
server: {}
Loading
Loading