Enterprise Readiness Assessment¶
1. Executive summary¶
Verdict: A small, narrowly-scoped admin API forked from someli-api's skeleton. The codebase is manageable (~2400 LoC of routes vs someli-api's 22 000+), but suffers from the same patterns: no tests, weak observability, mixed auth schemes, and shared-helper drift. It has the least deploy infrastructure of the four backends — no Dockerfile, no CI workflow committed in the repo. There are two high-severity security findings (hardcoded session secret, hardcoded Slack token) that should be addressed this week.
Top 3 strengths:
1. Small surface — only 40 endpoints; easy to read; easy to refactor.
2. Sensible structure inherited from someli-api — server / routes / actions / helpers / middlewares is a known shape.
3. Modern admin FE — admin_console_R is on Vite + React + TS + shadcn/ui, a forward-looking stack that pairs well with a cleanup of this backend.
Top 5 risks:
1. Hardcoded credentials in source (Slack bot token; express-session secret)
2. No CI / no Dockerfile — deploys are ad-hoc
3. In-memory token revocation + no token expiry = effectively long-lived tokens, no real logout
4. Helper-code drift from someli-api (some helpers byte-identical, some heavily diverged) — bug fixes need coordination
5. Auth-by-SQL-filter — no requireRole middleware; new endpoints can accidentally expose admin data
Top 5 recommendations:
1. This week (Phase 0a): rotate Slack token; move session secret to env; move conf/credentials.json out of the repo (if committed)
2. Phase 0: add Dockerfile, CI workflow, /health endpoint, structured logging, request id middleware
3. Phase 0: introduce requireRole(...) middleware and apply per-router
4. Phase 1: extract the 4 byte-identical helpers (tokenGenerator, revokeToken, ragProcess, webScraping) into a shared npm package
5. Phase 1: prune ~20 unused dependencies (Passport, Twitter, Expo, path/fs/http/stream/url squatters)
2. Methodology & scope¶
Audited via find, cat, diff, grep, wc against the cloned someli-gh/Someli-admin-api/ directory. Compared against someli-api/ for shared lineage. No tests run (none exist).
3. Maturity assessment (CMMI 1–5)¶
| Pillar | Current | 12-mo target | Why |
|---|---|---|---|
| Architecture & Modularity | 2 | 3 | Small, comprehensible; needs requireRole middleware and route splitting (one 1400-line file is enough) |
| API Contract & Versioning | 1 | 2 | No OpenAPI; inconsistent path naming (/word:param vs /word/:param); typos in path names |
| Data Architecture | 2 | 2 | Same MySQL schema as platform; queries mostly parameterised; some dynamic-filter risk (F-8) |
| Background Processing | n/a | n/a | No jobs in this repo |
| Security & Compliance | 1 | 3 | Two hardcoded credentials; CORS wildcard; in-memory revocation; auth-by-SQL-filter |
| Observability | 1 | 3 | console.log only; no health, no metrics, no error tracking |
| Reliability & Resilience | 1 | 2 | sync-mysql blocks the event loop; no graceful shutdown |
| Scalability | 2 | 3 | Admin tool — low traffic by nature, so this is less acute |
| Testing & Quality Gates | 1 | 2 | Zero tests; no CI gate |
| CI/CD & Deployment | 1 | 3 | No Dockerfile, no Jenkins, no GHA in this repo |
| Infrastructure as Code | 1 | 2 | nothing |
| Cost Visibility & FinOps | 2 | 2 | Small footprint; not a top concern |
| Documentation & Knowledge Management | 2 | 3 | This audit covers the gap; needs OpenAPI |
| Team Practices & Governance | 2 | 3 | Branch model exists; no PR template, no code-owners file |
4. Findings (security-leading)¶
See security.md. Summary:
| ID | Severity | Description | Phase |
|---|---|---|---|
| F-1 | HIGH | Hardcoded express-session secret in server.js |
0a |
| F-2 | HIGH | Hardcoded Slack bot token in routes/auth.js |
0a |
| F-3 | MEDIUM | In-memory token revocation (cleared on restart) | 0 |
| F-4 | MEDIUM | Encrypted tokens have no expiry | 0 |
| F-5 | MEDIUM | CORS wildcard | 0 |
| F-6 | LOW | Webhook body-parser exemption with no handlers | 1 |
| F-7 | MEDIUM | Role gating via SQL only, no requireRole middleware |
0 |
| F-8 | MEDIUM | Possible SQL injection via dynamic filter interpolation (spot-check needed) | 0 |
| F-9 | LOW | 150 MB JSON body limit on unauthenticated endpoints | 0 |
| F-10 | HIGH (if true) | conf/credentials.json may be committed (Google service account) |
0a verify; then immediate rotation |
Non-security findings:
| ID | Severity | Description | Phase |
|---|---|---|---|
| N-1 | n/a | No tests, no CI | 0 |
| N-2 | n/a | No Dockerfile / no nginx config | 0 |
| N-3 | n/a | ~20 unused npm dependencies | 0a |
| N-4 | n/a | Two coexisting auth schemes (Bearer JWT + encrypted-token); pick one | 1 |
| N-5 | n/a | aws-sdk v2 in addition to v3; align |
2 |
| N-6 | n/a | Helper drift with someli-api: 4 files identical, 6 forked |
1 (extract identicals) |
5. Strategic decisions¶
- Where does admin logic live going forward? Two options:
- Keep it here: continue to evolve
Someli-admin-apias the admin scope grows. Pro: clean separation; small surface. Con: helper-drift compounds. - Fold it back into
someli-api: undo the fork; mount admin routes inside the main app, protected by a role check. Pro: zero drift; one runtime. Con: biggersomeli-api; admin work blocks on the main app's release cadence.
Audit recommendation: keep it here. The trend across the platform is more service separation, not less. But invest in the helper-extraction (Phase 1) so the drift becomes a fixed cost rather than growing.
-
Auth scheme consolidation. Bearer JWT vs encrypted-token. The admin FE uses encrypted-token; keep that, deprecate the JWT path. Remove
methods.js'sensureTokenonce nothing uses it. -
Observability investment. The admin tool is the smallest, lowest-traffic backend — the ideal pilot for adding Sentry + pino + request ids + Prometheus metrics. Patterns proven here can roll out to
someli-apilater.
6. Roadmap¶
Phase 0a — This week¶
- Rotate Slack token; move to
process.env.SLACK_BOT_TOKEN(F-2) - Move session secret to
process.env.SESSION_SECRET; throw if unset (F-1) - Verify whether
conf/credentials.jsonis committed; if so, rotate and gitignore (F-10) - Prune unused npm deps (
path,http,fs,stream,url,crypto,fetch, possiblyrequest,passport-*,twitter*,expo-server-sdk) (N-3)
Phase 0 — Stabilise (months 0–3)¶
- Add Dockerfile (copy/adapt from
someli-api) (N-2) - Add CI workflow (GitHub Actions; copy/adapt from
someli-api/.github/workflows/dev-api-deploy.yml) (N-2) - Add
/healthendpoint - Add morgan access logs
- Add request-id middleware
- Move token revocation to DB-backed store (F-3)
- Add
requireRole(...)middleware; apply per-router (F-7) - Audit dynamic-SQL filters; replace string interpolation with
?placeholders (F-8) - Tighten CORS to known FE origins (F-5)
- Tighten body-size limits on unauthenticated endpoints (F-9)
- Encode an
expclaim in the encrypted-token (F-4)
Phase 1 — Foundation (months 3–9)¶
- Extract
tokenGenerator.js,revokeToken.js,ragProcess.js,webScraping.jsto a shared internal npm package (N-6) - Sentry integration (or equivalent)
- Smoke tests + auth tests (N-1)
- OpenAPI spec generation
- Deprecate
methods.ensureTokenpath (Decision 2)
Phase 2 — Modular refactor (months 9–18)¶
- Split
routes/routes.jsandroutes/auth.jsby domain (personnel, accounts, marketing) (Pillar 1) - Migrate
aws-sdkv2 calls to v3 (Pillar 5) - Move from
mysql/sync-mysqltomysql2/promiseconsistently (Pillar 5)
Phase 3 — Selective extraction (months 18+)¶
- Only if needed: split into multiple admin services by domain (accounts, marketing, support tooling)
7. Risk register¶
| ID | Risk | Likelihood | Impact | Mitigation phase |
|---|---|---|---|---|
| R-1 | Leaked Slack bot token used by attacker for phishing in customer Slack | Medium | Medium | 0a |
| R-2 | Stale encrypted token replayed after intended logout (in-memory revocation) | Medium | Medium | 0 |
| R-3 | New endpoint shipped without role gating exposes admin data | Medium | High | 0 |
| R-4 | Helper drift causes a bug fix in someli-api not to apply here |
High | Medium | 1 |
| R-5 | sync-mysql blocks event loop during a heavy admin operation (e.g., getAllOwnerList with no filters) |
Medium | Medium | 2 |
| R-6 | No CI → manual deploy errors (wrong env, wrong branch) | Medium | Medium | 0 |
| R-7 | Production runs nodemon instead of node (because that's what start does) |
Low | Medium | 0 |
8. Standards compliance¶
- OWASP A02 Cryptographic Failures: encrypted-token format with no expiry; AES key handling not audited
- OWASP A04 Insecure Design: in-memory revocation; auth-by-SQL-filter; CORS wildcard
- OWASP A05 Security Misconfiguration: hardcoded credentials; default config
- OWASP A07 Identification & Authentication Failures: long-lived tokens; weak logout
9. Open questions¶
See verify-markers.md.