Skip to content

[codex] Preserve unrelated crontab entries#38

Merged
Pectics merged 1 commit into
mainfrom
codex/issue-2-preserve-crontab-entries
Jun 24, 2026
Merged

[codex] Preserve unrelated crontab entries#38
Pectics merged 1 commit into
mainfrom
codex/issue-2-preserve-crontab-entries

Conversation

@Pectics

@Pectics Pectics commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Summary

  • Preserve unrelated user crontab entries when running mihoro cron enable or mihoro cron disable.
  • Manage Mihoto auto-update through stable # mihoto: begin/end auto-update markers and migrate exact legacy current-binary entries.
  • Read live crontab state for mihoro cron status, with backup, post-write verification, and rollback around writes.

Closes #2.

Upstream references

Safety differences from upstream PR #197

  • Uses explicit Mihoto-managed marker lines instead of substring ownership detection.
  • Quotes the executable path in the generated cron command.
  • Distinguishes missing crontab from other crontab -l failures.
  • Saves a pre-write backup under the user state/cache area and verifies live crontab state after writes.
  • Attempts rollback from the in-memory backup if post-write verification fails.

Migration, security, and rollback impact

  • Existing unmarked cron entries for the exact current Mihoto binary are removed during enable/disable to prevent duplicate auto-update jobs.
  • Unrelated crontab lines, comments, and similar commands are preserved.
  • Backup files contain the previous crontab contents and are not printed to logs.
  • No CLI syntax changes and no README update was needed because command usage remains unchanged.

Verification

  • cargo test cron -- --nocapture
  • cargo test
  • cargo fmt --all -- --check
  • cargo clippy
  • cargo check --all-targets

Use marked Mihoto cron blocks so enable, disable, and status operate on owned entries without replacing unrelated user jobs. Add backup, verification, rollback, and legacy-entry cleanup around crontab writes.

Verification:
- cargo test cron -- --nocapture
- cargo test
- cargo fmt --all -- --check
- cargo clippy
- cargo check --all-targets

Co-Authored-By: Codex GPT-5 <noreply@openai.com>
@Pectics Pectics marked this pull request as ready for review June 24, 2026 09:01
Copilot AI review requested due to automatic review settings June 24, 2026 09:01
@Pectics Pectics merged commit faaa498 into main Jun 24, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens mihoro cron management so enabling/disabling auto-update preserves unrelated user crontab lines, using stable Mihoto-owned marker blocks plus migration from legacy “current binary” entries, and adding backup + verification/rollback around writes.

Changes:

  • Introduces Mihoto-managed # mihoto: begin/end auto-update markers and merges/removes only the managed block.
  • Reads live crontab -l state for status/enable/disable, with legacy entry migration to prevent duplicates.
  • Adds pre-write backups and post-write verification with rollback on failure.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/cron.rs
Comment on lines +255 to +267
fn verify_auto_update_enabled(expected_block: &str, bin_path: &str) -> Result<()> {
let snapshot = read_current_crontab()?;
if count_managed_cron_blocks(&snapshot.content) != 1 {
anyhow::bail!("Expected exactly one mihoto-managed cron block after enable");
}
if !snapshot.content.contains(expected_block) {
anyhow::bail!("Installed crontab does not contain the expected mihoto cron block");
}
if remove_legacy_current_binary_entries(&snapshot.content, bin_path) != snapshot.content {
anyhow::bail!("Installed crontab still contains a legacy mihoto cron entry");
}
Ok(())
}
Comment thread src/cron.rs
Comment on lines +238 to +245
fn write_crontab_backup(snapshot: &CrontabSnapshot) -> Result<PathBuf> {
let backup_path = crontab_backup_path();
if let Some(parent) = backup_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&backup_path, &snapshot.content)?;
Ok(backup_path)
}
Comment thread src/cron.rs
Comment on lines +37 to +41
let secs = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_secs())
.unwrap_or(0);
base.join("mihoro").join(format!("crontab-{}.bak", secs))
Comment thread src/cron.rs
Comment on lines +206 to +214
fn install_crontab(content: &str) -> Result<()> {
let crontab_file = crontab_path();
fs::write(&crontab_file, content)?;
let status = Command::new("crontab").arg(&crontab_file).status()?;
if !status.success() {
anyhow::bail!("Failed to install crontab");
}
Ok(())
}
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.

Preserve unrelated crontab entries when enabling or disabling updates

2 participants