fix: ci lint

pull/370/head
zijiren233 5 months ago
parent fb99211b38
commit 4f6847c925
No known key found for this signature in database
GPG Key ID: 534E082AAA9B39DC

@ -37,34 +37,6 @@ jobs:
- name: Check formatting
run: cargo fmt --all -- --check
# Run Clippy lints
clippy:
name: Clippy Lints
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Install protobuf compiler
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
- name: Print Rust environment
run: |
rustc -Vv
cargo -V
cargo clippy -V
uname -a
- name: Run Clippy
run: cargo clippy --workspace --all-targets --locked
# Build
build:
name: Build
@ -103,6 +75,8 @@ jobs:
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- name: Install cargo-nextest
uses: taiki-e/install-action@nextest
@ -122,10 +96,10 @@ jobs:
- name: Cache Rust build artifacts
uses: Swatinem/rust-cache@v2
- name: Run non-ignored checks
- name: Run clippy
timeout-minutes: 60
run: |
cargo check --workspace --locked
cargo clippy --workspace --all-targets --locked
- name: Run non-ignored tests with nextest
timeout-minutes: 60
@ -172,7 +146,7 @@ jobs:
- name: Run ignored tests with nextest
timeout-minutes: 60
run: |
cargo nextest run --workspace --locked --run-ignored only --nff
cargo nextest run --workspace --locked --run-ignored only --nff -j$(nproc)
# Security audit
security-audit:
@ -227,19 +201,6 @@ jobs:
run: cargo deny check sources
continue-on-error: false # Fail on untrusted sources
# Dependency review (only on PRs)
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: moderate
# Check for unused dependencies
udeps:
name: Unused Dependencies

@ -0,0 +1,27 @@
name: Dependency Review
on:
pull_request:
paths:
- Cargo.lock
- Cargo.toml
- "**/Cargo.toml"
permissions:
contents: read
jobs:
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: moderate

6
Cargo.lock generated

