Skip to content

Feat/tool broker extraction phase1 - #1859

Merged
lavkushry merged 3 commits into
mainfrom
feat/tool-broker-extraction-phase1
Jul 12, 2026
Merged

Feat/tool broker extraction phase1#1859
lavkushry merged 3 commits into
mainfrom
feat/tool-broker-extraction-phase1

Conversation

@lavkushry

Copy link
Copy Markdown
Owner

Summary

Closes #

Type of change

  • Bug fix
  • New feature
  • Refactor / cleanup
  • Docs
  • Security fix
  • Performance improvement
  • CI / build

Checklist

  • Tests added/updated; cargo test --workspace and python3 -m unittest discover -s sdk-python/tests pass.
  • cargo fmt --all -- --check and cargo clippy --workspace --all-targets -- -D warnings pass.
  • python3 -m black --check sdk-python/ examples/ passes.
  • No hardcoded secrets; secrets stay out of logs/receipts (hashes only).
  • Tenant-owned queries bind/filter tenant_id; parameterized SQL only.
  • PR title follows Conventional Commits (feat:, fix:, docs:, etc.).

Integrity invariants (do not weaken)

  • If canonicalization/hashing changed, the scheme version was bumped and the SDK ↔ gateway byte-equality corpora were updated together.
  • Fail-closed behavior preserved (unknown → deny; critical → deny; high-risk → approval; hash mismatch / expired / consumed approval → no execution).
  • Trust-provenance changes only let classifiers tighten a label, never loosen it.

Notes for reviewers

lavkushry and others added 2 commits July 12, 2026 21:05
…tool-broker binary

Phase 1 of the tool-broker extraction: the gateway process no longer links
aegis-tool-broker-connectors (removed from src/Cargo.toml production deps,
kept as a dev-dependency for the one deliberate mock-server test exception).
It never resolves a real provider credential or runs a shell command itself
anymore. POST /v1/broker/execute now calls the new standalone
aegis-tool-broker binary over HTTP with a required service-to-service
bearer token (AEGIS_TOOL_BROKER_API_TOKEN); with no broker configured it
fails closed with 501, matching the OIDC/signed-policy-bundle precedent.

The gateway is unchanged for authorization, hash-bound approval consumption,
and receipt emission -- only the connector-execution step moved process.
Ships with a Helm chart (helm/aegis-tool-broker/) and a docker-compose.full.yml
service, both wired for local/dev use.

Known Phase-1 gap (documented in Tool_Broker.md's Honest Scope, not glossed
over): the gateway consumes the approval before the broker HTTP call, so a
broker-unreachable failure burns the approval without executing the action.
Covered by execute_fails_closed_when_the_broker_is_unreachable.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Updated README.md to include links to new architecture and migration documents.
- Modified architecture-map.json to reflect changes in the SOC Console Dashboards description and file paths.
- Revised architecture.md to establish mandatory architecture laws and clarify dependency flows and integrity laws.
- Updated mkdocs.yml to include new architecture law and low-level design documents in the navigation.
- Improved audit-doc-quality.mjs to ensure no trailing newlines in rendered output.
- Added LLD.md to the list of required documents in validate-docs.mjs for documentation validation.
Copilot AI review requested due to automatic review settings July 12, 2026 16:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@ecc-tools

ecc-tools Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The head commit changed during the review from ece6a0f to 3d90af2.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/tool-broker-extraction-phase1
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/tool-broker-extraction-phase1

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.44.1)
src/src/main.rs

ast-grep timed out on this file


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.

@lavkushry
lavkushry merged commit 696f5e3 into main Jul 12, 2026
26 of 28 checks passed
@lavkushry
lavkushry deleted the feat/tool-broker-extraction-phase1 branch July 12, 2026 16:42

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request extracts the tool broker from the gateway into a standalone aegis-tool-broker binary (Phase 1 extraction), removing the connector and credential execution engine from the gateway process to enhance security. It also introduces the target high-level and low-level designs, a migration matrix, and a 36-week roadmap. The code review identified several critical improvements: a timing attack vulnerability in the token comparison function that requires a constant-time comparison, an unbounded response body read in the gateway's client that should be fixed by setting a timeout on the HTTP client builder, a non-portable healthcheck host (0.0.0.0) that should be replaced with 127.0.0.1, and a misleading optional: true flag in the Helm secret reference for the required API token.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

I am having trouble creating individual review comments. Click here to see my feedback.

bins/aegis-tool-broker/src/auth.rs (18-24)

security-high high

The tokens_match function compares hex-encoded SHA-256 digests using a standard non-constant-time string comparison (==). This is vulnerable to a timing attack that can leak the characters of the hash, allowing an attacker to reconstruct the hash and perform offline brute-force attacks. To prevent this, compare the raw binary digests using a constant-time comparison algorithm.

pub fn tokens_match(configured: &str, provided: &str) -> bool {
    use sha2::{Digest, Sha256};
    let conf_hash = Sha256::digest(configured.as_bytes());
    let prov_hash = Sha256::digest(provided.as_bytes());

    // Constant-time comparison of the 32-byte digests to prevent timing attacks
    let mut accum = 0;
    for (a, b) in conf_hash.iter().zip(prov_hash.iter()) {
        accum |= a ^ b;
    }
    accum == 0
}

src/src/tool_broker_client.rs (67-74)

high

The reqwest::Client is created without a timeout, and tokio::time::timeout only wraps the .send() call. This means the subsequent reading of the response body (via .json().await) is completely unbounded. If the tool broker hangs or transmits the body extremely slowly, the gateway thread/task will block indefinitely, potentially leading to resource exhaustion. Configuring the timeout on the reqwest::Client itself ensures the entire request lifecycle, including the body read, is bounded.

    pub fn new(base_url: String, api_token: String, timeout_secs: u64) -> Self {
        let timeout = Duration::from_secs(timeout_secs);
        let http = reqwest::Client::builder()
            .timeout(timeout)
            .build()
            .unwrap_or_else(|_| reqwest::Client::new());
        Self {
            execute_url: format!("{base_url}/v1/execute"),
            api_token,
            http,
            timeout,
        }
    }

bins/aegis-tool-broker/src/main.rs (50-56)

medium

The healthcheck command attempts to connect directly to cli.listen, which defaults to 0.0.0.0:8899. Connecting to 0.0.0.0 is non-portable and fails on macOS and certain Linux network configurations. It is safer and more robust to replace 0.0.0.0 with 127.0.0.1 for local healthcheck requests.

    if cli.healthcheck {
        let host = if cli.listen.starts_with("0.0.0.0:") {
            cli.listen.replace("0.0.0.0:", "127.0.0.1:")
        } else {
            cli.listen.clone()
        };
        let url = format!("http://{host}/livez");
        return match reqwest::get(&url).await {
            Ok(resp) if resp.status().is_success() => Ok(()),
            _ => std::process::exit(1),
        };
    }

helm/aegis-tool-broker/templates/deployment.yaml (47-52)

medium

The AEGIS_TOOL_BROKER_API_TOKEN environment variable is strictly required for the tool broker binary to start. Setting optional: true on the secretKeyRef is misleading because if the secret or key is missing, the container will still start but immediately crash-loop. Removing optional: true (or setting it to false) allows Kubernetes to block the deployment and surface a clear "missing secret" event, which is much easier to diagnose.

            - name: AEGIS_TOOL_BROKER_API_TOKEN
              valueFrom:
                secretKeyRef:
                  name: {{ include "aegis-tool-broker.secretName" . }}
                  key: AEGIS_TOOL_BROKER_API_TOKEN

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