Skip to content

feat(git): establish Gitoxide repository admission and import - #3561

Open
zhiiw wants to merge 23 commits into
apache:mainfrom
zhiiw:codex/gitoxide-short-lived-helper
Open

feat(git): establish Gitoxide repository admission and import#3561
zhiiw wants to merge 23 commits into
apache:mainfrom
zhiiw:codex/gitoxide-short-lived-helper

Conversation

@zhiiw

@zhiiw zhiiw commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Establish one owner-bound Gitoxide repository admission and fresh source-import boundary without restoring bundled Git or discovering system Git.

  • one-request/one-response Rust helper with isolated strict Gitoxide configuration;
  • owner-bound helper artifact, invocation, and repository-admission capabilities;
  • explicit checksum verification for every claimed commit, tree, and blob before parsing, recursion, or copy;
  • one bounded verified tree walker shared by source preflight and copy;
  • portable managedTreePolicyVersion: 1 for cross-platform materialization;
  • fresh-only destination claim and deterministic zero-parent baseline publication;
  • separate bounded deadlines for inspection and large imports;
  • one exhaustive Rust/TypeScript helper error contract.

Primary invariant

Only an admitted short-lived Gitoxide helper invocation may establish the immutable repository identity and source graph used by later managed-workspace operations. A claimed Git OID is accepted only when the object bytes recompute to that exact SHA-1. The admission capability prevents later callers from resubmitting the source path, HEAD/tree identity, helper identity, or tree policy.

Source preflight and copy use the same bounded verified graph walker. Policy v1 rejects path components that cannot be safely materialized across Linux, macOS, and Windows, including Windows device names, reserved/control characters, trailing dots/spaces, .git aliases, and folded path collisions.

Failure and trust boundaries

  • SHA-256 is explicitly rejected; unknown formats are normalized to unknown and fail closed without system-Git fallback.
  • All source/ref/policy/object-graph preflight completes before an atomic create_dir() destination claim.
  • Existing paths—including partial imports, foreign repositories, and the source itself—are rejected without takeover or deletion.
  • Inspection has a 5-second deadline; source import has a 10-minute deadline. Resource limits are admission limits, not an SLA.
  • This Draft verifies helper bytes immediately before path-based spawn, but does not claim resistance to malicious same-user replacement in the verify→exec window. Production use requires a packaged-release trust root and protected installation directory.
  • Durable receipt/quarantine/recovery ownership and a state-root-bound destination capability remain follow-up work.
  • No Desktop/CLI/Write/Edit consumer is included; this PR remains Draft.

Verification

  • Rust 1.98 formatting and helper suites pass on Ubuntu, macOS, and Windows.
  • Real-helper Runtime Host contracts pass on all three platforms.
  • Regression coverage includes mismatched commit/tree storage keys, unknown object formats, portable path policy, destination races, foreign/aliased destinations, object/resource limits, and import timeout process-tree termination.
  • Runtime Host build, Windows skip inventory, CI planner, Biome, and git diff --check pass locally.
中文说明

摘要

本 PR 建立一条 owner-bound 的 Gitoxide repository admission 与 fresh source-import 边界,不恢复 bundled Git,也不从系统 PATH 发现 Git。

  • Rust helper 每次只处理一个请求,使用 isolated/strict Gitoxide 配置;
  • helper artifact、invocation、repository admission 均使用 owner-bound opaque capability;
  • claimed commit/tree/blob 在解析、递归或复制前都重新计算 SHA-1;
  • source preflight 与 copy 共用同一个有界 verified tree walker;
  • managedTreePolicyVersion: 1 明确定义为跨平台可物化策略;
  • destination 通过原子 create_dir() 领取,并发布确定性的 zero-parent baseline;
  • inspection/import 使用不同的有界 deadline;
  • Rust/TypeScript 使用同一份穷举 error contract。

主要不变量

只有已 admission 的短生命周期 Gitoxide helper 才能建立后续 managed workspace 使用的 immutable repository identity 与 source graph。Git OID 不能自证身份:对象 bytes 必须重新计算得到 exact claimed SHA-1。