@ -4769,21 +4769,16 @@ dependencies = [
"http-body",
"http-body-util",
"hyper",
"hyper-rustls",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls",
"rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tokio-rustls",
"tokio-util",
"tower",
"tower-http",
@ -4793,7 +4788,6 @@ dependencies = [
"wasm-bindgen-futures",
"wasm-streams 0.4.2",
"web-sys",
"webpki-roots 1.0.7",
]
[[package]]

@ -121,7 +121,8 @@ reqwest = { version = "0.13", default-features = false, features = [
# Database
sqlx = { version = "0.8", features = [
"runtime-tokio-rustls",
"runtime-tokio",
"tls-rustls-aws-lc-rs",
"postgres",
"migrate",
"uuid",
@ -186,7 +187,10 @@ webrtc = "0.17.1"
synctv-xiu = { path = "synctv-xiu", default-features = false }
# Object Storage
opendal = { version = "0.55.0", features = ["services-s3"] }
opendal = { version = "0.55.0", default-features = false, features = [
"executors-tokio",
"services-s3",
] }
# Logging & Tracing
tracing = "0.1.44"
@ -243,7 +247,10 @@ ipnet = "2.12.0"
# Email
lettre = { version = "0.11", default-features = false, features = [
"tokio1-rustls-tls",
"tokio1-rustls",
"rustls-no-provider",
"aws-lc-rs",
"webpki-roots",
"builder",
"smtp-transport",
"hostname",
@ -276,8 +283,14 @@ utoipa-swagger-ui = { version = "9.0.2", features = ["axum"] }
mockall = "0.14.0"
wiremock = "0.6.5"
tempfile = "3.27.0"
testcontainers = "0.27.3"
testcontainers-modules = { version = "0.15.0", features = ["postgres", "redis"] }
testcontainers = { version = "0.27.3", default-features = false, features = [
"aws-lc-rs",
] }
testcontainers-modules = { version = "0.15.0", default-features = false, features = [
"aws-lc-rs",
"postgres",
"redis",
] }
tokio-tungstenite = { version = "0.29.0", default-features = false, features = ["connect"] }
# Benchmarking

@ -355,6 +355,7 @@ fn check_email_health(svc: &synctv_core::service::EmailService) -> String {
/// additional traffic to prevent OOM or performance degradation.
const MEMORY_UNHEALTHY_THRESHOLD_PERCENT: f64 = 90.0;
#[cfg(any(target_os = "linux", target_os = "macos", test))]
fn memory_usage_percent(used_bytes: u64, total_bytes: u64) -> Option<f64> {
if total_bytes == 0 {
return None;

@ -941,15 +941,10 @@ impl RemoteProviderManager {
}
}
let provider = rustls::crypto::CryptoProvider::get_default()
.cloned()
.unwrap_or_else(|| Arc::new(rustls::crypto::ring::default_provider()));
let guard = synctv_common::ssrf::SsrfGuard::default_policy();
let address_overrides = Arc::clone(&self.address_overrides);
let tls_config = ClientConfig::builder_with_provider(provider)
.with_safe_default_protocol_versions()
.map_err(|e| format!("TLS protocol version error: {e}"))?
let tls_config = ClientConfig::builder()
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoVerifier))
.with_no_client_auth();

@ -3180,8 +3180,22 @@ async fn scenario_provider_instance_parse_timeout() {
}
fn install_rustls_provider_once() {
let _ =
rustls::crypto::CryptoProvider::install_default(rustls::crypto::ring::default_provider());
let _ = rustls::crypto::CryptoProvider::install_default(default_rustls_provider());
}
fn default_rustls_provider() -> rustls::crypto::CryptoProvider {
#[cfg(feature = "tls-aws-lc")]
{
rustls::crypto::aws_lc_rs::default_provider()
}
#[cfg(all(not(feature = "tls-aws-lc"), feature = "tls-ring"))]
{
rustls::crypto::ring::default_provider()
}
#[cfg(not(any(feature = "tls-aws-lc", feature = "tls-ring")))]
compile_error!("remote_provider_manager_tests require a rustls crypto provider feature");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]

@ -5,7 +5,9 @@ use anyhow::Context;
use tokio::sync::watch;
use tokio::task::JoinHandle;
use tonic::transport::Server;
use tracing::{info, warn};
use tracing::info;
#[cfg(unix)]
use tracing::warn;
use synctv_api::impls::{AdminApiImpl, ClientApiImpl};
use synctv_core::{
@ -31,7 +33,17 @@ pub async fn spawn_management_server(
) -> anyhow::Result<JoinHandle<anyhow::Result<()>>> {
match config.config.management.transport {
ManagementTransport::Tcp => spawn_management_tcp_server(config).await,
ManagementTransport::Unix => spawn_management_unix_server(config),
ManagementTransport::Unix => {
#[cfg(unix)]
{
spawn_management_unix_server(config)
}
#[cfg(not(unix))]
{
spawn_management_unix_server(&config)
}
}
}
}
@ -52,42 +64,41 @@ async fn spawn_management_tcp_server(
Ok(handle)
}
#[cfg(unix)]
fn spawn_management_unix_server(
config: ManagementServerConfig,
) -> anyhow::Result<JoinHandle<anyhow::Result<()>>> {
#[cfg(not(unix))]
{
let _ = config;
Err(anyhow::anyhow!(
"management.transport=unix is not supported on this platform"
))
}
#[cfg(unix)]
{
let socket_path = config.config.management.unix_socket_path.clone();
prepare_management_unix_socket(&socket_path)?;
let listener = tokio::net::UnixListener::bind(&socket_path).with_context(|| {
format!(
"failed to bind management unix socket {}",
absolute_display_path(Path::new(&socket_path))
)
})?;
restrict_management_unix_socket_permissions(Path::new(&socket_path))?;
info!(
"Management gRPC server listening on unix://{}",
let socket_path = config.config.management.unix_socket_path.clone();
prepare_management_unix_socket(&socket_path)?;
let listener = tokio::net::UnixListener::bind(&socket_path).with_context(|| {
format!(
"failed to bind management unix socket {}",
absolute_display_path(Path::new(&socket_path))
);
)
})?;
restrict_management_unix_socket_permissions(Path::new(&socket_path))?;
info!(
"Management gRPC server listening on unix://{}",
absolute_display_path(Path::new(&socket_path))
);
let handle = tokio::spawn(async move {
let incoming = tokio_stream::wrappers::UnixListenerStream::new(listener);
let result = serve_management(config, incoming, Some(socket_path.clone())).await;
cleanup_management_unix_socket(&socket_path);
result
});
let handle = tokio::spawn(async move {
let incoming = tokio_stream::wrappers::UnixListenerStream::new(listener);
let result = serve_management(config, incoming, Some(socket_path.clone())).await;
cleanup_management_unix_socket(&socket_path);
result
});
Ok(handle)
}
Ok(handle)
}
#[cfg(not(unix))]
fn spawn_management_unix_server(
_: &ManagementServerConfig,
) -> anyhow::Result<JoinHandle<anyhow::Result<()>>> {
Err(anyhow::anyhow!(
"management.transport=unix is not supported on this platform"
))
}
async fn serve_management<I, IO>(

@ -1,9 +1,9 @@
use anyhow::{bail, Context, Result};
#[cfg(unix)]
use hyper_util::rt::TokioIo;
use std::time::Duration;
use synctv_core::bootstrap::{load_config_with_options, load_dotenv, LoadConfigOptions};
use synctv_management::proto::management_service_client::ManagementServiceClient;
use tokio::net::UnixStream;
use tonic::transport::Channel;
use tonic::{metadata::MetadataValue, service::Interceptor, Request, Status};
@ -247,35 +247,50 @@ async fn connect_channel(endpoint: &str) -> Result<Channel> {
.connect()
.await
.with_context(|| format!("failed to connect to admin endpoint {endpoint}")),
AdminEndpoint::Unix(path) => {
let error_path = path.clone();
tonic::transport::Endpoint::try_from("http://[::]:50052")
.context("invalid synthetic unix endpoint")?
.connect_timeout(MANAGEMENT_CONNECT_TIMEOUT)
.connect_with_connector(tower::service_fn(move |_: tonic::transport::Uri| {
let path = path.clone();
async move {
let stream = UnixStream::connect(path).await?;
Ok::<_, std::io::Error>(TokioIo::new(stream))
}
}))
.await
.with_context(|| format!("failed to connect to admin unix socket {error_path}"))
}
AdminEndpoint::Unix(path) => connect_unix_channel(&path).await,
}
}
#[cfg(unix)]
async fn connect_unix_channel(path: &str) -> Result<Channel> {
let socket_path = path.to_owned();
let error_path = socket_path.clone();
tonic::transport::Endpoint::try_from("http://[::]:50052")
.context("invalid synthetic unix endpoint")?
.connect_timeout(MANAGEMENT_CONNECT_TIMEOUT)
.connect_with_connector(tower::service_fn(move |_: tonic::transport::Uri| {
let path = socket_path.clone();
async move {
let stream = tokio::net::UnixStream::connect(path).await?;
Ok::<_, std::io::Error>(TokioIo::new(stream))
}
}))
.await
.with_context(|| format!("failed to connect to admin unix socket {error_path}"))
}
#[cfg(not(unix))]
fn connect_unix_channel(_path: &str) -> std::future::Ready<Result<Channel>> {
std::future::ready(Err(anyhow::anyhow!(
"unix management endpoints are not supported on this platform"
)))
}
#[cfg(test)]
mod tests {
use super::{
normalize_endpoint, resolve_candidate_endpoints, AdminConnectionOptions, RemoteAdminSession,
};
use super::{normalize_endpoint, resolve_candidate_endpoints, AdminConnectionOptions};
#[cfg(unix)]
use super::RemoteAdminSession;
#[cfg(unix)]
use std::pin::Pin;
use synctv_core::config::default_management_unix_socket_path;
use tempfile::tempdir;
#[cfg(unix)]
use futures_util::stream;
#[cfg(unix)]
use std::sync::{Arc, Mutex};
#[cfg(unix)]
use synctv_management::proto::{
management_service_server::{ManagementService, ManagementServiceServer},
AddAdminRequest, AddDirectUrlMediaRequest, AddMediaRequest, AddProviderInstanceRequest,
@ -299,8 +314,11 @@ mod tests {
UpdateSettingsRequest, UpdateUserPasswordRequest, UpdateUserRoleRequest,
UpdateUserUsernameRequest,
};
#[cfg(unix)]
use synctv_proto::{admin as admin_proto, client as client_proto};
#[cfg(unix)]
use tonic::transport::Server;
#[cfg(unix)]
use tonic::{Request, Response, Status};
struct EnvVarGuard {
@ -318,6 +336,7 @@ mod tests {
}
}
#[cfg(unix)]
fn set(key: &'static str, value: &str) -> Self {
let previous = std::env::var(key).ok();
std::env::set_var(key, value);
@ -356,11 +375,13 @@ mod tests {
}
}
#[cfg(unix)]
#[derive(Clone, Default)]
struct TestManagementService {
seen_authorization: Option<Arc<Mutex<Vec<Option<String>>>>>,
}
#[cfg(unix)]
#[tonic::async_trait]
impl ManagementService for TestManagementService {
type StopServerStream =
@ -974,6 +995,7 @@ management:
let _ = serve_handle.await;
}
#[cfg(unix)]
#[tokio::test]
async fn remote_admin_session_injects_management_bearer_token_from_config() {
let _env_guard = EnvVarGuard::remove("SYNCTV_MANAGEMENT_AUTH_TOKEN");
@ -1040,6 +1062,7 @@ management:
let _ = serve_handle.await;
}
#[cfg(unix)]
#[tokio::test]
async fn remote_admin_session_does_not_inherit_config_token_for_explicit_endpoint() {
let _env_guard = EnvVarGuard::remove("SYNCTV_MANAGEMENT_AUTH_TOKEN");
@ -1107,6 +1130,7 @@ management:
let _ = serve_handle.await;
}
#[cfg(unix)]
#[tokio::test]
async fn remote_admin_session_can_opt_in_to_config_token_for_explicit_endpoint() {
let _env_guard = EnvVarGuard::remove("SYNCTV_MANAGEMENT_AUTH_TOKEN");
@ -1174,6 +1198,7 @@ management:
let _ = serve_handle.await;
}
#[cfg(unix)]
#[tokio::test]
async fn remote_admin_session_uses_env_token_for_explicit_endpoint() {
let _env_guard =
@ -1227,6 +1252,7 @@ management:
let _ = serve_handle.await;
}
#[cfg(unix)]
#[tokio::test]
async fn remote_admin_session_with_explicit_endpoint_ignores_missing_config_file() {
let temp_dir = tempfile::tempdir().expect("temp dir should be created");

Loading…
Cancel
Save