From 9af3aaec69b71272f1287f99973d3dc277987c8d Mon Sep 17 00:00:00 2001 From: tdgao Date: Wed, 16 Sep 2026 11:51:00 -0600 Subject: [PATCH 1/5] feat: add more versions loader validation on version creation --- .../src/routes/v3/version_creation.rs | 1 + apps/labrinth/src/validate/fabric.rs | 80 +++++++++++++++++++ apps/labrinth/src/validate/mod.rs | 49 +++++++++++- apps/labrinth/src/validate/plugin.rs | 34 ++++++++ 4 files changed, 163 insertions(+), 1 deletion(-) diff --git a/apps/labrinth/src/routes/v3/version_creation.rs b/apps/labrinth/src/routes/v3/version_creation.rs index 08097b4d675..65953332e84 100644 --- a/apps/labrinth/src/routes/v3/version_creation.rs +++ b/apps/labrinth/src/routes/v3/version_creation.rs @@ -1003,6 +1003,7 @@ pub async fn upload_file( loaders.clone(), file_type, version_fields.to_vec(), + dependencies, &mut *transaction, redis, ) diff --git a/apps/labrinth/src/validate/fabric.rs b/apps/labrinth/src/validate/fabric.rs index 3d634e8f1b4..1ce4f95c751 100644 --- a/apps/labrinth/src/validate/fabric.rs +++ b/apps/labrinth/src/validate/fabric.rs @@ -1,3 +1,5 @@ +use crate::database::models::legacy_loader_fields::MinecraftGameVersion; +use crate::models::projects::Loader; use crate::validate::{ SupportedGameVersions, ValidationError, ValidationResult, validate_pack_formats, @@ -7,6 +9,10 @@ use zip::ZipArchive; pub struct FabricValidator; +const FABRIC_18W43B_TIMESTAMP: i64 = 1_540_393_350; +const LEGACY_FABRIC_1_3_TIMESTAMP: i64 = 1_343_253_600; +const LEGACY_FABRIC_1_13_2_TIMESTAMP: i64 = 1_540_208_467; + impl super::Validator for FabricValidator { fn get_file_extensions(&self) -> &[&str] { &["jar"] @@ -20,6 +26,35 @@ impl super::Validator for FabricValidator { SupportedGameVersions::All } + fn ensure_required_loaders( + &self, + archive: &mut ZipArchive>, + loaders: &[Loader], + ) -> Result<(), ValidationError> { + if loaders.iter().any(|loader| loader.0 == "bta-babric") { + return Ok(()); + } + + let manifest = match archive.by_name("fabric.mod.json") { + Ok(manifest) => manifest, + Err(zip::result::ZipError::FileNotFound) => return Ok(()), + Err(error) => return Err(error.into()), + }; + + let Ok(metadata) = + serde_json::from_reader::<_, serde_json::Value>(manifest) + else { + return Ok(()); + }; + + if has_bta_loader_dependency(&metadata["depends"]["fabricloader"]) { + return Err(ValidationError::InvalidInput( + "files whose `fabric.mod.json` requires a `fabricloader` version containing `-bta.` must include the `bta-babric` loader".into(), + )); + } + Ok(()) + } + fn validate( &self, archive: &mut ZipArchive>, @@ -33,3 +68,48 @@ impl super::Validator for FabricValidator { Ok(validate_pack_formats(archive)) } } + +fn has_bta_loader_dependency(requirement: &serde_json::Value) -> bool { + match requirement { + serde_json::Value::String(range) => range.contains("-bta."), + serde_json::Value::Array(ranges) => { + ranges.iter().any(has_bta_loader_dependency) + } + _ => false, + } +} + +pub(super) fn validate_game_versions( + loaders: &[Loader], + game_versions: &[MinecraftGameVersion], +) -> Result<(), ValidationError> { + for loader in loaders { + let valid = !game_versions.is_empty() + && game_versions.iter().all(|version| match loader.0.as_str() { + "fabric" => { + version.created.timestamp() >= FABRIC_18W43B_TIMESTAMP + } + "legacy-fabric" => (LEGACY_FABRIC_1_3_TIMESTAMP + ..=LEGACY_FABRIC_1_13_2_TIMESTAMP) + .contains(&version.created.timestamp()), + "babric" | "bta-babric" => version.version == "b1.7.3", + _ => true, + }); + let requirement = match loader.0.as_str() { + "fabric" => "`18w43b` or later", + "legacy-fabric" => "between `1.3` and `1.13.2`, inclusive", + "babric" | "bta-babric" => "`b1.7.3` only", + _ => continue, + }; + if !valid { + return Err(ValidationError::InvalidInput( + format!( + "the `{}` loader requires minecraft versions {requirement}", + loader.0, + ) + .into(), + )); + } + } + Ok(()) +} diff --git a/apps/labrinth/src/validate/mod.rs b/apps/labrinth/src/validate/mod.rs index 1bb9815e029..ea3a3c9e6fb 100644 --- a/apps/labrinth/src/validate/mod.rs +++ b/apps/labrinth/src/validate/mod.rs @@ -1,8 +1,10 @@ use crate::database::PgTransaction; use crate::database::models::legacy_loader_fields::MinecraftGameVersion; use crate::database::models::loader_fields::VersionField; +use crate::database::models::version_item::DependencyBuilder; +use crate::models::ids::ProjectId; use crate::models::pack::PackFormat; -use crate::models::projects::{FileType, Loader}; +use crate::models::projects::{DependencyType, FileType, Loader}; use crate::validate::datapack::DataPackValidator; use crate::validate::fabric::FabricValidator; use crate::validate::forge::{ForgeValidator, LegacyForgeValidator}; @@ -39,6 +41,8 @@ mod resourcepack; mod rift; mod shader; +const HALPLIBE_PROJECT_ID: &str = "IIu8YulV"; + #[derive(Error, Debug)] pub enum ValidationError { #[error("Unable to read Zip Archive: {0}")] @@ -95,6 +99,14 @@ pub trait Validator: Sync { fn get_supported_loaders(&self) -> &[&str]; fn get_supported_game_versions(&self) -> SupportedGameVersions; + fn ensure_required_loaders( + &self, + _archive: &mut ZipArchive>, + _loaders: &[Loader], + ) -> Result<(), ValidationError> { + Ok(()) + } + fn validate( &self, archive: &mut ZipArchive>, @@ -139,6 +151,7 @@ static VALIDATORS: &[&dyn Validator] = &[ &BungeeCordValidator, &VelocityValidator, &SpongeValidator, + &GeyserValidator, &CanvasShaderValidator, &ShaderValidator, &CoreShaderValidator, @@ -178,6 +191,7 @@ pub async fn validate_file( loaders: Vec, file_type: Option, version_fields: Vec, + dependencies: &[DependencyBuilder], transaction: &mut PgTransaction<'_>, redis: &RedisPool, ) -> Result { @@ -189,6 +203,10 @@ pub async fn validate_file( MinecraftGameVersion::list(None, None, &mut *transaction, redis) .await?; + validate_dependencies(&loaders, dependencies)?; + + fabric::validate_game_versions(&loaders, &game_versions)?; + validate_minecraft_file( data, file_extension, @@ -200,6 +218,29 @@ pub async fn validate_file( .await } +fn validate_dependencies( + loaders: &[Loader], + dependencies: &[DependencyBuilder], +) -> Result<(), ValidationError> { + if loaders + .iter() + .any(|loader| matches!(loader.0.as_str(), "bta-babric" | "mrpack")) + { + return Ok(()); + } + if dependencies.iter().any(|dependency| { + dependency.dependency_type != DependencyType::Incompatible.as_str() + && dependency.project_id.is_some_and(|id| { + ProjectId::from(id).to_string() == HALPLIBE_PROJECT_ID + }) + }) { + return Err(ValidationError::InvalidInput( + "versions that depend on `halplibe` must include the `bta-babric` loader".into(), + )); + } + Ok(()) +} + async fn validate_minecraft_file( data: Bytes, file_extension: String, @@ -217,6 +258,12 @@ async fn validate_minecraft_file( }, }; + if let MaybeProtectedZipFile::Unprotected(archive) = &mut zip { + for validator in VALIDATORS { + validator.ensure_required_loaders(archive, &loaders)?; + } + } + if let Some(file_type) = file_type { match file_type { FileType::RequiredResourcePack | FileType::OptionalResourcePack => { diff --git a/apps/labrinth/src/validate/plugin.rs b/apps/labrinth/src/validate/plugin.rs index 4f637c66f20..51391cc0a8d 100644 --- a/apps/labrinth/src/validate/plugin.rs +++ b/apps/labrinth/src/validate/plugin.rs @@ -1,9 +1,43 @@ +use crate::models::projects::Loader; use crate::validate::{ SupportedGameVersions, ValidationError, ValidationResult, }; use std::io::Cursor; use zip::ZipArchive; +/// Checks loader metadata without imposing file-format requirements on Geyser uploads. +pub struct GeyserValidator; + +impl super::Validator for GeyserValidator { + fn get_file_extensions(&self) -> &[&str] { + &[] + } + + fn get_supported_loaders(&self) -> &[&str] { + &[] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn ensure_required_loaders( + &self, + archive: &mut ZipArchive>, + loaders: &[Loader], + ) -> Result<(), ValidationError> { + if archive.file_names().any(|name| name == "extension.yml") + && !loaders.iter().any(|loader| loader.0 == "geyser") + { + return Err(ValidationError::InvalidInput( + "files containing `extension.yml` in the root directory must use the Geyser Extension loader".into(), + )); + } + + Ok(()) + } +} + pub struct PluginYmlValidator; impl super::Validator for PluginYmlValidator { From f02017edba9f1ec6322eb78edec5a46898959553 Mon Sep 17 00:00:00 2001 From: tdgao Date: Wed, 16 Sep 2026 11:59:39 -0600 Subject: [PATCH 2/5] feat: add risugami loader validator --- apps/labrinth/src/validate/mod.rs | 3 ++ apps/labrinth/src/validate/risugami.rs | 61 ++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 apps/labrinth/src/validate/risugami.rs diff --git a/apps/labrinth/src/validate/mod.rs b/apps/labrinth/src/validate/mod.rs index ea3a3c9e6fb..d428b7a41fe 100644 --- a/apps/labrinth/src/validate/mod.rs +++ b/apps/labrinth/src/validate/mod.rs @@ -15,6 +15,7 @@ use crate::validate::plugin::*; use crate::validate::quilt::QuiltValidator; use crate::validate::resourcepack::{PackValidator, TexturePackValidator}; use crate::validate::rift::RiftValidator; +use crate::validate::risugami::RisugamiValidator; use crate::validate::shader::{ CanvasShaderValidator, CoreShaderValidator, ShaderValidator, }; @@ -39,6 +40,7 @@ pub mod project; mod quilt; mod resourcepack; mod rift; +mod risugami; mod shader; const HALPLIBE_PROJECT_ID: &str = "IIu8YulV"; @@ -157,6 +159,7 @@ static VALIDATORS: &[&dyn Validator] = &[ &CoreShaderValidator, &DataPackValidator, &RiftValidator, + &RisugamiValidator, &NeoForgeValidator, ]; diff --git a/apps/labrinth/src/validate/risugami.rs b/apps/labrinth/src/validate/risugami.rs new file mode 100644 index 00000000000..b83afa03f68 --- /dev/null +++ b/apps/labrinth/src/validate/risugami.rs @@ -0,0 +1,61 @@ +use crate::validate::{ + SupportedGameVersions, ValidationError, ValidationResult, +}; +use std::io::Cursor; +use zip::ZipArchive; + +pub struct RisugamiValidator; + +impl super::Validator for RisugamiValidator { + fn get_file_extensions(&self) -> &[&str] { + &["zip", "jar"] + } + + fn get_supported_loaders(&self) -> &[&str] { + &["modloader"] + } + + fn get_supported_game_versions(&self) -> SupportedGameVersions { + SupportedGameVersions::All + } + + fn validate( + &self, + archive: &mut ZipArchive>, + ) -> Result { + if archive.file_names().any(|name| name == "instance.cfg") + && archive.file_names().any(|name| name == "mmc-pack.json") + { + return Err(ValidationError::InvalidInput( + "multimc and prism modpacks cannot be uploaded as risugami's modloader mods".into(), + )); + } + + if archive.file_names().any(|name| name == "level.dat") { + return Err(ValidationError::InvalidInput( + "minecraft worlds cannot be uploaded as risugami's modloader mods".into(), + )); + } + + for name in archive.file_names() { + let Some((_, extension)) = name.rsplit_once('.') else { + continue; + }; + if ["mcpack", "mcworld", "mctemplate"] + .iter() + .any(|blocked| extension.eq_ignore_ascii_case(blocked)) + { + return Err(ValidationError::InvalidInput( + "bedrock packs cannot be uploaded as risugami's modloader mods".into(), + )); + } + if extension.eq_ignore_ascii_case("sk") { + return Err(ValidationError::InvalidInput( + "skript packs cannot be uploaded as risugami's modloader mods".into(), + )); + } + } + + Ok(ValidationResult::Pass) + } +} From 3da4c27a2ee7d2fb68955b2e6040910d6d3c5a25 Mon Sep 17 00:00:00 2001 From: tdgao Date: Wed, 16 Sep 2026 12:17:45 -0600 Subject: [PATCH 3/5] feat: add additional files validation --- .../components/VersionFileRow.vue | 1 - apps/labrinth/src/validate/mod.rs | 67 ++++++++++++++++++- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/components/ui/create-project-version/components/VersionFileRow.vue b/apps/frontend/src/components/ui/create-project-version/components/VersionFileRow.vue index 486561dcb7f..4c869b137cc 100644 --- a/apps/frontend/src/components/ui/create-project-version/components/VersionFileRow.vue +++ b/apps/frontend/src/components/ui/create-project-version/components/VersionFileRow.vue @@ -98,7 +98,6 @@ const versionTypes = computed( () => [ !editingVersion && { class: 'text-sm', value: 'primary', label: fileTypeLabels.primary }, - { class: 'text-sm', value: 'unknown', label: fileTypeLabels.unknown }, isDatapackProject.value && { class: 'text-sm', value: 'required-resource-pack', diff --git a/apps/labrinth/src/validate/mod.rs b/apps/labrinth/src/validate/mod.rs index d428b7a41fe..23658321fc5 100644 --- a/apps/labrinth/src/validate/mod.rs +++ b/apps/labrinth/src/validate/mod.rs @@ -1,6 +1,8 @@ use crate::database::PgTransaction; use crate::database::models::legacy_loader_fields::MinecraftGameVersion; -use crate::database::models::loader_fields::VersionField; +use crate::database::models::loader_fields::{ + Loader as DBLoader, VersionField, +}; use crate::database::models::version_item::DependencyBuilder; use crate::models::ids::ProjectId; use crate::models::pack::PackFormat; @@ -206,6 +208,10 @@ pub async fn validate_file( MinecraftGameVersion::list(None, None, &mut *transaction, redis) .await?; + let available_loaders = DBLoader::list(&mut *transaction, redis).await?; + + validate_file_type_for_loaders(file_type, &loaders, &available_loaders)?; + validate_dependencies(&loaders, dependencies)?; fabric::validate_game_versions(&loaders, &game_versions)?; @@ -221,6 +227,33 @@ pub async fn validate_file( .await } +fn validate_file_type_for_loaders( + file_type: Option, + loaders: &[Loader], + available_loaders: &[DBLoader], +) -> Result<(), ValidationError> { + if matches!( + file_type, + Some(FileType::SourcesJar | FileType::DevJar | FileType::JavadocJar) + ) { + let supports_jar_files = available_loaders + .iter() + .filter(|loader| { + loaders.iter().any(|selected| selected.0 == loader.loader) + }) + .flat_map(|loader| &loader.supported_project_types) + .any(|project_type| { + matches!(project_type.as_str(), "mod" | "plugin") + }); + if !supports_jar_files { + return Err(ValidationError::InvalidInput( + "sources, dev, and javadoc jars are only supported for mods and plugins".into(), + )); + } + } + Ok(()) +} + fn validate_dependencies( loaders: &[Loader], dependencies: &[DependencyBuilder], @@ -244,6 +277,34 @@ fn validate_dependencies( Ok(()) } +fn validate_additional_jar( + file: &MaybeProtectedZipFile, + file_extension: &str, + file_type: FileType, +) -> Result { + if file_extension != "jar" { + return Err(ValidationError::InvalidInput( + "sources, dev, and javadoc jars must use the `.jar` extension" + .into(), + )); + } + + let MaybeProtectedZipFile::Unprotected(archive) = file else { + return Err(ValidationError::InvalidInput( + "additional jars must be readable jar archives".into(), + )); + }; + + if file_type == FileType::SourcesJar + && !archive.file_names().any(|name| name.ends_with(".java")) + { + return Err(ValidationError::InvalidInput( + "sources jars must contain at least one `.java` file".into(), + )); + } + Ok(ValidationResult::Pass) +} + async fn validate_minecraft_file( data: Bytes, file_extension: String, @@ -283,7 +344,9 @@ async fn validate_minecraft_file( )) }; } - FileType::DevJar | FileType::SourcesJar | FileType::JavadocJar => {}, + FileType::DevJar | FileType::SourcesJar | FileType::JavadocJar => { + return validate_additional_jar(&zip, &file_extension, file_type); + }, FileType::Unknown => {} } } From 8eb19bb0f5a832893b30822509244d7f60dd2174 Mon Sep 17 00:00:00 2001 From: tdgao Date: Tue, 22 Sep 2026 11:31:05 -0600 Subject: [PATCH 4/5] refactor: remove timestamps and lookup game version instead --- apps/labrinth/fixtures/dummy_data.sql | 12 ++++-- apps/labrinth/src/test/dummy_data.rs | 2 +- apps/labrinth/src/validate/fabric.rs | 60 ++++++++++++++++++--------- apps/labrinth/src/validate/mod.rs | 7 +++- apps/labrinth/tests/loader_fields.rs | 5 ++- apps/labrinth/tests/v2/tags.rs | 5 ++- 6 files changed, 64 insertions(+), 27 deletions(-) diff --git a/apps/labrinth/fixtures/dummy_data.sql b/apps/labrinth/fixtures/dummy_data.sql index 90d580ea3f5..17b27a8abf1 100644 --- a/apps/labrinth/fixtures/dummy_data.sql +++ b/apps/labrinth/fixtures/dummy_data.sql @@ -32,15 +32,16 @@ INSERT INTO loaders (id, loader) VALUES (9, 'datapack'); INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id) SELECT l.id, pt.id -FROM loaders l -CROSS JOIN project_types pt +FROM + loaders AS l + CROSS JOIN project_types AS pt WHERE (l.loader IN ('bukkit', 'waterfall') AND pt.name = 'plugin') OR (l.loader = 'datapack' AND pt.name = 'datapack'); INSERT INTO loaders_project_types_games (loader_id, project_type_id, game_id) SELECT lpt.joining_loader_id, lpt.joining_project_type_id, 1 -FROM loaders_project_types lpt +FROM loaders_project_types AS lpt WHERE lpt.joining_loader_id IN (7, 8, 9); -- Adds dummies to mrpack_loaders @@ -74,6 +75,11 @@ ON CONFLICT DO NOTHING; -- Sample game versions, loaders, categories -- Game versions is '2' INSERT INTO loader_field_enum_values (enum_id, value, metadata, created) +VALUES + (2, '1.3', '{"type":"snapshot","major":false}', '2012-07-25 22:00:00+00'), + (2, '1.13.2', '{"type":"release","major":false}', '2018-10-22 11:41:07+00'), + (2, '18w43b', '{"type":"snapshot","major":false}', '2018-10-24 15:02:30+00'); +INSERT INTO loader_field_enum_values (enum_id, value, metadata, created) VALUES (2, '1.20.1', '{"type":"release","major":false}', '2021-08-18 15:48:58.435729+00'); INSERT INTO loader_field_enum_values (enum_id, value, metadata, created) VALUES (2, '1.20.2', '{"type":"release","major":false}', '2021-08-18 15:48:59.435729+00'); diff --git a/apps/labrinth/src/test/dummy_data.rs b/apps/labrinth/src/test/dummy_data.rs index 4b8038be1a7..880dfbe1fcb 100644 --- a/apps/labrinth/src/test/dummy_data.rs +++ b/apps/labrinth/src/test/dummy_data.rs @@ -21,7 +21,7 @@ use super::{ use super::{database::USER_USER_ID, get_json_val_str}; -pub const DUMMY_DATA_UPDATE: i64 = 9; +pub const DUMMY_DATA_UPDATE: i64 = 10; pub const DUMMY_CATEGORIES: &[&str] = &[ "combat", diff --git a/apps/labrinth/src/validate/fabric.rs b/apps/labrinth/src/validate/fabric.rs index 1ce4f95c751..46bc0df5b47 100644 --- a/apps/labrinth/src/validate/fabric.rs +++ b/apps/labrinth/src/validate/fabric.rs @@ -1,3 +1,4 @@ +use crate::database::models::DatabaseError; use crate::database::models::legacy_loader_fields::MinecraftGameVersion; use crate::models::projects::Loader; use crate::validate::{ @@ -9,10 +10,6 @@ use zip::ZipArchive; pub struct FabricValidator; -const FABRIC_18W43B_TIMESTAMP: i64 = 1_540_393_350; -const LEGACY_FABRIC_1_3_TIMESTAMP: i64 = 1_343_253_600; -const LEGACY_FABRIC_1_13_2_TIMESTAMP: i64 = 1_540_208_467; - impl super::Validator for FabricValidator { fn get_file_extensions(&self) -> &[&str] { &["jar"] @@ -82,26 +79,49 @@ fn has_bta_loader_dependency(requirement: &serde_json::Value) -> bool { pub(super) fn validate_game_versions( loaders: &[Loader], game_versions: &[MinecraftGameVersion], + all_game_versions: &[MinecraftGameVersion], ) -> Result<(), ValidationError> { + let release_date = |name: &str| { + all_game_versions + .iter() + .find(|version| version.version == name) + .map(|version| version.created) + .ok_or_else(|| { + DatabaseError::SchemaError(format!( + "missing minecraft game version `{name}` required for loader validation" + )) + }) + }; + for loader in loaders { - let valid = !game_versions.is_empty() - && game_versions.iter().all(|version| match loader.0.as_str() { - "fabric" => { - version.created.timestamp() >= FABRIC_18W43B_TIMESTAMP - } - "legacy-fabric" => (LEGACY_FABRIC_1_3_TIMESTAMP - ..=LEGACY_FABRIC_1_13_2_TIMESTAMP) - .contains(&version.created.timestamp()), - "babric" | "bta-babric" => version.version == "b1.7.3", - _ => true, - }); - let requirement = match loader.0.as_str() { - "fabric" => "`18w43b` or later", - "legacy-fabric" => "between `1.3` and `1.13.2`, inclusive", - "babric" | "bta-babric" => "`b1.7.3` only", + let (valid, requirement) = match loader.0.as_str() { + "fabric" => { + let minimum = release_date("18w43b")?; + ( + game_versions + .iter() + .all(|version| version.created >= minimum), + "`18w43b` or later", + ) + } + "legacy-fabric" => { + let supported = release_date("1.3")?..=release_date("1.13.2")?; + ( + game_versions + .iter() + .all(|version| supported.contains(&version.created)), + "between `1.3` and `1.13.2`, inclusive", + ) + } + "babric" | "bta-babric" => ( + game_versions + .iter() + .all(|version| version.version == "b1.7.3"), + "`b1.7.3` only", + ), _ => continue, }; - if !valid { + if game_versions.is_empty() || !valid { return Err(ValidationError::InvalidInput( format!( "the `{}` loader requires minecraft versions {requirement}", diff --git a/apps/labrinth/src/validate/mod.rs b/apps/labrinth/src/validate/mod.rs index 23658321fc5..a899048600d 100644 --- a/apps/labrinth/src/validate/mod.rs +++ b/apps/labrinth/src/validate/mod.rs @@ -45,6 +45,7 @@ mod rift; mod risugami; mod shader; +// BTA loader must exist if HalpLibe project is selected as a dependency const HALPLIBE_PROJECT_ID: &str = "IIu8YulV"; #[derive(Error, Debug)] @@ -214,7 +215,11 @@ pub async fn validate_file( validate_dependencies(&loaders, dependencies)?; - fabric::validate_game_versions(&loaders, &game_versions)?; + fabric::validate_game_versions( + &loaders, + &game_versions, + &all_game_versions, + )?; validate_minecraft_file( data, diff --git a/apps/labrinth/tests/loader_fields.rs b/apps/labrinth/tests/loader_fields.rs index 7d2eab670a4..4e5f30bb456 100644 --- a/apps/labrinth/tests/loader_fields.rs +++ b/apps/labrinth/tests/loader_fields.rs @@ -543,7 +543,10 @@ async fn get_loader_fields_variants() { "1.20.4", "1.20.3", "1.20.2", - "1.20.1" + "1.20.1", + "18w43b", + "1.13.2", + "1.3" ] ); }) diff --git a/apps/labrinth/tests/v2/tags.rs b/apps/labrinth/tests/v2/tags.rs index 8126d7a4eed..ee92894de4d 100644 --- a/apps/labrinth/tests/v2/tags.rs +++ b/apps/labrinth/tests/v2/tags.rs @@ -38,7 +38,10 @@ async fn get_tags() { "1.20.4", "1.20.3", "1.20.2", - "1.20.1" + "1.20.1", + "18w43b", + "1.13.2", + "1.3" ] .iter() .map(|s| s.to_string()) From 164bfbf72e8d267b48f2fdbda33d6f7f3d2d7428 Mon Sep 17 00:00:00 2001 From: tdgao Date: Tue, 22 Sep 2026 11:58:07 -0600 Subject: [PATCH 5/5] fix ci --- _typos.toml | 2 ++ apps/labrinth/src/validate/fabric.rs | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/_typos.toml b/_typos.toml index 33c5b1a27d0..e51adac4c6b 100644 --- a/_typos.toml +++ b/_typos.toml @@ -32,5 +32,7 @@ consts = "consts" Cpy = "Cpy" [default.extend-identifiers] +# BTA dependency project name +HalpLibe = "HalpLibe" # Constant from the `zip` crate ZIP64_BYTES_THR = "ZIP64_BYTES_THR" diff --git a/apps/labrinth/src/validate/fabric.rs b/apps/labrinth/src/validate/fabric.rs index 46bc0df5b47..4fe380915e4 100644 --- a/apps/labrinth/src/validate/fabric.rs +++ b/apps/labrinth/src/validate/fabric.rs @@ -1,10 +1,10 @@ -use crate::database::models::DatabaseError; use crate::database::models::legacy_loader_fields::MinecraftGameVersion; use crate::models::projects::Loader; use crate::validate::{ SupportedGameVersions, ValidationError, ValidationResult, validate_pack_formats, }; +use eyre::eyre; use std::io::Cursor; use zip::ZipArchive; @@ -87,9 +87,9 @@ pub(super) fn validate_game_versions( .find(|version| version.version == name) .map(|version| version.created) .ok_or_else(|| { - DatabaseError::SchemaError(format!( - "missing minecraft game version `{name}` required for loader validation" - )) + eyre!( + "missing minecraft game version `{name}` required for loader validation" + ) }) };