Skip to content

fix(codex): safely unlink generated profiles - #7021

Merged
lidge-jun merged 4 commits into
lidge-jun:devfrom
luvs01:codex/upstream-profile-unlink-20261013
Oct 13, 2026
Merged

lidge-jun merged 4 commits into
lidge-jun:devfrom
luvs01:codex/upstream-profile-unlink-20261013

Conversation

@luvs01

@luvs01 luvs01 commented Oct 13, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Generated-profile cleanup refuses final-component symlinks before changing Codex configuration or recovery evidence. Regular profile removal uses the held configuration lock, canonical parent and identity rechecks; pathname unlink is not atomic against writers that ignore that lock.

Journal replay preserves the config/profile pair and recovery evidence for eligible symlinked profiles, including dangling generated links. ENOENT at the final type observation is treated as absence. Profile removal after config publication is covered by withConfigWriteRecovery, so a later refusal restores the owned config preimage.

The follow-up commit 798080e9ed39cc0d3ab4a86c1871fa13d65667ca retains the maintainer's d192960111a4a338da7ec17704fbe6af2ea4b55d merge of dev and adds the missing recovery cases. All seven files in the complete proposal match the verified source at cc7897e4576d159782cb26ef916dd84da4758d8c byte for byte.

Verification

On the final candidate contents, Windows and Bun 1.4.3 (c6da4a4d3):

  • bun test --isolate --timeout 60000 tests/codex-integration/codex-journal.test.ts tests/codex-integration/codex-journal-recovery.test.ts: 52 passed, 6 POSIX-only skipped, 0 failed; 318 assertions, 204.98 seconds.
  • The run includes rollback after a profile-removal refusal, dangling-link metadata refusal, and ENOENT at the final type observation. The POSIX real-symlink cases remain for hosted Linux validation; Windows skips do not establish Windows symlink behavior.
  • bun run typecheck, bun run structure:check, bun run privacy:scan, and git diff --check passed.
  • The original three regressions failed before the source fix and passed after it in source validation. This follow-up reran the two focused files against the actual integration candidate; it did not repeat the negative controls.
  • Full local and import-graph suites were not repeated under the repository resource exception: focused integration tests already take over three minutes and other worktrees share the runner. Broader hosted checks must be evaluated against this new HEAD. Previous-head CI is historical evidence, not a pass for this commit.

Keep this PR in Draft pending current-head CI and independent maintainer security review. No installed app, real account or user service was exercised.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • The Codex-home contract and focused regressions are updated.
  • Local validation and its platform limits are recorded.
  • Current-head required CI and explicit maintainer security review are complete.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

Summary by CodeRabbit

  • Bug Fixes

    • Codex configuration removal and recovery now refuse to modify profiles that are symbolic links, helping preserve configuration and recovery data.
    • Profile cleanup verifies the file before removing it and confirms it is gone afterward.
    • Removal now checks that the configuration has not changed since it was inspected, helping preserve concurrent edits and recovery data.
    • Recovery handles profiles that disappear during inspection without treating them as present.
  • Documentation

    • Clarified profile-removal safeguards and recovery behavior, including limitations when other processes modify files concurrently.

Refuse final-component profile symlinks before configuration or recovery
journal changes. Unlink the checked regular entry under its canonical
parent and preserve recovery evidence when its destination changes.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 468cd7dc-dc09-4b94-9226-957f46be9edd
📥 Commits

Reviewing files that changed from the base of the PR and between 798080e and 7c93614.

📒 Files selected for processing (4)
  • src/codex/config-write-lock.ts
  • src/codex/inject/remove.ts
  • structure/codex-home.md
  • tests/codex-integration/codex-journal-recovery.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

📝 Walkthrough

Codex profile removal now uses guarded cleanup and config-write recovery with preimage checks. Journal restoration checks profile paths for symbolic links before changing configuration or removing recovery evidence. Integration tests cover symlink handling, regular-profile restoration, and filesystem races.

Changes: Codex profile safety

Layer / File(s) Summary
Guarded profile removal
src/codex/config-write-lock.ts, src/codex/inject/config-write-section.ts, src/codex/inject/remove.ts, tests/codex-integration/codex-journal-recovery.test.ts, tests/codex-integration/codex-journal.test.ts
withConfigWriteRecovery can require a matching preimage. Profile removal validates the held lock and expected file identity before unlinking. removeCodexConfig rejects a symlinked profile when profile preservation is disabled and uses config-write recovery for existing config. Tests cover failed cleanup, concurrent edits, and preservation of config, profile, and journal state.
Journal restore checks
src/codex/journal.ts, tests/codex-integration/codex-journal-recovery.test.ts, tests/codex-integration/codex-journal.test.ts, structure/codex-home.md
Journal restoration checks the profile path before restoring config or removing the journal. A symlink causes an incomplete restore; an ENOENT race is treated as absence. Tests cover dangling symlinks and regular profiles. The documentation describes the preimage and identity checks and notes that advisory locking does not serialize non-cooperating edits.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 7c936

The change makes generated-profile removal refuse symlinks and restore config on failure, and no concrete merge-blocking risk was found. Confirm the hosted POSIX symlink tests pass before merging.

Pre-merge checks · Passed 4 · Failed 1

Failed Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 6 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title accurately describes the main change: generated-profile removal now performs safe unlinking with symlink and recovery protections.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 6 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Deterministic PR hygiene checks passed.

@github-actions github-actions Bot added the bug Something isn't working label Oct 13, 2026
lidge-jun and others added 2 commits October 13, 2026 00:18
Carry the verified rollback, dangling-link and ENOENT follow-up with focused journal regressions. Preserve the existing configuration lock and document its pathname race boundary.

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@lidge-jun
lidge-jun marked this pull request as ready for review October 13, 2026 09:15

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 798080e9ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/codex/inject/remove.ts Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-13T09:28:25.741988Z 798080e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@lidge-jun

Copy link
Copy Markdown
Owner

Thanks @luvs01! Maintainer review is done and approved at 7c93614; I'll squash-merge once CI is green on that exact head. Each new push restarts the full CI queue (currently ~1h), so please hold further pushes on this PR unless something is broken.

@lidge-jun

Copy link
Copy Markdown
Owner

Thanks @luvs01! Reviewed: this fixes a real bug: profile removal passed the realpath to unlink, so a symlinked generated profile deleted its target. Removal now refuses a final-component symlink, unlinks only the verified entry under the canonical parent, journal replay refuses symlinked profiles before touching config or evidence, and config publication is rolled back from the same preimage bytes if a later step throws.

Maintainer integration into dev under MAINTAINERS.md (admin dev-only PR bypass). Exact-head CI evidence: every check green on 7c9361423a3a2fedb8b6c61841df59e425978e91 (test 1–4/4, Windows shards where applicable, enforce-target), all review threads resolved, clean merge onto current dev.

@lidge-jun
lidge-jun merged commit a6008d1 into lidge-jun:dev Oct 13, 2026
44 of 47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants