Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
0f72c95
rtbit-fluent: Files tab as a folder Tree with include/skip priority (…
thedancingdeveloper Nov 2, 2026
c5853fb
rtbit-ui-core: drop last egui reference from error doc comment (WI-2770)
thedancingdeveloper Nov 2, 2026
7081060
Revert "rtbit-fluent: Files tab as a folder Tree with include/skip pr…
thedancingdeveloper Nov 2, 2026
4634677
rtbit-fluent: Files tab as a folder Tree with include/skip priority (…
thedancingdeveloper Nov 2, 2026
c93e33e
test(swarmforge): router-level tests for POST /torrents/{id}/files/{i…
thedancingdeveloper Nov 2, 2026
45ed5ef
qbit: real app/preferences share limits and dht/pex/lsd; apply on set…
thedancingdeveloper Nov 2, 2026
af3bcdf
ci: report nightly release dry-run failures (WI-2898)
thedancingdeveloper Nov 2, 2026
4f8e646
rtbit-fluent: main-screen keyboard shortcuts (WI-2869)
thedancingdeveloper Nov 2, 2026
0186a88
ci: enforce cargo-deny dependency policy
thedancingdeveloper Nov 2, 2026
2c58cbb
Add torrent table keyboard navigation
thedancingdeveloper Nov 2, 2026
4477257
rtbit-fluent: add detail pane empty states
thedancingdeveloper Nov 2, 2026
2a0c393
Improve toolbar accessibility and focus visibility
thedancingdeveloper Nov 2, 2026
96be0f0
rtbit-fluent: dialogs close on Escape and confirm on Enter (WI-2871)
thedancingdeveloper Nov 2, 2026
978414e
rtbit-fluent: daemon-lost banner with 1s-30s backoff reconnect (WI-2874)
thedancingdeveloper Nov 2, 2026
d99d58d
rtbit-fluent: tests for detail pane tabs (WI-2875)
thedancingdeveloper Nov 2, 2026
e54e3fc
rtbit-fluent: tests for status bar, shell navigation and bridge error…
thedancingdeveloper Nov 2, 2026
39f8481
qbit API: app/getFreeSpaceAtPath and real free_space_on_disk in sync/…
thedancingdeveloper Nov 2, 2026
92f20f8
rtbit-fluent: right-click context menu on torrent rows (WI-2878)
thedancingdeveloper Nov 2, 2026
4867f6c
qbit API: add torrents/pieceAvailability (WI-2886)
thedancingdeveloper Nov 2, 2026
d32fd23
rtbit-fluent: persist table sort and column widths; add Up column (WI…
thedancingdeveloper Nov 2, 2026
773436e
docs: audit Fluent client parity (WI-2877)
thedancingdeveloper Nov 2, 2026
fb571e3
feat(rtbit-fluent): open add dialog from torrent drops
thedancingdeveloper Nov 2, 2026
ab94504
rtbit-fluent: add RSS rule priority selector (#287)
thedancingdeveloper Nov 2, 2026
cdd9f7f
rtbit-fluent: add trackers from torrent detail (#286)
thedancingdeveloper Nov 2, 2026
86642fe
Add per-category share limits (WI-2889)
thedancingdeveloper Nov 2, 2026
aa2b89a
Report real qbit API build information
thedancingdeveloper Nov 2, 2026
3626f8b
Resolve metadata test merge
thedancingdeveloper Nov 2, 2026
37c5b98
CI: check generated parity summary drift
thedancingdeveloper Nov 2, 2026
408d731
ci: test fluent app for client dependency changes
thedancingdeveloper Nov 2, 2026
f38d5df
Add Radarr and Lidarr replay fixtures (WI-2896)
thedancingdeveloper Nov 2, 2026
28cb323
Add missing payload diagnosis
thedancingdeveloper Nov 2, 2026
fd8f4e7
Add bulk category and tag editing
thedancingdeveloper Nov 2, 2026
2cb9ec7
Add real per-file priority levels
thedancingdeveloper Nov 2, 2026
c6d8fc1
Release: smoke-test fluent artifacts before publishing
thedancingdeveloper Nov 2, 2026
784d47d
CI: smoke test daemon container in merge queue
thedancingdeveloper Nov 2, 2026
c15937a
Add fluent per-file priority controls
thedancingdeveloper Nov 2, 2026
78bf4ab
librtbit: crash-safe atomic state writes; quarantine corrupt state files
thedancingdeveloper Nov 2, 2026
64583e0
Low-disk guard: default 1 GiB floor and 'low disk space' status error
thedancingdeveloper Nov 2, 2026
f8c971a
Fixes #290: bound graceful shutdown save
thedancingdeveloper Nov 2, 2026
7716c77
fix: add tracker and DHT retry backoff (Fixes #299)
thedancingdeveloper Nov 2, 2026
dfe357f
rtbit-fluent: add filter sidebar (Fixes #297)
thedancingdeveloper Nov 2, 2026
e49eeba
rtbit-fluent: add status bar speed controls (Fixes #296)
thedancingdeveloper Nov 2, 2026
d82cd3e
fix(fluent-1): restore build after concurrent lands
thedancingdeveloper Nov 2, 2026
c00b21d
Fixes #291: add torrent metadata and management controls
thedancingdeveloper Nov 2, 2026
866e0f5
Add torrent location and rename dialogs; Fixes #298
thedancingdeveloper Nov 2, 2026
f06910d
Implement qbit app network and shutdown endpoints (Fixes #293)
thedancingdeveloper Nov 2, 2026
e1724aa
Fix release dry-run runner policy
thedancingdeveloper Nov 2, 2026
44c2060
chore: fold Dependabot updates and group scheduling
thedancingdeveloper Nov 2, 2026
9f4d548
Harden session recovery and torrent locations
thedancingdeveloper Nov 2, 2026
9a85d7d
feat(qbit): report in-flight piece states and refresh parity notes (F…
thedancingdeveloper Nov 2, 2026
1a2b336
style: cargo fmt
thedancingdeveloper Nov 2, 2026
f4c9815
Fix clippy needless_borrows_for_generic_args in qbit tags handler
thedancingdeveloper Nov 2, 2026
1da08bb
feat: show Files missing status with Set location / Force recheck (WI…
thedancingdeveloper Nov 2, 2026
2393ae2
Recheck throughput: concurrent-recheck cap (default 2), live resize, …
thedancingdeveloper Nov 2, 2026
7f092a8
WI-2895: shared SSRF-safe fetcher for URL add, RSS and blocklists
thedancingdeveloper Nov 2, 2026
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
72 changes: 9 additions & 63 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,77 +1,23 @@
# Dependabot version-update configuration.
#
# Security updates are enabled separately at the repo level and run regardless
# of this file. This config adds scheduled *version* updates to keep manifests
# and lockfiles fresh proactively. Updates are grouped to minimise PR noise.
version: 2
updates:
# ---- Rust: main workspace (covers all crates/* and desktop/src-tauri) ----
- package-ecosystem: cargo
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
interval: monthly
groups:
cargo-minor-patch:
update-types:
- minor
- patch

# ---- Rust: benchv2 (excluded from the workspace) ----
- package-ecosystem: cargo
directory: "/benchv2"
schedule:
interval: weekly
open-pull-requests-limit: 5
groups:
benchv2-minor-patch:
update-types:
- minor
- patch

# ---- Rust: fuzz (excluded from the workspace) ----
- package-ecosystem: cargo
directory: "/fuzz"
schedule:
interval: weekly
open-pull-requests-limit: 5
groups:
fuzz-minor-patch:
update-types:
- minor
- patch

# ---- npm: web UI (crates/librtbit/webui) ----
- package-ecosystem: npm
directory: "/crates/librtbit/webui"
schedule:
interval: weekly
open-pull-requests-limit: 10
groups:
webui-minor-patch:
update-types:
- minor
- patch

# ---- npm: root workspace (includes the desktop package) ----
cargo:
patterns: ["*"]
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
interval: monthly
groups:
root-npm-minor-patch:
update-types:
- minor
- patch

# ---- GitHub Actions workflows ----
npm:
patterns: ["*"]
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 5
interval: monthly
groups:
actions-all:
patterns:
- "*"
actions:
patterns: ["*"]
24 changes: 18 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
rust: ${{ steps.classify.outputs.rust }}
rust_full: ${{ steps.classify.outputs.rust_full }}
rust_packages: ${{ steps.classify.outputs.rust_packages }}
rust_fluent: ${{ steps.classify.outputs.rust_fluent }}
desktop: ${{ steps.classify.outputs.desktop }}
webui: ${{ steps.classify.outputs.webui }}
website: ${{ steps.classify.outputs.website }}
Expand All @@ -46,11 +47,11 @@ jobs:
run: |
set -euo pipefail
if [[ "$EVENT" != pull_request ]]; then
printf 'rust=true\nrust_full=true\nrust_packages=\ndesktop=true\nwebui=true\nwebsite=true\n' >>"$GITHUB_OUTPUT"
printf 'rust=true\nrust_full=true\nrust_packages=\nrust_fluent=true\ndesktop=true\nwebui=true\nwebsite=true\n' >>"$GITHUB_OUTPUT"
exit 0
fi
files="$(git diff --name-only "$(git merge-base "$BASE_SHA" HEAD)" HEAD)"
rust=false full=false desktop=false webui=false website=false
rust=false full=false fluent=false desktop=false webui=false website=false
packages=()
add_package() {
local pkg
Expand Down Expand Up @@ -80,8 +81,15 @@ jobs:
# The menu description has no window toolkit, so CI can test it.
# The Tauri binary stays excluded: the runner has no webkit.
desktop/menu/*) rust=true desktop=true; add_package rtbit-desktop-menu ;;
# The native app consumes the daemon's API types directly.
crates/librtbit/src/http_api_types.rs)
rust=true; fluent=true ;;
crates/librtbit/*) rust=true desktop=true; add_package swarmforge ;;
crates/rtbit/*) rust=true; add_package rtbit ;;
# The native client and UI crates are reverse dependencies of the
# fluent app, so changes to either must test the app as well.
crates/rtbit-client/*|crates/rtbit-ui-core/*)
rust=true; fluent=true ;;
website/*) website=true ;;
# An unrecognised crate path (a new member, or a path we have not
# mapped yet) is not safe to narrow, so it takes everything.
Expand All @@ -90,11 +98,11 @@ jobs:
done <<<"$files"
# A Rust change we could not attribute to a package still needs the
# full workspace rather than no check at all.
if [[ "$rust" == true && "$full" == false && ${#packages[@]} -eq 0 ]]; then
if [[ "$rust" == true && "$full" == false && "$fluent" == false && ${#packages[@]} -eq 0 ]]; then
full=true
fi
printf 'rust=%s\nrust_full=%s\nrust_packages=%s\ndesktop=%s\nwebui=%s\nwebsite=%s\n' \
"$rust" "$full" "${packages[*]-}" "$desktop" "$webui" "$website" | tee -a "$GITHUB_OUTPUT"
printf 'rust=%s\nrust_full=%s\nrust_packages=%s\nrust_fluent=%s\ndesktop=%s\nwebui=%s\nwebsite=%s\n' \
"$rust" "$full" "${packages[*]-}" "$fluent" "$desktop" "$webui" "$website" | tee -a "$GITHUB_OUTPUT"

# Shell checks for the release scripts and repository layout. They take
# seconds and touch no network, so they run on every event.
Expand Down Expand Up @@ -154,7 +162,7 @@ jobs:
with:
shared-key: ci
save-if: ${{ env.RUST_CACHE_SAVE_IF }}
- uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29
- uses: taiki-e/install-action@5488ac5a951645ce95062214902ac4b6bc1a1037 # v2.87.32
with:
tool: cargo-nextest
- uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable
Expand All @@ -181,10 +189,14 @@ jobs:
- name: Test
env:
SCOPE_ARGS: ${{ steps.scope.outputs.args }}
RUST_FLUENT: ${{ needs.changes.outputs.rust_fluent }}
CARGO_PROFILE_TEST_DEBUG: 0
run: |
read -r -a args <<<"$SCOPE_ARGS"
cargo nextest run "${args[@]}" --all-targets --locked --no-default-features --features default-tls
if [[ "$RUST_FLUENT" == true ]]; then
cargo nextest run -p rtbit-fluent --all-targets --locked
fi
# The shipped binary is worth a release-profile compile on a PR that
# touches it. The queue builds it for every entry anyway.
- name: Build the release binary
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ jobs:
esac
fi
printf 'ref=%s\n' "$ref" >> "$GITHUB_OUTPUT"
- uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
- uses: github/codeql-action/init@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
languages: ${{ matrix.language }}
- uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
- uses: github/codeql-action/analyze@9b3254085494b55a0f7c4c2b3d2d52cc712ce370 # v4.39.1
with:
category: /language:${{ matrix.language }}
ref: ${{ steps.target.outputs.ref }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/compat-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
- uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down Expand Up @@ -72,7 +72,7 @@ jobs:
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
- uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down
63 changes: 62 additions & 1 deletion .github/workflows/container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
branches: [main, dev]
tags: ['v*']
workflow_dispatch:
merge_group:
types: [checks_requested]

permissions:
contents: read
Expand All @@ -16,6 +18,7 @@ concurrency:

jobs:
publish:
if: github.event_name != 'merge_group'
# Privileged publication capacity is selected only for this repository and
# this workflow deliberately has no pull_request trigger.
runs-on: [self-hosted, linux, docker, publish]
Expand All @@ -25,7 +28,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: docker/setup-qemu-action@99012661954931238ded8c8b007157a8430204e1 # v4
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4
- uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
- uses: docker/login-action@81c6f93d4bc991e510b342a00b419b3bb4efc5c6 # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down Expand Up @@ -80,3 +83,61 @@ jobs:
-H 'Accept: application/vnd.oci.image.index.v1+json, application/vnd.oci.image.manifest.v1+json, application/vnd.docker.distribution.manifest.v2+json' \
"https://ghcr.io/v2/thedancingdeveloper-org/rusttorrent/manifests/$tag" > manifest.json
jq -e '.schemaVersion == 2' manifest.json >/dev/null

smoke:
if: github.event_name == 'merge_group'
runs-on: [self-hosted, linux, docker, publish]
permissions:
contents: read
env:
IMAGE: rusttorrent-container-smoke:${{ github.sha }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Build the daemon image
run: docker build --tag "$IMAGE" --file Dockerfile .
- name: Start and probe the daemon
shell: bash
run: |
set -euo pipefail
volume="rusttorrent-smoke-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
container="rusttorrent-smoke-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
cleanup() {
docker rm --force "$container" >/dev/null 2>&1 || true
docker volume rm "$volume" >/dev/null 2>&1 || true
docker image rm "$IMAGE" >/dev/null 2>&1 || true
}
trap cleanup EXIT

docker volume create "$volume" >/dev/null
docker run --detach --name "$container" --volume "$volume:/home/rtbit/db" \
--publish 3030:3030 "$IMAGE" >/dev/null

deadline=$((SECONDS + 30))
setup_token=''
while (( SECONDS < deadline )); do
if ! setup_token=$(docker exec "$container" cat /home/rtbit/db/session/setup-token 2>/dev/null); then
setup_token=''
fi
if [[ -n "$setup_token" ]] && curl --fail --silent --show-error \
--output /dev/null http://127.0.0.1:3030/healthz; then
break
fi
sleep 1
done
[[ -n "$setup_token" ]]
(( SECONDS < deadline ))

curl --fail --silent --show-error \
--header 'Content-Type: application/json' \
--data "{\"username\":\"smoke\",\"password\":\"smoke-password\",\"setup_token\":\"$setup_token\"}" \
http://127.0.0.1:3030/api/v2/auth/setup >/dev/null
version=$(curl --fail --silent --show-error \
--user smoke:smoke-password http://127.0.0.1:3030/api/v2/app/webapiVersion)
[[ "$version" == '2.11.3' ]]
curl --fail --silent --show-error \
http://127.0.0.1:3030/healthz >/dev/null

docker stop --time 30 "$container" >/dev/null
[[ "$(docker inspect --format '{{.State.ExitCode}}' "$container")" == 0 ]]
docker run --rm --volume "$volume:/data" --entrypoint sh "$IMAGE" \
-c 'test -s /data/session/session.json'
19 changes: 19 additions & 0 deletions .github/workflows/policy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,22 @@ jobs:
- name: Verify migration policies
shell: bash
run: bash ci/migration-policy.sh
- name: Detect dependency policy changes
id: dependency-policy
if: github.event_name == 'pull_request'
shell: bash
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
if git diff --quiet "$BASE_SHA" HEAD -- Cargo.lock ':(glob)**/Cargo.toml' deny.toml; then
echo "run=false" >> "$GITHUB_OUTPUT"
else
echo "run=true" >> "$GITHUB_OUTPUT"
fi
- uses: taiki-e/install-action@8cca0918f8471c33515202b73f56ab27f2bed283 # v2.87.29
if: github.event_name != 'pull_request' || steps.dependency-policy.outputs.run == 'true'
with:
tool: cargo-deny@0.20.2
- name: Verify Rust dependency policy
if: github.event_name != 'pull_request' || steps.dependency-policy.outputs.run == 'true'
run: cargo deny check advisories licenses bans sources
62 changes: 62 additions & 0 deletions .github/workflows/release-dry-run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ jobs:
cargo build -p rtbit-fluent --release --target x86_64-pc-windows-msvc
rm -rf target/desktop-stage
bash packaging/scripts/build-desktop.sh windows "$tag" target/desktop-stage
- name: Smoke-test Windows fluent artifact
shell: bash
run: |
set -euo pipefail
version="$(sed -n 's/^version = "\(.*\)"/\1/p' crates/rtbit/Cargo.toml | head -1)"
tag="v$version"
expected="rtbit-fluent $version"
actual="$(target/desktop-stage/rtbit-fluent-"$tag"-windows-x86_64.exe --version)"
test "$actual" = "$expected"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-dry-run-windows-fluent-${{ github.sha }}
Expand Down Expand Up @@ -157,6 +166,14 @@ jobs:
rm -rf target/desktop-stage
bash packaging/scripts/build-desktop.sh linux "$tag" target/desktop-stage
bash packaging/scripts/build-desktop.sh sbom "$tag" target/desktop-stage
- name: Smoke-test Linux fluent artifact
shell: bash
run: |
set -euo pipefail
tag="${{ steps.tag.outputs.tag }}"
expected="rtbit-fluent ${tag#v}"
actual="$(target/desktop-stage/rtbit-fluent-"$tag"-linux-x86_64 --version)"
test "$actual" = "$expected"
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
continue-on-error: true
with:
Expand Down Expand Up @@ -278,3 +295,48 @@ jobs:
done
test "$count" -eq 2 || { echo "::error::expected 2 signed executables (daemon and fluent), verified $count"; exit 1; }
(cd release-artifacts && sha256sum -c "SHA256SUMS-$tag.txt")

report-failure:
name: Report release dry-run failure
if: >-
${{ always() && github.event_name != 'pull_request' &&
(needs.build-windows-fluent.result == 'failure' || needs.dry-run.result == 'failure') }}
needs: [build-windows-fluent, dry-run]
runs-on: [self-hosted, linux]
permissions:
contents: read
issues: write
steps:
- name: Open or update the tracking issue
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
with:
script: |
const title = '[CI] Release dry run is failing';
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
const report = [
`The ${context.eventName} release dry run failed.`,
'',
`Run: ${runUrl}`,
`Commit: ${context.sha}`,
'',
'This workflow does not publish release artifacts.',
].join('\n');
const {data: issues} = await github.rest.issues.listForRepo({
...context.repo,
state: 'open',
per_page: 100,
});
const existing = issues.find(issue => !issue.pull_request && issue.title === title);
if (existing) {
await github.rest.issues.createComment({
...context.repo,
issue_number: existing.number,
body: report,
});
} else {
await github.rest.issues.create({
...context.repo,
title,
body: report,
});
}
Loading
Loading