Skip to content

fix(proxy): EPMCDME-15375 - refresh and clean up claude-code-otlp settings backup - #651

Merged
uladzislausvetlakou merged 13 commits into
codemie-ai:mainfrom
Oleh-Prusak-epam:EPMCDME-15375
Oct 21, 2026
Merged

uladzislausvetlakou merged 13 commits into
codemie-ai:mainfrom
Oleh-Prusak-epam:EPMCDME-15375

Conversation

@Oleh-Prusak-epam

@Oleh-Prusak-epam Oleh-Prusak-epam commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes EPMCDME-15375: codemie proxy connect/disconnect --claude-code-otlp left a stale settings.json.codemie-backup on disk — created only once on first connect and never refreshed, cleaned up only when the stripped settings became fully empty. A later disconnect could restore an outdated backup, reverting values the user deliberately changed or removed after connecting.

Changes

  • Key the connect-time backup refresh on whether CodeMie already manages the file (via hooks or env keys), not on whether a backup file happens to exist — a stale backup no longer survives a disconnect + manual edit + reconnect cycle untouched.
  • removeClaudeCodeOtlpConfig no longer restores raw backup bytes on disconnect. It always derives the result from the current live settings file and deletes it outright when nothing foreign remains. The backup is unlinked after every successful disconnect, not just the previously-empty-only case.
  • CR-001 fix-up: alreadyManaged also considers CODEMIE_ENV_KEYS presence in env (not just hook commands), closing a path where a live bearer token could be raw-copied into the backup.
  • CR-003 fix-up: requires a value match (not just key presence) for env-managed detection, so a genuinely foreign value under a managed env-key name (reachable via --force) is preserved instead of silently dropped.
  • Dropped the now-dead usedBackup field and its "Restored the pre-connect backup" CLI warning, since disconnect can no longer restore backup content.
  • connect --force no longer causes permanent, unrecoverable loss of a value it overwrites (e.g. a user's own OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_EXPORTER_OTLP_HEADERS pointing at their own collector). removeClaudeCodeOtlpConfig puts a displaced value back into the live file before deleting the backup — only for a key that's still holding codemie's own current value at disconnect time, so a value the user changed again after connect is correctly left alone (AC3).
  • The connect-side backup is refreshed on every connect that modifies an already-managed settings file, not just the first one. A value an earlier --force connect displaced into the old backup is carried forward into the freshly rebuilt one, via a shared withDisplacedEnvValues helper.

Additional hardening (follow-up round, on top of the above)

Prompted by an independent review of the above (findings #1–#13 against a prior head), plus a subsequent multi-lens re-review of the fix-up itself:

  • Value-based env ownership everywhere, not presence-based. A user's own pre-existing OTEL setup that happens to share one of codemie's keys (e.g. CLAUDE_CODE_ENABLE_TELEMETRY='1') is no longer misclassified as "already codemie's" and stripped wholesale; and a user's edit to a codemie-managed key after connect is no longer silently erased on disconnect. Both the connect-time backup build and the disconnect-time strip now gate every CODEMIE_ENV_KEYS deletion on isCodemieOwnedEnvValue, not key presence.
  • Symmetric OTEL_EXPORTER_OTLP_ENDPOINT ↔ OTEL_EXPORTER_OTLP_HEADERS pairing. Neither is treated as codemie-owned unless the other also looks like codemie's own — closes a false positive on the generic Authorization=Bearer <token> prefix (a foreign collector using the exact same, non-secret default gateway key the daemon falls back to would otherwise have been misclassified) and the symmetric case of a foreign endpoint coincidentally sharing our path suffix.
  • Hook values get the same displaced-value recovery as env values. A new withDisplacedHooks helper (mirroring withDisplacedEnvValues) restores a malformed (non-array) hook value a --force connect once displaced, gated the same way — only while the live file still currently holds codemie's own command for that event. Closes the "Known remaining gap" called out below in the previous round.
  • CODEMIE_ANALYTICS_PROJECT_FILTER is now gated on holding a well-formed allowlist value before being stripped, instead of by key presence alone.
  • CODEMIE_ENV_FIXED_VALUES is a real Record<FixedCodemieEnvKey, string> (no Partial + as-cast), so a future key added to CODEMIE_ENV_KEYS without a fixed value is now a compile error instead of a silent runtime gap.
  • readBackupSettings sanitizes non-string env values from a corrupted/hand-edited backup file instead of letting them flow into the live settings file.
  • A failed backup-file unlink (e.g. Windows EPERM from a locked file) on either connect or disconnect is now best-effort (logged, not thrown) — it no longer fails the whole operation, since the important state change (settings.json itself) has already landed by that point.
  • docs/COMMANDS.md now documents the backup lifecycle.

Testing

  • Tests added/updated (TDD per change) — connector suite: 65/65 passing (was 56 before this round).
  • Full proxy command module: 463/463 passing.
  • Full unit suite: 353 files / 5270 tests passing (2 pre-existing skips), zero-warning lint, typecheck all green.
  • Isolated, real-build verification (not just unit tests): ~25+ scenarios run per round against a compiled build in a throwaway $HOME/CODEMIE_HOME (real user settings never touched) — the ticket's original end-to-end repro, every reviewer-reported finding individually reproduced and re-verified fixed, AC1–AC3 regression checks, and the new hardening round's specific false-positive/EPERM/corrupted-backup scenarios.
  • Verified locally by Klim Starykau — all good.

Known remaining items (deliberately out of scope for this PR)

  • OTEL_EXPORTER_OTLP_ENDPOINT's and HEADERS' ownership checks remain pattern-based (fixed suffix/prefix + sibling pairing), since disconnect never reads live daemon state. This is believed sufficiently narrow after this round's hardening; a coincidental match against both halves of the pattern together is not considered a realistic collision.
  • The backup for a hand-corrupted hooks block (as opposed to env, which is now sanitized) is not independently type-validated — hook values are intentionally heterogeneous by design (a displaced "malformed" value can legitimately be any non-array shape the user owned), so a blanket type filter here risks breaking legitimate displaced-hook recovery rather than only rejecting corruption.
  • PR description/task-artifact process items (CI status, coordination with the overlapping conflict in disconnect-orchestrator.ts from PR fix(proxy): resolve merge conflicts for #580 (proxy disconnect support) #618) are tracked separately and not part of this code change.

Checklist

  • Code follows project standards
  • CI is green locally (lint, typecheck, build, unit suite, secrets scan via pre-commit)
  • No merge conflicts with main

Key the backup-refresh decision on whether CodeMie already owns part
of settings.json, not on whether a backup file happens to exist. A
stale backup from a prior connect no longer survives a disconnect +
manual edit + reconnect cycle untouched.
…isconnect

removeClaudeCodeOtlpConfig no longer restores raw backup bytes. It
always derives the result from the current live settings file and
deletes it outright when nothing foreign remains, so disconnect can
no longer resurrect a value the user changed or removed after the
connect that captured the backup. The backup is now also unlinked
after every successful disconnect, not just the fully-empty case.
…disconnect

claude-code-otlp's disconnect can no longer restore backup content,
so the usedBackup field and its CLI warning were dead code.
alreadyManaged previously only looked at hook commands, so a settings
file with codemie env keys (incl. the OTLP bearer token) but no
codemie hook group was misclassified as unmanaged, causing a raw
copyFile backup that could enshrine the live bearer token as the
pre-connect original. Now also treated as managed, routing it through
the strip-and-rebuild backup path.
…env-managed detection

The CR-001 fix (checking for CODEMIE_ENV_KEYS presence) was too broad:
under --force, a settings file with a genuinely foreign value under one
of the 9 managed env var names was misclassified as already-managed,
and stripCodemieManagedContent would then silently drop that foreign
value from the rebuilt backup with no other copy. Require the existing
value to match what this tool would write, so a foreign value falls
through to the raw-copy backup path instead.
Technical analysis, plan, code-review verdicts (final + check),
QA report, gate plan, and actual complexity assessment for the
claude-code-otlp settings backup refresh/cleanup fix.
The check-round verdict file still showed request-changes from before
CR-003 was fixed, since sdlc-light's rule skips a 3rd automated review
round after a check-round request-changes in favor of a human decision.
Updates the verdict to approve, moves CR-003 to finding_status:resolved,
and records the decision history (final -> check -> human approval) so
the committed artifact matches the actual, fully-resolved state.
@Oleh-Prusak-epam Oleh-Prusak-epam changed the title fix(proxy): refresh and clean up claude-code-otlp settings backup fix(proxy): EPMCDME-15375 - refresh and clean up claude-code-otlp settings backup Oct 18, 2026

@Bondimm Bondimm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • CI hasn't run on this PR. The CI runs for bd43e16f and for the earlier heads 5c66845e and 40ae4176 are waiting for maintainer approval (action_required), so there are no Build / Test (Ubuntu) / Test (Windows) results yet. The branch is up to date with main and merges cleanly.
  • Checked locally on Windows on bd43e16f: npm run typecheck, eslint on the four changed .ts files, and commitlint on the commits and the title pass. vitest --project unit src/cli/commands/proxy passes (19 files, 451 tests).
  • Checked against EPMCDME-15375: I replayed the ticket's steps with the real connect and disconnect functions and a temporary home. The backup is gone after the first disconnect, holds STEP: B after the reconnect, and the settings file is deleted after the final disconnect, so AC2 and AC3 hold. AC1 is only partly met (thread below).
  • Feature flag: none. Every proxy disconnect --claude-code-otlp now deletes the backup and never restores it. Revert: code only and clean. After a revert, a disconnect that leaves the file empty would again restore whatever backup is on disk.
  • Open PRs touching the same files: #618 conflicts with this PR in disconnect-orchestrator.ts, and it still prints the "Restored the pre-connect backup" warning from result.usedBackup, which this PR removes. Whichever merges second needs to drop that block. #634 (more hook events in the same connector), #649 and #654 merge cleanly.

What needs rechecking after the next push:

  • CI on the new head, once approved, including Test (Windows);
  • connect --force over the user's own OTEL values, then disconnect: the user's values come back;
  • the backup after a connect while CodeMie is already connected.

…n every managed connect

Addresses two review findings on PR codemie-ai#651 for EPMCDME-15375:

- disconnect no longer permanently destroys a value --force overwrote at
  connect time (e.g. a user's own OTEL collector endpoint/headers). The
  backup's displaced value is put back into the live settings file, but
  only for keys still holding codemie's own current value - a value the
  user changed again after connect is left alone, preserving AC3.
- the connect-side backup is now refreshed on every connect that modifies
  an already-managed settings file, not just the first one, closing the
  AC1 gap (CR-002). A value a prior --force connect displaced into the old
  backup is carried forward into the refreshed one so it isn't lost before
  the eventual disconnect.

Both paths share a new withDisplacedEnvValues helper instead of duplicating
the restore/carry-forward logic. Verified live against isolated $HOME
reproductions (not just unit tests), including a full replay of the
ticket's original repro sequence; full unit suite (5258 tests) and
lint/typecheck/license-check all green.
Oleh-Prusak-epam and others added 3 commits October 20, 2026 20:33
…E-15375)

Closes the remaining findings from the external PR codemie-ai#651 review: env-key
ownership is now checked by value everywhere (not just presence), with
OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS each requiring
the other to also look like codemie's own before either is treated as
owned (closes the generic-Bearer-prefix and coincidental-suffix false
positives on both sides). CODEMIE_ANALYTICS_PROJECT_FILTER is now gated
on holding a well-formed allowlist value rather than stripped by key
presence alone. CODEMIE_ENV_FIXED_VALUES is a real Record (no Partial +
as-cast), so a future key added to CODEMIE_ENV_KEYS without a fixed value
is now a compile error. readBackupSettings sanitizes non-string env
values from a corrupted/hand-edited backup instead of letting them flow
into the live settings file. A failed backup-file unlink (e.g. Windows
EPERM) on either connect or disconnect is now best-effort and no longer
fails the whole operation, since the important state change has already
landed by that point. Documents the backup lifecycle in docs/COMMANDS.md.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
…PMCDME-15375)

Shortens several JSDoc blocks and inline comments that were disproportionately
long for the code they annotate, while keeping the non-obvious rationale each
one exists to record. No behavior change.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
…nnector (EPMCDME-15375)

Second pass: shortens isHookEntry/stripCodemieCommandsFromGroups JSDoc and
four inline comments in writeClaudeCodeOtlpConfig/removeClaudeCodeOtlpConfig,
plus the fs/promises mock-factory comment in the test file. No behavior change.

Generated with AI

Co-Authored-By: codemie-ai <codemie.ai@gmail.com>
@uladzislausvetlakou
uladzislausvetlakou merged commit bae5768 into codemie-ai:main Oct 21, 2026
5 checks passed
gokhanozdemir pushed a commit to gokhanozdemir/codemie-code that referenced this pull request Oct 21, 2026
…tings backup (codemie-ai#651)

Co-authored-by: codemie-ai <codemie.ai@gmail.com>
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.

4 participants