Skip to content

[P2.25] record_installation and the credential-manager migration have unguarded read-modify-write / error paths #1085

Description

@frankbria

Follow-up from the PR #1084 review of #954. Two narrow gaps deliberately left out of that change as out-of-scope.

1. record_installation does an unlocked read-modify-write

codeframe/core/installer.py:record_installation reads environment.json, adds one entry, and writes the whole file back. #954 made that write atomic (no truncation on crash), but there is no lock around the read-modify-write, so two concurrent installs can still lose an entry: both read the same base, and the second write drops the first tool.

credentials.py already models the fix — CredentialStore._store_lock() wraps its read-modify-write in a thread lock plus an optional cross-process filelock.

Low practical impact today: installs are usually sequential and driven by one cf env install run. It becomes real if cf env install ever parallelises tools.

2. A corrupted per-user credential store yields an unformatted 500

get_credential_manager() (the FastAPI dependency used by ui/routers/settings_v2.py and github_integrations_v2.py) calls _migrate_machine_wide_entries().store() before the route body runs. Since #954, .store() can raise CredentialStoreUnreadableError. Because it is raised in the dependency rather than the handler, it bypasses each route’s own try/except Exceptionapi_error(...), so the client gets a bare 500 instead of the formatted error the routes produce everywhere else.

The CLI equivalent of this was fixed in #954 (cf auth setup / cf auth rotate now catch it and print the exception’s recovery text); the HTTP surface was not.

Acceptance criteria

  • record_installation serialises its read-modify-write (reuse the _store_lock pattern); a two-thread test records both tools with neither lost
  • An unreadable credential store surfaced through the v2 routers returns the standard api_error(...) shape, not a bare 500; test asserts the status code and body shape
  • Neither path overwrites an unreadable store (already guaranteed by [P2.4] Make config, credential, installer and workspace-init writes atomic and crash-safe #954 — assert it stays true)

Context

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2-medium-betaMedium priority - nice to have for betapriority:mediumtype:bugSomething is broken and needs fixing

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions