Skip to content

feat(paseo): register child repos in parent mounts - #391

Merged
mogul merged 4 commits into
mainfrom
feature/paseo-register-mounts-multi-repo
Aug 27, 2026
Merged

feat(paseo): register child repos in parent mounts#391
mogul merged 4 commits into
mainfrom
feature/paseo-register-mounts-multi-repo

Conversation

@mogul

@mogul mogul commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Updates the Paseo acq kit so project pre-population handles parent-directory mounts that contain multiple Git repositories.

The registrar now:

  • registers a mount itself when the mount is a Git repo
  • otherwise registers direct child directories that contain a .git entry
  • follows direct-child symlinks that resolve to directories, matching worktree/submodule use cases under an operator-selected mount
  • falls back to registering the mount itself when no child Git repos are found
  • keeps discovery shallow, deterministic, de-duplicated, and fail-open

Closes #390

Review Follow-Up

Addressed review feedback from #391:

  • Documented the direct-child symlink-follow behavior in the Paseo README and decision record.
  • Refactored the live verify expected-set calculation to import projectDirsFromMounts from the shipped registrar instead of duplicating the expansion algorithm inline.
  • Disclosure: this branch also currently contains two unrelated CI link-check commits, ci: ignore unavailable federal playbook link and ci: check only changed markdown links on PRs, touching .github/workflows/ci.yml and .markdown-link-check.json. They should be reviewed as CI-wide link-check behavior changes or split before merge if maintainers prefer a narrower Paseo-only PR.

AI Assistance

This PR was prepared with OpenCode Agent assistance. Human review required before merge.

Verification

  • PASS: node --check integrations/isolation/acq-kits/paseo/files/home/paseo-register-mounts.mjs
  • PASS: bash -n integrations/isolation/acq-kits/paseo/scripts/verify
  • PASS: cd integrations/isolation/acq-kits/paseo && node --test 'tests/**/*.test.mjs'
    • 8 tests passed
  • PASS: git diff --check
  • PASS: make test-kits
    • usai-provider kit tests passed
    • paseo kit tests passed
    • providers/usai catalog + emitter tests passed
  • PASS: python3 integrations/isolation/acq-kits/validate-kits.py --strict
    • all 7 acq kits valid
  • PASS: python3 scripts/validate_repo.py
    • all validators passed
    • existing advisory sensitive-term/network warnings were reported, unrelated to this change

Host-Side / Live Testing

Not run: RUN_ACQ=1 integrations/isolation/acq-kits/paseo/scripts/verify.

The change is in post-discovery path expansion after mounts have already been found, so the script-level behavior tests cover the core logic. The live verify fixture was also updated so a future live run exercises a parent-directory mount containing direct child repos, and the expected-set logic now imports the registrar's exported expansion function to avoid drift.

Rollback

Revert this commit to restore one-project-per-qualifying-mount behavior.

Security Impact

No authentication, authorization, or network exposure changes. The registrar still only inspects already-mounted read-write host directories inside the sandbox and still fails open. The scan is shallow and limited to direct child directories; direct-child symlinks are followed only when they resolve to directories under an operator-selected mounted path.

Detect read-write host mounts that are parent directories containing direct child Git repositories and register each child repository as its own Paseo project. Preserve the existing fallback for mounts with no child repositories.

Co-authored-by: OpenCode Agent <agent@gsa.gov>
@mogul
mogul requested a review from a team as a code owner August 27, 2026 01:57
The link-check job reports playbook.cio.gov as status 0 from CI runners even though it is a stable federal reference. Add it to the markdown-link-check ignore list to avoid blocking unrelated PRs on that external endpoint.

Co-authored-by: OpenCode Agent <agent@gsa.gov>
Limit pull request Link Check runs to modified Markdown files while keeping full repository scans on pushes to main. This should reduce PR link-check runtime without losing periodic full coverage.

Co-authored-by: OpenCode Agent <agent@gsa.gov>
wz-gsa
wz-gsa previously approved these changes Aug 27, 2026

@wz-gsa wz-gsa 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.

Adversarial review — LGTM on the paseo feature; one process note to flag

