Skip to content

Conversation

@IGN-Styly
Copy link
Member

@IGN-Styly IGN-Styly commented Nov 30, 2025

Summary by CodeRabbit

  • New Features

    • Added an authentication-check endpoint to the Engine service.
  • Bug Fixes

    • Strengthened error handling across server and tooling flows to avoid panics and provide clearer error responses and logs.
    • Safer startup and runtime handling with better validation and permission responses.
  • Configuration Changes

    • Server config field renamed from port to host (default preserved).
  • Breaking Changes

    • Public TaskRegistry API removed; integrations must be updated.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

Walkthrough

Adds a new CheckAuth RPC, strengthens error handling and safer lookups across binaries, renames server config field porthost, logs startup host, and removes the public TaskRegistry trait.

Changes

Cohort / File(s) Summary
RPC / Proto
engine/proto/engine.proto
Added rpc CheckAuth(empty) returns (empty) to the Engine service.
Server: auth & control flow
engine/src/bin/server.rs
Added check_auth RPC implementation; refactored many handlers to use CheckAdminAuth; replaced unsafe map access with key-based lookups and explicit gRPC errors; improved lock/poison handling and startup bind-address derivation from config.host; safer persistence/serialization error mapping.
Binary: packer error handling
engine/src/bin/packer.rs
Replaced numerous unwrap()s with guarded matches and logging for Schema, Unpack, and Pack flows; added error branches for I/O, parsing, deserialization, template lookup, and output writes.
Auth metadata parsing
engine/src/lib.rs
Simplified metadata extraction for uid/authorization into a functional chain using and_then, map, and unwrap_or_default (no signature changes).
Config struct rename
enginelib/src/config.rs
Renamed ConfigTomlServer.port: Stringhost: String; updated Default to host: "[::1]:50051".
Startup logging
enginelib/src/events/start_event.rs
Added a trace/info log to record api.cfg.config_toml.host at startup.
Task API removal
enginelib/src/task.rs
Removed the public TaskRegistry trait and its methods (register, get, serialize, deserialize).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • engine/src/bin/server.rs — review authorization flow changes, new check_auth, key-based map indexing, and error mapping.
  • engine/src/bin/packer.rs — ensure new guarded flows preserve intended behavior and error messages are sufficient.
  • enginelib/src/config.rs & usages — confirm porthost rename is applied everywhere and parsing/format expectations remain valid.
  • enginelib/src/task.rs — verify removal of TaskRegistry does not break consumers or required implementations.
  • engine/src/lib.rs — confirm metadata parsing changes preserve authentication semantics and edge-case handling.

🐰
A tiny hop — CheckAuth is new today,
No panics now, logs lead the way.
Host renamed, the startup bell rings,
Registry gone, but the engine still springs.
I nibble code crumbs and twitch my nose — hooray! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'remove prototype trait' is vague and does not clearly communicate the scope and impact of the PR. While it references trait removal, it fails to specify which trait and the PR actually encompasses much broader changes including auth checks, error handling improvements, configuration changes, and RPC additions beyond just trait removal. Consider using a more descriptive title that captures the primary changes, such as 'Add admin auth checks and error handling, remove TaskRegistry trait' or focus on the most impactful change if prioritizing brevity.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
engine/src/bin/server.rs (3)

411-419: Inconsistent task ID parsing pattern.

This code uses split(":") which will break if task names contain colons. However, create_task (line 596) uses splitn(2, ':') which correctly handles this case. Consider applying the same splitn approach here for consistency:

