From b6dc15cf022f4034c2c30777bc8a15a9599d6ba6 Mon Sep 17 00:00:00 2001 From: pdparchitect Date: Mon, 1 Jun 2026 23:12:33 +0000 Subject: [PATCH] - Re-formatting. - feat: add tag-release workflow and VERSION file for automated tagging - feat: add authentication section to README with API token setup and recommendations --- .env.example | 2 +- .github/workflows/release.yaml | 3 + .github/workflows/tag-release.yaml | 66 +++++++++++++++++ .gitignore | 2 +- Makefile | 2 +- NOTICE.md | 2 +- README.md | 110 ++++++++++++++++++++++++----- RELEASES.md | 4 +- VERSION | 1 + cmd/rook/main.go | 2 +- internal/agent/runner.go | 2 +- 11 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 .github/workflows/tag-release.yaml create mode 100644 VERSION diff --git a/.env.example b/.env.example index 498beb5..38eb420 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ # Copy to .env and fill in. Rook loads .env automatically on startup. -# ChatBotKit API token — required. +# ChatBotKit API token - required. CHATBOTKIT_API_SECRET= diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 23a6e44..b245bcb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -4,6 +4,9 @@ on: push: tags: - 'v*' + # Dispatched by tag-release.yaml at the new tag ref. Needed because tags + # pushed with GITHUB_TOKEN do not trigger the push-tags event above. + workflow_dispatch: permissions: contents: write diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml new file mode 100644 index 0000000..12b6c1e --- /dev/null +++ b/.github/workflows/tag-release.yaml @@ -0,0 +1,66 @@ +# Auto-tag when merging to main. +# +# Reads the version from the VERSION file and, if the matching tag does not +# already exist, creates and pushes it, then dispatches the Release workflow +# (which builds and publishes the binaries). The dispatch is required because +# tags pushed with GITHUB_TOKEN do not trigger other workflows. +name: Tag Release + +on: + push: + branches: + - main + +jobs: + tag: + runs-on: ubuntu-latest + permissions: + contents: write + actions: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get version from VERSION file + id: version + run: | + if [ -f VERSION ]; then + VERSION=$(cat VERSION) + else + VERSION="0.0.0" + fi + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Version: $VERSION" + + - name: Check if tag exists + id: check_tag + run: | + if git rev-parse "v${{ steps.version.outputs.version }}" >/dev/null 2>&1; then + echo "exists=true" >> $GITHUB_OUTPUT + echo "Tag v${{ steps.version.outputs.version }} already exists" + else + echo "exists=false" >> $GITHUB_OUTPUT + echo "Tag v${{ steps.version.outputs.version }} does not exist" + fi + + - name: Create and push tag + if: steps.check_tag.outputs.exists == 'false' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}" + git push origin "v${{ steps.version.outputs.version }}" + + - name: Trigger release workflow + if: steps.check_tag.outputs.exists == 'false' + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release.yaml', + ref: 'v${{ steps.version.outputs.version }}' + }) diff --git a/.gitignore b/.gitignore index dde95b8..7e9604a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ # Release artifacts /dist/ -# Go workspace — local development only +# Go workspace - local development only go.work go.work.sum diff --git a/Makefile b/Makefile index 2a4c75f..3bbb999 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ GOSDK ?= ../go-sdk workspace: go work init . $(GOSDK) - @echo "go.work created — local builds now use $(GOSDK)" + @echo "go.work created - local builds now use $(GOSDK)" build: @echo "Building $(CMD) ($(VERSION))..." diff --git a/NOTICE.md b/NOTICE.md index c8a64e9..1e841df 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -3,7 +3,7 @@ Rook bundles third-party content under the terms below. This file is provided to satisfy the attribution requirements of those licenses. -## Embedded skill library — `skills/` +## Embedded skill library - `skills/` The contents of the [`skills/`](skills/) directory are sourced from the **claude-bughunter** project by Sachin Sharma: diff --git a/README.md b/README.md index a20de31..3618df1 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **Rook** is a standalone, autonomous security agent for vulnerability research, bug hunting and source-code auditing. It is a single Go executable built on the [ChatBotKit Go SDK](https://github.com/chatbotkit/go-sdk), with a library of -security skills embedded directly into the binary — no external files, no setup +security skills embedded directly into the binary - no external files, no setup beyond an API key. Give Rook a target and a scope, and it works through the problem the way a @@ -16,11 +16,48 @@ written report. > against systems, code and services you own or are explicitly authorized to > test. Always pass an explicit `--scope`. +## Why Rook? + +Security work happens in awkward places - a hardened bastion, an air-gapped +network, a throwaway cloud VM, a CI runner, someone else's laptop during an +engagement. Rook is built for exactly those: + +- **One single executable.** Everything - the agent loop, the tools, and the + entire skill library - is compiled into one binary via Go's `embed`. There is + no runtime to install, no interpreter, no `node_modules`, no virtualenv, no + config files to ship alongside it. Download one file, `chmod +x`, run. +- **Portable everywhere.** Statically linked (`CGO_ENABLED=0`) and + cross-compiled for Linux, macOS and Windows on both amd64 and arm64. The same + tool drops onto an Apple-silicon laptop, an x86 server, or an ARM box with no + changes. Nothing to match against the host's libraries or OS version. +- **Nothing to fetch at runtime.** Because the skills are baked in, Rook works + in locked-down or offline environments where you can't `pip install` or pull + containers. Its only external dependency is the ChatBotKit API (and your key). +- **The hard parts run as a service.** This is the real reason Rook feels so + light. The AI agent harness - model orchestration, the reasoning and + tool-execution loop, skill handling, scaling and reliability - runs as a + managed service on ChatBotKit, built and maintained by a dedicated team of + engineers who do only this. The binary doesn't reimplement any of that + complexity; it embeds the skills and streams the conversation. So the agent + itself stays small and focused on the task at hand, and you inherit harness + improvements without shipping a new build. +- **Trivial to distribute and audit.** A single artifact with a published + checksum is easy to vet, copy onto a target box, version-pin, and remove + cleanly afterwards - important when you're operating inside someone else's + scope. +- **Purpose-built, not a general chatbot.** Rook ships as a focused + vulnerability-research and bug-hunting agent: it knows the methodology, the + bug classes, and the reporting discipline out of the box, and stays within + the authorization boundary you give it. + +In short: the value isn't just "an AI security agent" - it's an AI security +agent you can carry anywhere as **one file** and run with **zero setup**. + ## Features - **Single self-contained binary.** The skill library is compiled into the executable via Go's `embed`, so it ships and runs as one file. -- **Autonomous agent loop.** Built on the Go SDK's `agent.ExecuteWithTools` — +- **Autonomous agent loop.** Built on the Go SDK's `agent.ExecuteWithTools` - the agent plans, acts, tracks progress and exits on its own, bounded by `--max-iterations`. - **Built-in tools.** File read/write/edit and sandboxed shell execution via @@ -50,6 +87,43 @@ Or clone and build with the provided `Makefile`: make build # → ./rook ``` +## Authentication + +Rook talks to the ChatBotKit API, so it needs an API token supplied via +`CHATBOTKIT_API_SECRET`. + +1. **Create a ChatBotKit account** at [chatbotkit.com](https://chatbotkit.com) + or [console.cbk.ai](https://console.cbk.ai). +2. **Create an API token** from the Tokens page + ([chatbotkit.com/tokens](https://chatbotkit.com/tokens)) and set it as + `CHATBOTKIT_API_SECRET` (export it, or put it in a `.env` file). + +### Recommended: run under a sub-account + +For better **isolation, cost control and observability**, we suggest running +Rook under a dedicated **sub-account** rather than your main account - each +engagement, tool or user then gets its own usage, billing and logs. For a +sub-account that is fully dedicated to Rook, a **standard token is enough**. + +### Recommended: use a scoped token + +We also recommend a **scoped token**, which limits the token to specific +ChatBotKit API routes (principle of least privilege), so a leaked key can't +touch the rest of your account. This matters less for a fully dedicated +sub-account, but it is good practice everywhere. + +Rook runs **statelessly**, so it only needs the stateless completion route. +When creating the token, set its `allowedRoutes` to: + +```yaml +allowedRoutes: + - conversation/complete +``` + +Route patterns omit the `/v1/` prefix. See +[How to Create Scoped API Tokens](https://chatbotkit.com/tutorials/how-to-create-scoped-api-tokens-for-restricted-access) +for the full guide. + ## Usage ```bash @@ -74,41 +148,41 @@ Rook loads a `.env` file automatically if present (see `.env.example`). | ------------------ | --------------- | --------------------------------------------- | | `--model` | `qwen-3.6-plus` | Model the agent reasons with | | `--max-iterations` | `40` | Maximum agent iterations before a forced stop | -| `--scope` | — | Authorization boundary (hosts, repos, paths) | -| `--scope-file` | — | Read the authorization scope from a file | +| `--scope` | - | Authorization boundary (hosts, repos, paths) | +| `--scope-file` | - | Read the authorization scope from a file | | `-v`, `--verbose` | `false` | Stream the agent's reasoning tokens to stdout | -| `-V`, `--version` | — | Print version and exit | +| `-V`, `--version` | - | Print version and exit | The agent's findings stream to **stderr**; with `--verbose`, reasoning tokens -stream to **stdout**. The final report is delivered as the agent's response — +stream to **stdout**. The final report is delivered as the agent's response - Rook does not write files on its own. If you want the report (or any other artifact) saved to disk, ask for it in the task and the agent will use its `write` tool. ## Embedded Skills -Rook ships with **51 security skills** — each a `SKILL.md` playbook under +Rook ships with **51 security skills** - each a `SKILL.md` playbook under [`skills/`](skills/), embedded into the binary at build time and offered to the agent as it works. They cover, roughly: -- **Methodology & mindset** — `bug-bounty`, `bb-methodology`, `redteam-mindset`, +- **Methodology & mindset** - `bug-bounty`, `bb-methodology`, `redteam-mindset`, `bb-local-toolkit`, `hunt-dispatch`. -- **Web/API vulnerability hunting** (24 `hunt-*` classes + `security-arsenal`) — +- **Web/API vulnerability hunting** (24 `hunt-*` classes + `security-arsenal`) - IDOR, SQLi, XSS, SSRF, RCE, SSTI, XXE, CSRF, OAuth, SAML, GraphQL, auth/MFA bypass, ATO, business logic, cache poisoning, HTTP smuggling, file upload, API misconfig, race conditions, and more. -- **Enterprise & infrastructure attack chains** — `m365-entra-attack`, +- **Enterprise & infrastructure attack chains** - `m365-entra-attack`, `okta-attack`, `cloud-iam-deep`, `vmware-vcenter-attack`, `enterprise-vpn-attack`, `hunt-sharepoint`, `hunt-aspnet`, `hunt-ntlm-info`, `apk-redteam-pipeline`, `supply-chain-attack-recon`. -- **Recon & OSINT** — `web2-recon`, `offensive-osint`, `osint-methodology`, +- **Recon & OSINT** - `web2-recon`, `offensive-osint`, `osint-methodology`, `hunt-subdomain`. -- **Web3** — `web3-audit`, `meme-coin-audit`. -- **Triage, reporting & hygiene** — `triage-validation`, `bugcrowd-reporting`, +- **Web3** - `web3-audit`, `meme-coin-audit`. +- **Triage, reporting & hygiene** - `triage-validation`, `bugcrowd-reporting`, `report-writing`, `redteam-report-template`, `evidence-hygiene`, `mid-engagement-ir-detection`. -These skills are sourced from the **claude-bughunter** project — see +These skills are sourced from the **claude-bughunter** project - see [Credits](#credits). ### Adding a skill @@ -126,7 +200,7 @@ description: One sentence the model uses to decide when to apply this skill. Step-by-step guidance... ``` -Rebuild the binary — the new skill is picked up automatically by the `embed` +Rebuild the binary - the new skill is picked up automatically by the `embed` directive. No registration code required. ## How it works @@ -140,8 +214,8 @@ embed.go //go:embed skills → the embedded skill library skills/ SKILL.md playbooks compiled into the binary ``` -The default model and the agent's system prompt (backstory) live in one place — -[`internal/config/config.go`](internal/config/config.go) — so they can be tuned +The default model and the agent's system prompt (backstory) live in one place - +[`internal/config/config.go`](internal/config/config.go) - so they can be tuned without touching the CLI or the agent loop. At startup Rook loads the embedded skills with `agent.LoadSkillsFromFS`, @@ -192,5 +266,5 @@ author and the bug-bounty community whose disclosed reports informed them. ## License -Rook itself is MIT licensed — see [LICENSE](LICENSE). Bundled third-party +Rook itself is MIT licensed - see [LICENSE](LICENSE). Bundled third-party content retains its original license; see [NOTICE.md](NOTICE.md). diff --git a/RELEASES.md b/RELEASES.md index 60c5f5b..4dc3ac9 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,8 +11,8 @@ multi-platform binaries and publishes them as a GitHub Release. ### go-sdk resolution The committed `go.mod` pins a **tagged release** of the Go SDK (e.g. -`github.com/chatbotkit/go-sdk v0.1.0`), so every build — clean clone, CI, -release, and `go install` — uses exactly that version. Builds are reproducible; +`github.com/chatbotkit/go-sdk v0.1.0`), so every build - clean clone, CI, +release, and `go install` - uses exactly that version. Builds are reproducible; no floating fetch step is involved. For development against a local checkout of the SDK, a **gitignored `go.work`** diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/cmd/rook/main.go b/cmd/rook/main.go index 366f4c2..67fb905 100644 --- a/cmd/rook/main.go +++ b/cmd/rook/main.go @@ -41,7 +41,7 @@ func main() { showVersion := flags.BoolP("version", "V", false, "print version and exit") flags.Usage = func() { - fmt.Fprintf(os.Stderr, "rook — autonomous security research agent\n\n") + fmt.Fprintf(os.Stderr, "rook - autonomous security research agent\n\n") fmt.Fprintf(os.Stderr, "Usage:\n rook [flags] \n rook version\n\nFlags:\n") flags.PrintDefaults() } diff --git a/internal/agent/runner.go b/internal/agent/runner.go index ac84684..0260ff7 100644 --- a/internal/agent/runner.go +++ b/internal/agent/runner.go @@ -53,7 +53,7 @@ func Run(ctx context.Context, cfg Config) (int, error) { fmt.Fprintf(os.Stderr, "Loaded %d embedded skill(s):\n", len(skills)) for _, s := range skills { - fmt.Fprintf(os.Stderr, " • %s — %s\n", s.Name, s.Description) + fmt.Fprintf(os.Stderr, " • %s - %s\n", s.Name, s.Description) } fmt.Fprintln(os.Stderr)