Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
164 commits
Select commit Hold shift + click to select a range
a662e9f
fix(compressor): reject provider error/refusal strings as fake summaries
Kyzcreig May 12, 2026
9c6214b
fix: parse openai-codex slash model switches
May 14, 2026
9f9bf61
fix(model-switch): support inline provider syntax
May 14, 2026
30a8a06
fix(delegation): allow explicit code_execution + honor explicit toolsets
May 14, 2026
7d4f9eb
docs: align 1Password skill with fleet service token
May 23, 2026
59429f3
fix(gateway): clear typing indicator on stale-result early-return path
May 28, 2026
9c52daa
fix(auxiliary): treat aux <task>.model: auto as sentinel, not a liter…
Kyzcreig May 12, 2026
1a633f7
fix(auxiliary_client): _get_cached_client honors normalize_resolved_m…
Kyzcreig May 12, 2026
8f78238
fix(models): name provider + endpoint in anthropic_messages fallback …
May 29, 2026
78ce24d
fix(auxiliary_client): consult ProviderProfile.api_mode in resolver
May 29, 2026
d68a4b0
fix(model-switch): resolve provider-module plugin providers in switch…
Kyzcreig May 29, 2026
4ed79b6
fix(telegram): make network-reconnect ladder configurable, raise defa…
May 29, 2026
ba371ef
fix(discord): let free-response channels quote bot mentions
May 29, 2026
8a8b816
fix(recap): backtick-wrap Files touched paths to stop gateway auto-at…
Kyzcreig Jun 2, 2026
e57e66e
feat(usage): retain last provider-call token snapshot
Kyzcreig Jun 2, 2026
445720a
feat(usage): persist last-turn token snapshot, survive agent eviction…
Kyzcreig Jun 3, 2026
2723832
fix(redact): exempt GIT_AUTHOR_*/GIT_COMMITTER_* from ENV-assignment …
Kyzcreig Jun 3, 2026
dce6274
test(models): make anthropic-messages warning test hermetic (#4)
Kyzcreig Jun 3, 2026
91feccc
fix(write_file): add post-write read-back verification (#5)
Kyzcreig Jun 4, 2026
bb54af8
mem0: add MEM0_CAPTURE recall-only mode (skip per-turn auto-capture)
Kyzcreig Jun 4, 2026
9ffb7e3
Blackbox Turn Telemetry — per-turn cost/token/tool telemetry + /cost …
Kyzcreig Jun 4, 2026
8506d9a
Notional pricing for subscription proxies/bridges + Codex (#7)
Kyzcreig Jun 4, 2026
f96e71a
test(file-ops): fix write_file mocks for atomic temp-file+rename path…
Kyzcreig Jun 4, 2026
33b069b
Blackbox card fixes: chat fields, cache %, alerts toggle, 3d price ca…
Kyzcreig Jun 4, 2026
74ed8a8
feat(approval): env-gated reboot/shutdown downgrade (HERMES_ALLOW_REB…
Kyzcreig Jun 4, 2026
bd7e010
blackbox: subagent cost rollup in /cost session + per-turn retention …
Kyzcreig Jun 4, 2026
a061c17
feat(log): tag Turn-ended diag line with cron task id (task=) (#11)
Kyzcreig Jun 4, 2026
20e7fd2
fix(blackbox): background_review fork inherits parent chat context (#12)
Kyzcreig Jun 4, 2026
7188575
fix(codex): fire no-byte TTFB watchdog before the stale timer
Kyzcreig Jun 4, 2026
05d38f1
feat(cron): per-job api_max_retries override
Kyzcreig Jun 4, 2026
bb4e644
fix(cron): pin fallback chain to job's provider — codex job can't sil…
Kyzcreig Jun 5, 2026
d5b2992
feat(cron): hermes cron run <id> --wait — synchronous single-job exec…
Kyzcreig Jun 5, 2026
6ae6cbe
feat(cron): per-job fallback chain (same-provider resilience)
Kyzcreig Jun 5, 2026
a184062
fix(banner): include local HEAD in update-check cache key
Kyzcreig Jun 5, 2026
0159f3e
fix(desktop): drop manual Content-Length in OAuth net.request (ERR_IN…
Kyzcreig Jun 5, 2026
9a1db22
fix(patch): error instead of silent no-op success on header-less V4A …
Kyzcreig Jun 6, 2026
5dd5d90
test(gateway): de-flake telegram topic reset tip assertion (#14)
Kyzcreig Jun 6, 2026
a8ffdad
test(gateway): de-flake stream-consumer edit-failure tail test (#15)
Kyzcreig Jun 6, 2026
e400a97
cron: cleaner status-aware delivery framing (no double-wrap on failur…
Kyzcreig Jun 7, 2026
9137c67
fix(compress): show real measured context alongside estimate; estimat…
Kyzcreig Jun 8, 2026
e7653ef
fix(compress): two-line readout — Chat size + Full request size (#18)
Kyzcreig Jun 8, 2026
dc8fa1d
fix(gateway): bind originating channel into session context for plugi…
Kyzcreig Jun 8, 2026
6968677
feat(telemetry): decompose context window (last-call cache split) + b…
Kyzcreig Jun 8, 2026
b4ee4fe
feat(telemetry): real per-request composition snapshot for /context /…
Kyzcreig Jun 8, 2026
f6c38eb
chore(attribution): map apollo@daemonarchy.local → Kyzcreig in AUTHOR…
Kyzcreig Jun 8, 2026
0fb0f79
feat(config): per-entry reasoning_effort in fallback_model chain (#21…
Kyzcreig Jun 8, 2026
9d562fd
feat(telemetry): tunable chars-per-token divisor for composition esti…
Kyzcreig Jun 9, 2026
54fec9b
feat(compression): config-driven per-model threshold (#25)
Kyzcreig Jun 9, 2026
ee81044
feat(telemetry): unify ALL rough token estimators on the 3.5 divisor …
Kyzcreig Jun 9, 2026
886877c
feat(telemetry): route 413/stale-call estimator through shared 3.5 di…
Kyzcreig Jun 9, 2026
73c7baf
style(cron): use 🪪 job_id: prefix instead of parenthesized (job_id: ……
Kyzcreig Jun 9, 2026
cb30b79
fix(codex): add progress-stall watchdog for keepalive-only Codex hang…
Kyzcreig Jun 9, 2026
72a34d4
feat(telemetry): split system prompt into identity+skills, add per-me…
Kyzcreig Jun 10, 2026
6f5ad9e
feat(telemetry): show message count on conversation-history line (#30)
Kyzcreig Jun 10, 2026
a0eec7d
fix: honor provider retry-after during fallback cooldown
Kyzcreig Jun 8, 2026
ae486b7
mem0 destructive-tools: Phase-0 SDK kill-gate spike (PASS)
Kyzcreig Jun 10, 2026
b9e0014
mem0: add gated destructive tools (mem0_forget + mem0_delete)
Kyzcreig Jun 10, 2026
c8ffda4
fix(telemetry): recompute skills-index split on gateway restore path …
Kyzcreig Jun 11, 2026
59080fe
feat(telemetry): show skill count on /context Skill index line (#32)
Kyzcreig Jun 11, 2026
36134d8
fix(model): route bare gpt-5.5 to Codex OAuth
Kyzcreig Jun 11, 2026
34dcdda
fix(browser): add --remote-allow-origins to CDP debug launch for Chro…
Kyzcreig Jun 11, 2026
d401577
fix(discord): stop typing indicator getting stuck on rate-limited cha…
Kyzcreig Jun 12, 2026
0d71b3f
fix(kanban): make --initial-status blocked sticky against recompute_r…
Kyzcreig Jun 12, 2026
d491a31
fix(bridge-routing): isolate background-review fork CLI session (#36)
Kyzcreig Jun 13, 2026
e76da44
feat(kanban): per-task model override write-path (#39)
Kyzcreig Jun 14, 2026
8453fe5
fix(blackbox-pricing): add claude-*-f2 failover aliases to notional A…
Kyzcreig Jun 14, 2026
8b332be
feat(mem0): direct-REST self-host backend (D-8) + B3/B4 scope hardening
Kyzcreig Jun 15, 2026
5fc2887
feat: widen blackbox composition call blobs (#40)
Kyzcreig Jun 15, 2026
aa0f725
fix(browser): suppress macOS "Keychain Not Found" modal on debug-Chro…
Kyzcreig Jun 15, 2026
ca9da42
test(browser): fleet-wide guard — every detached-Chrome launcher must…
Kyzcreig Jun 15, 2026
5ae50ce
mem0: bound httpx connection pool to stop fd leak
Kyzcreig Jun 15, 2026
67d79e8
state: survive missing trigram tokenizer (FTS5 present, trigram absent)
Kyzcreig Jun 15, 2026
531f1e8
harden mem0 client against fd-leak (HANDOFF-fd-leak-client-pool.md)
Kyzcreig Jun 15, 2026
b52dc04
ci(fleet): add posture-B floor — SAST (semgrep) + secret-scan (gitlea…
Kyzcreig Jun 15, 2026
f50f226
Merge branch 'main' into feat/mem0-selfhost-rest
Kyzcreig Jun 15, 2026
59ed0e4
mem0 client: optional CA bundle for private-CA HTTPS (mem0.ace cutove…
Kyzcreig Jun 15, 2026
3087d45
mem0 client: reads scope to user_id only, writes scope both (cutover …
Kyzcreig Jun 15, 2026
08f9f68
Merge fork/main (CI posture-B floor PR #42) into mem0 self-host cutov…
Kyzcreig Jun 15, 2026
becb4ef
fix(blackbox): two-tier char->token divisor (fixed=4.0, non-fixed=3.5…
Kyzcreig Jun 15, 2026
930d367
fix(blackbox): alert card output -> finished/unfinished (#44)
Kyzcreig Jun 15, 2026
36fcdc3
fix(blackbox): tune fixed char->token divisor 4.0 -> 4.2 (post-deploy…
Kyzcreig Jun 15, 2026
70c48d8
fix(blackbox): single global fixed char->token divisor 4.2 -> 4.5 (#46)
Kyzcreig Jun 15, 2026
f9a2dc0
fix(pricing): bill cache-write at input rate when no cache-write rate…
Kyzcreig Jun 15, 2026
20af383
ci: add fleet CI-fail alert workflow (loud #alerts ping on real failure)
Jun 16, 2026
3109924
feat: reversible half-turn /undo + /redo across CLI, gateway, TUI (#49)
Kyzcreig Jun 16, 2026
09d7178
test(mem0): skip self-host tests when optional mem0 package absent (#50)
Kyzcreig Jun 16, 2026
d8c2836
Merge upstream NousResearch/main into fork/main (2026-06-16 sync)
Kyzcreig Jun 16, 2026
8f7a238
Merge pull request #52 from Kyzcreig/sync/upstream-2026-06-16
Kyzcreig Jun 16, 2026
0a86f6f
fix(gateway): classify credential-resolution errors as auth failures …
Kyzcreig Jun 17, 2026
af299ca
fix(pricing): pattern-match notional-Anthropic -fN failover lanes + c…
Kyzcreig Jun 17, 2026
4aac06a
fix(pricing): fall back to base snapshot for dated Anthropic model id…
Kyzcreig Jun 17, 2026
8a88cd7
fix(auxiliary): resolve aux provider+model as a matched pair in _reso…
Kyzcreig Jun 18, 2026
8b86963
feat: vendor LCM context engine
Jun 16, 2026
3cd73eb
test: add isolated LCM smoke gate
Jun 16, 2026
6622f41
Implement LCM fail-open degraded fallback
Jun 16, 2026
6c8202b
feat(lcm): storage security, redaction corpus, encryption, retention
Kyzcreig Jun 16, 2026
e29944b
feat(lcm): add live recovery statistical harness
Kyzcreig Jun 16, 2026
48376f7
fix(lcm): Wilson lower-bound gate default 0.95 -> 0.90 per PRD-6
Kyzcreig Jun 16, 2026
7ee0212
feat: add LCM benchmark battery
Kyzcreig Jun 16, 2026
a036785
feat(lcm): add Aegis stress and config preflight gates
Kyzcreig Jun 16, 2026
d9d2266
feat(lcm): add upstream drift metadata checker
Kyzcreig Jun 16, 2026
87b379b
docs(lcm): t80 integration evidence pack (8 lanes, 81 tests green)
Kyzcreig Jun 16, 2026
4899803
fix(lcm): real session-mode live-recovery driver for Aegis shakedown
Kyzcreig Jun 17, 2026
edcf3cf
test(lcm): add Haiku session-mode shakedown controls
Kyzcreig Jun 17, 2026
4b36982
fix(lcm): null-safe lcm_grep query + Tier-0 QA battery (PRD-7)
Kyzcreig Jun 17, 2026
1d5ebbe
feat(lcm): Arm-B live node-served recovery harness (PRD-7)
Kyzcreig Jun 17, 2026
e0cf699
fix(lcm): Arm-B harness follows session rollover to node-bearing session
Kyzcreig Jun 17, 2026
df420d1
chore(lcm): sequential Arm-A->Arm-B N=180 campaign runner (PRD-7)
Kyzcreig Jun 17, 2026
7d33c98
feat(lcm): multi-sentinel-per-session Arm-B batching (~Kx cheaper)
Kyzcreig Jun 17, 2026
0c96621
chore(lcm): batched Arm-B campaign w/ validation gate before full N=180
Kyzcreig Jun 17, 2026
5c0eced
fix(fallback): re-sync auxiliary-routing runtime globals on failover …
Kyzcreig Jun 17, 2026
1f83923
feat(lcm-qa): heartbeat campaign milestones to #hermes-lcm
Kyzcreig Jun 17, 2026
a8ac516
fix(lcm-arm-b): semantic probes + contention guard + front-loaded con…
Kyzcreig Jun 17, 2026
a3fa06a
fix(lcm-campaign): drain 45s after Arm A before Arm B (DB-flush race)
Kyzcreig Jun 17, 2026
dc4245a
fix(lcm): lcm_expand_query degrades on malformed aux-LLM response (co…
Kyzcreig Jun 17, 2026
d5cec6e
fix(lcm-arm-b): interpreter guard + don't score import errors as reco…
Kyzcreig Jun 17, 2026
9f0c416
feat(lcm-campaign): self-contained tightened-A + semantic-B campaign,…
Kyzcreig Jun 17, 2026
9c8811a
spec(PRD-8): Aegis LCM store snapshot+reset for clean Phase-2 benchmark
Kyzcreig Jun 17, 2026
2609ba7
feat(PRD-8): implement Aegis LCM store reset runbook (dry-run verified)
Kyzcreig Jun 17, 2026
481ddd7
PRD-8.1: probe-isolation harness (Arm A --probe-kind exact default, A…
Kyzcreig Jun 18, 2026
589edef
PRD-8.1 build: VOID-redraw+void_rate (AC-2), enforcing param-pin (AC-…
Kyzcreig Jun 18, 2026
fb3008a
fix(lcm-campaign): staged Arm A N=120 shakedown needs --allow-underpo…
Kyzcreig Jun 18, 2026
e84170e
fix(lcm-arm-a): route gateway LCM writes to --lcm-db via LCM_DATABASE…
Kyzcreig Jun 18, 2026
26f6915
feat(lcm-arm-b): PRD-8.2 gate split — recovery-correctness vs condens…
Kyzcreig Jun 18, 2026
f923a9e
feat(lcm): PRD-8.3 multi-fact disambiguation — identifier fidelity + …
Kyzcreig Jun 19, 2026
f3dfb89
feat(lcm): AC-5 baseline-repro toggle (--no-escalation) for K=2 disam…
Kyzcreig Jun 19, 2026
834f0a0
feat(lcm): staged K=2 disambiguation cutover campaign + reboot-surviv…
Kyzcreig Jun 19, 2026
15e1d95
docs(lcm-qa): preserve Arm-A/Arm-B campaign QA evidence + armab scrip…
Kyzcreig Jun 19, 2026
2a2b992
Merge pull request #57 from Kyzcreig/reconcile/compression-auxpair
Kyzcreig Jun 19, 2026
3e189da
Merge pull request #58 from Kyzcreig/reconcile/lcm-prd78
Kyzcreig Jun 19, 2026
2f530dd
feat(gateway): runtime-footer provider_model, context_full, reasoning…
Kyzcreig Jun 19, 2026
73332c3
Merge pull request #59 from Kyzcreig/feat/runtime-footer-fields
Kyzcreig Jun 19, 2026
c2cf19f
fix(lcm): use nohup instead of setsid for macOS K=2 autofire
Kyzcreig Jun 19, 2026
5a62b9c
Merge pull request #60 from Kyzcreig/fix/lcm-nohup-macos-detach
Kyzcreig Jun 19, 2026
5ec895c
fix(auxiliary): keep auto model resolved from runtime pair (#61)
Kyzcreig Jun 19, 2026
8176539
fix(scripts): add explicit encoding for lcm report writes (#62)
Kyzcreig Jun 19, 2026
efe50db
fix(lcm): toggleable Prong-A identifier fidelity — fixes baseline-rep…
Kyzcreig Jun 19, 2026
fdee6d9
fix(lcm): K=2 campaign — per-stage store reset + abort-safe done-marker
Kyzcreig Jun 19, 2026
a1a1a10
feat(mem0): add gated canonical user_id pinning with provenance
Kyzcreig Jun 20, 2026
051c207
fix(lcm): detect and repair content-drifted messages_fts triggers
Kyzcreig Jun 20, 2026
088bafc
test(lcm): e2e legacy-DB migration tests against real MessageStore init
Kyzcreig Jun 20, 2026
a8e443a
fix(compression): re-resolve per-model threshold on model switch/fall…
Kyzcreig Jun 20, 2026
b62cb03
fix(compression): anti-thrash counter via request-level effectiveness…
Kyzcreig Jun 20, 2026
3571713
test(compression): add request-level thrash integration test (Phase C)
Kyzcreig Jun 20, 2026
4972c37
feat(fallback): announce model fallback in chat, always-emitted + ded…
Kyzcreig Jun 20, 2026
2278a23
test(compression): D-6 failed-summary-over-threshold on real done-pat…
Kyzcreig Jun 20, 2026
d0f8842
feat(fallback): render provider/model on both sides of fallback announce
Kyzcreig Jun 20, 2026
d1fa251
test(hermetic): reset auxiliary_client runtime caches between tests
Kyzcreig Jun 20, 2026
39cec22
test(hermetic): block macOS Keychain + HERMES_REAL_HOME leaks in agen…
Kyzcreig Jun 20, 2026
9454c21
test(hermetic): eliminate remaining cross-file pollution in tests/agent
Kyzcreig Jun 20, 2026
02a357e
feat(compaction-announce): pure snippet extractor + engine-aware form…
Kyzcreig Jun 20, 2026
c7d0795
feat(compaction-announce): record fallback event + turn-scoped post-f…
Kyzcreig Jun 20, 2026
2870fd4
feat(compaction-announce): emit at the engine-agnostic compression do…
Kyzcreig Jun 20, 2026
273707c
test(compaction-announce): real LCM-engine done-site e2e (Phase 0+2b)
Kyzcreig Jun 20, 2026
44791a6
test(compaction-announce): Telegram filter pass-through + single-done…
Kyzcreig Jun 20, 2026
4c595fc
fix(gateway): pass agent provider into runtime-footer result dict
Kyzcreig Jun 20, 2026
a603d1f
fix(stream): recover split-surrogate emoji instead of falling back to…
Kyzcreig Jun 20, 2026
adc8146
merge(mem0): land S2 canonical user_id pinning (a1a1a1065) into main
Kyzcreig Jun 20, 2026
2d9837b
fix(mem0): api_key optional in schema; harden composition test env is…
Kyzcreig Jun 20, 2026
b484232
fix(undo): preserve partial /redo progress, bound _states, public red…
Kyzcreig Jun 20, 2026
8f7c231
test(run_agent): split monolithic test_run_agent.py to fix CI shard t…
Kyzcreig Jun 21, 2026
d4c0ea5
SPEC-10: strengthen mem0_conclude save-guidance for capture=off model…
Kyzcreig Jun 21, 2026
eb5a817
docs(pricing): document _lookup_official_docs_pricing precedence (#68)
Kyzcreig Jun 21, 2026
d2efa01
fix(discord): stop "is typing…" orphaned by typing-loop recreate race
Kyzcreig Jun 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions .github/workflows/fleet-ci-fail-alert.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Fleet-added (Apollo). NOT upstream — do not expect on NousResearch/hermes-agent.
# Fires a single LOUD ping to the fleet #alerts channel ONLY when a real CI
# workflow concludes in failure. The failure-filter lives HERE (`if: failure`)
# because the Hermes webhook adapter filters by event TYPE only, not payload
# conclusion — a deliver_only route on raw check_suite/status would also fire on
# SUCCESS and re-create the flood this replaces. Zero-LLM: the receiver route is
# deliver_only, so this is a pure notification, never an agent run.
name: Fleet CI-fail alert

on:
workflow_run:
workflows:
- "Tests"
- "Lint (ruff + ty)"
- "Fleet SAST (semgrep)"
- "Fleet Secret Scan (gitleaks)"
- "OSV-Scanner"
- "Supply Chain Audit"
types:
- completed

permissions:
contents: read

jobs:
notify-on-failure:
name: notify-on-failure
runs-on: ubuntu-latest
# Only on a genuine failure of the upstream workflow. Success/cancelled/skipped → no-op.
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
steps:
- name: Sign and POST CI-failure event
env:
CI_FAIL_WEBHOOK_SECRET: ${{ secrets.CI_FAIL_WEBHOOK_SECRET }}
WEBHOOK_URL: https://hooks.angventures.io/webhooks/ci-fail
WF_NAME: ${{ github.event.workflow_run.name }}
WF_BRANCH: ${{ github.event.workflow_run.head_branch }}
WF_SHA: ${{ github.event.workflow_run.head_sha }}
WF_URL: ${{ github.event.workflow_run.html_url }}
WF_ACTOR: ${{ github.event.workflow_run.actor.login }}
REPO: ${{ github.repository }}
WF_EVENT: ${{ github.event.workflow_run.event }}
run: |
set -euo pipefail
if [ -z "${CI_FAIL_WEBHOOK_SECRET:-}" ]; then
echo "::error::CI_FAIL_WEBHOOK_SECRET is not set; cannot sign the alert." >&2
exit 1
fi
# Build the JSON body. event_type=ci_failure is what the receiver route
# filters on (X-GitHub-Event header is also set to the same value).
BODY="$(jq -nc \
--arg event_type "ci_failure" \
--arg repo "$REPO" \
--arg workflow "$WF_NAME" \
--arg branch "$WF_BRANCH" \
--arg sha "$WF_SHA" \
--arg run_url "$WF_URL" \
--arg actor "$WF_ACTOR" \
--arg trigger "$WF_EVENT" \
'{event_type:$event_type, repo:$repo, workflow:$workflow, branch:$branch, sha:$sha, run_url:$run_url, actor:$actor, trigger:$trigger}')"
# Generic HMAC-SHA256 hex over the raw body → X-Webhook-Signature.
SIG="$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$CI_FAIL_WEBHOOK_SECRET" | sed 's/^.* //')"
CODE="$(curl -sS -o /tmp/resp.txt -w '%{http_code}' \
-X POST "$WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: ci_failure" \
-H "X-GitHub-Delivery: ci-fail-${WF_SHA}-${GITHUB_RUN_ID}" \
-H "X-Webhook-Signature: ${SIG}" \
--data "$BODY")"
echo "Receiver responded HTTP $CODE"
cat /tmp/resp.txt || true
# 2xx = delivered/accepted. Non-2xx fails the step so the miss is visible.
case "$CODE" in
2*) echo "CI-failure alert delivered." ;;
*) echo "::error::CI-fail alert POST returned HTTP $CODE" >&2; exit 1 ;;
esac
41 changes: 41 additions & 0 deletions .github/workflows/fleet-sast.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Fleet-added (Apollo/greploop posture-B floor). NOT upstream — do not expect on NousResearch/hermes-agent.
# Provides the `sast` deterministic-floor component. Diff-aware where it helps, full-tree gate at ERROR.
name: Fleet SAST (semgrep)

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: fleet-sast-${{ github.ref }}
cancel-in-progress: true

jobs:
sast:
name: sast
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"

- name: Install semgrep
run: pip install "semgrep==1.46.0"

- name: Run semgrep (ERROR severity gate)
run: |
semgrep \
--config=p/python \
--config=p/secrets \
--severity=ERROR \
--error \
--quiet \
hermes/
61 changes: 61 additions & 0 deletions .github/workflows/fleet-secret-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Fleet-added (Apollo/greploop posture-B floor). NOT upstream — do not expect on NousResearch/hermes-agent.
# Provides the `secret_scan` deterministic-floor component. DIFF-SCOPED on PRs: scans only the PR
# commit range, NOT full history (the fork inherits ~768 generic-api-key false positives in upstream
# test fixtures/docs — a full-tree scan would pin this RED forever). On push to main, scans the push range.
name: Fleet Secret Scan (gitleaks)

on:
pull_request:
push:
branches: [main]

permissions:
contents: read

concurrency:
group: fleet-secret-scan-${{ github.ref }}
cancel-in-progress: true

jobs:
secret_scan:
name: secret_scan
runs-on: ubuntu-latest
steps:
- name: Checkout (full history for range scan)
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Compute scan range
id: range
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
BASE="${{ github.event.pull_request.base.sha }}"
HEAD="${{ github.event.pull_request.head.sha }}"
else
BASE="${{ github.event.before }}"
HEAD="${{ github.sha }}"
fi
# Guard against the all-zero "before" SHA on first push / new branch.
if ! git cat-file -e "${BASE}^{commit}" 2>/dev/null; then
BASE="$(git rev-parse "${HEAD}~1" 2>/dev/null || echo "${HEAD}")"
fi
echo "base=${BASE}" >> "$GITHUB_OUTPUT"
echo "head=${HEAD}" >> "$GITHUB_OUTPUT"
echo "scanning ${BASE}..${HEAD}"

- name: Install gitleaks
run: |
VER=8.18.4
curl -fsSL "https://github.com/gitleaks/gitleaks/releases/download/v${VER}/gitleaks_${VER}_linux_x64.tar.gz" -o gl.tgz
tar xzf gl.tgz gitleaks
sudo mv gitleaks /usr/local/bin/

- name: Gitleaks (diff-scoped)
run: |
gitleaks detect \
--source . \
--no-banner \
--redact \
--log-opts="${{ steps.range.outputs.base }}..${{ steps.range.outputs.head }}" \
--exit-code 1
24 changes: 24 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Gitleaks configuration for the hermes-agent fork.
#
# Extends the stock gitleaks ruleset and allowlists the obviously-fake credential
# *fixtures* the test suite uses (mocked clients / redaction tests, never real).
# They surfaced only because the diff-scoped scan re-reads them as "added" lines
# when a large test file is split/moved (PR #66).
#
# gitleaks `stopwords` allowlist a finding when its detected SECRET contains one
# of these substrings (case-insensitive). gitleaks strips the literal "..." from
# the secret it evaluates, so we match the distinctive ALPHANUMERIC token of each
# fake fixture. These tails are specific to the known fakes; a real high-entropy
# key does not contain them (verified with an sk-ant-api03 injection negative
# test that is still CAUGHT with this config).

[extend]
useDefault = true

[allowlist]
description = "Fake test-fixture API keys (mocked clients / redaction tests, never real)."
stopwords = [
"1234567890", # test-key-1234567890 (AIAgent constructor stub) / test-k...7890
"2mno", # gsk_ab...2mno / sk-ant...2mno (redaction fixtures)
"mnop", # sk-or-...mnop (key-masking fixture)
]
Loading