-        let alen = &task_id.split(":").collect::<Vec<&str>>().len();
-        if *alen != 2 {
+        let parts: Vec<&str> = task_id.splitn(2, ':').collect();
+        if parts.len() != 2 || parts[0].is_empty() || parts[1].is_empty() {
             info!("Invalid task ID format: {}", task_id);
             return Err(Status::invalid_argument(
                 "Invalid task ID format, expected 'namespace:name",
             ));
         }
-        let namespace = &task_id.split(":").collect::<Vec<&str>>()[0];
-        let task_name = &task_id.split(":").collect::<Vec<&str>>()[1];
+        let namespace = parts[0];
+        let task_name = parts[1];

495-500: Same inconsistent parsing pattern as aquire_task.

Apply the same splitn(2, ':') approach used in create_task for consistency:

-        let alen = &task_id.split(":").collect::<Vec<&str>>().len();
-        if *alen != 2 {
+        let parts: Vec<&str> = task_id.splitn(2, ':').collect();
+        if parts.len() != 2 || parts[0].is_empty() || parts[1].is_empty() {
             return Err(Status::invalid_argument("Invalid Params"));
         }
-        let namespace = &task_id.split(":").collect::<Vec<&str>>()[0];
-        let task_name = &task_id.split(":").collect::<Vec<&str>>()[1];
+        let namespace = parts[0];
+        let task_name = parts[1];

275-282: Unused variable end in pagination logic.

The end variable is computed but never used. The pagination on lines 278-281 uses data.page_size directly instead of the clamped value. This appears to be dead code, or the pagination limit isn't being enforced as intended:

         let index = data.page * data.page_size as u64;
-        let end = index + (api.cfg.config_toml.pagination_limit.min(data.page_size) as u64);
+        let clamped_page_size = api.cfg.config_toml.pagination_limit.min(data.page_size) as usize;
         let final_vec: Vec<_> = q
             .iter()
             .skip(index as usize)
-            .take(data.page_size as usize)
+            .take(clamped_page_size)
             .cloned()
             .collect();
🧹 Nitpick comments (1)
engine/src/bin/packer.rs (1)

195-272: Consider reducing nesting with early returns or the ? operator.

The error handling logic is correct, but the deep nesting (8+ levels) reduces readability. Consider extracting the pack logic into a helper function that returns Result<(), Box<dyn Error>> and uses ? for propagation, or use crates like anyhow for ergonomic error handling in CLI tools.

Example pattern:

fn pack_tasks(api: &mut EngineAPI, input: &Path) -> Result<(), Box<dyn std::error::Error>> {
    let toml_str = std::fs::read_to_string(input)?;
    let raw: RawDoc = toml::from_str(&toml_str)?;
    let entries = parse_entries(raw);
    // ... process entries ...
    let data = bincode::serialize(&api.task_queue)?;
    let mut file = File::create("output.rustforge.bin")?;
    file.write_all(&data)?;
    Ok(())
}

Then call it with:

if let Err(e) = pack_tasks(&mut api, &input.input) {
    error!("Pack failed: {}", e);
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 148ea78 and bf372a7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • engine/proto/engine.proto (1 hunks)
  • engine/src/bin/packer.rs (1 hunks)
  • engine/src/bin/server.rs (10 hunks)
  • engine/src/lib.rs (1 hunks)
  • enginelib/src/config.rs (1 hunks)
  • enginelib/src/events/start_event.rs (2 hunks)
  • enginelib/src/task.rs (0 hunks)
💤 Files with no reviewable changes (1)
  • enginelib/src/task.rs
🧰 Additional context used
🧬 Code graph analysis (4)
engine/proto/engine.proto (1)
enginelib/src/events/auth_event.rs (1)
  • Events (43-68)
enginelib/src/events/start_event.rs (1)
enginelib/src/events/mod.rs (1)
  • start_event (9-9)
engine/src/bin/packer.rs (3)
enginelib/src/events/mod.rs (1)
  • ID (11-13)
enginelib/src/task.rs (2)
  • StoredExecutingTask (17-22)
  • StoredTask (12-15)
enginelib/src/api.rs (1)
  • EngineAPI (53-164)
engine/src/bin/server.rs (6)
engine/src/lib.rs (1)
  • get_auth (11-17)
enginelib/src/events/admin_auth_event.rs (1)
  • CheckAdminAuth (72-81)
enginelib/src/config.rs (1)
  • new (31-43)
enginelib/tests/event_tests.rs (1)
  • id (18-20)
enginelib/src/events/mod.rs (1)
  • ID (11-13)
engine/src/bin/packer.rs (1)
  • bincode (140-140)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Rust project - latest (nightly)
  • GitHub Check: Rust project - latest (stable)
  • GitHub Check: Rust project - latest (beta)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (14)
engine/src/bin/packer.rs (2)

113-124: LGTM!

Solid error handling for file creation and writing with clear success/failure logging.


140-165: LGTM!

Good defensive pattern: verifying task bytes before deserializing with from_bytes(), and proper logging for unknown templates.

engine/src/lib.rs (1)

3-17: Clean idiomatic refactoring of metadata extraction.

The functional chain using and_then, map, and unwrap_or_default is a concise and safe pattern for extracting optional metadata values. Both functions handle missing or invalid UTF-8 metadata gracefully by returning an empty string.

enginelib/src/events/start_event.rs (1)

3-4: Good observability addition for startup logging.

Logging the host at startup aids debugging and operational visibility. The change correctly references the renamed host field from configuration.

Also applies to: 24-24

engine/proto/engine.proto (1)

11-11: New authentication check endpoint added.

The CheckAuth RPC provides a dedicated endpoint for verifying admin credentials. The implementation in server.rs returns permission_denied on failure and an empty response on success, which is appropriate for an auth-check endpoint.

enginelib/src/config.rs (1)

9-9: Field rename from port to host is semantically accurate.

The rename correctly reflects that this field contains the full socket address (host:port), not just a port number.

Note: This is a breaking change for users with existing config.toml files—they will need to rename port to host. Consider documenting this in release notes or migration guide.

Also applies to: 16-16

engine/src/bin/server.rs (8)

37-50: New check_auth endpoint implementation looks correct.

The implementation follows the established pattern for admin authentication checks. Passing an empty identifier ("".into(), "".into()) for the target is consistent with the general auth check use case where no specific resource is being accessed.


57-65: Admin auth check for delete_task is appropriate.

Task deletion is correctly gated behind admin authentication rather than user-level auth.


347-353: Improved lock handling prevents panic on poisoned lock.

The match on out.read() gracefully handles the poisoned lock case by returning an empty payload instead of panicking. Good defensive programming.


431-476: Significant improvement in task acquisition safety and error handling.

Key improvements:

  • Safe key-based lookup with proper empty check before remove(0)
  • Serialization and DB insertion errors now return proper Status::internal instead of panicking
  • unwrap_or_default() for optional collections prevents panic on missing keys

517-574: Consistent error handling improvements in publish_task.

All serialization and DB operations now properly return Status::internal on failure. The unwrap_or_default() pattern for optional collections is consistently applied.


596-602: Improved task ID parsing with splitn.

Using splitn(2, ':') correctly handles task names that might contain colons, only splitting on the first occurrence. The validation for empty parts prevents accepting malformed IDs like :task or namespace:.


643-651: Safe address parsing with fallback.

The fallback to 127.0.0.1:50051 handles cases where the configured IPv6 address [::1]:50051 fails to parse (e.g., on IPv4-only systems). This provides good resilience.


656-668: Clean error handling for server startup.

Mapping errors to Box<dyn std::error::Error> enables consistent error propagation with ? throughout the main function.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
engine/src/bin/packer.rs (1)

39-41: Validate compound key format to prevent silent failures.

If compound_key lacks a colon or is malformed, id will be an empty string (and namespace will be the full key or empty). Downstream lookups at lines 167 and 217-218 will then use ID(namespace, "") or ID("", id), which may silently fail to match any template in the registry.

Consider validating the split result or logging a warning when namespace or id is empty.

 for (compound_key, records) in raw.0 {
     // split on colon: "widget:button" -> ("widget", "button")
     let mut parts = compound_key.splitn(2, ':');
     let namespace = parts.next().unwrap_or("").to_string();
     let id = parts.next().unwrap_or("").to_string();
+    
+    if namespace.is_empty() || id.is_empty() {
+        error!("Invalid compound key format '{}': expected 'namespace:id'", compound_key);
+        continue;
+    }

     for data in records {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf372a7 and 3c88a49.

📒 Files selected for processing (1)
  • engine/src/bin/packer.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
engine/src/bin/packer.rs (3)
enginelib/src/config.rs (1)
  • new (31-43)
enginelib/src/events/mod.rs (1)
  • ID (11-13)
enginelib/tests/event_tests.rs (1)
  • id (18-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (rust)
🔇 Additional comments (3)
engine/src/bin/packer.rs (3)

113-124: Well-structured error handling.

The nested match statements properly log failures at both the file creation and write stages, preventing silent failures.


163-204: Past review feedback properly addressed.

The output file is now written only when deserialization succeeds (inside the if let Some(k) = maybe_queue block). This prevents the issue flagged in the previous review where an empty output file was created even when errors occurred.


210-288: Robust error handling throughout the Pack command.

The nested match structure ensures that:

  • File read failures are logged and prevent further processing
  • TOML parse errors are logged and prevent serialization
  • Per-entry template lookup and conversion failures are logged without stopping processing of other entries
  • Serialization and file write failures are properly logged

This comprehensive approach prevents silent failures and provides clear diagnostic information.

let mut final_out: Vec<String> = Vec::new();

for tasks in k.tasks {
match api.task_registry.tasks.get(&tasks.0.clone()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for all task_registry access patterns
rg -n 'task_registry\.(tasks\.)?get' --type rust -C 2

Repository: GrandEngineering/engine

Length of output: 1224


🏁 Script executed:

#!/bin/bash
# Read lines around 217-218 in packer.rs
sed -n '210,225p' engine/src/bin/packer.rs

# Search for TaskRegistry struct definition
rg -n 'struct TaskRegistry|impl.*TaskRegistry' --type rust -A 5

Repository: GrandEngineering/engine

Length of output: 1585


🏁 Script executed:

#!/bin/bash
# Find TaskRegistry struct definition
rg -n 'struct.*TaskRegistry|pub struct.*TaskRegistry' --type rust -A 10

# Find Registry trait definition
rg -n 'trait Registry' --type rust -A 10

Repository: GrandEngineering/engine

Length of output: 1086


🏁 Script executed:

#!/bin/bash
# Read full context around line 167 to understand usage
sed -n '165,175p' engine/src/bin/packer.rs

Repository: GrandEngineering/engine

Length of output: 727


🏁 Script executed:

#!/bin/bash
# Find the actual implementation of the get() method for EngineTaskRegistry
rg -n 'fn get' enginelib/src/api.rs -A 5 | head -20

Repository: GrandEngineering/engine

Length of output: 315


Use the consistent .get() method instead of direct field access.

Line 167 uses api.task_registry.tasks.get(...) (direct HashMap access) while the rest of the codebase uses api.task_registry.get(...) (the Registry trait method). Both work functionally but return different types—Arc<dyn Task> vs Box<dyn Task> respectively. For consistency with the Registry API pattern used elsewhere (e.g., lines 217-218, server.rs:528, server.rs:603), use .get() instead.

🤖 Prompt for AI Agents
In engine/src/bin/packer.rs around line 167, replace the direct HashMap access
api.task_registry.tasks.get(&tasks.0.clone()) with the Registry API call
api.task_registry.get(&tasks.0) to match the rest of the codebase; update any
downstream handling to accept the type returned by api.task_registry.get (adjust
variable ownership/borrowing or convert the returned Box/Arc as needed) so the
code uses the registry's .get() method consistently.

@IGN-Styly IGN-Styly merged commit 09fbd99 into main Nov 30, 2025
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants