Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/codeql-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ jobs:
echo "::error::Could not validate required run creation time before CodeQL verdict lookup."
exit 1
fi
runs_json="$(gh api --method GET --paginate --slurp -f per_page=100 -f event=repository_dispatch -f created=">=${required_created_at}" "repos/ContextualWisdomLab/.github/actions/workflows/codeql-scan-dispatch.yml/runs")"
runs_json="$(gh api --method GET --paginate -f per_page=100 -f event=repository_dispatch -f created=">=${required_created_at}" "repos/ContextualWisdomLab/.github/actions/workflows/codeql-scan-dispatch.yml/runs" | jq -s .)"
run_id="$(printf '%s' "$runs_json" | jq -r --arg title "$expected_title" --arg path ".github/workflows/codeql-scan-dispatch.yml" '
[
.[] | .workflow_runs[]
Expand All @@ -263,7 +263,7 @@ jobs:
| .id // empty
')"
if [[ "$run_id" =~ ^[1-9][0-9]*$ ]]; then
jobs_json="$(gh api --paginate --slurp "repos/ContextualWisdomLab/.github/actions/runs/${run_id}/jobs")"
jobs_json="$(gh api --paginate "repos/ContextualWisdomLab/.github/actions/runs/${run_id}/jobs" | jq -s .)"
dispatch_job="$(printf '%s' "$jobs_json" | jq -c --arg name "$expected_job" '
[.[] | .jobs[] | select(.name == $name)]
| if length == 1 then .[0] else empty end
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/codeql-scan-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1057,7 +1057,7 @@ jobs:
exit 1
fi

if ! required_job_pages="$(github_api --paginate --slurp "repos/${TARGET_REPOSITORY}/actions/runs/${REQUIRED_RUN_ID}/jobs?per_page=100")"; then
if ! required_job_pages="$(github_api --paginate "repos/${TARGET_REPOSITORY}/actions/runs/${REQUIRED_RUN_ID}/jobs?per_page=100" | jq -s .)"; then
echo "::error::CodeQL settlement could not read the required jobs."
exit 1
fi
Expand Down Expand Up @@ -1094,8 +1094,8 @@ jobs:
exit 1
fi

if ! handler_job_pages="$(GH_TOKEN="$HANDLER_READ_TOKEN" gh api --paginate --slurp "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs?per_page=100")" ||
! handler_artifact_pages="$(GH_TOKEN="$HANDLER_READ_TOKEN" gh api --paginate --slurp "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/artifacts?per_page=100")"; then
if ! handler_job_pages="$(GH_TOKEN="$HANDLER_READ_TOKEN" gh api --paginate "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs?per_page=100" | jq -s .)" ||
! handler_artifact_pages="$(GH_TOKEN="$HANDLER_READ_TOKEN" gh api --paginate "repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/artifacts?per_page=100" | jq -s .)"; then
echo "::error::CodeQL settlement could not read exact handler evidence."
exit 1
fi
Expand Down
20 changes: 20 additions & 0 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -733,10 +733,30 @@ jobs:
# the generic Python coverage path failed at collection with `ImportError: cannot
# import name '_core'`, both surfacing as an indistinguishable "Coverage gate: failure"
# even when the pull request itself introduced no regression.
rust_lock_args=()
rust_change_files="${RUNNER_TEMP}/opencode-rust-change-files"
if ! git -C "$COVERAGE_SOURCE_WORKDIR" diff --no-renames --name-only -z \
"$PR_BASE_SHA" "$PR_HEAD_SHA" >"$rust_change_files"; then
echo "::error::Could not classify exact-head Cargo changes." >&2
exit 1
fi
rust_lock_changed=0
rust_manifest_changed=0
while IFS= read -r -d '' changed_path; do
case "${changed_path##*/}" in
Cargo.lock) rust_lock_changed=1 ;;
Cargo.toml) rust_manifest_changed=1 ;;
esac
done <"$rust_change_files"
if [ "$rust_lock_changed" -eq 1 ] && [ "$rust_manifest_changed" -eq 0 ]; then
# The trusted materializer still rejects non-base pins and changed graphs.
rust_lock_args=(--head-sha "$PR_HEAD_SHA")
fi
python3 -I "$GITHUB_WORKSPACE/scripts/ci/materialize_base_rust_dependencies.py" \
--repo-root "$COVERAGE_SOURCE_WORKDIR" \
--base-sha "$PR_BASE_SHA" \
--output-dir "$coverage_build_dir/base-rust-dependencies" \
"${rust_lock_args[@]}" \
--vendor-dir-for-config /opt/base-rust-dependencies/vendor
cat >"$coverage_build_dir/Dockerfile" <<'DOCKERFILE'
FROM docker.io/library/python:3.14-slim@sha256:b877e50bd90de10af8d82c57a022fc2e0dc731c5320d762a27986facfc3355c1
Expand Down
216 changes: 202 additions & 14 deletions scripts/ci/materialize_base_rust_dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
manifests are read (never the pull request's), and vendoring itself uses Cargo's own built-in
per-package checksum verification (every ``[[package]]`` entry in a lock file carries a
``checksum``), so no separate hash-pin parser is needed the way ``requirements*.txt`` needed one.

An explicit ``--head-sha`` opts into a narrower lock-repair intake: every Cargo manifest
remains byte-identical to base, every registry record (including resolved dependency edges)
must already occur in the base lock union, and local identities must already be base-pinned.
Only lock bytes are overlaid; Cargo vendor --locked still verifies the unchanged manifests
and package checksums. Separate provenance records the base manifests and head lock blobs.
"""

from __future__ import annotations
Expand Down Expand Up @@ -120,7 +126,9 @@ def _select_vendor_roots(
for path in cargo_paths
if path.endswith("Cargo.lock")
}
for manifest_path in sorted(path for path in cargo_paths if path.endswith("Cargo.toml")):
for manifest_path in sorted(
path for path in cargo_paths if path.endswith("Cargo.toml")
):
content = _git(repo_root, "show", f"{base_sha}:{manifest_path}")
if not _is_workspace_manifest(content):
continue
Expand All @@ -131,7 +139,9 @@ def _select_vendor_roots(
)
for lock_dir in sorted(locks):
if lock_dir not in manifests:
raise RuntimeError(f"base Cargo.lock at {lock_dir} has no sibling Cargo.toml")
raise RuntimeError(
f"base Cargo.lock at {lock_dir} has no sibling Cargo.toml"
)
if not locks:
return []
# Deterministic order with the repository root first when it is one of the roots,
Expand All @@ -156,18 +166,27 @@ def _placeholder_target_paths(manifest_content: bytes) -> list[str]:
if "package" not in parsed:
return []
paths = {"src/lib.rs", "src/main.rs"}
lib_path = parsed.get("lib", {}).get("path") if isinstance(parsed.get("lib"), dict) else None
lib_path = (
parsed.get("lib", {}).get("path")
if isinstance(parsed.get("lib"), dict)
else None
)
if isinstance(lib_path, str):
paths.add(lib_path)
for bin_target in parsed.get("bin", []) if isinstance(parsed.get("bin"), list) else []:
for bin_target in (
parsed.get("bin", []) if isinstance(parsed.get("bin"), list) else []
):
bin_path = bin_target.get("path") if isinstance(bin_target, dict) else None
if isinstance(bin_path, str):
paths.add(bin_path)
return sorted(paths)


def _reconstruct_base_tree(
repo_root: pathlib.Path, base_sha: str, cargo_paths: list[str], work_dir: pathlib.Path
repo_root: pathlib.Path,
base_sha: str,
cargo_paths: list[str],
work_dir: pathlib.Path,
) -> None:
"""Write every tracked base Cargo manifest into ``work_dir`` at its repository path.

Expand All @@ -182,7 +201,10 @@ def _reconstruct_base_tree(
if destination.name == "Cargo.toml":
for target_path in _placeholder_target_paths(content):
target_relative_path = pathlib.PurePosixPath(target_path)
if target_relative_path.is_absolute() or ".." in target_relative_path.parts:
if (
target_relative_path.is_absolute()
or ".." in target_relative_path.parts
):
raise RuntimeError(
"Cargo target path must stay inside its manifest root: "
f"{target_path}"
Expand Down Expand Up @@ -227,14 +249,151 @@ def _run_cargo_vendor(
)


def _normalized_lock_records(content: bytes) -> list[dict]:
"""Compare bounded lock records with uniquely resolved dependency identities."""
parsed = tomllib.loads(content.decode("utf-8"))
packages = parsed.get("package")
if (
set(parsed) - {"version", "package"}
or parsed.get("version") not in {3, 4}
or not isinstance(packages, list)
or len(packages) > 10000
):
raise ValueError("head intake requires a bounded version 3/4 Cargo lock")
identities = {}
by_name = {}
for package in packages:
if not isinstance(package, dict):
raise ValueError("invalid Cargo lock package")
source = package.get("source")
allowed = {"name", "version", "dependencies"}
if source is not None:
allowed |= {"source", "checksum"}
if (
source != "registry+https://github.com/rust-lang/crates.io-index"
or not isinstance(package.get("checksum"), str)
or not re.fullmatch(r"[0-9a-f]{64}", package["checksum"])
):
raise ValueError(
"head intake requires existing crates.io checksum pins"
)
if set(package) - allowed or any(
not isinstance(package.get(k), str) or not package[k]
for k in ("name", "version")
):
raise ValueError("unsupported Cargo lock package fields")
identity = (package["name"], package["version"], source)
if identity in identities:
raise ValueError("duplicate Cargo lock package identity")
identities[identity] = package
by_name.setdefault(identity[0], []).append(identity)
records = []
for package in packages:
dependencies = package.get("dependencies", [])
if not isinstance(dependencies, list) or len(dependencies) > 10000:
raise ValueError("invalid Cargo lock dependencies")
edges = []
for dependency in dependencies:
if not isinstance(dependency, str):
raise ValueError("invalid Cargo lock dependency identity")
parts = dependency.split()
if not 1 <= len(parts) <= 3:
raise ValueError("unsupported Cargo lock dependency identity")
candidates = [
identity
for identity in by_name.get(parts[0], [])
if (len(parts) < 2 or identity[1] == parts[1])
and (len(parts) < 3 or f"({identity[2]})" == parts[2])
]
if len(candidates) != 1:
raise ValueError("missing or ambiguous Cargo lock dependency identity")
edges.append(candidates[0])
if len(edges) != len(set(edges)):
raise ValueError("duplicate Cargo lock dependency edge")
records.append({**package, "dependencies": sorted(edges, key=repr)})
return records


def _validated_head_locks(
repo_root: pathlib.Path, base_sha: str, head_sha: str, cargo_paths: list[str]
) -> tuple[dict[str, bytes], dict]:
"""Allow head locks only to recombine records pinned in the base lock union.

Manifest bytes remain from base. Local-package closure still requires the
unchanged base manifests to pass Cargo vendor --locked; this function does
not authorize new registry records, git sources or package checksums.
"""
if not SHA_RE.fullmatch(head_sha):
raise ValueError("head SHA must be exactly 40 hexadecimal characters")
head_paths = _regular_cargo_blob_paths(repo_root, head_sha)
if head_paths != cargo_paths:
raise ValueError("head Cargo manifest/lock paths must equal base")
changed = _git(repo_root, "diff", "--name-only", "-z", base_sha, head_sha).split(
b"\0"
)
if any(
path and pathlib.PurePosixPath(path.decode()).name == "Cargo.toml"
for path in changed
):
raise ValueError("head Cargo manifests must remain byte-identical to base")

def lock_bytes(revision: str, path: str) -> bytes:
"""Read a revision-pinned lock after checking its bounded blob size."""
size = int(_git(repo_root, "cat-file", "-s", f"{revision}:{path}"))
if size > 16 * 1024 * 1024:
raise ValueError("Cargo lock exceeds bounded size")
return _git(repo_root, "show", f"{revision}:{path}")

paths = [path for path in cargo_paths if path.endswith("Cargo.lock")]
base_records = []
for path in paths:
base_records.extend(_normalized_lock_records(lock_bytes(base_sha, path)))
registry_records = {
json.dumps(row, sort_keys=True) for row in base_records if row.get("source")
}
local_identities = {
(row["name"], row["version"]) for row in base_records if not row.get("source")
}
locks = {}
receipts = []
for path in paths:
content = lock_bytes(head_sha, path)
for row in _normalized_lock_records(content):
if row.get("source"):
if json.dumps(row, sort_keys=True) not in registry_records:
raise ValueError(
"head registry record differs from base lock union"
)
elif (row["name"], row["version"]) not in local_identities:
raise ValueError("head local identity differs from base lock union")
locks[path] = content
receipts.append(
{
"path": path,
"base_lock_blob": _git(repo_root, "rev-parse", f"{base_sha}:{path}")
.decode()
.strip(),
"lock_blob": _git(repo_root, "rev-parse", f"{head_sha}:{path}")
.decode()
.strip(),
}
)
return locks, {
"manifest_revision": base_sha.lower(),
"lock_revision": head_sha.lower(),
"locks": receipts,
}


def materialize(
repo_root: pathlib.Path,
base_sha: str,
output_dir: pathlib.Path,
*,
vendor_dir_for_config: str | None = None,
head_sha: str | None = None,
) -> list[str]:
"""Vendor the base commit's Cargo dependency closure into ``output_dir``.
"""Vendor base manifests with base locks or explicitly bounded head locks.

Returns the list of source-tree-relative ``Cargo.lock`` paths that were vendored. An empty
list means no Rust project (or no lock file) exists at the base commit, which is not an
Expand All @@ -256,6 +415,11 @@ def materialize(
cargo_paths = _regular_cargo_blob_paths(resolved_repo, base_sha)
vendor_roots = _select_vendor_roots(resolved_repo, base_sha, cargo_paths)
manifest: list[str] = []
head_locks, provenance = (
_validated_head_locks(resolved_repo, base_sha, head_sha, cargo_paths)
if head_sha is not None
else ({}, None)
)
if vendor_roots:
primary_root, *additional_roots = vendor_roots

Expand All @@ -270,8 +434,12 @@ def _lock_for(root: str) -> str:
with tempfile.TemporaryDirectory() as work_dir:
work_path = pathlib.Path(work_dir)
_reconstruct_base_tree(resolved_repo, base_sha, cargo_paths, work_path)
for path, content in head_locks.items():
(work_path / path).write_bytes(content)
manifest_path = _manifest_for(primary_root, work_path)
sync_manifests = [_manifest_for(root, work_path) for root in additional_roots]
sync_manifests = [
_manifest_for(root, work_path) for root in additional_roots
]
# Every root's lock is reported, so a failure names the whole vendored set
# rather than only the primary root.
lock_path = ", ".join(_lock_for(root) for root in vendor_roots)
Expand All @@ -286,10 +454,14 @@ def _lock_for(root: str) -> str:
if completed.returncode != 0:
stderr = completed.stderr.decode("utf-8", errors="replace")
normalized_stderr = " ".join(stderr.split())
detail = normalized_stderr[:500] if normalized_stderr else (
f"exit status {completed.returncode}"
detail = (
normalized_stderr[:500]
if normalized_stderr
else (f"exit status {completed.returncode}")
)
raise RuntimeError(
f"cargo vendor failed for base lock {lock_path}: {detail}"
)
raise RuntimeError(f"cargo vendor failed for base lock {lock_path}: {detail}")
config_text = completed.stdout
if vendor_dir_for_config is not None:
config_text = config_text.replace(
Expand All @@ -299,6 +471,10 @@ def _lock_for(root: str) -> str:
(output_dir / "cargo-config.toml").write_bytes(config_text)
manifest = [_lock_for(root) for root in vendor_roots]

if provenance is not None:
(output_dir / "lock-provenance.json").write_text(
json.dumps(provenance, indent=2) + "\n"
)
(output_dir / "manifest.json").write_text(
json.dumps(manifest, indent=2, sort_keys=True) + "\n",
encoding="utf-8",
Expand All @@ -311,6 +487,7 @@ def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--repo-root", required=True, type=pathlib.Path)
parser.add_argument("--base-sha", required=True)
parser.add_argument("--head-sha", default=None)
parser.add_argument("--output-dir", required=True, type=pathlib.Path)
parser.add_argument("--vendor-dir-for-config", default=None)
args = parser.parse_args(argv)
Expand All @@ -321,17 +498,28 @@ def main(argv: list[str] | None = None) -> int:
args.base_sha,
args.output_dir,
vendor_dir_for_config=args.vendor_dir_for_config,
head_sha=args.head_sha,
)
except (OSError, RuntimeError, ValueError) as exc:
print(
f"::error::Could not materialize base Rust dependencies: {exc}", file=sys.stderr
f"::error::Could not materialize base Rust dependencies: {exc}",
file=sys.stderr,
)
return 1

if manifest:
print(f"Materialized trusted base Cargo vendor directory from {manifest[0]}.")
if args.head_sha:
print(
f"Materialized Cargo vendor directory from base manifests and bounded head locks: {manifest[0]}."
)
else:
print(
f"Materialized trusted base Cargo vendor directory from {manifest[0]}."
)
else:
print("No tracked Cargo.lock exists at the validated base SHA; Rust vendoring skipped.")
print(
"No tracked Cargo.lock exists at the validated base SHA; Rust vendoring skipped."
)
return 0


Expand Down
Loading
Loading