FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: keys rotate, status Codex/Gemini checks, remote developer health (#20 #21 #22) by codeprakhar25 · Pull Request #26 · codeprakhar25/agentdiff · GitHub

feat: keys rotate, status Codex/Gemini checks, remote developer health (#20 #21 #22) - #26

Merged
codeprakhar25 merged 2 commits into
mainfrom
feat/issues-20-21-22
May 13, 2026
Merged

feat: keys rotate, status Codex/Gemini checks, remote developer health (#20 #21 #22)#26
codeprakhar25 merged 2 commits into
mainfrom
feat/issues-20-21-22

Conversation

codeprakhar25 commented May 13, 2026
edited
Loading

Copy link
Copy Markdown
Owner

What does this PR do?

Closes #20,
Closes #21,
Closes #22.

Issue #20 — agentdiff keys rotate

  • keys::archive_current_keypair: moves the active keypair into a timestamped folder under ~/.agentdiff/keys/archive/ with an archive.toml metadata file (key_id, archived_at, optional expires_at)
  • keys::try_load_archived_verifying_key: lets agentdiff verify fall back to the local archive when a key ID is absent from the git registry — ensures traces signed by rotated keys remain verifiable offline
  • keys rotate --resign-last N: re-signs the last N entries of the current branch's local trace buffer with the newly generated key

Issue #21 — agentdiff status Codex/Gemini enablement flags

  • Codex: after confirming the hook marker is present in ~/.codex/config.toml, additionally checks features.codex_hooks = true via TOML parse — warns with re-run hint if missing
  • Gemini: after confirming capture-antigravity is registered in settings.json, additionally checks tools.enableHooks = true via JSON parse — warns if the flag is absent (without it, Gemini ignores hooks even when entries are present)

Issue #22 — Per-developer health in agentdiff status --remote

  • Adds REMOTE TRACE BRANCHES table: one row per refs/agentdiff/traces/* ref with trace count, age, and stale (>7d) warning
  • Adds DEVELOPERS table: groups traces by AgentdiffMetadata.author, shows trace count and last-active age; stale developers highlighted in yellow
  • --since DURATION flag (e.g. 7, 7d, 48h) filters both tables to the active window

Type of change

  • New feature
  • Bug fix (Greptile review fixes applied)

Greptile bugs addressed

  • archive_current_keypair (src/keys.rs): removed redundant if pub_path.exists() re-check after the private key has already been renamed — the public key existence is guaranteed by the anyhow::ensure! above, so the re-check created a silent partial-archive path that would leave old-key traces unverifiable after rotation
  • status --remote Gemini arm (src/commands/status.rs): the (true, true) else branch was printing an ok()-prefixed line before the actual warn() — consolidated into a single warn() line so the output is not misleading

Testing

  • cargo check passes (no errors)
  • agentdiff status runs correctly (verified via post-commit hook output)

Checklist

  • Follows existing code style
  • No new dependencies (toml and serde_json were already in Cargo.toml)

github-actions Bot commented May 13, 2026
edited
Loading

Copy link
Copy Markdown

AgentDiff Report

Summary

Agent Lines %
cursor 487 99%
claude-code 3 1%

Review Context

  • Intent: unspecified (490 lines, 6 files)
    • Agent/model: claude-code, cursor / claude-sonnet-4-6, composer-2
    • Prompt: You are picking up a task from another AI agent. Read the handoff document at .relay/handoffs/HANDOFF-2026-05-13T14-45-47-57be9f.md carefully before doing ..., so I continued the working on the issue with another agent and raised a PR can you see the PR and comments and code changes we did to verify everyting was do...

Files To Review First

File Lines Dominant Agent Intent Context
src/commands/status.rs 257 cursor unspecified trace 508a58bd
src/keys.rs 136 cursor unspecified trace 508a58bd
src/commands/keys.rs 64 cursor unspecified trace 508a58bd
src/commands/verify.rs 19 cursor unspecified trace 508a58bd
src/cli.rs 13 cursor unspecified trace 508a58bd
src/main.rs 1 cursor unspecified trace 508a58bd
Trace details
Trace Agent Intent Files Lines
508a58bd cursor unspecified src/cli.rs, src/commands/keys.rs, src/commands/status.rs, src/commands/verify.rs, src/keys.rs, +1 more 487
d1465c95 claude-code unspecified src/commands/status.rs, src/keys.rs 3

greptile-apps Bot commented May 13, 2026
edited
Loading

Copy link
Copy Markdown

Greptile Summary

This PR replaces the old .key.bak rotation strategy with a proper timestamped archive under ~/.agentdiff/keys/archive/, allowing agentdiff verify to fall back to locally-archived keys when the git registry has no entry for a rotated key ID. It also adds an optional --resign-last N flag to re-sign recent local trace entries with the new key after rotation, and extends agentdiff status with a remote developer health table and a --since filter.

  • Key archiving (keys.rs, commands/keys.rs): rotation now moves the old keypair into a dated subdirectory with an archive.toml manifest; try_load_archived_verifying_key scans that directory during verification, falling back to the public key file for legacy (pre-manifest) folders.
  • --resign-last N (commands/keys.rs): re-signs the tail of the current branch's local JSONL trace buffer with the new key using an in-place std::fs::write, which is not atomic and can corrupt the file on a mid-write failure.
  • Status improvements (commands/status.rs, cli.rs): adds Gemini tools.enableHooks and Codex features.codex_hooks validation, a per-ref and per-developer activity table from remote trace branches, and --since duration filtering.

Confidence Score: 4/5

Safe to merge after addressing the non-atomic write in the re-sign path.

The key archiving and verify fallback logic are sound. The one concrete defect is in resign_last_local_traces: it uses std::fs::write directly on the live trace file, which truncates before writing — a disk-full or I/O error mid-write silently destroys all trace lines, including those not being re-signed. An atomic write (write to a .tmp sibling, then rename) would eliminate this risk.

src/commands/keys.rs — the resign_last_local_traces write path.

Important Files Changed

Filename Overview
src/commands/keys.rs Rotation now archives instead of .bak-renaming keys; new resign_last_local_traces uses a non-atomic std::fs::write that can corrupt the trace buffer if interrupted mid-write.
src/keys.rs New archive_current_keypair and try_load_archived_verifying_key functions implement a proper timestamped archive; minor double Utc::now() call produces a slight timestamp inconsistency between the directory name and archive.toml.
src/commands/verify.rs Falls back to the local archive via try_load_archived_verifying_key when the git registry has no entry for a key ID; clean two-level lookup without regressions.
src/commands/status.rs Adds Gemini tools.enableHooks and Codex features.codex_hooks checks, remote developer health table, and --since filter; --since parsing accepts negative integers only caught by the downstream ensure!.
src/cli.rs Adds RotateKeysArgs with optional --resign-last and --since to StatusArgs; straightforward CLI plumbing.
src/main.rs One-line change to destructure Rotate(args) and pass &args to run_rotate; no issues.

Reviews (2): Last reviewed commit: "fix: address Greptile review bugs in arc..." | Re-trigger Greptile

Comment thread src/keys.rs Outdated
Comment thread src/commands/status.rs
- keys.rs: remove redundant pub_path.exists() guard after private key
  rename — public key existence is already ensured before the rename,
  so re-checking creates a silent partial-archive path that leaves old
  traces unverifiable after rotation
- status.rs: fix misleading ok() prefix in Gemini (true,true) arm when
  tools.enableHooks is not set; consolidate into a single warn() line

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
codeprakhar25 changed the title fix: updates keys lifecycle feat: keys rotate, status Codex/Gemini checks, remote developer health (#20 #21 #22) May 13, 2026
codeprakhar25 merged commit e11a569 into main May 13, 2026
3 checks passed
codeprakhar25 deleted the feat/issues-20-21-22 branch May 13, 2026 18:34
Comment thread src/commands/keys.rs
Comment on lines +106 to +130
let raw = std::fs::read_to_string(&path)
.with_context(|| format!("reading {}", path.display()))?;
let mut lines: Vec<String> = raw.lines().map(String::from).collect();
while lines.last().map(|l| l.trim().is_empty()).unwrap_or(false) {
lines.pop();
}
anyhow::ensure!(!lines.is_empty(), "local trace buffer is empty");

let take = n.min(lines.len());
let start = lines.len() - take;
for i in start..lines.len() {
let mut val: serde_json::Value = serde_json::from_str(&lines[i])
.with_context(|| format!("parsing trace line {}", i + 1))?;
if let Some(obj) = val.as_object_mut() {
obj.remove("sig");
}
let sig = keys::sign_record(&val)?;
val.as_object_mut()
.context("trace entry must be a JSON object")?
.insert("sig".to_string(), serde_json::to_value(&sig)?);
lines[i] = serde_json::to_string(&val)?;
}

std::fs::write(&path, lines.join("\n") + "\n")
.with_context(|| format!("writing {}", path.display()))?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Non-atomic write can corrupt the trace buffer on failure

std::fs::write opens the file with O_TRUNC, zeroing its contents before writing the new data. If the write is interrupted (e.g. disk-full mid-write, process killed, I/O error), the file is left truncated and partially written — all original trace lines, including the ones not being re-signed, are lost. Because this is an audit-trail store, a silently half-written file is worse than a failed write.

The fix is to write to a .tmp sibling and atomically replace the original via std::fs::rename.

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

Labels

None yet

Projects

None yet

1 participant


Back | FazBrowse Home | New Git URL