Skip to content

feat: implement imix execution guardrails#2061

Merged
hulto merged 6 commits intomainfrom
feat/imix-guardrails-5041236407544312228
Mar 14, 2026
Merged

feat: implement imix execution guardrails#2061
hulto merged 6 commits intomainfrom
feat/imix-guardrails-5041236407544312228

Conversation

@hulto
Copy link
Collaborator

@hulto hulto commented Mar 8, 2026

Implements the requested execution guardrails capability for the imix agent.

Changes

  • New Library Crate (guardrails): Created a dedicated guardrails crate mirroring the design of host_unique. Includes a Guardrail trait.
  • Guardrail Implementations:
    • File: Checks if a specific file exists on disk.
    • Process: Checks if a specific process is currently running via the sysinfo crate.
    • Registry: Checks if a specific registry subkey (and optionally a value name) exists. This is conditionally compiled for Windows using the winreg crate.
  • Configuration (pb/src/config.rs): Integrated guardrails::check_guardrails() into the initial beacon configuration phase. If the check returns false, the agent safely logs and exits std::process::exit(0).
  • Build-time Validation: Configured a build.rs script in the guardrails crate to parse the IMIX_GUARDRAILS environment variable into a typed JSON structure. If the JSON format is invalid, compilation will fail, preventing misconfigured payloads.
  • Documentation: Updated docs/_docs/user-guide/imix.md adding a "Guardrails" section that explains usage and provides JSON configuration examples.
  • Testing: Added inline unit tests within the guardrails crate to test the various implementations and deserialization logic.

All workspace tests continue to pass successfully.


PR created automatically by Jules for task 5041236407544312228 started by @hulto

Adds a modular `guardrails` capability to `imix` similar to `host_unique`.
This allows operators to enforce that an implant only executes if specific
conditions (file presence, running process, or registry keys) are met on the host.

- Adds new `guardrails` workspace library crate.
- Supports `file`, `process`, and `registry` (Windows) rules.
- Integrates `IMIX_GUARDRAILS` JSON configuration loading at compile time via `build.rs`
- Validates guardrails at runtime startup, exiting gracefully if checks fail.
- Updates documentation with usage examples.

Co-authored-by: hulto <7121375+hulto@users.noreply.github.com>
@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 8, 2026

Summary

Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
2795    ±0 2795    ±0 0    ±0 0    ±0 0    ±0 0    ±0 1ms    ±0

Previous Results

Build 🏗️ Result 🧪 Tests 📝 Passed ✅ Failed ❌ Skipped ⏭️ Other ❓ Flaky 🍂 Duration ⏱️
#1669 2795 2795 0 0 0 0 38.9s

Insights

Average Tests per Run Total Flaky Tests Total Failed Slowest Test (p95)
2795 0 0 5.8s

Slowest Tests

Test 📝 Results 📊 Duration (avg) ⏱️ Duration (p95) ⏱️
TestDockerExecutor_Build_ContextCancellation 1 5.8s 5.8s
eldritch-libsys: std::dll_inject_impl::tests::test_dll_inject_simple 1 5.1s 5.1s
TestInteractiveShell 1 5.1s 5.1s
TestOtherStreamOutput 1 5.0s 5.0s
imix::bin/imix: install::tests::test_install_execution 3 1.7s 4.9s
imix::bin/imix: install::tests::test_install_execution 3 1.7s 4.9s
imix::bin/imix: install::tests::test_install_execution 3 1.7s 4.9s
TestDockerExecutor_Build_SimpleEcho 1 3.3s 3.3s
imix::bin/imix: tests::task_tests::test_task_streaming_output 3 3.0s 3.0s
imix::bin/imix: tests::task_tests::test_task_streaming_output 3 3.0s 3.0s

🎉 No failed tests in this run. | 🍂 No flaky tests in this run.

Github Test Reporter by CTRF 💚

🔄 This comment has been updated

};

let guardrails = parse_guardrails();
if !guardrails::check_guardrails(guardrails) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Update check_guardrails such that only one needs to be succesful not all.
Clarify this behavior in the docs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Hi! You mentioned me here. Is there anything specific you would like me to change or review regarding the guardrails check?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@jules Update check_guardrails such that only one needs to be succesful not all.
Clarify this behavior in the docs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Done. Updated the check_guardrails implementation to pass if any guardrail matches (OR condition) and return true if the guardrails list is empty. Docs were updated to reflect this.

sys.refresh_processes();

for (_, process) in sys.processes() {
if process.name().eq_ignore_ascii_case(&self.name) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Update names and matches to always be lower case clarify in docs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there an issue with how the process name is being checked?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@jules Update names and matches to always be lower case clarify in docs.

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated the docs to clarify that these matches are evaluated as case-insensitive.

if self.path.is_empty() {
return false;
}
Path::new(&self.path).exists()
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Update names and matches to always be lower case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you have any questions or feedback about the file existence check?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@jules Update names and matches to always be lower case.

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated the process check and the file check (for Windows) to use to_lowercase() for case-insensitive matching.

google-labs-jules bot and others added 2 commits March 8, 2026 21:15
Adds a modular `guardrails` capability to `imix` similar to `host_unique`.
This allows operators to enforce that an implant only executes if specific
conditions (file presence, running process, or registry keys) are met on the host.

- Adds new `guardrails` workspace library crate.
- Supports `file`, `process`, and `registry` (Windows) rules.
- Integrates `IMIX_GUARDRAILS` JSON configuration loading at compile time via `build.rs`
- Validates guardrails at runtime startup, exiting gracefully if checks fail.
- Updates documentation with usage examples.

Co-authored-by: hulto <7121375+hulto@users.noreply.github.com>
Adds a modular `guardrails` capability to `imix` similar to `host_unique`.
This allows operators to enforce that an implant only executes if specific
conditions (file presence, running process, or registry keys) are met on the host.

- Adds new `guardrails` workspace library crate.
- Supports `file`, `process`, and `registry` (Windows) rules.
- Integrates `IMIX_GUARDRAILS` JSON configuration loading at compile time via `build.rs`
- Validates guardrails at runtime startup, exiting gracefully if checks fail.
- Updates documentation with usage examples.

Co-authored-by: hulto <7121375+hulto@users.noreply.github.com>
@hulto hulto marked this pull request as ready for review March 8, 2026 22:39
@hulto hulto merged commit 1fde9c7 into main Mar 14, 2026
8 checks passed
@hulto hulto deleted the feat/imix-guardrails-5041236407544312228 branch March 14, 2026 18:45
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.

1 participant