Skip to content

feat: sync upstream main with orchestrator, blue-team, and benchmark overhaul - #439

Closed
l50 wants to merge 484 commits into
dreadnode:mainfrom
l50:main
Closed

feat: sync upstream main with orchestrator, blue-team, and benchmark overhaul#439
l50 wants to merge 484 commits into
dreadnode:mainfrom
l50:main

Conversation

@l50

@l50 l50 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Key Changes:

  • Reintroduced an LLM-driven orchestrator with proposal-based work mediation, configurable planner intervals, wall-clock timeouts, self-healing, and per-role token/cost accounting
  • Built out a comprehensive blue-team investigation pipeline with deterministic detection sweeps, simulated containment loops, coverage measurement against red ground truth, and Redis-backed escalation state
  • Migrated Ansible tooling roles to external l50.arsenal and l50.bulwark collections and moved EC2/proxmox/k8s provisioning to Taskfile-driven shell helpers
  • Added an end-to-end EC2 operation runner, benchmark capture/replay pipeline with Tempo trace support, and expanded ATT&CK technique mapping for AD attack paths

Added:

  • Benchmark subsystem - Introduced ares-cli/src/benchmark/ with capture, replay, manifest, S3 snapshot, and Tempo push modules, plus a benchmarks/replay-stack/ Docker compose environment and docs/benchmark-replay.md
  • Orchestrator planning and proposals - Added orchestrator_planning.rs, proposals.rs, flags.rs, and config-backed orchestrator flags with discovery-driven wakes and dispatch cooldowns
  • Blue-team sweep and containment - Added orchestrator/blue/sweep.rs, simulated_response.rs, coverage/provenance reports, blue_invalidation.rs, and op_state_event.rs for op-state projection
  • Cleanup and teardown pipeline - Added orchestrator/cleanup/ (baseline, capture, dispatcher, engine, journal, registry) with write-ahead mutation journaling and post-op auto teardown
  • ACL attack graph - Added orchestrator/acl_graph.rs and parsers/bloodhound.rs for BloodHound parsing and ranked ACL edge dispatch
  • New ares-tools modules - Added redact.rs, sanitize.rs, mutation.rs, credentials.rs, kerberos_skew.rs, privesc/windows_payload.rs, parsers/lateral.rs, and blue/loki_bulk.rs
  • Claude CLI provider - Added ares-llm/src/provider/claude_cli.rs and tool_registry/provenance.rs
  • Agent skills and docs - Added .claude/skills/ares/ reference suite, dreadgoad-expert/rust-ares-expert agents, and docs/grafana-mcp.md
  • Vector and tuning Ansible roles - Added ansible/roles/vector/ for S3 log shipping, base/tasks/tuning.yml, logrotate/NATS runtime playbooks, and golden AMI build scripts
  • Infrastructure tooling - Added .taskfiles/benchmark, .taskfiles/k8s, .taskfiles/obs, .taskfiles/proxmox, .env.example, EC2 helper scripts (e2e-op.sh, run-ssm.sh, setup-history-db.sh), and demo preflight gate
  • Reasoning model support - Added configurable reasoning effort, cached token accounting, and truncated-completion recovery with retry nudges

Changed:

  • Orchestrator core - Substantially expanded completion.rs, deferred.rs, mod.rs, dispatcher/, state/, and result_processing/ to harden dedup, credential attribution, crack task deduplication, and containment invalidation
  • Trust and ADCS automation - Reworked trust.rs, adcs_exploitation.rs, dacl_abuse.rs, s4u.rs, and secretsdump.rs for cross-forest handling, ESC gating, and shadow-credential chains
  • Credential resolution - Overhauled worker/credential_resolver.rs and tool_executor.rs to unify auth resolution, pass-the-hash, and Kerberos ticket reconciliation
  • Detection and MITRE mapping - Expanded detections.yaml, mitre_techniques.yaml, and correlation engine for shadow credentials, NoPac, golden ticket, and unsecured credential detections
  • Config as source of truth - Restructured config/ares.yaml, config/sections.rs, and model selection to centralize agent config and apply per-role max_steps from YAML
  • CI and build - Reworked build-and-push-templates.yaml, removed molecule.yaml, added reusable buildx setup action, and pinned hashcat/toolchain versions
  • Documentation consolidation - Rewrote docs/blue.md, docs/red.md, docs/infrastructure.md, README.md, and warpgate template docs to reference main branch
  • Migrations - Renamed init migration and added analytical, dedup, and team-flag SQL migrations

Removed:

  • Legacy Ansible tooling roles - Removed acl_tools, coercion_tools, cracking_tools, credential_access_tools, lateral_movement_tools, privesc_tools, recon_tools, alloy, mythic, aws_cloudwatch_agent, aws_ssm_agent, and dc_audit_sacl in favor of external collections
  • Remote crackd hashcat backend - Removed the remote crackd client in favor of direct hashcat dispatch with lifecycle logging
  • KrbRelayUp automation - Removed automation/krbrelayup.rs and seimpersonate escalation automation
  • Legacy grafana credentials and orchestrator wrapper - Removed legacy grafana credential fields from config, orchestrator-wrapper.sh/orchestrator-wrapper-patch.yaml, docs/plan-loot-gaps.md, and outdated grafana MCP docs

l50 and others added 30 commits July 20, 2026 20:11
)

**Key Changes:**

- Fixed roast ciphertext (AS-REP, TGS-REP) being treated as
authenticating hashes, causing impacket to fall into interactive
`getpass()` during MSSQL link pivots
- Fixed `KDC_ERR_C_PRINCIPAL_UNKNOWN` incorrectly revoking the acting
principal during routine kerberoast/SPN enumeration, and added
corroboration threshold for weak credential-reject signals
- Added automatic post-S4U DCSync dispatch when a constrained-delegation
S4U succeeds against a DC, converting the foothold into a krbtgt dump
- Fixed hashcat GPU underutilization on the T4 cracker box via
configurable workload profile and corrected potfile path resolution for
systemd services

**Added:**

- Post-S4U secretsdump automation - added `plan_post_s4u_dump` and
`maybe_dispatch_post_s4u_secretsdump` to `s4u.rs`; fires a direct
`secretsdump_kerberos` tool call with `-use-vss` after any successful
S4U to a DC's CIFS SPN, deduped on `(dc_ip, domain)` and cleared on
failure for retry
- Hashcat workload profile support - added `ARES_HASHCAT_WORKLOAD` env
var (default `3`, dedicated cracker sets `4`) and `-w` flag to every
`niced_hashcat()` invocation; measured +50% hash rate on T4 under fleet
load vs default `-w 2`
- `home` crate dependency to `ares-tools` for `getpwuid`-backed home
directory resolution when `$HOME` is unset under systemd
- `containment_reject_counts` map to `StateInner` tracking per-principal
weak credential-reject observations before revocation is published
- `ec2:kill` task to the EC2 Taskfile for stopping and deleting running
operations
- `ARES_HASHCAT_WORKLOAD=4` and `HOME=/root` environment variables
injected into the EC2 cracker deployment env file
- `select_binary` function in `ares-core/build.rs` to map each tool
`fn_name` to the binary it actually invokes within a multi-binary group,
fixing mislabeled MITRE spans

**Changed:**

- `is_authenticating_hash_type` is now `pub(crate)` and strips
hyphens/underscores before matching, so canonical stored spellings
`"AS-REP"` and `"TGS-REP"` correctly collapse onto roast tokens instead
of passing through as authenticating hashes
- `candidate_pivot_logins` in `mssql_link_pivot.rs` now filters hashes
through `is_authenticating_hash_type`, preventing kerberoast/AS-REP
ciphertext accounts from consuming the `MAX_PIVOT_ATTEMPTS` budget on
guaranteed `getpass()` failures
- Credential revocation logic split into strong
(`KDC_ERR_CLIENT_REVOKED`, published immediately) and weak
(`STATUS_LOGON_FAILURE`/`INVALID_CREDENTIALS`, requires
`CREDENTIAL_REVOKE_MIN_OBSERVATIONS=2` corroborating observations)
paths; spray/brute techniques are gated out of the weak path entirely
- `KDC_ERR_C_PRINCIPAL_UNKNOWN` removed from
`CREDENTIAL_REJECT_MARKERS`; it is a routine SPN-enumeration
side-effect, not evidence the acting account was disabled
- S4U DC IP resolution switched from `domain_controllers` map lookup to
`state.resolve_dc_ip()` to avoid wrong-realm dispatch when the map is
empty or miskeyed; `dc_ip` field now also emitted in `build_s4u_payload`
alongside `target_ip` so getST's `-dc-ip` flag is populated
- `tools.yaml` impacket credential-access group reordered to
`[impacket-secretsdump, impacket-GetNPUsers, impacket-GetUserSPNs]` so
`select_binary` resolves `secretsdump`/`ntds_dit_extract` to the correct
binary
- `default_hashcat_potfile` now uses `home::home_dir()` instead of
`std::env::var("HOME")` so the per-op potfile wipe finds the real file
under systemd where `$HOME` is unset
**Key Changes:**

- Added retry loop for transient `KRB_AP_ERR_MODIFIED` PKINIT failures
during certipy auth, retrying up to 4 times
- Fixed auth command to pass bare sAMAccountName via `-username` instead
of UPN form, preventing AS-REP failures for RID-500 Administrator
- Corrected overall success determination to handle RC4-disabled KDCs
where certipy auth exits non-zero despite producing a valid ccache

**Changed:**

- certipy auth invocation - Replaced single-shot `certipy auth` command
with a retry loop (up to 4 attempts) that detects transient
`KRB_AP_ERR_MODIFIED` errors caused by intermittent DH/session-key
mismatches on AES-only KDCs; also added `-username` flag passing the
bare sAMAccountName (split from UPN) to prevent PKINIT AS-REP failures
for the built-in Administrator account (`certipy_esc1_full_chain` in
`adcs.rs`)

