feat(org-import): !external cross-repo subtree resolver (Phase 3a, task #222) #105
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "feature/external-ref-resolver"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Phase 3a of internal#77 (task #222). Adds gitops-style cross-repo subtree composition to the platform's org-template importer — the proper-fix alternative to the operator-side filesystem symlink approach shipped in parent template PR #5.
Design was posted on internal#77 comment 1995 and approved by Hongming with
goon all 4 decision points 2026-05-08.Schema
A
!external-tagged mapping anywhere a workspace entry is allowed (workspaces:, roots:, children:):How it works
git.moleculesai.app/molecule-ai/; override viaMOLECULE_EXTERNAL_REPO_ALLOWLIST), ref against^[a-zA-Z0-9_./-]+$regex, path against relative-and-down-only.git ls-remote.<orgBaseDir>/.external-cache/<safe-repo>/<sha>/. Content-addressable; same(repo, sha)reuses cache.git clone --depth=1 -b <ref>withMOLECULE_GITEA_TOKENinjected into URL. Atomic via tmp-then-rename.<cacheDir>/<path>.expandNode): nested!includeand!externalresolve naturally — relative!includepaths resolve viasubDir = filepath.Dir(yamlPathAbs), naturally inside the cache.files_dirscalar (idempotent — won't double-prefix). After this, fetched workspaces look like ordinary in-tree workspaces; downstream pipeline unchanged.Why files_dir but not !include
files_diris consumed at workspace-provisioning time RELATIVE TOorgBaseDir. After fetch the actual files live at<cacheDir>/dev-lead/core-be/, but the workspace.yaml saysfiles_dir: dev-lead/core-be. Without rewrite,resolveInsideRootwould compute<orgBaseDir>/dev-lead/core-be— doesn't exist. Rewrite prepends the cache-relative prefix.!includepaths resolve RELATIVE TO their containing file's dir. After fetch the containing file IS in the cache, so its relative includes naturally Just Work. No rewrite needed.Tests
8 unit tests with
fakeFetcherinjection (no network):TestResolveExternalMapping_HappyPath— top + nested workspace files_dir both cache-prefixedTestResolveExternalMapping_AllowlistRejection— github.com/foo/bar rejectedTestResolveExternalMapping_PathTraversalRejection—../../etc/passwdrejectedTestResolveExternalMapping_BadRefRejection—main; rm -rf /rejectedTestResolveExternalMapping_MissingRequiredFields— repo/ref/path all requiredTestRewriteFilesDirAndIncludes— basic walk+prefixTestRewriteFilesDirAndIncludes_Idempotent— no double-prefixTestAllowlistedHostPath— env override + globFull
go test ./internal/handlers/clean (5.2s, no regressions).Security review (per SOP Phase 2)
git clone -b <ref>external.pathresolveInsideRootcheck before file openMOLECULE_GITEA_TOKENis read-only scope; never loggedBackwards compat
Pure additive. Existing
!include+ inline workspaces unchanged. The dev-lead symlink in parent template PR #5 keeps working —!externalis the ALTERNATIVE, not a replacement. Migration of parent template to use!externalinstead of symlink is a separate PR-D (post-stabilization).What's still ahead (separate PRs)
git clone+ls-remotepaths).dev-leadsymlink to!externalblock.Refs
!externalcross-repo subtree resolver (Phase 3a, internal#77 / task #222)LGTM. Design matches the agreed spec from internal#77 comment 1995. Allowlist + ref-regex + path-traversal checks are sound. 8 unit tests with fakeFetcher cover the resolver+rewrite logic clean. Path-rewrite-after-recurse is the right order — verified happy-path test catches the alternative.