From 5a4cb5fb76656243f4ccc90174627bff80ec04ab Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Fri, 11 Oct 2024 18:21:58 +0300 Subject: [PATCH 01/12] Added multiple flags to moodle --- Cargo.toml | 1 + src/moodle.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e5245ff..08af1a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ serde = { version = "1.0", default-features = false, features = ["derive"] } toml = "0.8" # Cli +itertools = "0.13.0" clap = { version = "4.5", features = ["derive", "cargo"] } thiserror = "1.0.63" tracing = { version = "0.1.40" } diff --git a/src/moodle.rs b/src/moodle.rs index dc5ebf2..d6ae58e 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -6,6 +6,8 @@ use moodle_xml::{ quiz::Quiz, }; use std::io::{self, BufRead, BufReader}; +use itertools::Itertools; +use crate::flag_generator::Flag; /// Create an exam from a list of task build process outputs, which includes the question as well pub fn create_exam( @@ -50,7 +52,7 @@ pub fn create_exam( let mut question = ShortAnswerQuestion::new(task_config.name.clone(), instructions_string, None); let answers = if item.flags.len() == 1 { - vec![ + vec![ Answer::new( 100, item.flags[0].encase_flag(), @@ -61,9 +63,10 @@ pub fn create_exam( item.flags[0].flag_string(), "Correct!".to_string().into(), ), - ] + ] } else { - todo!("Multiple flags in subtasks not supported yet") + // Adds 1-inf flags as answer with chosen separator + process_multiple_flags(item.flags.clone(), ";") }; question .add_answers(answers) @@ -82,3 +85,71 @@ pub fn create_exam( .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Error: {:?}", e)))?; Ok(()) } + +// Function to encase each flag with a specified separator +fn encase_each_flag(flags: &[Flag], separator: &str) -> String { + flags.iter().map(|f| f.encase_flag()).join(separator) +} + +// Function to join flags without encasing them +fn join_flags(flags: &[Flag], separator: &str) -> String { + flags.iter().map(|f| f.flag_string()).join(separator) +} + +// Function to process multiple flags and create answers +fn process_multiple_flags(flags: Vec, separator: &str) -> Vec { + let total_flags = flags.len(); + let mut answers = Vec::new(); + + for r in 1..=total_flags { + for combination in flags.iter().combinations(r) { + for perm in combination.iter().permutations(r) { + let perm_flags: Vec = perm.iter().cloned().map(|&flag| flag.clone()).collect(); + let encased_combined_answer = encase_each_flag(&perm_flags, separator); // Pass as a slice + let combined_answer = join_flags(&perm_flags, separator); // Pass as a slice + + // Calculate points based on the number of flags + let points = ((r as f64 / total_flags as f64) * 100.0).round() as u8; + + answers.push(Answer::new(points, encased_combined_answer.clone(), "Correct!".to_string().into())); + answers.push(Answer::new(points, combined_answer.clone(), "Correct!".to_string().into())); + } + } + } + + answers +} + +#[cfg(test)] +mod tests { + use super::*; + use uuid::Uuid; + use crate::flag_generator::Algorithm; + + #[test] + fn test_multiple_flags() { + let mut flags = Vec::new(); + + let id = Uuid::now_v7(); + let secret = "Work".to_string(); + let secret2 = "dslpl".to_string(); + let secret3 = "dslpl".to_string(); + let taskid = "task1".to_string(); + let taskid2 = "Wording mording".to_string(); + let taskid3 = "kdosogkdo".to_string(); + let prefix = "task_prefix".to_string(); + + let flag1 = Flag::new_random_flag(taskid2,32); + let flag2 = Flag::new_user_flag(taskid, &Algorithm::HMAC_SHA3_256, &secret, &secret3, &id); + let flag3 = Flag::new_user_flag(prefix, &Algorithm::HMAC_SHA3_256, &secret2, &taskid3, &id); + + flags.push(flag1); + flags.push(flag2); + flags.push(flag3); + + let answers = process_multiple_flags(flags, ";"); + for answer in answers { + println!("{:?}", answer); + } + } +} \ No newline at end of file From a29ca7e603889ad2485791bc0359336b9b3c16ed Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Fri, 11 Oct 2024 18:43:06 +0300 Subject: [PATCH 02/12] clippy --- src/moodle.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index d6ae58e..c67cee3 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -52,18 +52,18 @@ pub fn create_exam( let mut question = ShortAnswerQuestion::new(task_config.name.clone(), instructions_string, None); let answers = if item.flags.len() == 1 { - vec![ - Answer::new( - 100, - item.flags[0].encase_flag(), - "Correct!".to_string().into(), - ), - Answer::new( - 100, - item.flags[0].flag_string(), - "Correct!".to_string().into(), - ), - ] + vec![ + Answer::new( + 100, + item.flags[0].encase_flag(), + "Correct!".to_string().into(), + ), + Answer::new( + 100, + item.flags[0].flag_string(), + "Correct!".to_string().into(), + ), + ] } else { // Adds 1-inf flags as answer with chosen separator process_multiple_flags(item.flags.clone(), ";") From ac6c0ee51eb0bab56dfe71131218c5c6a378e22c Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Fri, 11 Oct 2024 18:48:15 +0300 Subject: [PATCH 03/12] more clippy --- src/moodle.rs | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index c67cee3..d1f1c71 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -53,16 +53,16 @@ pub fn create_exam( ShortAnswerQuestion::new(task_config.name.clone(), instructions_string, None); let answers = if item.flags.len() == 1 { vec![ - Answer::new( - 100, - item.flags[0].encase_flag(), - "Correct!".to_string().into(), - ), - Answer::new( - 100, - item.flags[0].flag_string(), - "Correct!".to_string().into(), - ), + Answer::new( + 100, + item.flags[0].encase_flag(), + "Correct!".to_string().into(), + ), + Answer::new( + 100, + item.flags[0].flag_string(), + "Correct!".to_string().into(), + ), ] } else { // Adds 1-inf flags as answer with chosen separator @@ -104,15 +104,24 @@ fn process_multiple_flags(flags: Vec, separator: &str) -> Vec { for r in 1..=total_flags { for combination in flags.iter().combinations(r) { for perm in combination.iter().permutations(r) { - let perm_flags: Vec = perm.iter().cloned().map(|&flag| flag.clone()).collect(); + let perm_flags: Vec = + perm.iter().cloned().map(|&flag| flag.clone()).collect(); let encased_combined_answer = encase_each_flag(&perm_flags, separator); // Pass as a slice let combined_answer = join_flags(&perm_flags, separator); // Pass as a slice // Calculate points based on the number of flags let points = ((r as f64 / total_flags as f64) * 100.0).round() as u8; - answers.push(Answer::new(points, encased_combined_answer.clone(), "Correct!".to_string().into())); - answers.push(Answer::new(points, combined_answer.clone(), "Correct!".to_string().into())); + answers.push(Answer::new( + points, + encased_combined_answer.clone(), + "Correct!".to_string().into() + )); + answers.push(Answer::new( + points, + combined_answer.clone(), + "Correct!".to_string().into() + )); } } } @@ -123,9 +132,9 @@ fn process_multiple_flags(flags: Vec, separator: &str) -> Vec { #[cfg(test)] mod tests { use super::*; - use uuid::Uuid; use crate::flag_generator::Algorithm; - + use uuid::Uuid; + #[test] fn test_multiple_flags() { let mut flags = Vec::new(); @@ -139,7 +148,7 @@ mod tests { let taskid3 = "kdosogkdo".to_string(); let prefix = "task_prefix".to_string(); - let flag1 = Flag::new_random_flag(taskid2,32); + let flag1 = Flag::new_random_flag(taskid2, 32); let flag2 = Flag::new_user_flag(taskid, &Algorithm::HMAC_SHA3_256, &secret, &secret3, &id); let flag3 = Flag::new_user_flag(prefix, &Algorithm::HMAC_SHA3_256, &secret2, &taskid3, &id); From 38447fe0768bbf4d93a2777ea182b768092927ce Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Fri, 11 Oct 2024 18:52:49 +0300 Subject: [PATCH 04/12] lastclippy --- src/moodle.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index d1f1c71..4389034 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -1,13 +1,13 @@ use crate::build_process::TaskBuildProcessOutput; use crate::config::{OutputKind, Task}; +use crate::flag_generator::Flag; +use itertools::Itertools; use moodle_xml::{ answer::Answer, question::{Question, QuestionType, ShortAnswerQuestion}, quiz::Quiz, }; use std::io::{self, BufRead, BufReader}; -use itertools::Itertools; -use crate::flag_generator::Flag; /// Create an exam from a list of task build process outputs, which includes the question as well pub fn create_exam( @@ -115,17 +115,16 @@ fn process_multiple_flags(flags: Vec, separator: &str) -> Vec { answers.push(Answer::new( points, encased_combined_answer.clone(), - "Correct!".to_string().into() + "Correct!".to_string().into(), )); answers.push(Answer::new( points, combined_answer.clone(), - "Correct!".to_string().into() + "Correct!".to_string().into(), )); } } } - answers } From 9dc3d136b7334f37a70ec53316f4376972ca1b2d Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Sat, 12 Oct 2024 12:04:32 +0300 Subject: [PATCH 05/12] format --- src/moodle.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index 4389034..51d9f5f 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -63,7 +63,7 @@ pub fn create_exam( item.flags[0].flag_string(), "Correct!".to_string().into(), ), - ] + ] } else { // Adds 1-inf flags as answer with chosen separator process_multiple_flags(item.flags.clone(), ";") @@ -104,7 +104,7 @@ fn process_multiple_flags(flags: Vec, separator: &str) -> Vec { for r in 1..=total_flags { for combination in flags.iter().combinations(r) { for perm in combination.iter().permutations(r) { - let perm_flags: Vec = + let perm_flags: Vec = perm.iter().cloned().map(|&flag| flag.clone()).collect(); let encased_combined_answer = encase_each_flag(&perm_flags, separator); // Pass as a slice let combined_answer = join_flags(&perm_flags, separator); // Pass as a slice @@ -160,4 +160,4 @@ mod tests { println!("{:?}", answer); } } -} \ No newline at end of file +} From 8987a66f77e365430ab55a7ccae1a98fd5a90624 Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Wed, 23 Oct 2024 15:18:32 +0300 Subject: [PATCH 06/12] multiple flag review changes --- src/moodle.rs | 78 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index 51d9f5f..48341e5 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -66,7 +66,7 @@ pub fn create_exam( ] } else { // Adds 1-inf flags as answer with chosen separator - process_multiple_flags(item.flags.clone(), ";") + process_multiple_flags(item.flags.clone(), " ") }; question .add_answers(answers) @@ -137,27 +137,77 @@ mod tests { #[test] fn test_multiple_flags() { let mut flags = Vec::new(); + let mut flags2 = Vec::new(); + let mut flags3 = Vec::new(); let id = Uuid::now_v7(); let secret = "Work".to_string(); let secret2 = "dslpl".to_string(); let secret3 = "dslpl".to_string(); let taskid = "task1".to_string(); - let taskid2 = "Wording mording".to_string(); - let taskid3 = "kdosogkdo".to_string(); - let prefix = "task_prefix".to_string(); + let taskid2 = "task2".to_string(); + let taskid3 = "task3".to_string(); + let taskid4 = "task4".to_string(); + let taskid5 = "task5".to_string(); + let taskid6 = "task6".to_string(); + let prefix4 = "task4_prefix".to_string(); + let prefix5 = "task5_prefix".to_string(); + let prefix6 = "task6_prefix".to_string(); + + let flag1 = Flag::new_random_flag(taskid, 32); + let flag2 = Flag::new_random_flag(taskid2, 32); + let flag3 = Flag::new_random_flag(taskid3, 32); + let flag4 = Flag::new_user_flag(prefix4, &Algorithm::HMAC_SHA3_256, &secret, &taskid4, &id); + let flag5 = Flag::new_user_flag(prefix5, &Algorithm::HMAC_SHA3_256, &secret2, &taskid5, &id); + let flag6 = Flag::new_user_flag(prefix6, &Algorithm::HMAC_SHA3_256, &secret3, &taskid6, &id); + + flags2.push(flag1); + + flags3.push(flag2); + flags3.push(flag3); + + flags.push(flag4); + flags.push(flag5); + flags.push(flag6); + + let answers = process_multiple_flags(flags, " "); + let answers2 = process_multiple_flags(flags2, " "); + let answers3 = process_multiple_flags(flags3, " "); - let flag1 = Flag::new_random_flag(taskid2, 32); - let flag2 = Flag::new_user_flag(taskid, &Algorithm::HMAC_SHA3_256, &secret, &secret3, &id); - let flag3 = Flag::new_user_flag(prefix, &Algorithm::HMAC_SHA3_256, &secret2, &taskid3, &id); - - flags.push(flag1); - flags.push(flag2); - flags.push(flag3); - - let answers = process_multiple_flags(flags, ";"); for answer in answers { - println!("{:?}", answer); + match answer.fraction{ + 33 => { + assert!(answer.text.contains("task4_prefix:") || answer.text.contains("task5_prefix:") || answer.text.contains("task6_prefix:")); + } + 67 => { + assert!((answer.text.contains("task4_prefix:") && answer.text.contains("task5_prefix:")) + || (answer.text.contains("task6_prefix:") && answer.text.contains("task5_prefix:")) + || (answer.text.contains("task6_prefix:") && answer.text.contains("task4_prefix:"))); + } + 100 => { + assert!((answer.text.contains("task4_prefix:") && answer.text.contains("task5_prefix:") && answer.text.contains("task6_prefix:"))); + } + _ => { + unreachable!("Unexpected fraction value encountered in test") + } + } + } + for answer in answers2 { + assert!(answer.fraction == 100); + assert!(answer.text.contains("task1:")); + } + for answer in answers3 { + match answer.fraction{ + 50 => { + assert!(answer.text.contains("task2:") || answer.text.contains("task3:")); + } + 100 => { + assert!(answer.text.contains("task2:") && answer.text.contains("task3:")); + } + _ => { + unreachable!("Unexpected fraction value encountered in test") + } + } } } } From 4d4b8719794e6841935dad8463a9e57232970cff Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Wed, 23 Oct 2024 15:30:01 +0300 Subject: [PATCH 07/12] changes --- src/moodle.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index 48341e5..64b2378 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -175,17 +175,30 @@ mod tests { let answers3 = process_multiple_flags(flags3, " "); for answer in answers { - match answer.fraction{ + match answer.fraction { 33 => { - assert!(answer.text.contains("task4_prefix:") || answer.text.contains("task5_prefix:") || answer.text.contains("task6_prefix:")); + assert!( + answer.text.contains("task4_prefix:") + || answer.text.contains("task5_prefix:") + || answer.text.contains("task6_prefix:") + ); } 67 => { - assert!((answer.text.contains("task4_prefix:") && answer.text.contains("task5_prefix:")) - || (answer.text.contains("task6_prefix:") && answer.text.contains("task5_prefix:")) - || (answer.text.contains("task6_prefix:") && answer.text.contains("task4_prefix:"))); + assert!( + (answer.text.contains("task4_prefix:") + && answer.text.contains("task5_prefix:")) + || (answer.text.contains("task6_prefix:") + && answer.text.contains("task5_prefix:")) + || (answer.text.contains("task6_prefix:") + && answer.text.contains("task4_prefix:")) + ); } 100 => { - assert!((answer.text.contains("task4_prefix:") && answer.text.contains("task5_prefix:") && answer.text.contains("task6_prefix:"))); + assert!( + (answer.text.contains("task4_prefix:") + && answer.text.contains("task5_prefix:") + && answer.text.contains("task6_prefix:")) + ); } _ => { unreachable!("Unexpected fraction value encountered in test") @@ -197,7 +210,7 @@ mod tests { assert!(answer.text.contains("task1:")); } for answer in answers3 { - match answer.fraction{ + match answer.fraction { 50 => { assert!(answer.text.contains("task2:") || answer.text.contains("task3:")); } From c2589ab548fb582d4d5afa878e3b3a12d3631920 Mon Sep 17 00:00:00 2001 From: Eetu Lassi Date: Wed, 23 Oct 2024 15:31:55 +0300 Subject: [PATCH 08/12] more changes --- src/moodle.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/moodle.rs b/src/moodle.rs index 64b2378..b31405a 100644 --- a/src/moodle.rs +++ b/src/moodle.rs @@ -158,8 +158,10 @@ mod tests { let flag2 = Flag::new_random_flag(taskid2, 32); let flag3 = Flag::new_random_flag(taskid3, 32); let flag4 = Flag::new_user_flag(prefix4, &Algorithm::HMAC_SHA3_256, &secret, &taskid4, &id); - let flag5 = Flag::new_user_flag(prefix5, &Algorithm::HMAC_SHA3_256, &secret2, &taskid5, &id); - let flag6 = Flag::new_user_flag(prefix6, &Algorithm::HMAC_SHA3_256, &secret3, &taskid6, &id); + let flag5 = + Flag::new_user_flag(prefix5, &Algorithm::HMAC_SHA3_256, &secret2, &taskid5, &id); + let flag6 = + Flag::new_user_flag(prefix6, &Algorithm::HMAC_SHA3_256, &secret3, &taskid6, &id); flags2.push(flag1); From 372df1f94e2b576d283053680a177f7f057ec2e0 Mon Sep 17 00:00:00 2001 From: PootisHunter Date: Thu, 5 Jun 2025 11:11:48 +0300 Subject: [PATCH 09/12] added README --- README.md | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/README.md b/README.md index 2b90f45..b7f543f 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,94 @@ Think of it as a dynamic CTF challenge generator, but with a twist: every partic It may or may not be completed. Heavily work-in-progress. +## Minimum Requirements + +1. **Configuration File**: A `.toml` file defining the module, tasks, stages, build logic, and deployment rules. +2. **Task Build**: a shell-based or other type build system for generating task based on flag. +3. **Execution (CLI)**: CLI or other type system to specify tasks to be build with given options + +## Configuration File Structure Overview + +- `Module`: Structure for the module/course containing Uuid and name +- `Categories`: Logical sections of the course (e.g. “Week 1” or “Basics”) +- `Tasks`: Each Task belongs to a category and consists of: + - `id`, `name`, `description`, `points` — basic task metadata. + - `Stages`: Subtasks within a task containing: + - `id`, `name`, `description`, `weight` + - `flag` — method for generating user-specific or random flags. + - `Build`: Build Instructions for task + - `directory` — relative path to the task code. + - `builder` — either `shell` or other type build specifing the entrypoint file. + - `Build Output`: Specifies the files or resources produced by the build. + - `resource` — downloadable binary or file. + - `internal` — used internally (e.g., server script). + - `readme` — instructions shown to users. + - `meta` — JSON metadata (key-value config for dynamic tasks). +- `Flag Types`: Defines configurations for flag generation methods + - `pure_random`: random string with given length. + - `user_derived`: userid and algorithm based deterministic flags that requires the algorithm and the secret. + - `rng_seed`: Generates consistent seed from user identity. +- `Deployment`: Configuration for deployment parameters + - `build_timeout`: Max build time (in seconds). + - `upload`: AWS S3 options for distributing artifacts: + - `BUCKET_NAME`, `USE_PRE_SIGNED`, expiration policies, etc. + + +example configuration file is `course.toml` + +### Supported Flag Types: +- user_derived algorithms: `HMAC_SHA3_256` + +## Builder + +Each task uses a **builder** that defines how the task is build. Different flags should produce different task instructions and answers. Meanwhile same flags should produce same instructions and answers deterministically +One way to achieve this is to utilize flag hash when generating different options for tasks. + +### Supported builders +- `shell`: Runs a shell entrypoint (default: `entrypoint.sh`) + +### Flags + +- `pure_random` is passed as enviroment variable with name `FLAG_PURE_RANDOM_{task_id}` +- `user_derived` is passed as enviroment variable with name `FLAG_USER_DERIVED_{task_id}` +- `rng_seed`: Generates consistent seed from user identity. `FLAG_USER_SEED_{task_id}` + +currently `user_derived` and `rng_seed` are functionally identical + +## CLI + +command line can be accessed by running command `aínigma` and the integrity of configuration file can be tested simply by + +```bash aínigma --config .toml generate --dry-run``` + +`generate` supports the following commands: + +- `--output-dir ` Optional. Directory to write build files to. If omitted, uses a temp dir. +- `--task ` Build a specific task by its unique ID. +- `--category ` (Not yet implemented.) Build an entire category based on number. +- `--dry-run` Performs a syntax check on the configuration and pretty prints it. +- `--number ` Specifies the number of variants to build + +command line also supports task generation to moodle xml file with `moodle` and following command: + +- `--category ` Moodle category name for grouping questions together. +- `--output ` Name of output XML file (default: quiz.xml). + +command line support `upload` to check bucket availability with command: + +- `--check-bucket` Ensures the target bucket exists and is accessible. + +All of these commands can also be seen with --help command. + +## Example of Moodle workflow +```mermaid +flowchart TD + A[Read TOML configuration] --> B[Generate flag] + B --> C[Assign flag to each task build] + C --> D[Run code with flag as environment variable] + D --> E[Generate Moodle XML file] + +``` #### License From 8b1819ae9e7dc961ea14460bd32f5be3dc48b563 Mon Sep 17 00:00:00 2001 From: PootisHunter Date: Thu, 5 Jun 2025 11:31:36 +0300 Subject: [PATCH 10/12] resolved deprecated version --- src/bin/cli.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bin/cli.rs b/src/bin/cli.rs index e9838c8..8bb4d4d 100644 --- a/src/bin/cli.rs +++ b/src/bin/cli.rs @@ -1,18 +1,18 @@ use ainigma::{ - build_process::{TaskBuildContainer, build_batch, build_sequential}, - config::{DEFAULT_BUILD_MANIFEST, ModuleConfiguration, Task, read_check_toml}, + build_process::{build_batch, build_sequential, TaskBuildContainer}, + config::{read_check_toml, ModuleConfiguration, Task, DEFAULT_BUILD_MANIFEST}, errors::BuildError, moodle::create_exam, storages::s3_upload, }; -use clap::{Args, Parser, Subcommand, crate_description}; +use clap::{crate_description, Args, Parser, Subcommand}; use once_cell::sync::Lazy; use std::{ path::{Path, PathBuf}, process::ExitCode, sync::{ - Arc, Mutex, atomic::{AtomicBool, Ordering}, + Arc, Mutex, }, thread, }; @@ -292,7 +292,9 @@ fn main() -> std::process::ExitCode { None => { match output_dir { OutputDirectory::Temprarory(output_dir) => { - let path = output_dir.into_path(); + let path = output_dir + .keep() + .expect("Failed to keep the temporal directory"); tracing::info!( "The build has been finished and the files are located in the temporal output directory: '{}'", path.display() From 1eb1b7d657fae067c10e7f911bf312b9b94bd6ba Mon Sep 17 00:00:00 2001 From: PootisHunter Date: Thu, 5 Jun 2025 11:38:54 +0300 Subject: [PATCH 11/12] formatting --- src/bin/cli.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin/cli.rs b/src/bin/cli.rs index 8bb4d4d..c41521e 100644 --- a/src/bin/cli.rs +++ b/src/bin/cli.rs @@ -1,18 +1,18 @@ use ainigma::{ - build_process::{build_batch, build_sequential, TaskBuildContainer}, - config::{read_check_toml, ModuleConfiguration, Task, DEFAULT_BUILD_MANIFEST}, + build_process::{TaskBuildContainer, build_batch, build_sequential}, + config::{DEFAULT_BUILD_MANIFEST, ModuleConfiguration, Task, read_check_toml}, errors::BuildError, moodle::create_exam, storages::s3_upload, }; -use clap::{crate_description, Args, Parser, Subcommand}; +use clap::{Args, Parser, Subcommand, crate_description}; use once_cell::sync::Lazy; use std::{ path::{Path, PathBuf}, process::ExitCode, sync::{ - atomic::{AtomicBool, Ordering}, Arc, Mutex, + atomic::{AtomicBool, Ordering}, }, thread, }; From c5036cec3b2dff5a116e18881f05531b4fb31771 Mon Sep 17 00:00:00 2001 From: PootisHunter Date: Thu, 5 Jun 2025 11:49:20 +0300 Subject: [PATCH 12/12] clippy --- src/bin/cli.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bin/cli.rs b/src/bin/cli.rs index c41521e..cc5b951 100644 --- a/src/bin/cli.rs +++ b/src/bin/cli.rs @@ -292,9 +292,7 @@ fn main() -> std::process::ExitCode { None => { match output_dir { OutputDirectory::Temprarory(output_dir) => { - let path = output_dir - .keep() - .expect("Failed to keep the temporal directory"); + let path = output_dir.keep(); tracing::info!( "The build has been finished and the files are located in the temporal output directory: '{}'", path.display()