This document describes how StarForge enforces code quality through continuous integration.
StarForge uses an automated CI pipeline to ensure consistent code quality. Every push and pull request is validated against:
- Code Formatting - Rust standard formatting via
cargo fmt - Code Linting - Best practices and correctness via
cargo clippy - Dependency Security - Supply chain security via
cargo deny - Compilation - Successful builds with no errors
- Tests - All tests pass without failures
- Smoke Tests - Basic CLI functionality works end-to-end
Purpose: Ensure all Rust code follows standard formatting conventions
Trigger: Every push and pull request
Status: ✅ Required (must pass)
cargo fmt --all --checkWhat it checks:
- Indentation (4 spaces)
- Line length and wrapping
- Spacing around operators and delimiters
- Import organization
- Comment formatting
Local equivalent:
# Check if code is formatted
cargo fmt --all --check
# Auto-format all code
cargo fmt --allPurpose: Audit dependencies for security vulnerabilities and license issues
Trigger: Every push and pull request
Status: ✅ Required (must pass)
cargo deny check --all-featuresWhat it checks:
- Known security advisories in dependencies (via RustSec advisory database)
- Only approved open-source licenses are present in the dependency tree
- Duplicate crate versions across the dependency graph
- Only dependencies from crates.io are allowed; untrusted registries and git sources are rejected
Configuration: The policy is defined in deny.toml at the repository root. Every ignored advisory must have a documented rationale.
Local equivalent:
# Install cargo-deny (if not present)
cargo install cargo-deny
# Run security auditcargo deny check
# Run all supply-chain checks
cargo deny check
# Run individual checks
cargo deny check advisories
cargo deny check licenses
cargo deny check bans
cargo deny check sourcesFailure behavior:
- cargo-deny exits non-zero on any policy violation, which fails the CI job.
- The
continue-on-errorflag is not used — all violations block the PR. - Output includes the specific advisory ID, crate name, and license that caused the failure.
Unsupported environments:
- If cargo-deny cannot be installed or run in the CI environment, the job fails rather than silently skipping.
- The CI configuration uses the official
EmbarkStudios/cargo-deny-action@v2action, which handles Rust toolchain setup automatically.
Handling new violations:
- Advisory: Update the dependency or add a documented ignore to
[advisories].ignoreindeny.toml. - License: Add the license to
[licenses].allowindeny.tomlif it is compatible, or replace the dependency. - Duplicate: Investigate whether the duplicate can be eliminated; duplicates are currently warned (not denied) to avoid breaking changes.
- Source: No new registries or git sources are allowed without explicit approval.
Purpose: Ensure documentation examples (doctests) compile and pass
Trigger: Every push and pull request
Status: ✅ Required (must pass)
cargo test --doc --lockedWhat it checks:
- All
```and```no_rundoc examples compile successfully - Pure-logic examples execute and pass assertions
- Public utility APIs stay documented with accurate examples
Local equivalent:
cargo test --doc --lockedSee DOCTEST_GUIDELINES.md for how to write doctests.
Purpose: Verify that StarForge ships with secure, privacy-respecting defaults
Trigger: Every push and pull request
Status: ✅ Required (must pass)
cargo test --test secure_defaults_audit --lockedWhat it checks:
- Telemetry opt-out is respected (defaults to enabled)
- AI telemetry cloud aggregation is disabled by default
- Friendbot is absent on mainnet, present on testnet
- Default network is testnet
- Plugin trust sources match known repos only
- Wallet encryption is opt-in
- File permissions are restricted (0600)
- Network passphrases are correct
See SECURE_DEFAULTS_AUDIT.md for the full checklist.
Purpose: Compile the project, run tests, and check for common mistakes
Trigger: Every push and pull request
Status: ✅ Required (must pass)
Steps:
-
Build
cargo build --locked
Compiles the entire project with locked dependencies
-
Test
cargo test --lockedRuns all unit and integration tests
-
Clippy (Linting)
cargo clippy --locked -- -D warnings
Checks for common mistakes and best practices, treating warnings as errors
What Clippy checks:
- Unnecessary complexity or redundant code
- Incorrect use of standard library functions
- Performance anti-patterns
- Memory safety issues
- Unused variables or imports
- Common pitfalls and idioms
Local equivalent:
# Check for Clippy warnings
cargo clippy --all-targets
# Apply auto-fixes (when available)
cargo clippy --fix --allow-dirty --allow-stagedPurpose: Ensure locked builds do not mutate dependency resolution on Linux, macOS, or Windows.
Trigger: Every push and pull request across all OS matrix targets
Status: ✅ Required (must pass)
# Enforce lockfile immutability
git diff --exit-code Cargo.lock
# Verify Cargo.lock reproducibility with StarForge
starforge verify lockfileWhat it checks:
Cargo.lockexact deterministic resolution across supported operating systems (Linux, macOS, Windows).- That locked compilation (
--locked) does not modifyCargo.lockor require dependency resolution updates. - Detection of out-of-sync dependency specifications between
Cargo.tomlandCargo.lock.
Purpose: Validate basic CLI functionality works end-to-end
Trigger: Every push and pull request
Status: ✅ Required (must pass)
cargo test --test cli_smoke --locked
./scripts/e2e-smoke.shWhat it tests:
starforge infoexits cleanlystarforge --versionshows versionstarforge --helplists commandsstarforge wallet listworksstarforge network showworksstarforge template listworksstarforge deploy --helpdocuments flags
Purpose: Validate that the Windows binary starts and its core help/doctor
surface works, mirroring what users get from the shipping .zip
Trigger: Every push and pull request (ci.yml → cli-windows) and on
installer changes (installer-tests.yml → installer-windows)
Status: ✅ Required (must pass) — also release-blocking via release.yml
pwsh -NoProfile -ExecutionPolicy Bypass -File tests/installer/windows_smoke.ps1 -Binary target\release\starforge.exeWhat it tests:
starforge --versionexits 0starforge --helpexits 0starforge infoexits 0 (binary startup)starforge config --helpexits 0 and listsdoctorstarforge config doctorruns diagnostically in an isolatedSTARFORGE_CONFIG_DIR; the offlineschemafinding must pass while network/toolchain findings (Horizon, Soroban RPC, Stellar CLI on PATH) are reported without failing the job
Failure visibility: each failing check prints the exact command, its exit
code, and captured output. Full output is teed to windows-smoke.log and
uploaded as a CI artifact on failure.
Windows support status: StarForge ships Windows x86_64 binaries as a
.zip from Releases.
Windows binaries are built and smoke-tested in CI on every push and pull
request, and the release pipeline refuses to publish a Windows binary that
fails these startup/help checks.
Each job has clear, descriptive names and output:
| Regression Type | Job | Failure Visibility |
|---|---|---|
| Formatting errors | Rustfmt | ❌ Clear diff of formatting issues |
| Lint violations | Build, Test & Clippy | ❌ Specific warning messages |
| Security issues | Cargo Deny | ❌ Advisory ID and description |
| Test failures | Build, Test & Clippy | ❌ Test name and assertion |
| Secure default regressions | Secure Defaults Audit | ❌ Which default changed |
| Broken doc examples | Documentation Tests | ❌ Compilation error or assertion failure |
| Broken CLI | CLI Smoke Tests | ❌ Which command failed |
| Broken Windows binary | Windows Binary Startup Smoke Tests | ❌ Exact command, exit code, and output (log artifact) |
Example failure output:
error: code must be formatted
...
Run `cargo fmt --all` to format your code
This enforcement is documented in:
- CONTRIBUTING.md - Full contribution guide with code quality section
- CONTRIBUTOR_QUICK_REFERENCE.md - Quick lookup for common commands
- CODE_STYLE_STANDARDS.md - Detailed code style and linting rules
- This file - CI enforcement and pipeline details
All new contributors see these documents in the onboarding flow.
Enforcing these checks ensures:
- No format drift - All code formatted identically via
cargo fmt - No style regressions - Linting catches anti-patterns before merge
- No security issues - Dependencies audited automatically
- No broken functionality - Tests and smoke tests run on every change
- No hidden complexity - Clippy enforces readability and maintainability
Run these commands locally to match what CI checks:
# 1. Format code
cargo fmt --all
# 2. Build project
cargo build --locked
# 3. Run tests
cargo test --locked
# 4. Check secure defaults
cargo test --test secure_defaults_audit --locked
# 4. Check doctests
cargo test --doc --locked
# 5. Check linting
cargo clippy --locked -- -D warnings
# 6. Verify smoke tests
cargo test --test cli_smoke --locked
# 7. Verify CLI JSON output stability contracts
cargo test --test json_contract_stability --lockedOr run all at once (simulates CI):
cargo fmt --all --check && \
cargo build --locked && \
cargo test --locked && \
cargo test --doc --locked && \
cargo clippy --locked -- -D warnings && \
cargo test --test cli_smoke --locked && \
cargo test --test json_contract_stability --lockedThe JSON contract stability check prevents stable --json fields listed in
tests/fixtures/json_contracts/stable-fields-baseline.json from disappearing
from docs/contracts/cli-json-fields.json unless they are first marked
deprecated.
StarForge enforces GitHub branch protections on the master branch:
- Required Status Checks: All CI workflow jobs (
fmt,msrv,deny,secure-defaults,build-and-test,clippy,smoke,cli-macos,cli-windows) must pass before a pull request can be merged. - Required Status Checks: All CI workflow jobs (
fmt,msrv,deny,doctests,build-and-test,clippy,smoke,cli-macos,cli-windows) must pass before a pull request can be merged. - Conflict-Free Enforcement: Pull requests with merge conflicts are blocked from merging. Branches must be cleanly rebased against
master. - Approved Reviews: PRs require maintainer review and approval with all conversational threads resolved.
To verify all merge gates locally before pushing and opening a PR, use the preflight script:
# 1. Run standard preflight merge gates
./scripts/preflight-pr.sh
# 2. Fast subset check during active development
./scripts/preflight-pr.sh --quick
# 3. Full suite check before final submission
./scripts/preflight-pr.sh --allThe script exits with a non-zero exit code if any gate fails, pinpointing the issue immediately.
You can also run individual gate commands manually:
# 1. Ensure your branch is up to date and conflict-free
git fetch origin
git rebase origin/master
# 2. Run full validation
cargo fmt --all --check && \
cargo deny check && \
cargo build --locked && \
cargo test --locked && \
cargo clippy --locked -- -D warnings
# 3. Verify smoke tests
cargo test --test cli_smoke --locked
# 4. Push and open PR
git push origin feat/your-feature
# Open PR on GitHubRust Analyzer extension - automatically formats on save:
{
"[rust]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}Clippy warnings in editor - set in settings:
{
"rust-analyzer.checkOnSave.command": "clippy",
"rust-analyzer.checkOnSave.extraArgs": [
"--",
"-D",
"warnings"
]
}Built-in Rust support automatically runs:
cargo fmtchecks (with auto-fix option)- Clippy linting (with action hints)
Enable in Settings → Languages & Frameworks → Rust → Rustfmt
rust.vim plugin with formatting:
let g:rustfmt_autosave = 1# Fix automatically
cargo fmt --all
# Verify
cargo fmt --all --check# See what auto-fixes are available
cargo clippy --fix --allow-dirty --allow-staged
# Or manually review and apply suggestions
cargo clippy --locked -- -D warnings# Check which dependency has the issue
cargo deny fetch
# Update to a patched version
cargo update# Use locked dependencies (what CI uses)
cargo test --locked
# Run in CI environment (single-threaded)
cargo test -- --test-threads=1Formatting is controlled by .rustfmt.toml. Current defaults are stable and widely adopted. To customize:
# Example: change max line length
max_width = 120However, changing these after merged code is not recommended as it affects blame and history.
Clippy rules are stable and enforced with -D warnings (deny). To suppress a specific warning:
#[allow(clippy::rule_name)]
fn my_function() {
// ...
}Document why the rule is suppressed in a comment.
- Location:
.github/workflows/ci.yml - Triggers: Every push and PR
- Jobs: fmt, deny, test, smoke
- Duration: ~2-3 minutes
- Managed by:
cargo deny - Config:
deny.toml(if present) - Checked: With
--all-features
- On Pull Request: Green checkmark ✅ means all checks passed
- On Pull Request: Red X ❌ means at least one check failed
- Click "Details": Shows which job failed and why
Monitor the Actions tab for:
- Flaky tests (inconsistent failures)
- New Clippy warnings introduced
- Dependency vulnerabilities discovered
- Performance regressions
Q: Why enforce -D warnings in Clippy?
A: Warnings are future errors. Treating them as errors now prevents accumulation and keeps code quality high.
Q: Can I skip CI checks?
A: No. All PRs must pass CI to merge. This ensures consistency and prevents breaking changes.
Q: What if CI fails for an environmental reason?
A: Rerun the check via GitHub Actions UI or push a new commit to trigger re-run.
Q: How often are dependencies updated?
A: Cargo.lock pins versions. Dependencies are updated manually via cargo update and tested before commit.
Q: Why test on every push, not just PRs?
A: Catches issues before opening PR, saves review time, and ensures master is always deployable.
- CONTRIBUTING.md - Contribution guidelines
- CODE_STYLE_STANDARDS.md - Code style and standards
- DEVELOPER_GUIDE.md - In-depth development guide
- Clippy lint list - All Clippy rules
- Rustfmt configuration - Formatting options
Last updated: 2026-06-01
Issue #207: Enforce formatting and linting in CI