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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[resolver]
incompatible-rust-versions = "fallback"
93 changes: 51 additions & 42 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,33 @@ permissions:
env:
RUSTC_WRAPPER: ""
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
RUSTDOCFLAGS: "-D warnings"

jobs:
lint-test:
name: Format, Clippy, Tests
runs-on: macos-14
timeout-minutes: 30

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true

- name: Format check
run: cargo fmt --all --check

- name: Clippy
run: cargo clippy --workspace --all-targets --all-features -- -D warnings -D clippy::all -D clippy::pedantic -D clippy::nursery -D clippy::cargo

- name: Test
run: cargo test --workspace --all-features

build:
name: Build ${{ matrix.label }}
quality:
name: Rust 1.99.0 quality gate (${{ matrix.label }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
- label: macOS Apple Silicon
runner: macos-14
target: aarch64-apple-darwin
binary: target/aarch64-apple-darwin/release/bitengine
deps: none
- label: Linux x86_64
runner: ubuntu-latest
target: x86_64-unknown-linux-gnu
binary: target/x86_64-unknown-linux-gnu/release/bitengine
deps: linux
- label: Linux ARM64
runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
binary: target/aarch64-unknown-linux-gnu/release/bitengine
deps: linux
env:
RUSTUP_TOOLCHAIN: "1.99.0"
CARGO_BUILD_TARGET: ${{ matrix.target }}

steps:
- name: Checkout
Expand All @@ -76,22 +50,57 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libx11-dev libxkbcommon-dev libwayland-dev libegl1-mesa-dev \
libx11-dev libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libegl1-mesa-dev \
libgtk-3-dev

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install pinned Rust
uses: dtolnay/rust-toolchain@1.99.0
with:
components: rustfmt, clippy
targets: ${{ matrix.target }}

- name: Verify native runner architecture
shell: bash
run: |
rustc --version --verbose
test "$(rustc --version --verbose | sed -n 's/^host: //p')" = '${{ matrix.target }}'

- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
key: quality-1.99.0-${{ matrix.target }}

- name: Release build
run: cargo build --release --target ${{ matrix.target }}
- name: Format, check, strict Clippy, tests, documentation, release
run: ./scripts/quality-gate.sh

- name: Verify binary exists
shell: bash
run: test -f "${{ matrix.binary }}"
- name: Verify release binary exists
run: test -f 'target/${{ matrix.target }}/release/bitengine'

# Preserve the existing early warning against future compiler changes. This
# supplementary job never selects the compiler used by the pinned gates above.
future-stable:
name: Future stable compatibility
runs-on: macos-14
timeout-minutes: 30
env:
RUSTUP_TOOLCHAIN: stable
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install stable Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache Cargo
uses: Swatinem/rust-cache@v2
- name: Print compiler version
run: rustc --version --verbose
- name: Format
run: cargo fmt --all --check
- name: Check
run: cargo check --locked --workspace --all-targets --all-features
- name: Clippy
run: cargo clippy --locked --workspace --all-targets --all-features -- -D warnings -D clippy::all -D clippy::pedantic -D clippy::nursery -D clippy::cargo
- name: Test
run: cargo test --locked --workspace --all-features
49 changes: 39 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,39 @@ permissions:

env:
RUSTC_WRAPPER: ""
RUSTUP_TOOLCHAIN: "1.99.0"
RUSTFLAGS: "-D warnings"
RUSTDOCFLAGS: "-D warnings"
CARGO_TERM_COLOR: always

jobs:
macos-arm64:
name: macOS Apple Silicon
runs-on: macos-14
timeout-minutes: 45
timeout-minutes: 60

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@1.99.0
with:
targets: aarch64-apple-darwin
components: rustfmt, clippy

- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true

- name: Build release binary
run: cargo build --release --target aarch64-apple-darwin
- name: Verify pinned Rust compiler
run: ./scripts/check-rust-toolchain.sh

- name: Run complete quality gate before packaging
env:
CARGO_BUILD_TARGET: aarch64-apple-darwin
run: ./scripts/quality-gate.sh

- name: Assemble app bundle
shell: bash
Expand All @@ -46,8 +55,10 @@ jobs:
APP_ROOT="dist/${APP_NAME}.app"
MACOS_DIR="$APP_ROOT/Contents/MacOS"
RESOURCES_DIR="$APP_ROOT/Contents/Resources"
BUNDLE_ID="com.csd113.BitEngine"
SHORT_VERSION="${GITHUB_REF_NAME#v}"
BUILD_VERSION="${GITHUB_RUN_NUMBER}"
REMOVABLE_VOLUMES_USAGE_DESCRIPTION="BitEngine needs access to removable volumes containing your configured node binaries and data."

mkdir -p "$MACOS_DIR" "$RESOURCES_DIR" out

Expand All @@ -63,7 +74,7 @@ jobs:
<key>CFBundleExecutable</key>
<string>${APP_EXECUTABLE}</string>
<key>CFBundleIdentifier</key>
<string>com.csd113.BitEngine</string>
<string>${BUNDLE_ID}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
Expand All @@ -80,10 +91,22 @@ jobs:
<string>12.0</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSRemovableVolumesUsageDescription</key>
<string>${REMOVABLE_VOLUMES_USAGE_DESCRIPTION}</string>
</dict>
</plist>
EOF

plutil -lint "$APP_ROOT/Contents/Info.plist" >/dev/null
if [[ "$(plutil -extract CFBundleIdentifier raw -o - "$APP_ROOT/Contents/Info.plist")" != "$BUNDLE_ID" ]]; then
echo "Generated Info.plist has an unexpected bundle identifier" >&2
exit 1
fi
if [[ "$(plutil -extract NSRemovableVolumesUsageDescription raw -o - "$APP_ROOT/Contents/Info.plist")" != "$REMOVABLE_VOLUMES_USAGE_DESCRIPTION" ]]; then
echo "Generated Info.plist is missing the removable-volume usage description" >&2
exit 1
fi

cp target/aarch64-apple-darwin/release/bitengine "$MACOS_DIR/$APP_EXECUTABLE"
chmod 755 "$MACOS_DIR/$APP_EXECUTABLE"
cp app-icon.icns "$RESOURCES_DIR/app-icon.icns"
Expand All @@ -104,7 +127,7 @@ jobs:
linux:
name: Linux ${{ matrix.label }}
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand All @@ -126,21 +149,27 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libx11-dev libxkbcommon-dev libwayland-dev libegl1-mesa-dev \
libx11-dev libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libegl1-mesa-dev \
libgtk-3-dev

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
uses: dtolnay/rust-toolchain@1.99.0
with:
targets: ${{ matrix.target }}
components: rustfmt, clippy

- name: Cache Cargo
uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true

- name: Build release binary
run: cargo build --release --target ${{ matrix.target }}
- name: Verify pinned Rust compiler
run: ./scripts/check-rust-toolchain.sh

- name: Run complete quality gate before packaging
env:
CARGO_BUILD_TARGET: ${{ matrix.target }}
run: ./scripts/quality-gate.sh

- name: Package executable
shell: bash
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

# Rust build and profiling output
/target/
/vendor/tor-hsservice/target/
*.profraw

# Local release-packaging output
Expand All @@ -14,3 +15,6 @@
# Local development helpers
dev-check.sh
clippy.sh

# Private Codex guidance
/rules.md
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Unreleased

- Added an always-visible, readiness-gated wallet connection card with validated local/LAN endpoints, matching QR/copy data, and actionable synchronization or failure detail
- Added an embedded Arti v3 onion service that exposes only the managed electrs port, persists its identity in validated private storage, rejects traffic while electrs is unavailable, and shuts down asynchronously
- Corrected Arti 0.45 introduction-point publication expiry bookkeeping so rapid onion-service restarts retain still-valid descriptors and discard expired records
- Added persistent System / Light / Dark themes and a restrained dashboard, binaries, controls, status, and error-state polish pass
- Added a collapsed Binaries → Advanced settings panel with persisted performance, source-retention, clean-build, and verbose-output controls
- Added version-aware macOS/Homebrew and Debian/Ubuntu apt dependency checks and narrowly scoped installation with Rust installation-method detection
- Raised the minimum supported Rust version and dependency checks to 1.99 and aligned the MSRV CI job
- Updated direct and transitive Cargo dependencies to the latest available releases, retaining the onion-service expiry fix on Arti 0.47
- Added authenticated source reuse and clean compilation-cache handling without changing transactional installation or rollback guarantees

## 1.0.0 - 2026-08-09

- Bumped the crate and release version to `1.0.0`
Expand Down
86 changes: 86 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Development standards

These rules apply to contributors and coding agents. The enforceable policy is
in [Cargo.toml](Cargo.toml), [clippy.toml](clippy.toml), and
[CI](.github/workflows/ci.yml). See [lint decisions](docs/lint-policy.md) for the
reasoning and the complete exception audit.

1. Compile, lint, test, and package with exact Rust **1.99.0**. Keep edition 2021.
Update the toolchain, MSRV, scripts, CI, release workflow, and documentation
together when deliberately advancing the compiler.
2. Pass every configured rustc and Clippy lint. New warnings are errors; do not
weaken groups, thresholds, or CI to accommodate a change.
3. Use a local `#[expect(lint, reason = "...")]` only for a reviewed technical
invariant. Explain it in the lint-policy exception inventory. Obsolete
expectations must fail. Never blanket-allow a lint group.
4. Document shared APIs, fallible operations, and error/ownership contracts.
Exported fallible APIs need `# Errors`; unsafe APIs need `# Safety`.
Keep visibility as narrow as callers permit.
5. Return contextual or typed errors for recoverable failures. Production code
must not use `unwrap`, `expect`, panic shortcuts, or direct process exit.
Fixture assertions can fail tests; they cannot justify production panics.
6. Keep unsafe regions minimal, with a nearby `SAFETY` comment establishing
pointer validity, initialization, ownership, and platform assumptions.
7. Use checked conversions and explicit overflow behavior for lengths, offsets,
counters, ports, PIDs, and deadlines. Production indexing must be statically
safe or checked. Display-only floating-point exceptions stay local.
8. Keep Iced update/render work responsive. Perform blocking I/O, source builds,
and process shutdown outside the update loop; avoid locks across awaits.
9. Own background tasks, bound queues and reads, join shutdown work, and preserve
cancellation, generation identities, and rejection of stale results.
10. Pass process arguments separately. Construct child environments explicitly;
never mutate the application's global environment. Drain both output streams,
preserve graceful shutdown, and clean up/reap the complete owned process group.
11. Treat paths, configuration, network messages, cookies, environment variables,
and recovered journals as untrusted. Validate before mutation. Preserve
symlink/file-identity checks, permissions, locking, and durability ordering.
12. Protect node data, wallets, indexes, user configuration, and custom binaries.
Preserve staged installation, signed-source verification, fail-closed signer
policies, non-cancellable activation, rollback, and idempotent crash recovery.
13. Keep RPC cookies and authentication material private and redacted, including
`Debug` output and chained errors. Maintain timeouts, response limits, and
strict protocol/readiness classification.
14. Avoid unnecessary allocation, cloning, indirection, or lock contention in
frequently executed paths. Prefer the standard library and existing crates;
add dependencies only when necessary.
15. Make focused changes. Preserve UI behavior/hooks, serialization, managed and
custom paths, and legacy environment/config compatibility. Avoid unrelated
cleanup and abstractions that only satisfy a complexity metric.
16. Add focused regression tests for meaningful behavior changes. Use temporary
directories, fake executables, and loopback peers. Never use real wallets or
node data, or require an upstream node compilation for ordinary refactoring.
17. Preserve all supported targets: macOS Apple Silicon, Linux x86_64, and Linux
ARM64. Do not introduce macOS Intel or universal packaging.
18. Pass the complete quality gate before handoff. Report commands, results,
changed files, and limitations. Do not commit, push, tag, or publish without
explicit authorization.

Run the same gate used by pinned CI and release packaging:

```bash
./scripts/quality-gate.sh
```

The gate prints and verifies both rustc and Cargo 1.99.0, then runs:

```bash
cargo fmt --all --check
cargo check --locked --workspace --all-targets --all-features
cargo clippy --locked --workspace --all-targets --all-features -- -D warnings -D clippy::all -D clippy::pedantic -D clippy::nursery -D clippy::cargo
cargo test --locked --workspace --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --locked --workspace --all-features --no-deps --document-private-items
cargo build --locked --release
```

If formatting fails, format the touched Rust files with the pinned rustfmt and
rerun `cargo fmt --all --check`. Use targeted tests during development, followed
by the full gate. There is currently one binary target and no package features
or library doctests; `--all-features` is coherent. Existing ignored integration
tests need explicit external prerequisites and remain opt-in.

Linux needs the GUI development packages listed in CI. Platform jobs run
natively with `CARGO_BUILD_TARGET` set to their release target. The additional
future-stable job detects upcoming compiler changes; exact 1.99.0 gates remain
mandatory. A local packaging build also verifies the exact toolchain.
Container tests need a child-reaping init, such as `docker run --init`, so killed
helper descendants can be reaped after their direct parent exits.
Loading
Loading