Skip to content

feat(git): name app-managed git folders after their project instead of a bare hex id - #10349

Open
pavkout wants to merge 4 commits into
Kong:developfrom
pavkout:INS-2612
Open

feat(git): name app-managed git folders after their project instead of a bare hex id#10349
pavkout wants to merge 4 commits into
Kong:developfrom
pavkout:INS-2612

Conversation

@pavkout

@pavkout pavkout commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

What

App-managed git repo folders (~/…/version-control/git/<id>) are named after
nothing but a random 32-char hex id, making it impossible to tell projects
apart on disk (see screenshot in INS-2612). This adds a human-readable slug:

git_57d071a646b34393929036c34dd0915e
→ git_camsproject_57d071a646b34393929036c34dd0915e

How

  • GitRepository gains a folderSlug field: a filesystem-safe slug of the
    owning project's name, snapshotted once and not kept in sync with later
    project renames (renaming the folder live is unsafe — see below).

  • models.gitRepository.getGitRepoFolderName() computes the on-disk folder
    name from folderSlug (falls back to the bare id when unset), used by both
    the main-process getRepoBaseDir/getGitFSClient and the renderer's
    resolveGitRepoBaseDir.

  • New repos, and any existing repo missing a slug, get backfilled by
    backfillAllManagedGitFolderSlugs() — a best-effort pass that runs once,
    awaited before the app window is created (entry.main.ts).

    That timing is load-bearing, not incidental: renaming a folder while
    anything else (a file watcher, a route loader's git call) can concurrently
    resolve the old path is unsafe — a reader holding the stale path can
    recreate it via the FS client's auto-mkdir-on-write behavior microseconds
    after the rename moves the real data away, silently forking a repo's files
    across two directories. An earlier version of this change did the backfill
    lazily on each repo's first load instead, and this exact race was reproduced
    against a real profile (verified below). Doing it once, pre-window, removes
    the race entirely: nothing can be reading these folders yet.

  • User-chosen directory repos are never touched — Insomnia doesn't own that
    folder.

Copilot AI lite review requested due to automatic review settings August 7, 2026 13:03
@pavkout pavkout self-assigned this Aug 7, 2026
@pavkout
pavkout requested a review from a team August 7, 2026 13:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 improves the on-disk readability of app-managed Git repository folders by embedding a filesystem-safe snapshot of the owning project’s name into the managed folder name (while preserving stability by not renaming on subsequent project renames). It also introduces a one-time, best-effort startup backfill that renames existing managed folders before the renderer/window is created to avoid races.

Changes:

  • Add GitRepository.folderSlug and a shared models.gitRepository.getGitRepoFolderName() helper to compute the managed folder name (slugged when available, legacy id otherwise).
  • Update both main-process and renderer path resolution to use getGitRepoFolderName() for consistent managed folder naming.
  • Add slugify() (with tests) and a startup backfillAllManagedGitFolderSlugs() pass awaited before window creation.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/insomnia/src/ui/utils/git-repo-path.ts Renderer path resolver now uses models.gitRepository.getGitRepoFolderName() and includes folderSlug in the shape.
packages/insomnia/src/main/git-service.ts Main-process path resolution updated; adds startup backfill to rename legacy managed folders safely before window creation.
packages/insomnia/src/entry.main.ts Awaits backfillAllManagedGitFolderSlugs() before launching the app window to avoid rename/path races.
packages/insomnia-data/src/models/git-repository.ts Adds folderSlug field and introduces getGitRepoFolderName() as the folder-name source of truth.
packages/insomnia-data/src/models/git-repository.test.ts Adds unit tests covering getGitRepoFolderName() behavior.
packages/insomnia-data/common-src/misc.ts Adds slugify() helper for creating filesystem-safe project-name slugs.
packages/insomnia-data/common-src/misc.test.ts Adds unit tests for slugify().

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

Comment on lines +25 to +31
export function slugify(input: string, maxLength = 40) {
const slug = input
.normalize('NFKD')
.replace(/[̀-ͯ]/g, '') // strip accents (combining diacritical marks)
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
Comment on lines +85 to +89
/**
* A filesystem-safe slug derived from the owning project's name at the time
* the app-managed folder was created (or, for repos that predate this field,
* backfilled the first time the repo is loaded). It is baked into the
* managed folder name for readability (see {@link getGitRepoFolderName}) and
// Should be unreachable — getGitRepoFolderName already validates folderSlug — but
// fall back to the safe bare-id path rather than ever returning one outside gitRoot.
console.warn('[git] Computed managed repo folder path escaped the git root, falling back to bare id:', folderName);
return path.join(gitRoot, gitRepositoryId);

@aikido-pr-checks aikido-pr-checks Bot Aug 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Potential file inclusion attack via reading file - medium severity
If an attacker can control the input leading into the ReadFile function, they might be able to read sensitive files and launch further attacks with that information.

Show fix
Suggested change
return path.join(gitRoot, gitRepositoryId);
const base = path.resolve(gitRoot);
const target = path.resolve(base, gitRepositoryId);
const relative = path.relative(base, target);
if (relative.startsWith('..') || path.isAbsolute(relative)) {
throw new Error('Invalid repository path');
}
return target;

Reply @AikidoSec ignore: [REASON] to ignore this issue.
More info

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.

2 participants