Safety/security fixes for auto-apply (dry-run side effects, agent sandboxing, screening answers, file perms)#59
Open
sebastianmukuria wants to merge 6 commits into
Conversation
- Dry-run prompt emits RESULT:DRYRUN, never RESULT:APPLIED - Email-only step does not send mail in dry-run; send_email tool disallowed - run_job recognizes DRYRUN (matched first); worker loop releases lock and falls through instead of marking applied - Guard against re-selecting the same released job forever (seen_urls) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Disallow Bash/Edit/Write/MultiEdit/NotebookEdit/WebFetch/WebSearch/Task/ KillShell built-ins (Read and Playwright/Gmail-send stay available) - Add a prompt-injection guard to the NEVER DO THESE prompt section Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Read age/background-check/felony/how-heard from profile['screening']; legally significant answers default to NOT PROVIDED (agent asks the human) - Drop hardcoded 'Previously Worked Here: No'; check it against resume history - Replace 'answer YES for same-domain tools' with honest skills-from-profile - Add screening section to profile.example.json and the init wizard Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SQLite NULL != 'in_progress' is NULL, so fresh jobs never matched the
target-URL query ('queue empty'). Select rows that are NULL or not
in_progress/applied, and exclude already-applied_at to prevent duplicates.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add config.write_private_text() (write + chmod 0600); use for profile.json, .env (all three write sites), generated prompt logs, and MCP configs - chmod the SQLite DB to 0600 in init_db; chmod APP_DIR to 0700 in ensure_dirs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Safety and security fixes for the auto-apply path, found during a pre-flight review of the codebase. This is 1 of 4 focused PRs from that review (safety, discovery/scoring, tailoring/apply output, setup) — each is independent and can be reviewed/merged on its own.
What & why
apply --dry-runis now genuinely side-effect-free. Previously a dry run still told the agent tosend_emailon the email-only path and to emitRESULT:APPLIED, which the launcher wrote to the DB asapply_status='applied'— permanently removing the job from the real queue. Dry run now emits a dedicatedRESULT:DRYRUN, sends no mail (the Gmail send tool is also disallowed in dry-run), and the worker releases the lock without marking applied. (apply/prompt.py,apply/launcher.py)bypassPermissions; the disallowed-tools list now also blocksBash/Edit/Write/MultiEdit/NotebookEdit/WebFetch/WebSearch/Task/KillShell(Read + Playwright + the Gmail tools it needs stay), and the prompt refuses instructions embedded in page content (prompt-injection guard). A malicious job page can no longer trivially run shell or exfiltrate~/.applypilot. (apply/launcher.py,apply/prompt.py)profile.screening, and unset legally significant answers are flagged for the human instead of guessed. The agent no longer claims experience with tools the candidate hasn't listed. (apply/prompt.py,wizard/init.py,profile.example.json)apply --urlqueue bug.apply_status != 'in_progress'isNULLfor fresh jobs in SQLite, so--urlalways reported "queue empty"; it also didn't exclude already-applied jobs (duplicate applications). Fixed the predicate. (apply/launcher.py)0600(profile.json,.env, prompt logs, MCP configs, the SQLite DB) and~/.applypilotis0700. (config.py,database.py,wizard/init.py,apply/launcher.py)Tests
Adds regression tests:
tests/test_dryrun.py,tests/test_prompt_screening.py,tests/test_acquire_job.py,tests/test_permissions.py(15 tests, all passing). CHANGELOG updated under[Unreleased].