From 12938d1ee46fd1c0a1eb1cafed95c1e27425cf1c Mon Sep 17 00:00:00 2001 From: Neshura Date: Tue, 12 Dec 2023 20:49:39 +0100 Subject: [PATCH 01/13] Various linting changes --- src/main.rs | 4 +--- src/v1/mod.rs | 29 ++++++++++++++--------------- src/v1/schemas.rs | 3 +-- src/v3/mod.rs | 2 +- src/v3/schemas.rs | 2 +- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/main.rs b/src/main.rs index 51e8abb..e973a6d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -225,8 +225,6 @@ async fn main() { Url::new("v3-L", concat!(api_base_3!(), "/openapi.json")), ]; - let is_alive: Arc = Arc::new(AtomicBool::new(true)); - loop { let db_auth_tokens = config.auth.clone(); let pool = PgPool::connect(dotenv!("DATABASE_URL")).await.unwrap(); @@ -256,7 +254,7 @@ async fn main() { abort() }); - let server = HttpServer::new(move || { + let _ = HttpServer::new(move || { App::new() .app_data(web::Data::new(AppState { db: pool.clone(), auth_tokens: db_auth_tokens.clone() })) .wrap(Logger::default()) diff --git a/src/v1/mod.rs b/src/v1/mod.rs index ad7c47a..cddfbba 100644 --- a/src/v1/mod.rs +++ b/src/v1/mod.rs @@ -1,5 +1,4 @@ use crate::{db, AppState}; -use actix_web::web::Json; use actix_web::{delete, get, post, put, web, HttpRequest, HttpResponse, Responder}; use std::collections::HashMap; use std::ops::Deref; @@ -9,7 +8,7 @@ use sqlx::QueryBuilder; pub(crate) mod schemas; -fn get_auth_header<'a>(req: &'a HttpRequest) -> Option<&'a str> { +fn get_auth_header(req: &HttpRequest) -> Option<&str> { req.headers().get("x-api-key")?.to_str().ok() } @@ -90,18 +89,18 @@ async fn get_user( Err(_) => return HttpResponse::InternalServerError().finish(), }; - let mut permissions: HashMap = HashMap::new(); + let mut user_permissions: HashMap = HashMap::new(); - permissions.insert("game_permissions".to_string(), user.game_permissions); - permissions.insert("empire_permissions".to_string(), user.empire_permissions); - permissions.insert("data_permissions".to_string(), user.data_permissions); - permissions.insert("user_permissions".to_string(), user.user_permissions); + user_permissions.insert("game_permissions".to_string(), user.game_permissions); + user_permissions.insert("empire_permissions".to_string(), user.empire_permissions); + user_permissions.insert("data_permissions".to_string(), user.data_permissions); + user_permissions.insert("user_permissions".to_string(), user.user_permissions); let return_data = schemas::User { user_token: user.token, discord_handle: user.discord_id, profile_picture: user.picture_url, - permissions: permissions + permissions: user_permissions }; return HttpResponse::Ok().json(return_data); @@ -290,17 +289,17 @@ pub(crate) async fn update_user( }; } - let mut permissions: HashMap = HashMap::new(); - permissions.insert("game_permissions".to_string(), user.game_permissions); - permissions.insert("empire_permissions".to_string(), user.empire_permissions); - permissions.insert("data_permissions".to_string(), user.data_permissions); - permissions.insert("user_permissions".to_string(), user.user_permissions); + let mut user_permissions: HashMap = HashMap::new(); + user_permissions.insert("game_permissions".to_string(), user.game_permissions); + user_permissions.insert("empire_permissions".to_string(), user.empire_permissions); + user_permissions.insert("data_permissions".to_string(), user.data_permissions); + user_permissions.insert("user_permissions".to_string(), user.user_permissions); let return_data = schemas::User { user_token: user.token, discord_handle: user.discord_id, profile_picture: user.picture_url, - permissions: permissions + permissions: user_permissions }; return HttpResponse::Ok().json(return_data); } else { @@ -348,7 +347,7 @@ pub(crate) async fn delete_user( .await { Ok(_) => {} - Err(e) => { + Err(_) => { return HttpResponse::InternalServerError().finish(); } }; diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs index e561cce..d6d9d65 100644 --- a/src/v1/schemas.rs +++ b/src/v1/schemas.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; -use utoipa::{IntoParams, ToSchema}; -use crate::v3::schemas::ChellarisGameLegacy; +use utoipa::{ToSchema}; // DB Permission Enums diff --git a/src/v3/mod.rs b/src/v3/mod.rs index 9d904a3..f1c414c 100644 --- a/src/v3/mod.rs +++ b/src/v3/mod.rs @@ -31,7 +31,7 @@ fn verify_auth(token: Option<&str>, data: &AppState) -> schemas::AuthReturn { return auth_return; } -fn get_auth_header<'a>(req: &'a HttpRequest) -> Option<&'a str> { +fn get_auth_header(req: &HttpRequest) -> Option<&str> { req.headers().get("x-api-key")?.to_str().ok() } diff --git a/src/v3/schemas.rs b/src/v3/schemas.rs index 847bccc..709a7b2 100644 --- a/src/v3/schemas.rs +++ b/src/v3/schemas.rs @@ -1,4 +1,4 @@ -use std::{collections::HashMap, hash::Hash}; +use std::{collections::HashMap}; use serde::{Serialize, Deserialize}; use utoipa::{ToSchema, IntoParams}; From c01ed85e7af3c90cad6bfc96a68ce2e5c1f33e44 Mon Sep 17 00:00:00 2001 From: Neshura Date: Tue, 12 Dec 2023 21:10:04 +0100 Subject: [PATCH 02/13] Postgres Watchdog Fix --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index e973a6d..f1df875 100644 --- a/src/main.rs +++ b/src/main.rs @@ -247,7 +247,7 @@ async fn main() { println!(" -> http://[{}]:{}", Ipv6Addr::UNSPECIFIED, 8080); println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080); - let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone) }); + let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone).await }); tokio::spawn(async move { actix_web::rt::signal::ctrl_c().await.unwrap(); println!("Ctrl-C received, killing Server"); From 83a1af59d9a413ff8d145d94b7deb434dba93a3b Mon Sep 17 00:00:00 2001 From: Neshura Date: Tue, 12 Dec 2023 21:15:50 +0100 Subject: [PATCH 03/13] General SIGINT handling instead of CTRLC handling --- src/main.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index f1df875..fd57680 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use chrono::Local; use actix_web::{middleware::Logger, web, App, HttpServer}; use serde::{Deserialize, Serialize}; use sqlx::{PgPool, Pool, Postgres, Connection}; +use tokio::signal::unix::SignalKind; use utoipa::{OpenApi, openapi::security::{SecurityScheme, ApiKey, ApiKeyValue}, Modify}; use utoipa_swagger_ui::{Config, SwaggerUi, Url}; @@ -249,8 +250,8 @@ async fn main() { let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone).await }); tokio::spawn(async move { - actix_web::rt::signal::ctrl_c().await.unwrap(); - println!("Ctrl-C received, killing Server"); + actix_web::rt::signal::unix::signal(SignalKind::interrupt()).unwrap().recv().await; + println!("SIGINT received, killing Server"); abort() }); From c0799484bba11f2b06e8e32b1ca6ff6753bb27ec Mon Sep 17 00:00:00 2001 From: Neshura Date: Tue, 12 Dec 2023 21:25:57 +0100 Subject: [PATCH 04/13] Add SigTerm handling for systemctl stop --- src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.rs b/src/main.rs index fd57680..5f59b99 100644 --- a/src/main.rs +++ b/src/main.rs @@ -249,6 +249,11 @@ async fn main() { println!(" -> http://{}:{}", Ipv4Addr::UNSPECIFIED, 8080); let watchdog_thread = tokio::spawn(async move { postgres_watchdog(pool_copy, shutdown_clone).await }); + tokio::spawn(async move { + actix_web::rt::signal::unix::signal(SignalKind::terminate()).unwrap().recv().await; + println!("SIGTERM received, killing Server"); + abort() + }); tokio::spawn(async move { actix_web::rt::signal::unix::signal(SignalKind::interrupt()).unwrap().recv().await; println!("SIGINT received, killing Server"); From 8373b278cc6242be75115381e755e1bbc2a668f7 Mon Sep 17 00:00:00 2001 From: Neshura Date: Tue, 12 Dec 2023 22:11:32 +0100 Subject: [PATCH 05/13] Various Fixes to API v1 --- src/v1/mod.rs | 90 +++++++++++++++++++++++++++-------------------- src/v1/schemas.rs | 6 ++-- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/v1/mod.rs b/src/v1/mod.rs index cddfbba..118d0ca 100644 --- a/src/v1/mod.rs +++ b/src/v1/mod.rs @@ -48,7 +48,9 @@ async fn verify_user_auth(data: &web::Data, auth_token: &str, user_tok // User Endpoints #[utoipa::path( - request_body = schemas::GetUserParams, + params( + schemas::GetUserParams + ), responses( (status = 200, description = "OK", body = User), (status = 403, description = "Unauthorized"), @@ -59,7 +61,7 @@ async fn verify_user_auth(data: &web::Data, auth_token: &str, user_tok ), )] #[get("/api/v1/user")] -async fn get_user( +pub(crate) async fn get_user( data: web::Data, params: web::Json, req: HttpRequest, @@ -195,9 +197,17 @@ pub(crate) async fn update_user( None => return HttpResponse::Unauthorized().finish(), }; + let mut user_permissions: HashMap = HashMap::new(); + match params.permissions { + Some(data) => {user_permissions = data.clone()}, + None => {}, + } + let mut elevated_auth = false; - if params.permissions["game_permissions"] || params.permissions["empire_permissions"] || params.permissions["data_permissions"] || params.permissions["user_permissions"] { - elevated_auth = true; + if user_permissions.len() != 0 { + if user_permissions["game_permissions"] || user_permissions["empire_permissions"] || user_permissions["data_permissions"] || user_permissions["user_permissions"] { + elevated_auth = true; + } } let auth = verify_user_auth(&data, &auth_token, ¶ms.user_token, schemas::TablePermission::User, elevated_auth).await; @@ -225,41 +235,43 @@ pub(crate) async fn update_user( any_param_present = true; } - for (entry, value) in params.permissions.iter() { - match entry.deref() { - "game_permissions" => { - user_query_separated.push( " game_permissions = "); - match any_param_present { - true => user_query_separated.push_bind(value), - false => user_query_separated.push_bind_unseparated(value) - }; - any_param_present = true; - }, - "empire_permissions" => { - user_query_separated.push( " empire_permissions = "); - match any_param_present { - true => user_query_separated.push_bind(value), - false => user_query_separated.push_bind_unseparated(value) - }; - any_param_present = true; - }, - "data_permissions" => { - user_query_separated.push( " data_permissions = "); - match any_param_present { - true => user_query_separated.push_bind(value), - false => user_query_separated.push_bind_unseparated(value) - }; - any_param_present = true; - }, - "user_permissions" => { - user_query_separated.push( " user_permissions = "); - match any_param_present { - true => user_query_separated.push_bind(value), - false => user_query_separated.push_bind_unseparated(value) - }; - any_param_present = true; - }, - _ => {} + if user_permissions.len() != 0 { + for (entry, value) in user_permissions.iter() { + match entry.deref() { + "game_permissions" => { + user_query_separated.push( " game_permissions = "); + match any_param_present { + true => user_query_separated.push_bind(value), + false => user_query_separated.push_bind_unseparated(value) + }; + any_param_present = true; + }, + "empire_permissions" => { + user_query_separated.push( " empire_permissions = "); + match any_param_present { + true => user_query_separated.push_bind(value), + false => user_query_separated.push_bind_unseparated(value) + }; + any_param_present = true; + }, + "data_permissions" => { + user_query_separated.push( " data_permissions = "); + match any_param_present { + true => user_query_separated.push_bind(value), + false => user_query_separated.push_bind_unseparated(value) + }; + any_param_present = true; + }, + "user_permissions" => { + user_query_separated.push( " user_permissions = "); + match any_param_present { + true => user_query_separated.push_bind(value), + false => user_query_separated.push_bind_unseparated(value) + }; + any_param_present = true; + }, + _ => {} + } } } diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs index d6d9d65..8fea931 100644 --- a/src/v1/schemas.rs +++ b/src/v1/schemas.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; -use utoipa::{ToSchema}; +use utoipa::{IntoParams, ToSchema}; // DB Permission Enums @@ -32,7 +32,7 @@ pub struct User { pub permissions: HashMap, } -#[derive(Serialize, Deserialize, ToSchema, Debug)] +#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] pub struct GetUserParams { #[schema(example = "abcdef")] pub user_token: String, @@ -54,7 +54,7 @@ pub struct UpdateUserParams { [\"user_permissions\"]: false, }\ ")] - pub permissions: HashMap, + pub permissions: Option>, } #[derive(Serialize, Deserialize, ToSchema, Debug)] From c8ed40c3cc3e8da68c0b0358fefc3759b7c749ef Mon Sep 17 00:00:00 2001 From: Neshura Date: Wed, 13 Dec 2023 19:05:58 +0100 Subject: [PATCH 06/13] Add Version Checking to Actions file --- .forgejo/workflows/build+release.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml index dd35a7c..ccbb560 100644 --- a/.forgejo/workflows/build+release.yml +++ b/.forgejo/workflows/build+release.yml @@ -10,9 +10,22 @@ jobs: run-tests: runs-on: docker steps: + - + name: Checking Out Repository Code + uses: https://code.forgejo.org/actions/checkout@v3 - name: Placeholder run: echo Placeholder Job + - + name: Check if Version in Cargo.toml matches Tag + run: | + VERSION=$(cat src-tauri/Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ") + if test $VERSION != "${{ github.ref_name }}"; then + echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'"; + exit 1 + else + echo "Version is: '$VERSION'"; + fi build: needs: test From 5c0c03fd7a10f7a435663f41dc0ecd00ac1369fb Mon Sep 17 00:00:00 2001 From: Neshura Date: Wed, 13 Dec 2023 19:06:32 +0100 Subject: [PATCH 07/13] Fix Param Naming mismatch --- src/v1/mod.rs | 10 ++++------ src/v1/schemas.rs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/v1/mod.rs b/src/v1/mod.rs index 118d0ca..4c0fb1b 100644 --- a/src/v1/mod.rs +++ b/src/v1/mod.rs @@ -48,9 +48,7 @@ async fn verify_user_auth(data: &web::Data, auth_token: &str, user_tok // User Endpoints #[utoipa::path( - params( - schemas::GetUserParams - ), + request_body = GetUserParams, responses( (status = 200, description = "OK", body = User), (status = 403, description = "Unauthorized"), @@ -60,7 +58,7 @@ async fn verify_user_auth(data: &web::Data, auth_token: &str, user_tok ("api_key" = []) ), )] -#[get("/api/v1/user")] +#[post("/api/v1/user")] pub(crate) async fn get_user( data: web::Data, params: web::Json, @@ -118,7 +116,7 @@ pub(crate) async fn get_user( (status = 500, description = "Internal Server Error") ), )] -#[post("/api/v1/user")] +#[post("/api/v1/user/create")] pub(crate) async fn create_user( data: web::Data, ) -> impl Responder { @@ -320,7 +318,7 @@ pub(crate) async fn update_user( } #[utoipa::path( - request_body = schemas::DeleteUserParams, + request_body = DeleteUserParams, responses( (status = 200, description = "OK"), (status = 403, description = "Unauthorized"), diff --git a/src/v1/schemas.rs b/src/v1/schemas.rs index 8fea931..81c23c3 100644 --- a/src/v1/schemas.rs +++ b/src/v1/schemas.rs @@ -32,7 +32,7 @@ pub struct User { pub permissions: HashMap, } -#[derive(Serialize, Deserialize, ToSchema, Debug, IntoParams)] +#[derive(Serialize, Deserialize, ToSchema, Debug)] pub struct GetUserParams { #[schema(example = "abcdef")] pub user_token: String, From 22fa59334cc41ff145e39e98781512d76e517329 Mon Sep 17 00:00:00 2001 From: Neshura Date: Wed, 13 Dec 2023 19:06:46 +0100 Subject: [PATCH 08/13] move API docs to different route than API endpoints --- src/main.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 5f59b99..6a3a574 100644 --- a/src/main.rs +++ b/src/main.rs @@ -221,9 +221,9 @@ async fn main() { struct ApiDocV1; let openapi_urls = vec![ - Url::new("v1", concat!(api_base_1!(), "/openapi.json")), - Url::new("v2-L", concat!(api_base_2!(), "/openapi.json")), - Url::new("v3-L", concat!(api_base_3!(), "/openapi.json")), + Url::new("v1", concat!(api_base!(), "-docs/openapi1.json")), + Url::new("v2-L", concat!(api_base!(), "-docs/openapi2l.json")), + Url::new("v3-L", concat!(api_base!(), "-docs/openapi3l.json")), ]; loop { @@ -299,15 +299,15 @@ async fn main() { SwaggerUi::new(concat!(api_base!(), "/swagger/{_:.*}")) .urls(vec![ ( - Url::new("v1", concat!(api_base_1!(), "/openapi.json")), + Url::new("v1", concat!(api_base!(), "-docs/openapi1.json")), openapi_v1.clone(), ), ( - Url::new("v2-l", concat!(api_base_2!(), "/openapi.json")), + Url::new("v2-l", concat!(api_base!(), "-docs/openapi2l.json")), openapi_v2_l.clone(), ), ( - Url::new("v3-l", concat!(api_base_3!(), "/openapi.json")), + Url::new("v3-l", concat!(api_base!(), "-docs/openapi3l.json")), openapi_v3_l.clone(), ), ]) From 717e3fda4915bc3bfdb825338109d297801bbd5d Mon Sep 17 00:00:00 2001 From: Neshura Date: Wed, 13 Dec 2023 19:07:00 +0100 Subject: [PATCH 09/13] Cargo.toml version bump --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 53947cb..ca617a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,7 +397,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chellaris-rust-api" -version = "1.0.3" +version = "1.2.4" dependencies = [ "actix-web", "chrono", diff --git a/Cargo.toml b/Cargo.toml index 7a9019a..f901372 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "chellaris-rust-api" -version = "1.0.3" +version = "1.2.4" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 48143979e5057720c0a0e9bd983b8cd5ad53d4b8 Mon Sep 17 00:00:00 2001 From: Neshura Date: Wed, 13 Dec 2023 19:08:05 +0100 Subject: [PATCH 10/13] Fix actions version check directory --- .forgejo/workflows/build+release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml index ccbb560..d7f3bc7 100644 --- a/.forgejo/workflows/build+release.yml +++ b/.forgejo/workflows/build+release.yml @@ -19,7 +19,7 @@ jobs: - name: Check if Version in Cargo.toml matches Tag run: | - VERSION=$(cat src-tauri/Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ") + VERSION=$(cat src/Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ") if test $VERSION != "${{ github.ref_name }}"; then echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'"; exit 1 From cd79f47caa00bae9df832cb7757c36f4af53017b Mon Sep 17 00:00:00 2001 From: Neshura Date: Mon, 18 Dec 2023 07:50:58 +0000 Subject: [PATCH 11/13] Fix Version Check in Actions --- .forgejo/workflows/build+release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml index d7f3bc7..96e61f8 100644 --- a/.forgejo/workflows/build+release.yml +++ b/.forgejo/workflows/build+release.yml @@ -19,7 +19,7 @@ jobs: - name: Check if Version in Cargo.toml matches Tag run: | - VERSION=$(cat src/Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ") + VERSION=$(cat Cargo.toml | grep -E "(^|\|)version =" | cut -f2- -d= | tr -d \" | tr -d " ") if test $VERSION != "${{ github.ref_name }}"; then echo "Expected Version is: '${{ github.ref_name }}' actual Version is: '$VERSION'"; exit 1 From 36709b6b800de1242f69f7f7f0eacc4fea8c2860 Mon Sep 17 00:00:00 2001 From: Neshura Date: Mon, 18 Dec 2023 08:06:12 +0000 Subject: [PATCH 12/13] Update .forgejo/workflows/build+release.yml --- .forgejo/workflows/build+release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml index 96e61f8..625e5e8 100644 --- a/.forgejo/workflows/build+release.yml +++ b/.forgejo/workflows/build+release.yml @@ -7,7 +7,7 @@ on: - '[0-9]+.[0-9]+.[0-9]+' - '[0-9]+.[0-9]+.[0-9]+rc[0-9]+' jobs: - run-tests: + tests: runs-on: docker steps: - @@ -28,7 +28,7 @@ jobs: fi build: - needs: test + needs: tests if: success() runs-on: docker container: rust:latest From e8f931392ef4e891b1038e1e509aaa9daef3349e Mon Sep 17 00:00:00 2001 From: Neshura Date: Mon, 18 Dec 2023 08:07:23 +0000 Subject: [PATCH 13/13] Update .forgejo/workflows/build+release.yml --- .forgejo/workflows/build+release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/build+release.yml b/.forgejo/workflows/build+release.yml index 625e5e8..c473e32 100644 --- a/.forgejo/workflows/build+release.yml +++ b/.forgejo/workflows/build+release.yml @@ -7,7 +7,7 @@ on: - '[0-9]+.[0-9]+.[0-9]+' - '[0-9]+.[0-9]+.[0-9]+rc[0-9]+' jobs: - tests: + test: runs-on: docker steps: - @@ -28,7 +28,7 @@ jobs: fi build: - needs: tests + needs: test if: success() runs-on: docker container: rust:latest