source preflight 和 copy 由同一 walker 执行相同的 checksum、资源预算与路径策略。portable policy v1 在所有平台统一拒绝 Windows device names、保留/控制字符、尾部点或空格、.git 别名以及折叠路径冲突,避免“import 已接受但 Windows 无法安全物化”。

仍保留的边界

  • SHA-256 明确不可用;未知格式统一返回 unknown 并 fail closed;
  • helper 不接管或删除已有 destination,包括 partial/foreign artifact;
  • 当前 Draft 不声称抵抗同一 OS 用户在 verify→exec 窗口替换 helper;正式使用需要 packaged-release trust root 和受保护安装目录;
  • durable receipt/quarantine/recovery owner 与 state-root-bound destination capability 仍在后续切片;
  • 当前没有 Desktop/CLI/Write/Edit 生产消费者,因此继续保持 Draft。

验证

  • Ubuntu、macOS、Windows 的 Rust 1.98 formatting、helper tests 与真实 Runtime Host helper contract 全部通过;
  • 回归覆盖错误 commit/tree 存储键、未知 object format、portable path policy、destination 并发、foreign/alias destination、资源预算和 timeout 进程树回收;
  • 本地 Runtime Host build、Windows inventory、CI planner、Biome 与 git diff --check 通过。

@zhiiw

zhiiw commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the unsupported-format admission gap at the open-error boundary.

gix 0.86.0 rejects an unknown extensions.objectFormat while constructing the repository handle, before repository.object_hash() is reachable. The helper now classifies that specific typed configuration error as repository_rejected / unsupported_object_format with exit 2, while unrelated repository-open failures remain operational errors with exit 1.

I also tested the adjacent replacement-ref identity hypothesis. With refs/replace/<HEAD> present, the isolated helper returns the raw HEAD commit and raw tree identity, not the replacement commit's tree. A regression now pins that behavior.

Verification: 4/4 Rust protocol tests pass; ASF header audit and diff check pass.

中文说明

已在 repository open-error 边界修复未知 object format 的分类缺口。

gix 0.86.0 会在构造 repository handle 时拒绝未知的 extensions.objectFormat,因此旧代码确实无法进入 repository.object_hash() 的 unknown 分支。现在 helper 会把该特定 typed-config error 转换为 exit 2 的 repository_rejected / unsupported_object_format;其他 open 失败仍保持 exit 1 的 operational error。

同时验证了相邻的 replacement-ref 身份假设:存在 refs/replace/<HEAD> 时,isolated helper 返回 raw HEAD commit 与 raw tree,不会把 replacement commit 的 tree 混入 observation。对应回归测试已经加入。

验证结果:Rust 协议测试 4/4 通过,ASF header audit 与 diff check 通过。

@zhiiw

zhiiw commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

The follow-up Gitoxide validation stack is now complete as three narrowly scoped stacked Drafts:

  1. artifact identity → opaque invocation capability
  2. bounded short-lived invocation owner
  3. exact repository observation → opaque admission capability

The combined real-helper contract now covers, on the same Runtime Host path:

  • forged release claims and wrong-owner capabilities fail closed;
  • symlink/junction helper paths and post-admission byte changes fail closed;
  • the helper runs with fixed argv, minimal environment, bounded I/O, timeout/cancellation, and no shell;
  • exit 0/1/2 map strictly to SHA-1 observation / stable operational failure / unsupported-format policy rejection;
  • raw repository paths and OIDs cannot self-authorize an admission capability;
  • SHA-256 repositories remain explicitly unsupported and receive no capability.

The three-platform workflow builds the real Rust helper and runs the artifact, invocation, and admission contracts. These PRs intentionally remain Draft: they do not claim a signed packaged-release trust root, a protected installation root, Desktop/CLI consumption, T1 persistence, source import, projection, candidate, or ref CAS. Those are production integration gates, not hidden assumptions in the helper validation stack.

中文说明

Gitoxide 后续验证链已经按三个窄边界完成:

  1. helper artifact identity → opaque invocation capability;
  2. bounded short-lived invocation owner;
  3. exact repository observation → opaque admission capability。