- Success and exit code logic - Replaced the previous success check
(`request_output.success && auth_output.success && dcsync_success`) with
a more nuanced `overall_success` determination: when DCSync ran, both
the request and DCSync steps must succeed (auth exit code is not
authoritative on RC4-disabled KDCs); when no DCSync tail ran, success
additionally requires `got_nt_hash` to ensure a clean auth that
recovered no hash is reported as a failure rather than silently deduped
as complete (`certipy_esc1_full_chain` in `adcs.rs`)
…n ticket stop condition (#242)

**Key Changes:**

- Added `--potfile-disable` to every hashcat invocation to prevent
persistent plaintext accumulation on disk
- Enabled `stop_on_golden_ticket` in the default operation config to
halt on golden ticket acquisition
- Fixed a shell printf format string in the EC2 Taskfile to avoid
potential flag misinterpretation

**Added:**

- Potfile suppression across all hashcat passes - Added
`--potfile-disable` argument in `niced_hashcat()` so no cross-operation
state accumulates on disk; cracks are recovered from per-pass stdout
instead, ensuring no plaintext is lost (`ares-tools/src/cracker.rs`)
- Doc comment explaining potfile rationale - Added inline documentation
to `niced_hashcat()` describing why the potfile is disabled and how
crack recovery works without it
- Test assertion for potfile flag - Extended the existing workload
profile test to verify `--potfile-disable` is present in every hashcat
command's argument list

**Changed:**

- Golden ticket stop condition - Flipped `stop_on_golden_ticket` from
`false` to `true` in `config/ares.yaml`, making operation halt
automatically upon golden ticket acquisition rather than continuing
- EC2 profile flag formatting - Corrected `printf -- '--profile %s'` to
`printf '%s' '--profile {{.AWS_PROFILE}}'` in
`.taskfiles/ec2/Taskfile.yaml` to properly pass the profile flag string
and avoid shells interpreting it as a printf option
**Key Changes:**

- Fixed a bug where canonical hyphenated hash type spellings (e.g.,
"AS-REP", "TGS-REP") were misclassified as priority-1 instead of
priority-0, causing crackable Kerberos tickets to be starved behind NTLM
floods
- Introduced punctuation stripping before match comparison so that
normalized forms from `dedup::normalize_hash_type` correctly collapse
onto bare roast tokens
- Expanded the priority-0 match arm to include additional Kerberos
ticket spellings (`krb5asrep`, `krb5tgs`, `tgsrep`, `tgs`)
- Added a regression test covering all affected canonical and variant
spellings

**Added:**

- Regression test for canonical roast spelling normalization -
`crack_priority_normalizes_canonical_roast_spellings` verifies that both
hyphenated canonical forms and bare token variants are correctly ranked
as priority-0, and that non-roastable types like NTLM remain priority-1

**Changed:**

- Hash type normalization in priority ranking - `crack_priority` in
`crack.rs` now strips `-` and `_` characters after lowercasing before
matching, mirroring the behavior of
`credential_resolver::is_authenticating_hash_type`; previously "AS-REP"
lowercased to "as-rep" which never matched the "asrep" arm,
misclassifying roastable tickets as priority-1 and allowing the
secretsdump NTLM flood to starve genuinely crackable AS-REP and TGS-REP
tickets indefinitely
…ed cross-forest admin (#244)

**Key Changes:**

- Introduced `is_native_adcs_enum_candidate` to identify same-domain,
non-machine accounts with recovered passwords as preferred ADCS
enumerators
- ADCS enumeration now selects a native domain user when available,
ensuring certipy correctly flags ESC1 (enrollee-supplies-subject)
templates as vulnerable
- Fell back to the forged cross-forest Administrator only when no native
credential exists, preserving existing behavior for uncracked
environments
- Added unit tests covering all candidate selection edge cases

**Added:**

- Native enrollee selection logic - `is_native_adcs_enum_candidate`
predicate filters for same-domain, non-machine accounts with a non-empty
plaintext password; delegation accounts and quarantined principals are
excluded by the caller in `dispatch_post_ticket_adcs_enumeration`
- Unit test suite for candidate selection -
`native_adcs_enum_candidate_prefers_same_domain_password_user` covers
eligible native user, case-insensitive domain match, cross-forest
account exclusion, machine account (`$` suffix) exclusion, and uncracked
credential exclusion

**Changed:**

- ADCS enumeration principal selection -
`dispatch_post_ticket_adcs_enumeration` now resolves a `native_user`
from state alongside `target_dc_ip` and passes it as the `username` in
`tool_args`, falling back to `"Administrator"` only when no native
candidate is found; this ensures certipy binds as a Domain Users member
so ESC1 templates are surfaced rather than silently skipped
- Structured log output for ADCS dispatch - added `principal` and
`native` fields to the tracing event so operators can confirm which
account was used for each enumeration run
| datasource  | package              | from    | to      |
| ----------- | -------------------- | ------- | ------- |
| github-tags | github/codeql-action | v4.37.1 | v4.37.2 |
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[taiki-e/install-action](https://redirect.github.com/taiki-e/install-action)
([changelog](https://redirect.github.com/taiki-e/install-action/compare/07b4745e0c39a41822af610387492e3e53aa222b..a6b2e2dcd845ddd7f509ce4f3ed3d922b80cc5d9))
| action | digest | `07b4745` → `a6b2e2d` |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
| datasource  | package          | from   | to     |
| ----------- | ---------------- | ------ | ------ |
| github-tags | actions/checkout | v7.0.0 | v7.0.1 |
| datasource  | package                   | from     | to       |
| ----------- | ------------------------- | -------- | -------- |
| github-tags | renovatebot/github-action | v46.1.19 | v46.1.20 |
| datasource  | package         | from   | to     |
| ----------- | --------------- | ------ | ------ |
| github-tags | actions/labeler | v6.2.0 | v7.0.0 |
| datasource  | package              | from   | to     |
| ----------- | -------------------- | ------ | ------ |
| github-tags | actions/setup-python | v6.3.0 | v7.0.0 |
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [pre-commit](https://redirect.github.com/pre-commit/pre-commit) |
`==4.6.0` → `==4.6.1` |
![age](https://developer.mend.io/api/mc/badges/age/pypi/pre-commit/4.6.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/pypi/pre-commit/4.6.0/4.6.1?slim=true)
|

---

### Release Notes

<details>
<summary>pre-commit/pre-commit (pre-commit)</summary>

###
[`v4.6.1`](https://redirect.github.com/pre-commit/pre-commit/blob/HEAD/CHANGELOG.md#461---2026-07-21)

[Compare
Source](https://redirect.github.com/pre-commit/pre-commit/compare/v4.6.0...v4.6.1)

\==================

##### Fixes

- Install `language: node` hooks via `git`.
  - Fixes npm 12.x compatibility
-
[#&#8203;3719](https://redirect.github.com/pre-commit/pre-commit/issues/3719)
PR by [@&#8203;asottile](https://redirect.github.com/asottile).
-
[#&#8203;3517](https://redirect.github.com/pre-commit/pre-commit/issues/3517)
issue by [@&#8203;ojob](https://redirect.github.com/ojob).
- Set `JULIA_DEPOT_PATH` for `language: julia`.
-
[#&#8203;3711](https://redirect.github.com/pre-commit/pre-commit/issues/3711)
PR by [@&#8203;damonbayer](https://redirect.github.com/damonbayer).
-
[pre-commit-ci/runner-image#335](https://redirect.github.com/pre-commit-ci/runner-image/issues/335)
issue by [@&#8203;damonbayer](https://redirect.github.com/damonbayer).
- Produce error on mistyped `--repo` for `pre-commit autoupdate`.
-
[#&#8203;3701](https://redirect.github.com/pre-commit/pre-commit/issues/3701)
PR by [@&#8203;mxr](https://redirect.github.com/mxr).
-
[#&#8203;3695](https://redirect.github.com/pre-commit/pre-commit/issues/3695)
issue by [@&#8203;mxr](https://redirect.github.com/mxr).
- Improve performance of commit existence check in `pre-push`.
-
[#&#8203;3726](https://redirect.github.com/pre-commit/pre-commit/issues/3726)
PR by [@&#8203;asottile](https://redirect.github.com/asottile).
-
[#&#8203;3604](https://redirect.github.com/pre-commit/pre-commit/issues/3604)
issue by [@&#8203;ptarjan](https://redirect.github.com/ptarjan).
- Avoid duplicating conflicted filenames during `pre-commit run
--all-files`.
-
[#&#8203;3727](https://redirect.github.com/pre-commit/pre-commit/issues/3727)
PR by [@&#8203;asottile](https://redirect.github.com/asottile).
-
[#&#8203;3706](https://redirect.github.com/pre-commit/pre-commit/issues/3706)
issue by [@&#8203;RomanValov](https://redirect.github.com/RomanValov).

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [grafana/grafana](https://redirect.github.com/grafana/grafana) | patch
| `13.1.0` → `13.1.1` |

---

### Release Notes

<details>
<summary>grafana/grafana (grafana/grafana)</summary>

###
[`v13.1.1`](https://redirect.github.com/grafana/grafana/releases/tag/v13.1.1):
13.1.1

[Download page](https://grafana.com/grafana/download/13.1.1)
[What's new
highlights](https://grafana.com/docs/grafana/latest/whatsnew/)

##### Features and enhancements

- **Go:** Update version to 1.26.5
[#&#8203;128015](https://redirect.github.com/grafana/grafana/pull/128015),
[@&#8203;macabu](https://redirect.github.com/macabu)
- **Provisioning:** Improve form errors for github connections
[#&#8203;128177](https://redirect.github.com/grafana/grafana/pull/128177),
[@&#8203;grafana-writer\[bot\]](https://redirect.github.com/grafana-writer\[bot])
- **Provisioning:** make sync per-resource write timeout configurable
[#&#8203;127868](https://redirect.github.com/grafana/grafana/pull/127868),
[@&#8203;grafana-writer\[bot\]](https://redirect.github.com/grafana-writer\[bot])

##### Bug fixes

- **Accessibility:** Ensure `InlineToast` contents are announced by
screenreaders
[#&#8203;128687](https://redirect.github.com/grafana/grafana/pull/128687),
[@&#8203;grafana-writer\[bot\]](https://redirect.github.com/grafana-writer\[bot])
- **DashboardDS:** Fix chained dashboard datasource panels showing stale
data
[#&#8203;127248](https://redirect.github.com/grafana/grafana/pull/127248),
[@&#8203;grafana-writer\[bot\]](https://redirect.github.com/grafana-writer\[bot])
- **Provisioning:** make GitHub webhook creation idempotent (fix repos
stuck unhealthy with HTTP 422)
[#&#8203;128201](https://redirect.github.com/grafana/grafana/pull/128201),
[@&#8203;floriecai](https://redirect.github.com/floriecai)

##### Plugin development fixes & changes

- **Pagination:** Set `aria-current` on active page
[#&#8203;128518](https://redirect.github.com/grafana/grafana/pull/128518),
[@&#8203;grafana-writer\[bot\]](https://redirect.github.com/grafana-writer\[bot])

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [serde_json](https://redirect.github.com/serde-rs/json) |
workspace.dependencies | patch | `1.0.150` → `1.0.151` |

---

### Release Notes

<details>
<summary>serde-rs/json (serde_json)</summary>

###
[`v1.0.151`](https://redirect.github.com/serde-rs/json/releases/tag/v1.0.151)

[Compare
Source](https://redirect.github.com/serde-rs/json/compare/v1.0.150...v1.0.151)

- Add RawValue::from\_string\_unchecked
([#&#8203;1331](https://redirect.github.com/serde-rs/json/issues/1331),
thanks
[@&#8203;WonderLawrence](https://redirect.github.com/WonderLawrence))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [tokio](https://tokio.rs)
([source](https://redirect.github.com/tokio-rs/tokio)) |
workspace.dependencies | patch | `1.53.0` → `1.53.1` |

---

### Release Notes

<details>
<summary>tokio-rs/tokio (tokio)</summary>

###
[`v1.53.1`](https://redirect.github.com/tokio-rs/tokio/releases/tag/tokio-1.53.1):
Tokio v1.53.1

[Compare
Source](https://redirect.github.com/tokio-rs/tokio/compare/tokio-1.53.0...tokio-1.53.1)

### 1.53.1 (July 20th, 2026)

##### Fixed

- signal: restore MSRV by removing `OnceLock::wait` from the Windows
handler ([#&#8203;8300])

##### Fixed (unstable)

- time: fix alt timer cancellation and insertion race ([#&#8203;8252])

##### Documented

- runtime: remove dead link definition in Runtime::block\_on
([#&#8203;8301])

[#&#8203;8252]: https://redirect.github.com/tokio-rs/tokio/pull/8252

[#&#8203;8300]: https://redirect.github.com/tokio-rs/tokio/pull/8300

[#&#8203;8301]: https://redirect.github.com/tokio-rs/tokio/pull/8301

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [async-nats](https://redirect.github.com/nats-io/nats.rs) |
workspace.dependencies | minor | `0.49` → `0.50` |

---

### Release Notes

<details>
<summary>nats-io/nats.rs (async-nats)</summary>

###
[`v0.50.0`](https://redirect.github.com/nats-io/nats.rs/releases/tag/async-nats/v0.50.0)

#### Overview

This release allows for on-demand swap between `chrono` and `time`
crates.

#### What's Changed

- Add chrono as alternative to time crate by
[@&#8203;Jarema](https://redirect.github.com/Jarema) in
[#&#8203;1595](https://redirect.github.com/nats-io/nats.rs/pull/1595)
- Use new start method for retry start in nats-server crate by
[@&#8203;Jarema](https://redirect.github.com/Jarema) in
[#&#8203;1603](https://redirect.github.com/nats-io/nats.rs/pull/1603)
- Fix account info deser failure on servers with tiered jetstream by
[@&#8203;xanderio](https://redirect.github.com/xanderio) in
[#&#8203;1604](https://redirect.github.com/nats-io/nats.rs/pull/1604)

#### Chrono vs Time

Enabling `chrono` anywhere in the
dependency graph selects the chrono backend for the whole build (Cargo
feature unification).

#### New Contributors

- [@&#8203;xanderio](https://redirect.github.com/xanderio) made their
first contribution in
[#&#8203;1604](https://redirect.github.com/nats-io/nats.rs/pull/1604)

**Full Changelog**:
<nats-io/nats.rs@async-nats/v0.49.1...async-nats/v0.50.0>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNzUuMCIsInVwZGF0ZWRJblZlciI6IjQzLjI3NS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
…an-mark timing fix (#256)

**Key Changes:**

- Implemented full ESC13 (issuance-policy OID → group link) exploitation
chain with correct plain-enrollment semantics — no `-upn`/`-sid`
override — preventing CA policy module rejections and KB5014754
strict-SID mapping failures
- Fixed scan target deduplication mark timing: moved `scanned_targets`
registration from submit-request time to actual-dispatch time,
preventing deferred/evicted scan tasks from permanently suppressing host
port scans
- Enabled gMSA password retrieval via machine-account NT hash (`-H`
auth), allowing the gMSA's sole authorized reader (`HOST$`) to be used
when it has no plaintext credential
- Fixed RID-less `$MACHINE.ACC` secretsdump row parsing so the dumped
host's own machine account is captured rather than silently dropped

**Added:**

- ESC13 full chain tool (`certipy_esc13_full_chain`) — plain enrollment,
PKINIT auth, and DCSync `krbtgt` with the elevated ccache; registered in
`ares-tools/src/lib.rs` and `parsers/mod.rs` alongside
`certipy_esc1_full_chain`
- `dispatch_esc13_deterministic` and `build_esc13_chain_args` —
deterministic ESC13 dispatcher with the same dedup/retry lifecycle as
ESC1, explicitly excluding `-upn`/`-sid` args; routing added to
`auto_adcs_exploitation` before the ESC8 branch
- `is_owned_domain_ntlm` filter in `crack.rs` — skips NTLM hashes from
already-dominated domains to prevent them from starving
AS-REP/kerberoast crack slots for forests not yet owned
- `scan_target_from_payload` helper in `submission.rs` — extracts the
target IP from recon payloads carrying `network_scan` or `nmap_scan`
techniques, used to gate the now-deferred scan mark
- `RE_NTLM_MACHINE_ACCT` regex in `hashes.rs` — dedicated pass for
RID-less `DOMAIN\HOST$:LM:NT:::` rows that the existing domain/plain
NTLM regexes (which require a numeric RID) would miss
- `on_behalf_nt_domain` helper in `adcs.rs` — derives the NetBIOS flat
name from the FQDN's first DNS label (uppercased) for certipy's
`-on-behalf-of`, fixing ESC3 failures caused by passing an FQDN there
- `run_post_ticket_adcs_enum` / `AdcsEnumOutcome` in `trust.rs` —
extracted reusable ADCS enumeration primitive that returns a typed
outcome; `dispatch_post_ticket_adcs_enumeration` now tries the native
enrollee first and falls back to the forged Administrator only when the
native run found nothing
- `reader_hash: Option<String>` field on `GmsaWork` and supporting
resolution logic in `select_gmsa_work` — resolves machine-account
readers from the hash store when no plaintext credential exists; payload
builder emits `credential.hash` when set
- `is_hash32` helper in `secrets.rs` — distinguishes a 32-hex hash from
a numeric RID to detect the RID-less `$MACHINE.ACC` shape in secretsdump
output

**Changed:**

- `crack_priority` match arms narrowed to `kerberoast | asrep |
asreproast` only — removed `krb5asrep`, `krb5tgs`, `tgsrep`, `tgs`
aliases that were never emitted by `normalize_hash_type`, and updated
tests to reflect the actual canonical spellings (`AS-REP`, `Kerberoast`)
- `parse_secretsdump` in `secrets.rs` — detects RID-less rows (field 1
is a 32-hex hash, not a numeric RID) and reads LM/NT from the shifted
positions; RID-less rows are never classified as trust keys since they
represent the host's own account
- `gmsa_dump_passwords` tool in `privesc/gmsa.rs` — passes the `hash`
argument through to `netexec_creds` for `-H` auth; updated tool
definition description and schema to document the `hash` field
- `submit_to_llm` in `submission.rs` — marks `DEDUP_SCANNED_TARGETS` at
actual dispatch time (after throttle and per-credential gates) instead
of at submit-request time; removed the early mark from
`task_builders.rs`
- `dispatch_post_ticket_adcs_enumeration` in `trust.rs` — refactored to
try native enrollee first, then fall back to forged Administrator if the
native run found zero vulnerabilities, ensuring a stale/rotated native
password never leaves the CA un-enumerated
- ESC3 `-on-behalf-of` argument in `adcs.rs` — now uses the NetBIOS flat
name (`CONTOSO`) instead of the FQDN (`contoso.local`), fixing CA policy
module denials (`0x80070547`)
- `config/ares.yaml` completion mode defaults — both
`stop_on_domain_admin` and `stop_on_golden_ticket` set to `false`
(full-forest compromise mode); expanded inline comments document all
three stop conditions and the multi-domain caveat for
`stop_on_golden_ticket`
…istory DB (#257)

**Key Changes:**

- Introduced a full mutation journal and teardown system that records
every persistent target change an operation makes and can reverse them
LIFO via `ares ops teardown`, surviving SIGKILL and post-op worker
shutdown
- Added pre-op attacker workspace sanitization (hashcat potfile, netexec
`~/.nxc` DBs/artifacts, Kerberos ccaches) to prevent ops from inheriting
prior op residue, exposed as both an automatic orchestrator pass and
`ares ops sanitize`
- Replaced the remote RDS dependency with a box-local loopback Postgres
for `ares-history`, eliminating cross-region networking for the
us-east-1 kali-ares box

**Added:**

- Mutation journal infrastructure (`orchestrator/cleanup/journal.rs`) —
a Redis LIST (`ares:op:{id}:mutation_journal`) that records every
successful mutating tool call with target, principal, forward args, and
a forward-time hint (e.g. pywhisker DeviceID, noPac machine account
name); rides the same 24h TTL as all other op keys so teardown works
long after the orchestrator exits
- `JournalingToolDispatcher` decorator
(`orchestrator/cleanup/dispatcher.rs`) — wraps the single shared
`Arc<dyn ToolDispatcher>` so both LLM-driven and deterministic tool
calls are captured at one choke point with zero changes to automation
modules
- Teardown engine (`orchestrator/cleanup/engine.rs`) — reads the journal
LIFO, dispatches inverses in-process via `ares_tools::dispatch`, runs
optional read-back validation probes, and emits a structured report with
per-entry status (Verified / Reverted / Unverified / Skipped / Failed)
- Undo registry (`orchestrator/cleanup/registry.rs`) — maps 18 mutating
tools to their inverse plans and reversibility classes (CLEAN /
NEEDS-CAPTURE / HARD / IMPOSSIBLE / UNSUPPORTED), with read-back probes
for `rbcd_write`, `add_computer`, `bloodyad_add_group_member`, and
`nopac`
- Forward-time state capture (`orchestrator/cleanup/capture.rs`) —
scrapes pywhisker DeviceID and noPac machine account name from tool
stdout so teardown can build faithful inverses without a
read-before-write
- `ares ops teardown` subcommand (`ares-cli/src/ops/teardown.rs`) —
standalone CLI entry point supporting `--latest`, `--dry-run`, and
`--only <tool>`; exits non-zero when any attempted revert fails so `task
ec2:teardown` and CI can gate on it
- `ares ops sanitize` subcommand (`ares-cli/src/ops/sanitize.rs`) —
manually triggers the workspace sanitizer and prints counts for potfile
reset, nxc paths removed, and ccaches removed
- `ares_tools::sanitize` module (`ares-tools/src/sanitize.rs`) — wipes
hashcat potfile, netexec `~/.nxc` workspaces/DBs/spider/artifacts, and
`/tmp/ares-tickets` ccaches; respects `ARES_KEEP_WORKSPACE=1`; warns
when remote crackd is configured (its server-side potfile is out of
reach)
- `bloodyad_get_object` tool (`ares-tools/src/acl.rs`) — LDAP read-back
used by teardown validation probes to confirm mutations are gone after
revert
- `task ec2:history-db` and `setup-history-db.sh` — idempotent
provisioner for a box-local PostgreSQL `ares_history` database with
passwordless loopback trust for `ares_admin`; ares self-migrates the
schema on first start
- `task ec2:teardown` — task wrapper that invokes `ares ops teardown`
over SSM with support for `OPERATION_ID`, `LATEST`, `DRY_RUN`, and
`ONLY` parameters

**Changed:**

- Orchestrator startup (`orchestrator/mod.rs`) — wraps the tool
dispatcher with `JournalingToolDispatcher` immediately after
construction, and runs the workspace sanitizer before any automation
dispatches a tool; also adds an explicit pre-launch `ares ops sanitize`
call in the EC2 launch script (belt-and-suspenders alongside the
in-binary pass)
- Default `ARES_DATABASE_URL` (`Taskfile.yaml`) — changed from empty
(RDS-dependent) to `postgresql://ares_admin@127.0.0.1:5432/ares_history`
(box-local loopback); DB reachability probe now derives host:port from
the URL rather than hardcoding the RDS endpoint, so it works for both
local and remote targets
- `task ec2:start` — extended to start `postgresql` alongside Redis and
NATS; the start is best-effort (no-op if `task ec2:history-db` has not
yet run) and the launcher probes 5432 before passing `ARES_DATABASE_URL`
to the orchestrator
- `add_computer` tool (`ares-tools/src/privesc/delegation.rs`) — added
optional `action` parameter (`add` [default] | `delete`) so teardown can
delete machine accounts created by an op without a separate tool
- `bloodyad_add_group_member` and `bloodyad_add_genericall`
(`ares-tools/src/acl.rs`) — added optional `action` parameter (default
`add`) so teardown can pass `remove` to reverse group membership and
GenericAll grants
- `pywhisker` builder (`ares-tools/src/acl.rs`) — added optional
`--device-id` flag forwarding so teardown can target the exact Key
Credential entry to remove using the captured DeviceID hint
- `task ec2:poll-op` precondition — added an explicit `test -x
{{.ARES_CLI}}` guard so a missing binary fails fast rather than silently
looping until `MAX_WAIT`
…on (#258)

**Key Changes:**

- Introduced a `simulated_response` module that translates blue
escalation decisions (`confirm_escalation`, `downgrade_escalation`) into
tracing spans for the demo dashboard and optionally publishes matching
op-state events to the red-side projector via NATS
- Added `OpStateRecorder` to `BlueCallbackHandler` so confirmed
containment actions (disable AD account, isolate host, revoke
krbtgt/certificate) invalidate red's in-flight and deferred task queues
- Fixed a multi-forest completion bug where a
discovered-but-never-exploited trust forge whose target forest was
already dominated via another path (native ADCS/DCSync) pinned the op
open to the hard max-runtime cap
- Added red dispatch freezing at the moment of op completion so the
swarm stops burning LLM tokens on the exploit/ACL backlog during the
post-completion blue-drain window

**Added:**

- `simulated_response` module
(`ares-cli/src/orchestrator/blue/simulated_response.rs`) — emits
`blue.simulated_response.<action_type>` spans (Tempo spanmetrics, demo
dashboard `Simulated Response Actions` panel) and provides
`payload_for_containment` / `publish_containment` helpers that translate
action slugs into `OpStateEventPayload` variants (`CredentialRevoked`,
`HostIsolated`, `KrbtgtRotated`, `CertificateRevoked`)
- `BlueCallbackHandler::with_recorder` constructor — wires a
caller-supplied `OpStateRecorder` (NATS-backed in production, capturing
in tests); the recorder-less `new` is preserved for call sites without a
broker
- `handle_confirm_escalation` and `handle_downgrade_escalation` async
handlers — replace the previous static path in `dispatch_callback`, emit
spans unconditionally, and publish containment observations when a
concrete action + target are named
- `task_dropped_by_containment` filter in `deferred.rs` — checks
isolated hosts, revoked credentials, and rotated krbtgt against deferred
task payloads before re-dispatch, preventing noisy
`STATUS_LOGON_FAILURE` / `STATUS_HOST_UNREACHABLE` errors during the
demo
- `dominated_forest_roots` extracted helper and
`escalation_target_forest_dominated` guard in `completion.rs` — shared
by `compute_undominated_forests` and
`has_pending_cross_forest_escalation` so the two completion guards can't
drift
- `containment_action` and `target` fields added to the
`confirm_escalation` tool schema in `ares-llm` — the LLM can now name a
specific containment action and its subject; `escalate_to_human` remains
the default no-op

**Changed:**

- `run_investigation` signature gains an `op_state_recorder` parameter
and splices `operation_id` into `alert.labels` before constructing the
callback handler, so blue-side spans carry `attack_operation_id` and
appear in per-op dashboard filters
- `BlueOrchestrator` reads `ARES_BLUE_SIMULATED_CONTAINMENT=1` at
startup; when set, it connects a NATS-backed recorder and logs
confirmation; when unset or when NATS is unavailable, it falls back to a
disabled recorder with a warning — blue detection and tracing are
unaffected either way
- `has_pending_cross_forest_escalation` now accepts `dominated_domains`
and skips escalation vulns whose `target_domain` forest root is already
dominated, closing the runaway-op bug without requiring a `written_off`
stamp
- `Dispatcher` gains a `red_draining: Arc<AtomicBool>` flag;
`mark_red_draining` is called by the completion monitor the instant the
op is deemed complete, and `do_submit_outcome` checks it as the single
choke point for all red task submission

**Removed:**

- Static `confirm_escalation` / `downgrade_escalation` handling from
`dispatch_callback` — these callbacks now route through the new async
handlers instead of the inline `Some(CallbackResult::TaskComplete { ..
})` stubs
**Key Changes:**

- Moved remote build directory from tmpfs (`/tmp`) to disk-backed
`/var/tmp` to prevent incremental build failures caused by systemd
cleanup sweeping cargo build artifacts
- Fixed PostgreSQL install check to detect the server rather than the
client, preventing silent failures when `postgresql-client` is already
present without a running cluster

**Changed:**

- Remote build directory path - Changed `REMOTE_BUILD_DIR` from
`/tmp/ares-build` to `/var/tmp/ares-build` in
`.taskfiles/ec2/Taskfile.yaml`; `/tmp` on kali-ares is a 7.7G tmpfs
subject to 10-day systemd-tmpfiles-clean sweeps that were reaping cargo
build-script outputs (e.g. `rustversion`'s `OUT_DIR/version.expr`) while
leaving fingerprints intact, causing `include!(OUT_DIR/version.expr)` to
fail with ENOENT on the next incremental build; `/var/tmp` is
disk-backed with 53G free and a 30-day retention policy
- PostgreSQL install trigger - Replaced `command -v psql` with `command
-v pg_lsclusters` in `setup-history-db.sh`; kali-ares ships
`postgresql-client` as a transitive dependency of other tooling, making
`psql` available even when no server or cluster exists, so the old guard
silently skipped installation; `pg_lsclusters` (from
`postgresql-common`) is the exact binary the script depends on next and
reliably indicates whether the server package is present
…260)

**Key Changes:**

- Report generation now runs on the remote backend (EC2 or K8s) rather
than locally, fixing a fundamental issue where Blue state lives in the
orchestrator's remote Redis, not localhost
- Generated reports are automatically fetched back to the local machine
via SSM (EC2) or `kubectl exec` (K8s) after remote generation
- Added `REGENERATE` flag support to allow forcing report regeneration
via `--regenerate` CLI argument

**Added:**

- `REGENERATE` variable support - new optional `REGENERATE=true` task
parameter that passes `--regenerate` to the CLI, enabling forced report
regeneration without changing the operation ID
- Remote-to-local report fetch logic - after remote generation, the
report path is parsed from CLI output and the file is pulled back
locally using either SSM (`run_ssm_cmd`) for EC2 or `kubectl exec` for
K8s transports, with validation that the fetched file is non-empty

**Changed:**

- Report generation transport - replaced direct local `{{.ARES_CLI}}
blue report` invocation with `{{.ARES_CLI}} {{.TRANSPORT_ARGS}} blue
report`, ensuring the command runs against the correct remote backend
- Output directory structure - reports are now saved under
`{{.OUTPUT_DIR}}/blue/` (with `mkdir -p` inlined into the main shell
block) instead of directly under `{{.OUTPUT_DIR}}`
- Shell robustness - added `set -euo pipefail` to the main command block
to catch errors early and prevent silent failures
- Task description - updated to document the new `REGENERATE=true` usage
option
…ons (#261)

**Key Changes:**

- Introduces a pre-LLM deterministic sweep that runs the full detection
catalog before the orchestrator loop starts, ensuring catalog coverage
is no longer dependent on the LLM's token/context budget
- Fixes multi-technique correlation by expanding
`load_investigation_report` to return one `BlueTeamDetection` per
distinct technique instead of collapsing to a single first match
- Improves detection accuracy across several templates (golden ticket,
S4U delegation, ADCS exploitation) and adds a new
`detect_valid_account_reuse` template
- Strengthens threat hunter guidance with mandatory attribution decision
trees for S4U and valid-account reuse, and corrects the MITRE technique
for constrained delegation from T1558.003 to T1550.003

**Added:**

- Deterministic baseline sweep module (`sweep.rs`) - runs every
detection template concurrently with bounded parallelism (default 6)
under a configurable wall-clock cap (default 360s); records each hit as
a MITRE technique, TTP-level evidence, and timeline event directly into
blue state before the LLM loop begins; result is folded into the
orchestrator task prompt so the LLM starts from a recorded baseline
rather than rediscovering detections
- `detect_valid_account_reuse` detection template targeting Event 4648
(explicit-credential logon) mapped to T1078.002, with patterns for
`TargetServerName`, `TargetInfo`, `explicit.credential`, and `runas`,
excluding machine-account targets
- `SweepOutcome` and `FiredDetection` structs with a `prompt_summary()`
method that generates a directive prompt section listing fired
techniques, no-match templates, and any templates cut off by the time
cap
- Environment variable controls: `ARES_BLUE_DETERMINISTIC_SWEEP`
(toggle, default on), `ARES_BLUE_SWEEP_CONCURRENCY`, and
`ARES_BLUE_SWEEP_TIMEOUT_SECS`
- Unit tests covering `parse_fire_count`, confidence/severity mapping,
evidence type mapping, `sweep_enabled` toggle behavior, and
`prompt_summary` output for both clean and timed-out runs

**Changed:**

- `load_investigation_report` return type changed from
`Option<BlueTeamDetection>` to `Vec<BlueTeamDetection>`, scanning only
the blue-authored body (before `## Appendix`) to avoid falsely crediting
blue with red's ground-truth technique list embedded in the appendix;
call site updated to use `extend` instead of conditional push
- False-positive identification logic tightened to only flag a detection
as a false positive when no red activity matches its technique,
preventing parent/sub-technique pairs (e.g. T1021 and T1021.002) from
spuriously flagging each other
- `detect_s4u_delegation` filter corrected to a single
`TransmittedServices` stage - the second stage filtering on
service-class prefixes (`cifs/`, `ldap/`, etc.) was matching against the
SAM account name in `ServiceName` rather than an SPN string, dropping
~98% of true positives (163 populated-TransmittedServices events reduced
to 2 in live measurement); machine-account exclude removed for the same
reason
- `detect_golden_ticket` reworked to target Event 4769 only with RC4
encryption (`0x17`) on DC SPNs (`cifs/`, `ldap/`, `host/`, `krbtgt`),
replacing tool-string patterns (`golden.*ticket`, `ticketer`) that never
appear in Windows Security logs
- `detect_adcs_exploitation` filter stage 2 extended with dangerous-EKU
OIDs (`2.5.29.37.0` Any Purpose, `1.3.6.1.4.1.311.20.2.1` Certificate
Request Agent, `1.3.6.1.4.1.311.76.6.1` SubCA) to catch ESC2/ESC3
enrollments that lack ESC keyword or SAN strings
- Threat hunter prompt updated with mandatory attribution decision trees
for S4U (T1550.003) and valid-account reuse (T1078.002), explicit
instruction to run `detect_s4u_delegation` and
`detect_valid_account_reuse` first before the token budget runs low, and
a reinforced rule that a fired detection query must be recorded as its
MITRE technique rather than described in prose
…ed filters (#262)

**Key Changes:**

- Fixed critical false positive flood in kerberoasting (690/870 events,
4% precision) and AS-REP roasting (411/590 events, 70% FP rate) by
anchoring patterns to specific XML field names instead of spanning
across field names and values
- Replaced chained `|=` (conjunctive AND) with regex alternation `|~
"(?i)(…)"` for multi-literal pattern stages, fixing a logic bug that
caused OR-intended stages to require all terms simultaneously
- Introduced `TicketEncryptionType..u003e0x17` and
`PreAuthType..u003e0.u003c` as field-anchored filter patterns, verified
against 24h live Loki windows
- Added regression tests covering the OR-vs-AND compile behavior and all
three fixed detection rules

**Added:**

- Regression test `multi_literal_stages_or_not_and` - verifies that RBCD
delegation attribute casings and remote-registry service state
alternatives compile to a single regex OR rather than a conjunctive `|=`
chain, guarding against re-introduction of the AND bug
- Regression test `golden_ticket_keys_on_ticket_encryption_type` -
asserts golden ticket stage 1 contains `TicketEncryptionType` and does
not match bare `0x17`/`rc4`
- Regression test `kerberoasting_keys_on_ticket_encryption_type` -
asserts kerberoast uses the field-anchored pattern and excludes the
name-spanning `encryption.*type` and SPN-shaped `servicename` patterns
- Regression test `asrep_roasting_keys_on_preauthtype_zero` - asserts
AS-REP roasting matches the closing-tag-anchored
`PreAuthType..u003e0.u003c` and excludes all three previously over-broad
patterns

**Changed:**

- Kerberoasting detection (`detect_kerberoasting`) - replaced three
broken regex patterns (`encryption.*type.*(0x17|rc4)`,
`ticket.*encryption.*(0x17|rc4)`, `servicename.*(mssql|http|ldap|cifs)`)
with a single `TicketEncryptionType..u003e0x17` field-anchored filter;
live data showed the old patterns matched 690/870 events with only 28
real RC4 tickets (662 false positives/day)
- AS-REP roasting detection (`detect_asrep_roasting`) - replaced four
over-broad OR'd patterns with `PreAuthType..u003e0.u003c`, anchoring the
closing XML tag to prevent `preauthtype.*0` from matching PreAuthType
values of 2/15/16/17 via trailing zeroes elsewhere on the line; live
data showed 411/590 events fired where only 12 were genuine no-pre-auth
TGTs
- Golden ticket detection (`detect_golden_ticket`) - updated stage 1
from bare `['0x17', 'rc4']` to `['TicketEncryptionType..u003e0x17']`,
preventing `rc4` from matching capability-enumeration fields
(ServiceSupportedEncryptionTypes, ClientAdvertizedEncryptionTypes)
present on ~90% of all 4769 events; stage 2 DC service class filter
retained with expanded comment explaining why it currently zeroes recall
and why it cannot be dropped without conflating golden ticket with
kerberoasting
- `build_pattern_filter` logic - removed the 2-3 literal fast-path that
chained `|= "a" |= "b"` (which ANDs terms, requiring all to appear on
one line); multi-literal stages now always compile to `|~ "(?i)(a|b)"`
so patterns within a stage are correctly disjunctive; single literals
retain the fast `|=` contains path
- Pattern filter test (`pattern_filter_uses_contains_for_few_literals`)
- renamed to `pattern_filter_ors_multiple_literals` and updated
assertion from chained `|=` to regex alternation to match corrected
behavior
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| returntocorp/semgrep | container | digest | `2b33f46` → `98c2572` |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [docker/login-action](https://redirect.github.com/docker/login-action)
([changelog](https://redirect.github.com/docker/login-action/compare/af1e73f918a031802d376d3c8bbc3fe56130a9b0..abd2ef45e78c5afb21d64d4ca52ee8550d9572c7))
| action | digest | `af1e73f` → `abd2ef4` |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[taiki-e/install-action](https://redirect.github.com/taiki-e/install-action)
([changelog](https://redirect.github.com/taiki-e/install-action/compare/a6b2e2dcd845ddd7f509ce4f3ed3d922b80cc5d9..3d7d7cd5ac7f994c1892ae0c06165095b9139094))
| action | digest | `a6b2e2d` → `3d7d7cd` |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
| datasource  | package              | from    | to      |
| ----------- | -------------------- | ------- | ------- |
| github-tags | github/codeql-action | v4.37.2 | v4.37.3 |
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| grafana/loki | patch | `3.7.3` → `3.7.4` |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [grafana/mimir](https://redirect.github.com/grafana/mimir)
([source](https://redirect.github.com/grafana/mimir/tree/HEAD/cmd/mimir))
| patch | `3.1.3` → `3.1.4` |

---

### Release Notes

<details>
<summary>grafana/mimir (grafana/mimir)</summary>

###
[`v3.1.4`](https://redirect.github.com/grafana/mimir/blob/HEAD/CHANGELOG.md#314)

##### Grafana Mimir

- \[BUGFIX] Packaging: Fix the DEB/RPM packages shipping the `mimir`,
`mimirtool`, `metaconvert`, and `query-tee` binaries without the
executable bit set, which caused `mimir.service` to fail to start.
[#&#8203;16166](https://redirect.github.com/grafana/mimir/issues/16166)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [tera](https://redirect.github.com/Keats/tera) |
workspace.dependencies | minor | `2.0.0` → `2.1.0` |

---

### Release Notes

<details>
<summary>Keats/tera (tera)</summary>

###
[`v2.1.0`](https://redirect.github.com/Keats/tera/blob/HEAD/CHANGELOG.md#210-2026-06-23)

[Compare
Source](https://redirect.github.com/Keats/tera/compare/v2.0.0...v2.1.0)

- Add .iter() method to Kwargs
- Add `Tera::contains_component` and `Tera::get_component_names`

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
l50 and others added 23 commits August 8, 2026 19:13
#472)

**Key Changes:**

- Extracted the duplicated `domain_to_base_dn` helper into a new shared
`ares-core::ldap` module, eliminating four separate copies across the
codebase
- Hardened the shared helper to drop empty domain labels, producing
well-formed DNs from malformed input rather than DNs containing empty
`DC=` components
- Removed a reserved-but-unused `hours_back` argument from the Grafana
alert-rules tool, aligning the schema with the provisioning endpoint's
argument-free contract

**Added:**

- Shared LDAP helper module - Created `ares-core/src/ldap.rs` with a
`domain_to_base_dn` function and a comprehensive test suite covering
nested domains, single labels, empty input, and malformed domains with
empty labels; registered the module in `ares-core/src/lib.rs`

**Changed:**

- DACL abuse automation - Updated `gpo_container_dn` in `dacl_abuse.rs`
to use the shared helper instead of its private `domain_base_dn` copy
- Credential access and recon tools - Replaced inline domain-splitting
logic in `credential_access/misc.rs` and `recon.rs` with calls to the
shared helper
- Grafana alert-rule executor - Reworked `get_alert_history` in
`grafana/rules.rs` to take no arguments, with documentation clarifying
that the provisioning endpoint returns time-independent rule definitions
- Credential access tests - Rewrote base DN tests in
`credential_access/misc.rs` to assert on the actual `-b` flag emitted by
the built command via a new `flag_value` helper, rather than
re-implementing the DN computation in the test

**Removed:**

- Duplicated helper implementations - Deleted the private
`domain_to_base_dn`/`domain_base_dn` functions and their associated
tests from `acl.rs`, `recon.rs`, `credential_access/misc.rs`,
`credential_access/mod.rs`, and `dacl_abuse.rs`
- Unused Grafana argument - Removed the `hours_back` property from the
`grafana_tool_definitions` input schema and the corresponding
`optional_i64` read in the executor
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
|
[community.docker](https://redirect.github.com/ansible-collections/community.docker)
| galaxy-collection | patch | `5.2.1` → `5.2.2` |

---

### Release Notes

<details>
<summary>ansible-collections/community.docker
(community.docker)</summary>

###
[`v5.2.2`](https://redirect.github.com/ansible-collections/community.docker/releases/tag/5.2.2)

[Compare
Source](https://redirect.github.com/ansible-collections/community.docker/compare/5.2.1...5.2.2)

See
<https://github.com/ansible-collections/community.docker/blob/main/CHANGELOG.md>
for all changes.

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNC4xMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0LjEyIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [grafana/grafana](https://redirect.github.com/grafana/grafana) | patch
| `13.1.2` → `13.1.3` |

---

### Release Notes

<details>
<summary>grafana/grafana (grafana/grafana)</summary>

###
[`v13.1.3`](https://redirect.github.com/grafana/grafana/releases/tag/v13.1.3):
13.1.3

[Download page](https://grafana.com/grafana/download/13.1.3)
[What's new
highlights](https://grafana.com/docs/grafana/latest/whatsnew/)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNC4xMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0LjEyIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| grafana/loki | patch | `3.7.4` → `3.7.6` |

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNC4xMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0LjEyIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [async-trait](https://redirect.github.com/dtolnay/async-trait) |
dev-dependencies | patch | `0.1.91` → `0.1.92` |
| [async-trait](https://redirect.github.com/dtolnay/async-trait) |
dependencies | patch | `0.1.91` → `0.1.92` |

---

### Release Notes

<details>
<summary>dtolnay/async-trait (async-trait)</summary>

###
[`v0.1.92`](https://redirect.github.com/dtolnay/async-trait/releases/tag/0.1.92)

[Compare
Source](https://redirect.github.com/dtolnay/async-trait/compare/0.1.91...0.1.92)

- Resolve double\_must\_use clippy lint in generated code
([#&#8203;303](https://redirect.github.com/dtolnay/async-trait/issues/303))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNC4xMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0LjEyIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [thiserror](https://redirect.github.com/dtolnay/thiserror) |
workspace.dependencies | patch | `2.0.19` → `2.0.20` |

---

### Release Notes

<details>
<summary>dtolnay/thiserror (thiserror)</summary>

###
[`v2.0.20`](https://redirect.github.com/dtolnay/thiserror/releases/tag/2.0.20)

[Compare
Source](https://redirect.github.com/dtolnay/thiserror/compare/2.0.19...2.0.20)

- Suppress redundant\_field\_names clippy lint in generated code
([#&#8203;454](https://redirect.github.com/dtolnay/thiserror/issues/454))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend Renovate
CLI](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNC4xMiIsInVwZGF0ZWRJblZlciI6IjQ0LjE0LjEyIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->

Co-authored-by: ares-renovate[bot] <286782180+ares-renovate[bot]@users.noreply.github.com>
**Key Changes:**

- Stripped hundreds of obvious, self-explanatory inline comments
throughout the ares-cli, ares-core, ares-llm, and ares-tools crates to
reduce noise and improve readability
- Rephrased a few remaining comments to be more concise and meaningful
rather than restating the code
- No functional or behavioral changes — this is a pure cleanup pass

**Changed:**

- Removed redundant "step-describing" comments across orchestrator
automation modules, state persistence, result processing, and dispatcher
logic that merely narrated what the following line already made clear
- Cleaned up section-label comments in report generators (blue team, red
team, detection playbooks, correlation reports) that duplicated the
associated `println!`/`push_str` section headers
- Trimmed obvious comments from parsers (nmap, secretsdump, shares,
trust, ntsd, credential tools) and blue team investigation read/write
helpers where the code was already descriptive
- Condensed retained comments for clarity — e.g., reworded the
exploitation "permanently marked exploited" note to "Set by result
processing on success" and simplified the MOTD banner-frame comment in
`ares-tools/src/filter.rs`
- Removed narrative comments from the LLM agent loop, providers
(anthropic, openai), routing, and tool registry, and folded the
"persists to Redis" note directly onto the relevant token-usage callback
…sing (#482)

**Key Changes:**

- Routed MSSQL NTLM coercion tasks to the `privesc` role since only that
role registers the `mssql_ntlm_coerce` tool
- Made the coercion prompt handle singular `technique` keys and
`relay_target` fallbacks so more task payloads render correctly
- Hardened `mssql_ntlm_coerce` output parsing to only claim a coercion
attempt when `xp_dirtree` actually executed, eliminating false positives
from listener-side captures and connection failures

**Added:**

- `impacket-mssqlclient` to the expected worker tool set so MSSQL
coercion has its required binary - `ares-cli/src/worker/tool_check.rs`
- `xp_dirtree_executed` helper that detects real execution by checking
for the `subdirectory` result marker while rejecting known failure
markers (login failed, permission denied, connection refused, TDS
connect, timeout) - `ares-tools/src/parsers/mod.rs`
- Extensive test coverage for coercion routing, prompt rendering
variants (singular vs plural techniques, relay-target fallback, unknown
targets), and parser behavior across empty output, refused logins,
denied procedures, TDS failures, and listener-side vs result-set
captures

**Changed:**

- MSSQL coercion dispatch now targets a named
`MSSQL_COERCION_TARGET_ROLE` (`privesc`) constant instead of the
hardcoded `"coercion"` role -
`ares-cli/src/orchestrator/automation/mssql_coercion.rs`
- Coercion prompt generation now resolves the target via
`coercion_target` (with `relay_target` fallback) and techniques via
`coercion_techniques` (accepting a singular `technique` key when the
plural array is absent), with plural taking precedence -
`ares-llm/src/prompt/coercion.rs`
- `mssql_ntlm_coerce` parsing now emits the `coercion_attempted`
vulnerability marker only when `xp_dirtree_executed` confirms execution,
gating it behind real result-set evidence -
`ares-tools/src/parsers/mod.rs`

**Removed:**

- Listener-side NetNTLMv2 hash extraction from the `mssql_ntlm_coerce`
arm, since raw hash captures are handled by listener-side parsers rather
than the coercion tool's output - `ares-tools/src/parsers/mod.rs`
**Key Changes:**

- Added underscore-formatted IP detection to the GOAD token sweep script
to catch lab IPs that use underscores instead of dots
- Updated a display test to use a valid lab IP pattern matching the
underscore convention

**Added:**

- Underscore IP pattern matching - Introduced an `ips_underscore`
pattern and appended it to the `banned` regex in
`scripts/goad-token-sweep.sh` so IPs like `10_1_2_51` are detected
alongside their dotted equivalents

**Changed:**

- Token category test assertion - Updated the `token_category` test in
`ares-cli/src/ops/loot/format/display.rs` to assert on
`mssql_192_168_58_51` instead of `mssql_10_1_2_51`, aligning the test
fixture with the underscore IP format
…ckends (#484)

**Key Changes:**

- Added `task ec2:e2e`, a gated end-to-end runner that deploys, verifies
binary provenance, runs a full red(+blue) operation, and fetches both
reports
- Unified all `blue:*` tasks behind a single `BLUE_TRANSPORT` selector
(`ec2`, `k8s`, or `local`) and consolidated the alert-submission tasks
into one `blue:submit`
- Removed the K8s pod file-sync tasks (`remote:sync`,
`remote:sync:full`) and red-team replay recording tasks in favor of
binary-deploy workflows
- Reworked the Rust cross-compile path to prefer `cargo-zigbuild` on all
hosts, avoiding rustc crashes under qemu emulation on Apple Silicon

**Added:**

- End-to-end operation runner - Introduced `task ec2:e2e` and its
backing `.taskfiles/ec2/scripts/e2e-op.sh`, which sanity-checks the
repo, gates against stale source and non-matching binary SHAs, refuses
prod hosts, restarts workers to drop the poisoned tool cache, launches a
fresh op, scans for the tool-pruning-cascade regression, and fetches
red/blue reports
- Log filtering on EC2 - Added a `FILTER` var to `ec2:logs` with `grep
--line-buffered` so blue lines can be isolated from the interleaved
orchestrator log without buffering delays
- Proxmox taskfile include - Wired `.taskfiles/proxmox/Taskfile.yaml`
into the root `Taskfile.yaml`
- Documentation for the new workflows - Expanded `README.md`,
`docs/blue.md`, and `docs/benchmark-replay.md` to cover `ec2:e2e`,
`blue:submit`, transport-aware logs, and the corrected `CAPTURE`/build
guidance

**Changed:**

- Blue transport model - Replaced the ec2/k8s if-branch in
`.taskfiles/blue/Taskfile.yaml` with a `case` supporting a new `local`
transport, and made `blue:submit`, `blue:playbook`, and
`blue:multi:logs` transport-aware; the playbook now streams JSON over
the transport instead of relying on a `kubectl cp` that silently copied
nothing
- Secure alert submission - `blue:submit` now passes the alert by value
and drops `--grafana-api-key`, falling back to the remote's own
`GRAFANA_SERVICE_ACCOUNT_TOKEN` to avoid leaking it into SSM history and
CloudTrail
- Rust cross-compile ordering - Reordered `remote:rust:build` in
`.taskfiles/remote/Taskfile.yaml` to try `cargo-zigbuild` first and warn
when falling back to `cross` on arm64 macOS
- Grafana token field lookup - Updated the
`GRAFANA_SERVICE_ACCOUNT_TOKEN` 1Password field from `api-token` to
`grafana-token`
- Pre-commit task reference - Repointed the CI workflow and root
taskfile to the namespaced `pre-commit:*` tasks
(`pre-commit:run-pre-commit`, `pre-commit:install-pc-hooks`)
- MAX_STEPS is now overridable - `blue:submit` and `blue:multi:remote`
accept a `MAX_STEPS` override instead of a hardcoded value
- README key-tasks table - Refreshed the blue task table and added a
note that every `blue:*` task reads `BLUE_TRANSPORT`

**Removed:**

- K8s file-sync tasks - Deleted `remote:sync` and `remote:sync:full` and
their supporting vars (`PARALLELISM`, `PVC_PATH`, `VERIFY_PVC_DIFF`)
from `.taskfiles/remote/Taskfile.yaml`, shifting to binary deploys
- Red-team replay recording tasks - Removed `red:multi:replay:copy`,
`:cat`, `:list`, and `:clear` from `.taskfiles/red/Taskfile.yaml`
- Redundant blue tasks - Dropped `blue:once:remote`, `blue:investigate`,
and `blue:multi` in favor of the unified `blue:submit`
- Obsolete root taskfile targets - Removed `get-dotenv-value`,
`run-pre-commit`, `rust:clean`, `ares:config:show`, and `check-aws-auth`
from `Taskfile.yaml`
…tput (#485)

**Key Changes:**

- Added an early return in `parse_tool_output` to short-circuit when
tool output is empty, preventing parser arms from fabricating evidence
purely from input parameters
- Introduced a regression test that verifies no parser arm mints
evidence keys from params alone across all 78 supported tools
- Added a guard test to keep the evidence key list synchronized with the
orchestrator's `result_has_parser_evidence` gate

**Added:**

- Empty-output guard in `parse_tool_output` - Returns an empty
discoveries object immediately when the trimmed output is empty, closing
a path where the orchestrator could accept params-derived markers as
proof an exploit succeeded (`ares-tools/src/parsers/mod.rs`)
- Comprehensive false-evidence regression test - Added
`no_parser_arm_mints_evidence_from_params_alone`, which iterates every
entry in the new `PARSED_TOOLS` list with a fully populated params
object and empty output, asserting no `EVIDENCE_KEYS` array is
populated; offenders are reported with context explaining the security
impact (`ares-tools/src/parsers/mod.rs`)
- Orchestrator gate consistency test - Added
`evidence_key_list_matches_the_orchestrator_gate` to assert the
`EVIDENCE_KEYS` count stays aligned with `result_has_parser_evidence` in
`ares-cli/src/orchestrator/result_processing/mod.rs`, prompting both to
be updated together (`ares-tools/src/parsers/mod.rs`)
- Test fixtures and constants - Added the `EVIDENCE_KEYS` and
`PARSED_TOOLS` slices plus the `fully_populated_params` helper to
support the new tests (`ares-tools/src/parsers/mod.rs`)
…sk consolidation (#486)

**Key Changes:**

- Consolidated blue-team tasks: replaced `blue:investigate`/`blue:multi`
with `blue:submit`, absorbed `blue:once:remote` into
`blue:multi:remote`, and made `blue:multi:logs`/`blue:playbook`
transport-aware
- Removed the dead `red:multi:replay:*` task surface and its
documentation, and the Python-era `remote:sync`/`remote:sync:full` tasks

**Changed:**

- Blue task surface documentation in `blue-team.md` reflects
`blue:submit` now honoring `{{.TRANSPORT_ARGS}}` (agreeing with read
tasks), `blue:multi:logs` becoming transport-aware (tailing
`/var/log/ares/orchestrator.log` on EC2), `blue:playbook` rewritten to
stream JSON over stdout, and `BLUE_TRANSPORT` accepting `local`
- Replay documentation in `benchmarks-and-replay.md` rewritten to record
that the four k8s-only `red:multi:replay:*` tasks were removed since
nothing ever wrote `/ares/replay/recording.jsonl`
- Config and CI references updated: `ares:config:show` folded into
`ares:config:check` (`config-and-env.md`), CI repointed from the
duplicate root `run-pre-commit` to `pre-commit:run-pre-commit`, and
`task init` fixed to call `pre-commit:install-pc-hooks`
(`tools-and-gates.md`)
- Detection playbook output path moved to
`blue/<op_id>_detection_playbook.json` and the `e2e-op.sh` knobs list
expanded with `ALLOW_STALE`, `BLUE_SETTLE_WAIT`/`BLUE_STALL_WAIT`, and
stricter `BLUE=0`/`SKIP_RESTART` handling
- Gemini operator agent examples updated to use `blue:multi:remote` and
the new `blue:submit ALERT=...` task (`.gemini/agents/ares-operator.md`)

**Removed:**

- The `red:multi:replay:*` task family (`copy`, `cat`, `list`, `clear`)
and its destructive-task warning, plus the `recordings/` output
directory notes describing the always-empty dead surface
- The Python-era `remote:sync` and `remote:sync:full` tasks that
operated on the long-gone `src/ares/**` tree, with guidance now pointing
at `task -y remote:rust:build && task -y remote:rust:deploy TEAM=blue`
- Stale `BUILD_TOOL` defaults-to-`auto` claims and the duplicate
root-level `run-pre-commit` CI task
#488)

**Key Changes:**

- Replaced hardcoded S3 buckets, regions, and account IDs with
runtime-injected placeholders and generic references across build
scripts and docs
- Renamed the ambiguous "phase2" golden AMI build stage to the
descriptive "tools-install" oneshot service throughout
- Made RDS endpoint configuration explicit and env-driven rather than
defaulting to a hardcoded RDS host

**Changed:**

- Golden AMI userdata parameterization - Replaced hardcoded `BUCKET` and
`us-east-1` region values in `scripts/ares-golden-userdata.sh` with
`__BUCKET__` and `__AWS_REGION__` placeholders that are rendered at
build time, so the script is no longer tied to a specific account or
region
- Build-time placeholder rendering - Updated
`scripts/build-ares-golden-ami.sh` to `sed`-substitute the placeholders
into a temp userdata file (with a cleanup trap and a guard that fails if
any placeholder is left unrendered), and pass that rendered file to
`run-instances`
- Phase renaming - Renamed the post-reboot
`ares-phase2.service`/`ares-phase2.sh` to
`ares-golden-tools-install.service`/`ares-golden-tools-install.sh`, and
the `PHASE2_DONE` S3 completion marker to `TOOLS_INSTALL_DONE`, updating
all references, log messages, and comments for clarity in both scripts
- RDS endpoint handling - Changed `.taskfiles/ec2/Taskfile.yaml` so
`RDS_ENDPOINT` now defaults from the `ARES_RDS_ENDPOINT` env var (or
empty) instead of a hardcoded RDS host, and gated the Secrets Manager
password lookup on `RDS_ENDPOINT` being supplied
- Documentation genericization - Replaced the literal AWS account ID
`381491903301` with `<account-id>` in the staging bucket examples in
`docs/benchmark-replay.md` and
`warpgate-templates/templates/ares-replay-stack/README.md`
**Key Changes:**

- Extracted the inline attacker IP resolution logic from the Proxmox
Taskfile into a dedicated, reusable shell script
- Replaced the `sh:`-computed `ATTACKER_IP` variable with an
`ATTACKER_IP_CMD` invocation, deferring IP resolution to runtime in each
task
- Updated all tasks to resolve the attacker IP on demand via command
substitution rather than relying on a pre-computed value

**Added:**

- Standalone attacker IP resolution script - Created
`.taskfiles/proxmox/scripts/attacker-ip.sh`, which queries the Proxmox
guest agent for network interfaces and parses out the first non-loopback
IPv4 address via Python, accepting `PROXMOX_SSH_HOST` and
`ATTACKER_VMID` as positional arguments with environment-variable
fallbacks

**Changed:**

- IP resolution strategy in `.taskfiles/proxmox/Taskfile.yaml` -
Replaced the eagerly evaluated `ATTACKER_IP` variable (which ran the
guest-agent query at parse time) with an `ATTACKER_IP_CMD` pointer to
the new script, so the IP is resolved lazily per task via
`IP="$({{.ATTACKER_IP_CMD}})"`; this avoids running the query on every
task invocation and keeps the complex parsing logic out of the YAML

**Removed:**

- Inline IP resolution logic - Removed the embedded multi-line Python
guest-agent parsing block from the `ATTACKER_IP` var definition in
`.taskfiles/proxmox/Taskfile.yaml`, now superseded by the external
script
**Key Changes:**

- Removed all compiled-in S3 bucket, region, and profile defaults from
the benchmark tooling, since these values are account-specific and
previously leaked lab/dev account names into the binary
- Introduced a new `benchmark:` configuration section and shared
resolution helpers so settings can come from `BENCHMARK_*` / `LOKI_S3_*`
env vars or `ares.yaml`, failing loudly when required values are missing
- Made bucket and region required inputs with clear error messages
naming both the env var and config key, rather than silently falling
back to a hardcoded account

**Added:**

- New `BenchmarkConfig` section - Added an optional `benchmark:` config
struct (`s3_bucket`, `aws_profile`, `aws_region`, `loki_s3_bucket`,
`loki_s3_region`, `loki_s3_profile`) in
`ares-core/src/config/sections.rs`, wired into `AresConfig` in
`config/mod.rs`
- Shared resolution helpers - Added `benchmark_section`, `resolve`, and
`require` in `snapshot_s3.rs`; `resolve` treats empty as unset
(defaulting to the credential chain) while `require` errors when a value
with no sane fallback is missing
- New env vars and validation - Added `LOKI_S3_BUCKET`,
`LOKI_S3_REGION`, `LOKI_S3_PROFILE` and a `BENCHMARK_S3_BUCKET`
precondition check in `.taskfiles/benchmark/Taskfile.yaml`

**Changed:**

- Config resolution across benchmark commands - Updated
`LokiS3::from_env`, `SnapshotConfig::from_env`, and their callers in
`capture.rs`, `mod.rs`, and `replay.rs` to return `Result` and pull
values from env or config instead of hardcoded constants
- Documentation and examples - Updated `.env.example`,
`docs/benchmark-replay.md`, and `README.md` to mark
`BENCHMARK_S3_BUCKET`, `BENCHMARK_AWS_REGION`, `LOKI_S3_BUCKET`, and
`LOKI_S3_REGION` as required with no defaults, and annotated the omitted
`benchmark:` section in `config/ares.yaml`
- Taskfile default bucket - Changed the `S3_BUCKET` var in
`.taskfiles/benchmark/Taskfile.yaml` to have no default, requiring it
via `.env`
- Golden userdata ordering - Reordered `scripts/ares-golden-userdata.sh`
to disable the tools-install service before writing the completion
marker to S3

**Removed:**

- Hardcoded S3 constants - Removed
`DEFAULT_LOKI_S3_BUCKET/REGION/PROFILE` and
`DEFAULT_BENCHMARK_BUCKET/PROFILE/REGION` from `capture.rs`, plus
`DEFAULT_S3_BUCKET`, `DEFAULT_AWS_REGION`, and `DEFAULT_AWS_PROFILE`
from `snapshot_s3.rs`, eliminating account-specific values baked into
the binary
**Key Changes:**

- Introduced a shared `CrackInflight` guard on `Dispatcher` so the
automation tick and the LLM `dispatch_crack` tool can no longer
independently re-queue the same hash, which previously wedged both
hashcat GPU slots for ~50 minutes across five redundant runs
- Replaced the per-loop local dedup `HashMap` and atomic counter in
`auto_crack_dispatch` with atomic capacity-checked reservations that a
second racing producer cannot bypass
- Added LLM-facing refusal/deferral responses in the `dispatch_crack`
tool for hashes that are already in flight, at capacity, or have
exhausted their crack attempts
- Wired crack-slot release into the task-completion and stale-task
reaping paths so a dying dispatch self-heals via a TTL backstop instead
of blocking a hash permanently

**Added:**

- Shared crack-scheduling guard - New `CrackInflight` type in
`dispatcher/mod.rs` with per-dispatch grouped reservations, a derived
active-count, `CRACK_INFLIGHT_TTL` backstop (45m), and
`DEFAULT_MAX_ACTIVE_CRACK_TASKS` cap configurable via
`ARES_MAX_ACTIVE_CRACK_TASKS`; exposes `try_reserve`, `release`,
`is_inflight`, `at_capacity`, `active`, `live_keys`, and `expire_stale`
- LLM crack-tool guardrails - In `callback_handler/dispatch.rs`, added
early `CallbackResult::Continue` responses that refuse hashes exceeding
`MAX_CRACK_ATTEMPTS` or already given up, defer when all slots are busy,
and reject re-dispatch of in-flight hashes, reserving the slot on
successful dispatch
- Reservation test coverage - Added async tests in `dispatcher/mod.rs`
covering cross-producer blocking, cap enforcement, partial-batch
reservation, idempotent release, and the TTL-vs-stall-ceiling invariant

**Changed:**

- Crack dispatch flow - `auto_crack_dispatch` now reserves candidate
keys atomically before batching, releases the slot on both stall-timeout
and completion, and derives active/inflight state from the shared guard
rather than local structures
- Task cleanup and completion paths - `release_reaped_task` and
`cleanup_stale_tasks` in `monitoring.rs` and `process_completed_task` in
`result_processing/mod.rs` now release the crack reservation for reaped
or completed tasks
- Heartbeat monitor signature - `spawn_heartbeat_monitor` and its call
sites in `orchestrator/mod.rs` now take the full `Arc<Dispatcher>`
instead of just `credential_inflight`, giving the monitor access to
`crack_inflight`
- Module exports - `automation/mod.rs` now re-exports
`MAX_CRACK_ATTEMPTS` for use by the LLM crack tool

**Removed:**

- Local inflight tracking in `auto_crack_dispatch` - Removed the
`InflightCrackSlot` drop-guard, the `inflight_crack_dedup` `HashMap`,
the `AtomicUsize` task counter, the `max_active_crack_tasks` env helper,
and the now-obsolete drop-on-panic slot-release test, all superseded by
the shared `CrackInflight` guard
**Key Changes:**

- Prevent the planner from re-dispatching WinRM lateral movement against
targets whose backing vulnerability has hit the max exploit-failure
abandonment cap
- Added per-target resolution of the WinRM `winrm_access` vulnerability
that backs a lateral technique
- Added comprehensive unit tests covering positive, negative, and
cross-host cases

**Added:**

- WinRM backing vuln resolution - Introduced `lateral_backing_vuln_id`
in `task_builders.rs` to locate the `winrm_access` vulnerability
matching a given target IP, returning `None` for non-WinRM techniques so
unrelated techniques are never gated
- Abandonment guard in the dispatcher - Added a check that skips lateral
dispatch (returning `Ok(None)` with a debug log) when the backing vuln
has been abandoned at max exploit failures, stopping the planner from
repeatedly targeting a dead WinRM host
- Test coverage - Added three tests in `task_builders.rs` verifying the
backing vuln resolves for a matching WinRM target, is absent for
non-WinRM techniques like psexec, and is scoped per target so one dead
host does not suppress others
…ue hole (#492)

**Key Changes:**

- Moved crack dedup key reservation from the callback dispatch path to
the submission layer, ensuring every crack task id — including deferred
re-submits from the drain — is tracked
- Added a non-refusing `reserve` method to `CrackInflight` so a real
hashcat run can never be left untracked, closing the hole that allowed
the same hash to be queued twice
- Introduced `crack_dedup_key_from_payload` to derive dedup keys
directly from the submitted payload rather than the originating `Hash`

**Added:**

- Payload-based dedup key derivation - Added
`crack_dedup_key_from_payload` and a shared `crack_dedup_key_parts`
helper in `automation/mod.rs`, letting the submission layer compute keys
from a payload without access to the source `Hash`
- Unconditional reservation recording - Added `CrackInflight::reserve`
in `dispatcher/mod.rs`, which always records a reservation (unlike
`try_reserve`), allowing `active` to briefly exceed `max_active` to
reflect true state instead of a capped guess
- Submission-layer reservation - Wired the new reservation into
`submission.rs` so every crack task id is reserved as it is submitted
- Test coverage - Added tests verifying payload-derived keys match those
built from the original `Hash` and that non-crack payloads yield `None`

**Changed:**

- Dedup key computation - Refactored `crack_dedup_key` to delegate to
`crack_dedup_key_parts`, and switched prefix slicing to be char-based
(`chars().take(32)`) to avoid byte-boundary issues

**Removed:**

- Callback-path reservation - Removed the `try_reserve` call from
`dispatch.rs`, since reservation now happens centrally at the submission
layer where every task id is observed
**Key Changes:**

- Introduced a `reasoning_effort` setting that threads from YAML/env
config through the agent loop into OpenAI reasoning-model requests
- Enforced strict precedence (env override > YAML > provider default)
with validation that silently ignores unrecognised values to avoid 400
errors on every call
- Restricted forwarding of `reasoning_effort` to gpt-5 family models
only, since non-reasoning models reject the parameter outright

**Added:**

- Reasoning effort configuration field - Added `reasoning_effort:
Option<String>` to `AgentConfig` in `ares-core/src/config/sections.rs`
and defaulted it to `None` in config construction paths
(`ares-core/src/config/mod.rs`)
- Config layering and validation - Added `with_config_reasoning_effort`
builder plus a `normalize_reasoning_effort` helper in
`ares-llm/src/agent_loop/config.rs` that trims, lowercases, and accepts
only `minimal`/`low`/`medium`/`high`, honouring the
`ARES_AGENT_REASONING_EFFORT` env override; unrecognised values are
dropped with a warning
- Request plumbing - Added `reasoning_effort` to `AgentLoopConfig` and
`LlmRequest` (`ares-llm/src/provider/mod.rs`), wired it through
`run_agent_loop_inner` in `ares-llm/src/agent_loop/runner.rs`
- OpenAI provider gating - Added `supports_reasoning_effort` and a
`reasoning_effort` field on `ApiRequest` in
`ares-llm/src/provider/openai.rs`, forwarding the value only to gpt-5
family models and omitting it from the wire when unset
- Per-role defaults - Set `reasoning_effort: low` for the recon,
credential_access, cracker, lateral_movement, and coercion agents in
`config/ares.yaml`
- Test coverage - Added precedence and casing tests for config layering
and provider tests verifying gating and wire omission

**Changed:**

- Per-role model logging - Extended the orchestrator's per-role model
log line in `ares-cli/src/orchestrator/mod.rs` to include the effective
reasoning effort (falling back to `provider-default`)
…494)

**Key Changes:**

- Fixed crack tasks collapsing onto a single queue signature because
their payloads carry no technique, target_ip, credential, or finding
fields, causing distinct hashes to be silently dropped while `enqueue`
reported them as successfully queued
- Routed crack task identity through the same
`crack_dedup_key_from_payload` used by the in-flight reservation guard,
keeping queue-identity and run-identity aligned
- Added comprehensive test coverage verifying signature behavior across
distinct, duplicate, and non-crack task types

**Added:**

- Test suite for crack task signatures - Added `make_crack_task` helper
and four tests in `ares-cli/src/orchestrator/deferred.rs` covering
distinct-hash differentiation, genuine-duplicate collapsing (including
case-insensitivity), reservation-key alignment, and confirmation that
hash identity only affects crack tasks while other task types keep their
existing signature behavior

**Changed:**

- Signature derivation for crack tasks - Modified `finding_key` in
`ares-cli/src/orchestrator/deferred.rs` to derive the discriminating
component from `crack_dedup_key_from_payload` when the task type is
`crack`, prefixing the result with `crack|`, so two crack tasks that
share a signature are exactly the two that would contend for one
in-flight reservation
- Documentation on `signature` and `finding_key` - Expanded doc comments
to explain the crack-queue dedup gap (mirroring the prior ACL gap) and
the reasoning behind unifying queue and run identity
**Key Changes:**

- Removed `base_url` and `api_key` fields from Grafana configuration in
favor of `dashboard_uid`
- Ensured backward compatibility by gracefully ignoring legacy
credential keys during config loading
- Updated example configuration and documentation to reflect the
streamlined Grafana section

**Changed:**

- Grafana config struct simplified - Removed `base_url` and `api_key`
fields from `GrafanaConfig`, retaining only `enabled` and
`dashboard_uid` in `ares-core/src/config/sections.rs`
- Config loading resilience - Added
`grafana_ignores_legacy_credential_keys` test to verify that configs
containing the removed `base_url` and `api_key` keys still parse without
error, and updated existing tests to assert `dashboard_uid` parsing in
`ares-core/src/config/mod.rs`
- Example configuration cleanup - Removed the `base_url` and `api_key`
entries from the Grafana section in `config/ares.yaml`
- Documentation update - Removed the outdated Grafana credential
configuration snippet from the blue team observability docs in
`docs/blue.md`
…ion gating (#496)

**Key Changes:**

- Fixed deployment label resolution so empty values fall through to the
`ARES_DEPLOYMENT` env var instead of pinning LogQL queries to
`deployment=""`, which matched nothing
- Gated e2e operation consolidation on operation finalization
(`completed_at`) rather than counts alone, preventing the terminal
investigation from being dropped from the scorecard
- Routed blue orchestrator tools in-process via a new
`BlueToolDispatcher`

**Added:**

- Shared `resolve_deployment` helper in `investigation.rs` that treats
empty alert labels and env vars as absent, correctly falling back from
label to `ARES_DEPLOYMENT` — this fixes cases where an unset target
environment yielded `Some("")` and suppressed the env fallback
- Unit test `resolve_deployment_label_env_precedence` covering label/env
precedence and empty-value fallthrough, deliberately consolidated into
one test since parallel test execution races on process-global
`std::env`
- `BlueToolDispatcher` wiring in `run_investigation` to route
orchestrator tools in-process, with an info log capturing the
investigation ID and resolved deployment

**Changed:**

- Blue completion detection in `e2e-op.sh` now also reads `completed_at`
from Redis and treats an unset value as blue still outstanding, since
the terminal investigation is submitted minutes after `ops status` first
reports "completed"
- `BlueCallbackHandler::new` in `callbacks.rs` and `run_investigation`
now delegate to the shared `resolve_deployment` helper instead of
duplicating inline label/env extraction logic
…-main

# Conflicts:
#	.github/workflows/build-and-push-templates.yaml
#	.github/workflows/meta-sync-labels.yaml
#	.github/workflows/molecule.yaml
#	.github/workflows/pre-commit.yaml
#	.github/workflows/release.yaml
#	.github/workflows/renovate.yaml
#	.github/workflows/rust.yaml
#	.github/workflows/semgrep.yaml
#	.github/workflows/test-template-builds.yaml
#	.github/workflows/validate-templates.yaml
#	Cargo.lock
#	Cargo.toml
#	ansible/requirements.yml
#	ares-cli/src/history/cost.rs
#	ares-cli/src/history/list.rs
#	ares-cli/src/history/search.rs
#	ares-cli/src/orchestrator/automation/adcs_exploitation.rs
#	ares-cli/src/orchestrator/automation/mssql_exploitation.rs
#	ares-cli/src/orchestrator/blue/chaining.rs
#	ares-cli/src/orchestrator/deferred.rs
#	ares-cli/src/orchestrator/diversity.rs
#	ares-cli/src/orchestrator/mod.rs
#	ares-cli/src/orchestrator/result_processing/mod.rs
#	ares-cli/src/orchestrator/strategy.rs
#	ares-core/src/config/defaults.rs
#	ares-core/src/config/sections.rs
#	ares-core/src/persistent_store/queries/credentials.rs
#	ares-llm/src/prompt/templates.rs
#	ares-llm/src/tool_registry/privesc/adcs.rs
#	ares-llm/templates/redteam/agents/system_instructions.md.tera
#	ares-tools/Cargo.toml
#	ares-tools/src/parsers/certipy.rs
#	ares-tools/src/parsers/delegation.rs
#	ares-tools/src/parsers/mssql.rs
#	config/ares.yaml
#	docs/attack-path-diversity.md
@dreadnode-renovate-bot dreadnode-renovate-bot Bot added area/docs Changes made to project documentation area/pre-commit Changes made to pre-commit hooks area/templates Changes made to warpgate template configurations area/github Changes made to GitHub Actions workflows labels Aug 10, 2026
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 80.28%. Comparing base (dd71e14) to head (8eb1585).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #439      +/-   ##
==========================================
+ Coverage   79.97%   80.28%   +0.30%     
==========================================
  Files         434      460      +26     
  Lines      126175   161268   +35093     
==========================================
+ Hits       100913   129477   +28564     
- Misses      25262    31791    +6529     
Files with missing lines Coverage Δ
ares-cli/src/benchmark/capture.rs 0.00% <ø> (ø)
ares-cli/src/benchmark/manifest.rs 100.00% <ø> (ø)
ares-cli/src/benchmark/mod.rs 0.00% <ø> (ø)
ares-cli/src/benchmark/replay.rs 9.55% <ø> (ø)
ares-cli/src/benchmark/snapshot_s3.rs 0.00% <ø> (ø)
ares-cli/src/benchmark/tempo_push.rs 66.37% <ø> (ø)
ares-cli/src/blue/delete.rs 0.00% <ø> (ø)
ares-cli/src/blue/evidence.rs 0.00% <ø> (ø)
ares-cli/src/blue/mod.rs 0.00% <ø> (ø)
ares-cli/src/blue/operation.rs 0.00% <ø> (ø)
... and 27 more

... and 330 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@l50

l50 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Superseded — split into #440 (GitHub Actions workflows only) and #441 (everything else; workflows excluded). Closing in favour of those two.

@l50 l50 closed this Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs Changes made to project documentation area/github Changes made to GitHub Actions workflows area/pre-commit Changes made to pre-commit hooks area/templates Changes made to warpgate template configurations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant