From 8ce880657c217d79d6bf5298800099a8b78a2360 Mon Sep 17 00:00:00 2001 From: Han Ngo Date: Thu, 25 Jun 2026 02:08:18 +0700 Subject: [PATCH 1/3] chore: scrub committed API keys + security baseline Console Labs consolidation hardening (lighter adoption). - SECURITY: pkg/config/config.go hardcoded SOLSCAN_TOKEN + BIRDEYE_API_KEY as viper defaults in this PUBLIC repo. Scrubbed to "" (env-only). The exposed keys must be ROTATED at the providers (still in git history). See docs/SECURITY-AUDIT-2026-06-25.md. - .gitleaks.toml: allowlist test/seed/sample fixtures (47 false positives) so CI gates on real leaks; gitleaks now clean. - .github/workflows/security.yml: gitleaks + govulncheck on PRs. - CLAUDE.md + docs/ARCHITECTURE.md: repo guidance + reindex. No other logic touched, no dependency bumped. Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 34 ++++++++++++++++++++++++++++++ docs/ARCHITECTURE.md | 32 ++++++++++++++++++++++++++++ docs/SECURITY-AUDIT-2026-06-25.md | 35 +++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 CLAUDE.md create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/SECURITY-AUDIT-2026-06-25.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..81b3fad4b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,34 @@ +# CLAUDE.md + +Guidance for AI agents (and humans) working in `mochi-api`. + +## What this is + +`mochi-api` is the core Go backend for Mochi (Console Labs): the Discord-bot API, token/NFT data, user/guild config, and on-chain helpers. Live on EKS `mochi-prod` (see Console Labs MAP.md). PUBLIC repo. + +- Module: `github.com/defipod/mochi` (legacy `defipod` path, see Notes), Go 1.19, gitflow (default branch `develop`). +- Entrypoints: `cmd/server` (the API) plus many `cmd/*` workers/cron jobs (price watchers, streak updaters, nft balance sync, etc.). +- Layout: `pkg/` (entities, handler, config, ...), `migrations/` (schema + seed), `abi/` (contract ABIs), `docs/` (swagger). + +## Commands + +- Build: `go build ./...` · Test: `go test ./...` (CI: `.github/workflows/ci-test.yml`) +- Run API: `go run ./cmd/server` +- Migrations: see `migrations/` (golang-migrate style) +- Deploy: GKE workflows `.github/workflows/gke-dev.yml` / `gke-prod.yml`; release `release.yaml` + +## Conventions + +- Config via viper + env (`pkg/config/config.go`). Secrets come from env / the platform, NEVER hardcoded defaults (see Security). +- Commit lint enforced (`.github/workflows/commitlint.yml`). +- gitflow: feature branches off `develop`. + +## Security / quality (consolidation hardening pass, 2026-06-25) + +- **INCIDENT (rotate):** `pkg/config/config.go` previously hardcoded `SOLSCAN_TOKEN` (a JWT) and `BIRDEYE_API_KEY` as viper defaults in this PUBLIC repo. This PR scrubbed them to empty (`set via env`). **The exposed keys must be rotated at SolScan and Birdeye** and are still in git history. See `docs/SECURITY-AUDIT-2026-06-25.md`. +- Secret scan: `gitleaks detect -c .gitleaks.toml`. The allowlist excludes test fixtures / seed data / `.env.sample` (mock data, not secrets) so the gate fires on REAL leaks. CI: `.github/workflows/security.yml`. +- Dependency audit: `govulncheck` runs in CI (the local toolchain could not build it; CI has a clean Go). Dependabot is enabled. Bump deliberately; this is a live prod service. + +## Notes + +- The Go module path is still `github.com/defipod/mochi` (pre-consolidation). Renaming it to `github.com/consolelabs/...` is a BREAKING change (every importer + internal path) and is NOT done here; flagged as a follow-up so the org consolidation has no orphan `defipod` URLs. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 000000000..e421a3ccb --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,32 @@ +# mochi-api architecture + +Go backend for Mochi (Console Labs). One API server plus a fleet of cron/worker binaries, all in one module (`github.com/defipod/mochi`). Runs on EKS `mochi-prod`. + +``` +mochi-api/ +├── cmd/ +│ ├── server/ the HTTP API (gin), main entrypoint +│ └── / price watchers, streak/role/nft-balance updaters, +│ coingecko/binance fetchers, dm-notify, etc. (cron jobs) +├── pkg/ +│ ├── handler/ HTTP handlers (per domain: user, guild, token, ...) +│ ├── entities/ business logic / service layer +│ ├── config/ viper + env config (config.go) +│ ├── repo/ model/ ... data access + models +│ └── ... +├── migrations/ schema migrations + seed/ + test_seed/ +├── abi/ on-chain contract ABIs +└── docs/ swagger + (this) architecture +``` + +## Shape + +- HTTP API (`cmd/server`) serves the Discord bot + web; the `cmd/*` workers run as scheduled jobs against the same DB/config. +- Postgres (CNPG `pg-prod` per MAP.md) + Redis + Kafka. Config + secrets via viper/env (platform-injected). +- Deploy: GKE workflows historically (`gke-dev`/`gke-prod`); current live runtime is EKS `mochi-prod`. + +## Notes for agents + +- Live prod service handling real user-facing data. Treat handler/entity changes as production changes; prefer additive, test with `go test ./...`. +- Many worker binaries share `pkg/`; a change to a shared entity can affect both the API and the cron fleet. +- Module path is legacy `defipod/*` (see SECURITY-AUDIT / CLAUDE.md); do not assume `consolelabs/*` import paths. diff --git a/docs/SECURITY-AUDIT-2026-06-25.md b/docs/SECURITY-AUDIT-2026-06-25.md new file mode 100644 index 000000000..2e03cf92c --- /dev/null +++ b/docs/SECURITY-AUDIT-2026-06-25.md @@ -0,0 +1,35 @@ +# Security audit: mochi-api (2026-06-25) + +Bounded security triage from the Console Labs consolidation hardening pass. **This repo is PUBLIC.** + +## INCIDENT: two third-party API keys were hardcoded in a public repo (ROTATE) + +`pkg/config/config.go` set live secrets as viper DEFAULTS, committed to this public repo: + +| Key | line | type | action | +|---|---|---|---| +| `SOLSCAN_TOKEN` | 462 | SolScan API JWT | **ROTATE at SolScan**, then set via env only | +| `BIRDEYE_API_KEY` | 463 | Birdeye API key | **ROTATE at Birdeye**, then set via env only | + +This PR scrubbed both to `""` (value sourced from env, as prod already does). **The values are still in git history** (this PR only changes the working tree). Rotation is the real fix; a history rewrite is optional and secondary. The secret values are NOT reproduced anywhere in this repo or PR. + +- Owner action: rotate both keys at the providers; confirm the prod env (EKS / Vault) supplies them; consider whether any other consumer used the default. +- Pre-merge check: confirm prod sets `SOLSCAN_TOKEN` + `BIRDEYE_API_KEY` via env, or the scrub turns those integrations off. + +## Secret scan: 49 -> 0 (after scrub + allowlist) + +`gitleaks detect --no-git` initially found 49. Breakdown: 2 real (the config.go defaults above, now scrubbed) + 47 false positives in test fixtures / seed data / `.env.sample` (mock api-keys + mock discord-client-ids). Added `.gitleaks.toml` allowlisting those fixture paths so the CI gate (`.github/workflows/security.yml`) fires on REAL leaks. Post-scrub + allowlist: **no leaks found**. + +## Dependency audit + +`govulncheck` added to CI (the local Go toolchain could not build it; CI has a clean Go). Dependabot is enabled on the repo. Findings are surfaced non-blocking until triaged; remediation is deliberate (live prod service). + +## Orphan defipod URL (flagged, not fixed) + +Go module path is `github.com/defipod/mochi` , a `defipod` reference inside a consolelabs repo. Renaming is a BREAKING change (all importers + internal imports) and is out of scope for this additive pass. Tracked so the consolidation's "no orphan defipod URLs" goal has a follow-up. + +## What this PR changes + +- `pkg/config/config.go`: scrub the 2 hardcoded secret defaults to `""` (the only code change; behavior = secrets now env-only). +- `.gitleaks.toml`, `.github/workflows/security.yml` (gitleaks + govulncheck), `CLAUDE.md`, `docs/ARCHITECTURE.md`, this record. +- No other logic touched, no dependency bumped. From 49e39342f91cd14bdf9f20349ec3dc8facc7a738 Mon Sep 17 00:00:00 2001 From: Han Ngo Date: Thu, 25 Jun 2026 02:53:28 +0700 Subject: [PATCH 2/3] docs: refresh README with Development & docs section Additive (consolidation hardening): points at CLAUDE.md + ARCHITECTURE + security baseline + build/test. Existing 7KB README preserved. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.MD | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.MD b/README.MD index 0400c31b0..3ea68ee43 100644 --- a/README.MD +++ b/README.MD @@ -190,3 +190,23 @@ If you'd like to contribute, please check out the [contributing guide](CONTRIBUT - Reach us at [discord](https://discord.gg/dddsYkB8Jw). - Discuss development in the #build-with-us channel. + + + +## Development & docs + +This repo was reindexed in the Console Labs org-consolidation hardening pass (2026-06). + +- `CLAUDE.md` , guidance for AI agents + humans (stack, conventions, commands). +- `docs/ARCHITECTURE.md` , what's here and how it fits together. +- `docs/SECURITY-AUDIT-2026-06-25.md` , secret-scan + dependency baseline. +- CI: `.github/workflows/security.yml` runs gitleaks + a dependency audit on every PR. + +Build / test: + +``` +go build ./... +go test ./... +``` + +Secrets come from env / the platform, never hardcoded. From 23720b92943d1cd252cb62598ff122da08e89c8a Mon Sep 17 00:00:00 2001 From: Han Ngo Date: Thu, 27 Aug 2026 13:24:56 +0700 Subject: [PATCH 3/3] docs: correct security audit claims after rebase The SOLSCAN_TOKEN/BIRDEYE_API_KEY scrub and the gitleaks/govulncheck CI setup this PR originally proposed were both superseded upstream by the time it rebased onto develop. Update the two doc files to describe what actually landed instead of what the original diff proposed. --- CLAUDE.md | 6 +++--- docs/SECURITY-AUDIT-2026-06-25.md | 15 +++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 81b3fad4b..e281d0dae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,9 +25,9 @@ Guidance for AI agents (and humans) working in `mochi-api`. ## Security / quality (consolidation hardening pass, 2026-06-25) -- **INCIDENT (rotate):** `pkg/config/config.go` previously hardcoded `SOLSCAN_TOKEN` (a JWT) and `BIRDEYE_API_KEY` as viper defaults in this PUBLIC repo. This PR scrubbed them to empty (`set via env`). **The exposed keys must be rotated at SolScan and Birdeye** and are still in git history. See `docs/SECURITY-AUDIT-2026-06-25.md`. -- Secret scan: `gitleaks detect -c .gitleaks.toml`. The allowlist excludes test fixtures / seed data / `.env.sample` (mock data, not secrets) so the gate fires on REAL leaks. CI: `.github/workflows/security.yml`. -- Dependency audit: `govulncheck` runs in CI (the local toolchain could not build it; CI has a clean Go). Dependabot is enabled. Bump deliberately; this is a live prod service. +- **INCIDENT (rotate):** `pkg/config/config.go` previously hardcoded `SOLSCAN_TOKEN` (a JWT) and `BIRDEYE_API_KEY` as viper defaults in this PUBLIC repo. Both fields have since been removed entirely upstream (SolScan/Birdeye retired in favor of Alchemy). **The exposed keys must be rotated at SolScan and Birdeye if not already done** and are still in git history. See `docs/SECURITY-AUDIT-2026-06-25.md`. +- Secret scan: `gitleaks detect -c .gitleaks.toml` (the release binary, no license needed). The allowlist excludes test fixtures / seed data / `.env.sample` (mock data, not secrets) so the gate fires on REAL leaks. CI: `.github/workflows/security.yml`. +- Dependency audit: `govulncheck` runs in CI on a modern Go toolchain (`go-version: stable`; the module itself stays on Go 1.19). Dependabot is enabled. Bump deliberately; this is a live prod service. ## Notes diff --git a/docs/SECURITY-AUDIT-2026-06-25.md b/docs/SECURITY-AUDIT-2026-06-25.md index 2e03cf92c..62b2b55da 100644 --- a/docs/SECURITY-AUDIT-2026-06-25.md +++ b/docs/SECURITY-AUDIT-2026-06-25.md @@ -11,18 +11,18 @@ Bounded security triage from the Console Labs consolidation hardening pass. **Th | `SOLSCAN_TOKEN` | 462 | SolScan API JWT | **ROTATE at SolScan**, then set via env only | | `BIRDEYE_API_KEY` | 463 | Birdeye API key | **ROTATE at Birdeye**, then set via env only | -This PR scrubbed both to `""` (value sourced from env, as prod already does). **The values are still in git history** (this PR only changes the working tree). Rotation is the real fix; a history rewrite is optional and secondary. The secret values are NOT reproduced anywhere in this repo or PR. +This PR originally scrubbed both to `""` (value sourced from env, as prod already does). By the time this PR rebased onto `develop`, both fields had already been removed from `pkg/config/config.go` upstream (the SolScan/Birdeye integrations were cut over to Alchemy), so no code change ships in the final diff. **The old values are still in git history** (removal only changes the working tree). Rotation is the real fix; a history rewrite is optional and secondary. The secret values are NOT reproduced anywhere in this repo or PR. -- Owner action: rotate both keys at the providers; confirm the prod env (EKS / Vault) supplies them; consider whether any other consumer used the default. -- Pre-merge check: confirm prod sets `SOLSCAN_TOKEN` + `BIRDEYE_API_KEY` via env, or the scrub turns those integrations off. +- Owner action: rotate both keys at the providers if not already done; confirm no other consumer still relies on the retired defaults. +- Pre-merge check: n/a, the fields no longer exist in config.go. ## Secret scan: 49 -> 0 (after scrub + allowlist) -`gitleaks detect --no-git` initially found 49. Breakdown: 2 real (the config.go defaults above, now scrubbed) + 47 false positives in test fixtures / seed data / `.env.sample` (mock api-keys + mock discord-client-ids). Added `.gitleaks.toml` allowlisting those fixture paths so the CI gate (`.github/workflows/security.yml`) fires on REAL leaks. Post-scrub + allowlist: **no leaks found**. +`gitleaks detect --no-git` initially found 49 on this PR's original diff. Breakdown: 2 real (the config.go defaults above, since removed upstream) + 47 false positives in test fixtures / seed data / `.env.sample` (mock api-keys + mock discord-client-ids). `develop` has its own `.gitleaks.toml` allowlist covering the fixture paths and a `.github/workflows/security.yml` that runs the gitleaks binary directly (no license required) plus govulncheck on a modern Go toolchain; this PR keeps develop's versions of both rather than reintroducing its own. ## Dependency audit -`govulncheck` added to CI (the local Go toolchain could not build it; CI has a clean Go). Dependabot is enabled on the repo. Findings are surfaced non-blocking until triaged; remediation is deliberate (live prod service). +`govulncheck` runs in CI (`develop`'s `security.yml`, `go-version: stable`). Dependabot is enabled on the repo. Findings are surfaced non-blocking until triaged; remediation is deliberate (live prod service). ## Orphan defipod URL (flagged, not fixed) @@ -30,6 +30,5 @@ Go module path is `github.com/defipod/mochi` , a `defipod` reference inside a co ## What this PR changes -- `pkg/config/config.go`: scrub the 2 hardcoded secret defaults to `""` (the only code change; behavior = secrets now env-only). -- `.gitleaks.toml`, `.github/workflows/security.yml` (gitleaks + govulncheck), `CLAUDE.md`, `docs/ARCHITECTURE.md`, this record. -- No other logic touched, no dependency bumped. +- No code change: the config.go scrub this PR proposed was superseded by an upstream removal of both fields, and the CI hardening (`.gitleaks.toml`, `.github/workflows/security.yml`) was superseded by develop's own fix for the same gitleaks-license and govulncheck-toolchain failures. Both kept as-is from develop. +- Adds `CLAUDE.md`, `docs/ARCHITECTURE.md`, this record, and a README refresh.