From 1a7e4c1b45d0ff20766760d5ef8e49dcb74d4126 Mon Sep 17 00:00:00 2001 From: Angel Galindo <131726962+AngelGalindo7@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:51:00 -0700 Subject: [PATCH 1/5] docs(infra): add CI status badge to README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d564ad7..dfab821 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +![CI](https://github.com/AngelGalindo7/heuristic-monkey/actions/workflows/ci.yml/badge.svg) + # Heuristic Monkey A Monte Carlo Tree Search bug hunter for web apps. The agent explores a target site stochastically, asks an LLM to predict what each action *should* do, and rewards itself when reality diverges from the prediction. Crashes, 5xx responses, broken images, and silent JS errors override the LLM and force a maximal "surprise" reward — so the search aggressively zooms in on real bugs. From 1e555d4879bce40330e9ded92bcf508739a03fc4 Mon Sep 17 00:00:00 2001 From: Angel Galindo <131726962+AngelGalindo7@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:51:24 -0700 Subject: [PATCH 2/5] docs(infra): add How it works section explaining MCTS, a11y tree state, and hard signals --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index dfab821..d45971b 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,10 @@ A Monte Carlo Tree Search bug hunter for web apps. The agent explores a target s Local-only. ~$0/month plus OpenAI usage (cents per run). +## How it works + +Heuristic Monkey uses MCTS (Monte Carlo Tree Search) to explore a web app — a tree search algorithm that balances exploring new parts of your app with revisiting areas where bugs were found. Each unique page state is represented as a snapshot of the browser's accessibility tree (the same semantic structure screen readers use), so two pages that look visually different but share the same interactive elements are treated as the same state. Hard signals — HTTP 500 responses, uncaught JavaScript errors, and broken image loads — detect bugs deterministically without any interpretation: when one fires, the agent scores that path maximally and focuses exploration there. The LLM layer is optional; all hard-signal detection works without an API key, and the LLM only adds soft "surprise" scoring to catch regressions that don't crash outright. + ## Quick Start ```bash From 9fcc637a1f0f70f3a8b45ff49302b95663b8c9cb Mon Sep 17 00:00:00 2001 From: Angel Galindo <131726962+AngelGalindo7@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:51:48 -0700 Subject: [PATCH 3/5] docs(infra): add Targeting your app section with generic SPA config examples --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index d45971b..ccd97f3 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,28 @@ Edit `config.yaml`: | `llm.enabled` / `llm.model` | Disable to run in pure hard-signal mode | | `auth.cookies` | Pre-login cookies applied before first `goto` | +## Targeting your app + +Point the monkey at any SPA by setting the target URL and allowed domains in `config.yaml`: + +```yaml +target: + url: https://your-app.example.com + allowedDomains: ["your-app.example.com", "api.your-app.example.com"] +``` + +For apps requiring authentication, supply cookies in `config.yaml`: + +```yaml +auth: + cookies: + - name: session + value: "your-session-token" + domain: "your-app.example.com" +``` + +Use passive mode (default) for apps you do not own — it never submits forms or mutates state. Use active mode (`--active`) for apps you own to enable form submission and authorization probes. + ## Environment Variables See `.env.example` for the full list. Key vars: From ddb96530e60e1dfe0600aaf686d516166424f611 Mon Sep 17 00:00:00 2001 From: Angel Galindo <131726962+AngelGalindo7@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:52:19 -0700 Subject: [PATCH 4/5] docs(infra): add Troubleshooting section covering expired cookies, passive mode, and coverage tuning --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index ccd97f3..dda643b 100644 --- a/README.md +++ b/README.md @@ -90,3 +90,11 @@ See `.env.example` for the full list. Key vars: - `OPENAI_API_KEY` — required for LLM-guided exploration - `GITHUB_TOKEN` + `GITHUB_REPO_OWNER` + `GITHUB_REPO_NAME` — auto-file GitHub issues on bugs - `LIGHTPANDA_BIN` — path to Lightpanda binary (optional, Linux only) + +## Troubleshooting + +**Auth cookies have expired** — re-export fresh cookies from your browser DevTools (Application > Cookies) and update the `auth.cookies` section in `config.yaml`. Cookies are applied before each run. + +**Forms are not being submitted** — the tool runs in passive mode by default, which never submits forms. Run with `--active` to enable form submission and write-dependent oracles. + +**No bugs found** — this may mean the app is well-built, or the exploration did not reach the buggy path. Increase `mcts.maxSteps` in `config.yaml` to explore more paths. Change `mcts.seed` to explore a statistically independent trajectory. From d96297e3bb55f728ebfd38d5a7b32c0523581d71 Mon Sep 17 00:00:00 2001 From: Angel Galindo <131726962+AngelGalindo7@users.noreply.github.com> Date: Tue, 23 Jun 2026 20:52:52 -0700 Subject: [PATCH 5/5] docs(infra): add CONTRIBUTING guide with oracle walkthrough, contract, and action type guide --- CONTRIBUTING.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9938d0c..ba408ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,6 +19,46 @@ npm start --active # active scan — enables form fills and authz replay See **Running Modes** in [README.md](README.md) for the full distinction. +## How to add a new oracle + +Step-by-step: + +1. Create `src/agent/oracles/myOracle.js` and export `checkMyOracle(options)` +2. Add signal constants to `HARD_SIGNALS` in `src/agent/expectations.js` +3. Wire it in `src/index.js`: step-level oracles go in the `ORACLE_REGISTRY` in `src/agent/oracles/registry.js`; run-level oracles (called once after the arm loop) go in `main()` alongside `authzReplay` +4. Write `tests/unit/myOracle.test.js` + +Code template: + +```js +/** + * @param {{ captures: object[], allowedDomains: string[], config: object, client?: object }} options + * @returns {Promise<{ signal: string|null, detail?: string }>} + */ +export async function checkMyOracle({ captures, allowedDomains, config }) { + if (!config.oracle?.myOracle?.enabled) return { signal: null }; + // detection logic here + return { signal: null }; // or { signal: 'MY_SIGNAL', detail: 'description' } +} +``` + +## Oracle contract + +Every oracle returns `{ signal: string|null, detail?: string }`. + +Two tiers: + +- **auto-assert**: fires when the finding has NO ambiguous legitimate interpretation — creates a `BUG/` artifact. Examples: HTTP 500, duplicate resource IDs from an idempotency-key replay. Rule: do not use auto-assert if any legitimate server behavior can produce the same signal. +- **flag-for-review**: fires when a human must confirm whether the finding is a real bug — creates a `FLAGGED/` artifact. Examples: missing security header, CORS misconfiguration, authorization leak. + +## How to add a new action type + +Three-file change: + +1. Create `src/actions/myAction.js` exporting `async function myAction(page, opts)` +2. Register it in `src/actions/macro.js` (or equivalent action dispatcher) +3. Add a weight entry in `config.yaml` under `actions.weights` + ## Pull request conventions - One file per commit. Commit message format: `type(scope component): description` @@ -28,6 +68,26 @@ See **Running Modes** in [README.md](README.md) for the full distinction. - Never bundle unrelated files in one commit. - `npm test` must pass before merging. +## Commit message format + +``` +type(scope component): description +``` + +Single line only. Types: `feat` `fix` `chore` `docs` `test` `refactor` `perf` `ci` + +Scopes: `agent` `browser` `perception` `actions` `llm` `observability` `triage` `config` `infra` `docs` + +Never add `Co-Authored-By` trailers. Never commit files under `docs/`. + +## Running tests + +```bash +npm test # unit tests (vitest) +npx playwright install chromium --with-deps # one-time setup for integration smoke +npx vitest run tests/smoke/integration.test.mjs # integration smoke +``` + ## Ethical use Do not run this tool against web apps you do not own or have written permission to test.