联合真实 helper 合同已经证明:伪造 claim、错误 owner、symlink/junction、admission 后字节变化全部 fail closed;helper 使用固定 argv、最小环境、I/O 上限、超时/取消且不经过 shell;exit 0/1/2 严格对应 SHA-1 observation、稳定 operational failure、unsupported-format policy rejection;裸 path/OID 不能自证 admission;SHA-256 默认拒绝且不签发 capability。

三平台 workflow 会构建真实 Rust helper,并运行 artifact、invocation、admission 合同。这些 PR 仍保持 Draft,因为正式发布签名信任根、受保护安装路径、Desktop/CLI、T1、source import、projection/candidate/ref CAS 尚未接入;这些是后续生产接线门槛,不是当前验证栈里的隐藏假设。

@zhiiw
zhiiw force-pushed the codex/gitoxide-short-lived-helper branch 3 times, most recently from 98d5106 to 3453011 Compare August 24, 2026 04:04
@zhiiw
zhiiw force-pushed the codex/gitoxide-short-lived-helper branch from 3453011 to 28a6b22 Compare August 24, 2026 09:09
@zhiiw zhiiw changed the title feat(git): add a short-lived Gitoxide admission helper feat(git): establish Gitoxide repository admission and import Aug 24, 2026
@zhiiw

zhiiw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

I expanded this Draft from the helper-only validation into one complete repository admission/import boundary.

The updated head now includes the previously isolated artifact authority, short-lived invocation owner, repository admission capability, and exact source-import data plane. The primary invariant is therefore reviewable end to end: only an admitted helper invocation can establish and import the immutable repository identity used by later managed-workspace work.

The branch was rebuilt from the latest main. Git range-diff reports all 12 extracted commits as patch-equivalent to the previously reviewed helper and fork PR #11-#14 slices. Successor publication, projection, packaging/product composition, Write/Edit, and resume remain out of scope.

Local Core/Storage/Runtime/Runtime Host builds pass. The dedicated Linux/macOS/Windows helper jobs are now running against the expanded head.

中文说明

我已经把这个 Draft 从“只有 helper 的验证切片”扩大成一条完整的 repository admission/import 边界。

当前 head 包含此前拆开的 artifact authority、短生命周期 invocation owner、repository admission capability 和 exact source-import data plane。现在可以端到端审查同一个主要不变量:只有经过 admission 的 helper invocation,才能确定并导入后续 managed workspace 使用的 immutable repository identity。

分支已经基于最新 main 重建。Git range-diff 显示 12 个提取提交与此前评审过的 helper 以及 fork #11-#14 patch 完全等价。Successor publication、projection、packaging/product composition、Write/Edit 和 resume 仍不在本 PR 范围内。

本地 Core、Storage、Runtime、Runtime Host 构建通过;Linux、macOS、Windows 专用 helper CI 正在针对新 head 运行。

@zhiiw
zhiiw force-pushed the codex/gitoxide-short-lived-helper branch 2 times, most recently from 4e6337f to 1377437 Compare August 24, 2026 09:48
@zhiiw

zhiiw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the adversarial review. I addressed the correctness findings in 13774374c and intentionally did not paper over the executable-identity limitation.

  1. Import takeover / recovery authority: import is now strictly fresh-only. Any existing destination—including the source repository itself, a foreign bare repository, a non-bare directory, or partial crash residue—is rejected with import_destination_not_fresh and is neither repaired nor deleted. Destination parents are walked before creation and symlink/junction/reparse aliases fail closed. The docs now state that this Draft does not yet prove a Maka-owned destination: the future Storage owner must issue the state-root-bound destination capability and own receipt/quarantine/retry.
  2. Verify-to-spawn TOCTOU: I did not add another hash check and call it solved. Node still performs a path-based spawn after closing the verified handle, so the Draft now explicitly excludes a malicious same-user replacement in that window. Production composition remains blocked on a packaged-release trust root and protected install directory.
  3. Deadline/resource mismatch: inspection remains 5 seconds; source import now has an independent 10-minute deadline. The 2 GiB / 200,000-file limits are documented as admission bounds, not an SLA.
  4. Admission binding: the opaque repository admission now binds the helper artifact digest and managedTreePolicyVersion: 1. Import requires the same helper identity and obtains the policy from the admission owner; callers cannot resubmit either value.
  5. Error protocol drift: Rust and TypeScript now expose the same exhaustive v1 reason list. CI tests compare the two declarations exactly, unknown internal reasons normalize to internal_error_reason_invalid, and the impossible TS-only unsupported_operation reason was removed.

