Skip to content

fix(remove): validate config capability names; delete only a strict child (PHARN-01) - #195

Merged
PrzemekGalarowicz merged 1 commit into
mainfrom
claude/bold-archimedes-5czyyn
Sep 24, 2026
Merged

PrzemekGalarowicz merged 1 commit into
mainfrom
claude/bold-archimedes-5czyyn

Conversation

@PrzemekGalarowicz

Copy link
Copy Markdown
Member

What this changes

A hand-edited pharn.config.json entry such as {"name":"../..","role":"lens"} made pharn remove ../.. recursively delete the whole project root, .git included. A name like ../../src deleted src/, and the interactive picker was affected the same way. Two causes: capability name/role were never validated at ingest, and safeJoin accepts the base directory itself.

  • Ingest (src/lib/pharn-config.ts): every capabilities[] entry must now be an object whose name matches CAPABILITY_NAME_RE (no control chars) and whose role is griller|lens. Otherwise config loading throws the new named CapabilityEntryError. It joins isConfigValidationError, so every command exits 1 and names the offending entry. No config this CLI ever wrote is newly rejected, because names come from the already-validated index.
  • Delete (src/commands/remove.ts, src/lib/validate.ts): the delete now goes through the new safeChildJoin, which returns only a single-segment child of the role subtree — never the base itself, never a deeper path. This is a second, independent check.
  • Docs: CLAUDE.md, SECURITY.md.

Built via /pharn-dev-ship; stage artifacts are in .dev/features/config-capability-name-validation/. Results:

  • validate: exit 0
  • regress: no-regressions
  • verify: PASS

Type of change

  • feat — new stack option, wizard step, or command capability
  • fix — bug fix
  • docs — docs-only change
  • chore / refactor — tooling or internal restructure, no behavior change

Area(s) touched

commands/remove | lib/validate | lib/pharn-config | docs (CLAUDE.md, SECURITY.md)

Checklist

  • Read the existing file(s) before editing; followed the ESM .js-extension import convention.
  • Updated the matching tests/*.test.ts (pharn-config, validate, remove). 38 of the new cases fail on the old source.
  • Updated the relevant docs.
  • Preserved the security invariants in src/lib/validate.ts; this PR adds safeChildJoin and does not change safeJoin.

Quality gates

  • npm run check passes locally (1277/1277 tests; run as a non-root user on node 22).
  • npm run build succeeds.
  • npm run test:coverage passes.

Notes for the reviewer

Start with validateCapabilityEntries and safeChildJoin. The remaining /pharn-dev-review findings are advisory and not addressed here (details in .dev/features/config-capability-name-validation/REVIEW.md):

  • no CHANGELOG entry;
  • the defense-in-depth refusal surfaces as an uncaught error on a path that should be unreachable;
  • list --json is covered only via the shared error union.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc


Generated by Claude Code

…hild (PHARN-01)

A hand-edited `pharn.config.json` entry such as `{"name":"../..","role":"lens"}`
made `pharn remove ../..` recursively delete the project root (including
`.git`): capability names were never validated at ingest, and `safeJoin`
accepts the base directory itself.

- `readPharnConfig` now validates every `capabilities[]` entry: an object whose
  `name` matches `CAPABILITY_NAME_RE` (no control characters) and whose `role`
  is `griller|lens`, else the new named `CapabilityEntryError` (joins
  `isConfigValidationError`, so every command exits 1 with the offender named).
- `remove` deletes through the new `safeChildJoin`, which only returns a
  single-segment child of the role subtree — a second, independent floor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvcuVhk8hTeDskp5pAJhnc
@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 1edddd41-97ba-42e0-8e81-5afc8cbe23b0


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@PrzemekGalarowicz
PrzemekGalarowicz merged commit 2b74a74 into main Sep 24, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants