diff --git a/.claude/agent-memory/review-review-issue-fixer/MEMORY.md b/.claude/agent-memory/review-review-issue-fixer/MEMORY.md new file mode 100644 index 0000000..4a794a8 --- /dev/null +++ b/.claude/agent-memory/review-review-issue-fixer/MEMORY.md @@ -0,0 +1,3 @@ +# Agent Memory Index + +- [project_firestore_adapter.md](project_firestore_adapter.md) — Firestore adapter fix patterns and decisions for this PR diff --git a/.claude/agent-memory/review-review-issue-fixer/project_firestore_adapter.md b/.claude/agent-memory/review-review-issue-fixer/project_firestore_adapter.md new file mode 100644 index 0000000..ec4e840 --- /dev/null +++ b/.claude/agent-memory/review-review-issue-fixer/project_firestore_adapter.md @@ -0,0 +1,19 @@ +--- +name: Firestore adapter fix patterns +description: Fix patterns and design decisions applied during PR review for the @please-auth/firestore adapter +type: project +--- + +Key fix decisions applied to this adapter: + +1. **Fail-closed defaults**: `matchesClientFilter` default changed to `return false`; `applyOperator` default changed to `return null` (forces client-side). Unknown operators should never silently pass records. + +2. **Transaction-aware bulk operations**: `updateMany`/`deleteMany` now check the `transaction` closure variable and use `transaction.update()`/`transaction.delete()` per-doc instead of `db.batch()` when inside a transaction. + +3. **Batch partial-failure error enrichment**: `batchDelete`/`batchUpdate` wrap each `batch.commit()` in try-catch and throw an error with `committedCount` and `totalCount` properties. + +4. **No re-read after create**: `create()` returns data directly using `docToRecord(id, docData, mapper)` instead of doing a redundant `docRef.get()` after `docRef.set()`. + +5. **Custom model name warning**: `getCollectionRef` default case logs a `console.warn` for unknown model names before the passthrough, since better-auth plugins may use custom collections. + +**Why:** These fixes reduce Firestore read costs, ensure correctness inside transactions, and make the adapter fail-closed rather than fail-open on unknown operators. diff --git a/.claude/agent-memory/review-review-security-reviewer/MEMORY.md b/.claude/agent-memory/review-review-security-reviewer/MEMORY.md new file mode 100644 index 0000000..b02c021 --- /dev/null +++ b/.claude/agent-memory/review-review-security-reviewer/MEMORY.md @@ -0,0 +1,3 @@ +# Agent Memory Index + +- [project_firestore_adapter.md](./project_firestore_adapter.md) — Firestore adapter for better-auth: architecture, security patterns, and key findings diff --git a/.claude/agent-memory/review-review-security-reviewer/project_firestore_adapter.md b/.claude/agent-memory/review-review-security-reviewer/project_firestore_adapter.md new file mode 100644 index 0000000..a348965 --- /dev/null +++ b/.claude/agent-memory/review-review-security-reviewer/project_firestore_adapter.md @@ -0,0 +1,27 @@ +--- +name: project_firestore_adapter +description: Firestore adapter for better-auth — architecture, security review findings, and key patterns +type: project +--- + +This is a new Firestore adapter package for the better-auth library (branch: amondnet/minsu-lee/add-firestore-adatper). + +Key files: +- packages/firestore/src/adapter.ts — main adapter logic (CRUD operations) +- packages/firestore/src/utils.ts — where clause processing, field mapping, batch ops +- packages/firestore/src/firestore.ts — Firebase app init helper +- packages/firestore/src/types.ts — config types, snake_case field maps + +**Why:** Adding Firestore as a supported database backend for better-auth. + +**How to apply:** Security review was performed 2026-03-24. Key findings: + +1. IMPORTANT: `updateMany` and `deleteMany` have no result limit on the initial Firestore query (query.get() without .limit()), allowing unbounded reads that can be weaponized for DoS if `where` clauses don't match at the Firestore layer and fall through to client-side filtering. See adapter.ts lines 301-302 and 361-362. + +2. IMPORTANT: `getCollectionRef` falls through to `db.collection(model)` for unknown model names, meaning any unvalidated model name from the adapter interface is used directly as a Firestore collection path. See utils.ts line 84. + +3. IMPORTANT (design): `findOne` with client-side filters fetches up to 100 docs from Firestore when clientFilters are present (adapter.ts line 141). No upper bound validation means large fetch windows on complex queries. + +4. No hardcoded secrets or credentials found. Credential handling delegates entirely to Firebase Admin SDK (Application Default Credentials or explicit AppOptions). + +5. The `matchesClientFilter` default case returns `true` (utils.ts line 288), meaning unknown operators silently allow all records through — a logic bypass if new operators are added to CleanedWhere without updating the switch. diff --git a/.gitignore b/.gitignore index 2ec158c..ddfdb10 100644 --- a/.gitignore +++ b/.gitignore @@ -234,6 +234,9 @@ Network Trash Folder Temporary Items .apdisk +### Please state +.please/state/ + ### Turborepo .turbo diff --git a/.mise.toml b/.mise.toml index 6cc01cc..2a35271 100644 --- a/.mise.toml +++ b/.mise.toml @@ -9,5 +9,9 @@ run = "bunx --bun commitlint --edit" description = "Set up git hooks" run = """ bun install -mise generate git-pre-commit --hook commit-msg --task commit-msg --write +if [ -d .git ]; then + mise generate git-pre-commit --hook commit-msg --task commit-msg --write +else + echo "Skipping hook setup (worktree detected)" +fi """ diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index 86f2f5e..0000000 --- a/commitlint.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = { - extends: ['@commitlint/config-conventional', '@commitlint/config-workspace-scopes'], - rules: { - 'subject-case': [0], - }, -};