Regression coverage now includes source==destination, foreign bare/non-bare destinations, parent symlink/junction tampering, unsupported policy versions, helper-identity substitution, operation-specific deadlines, and Rust/TypeScript reason parity.

Local Core/Storage/Runtime/Runtime Host builds, focused Node tests, Biome, and diff checks pass. The real Gitoxide workflow is green on macOS and Windows; Ubuntu is currently waiting for a runner.

中文说明

感谢这次对抗性审查。13774374c 已处理实质 correctness 问题,同时没有用“再 hash 一次”伪装修复 executable identity。

  1. import 接管/恢复权限:改成严格 fresh-only。source 自身、foreign bare repo、non-bare 目录和 crash residue 只要已经存在,一律 import_destination_not_fresh,不会修复或删除。创建前逐级检查父路径,symlink/junction/reparse alias 会 fail closed。文档也明确:当前 Draft 尚未证明 destination 是 Maka-owned;未来必须由 Storage owner 签发 state-root-bound capability,并负责 receipt/quarantine/retry。
  2. verify→spawn TOCTOU:Node 关闭已验证 handle 后仍只能按 path spawn,所以当前实现不能抵抗同一 OS 用户在窗口内替换 executable。这个限制已经写进合同,production composition 必须等待 packaged-release trust root 与受保护安装目录。
  3. deadline:repository inspection 保持 5 秒,source import 独立为 10 分钟。2 GiB/200,000 files 是输入上限,不是 SLA。
  4. admission 绑定:repository admission 现在同时冻结 helper digest 与 managedTreePolicyVersion: 1;import 必须使用同一 helper identity,policy 只能由 admission owner 提供。
  5. 错误协议:Rust/TypeScript 使用同一份完整 v1 reason list,测试做 exact parity;未知内部 reason 归一为 internal_error_reason_invalid,删除了 TS 独有且不可达的 unsupported_operation

新增回归覆盖 source==destination、foreign bare/non-bare、父路径 symlink/junction、未知 policy、helper identity 替换、operation-specific deadline 和错误协议一致性。

本地四个 workspace build、Node 定向测试、Biome、diff check 均通过。真实 Gitoxide workflow 的 macOS 与 Windows 已绿色;Ubuntu 仍在等待 runner。

@zhiiw

