Skip to content

cso start crashes with UNSAFE_PATH on repos containing untracked nested git repositories; history-inputs fails on routine repos due to a 1 MiB log cap #3255

Closed

Description

@jerwei-peterstuyvesant

Environment

  • gstack 1.91.121.0 (revision=1.91.121.0 (d258bcffb0cb)), CSO helper ABI 3
  • Windows 11 x64 (repro is OS-agnostic; see below)
  • Bun 1.4.3, Node 22.23.3

Bug 1 — UNSAFE_PATH: Expected a contained relative path (crash, blocks all audits)

Symptom

gstack-cso start --repo PATH fails before creating a run, for every --repo path form:

{"ok":false,"error":{"code":"UNSAFE_PATH","message":"Expected a contained relative path"}}

doctor passes on the same repo; only start fails.

Root cause

When the audited repository contains an untracked nested git repository (a directory holding its own .git that is not a registered submodule), git ls-files --cached --others --exclude-standard -z emits that directory as a single entry with a trailing slash (e.g. shadcn-ui/).

paths() in lib/cso/snapshot.ts:520 feeds the value to relativePath() without stripping the slash:

// lib/cso/snapshot.ts:520
seen.add(relativePath(value)); // throws on "shadcn-ui/"

relativePath() (lib/cso/contracts.ts:418) rejects any path whose split('/') yields an empty segment, so dir/ throws. The sibling collector at snapshot.ts:547 already strips the slash and does not crash:

// lib/cso/snapshot.ts:547
ignoredDirectories.add(relativePath(value.replace(/\/$/, '')));

Repro (OS-agnostic)

  1. git init outer && cd outer && echo hi > README.md && git add . && git commit -m init
  2. mkdir inner && cd inner && git init && echo x > f.txt
  3. gstack-cso start --repo . → the exact error above.

Fails identically on any OS; it is triggered by repo content, not by path arguments or Windows.

Suggested fix

Strip the trailing slash in paths() before relativePath(value), mirroring line 547:

seen.add(relativePath(value.replace(/\/$/, '')));

Workaround (repo-local, reversible)

Add each nested repository to .git/info/exclude (e.g. shadcn-ui/, solid-glass/). start then succeeds.

Bug 2 — history-inputs not assessed: bounded git log truncated at 1 MiB

Symptom

Every coverage domain reports history-inputs: not_assessed with gap: Could not read bounded Git metadata: log exceeded the output limit (request rejected).

Root cause

The history capture at lib/cso/snapshot.ts:879-896 runs a full-patch log:

git log --max-count=100 --format=... --unified=3 -p <range> --

but passes no maxBytes to the git() helper. In lib/cso/process.ts:598 the effective cap is min(opts.maxBytes ?? MAX_OUTPUT, ...) = MAX_OUTPUT = 1 MiB (lib/cso/contracts.ts:5). Full patches for 100 commits on a routine Next.js app measure 2.4 MiB (git log --max-count=100 -p on the repro repo), so the read is truncated and history capture fails on ordinary repositories. The 16 MiB RAW_OUTPUT_LIMIT (process.ts:562) is unreachable here because maxBytes is omitted.

Suggested fix

Either pass an explicit larger maxBytes (raw mode allows up to RAW_OUTPUT_LIMIT) to the history git() call, or make history capture tolerate truncation (e.g. capture commit metadata without -p when the patch output exceeds the cap).

Notes

  • Both issues observed on a real repo (Renhuai-123/ziwei-doushu clone); Bug 1 reproduces in a 3-file sandbox through the compiled launcher.
  • With the Bug 1 workaround in place, start completes: run captures 125 source entries, snapshot coverage passes; only history-inputs remains blocked by Bug 2.

Activity

  1. capy-ai commented on Oct 19, 2026

    @capy-ai
    Contributor

    Fixed in #3303, which is up for review now.

    • Bug 1 (nested repo, UNSAFE_PATH): a directory that Git lists as a single entry (an untracked nested repo or a submodule gitlink) is recorded as an explicit excluded: nested Git repository entry and never read. start succeeds, and the snapshot coverage lists the exclusion. This is @surlymochan's fix(cso): treat untracked nested repos and submodules as snapshot boundaries #3256, landed with authorship kept.
    • Bug 2 (history over 1 MiB): history now degrades instead of failing. The newest whole commits that fit the 1 MiB redaction bound are kept. If even the newest patch is too large, only commit metadata is kept. history.txt starts with a [gstack-cso history truncated: …] marker, and history-inputs is reported as partial with the reason. Redaction still covers everything it keeps.

    Thanks for the precise repro. The workaround (.git/info/exclude) isn't needed after this lands.

  2. capy-ai commented on Oct 19, 2026

    @capy-ai
    Contributor

    Fixed in #3303, released as v1.91.152.0 (404ddf0). Thanks for the detailed report and root-cause analysis. If anything still fails after you upgrade, reopen this with the gstack-cso output. — GStack Minder

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions