You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@magpie.apache.org by po...@apache.org on 2026/09/18 17:48:49 UTC
(magpie) branch main updated: fix(vetted-ops): repo-tree must not answer with a truncated tree (#1282)
This is an automated email from the ASF dual-hosted git repository.
potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/magpie.git
The following commit(s) were added to refs/heads/main by this push:
new 237fa1d8 fix(vetted-ops): repo-tree must not answer with a truncated tree (#1282)
237fa1d8 is described below
commit 237fa1d86ada3d11c6e5f605c2d2fdc207b5b9f7
Author: Jarek Potiuk <ja...@potiuk.com>
AuthorDate: Fri Sep 18 19:48:44 2026 +0200
fix(vetted-ops): repo-tree must not answer with a truncated tree (#1282)
`repo-tree` asks for a recursive git tree and projects the response
straight to `.tree[].path`. On a large repository the GitHub API answers
`recursive=1` with `truncated: true` and a *partial* `tree`, and that
projection discards the flag — the caller gets a short listing that is
indistinguishable from a complete one.
The failure is silent and the output is plausible, which is the worst
shape a read operation can fail in. Observed on a private archive: the
operation returned 56,981 paths and every entry under one top-level
directory was simply absent, so a sweep built on it concluded that
directory did not exist.
Surface the truncation as a jq `error(...)` instead. `gh` then exits
non-zero and the dispatcher reports exit code 4 (the underlying command
failed) rather than success with half a tree. A complete response is
unaffected and still projects to plain paths.
Generated-by: Claude Opus 5
---
tools/vetted-ops/src/vetted_ops/ops.py | 9 ++++++++-
tools/vetted-ops/tests/test_vetted_ops.py | 23 +++++++++++++++++++++++
2 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/tools/vetted-ops/src/vetted_ops/ops.py b/tools/vetted-ops/src/vetted_ops/ops.py
index 356e3c23..67132e7d 100644
--- a/tools/vetted-ops/src/vetted_ops/ops.py
+++ b/tools/vetted-ops/src/vetted_ops/ops.py
@@ -1650,7 +1650,14 @@ _register(
"-f",
"recursive=1",
"--jq",
- ".tree[].path",
+ # A recursive tree over a large repository comes back with
+ # `truncated: true` and a partial `tree`. Projecting straight to
+ # paths drops that flag, so a caller cannot tell a complete listing
+ # from a partial one and reads the gap as "those paths do not
+ # exist". Fail loudly instead of answering with half a tree.
+ 'if .truncated then error("repo-tree: the GitHub API truncated '
+ "this tree; the listing is incomplete. Walk the tree level by "
+ 'level instead of relying on recursive=1.") else .tree[].path end',
],
)
)
diff --git a/tools/vetted-ops/tests/test_vetted_ops.py b/tools/vetted-ops/tests/test_vetted_ops.py
index d6452ce0..01844e4f 100644
--- a/tools/vetted-ops/tests/test_vetted_ops.py
+++ b/tools/vetted-ops/tests/test_vetted_ops.py
@@ -372,6 +372,29 @@ def test_no_read_operation_sends_fields_without_an_explicit_get(policy: config.C
assert argv[argv.index("-X") + 1] == "GET", f"{name} sends fields with a non-GET method"
+def test_repo_tree_refuses_to_report_a_truncated_listing(policy: config.Config) -> None:
+ """
+ `gh api .../git/trees/<ref>?recursive=1` answers a large repository with
+ `truncated: true` and a *partial* `tree`. Projecting straight to
+ `.tree[].path` discards that flag, so the caller receives a short listing
+ that is indistinguishable from a complete one — and concludes that whole
+ directories do not exist.
+
+ That is the worst shape a read operation can fail in: silently, with
+ plausible output. The builder must surface the truncation as an error so the
+ dispatcher exits non-zero (code 4) instead of answering with half a tree.
+ """
+ op = ops.resolve("repo-tree")
+ params, _ = cli._validate_params(op, ["main"], policy)
+ argv = cli.build_argv(op, params, policy)
+
+ jq = argv[argv.index("--jq") + 1]
+ assert ".truncated" in jq, "repo-tree drops the API's truncation flag"
+ assert "error(" in jq, "repo-tree must fail loudly on a truncated tree"
+ # The complete-tree path still projects to plain paths.
+ assert ".tree[].path" in jq
+
+
def test_board_add_item_takes_a_content_node_id(policy: config.Config) -> None:
"""
Adding an issue to the board keys on the *content* node id, not a project