Skip to content

fix: re-verify security findings + doctor API-key logic in skill mode#19

Merged
derek-palmer merged 4 commits into
mainfrom
feat/skill-mode-prompt-only
May 26, 2026
Merged

fix: re-verify security findings + doctor API-key logic in skill mode#19
derek-palmer merged 4 commits into
mainfrom
feat/skill-mode-prompt-only

Conversation

@derek-palmer
Copy link
Copy Markdown
Owner

@derek-palmer derek-palmer commented May 26, 2026

Summary

  • Security re-verification: Checked all 19 H/M/L findings from the prior security review against post-v0.4.2 code. 17 were already fixed; 2 addressed in this PR.
  • L5 fixed: counts.get() was redundant on a pre-initialized dict in format_report; replaced with counts[f.severity] += 1.
  • Task 2 (doctor API-key logic): _check_provider_api_key was adding a --prompt-only hint conditionally when _skill_mode_active() was true, making the Finding differ from outside-skill-mode. When a provider is explicitly configured in forerunner.config.yaml, a missing API key is always a real failure — skill mode should not change the severity or message. Removed the conditional; warn path now always emits the same Finding regardless of skill mode. No-config + skill-mode path correctly returns ok (unchanged — no explicit provider means no API key needed).

Security finding status table

Finding Status Action
H1 — arbitrary Python exec in doctor fixed --run-scripts gate in place
H2 — npx paths unpinned fixed codeforerunner@0.4.1 / v0.4.1 pinned in install.sh + install.ps1
H3 — Google API key in URL query string fixed comment in google.py explaining this is documented/required
M1 — wrong YAML structure for enabled_rules fixed tasks.check.enabled_rules correct in _STARTER_CONFIG and config.py
M2 — path traversal in MCP name param fixed /, \\, .. blocked + is_relative_to check
M3 — thread-unsafe sys.stdout swap fixed no sys.stdout swap in cli.py
M4 — no HTTP timeout in providers fixed timeout=120 on all urlopen calls
M5 — dead any_error flag fixed flag set on errors in installer.py
M6 — int() raises ValueError not ConfigError fixed _to_int wraps into ConfigError
M7 — SSRF via OLLAMA_HOST fixed _validate_ollama_base in ollama.py
L1 — assert span is not None fixed RuntimeError raised instead
L2 — dead config fields fixed not present in ForerunnerConfig
L3 — sys.modules pollution fixed uuid suffix for unique module names
L4 — _description_for reads whole file fixed line-by-line iteration
L5 — redundant .get() on always-initialized dict fixed this PR counts[f.severity] += 1
L6 — MCP server doesn't enforce initialize first fixed _initialized flag + error response
L7 — regex metacharacters in extension needles fixed .includes() used
L8 — no stream test coverage fixed test_generate_stream_flag_yields_chunks exists
L9 — find_prompts_root walks to root fixed parents[:10] depth limit

Test plan

  • uv run python -m pytest tests/ -q → 196 passed, 1 skipped
  • New test: test_provider_api_key_warn_even_in_skill_mode_when_provider_explicit verifies warn is emitted when skill mode active + explicit provider + missing key

🤖 Generated with Claude Code

… generate

In skill mode (Claude Code, Codex, Gemini CLI, etc.) the host agent IS the
model — calling forerunner generate should output the assembled prompt bundle
for the agent to process, not make a provider API call.

Changes:
- `forerunner generate --prompt-only <task>`: outputs the assembled prompt
  bundle to stdout and exits; no API key or provider needed. This is the
  correct command for skill-mode use in all SKILL.md Execute sections.
- Auto-detect skill context: when no explicit provider is configured, no API
  key is set, and Ollama is not running, cmd_generate now emits the prompt
  bundle directly (exit 0) instead of erroring. On a TTY, adds a brief stderr
  hint; on piped stdout, emits cleanly with no extra output.
