Skip to content

fix(cron,mcp): allow day/month names in cron, prune output files, secure OAuth writes#6670

Open
aaronlab wants to merge 1 commit into
NousResearch:mainfrom
aaronlab:fix/cron-regex-oauth-perms-output-pruning
Open

fix(cron,mcp): allow day/month names in cron, prune output files, secure OAuth writes#6670
aaronlab wants to merge 1 commit into
NousResearch:mainfrom
aaronlab:fix/cron-regex-oauth-perms-output-pruning

Conversation

@aaronlab

@aaronlab aaronlab commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • cron/jobs: broaden cron schedule validation regex to accept standard day/month names (MON-FRI, JAN, etc.)
  • cron/jobs: add output file pruning (keep last 100 per job) to prevent unbounded disk growth
  • mcp_oauth: eliminate TOCTOU permission window on OAuth token files

Details

Cron regex rejects valid day/month names (MEDIUM)

The pre-validation regex r'^[\d\*\-,/]+$' only allows digits and special chars. Standard cron expressions like 0 9 * * MON-FRI contain alphabetic day names that fail this regex, falling through to the duration/timestamp parsers and raising "Unrecognized schedule format". croniter itself fully supports these names.

Fix: change character class to [\d\w\*\-,/] to allow letters. Actual validation is still done by croniter().

Cron output directory grows without bound (MEDIUM)

Every job execution writes ~/.hermes/cron/output/{job_id}/{timestamp}.md. No cleanup exists — a 5-minute job creates ~105K files/year. remove_job() doesn't clean the output directory either.

Fix: add _prune_job_output() that keeps the newest 100 files per job, called after each save.

MCP OAuth token TOCTOU (MEDIUM)

_write_json() uses Path.write_text() which creates files with the process umask (typically 0o644, world-readable). os.chmod(tmp, 0o600) runs afterward — between write and chmod, OAuth tokens (access/refresh) are readable by other users.

Fix: use os.open(path, O_WRONLY|O_CREAT|O_TRUNC, 0o600) + os.fdopen() to create the file with restricted permissions from the start (matching the pattern used in cron/jobs.py for job persistence).

Test plan

  • Verify parse_schedule("0 9 * * MON-FRI") succeeds
  • Verify output files are pruned to 100 after save
  • Verify OAuth token temp file has 0o600 permissions on creation
  • Run pytest tests/ -q

🤖 Generated with Claude Code

…s, secure OAuth token writes

- cron/jobs: broaden schedule validation regex from [\d\*\-,/] to
  [\d\w\*\-,/] so standard day/month names (MON-FRI, JAN, etc.) pass
  the pre-check and reach croniter for proper validation instead of
  being rejected as "Unrecognized schedule format"
- cron/jobs: add _prune_job_output() to cap output files at 100 per job
  after each save — without pruning, a 5-minute job creates ~105K files
  per year with no cleanup mechanism
- mcp_oauth: open token temp file with os.open(0o600) instead of
  Path.write_text + os.chmod, eliminating the TOCTOU window where OAuth
  tokens are world-readable between write and permission change

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cron Cron scheduler and job management tool/mcp MCP client and OAuth labels Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants