feat(paseo): register child repos in parent mounts - #391
Conversation
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>
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
left a comment
There was a problem hiding this comment.
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>
|
Addressed the review feedback in commit 4b98b93. Changes:
Verification:
Not run: AI-assisted by OpenCode Agent; human review required before merge. |
Summary
Updates the Paseo acq kit so project pre-population handles parent-directory mounts that contain multiple Git repositories.
The registrar now:
.gitentryCloses #390
Review Follow-Up
Addressed review feedback from #391:
projectDirsFromMountsfrom the shipped registrar instead of duplicating the expansion algorithm inline.ci: ignore unavailable federal playbook linkandci: check only changed markdown links on PRs, touching.github/workflows/ci.ymland.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
node --check integrations/isolation/acq-kits/paseo/files/home/paseo-register-mounts.mjsbash -n integrations/isolation/acq-kits/paseo/scripts/verifycd integrations/isolation/acq-kits/paseo && node --test 'tests/**/*.test.mjs'git diff --checkmake test-kitspython3 integrations/isolation/acq-kits/validate-kits.py --strictpython3 scripts/validate_repo.pyHost-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.