zhiiw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the adversarial review. I addressed the findings in 73f2f64d9, 92f7e4250, and 9d7aaa9c4 without changing the three-layer capability architecture.

  1. Fresh destination is now an atomic claim. The helper validates all source/ref/policy preconditions first, then claims the leaf with create_dir. AlreadyExists deterministically becomes import_destination_not_fresh; only the winning process can initialize or write the bare repository. Initialization now uses explicit isolated init_opts, destination_must_be_empty, and SHA-1. The existing-ref/same-commit success branch was removed, so publication has one rule: MustNotExist.
  2. Ref syntax is authoritative before side effects. refs/maka/* remains the namespace preflight, while gix::refs::FullName now performs complete Git ref validation before destination creation. Invalid forms such as refs/maka/a..b return invalid_baseline_ref and leave the destination absent.
  3. Commit/tree allocations are bounded before decode. Source HEAD commit and every reachable tree are checked with find_header() before full decode. Policy v1 now caps commit objects at 1 MiB, a single tree at 8 MiB, and cumulative reachable tree bytes at 64 MiB. Isolated open also fixes gitoxide.objects.allocLimit=64 MiB. Oversized commit/tree fixtures prove rejection before destination creation.
  4. The concurrent-owner regression is production-shaped. Two real helper processes import different sources into one destination. Exactly one succeeds, the loser returns import_destination_not_fresh, and the winning object database does not contain the losing source blob.
  5. The dedicated CI contract is closed. The workflow is in the PR-trigger allowlist; checkout and setup-node are pinned to repository-standard full SHAs; checkout uses persist-credentials: false; and both repository-admission owner paths explicitly trigger the three-platform gate.
  6. Timeout wiring now has a behavior test. On POSIX, the test admits a real executable hanging helper with a live descendant, advances the mock clock through the 5-second inspection deadline without settlement, then reaches the 10-minute import deadline and proves both processes are terminated with gitoxide_helper_invocation_timed_out. This adds no executable/timeout injection seam to production code.

Local CI-planner tests, Runtime Host build, protocol parity, Biome, and diff checks pass. The updated dedicated gate is green on macOS and Windows; Ubuntu is currently waiting for a runner. The general package/test/audit checks are still running or queued.

The previously documented later boundaries remain intentionally unchanged: verify-to-spawn replacement resistance needs the packaged-release trust root; destination ownership still needs a state-root lease/capability; and partial artifact receipt/quarantine belongs to the future Storage owner.

中文说明

感谢这次对抗性审查。73f2f64d992f7e42509d7aaa9c4 已经在不改变三层 capability 架构的前提下完成收口。

  1. fresh destination 改为原子领取。 helper 先完成 source/ref/policy 的全部无副作用验证,再用 create_dir 原子领取叶子目录。路径已存在时稳定返回 import_destination_not_fresh;只有胜出的进程能初始化和写入 bare repository。初始化使用 isolated init_optsdestination_must_be_empty 和显式 SHA-1。删除了“ref 已存在且 commit 相同也算成功”的旁路,publication 只剩 MustNotExist
  2. ref 在副作用前由 Gitoxide 权威校验。 refs/maka/* 只负责 namespace preflight,完整 Git ref grammar 由 gix::refs::FullName 在 destination 创建前验证。refs/maka/a..b 等非法形式返回 invalid_baseline_ref,destination 仍不存在。
  3. commit/tree 在完整 decode 前受预算约束。 HEAD commit 和每个 reachable tree 都先通过 find_header() 读取类型/大小。v1 固定 commit 1 MiB、单 tree 8 MiB、全部 reachable tree 64 MiB,并在 isolated open 中固定 gitoxide.objects.allocLimit=64 MiB。恶意 oversized commit/tree fixture 证明拒绝发生在 destination 创建前。
  4. 并发 owner 使用真实双进程测试。 两个 helper 从不同 source 争抢同一 destination,恰好一个成功;失败者稳定返回 not-fresh,winner object database 中也不存在 loser 的 source blob。
  5. CI 合同闭环。 workflow 已加入 PR trigger allowlist;checkout/setup-node 使用仓库标准完整 SHA;checkout 禁止 credential persistence;repository admission owner 及其测试显式进入三平台 path filter。
  6. timeout 改成行为测试。 POSIX CI 会 admission 一个真实 hanging executable helper 及其 descendant:逻辑时钟经过 5 秒 inspect deadline 时 import 仍未 settle,到 10 分钟 import deadline 后整个 process tree 被终止,并稳定返回 gitoxide_helper_invocation_timed_out。生产代码没有新增任意 executable 或 timeout 注入 seam。

本地 CI planner、Runtime Host build、错误协议一致性、Biome 和 diff check 均通过。更新后的专用 gate 在 macOS、Windows 已绿色;Ubuntu 正在等待 runner,通用 package/test/audit 仍在运行或排队。

原先明确记录的后续边界保持不变:verify→spawn 的替换抵抗要依赖 packaged-release trust root;destination ownership 要等 state-root lease/capability;partial artifact 的 receipt/quarantine 由未来 Storage owner 负责。

@zhiiw

zhiiw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining object-identity, graph-walker, portability, protocol, CI, and documentation findings in ea3699465, b0c79b25b, and 8abe835a1.

  1. Claimed object identity is now verified before use. A single load_verified_object() boundary performs header kind/size checks, loads the object under the bounded Gitoxide allocation policy, rechecks the loaded kind/size, and calls Data::verify_checksum(expected_oid). Inspection verifies the claimed HEAD commit; import verifies the expected source commit and every reachable tree/blob. Stable head_commit_identity_mismatch and source_head_commit_identity_mismatch reasons were added to the exhaustive Rust/TypeScript contract.
  2. Preflight and copy now share one graph authority. The separate validate_source_tree and copy_source_tree implementations were replaced by one walk_verified_source_tree in validate-only or copy mode. Each tree is checksum-verified before parsing or descending, and both passes enforce the same depth/visit/entry/path/tree-byte/blob/file/total-byte limits. Copy cannot recurse through newly substituted unverified tree bytes.
  3. managedTreePolicyVersion: 1 is explicitly portable. The owner now rejects ASCII controls, Windows reserved characters, device names (including extension forms), trailing dots/spaces, .git/.gitattributes aliases, separators, and folded NFC/case collisions on every platform. This prevents import from accepting a graph that a later Windows projection cannot safely materialize.
  4. Unknown formats have a closed response vocabulary. Rust returns only sha256 or unknown for unsupported formats; the TypeScript decoder accepts exactly those values. Raw untrusted config text is no longer reflected across the protocol.
  5. Regression and delivery closure. New real-helper fixtures replace the loose bytes stored under claimed commit/tree keys and prove stable rejection before destination creation. The Windows skip inventory was regenerated, the architecture docs and PR body now describe the consolidated admission/import authority, and stale test counts were removed.

Verification at head 8abe835a1:

  • Gitoxide helper admission workflow: Ubuntu, macOS, and Windows all pass, including Rust 1.98 formatting, Rust helper tests, Runtime Host build, and real-helper contracts.
  • Local Runtime Host build and focused protocol tests pass.
  • Windows skip inventory is current at 64 declarations; CI planner is 32/32.
  • Biome and git diff --check pass.
  • The general test and package jobs are still running; the earlier inventory failure is closed.

The Draft boundary remains unchanged: packaged-release trust, protected installation, state-root destination capability, partial-artifact recovery ownership, and Desktop/CLI/Write/Edit consumers remain follow-up gates.

中文说明

已在 ea3699465b0c79b25b8abe835a1 中处理剩余问题:

  1. claimed object identity 在使用前显式验证。 新的唯一 load_verified_object() owner 会依次执行 header 类型/大小检查、受限读取、loaded kind/size 复核和 Data::verify_checksum(expected_oid)。inspection 校验 HEAD commit;import 校验 expected commit 以及全部 reachable tree/blob。Rust/TypeScript 穷举错误合同新增稳定 identity-mismatch reason。
  2. preflight 与 copy 共用同一个 graph walker。 原来的两套近似实现已合并为 walk_verified_source_tree 的 validate-only/copy 两种模式。每棵 tree 都在 parse/递归前完成 checksum,两个 pass 使用完全相同的 depth、visit、entry、path、tree-byte、blob/file/total-byte 预算。
  3. managedTreePolicyVersion: 1 明确定义为 portable policy。 所有平台统一拒绝 ASCII control、Windows reserved characters/device names(含扩展名形式)、尾部点/空格、.git/.gitattributes 别名、separator 和 NFC+大小写折叠冲突,避免 import 接受但 Windows projection 无法安全物化。
  4. unknown object format 使用闭合词汇。 Rust 对不支持格式只返回 sha256unknown,TypeScript decoder 也只接受这两项,不再回显任意未受信配置文本。
  5. 回归与交付收尾。 真实 helper fixture 会把另一对象 bytes 放进 claimed commit/tree 的 loose storage key,证明 destination 创建前稳定拒绝。Windows inventory、架构文档和 PR body 均已更新。

当前 head 8abe835a1 的验证:

  • Ubuntu、macOS、Windows 专属 Gitoxide workflow 全部通过,包括 Rust 1.98 formatting、Rust helper suite、Runtime Host build 和真实 helper contract;
  • 本地 Runtime Host build 与定向 protocol tests 通过;
  • Windows inventory 当前为 64 条,CI planner 32/32;
  • Biome 与 git diff --check 通过;
  • 通用 test/package 仍在运行,旧的 inventory 红灯已经关闭。

Draft 的后续边界没有伪装完成:packaged-release trust、受保护安装目录、state-root destination capability、partial artifact recovery owner 以及 Desktop/CLI/Write/Edit consumer 仍属于后续切片。

@zhiiw

zhiiw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed re-review. I addressed the remaining import-authority findings in 90b051892 and 3c6ab082b.

  • Canonical Git tree identity: the verified walker now rejects every raw mode token except 40000, 100644, and 100755 before destination claim. It also enforces Git's canonical base_name_compare ordering, including the implicit / suffix for directories. The pinned gix EntryRef does not implement Ord, so the comparison is implemented explicitly and covered for file/directory prefix cases.
  • Versioned portable path equivalence: the collision key is now Unicode 17.0 NFC -> Unicode 16.0 Default Full Case Folding (non-Turkic) -> Unicode 17.0 NFC, using pinned caseless = 0.2.2. Original and folded paths have independent per-path and aggregate byte budgets. Greek final sigma, Straße/STRASSE, NFC/NFD equivalence, and lowercase superscript device names are covered.
  • Exact response correlation: the Runtime Host decoder now binds a successful import response to the requested source HEAD, baseline ref, and managed-tree policy version. A structurally valid response for another request is rejected as gitoxide_helper_invocation_protocol_invalid.
  • Bounded observation memory: the preflight path set is dropped before the copy pass; only scalar expected counts survive, and the response is derived from the copy pass after cross-observation validation.
  • Contract wording: the documents now describe this as a portable lexical policy. They explicitly defer real path-length, 8.3 alias, volume case behavior, ACL, and post-create observation to a future filesystem materialization profile.

Regression coverage now includes corrupt blob storage identity, raw noncanonical/zero-padded modes, unsorted raw trees, Unicode fold collisions, lowercase reserved-device paths, and mismatched helper responses. All current checks pass: the fresh Rust helper and real invocation contract on Ubuntu/macOS/Windows, the main CI suite, dependency audit, and the Windows release/update/rollback contract.

This PR can now be treated as merge-ready enabling infrastructure rather than product-ready functionality. The absence of a currently activated Desktop/CLI/Write/Edit consumer does not, by itself, require Draft status: the slice proves a complete repository-admission/import invariant, remains inert in production, and has concrete extracted downstream consumers for successor/projection, packaged authority, and Runtime Host composition. Those later slices must still land before managed mode is exposed to users.

GitHub currently reports the PR as mergeable, and a merge-tree check against current upstream/main is clean. This PR still does not claim to provide the packaged trust root, protected installation root, durable state-root artifact owner, projection/recovery owner, or a user-visible managed-workspace capability.

中文说明

感谢这次细致的复审。本轮剩余问题已经在 90b0518923c6ab082b 中处理:

  • Canonical Git tree identity: verified walker 会在领取 destination 之前,只允许 raw mode token 40000100644100755。同时按 Git 的 base_name_compare 规则验证 canonical ordering,目录按隐含 / 后缀参与比较。锁定版本的 gix::EntryRef 实际没有实现 Ord,因此这里显式实现并测试了文件、目录和前缀排序。
  • 版本化 portable path equivalence: collision key 固定为 Unicode 17.0 NFC -> Unicode 16.0 Default Full Case Folding(non-Turkic)-> Unicode 17.0 NFC,并锁定 caseless = 0.2.2。原路径和 fold 后路径分别有单路径与累计 byte budget。已覆盖 Greek final sigma、Straße/STRASSE、NFC/NFD 和小写 superscript 设备名。
  • Exact response correlation: Runtime Host decoder 现在会把成功响应精确绑定到请求的 source HEAD、baseline ref 和 policy version;另一个请求的合法 shape 响应会被拒绝为 gitoxide_helper_invocation_protocol_invalid
  • 内存边界: preflight 的 path set 会在 copy pass 前释放,只保留标量计数;最终响应来自 copy pass,并验证两次 observation 一致。
  • 文档收窄: 当前能力明确命名为 portable lexical policy;真实 path-length、8.3 alias、volume case、ACL 和 post-create observation 由后续 filesystem materialization profile 证明。

新增回归覆盖 corrupt blob storage identity、非 canonical/zero-padded raw mode、未排序 raw tree、Unicode fold collision、小写 reserved-device path 和错配 helper response。当前 Gitoxide 三平台 gate、通用 CI、Dependency audit、Windows release/update/rollback contract 均已通过。

当前 PR 可以视为可合并的 enabling infrastructure,但不能视为已经产品化的功能。没有已经激活的 Desktop/CLI/Write/Edit 消费者,本身不再构成必须保持 Draft 的理由:本切片已经独立证明完整的 repository admission/import 不变量,默认不会激活生产行为,而且 successor/projection、packaged authority 和 Runtime Host composition 都已有明确的下游 extraction slice。只有这些下游能力完成后,managed mode 才能向用户开放。

GitHub 当前报告 PR 可合并,和最新 upstream/main 的 merge-tree 也无冲突。本 PR 仍不声称已经提供 packaged trust root、受保护安装目录、durable state-root artifact owner、projection/recovery owner 或用户可见的 managed-workspace 能力。

@zhiiw
zhiiw marked this pull request as ready for review August 24, 2026 17:06
@zhiiw
zhiiw marked this pull request as draft August 24, 2026 18:01
@zhiiw
zhiiw marked this pull request as ready for review August 24, 2026 18:10
@zhiiw

zhiiw commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Addressed both remaining findings in 9e3163af3 and b1604d358.

  1. Repository metadata is now bounded before gix::open(). The helper resolves the exact .git / commondir metadata path files with bounded readers, accounts those bytes plus the repository-local config and config.worktree, and rejects totals above 1 MiB with the allowlisted repository_metadata_limit_exceeded reason. Only after that gate does Gitoxide open the repository. lossy_config(true) also avoids retaining comments and whitespace inside the admitted budget. The real Rust helper regression exercises both inspect and import with an oversized local config and proves import rejects before destination creation.
  2. The process marker handshake now uses elapsed time. The test waits against a 10-second monotonic performance.now() deadline rather than 1,000 scheduler turns. It deliberately waits for a marker published after one wall-clock second, while retaining setImmediate only as the polling yield so it remains independent of the mocked operation timeout clock. The dedicated workflow now uses the repository release contract, Node 24.18.1.

The dedicated Gitoxide admission gate is green on Ubuntu, macOS, and Windows, including Rust 1.98 formatting, the new real-helper metadata regression, Runtime Host build, and the invocation/process-tree contract. Dependency audit is also green; the broader CI and Windows package jobs are still running.

中文说明

两个剩余问题已在 9e3163af3b1604d358 中处理。

  1. repository metadata 在 gix::open() 前受预算约束。 helper 会先用有界 reader 解析 .git / commondir 路径文件,并累计这些文件以及 repository-local configconfig.worktree 的实际字节数;总量超过 1 MiB 时稳定返回白名单内的 repository_metadata_limit_exceeded,只有通过这道门后 Gitoxide 才会打开仓库。同时启用 lossy_config(true),避免在预算内继续保留无关注释和空白。真实 Rust helper 回归同时覆盖 inspect 与 import,并证明超大 local config 会在 destination 创建前被拒绝。
  2. process marker 握手改用真实经过时间。 测试现在使用单调的 performance.now() 和 10 秒截止时间,不再把 1,000 次调度当作超时。新增回归会在真实 1 秒后发布 marker;轮询只用 setImmediate 让出调度,因此不会被 operation timeout 的 mock clock 卡住。专用 workflow 也已切到仓库 release 合同中的 Node 24.18.1

Gitoxide 专用 gate 已在 Ubuntu、macOS、Windows 全部通过,包含 Rust 1.98 formatting、新增真实 helper metadata 回归、Runtime Host build 与 invocation/process-tree 合同。Dependency audit 也已通过;通用 CI 和 Windows package job 仍在运行。

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.

1 participant