The registration feature is sound. `expandMountToProjectDirs` is fs-API-only (readdir/stat/readFile) — no shell/`git` subprocess spawned, no repo-derived string ever reaches a shell command. Path traversal via a crafted child name isn't reachable: `readdirSync` entries can't be `.`/`..`, and a directory-entry basename can't contain `/`, so `join(mount, entry.name)` can't escape `mount`. The one real behavioral edge — following a direct-child symlink one level and registering the symlink's target — is by design (worktree/submodule support over a mount the OPERATOR chose to bind in), not an injected-input risk; it's a minor doc-completeness gap (neither README nor the decision doc mentions it), not a security defect.

Write scope is unchanged: the script is read-only against the filesystem; the only side effect is the pre-existing daemon RPC (`addProject`), whose idempotency this PR doesn't touch. `spec.yaml` needed no changes (no new caps, mode/user unchanged) and none were made. `scripts/verify` got real new live coverage — both a positive assertion (child repos registered) and a correctly-inverted negative one (the parent mount itself is NOT registered once children are found) — exercising the exact scenario from #390's own example.

Test coverage for the new logic is solid: both `.git`-as-directory and `.git`-as-file (worktree) shapes, symlinked child, no-child fallback, mount-that-is-itself-a-repo (correctly not expanded into its own submodules), missing-mount no-throw, and cross-mount dedup.

Process note, not a code defect: this PR's commit history has 3 commits, and 2 of them (`ci: ignore unavailable federal playbook link`, `ci: check only changed markdown links on PRs`) are unrelated CI-tooling changes to `.github/workflows/ci.yml`/`.markdown-link-check.json` — zero relation to paseo, and the PR description doesn't mention either one. Worth noting: issue #392 exists specifically because a workflow-scope token limitation was cited as the reason that change couldn't land directly — but it evidently did land, inside this PR, undisclosed. Not blocking the paseo feature, but recommend either splitting those two commits into their own PR (closing #392 properly) or adding a line to the description disclosing/justifying them before merge, so reviewers scoping this as "just the paseo change" don't miss that it also alters CI-wide link-check behavior.

Two minor non-blocking suggestions: (1) a sentence in the README/decision-doc on the symlink-follow behavior; (2) `scripts/verify`'s expected-set computation re-implements `expandMountToProjectDirs`'s algorithm inline as an embedded Node script rather than importing the real exported function — a future edit to the `.mjs` could silently desync from this copy without failing `verify`'s own syntax check.

All CI checks green. Approve on the feature; flagging the CI-rider disclosure as the one thing worth addressing before/at merge.

AI-assisted (OpenCode).

Document direct-child symlink handling and update live verify to import the registrar's project expansion helper instead of duplicating the algorithm.

Co-authored-by: OpenCode Agent <bret.mogilefsky@gsa.gov>
@mogul

mogul commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review feedback in commit 4b98b93.

Changes:

  • Documented the direct-child symlink-follow behavior in the Paseo README and decision record.
  • Refactored live verify step 10 to import the registrar's exported project expansion helper instead of duplicating the expansion algorithm inline.
  • Updated the PR body to disclose the two unrelated CI link-check commits currently on this branch, per the process note.

Verification:

  • PASS: node --check integrations/isolation/acq-kits/paseo/files/home/paseo-register-mounts.mjs
  • PASS: bash -n integrations/isolation/acq-kits/paseo/scripts/verify
  • PASS: cd integrations/isolation/acq-kits/paseo && node --test 'tests/**/*.test.mjs' (8 tests)
  • PASS: git diff --check
  • PASS: python3 integrations/isolation/acq-kits/validate-kits.py --strict
  • PASS: make test-kits
  • PASS: python3 scripts/validate_repo.py (existing advisory warnings only, unrelated)

Not run: RUN_ACQ=1 integrations/isolation/acq-kits/paseo/scripts/verify live sandbox validation.

AI-assisted by OpenCode Agent; human review required before merge.

@mogul
mogul merged commit eded00c into main Aug 27, 2026
8 checks passed
@mogul
mogul deleted the feature/paseo-register-mounts-multi-repo branch August 27, 2026 22:03
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.

feat(paseo): register git repos inside parent-directory mounts

2 participants