- `forerunner doctor`: "no API key" is now [ok] when a managed skill
  destination is installed (skill mode active) rather than [warn].
- All 26 per-task SKILL.md Execute sections updated:
  `forerunner doc <task>` → `forerunner generate --prompt-only <task>`
- Canonical skill body (agent/codeforerunner.skill.md) updated with skill-mode
  explanation and synced to both distribution copies.
- 194 tests pass (7 updated to reflect new behavior).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

📝 Walkthrough

Walkthrough

This PR implements "skill mode," enabling the host agent to assemble and emit prompt bundles via forerunner generate --prompt-only <task> without requiring external API keys or providers. The change unifies documentation instructions across 18 skill files, adds CLI support for prompt-only output and auto-detection when no API key is available, and includes health-check logic to suppress API-key requirements when managed skills are installed.

Changes

Skill Mode Feature

Layer / File(s) Summary
Skill Mode Detection and Health Reporting
src/codeforerunner/doctor.py
Introduces _skill_mode_active() helper that scans installed skill paths for managed markers. Updates provider-api-key checks to return ok findings when skill mode is detected, suppressing API-key warnings since the host agent handles generation.
CLI --prompt-only Flag and Skill Mode Auto-Detect
src/codeforerunner/cli.py
Adds --prompt-only flag to generate command that routes through cmd_doc to emit assembled prompt bundles to stdout. Implements auto-detect branch for missing-API-key scenarios: when no provider is configured and Ollama is unavailable, outputs the bundle with an interactive hint for TTY sessions.
Skill Mode Test Coverage
tests/test_cli.py, tests/test_doctor.py
Adds test cases verifying --prompt-only emits bundles without API calls, skill-mode auto-detect outputs bundles when no credentials are available, and explicit-provider scenarios still error with missing keys. Updates doctor tests to patch _skill_mode_active state for isolated verification.
Skill Documentation Updates
agent/codeforerunner.skill.md, skills/*/SKILL.md, plugins/codeforerunner/skills/*/SKILL.md
Consistent pattern updates across 18 SKILL.md files: replaces forerunner doc <task> instructions with forerunner generate --prompt-only <task> and clarifies that the generated stdout output is an assembled prompt bundle that the reader should then execute. Emphasizes distinction between skill mode (host-agent execution, no API key) and standalone CLI usage (provider-backed generation).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • derek-palmer/codeforerunner#11: Introduces the canonical agent/codeforerunner.skill.md contract that this PR updates to define the new forerunner generate --prompt-only workflow.
  • derek-palmer/codeforerunner#14: Earlier prompt-bundle assembly updates affecting the same documentation files and CLI workflow patterns that this PR refactors.

Poem

