ホーム / Skills / 開発効率化 / Caveman Review コードレビュー
開発効率化

Caveman Review コードレビュー

Julius BrusseeApache-2.0Skill の言語: 英語
ライセンス確認済みスクリプトなし
デモ実行記録 · claude-opus-5-5 · 2026年10月
Please review the diff before I merge it: ```diff --- a/src/orders/service.ts +++ b/src/orders/service.ts @@ -12,14 +12,24 @@ export class OrderService { async getOrderTotal(orderId: string): Promise<number> { - const order = await this.repo.findById(orderId); - return order.items.reduce((sum, i) => sum + i.price * i.qty, 0); + const order = await this.repo.findById(orderId); + let total = 0; + for (let i = 0; i <= order.items.length; i++) { + total += order.items[i].price * order.items[i].qty; + } + return total; } async applyCoupon(orderId: string, code: string) { - const coupon = await this.coupons.find(code); + const coupon = this.coupons.find(code); if (coupon.expiresAt < Date.now()) throw new Error("expired"); - await this.repo.update(orderId, { couponId: coupon.id }); + this.repo.update(orderId, { couponId: coupon.id }).catch(() => {}); } + + async listOrders(userId: string) { + return this.db.query(`SELECT * FROM orders WHERE user_id = '${userId}'`); + } } ```
Skill: caveman-review

I wouldn't merge this yet. There are 3 bugs that will break things, 1 SQL injection, and 1 risk. The original code was correct before this change.

src/orders/service.ts

  • L15: 🔴 bug: the loop runs one step too far. i <= order.items.length reads order.items[length], which is undefined, so .price throws a TypeError on every call. Use <, or keep the original reduce, which was correct and shorter.
  • L22: 🔴 bug: await was removed from this.coupons.find(code), so coupon is now a Promise. coupon.expiresAt is undefined and undefined < Date.now() is false, so the expiry check never fires and expired coupons are accepted. coupon.id is also undefined. Put the await back.
  • L24: 🔴 bug: the update is fire-and-forget and .catch(() => {}) hides any failure. Callers see success even when the coupon was never saved, and nothing is logged. Put back await this.repo.update(...) and let errors reach the caller.
  • L22-23: 🟡 risk: if find returns null for an unknown code, coupon.expiresAt throws a TypeError instead of a clear error. Add if (!coupon) throw new Error("invalid coupon").

L28: 🔴 security: SQL injection in listOrders. userId is put straight into the SQL string. A value like ' OR '1'='1 returns every user's orders, and with stacked queries an attacker could change or delete data (CWE-89, OWASP A03). Even if userId comes from an auth token today, this function can't assume that, and a single caller passing a request param makes it exploitable. Use a parameterized query, e.g. this.db.query("SELECT * FROM orders WHERE user_id = $1", [userId]) (use whatever placeholder syntax your driver expects).

  • L28: 🔵 nit: SELECT * returns every column and will pick up any column added later. List the columns you need.
  • L27: 🔵 nit: no return type, unlike getOrderTotal. Add Promise<Order[]>.

Real run recorded with claude-code / claude-opus-5-5. Output is shown verbatim, unmodified.

できること

コードレビューのコメントを L<行>: <問題>. <修正>. という短い形式で書き、そのまま Pull Request に貼れる形で出力します。

仕組み

  1. /caveman-review、"review this PR"、"review the diff" で起動します。
  2. 指摘ごとに 1 行。正確な行番号、バッククォートで囲んだシンボル名、具体的な修正方法を書き、必要に応じて重要度タグ(🔴 バグ、🟡 リスク、🔵 細かい指摘、❓ 質問)を付けます。
  3. ぼかした言い回しや diff の説明の繰り返しを省きます。セキュリティ問題、設計上の意見の相違、新しいメンバー向けの説明では、きちんとした段落で書きます。

向いている場面

diff や Pull Request をレビューし、指摘をすばやく読みたいとき。

知っておきたいこと

コメントを書くだけです。コードの修正、承認や変更要求、リンターの実行は行いません。

補足とリスク

指示だけのファイルです。スクリプトはなく、ネットワーク接続もファイルの書き込みも行いません。 パッケージには元リポジトリの README、LICENSE、NOTICE も含まれます。 レビューの指摘はモデルの出力です。投稿する前に確認してください。

SKILL.md 原文パッケージ内 4 ファイル