🐰 Hoppy days of skill-free keys!
No API calls, if you please;
Prompt bundles skip the wire,
Host agents handle their desire.
Docs rewritten, clean and bright,
Skill mode shining, oh what a sight!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The PR title claims to 're-verify security findings + doctor API-key logic' but the actual changes focus on adding --prompt-only flag, skill-mode auto-detect, and updating documentation to use the new CLI workflow. Update the title to reflect the primary change: e.g., 'feat: add --prompt-only flag and skill-mode auto-detect' or 'feat: implement skill-mode auto-detect with --prompt-only flag'.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/skill-mode-prompt-only
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/skill-mode-prompt-only

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/codeforerunner/doctor.py`:
- Around line 299-306: The current early return that emits Finding("ok",
"provider-api-key", ...) when _skill_mode_active() is true hides missing API-key
failures for explicitly configured providers; instead, change the logic in the
doctor check so that _skill_mode_active() only suppresses the missing-key
warning for providers that are not explicitly/configured, and if the provider is
configured (the same provider used by generate in cli.py), emit a failing
Finding indicating the API key is missing. In practice, remove or adjust the
unconditional return under _skill_mode_active(), add a check for whether the
provider is explicitly configured (the same condition used by generate in
cli.py), and if configured create a non-"ok" Finding reporting the missing
env_var; otherwise keep the skill-mode "ok" behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 742b7136-d1bd-4888-a81f-cf69c40f8df3

📥 Commits

Reviewing files that changed from the base of the PR and between 174cde0 and 3ba9345.

📒 Files selected for processing (31)
  • agent/codeforerunner.skill.md
  • plugins/codeforerunner/skills/codeforerunner/SKILL.md
  • plugins/codeforerunner/skills/forerunner-api-docs/SKILL.md
  • plugins/codeforerunner/skills/forerunner-audit/SKILL.md
  • plugins/codeforerunner/skills/forerunner-changelog/SKILL.md
  • plugins/codeforerunner/skills/forerunner-check/SKILL.md
  • plugins/codeforerunner/skills/forerunner-diagrams/SKILL.md
  • plugins/codeforerunner/skills/forerunner-flows/SKILL.md
  • plugins/codeforerunner/skills/forerunner-init/SKILL.md
  • plugins/codeforerunner/skills/forerunner-readme/SKILL.md
  • plugins/codeforerunner/skills/forerunner-review/SKILL.md
  • plugins/codeforerunner/skills/forerunner-scan/SKILL.md
  • plugins/codeforerunner/skills/forerunner-stack-docs/SKILL.md
  • plugins/codeforerunner/skills/forerunner-version-audit/SKILL.md
  • skills/codeforerunner/SKILL.md
  • skills/forerunner-api-docs/SKILL.md
  • skills/forerunner-audit/SKILL.md
  • skills/forerunner-changelog/SKILL.md
  • skills/forerunner-check/SKILL.md
  • skills/forerunner-diagrams/SKILL.md
  • skills/forerunner-flows/SKILL.md
  • skills/forerunner-init/SKILL.md
  • skills/forerunner-readme/SKILL.md
  • skills/forerunner-review/SKILL.md
  • skills/forerunner-scan/SKILL.md
  • skills/forerunner-stack-docs/SKILL.md
  • skills/forerunner-version-audit/SKILL.md
  • src/codeforerunner/cli.py
  • src/codeforerunner/doctor.py
  • tests/test_cli.py
  • tests/test_doctor.py

Comment thread src/codeforerunner/doctor.py Outdated
derek-palmer and others added 3 commits May 25, 2026 21:52
…in skill mode

doctor was returning [ok] when skill mode active + provider configured +
key missing. forerunner generate (without --prompt-only) still refuses to
run in that case, so the ok was misleading. Now always emits warn; appends
a --prompt-only hint when skill mode is detected so the user knows the
key-free path exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Kept origin/main's _get_bundle(ns) → bundle structure in cmd_generate
and the stream test added by the model-default PR.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…curity findings

- Remove skill-mode conditional hint from _check_provider_api_key warn path.
  When a provider is explicitly configured in forerunner.config.yaml, a missing
  API key is always a real problem — skill mode does not excuse it.
  No-config + skill-mode-active path correctly returns ok (unchanged).
- Fix L5: replace redundant counts.get() with direct += on pre-initialized dict.
- Add test: explicit provider + skill mode active + missing key → warn (not ok).

Security finding verification (all H/M/L from review):
H1 fixed (--run-scripts gate), H2 fixed (npx pinned @0.4.1), H3 fixed (comment),
M1-M7 fixed, L1-L9 fixed (L5 fixed in this commit; all others verified present).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@derek-palmer derek-palmer changed the title feat: add --prompt-only flag and skill-mode auto-detect fix: re-verify security findings + doctor API-key logic in skill mode May 26, 2026
@derek-palmer derek-palmer merged commit b99751c into main May 26, 2026
3 checks passed
@derek-palmer derek-palmer deleted the feat/skill-mode-prompt-only branch May 26, 2026 13:35
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.

1 participant