Skip to content

fix(xtask): resolve local-registry install via sparse+file index (#856) - #970

Open
EffortlessSteven wants to merge 4 commits into
mainfrom
fix/856-sparse-registry-install
Open

fix(xtask): resolve local-registry install via sparse+file index (#856)#970
EffortlessSteven wants to merge 4 commits into
mainfrom
fix/856-sparse-registry-install

Conversation

@EffortlessSteven

@EffortlessSteven EffortlessSteven commented Jul 25, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix verify-local-release-install Linux index resolution by using sparse+file:// for the isolated registry index and cargo install --registry adze-local instead of anonymous --index.
  • Inject registry = "adze-local" into packaged workspace manifests so install-time dependency resolution stays on the local registry.
  • Default the Local Release Receipt workflow input to workspace version 0.9.0 (0.10.0 remains blocked on release: authorize publish workflow and capture crates.io install receipt #325).

Root cause

Publish succeeded but cargo install --index file://… could not resolve adze-cli on ubuntu-latest. Cargo treats plain file:// as git-index protocol; the harness writes sparse index files. Switching to sparse+file:// + named registry matches Cargo's sparse local registry contract.

Test plan

  • cargo test -p xtask local_registry
  • cargo test -p xtask local_release
  • Re-dispatch Local Release Receipt on fix/856-sparse-registry-install with version 0.9.0 after merge (or on branch pre-merge)

Claim boundary

Proves pre-release local-registry package-first flow at current workspace version (0.9.0). Does not prove crates.io install, 0.10.0 publish, or #325 release authorization.

Parent: #856 / #853


Summary by cubic

Fixes Linux local-registry installs by switching to a git-backed local index at file:// and installing via cargo install --registry adze-local. Packaged crates pin workspace deps to adze-local; crate downloads use file://.

  • Bug Fixes

    • Use a git index at file:// and set config.json dl to file://; install via --registry adze-local.
    • Repack packaged crates to inject registry = "adze-local" for workspace deps (including under target.*); fail if any path deps remain or pins are missing.
  • New Features

Written for commit d4570b6. Summary will update on new commits.

Review in cubic

Adds a manual ubuntu-latest lane that runs verify-local-release-install and uploads the machine-readable receipt artifact. Registers the lane in policy/ci-lane-whitelist.toml as advisory deep product proof.

Co-authored-by: Cursor <cursoragent@cursor.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

Local release receipt flow

Layer / File(s) Summary
Registry-pinned crate packaging
xtask/src/local_registry.rs
Packaged crates are rewritten with adze-local registry pins for published workspace dependencies, including target-specific tables, and validated before repacking.
Sparse registry installation
xtask/src/local_registry.rs
Local registry configuration uses sparse+file:// indexes, while CLI installation selects the adze-local registry by name.
Receipt workflow and CI lane
.github/workflows/local-release-receipt.yml, policy/ci-lane-whitelist.toml
A manual workflow runs verification in dry-run or receipt mode, uploads generated JSON, and registers the corresponding non-blocking CI lane and evidence.
Estimated code review effort: 4 (Complex) ~45 minutes

Possibly related issues

  • Issue 856 — Adds the isolated local-registry package/install receipt flow and CI evidence generation described by the issue.

Poem

A rabbit hops through crates so neat,
Pins each path with registry feet.
Sparse files shine, installs run true,
A receipt blooms in artifact blue.
“Hop-hop!” says Bun, “the proof is sweet!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main fix: local-registry installs via a sparse+file index in xtask.
Description check ✅ Passed The description matches the changeset, covering the registry fix, manifest pinning, and receipt workflow update.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/856-sparse-registry-install

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/local-release-receipt.yml:
- Line 29: Pin the third-party actions in the workflow—actions/checkout,
dtolnay/rust-toolchain, and actions/upload-artifact—to their resolved immutable
commit SHAs instead of the current version tags or master branch, preserving
each action’s existing version/reference.
- Line 29: Update the actions/checkout step to disable credential persistence by
setting persist-credentials to false; leave the existing checkout version and
workflow steps unchanged.
- Line 38: Update both run steps invoking verify-local-release-install to pass
inputs.version through an environment variable, then reference that variable in
the shell command instead of interpolating the GitHub expression inside the
script. Preserve the existing command arguments and dry-run behavior while
ensuring the untrusted value is not embedded in shell script text.

In `@xtask/src/local_registry.rs`:
- Around line 127-138: Extend manifest_missing_registry_for_workspace_deps to
inspect every target.<cfg>.dependencies table in addition to the top-level
dependency tables, matching the target-table handling in
inject_registry_into_manifest. Update the related regression test to include an
unpinned workspace dependency under a target-specific table and verify the
checker rejects it.
- Around line 589-665: The dependency checks in inject_registry_into_manifest
and the corresponding target-specific path must match published_set against each
dependency’s effective package name, using the package field when present and
the table key otherwise. Apply this lookup consistently before
registry_pinned_dependency_spec and in the related validation logic so renamed
dependencies such as parser/package = "adze-parser" are pinned correctly.
- Around line 701-760: The crate packaging flow should no longer depend on
external tar subprocesses. Replace the extract, manifest rewrite, and repack
logic in repack_crate_with_manifest, together with the related manifest-read
path in the same module, with in-process Rust tar/gzip handling using the
project’s tar/flate2 support; preserve archive contents, crate-root layout, and
existing error context.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 590bd3aa-4fb4-4473-b51b-8246ee0b43bc

📥 Commits

Reviewing files that changed from the base of the PR and between dd68e22 and d23d58b.

📒 Files selected for processing (3)
  • .github/workflows/local-release-receipt.yml
  • policy/ci-lane-whitelist.toml
  • xtask/src/local_registry.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • EffortlessMetrics/adze (auto-detected)
  • EffortlessMetrics/em-ci (auto-detected)
  • EffortlessMetrics/ripr (auto-detected)
  • EffortlessMetrics/unsafe-review (auto-detected)
  • EffortlessMetrics/cargo-allow (auto-detected)

runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v6.0.2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Security Misconfiguration (CWE-1357)

Reachability: Internal

Pin third-party actions to a commit SHA.

actions/checkout@v6.0.2, dtolnay/rust-toolchain@master, and actions/upload-artifact@v7.0.0 are all referenced by mutable tag/branch rather than a pinned commit SHA; @master in particular can change at any time. This is flagged by policy as required (blanket SHA-pinning) and is a standard supply-chain hardening step for CI.

#!/bin/bash
# Resolve current commit SHAs for the referenced tags/branches to pin against.
gh api repos/actions/checkout/git/refs/tags/v6.0.2 --jq '.object.sha'
gh api repos/actions/upload-artifact/git/refs/tags/v7.0.0 --jq '.object.sha'
gh api repos/dtolnay/rust-toolchain/git/refs/heads/master --jq '.object.sha'

Also applies to: 32-32, 46-46

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 29-29: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 29-29: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/local-release-receipt.yml at line 29, Pin the third-party
actions in the workflow—actions/checkout, dtolnay/rust-toolchain, and
actions/upload-artifact—to their resolved immutable commit SHAs instead of the
current version tags or master branch, preserving each action’s existing
version/reference.

Source: Linters/SAST tools


🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Sensitive Data Exposure (CWE-522): Insufficiently Protected Credentials

Reachability: Internal

Disable credential persistence on checkout.

actions/checkout defaults to persist-credentials: true, leaving the GITHUB_TOKEN in .git/config for the rest of the job — including the cargo run/cargo install steps that execute arbitrary workspace/dependency build code. This job never needs to push, so persistence should be disabled.

🔒️ Proposed fix
       - uses: actions/checkout@v6.0.2
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6.0.2
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 29-29: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 29-29: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/local-release-receipt.yml at line 29, Update the
actions/checkout step to disable credential persistence by setting
persist-credentials to false; leave the existing checkout version and workflow
steps unchanged.

Source: Linters/SAST tools


- name: Run local-registry receipt (dry-run)
if: inputs.dry_run
run: cargo run -q -p xtask -- verify-local-release-install --version "${{ inputs.version }}" --dry-run

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Injection (CWE-94): Improper Control of Generation of Code ('Code Injection')

Reachability: External

Shell/template injection via ${{ inputs.version }} in run:.

Both run: steps interpolate the untrusted workflow_dispatch input directly into the shell command text. A version string containing quote/shell metacharacters can break out of the quoted argument and execute arbitrary commands on the runner. Pass the input through an environment variable instead so the value is never substituted into the script text itself.

🛡️ Proposed fix
       - name: Run local-registry receipt (dry-run)
         if: inputs.dry_run
-        run: cargo run -q -p xtask -- verify-local-release-install --version "${{ inputs.version }}" --dry-run
+        env:
+          RECEIPT_VERSION: ${{ inputs.version }}
+        run: cargo run -q -p xtask -- verify-local-release-install --version "$RECEIPT_VERSION" --dry-run

       - name: Run local-registry receipt
         if: ${{ !inputs.dry_run }}
-        run: cargo run -q -p xtask -- verify-local-release-install --version "${{ inputs.version }}" --receipt-out target/local-release-receipt.json
+        env:
+          RECEIPT_VERSION: ${{ inputs.version }}
+        run: cargo run -q -p xtask -- verify-local-release-install --version "$RECEIPT_VERSION" --receipt-out target/local-release-receipt.json

Also applies to: 42-42

🧰 Tools
🪛 zizmor (1.26.1)

[error] 38-38: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/local-release-receipt.yml at line 38, Update both run
steps invoking verify-local-release-install to pass inputs.version through an
environment variable, then reference that variable in the shell command instead
of interpolating the GitHub expression inside the script. Preserve the existing
command arguments and dry-run behavior while ensuring the untrusted value is not
embedded in shell script text.

Source: Linters/SAST tools

Comment thread xtask/src/local_registry.rs
Comment on lines +589 to +665
for (name, spec) in deps {
if !published_set.contains(name) {
continue;
}
if !dependency_spec_has_registry(spec) {
return true;
}
}
}
false
}

fn dependency_spec_has_registry(spec: &toml::Value) -> bool {
match spec {
toml::Value::Table(table) => table
.get("registry")
.and_then(toml::Value::as_str)
.is_some_and(|registry| registry == REGISTRY_NAME),
_ => false,
}
}

fn inject_registry_deps_into_crate(
crate_path: &Path,
published_set: &BTreeSet<String>,
) -> Result<()> {
let manifest_member = packaged_manifest_member(crate_path)?;
let manifest = packaged_manifest_text(crate_path)?;
let updated = inject_registry_into_manifest(&manifest, published_set)?;
if updated == manifest {
return Ok(());
}
repack_crate_with_manifest(crate_path, &manifest_member, &updated)
}

fn inject_registry_into_manifest(
manifest: &str,
published_set: &BTreeSet<String>,
) -> Result<String> {
let mut value: toml::Value = manifest
.parse()
.context("parsing packaged manifest for registry injection")?;
let root = value
.as_table_mut()
.context("packaged manifest root must be a table")?;

for table_name in ["dependencies", "dev-dependencies", "build-dependencies"] {
let Some(deps) = root.get_mut(table_name).and_then(toml::Value::as_table_mut) else {
continue;
};
for (name, spec) in deps.iter_mut() {
if !published_set.contains(name) {
continue;
}
*spec = registry_pinned_dependency_spec(spec)?;
}
}

if let Some(target) = root.get_mut("target").and_then(toml::Value::as_table_mut) {
let target_keys = target.keys().cloned().collect::<Vec<_>>();
for target_key in target_keys {
let Some(target_table) = target.get_mut(&target_key).and_then(toml::Value::as_table_mut)
else {
continue;
};
for table_name in ["dependencies", "dev-dependencies", "build-dependencies"] {
let Some(deps) = target_table
.get_mut(table_name)
.and_then(toml::Value::as_table_mut)
else {
continue;
};
for (name, spec) in deps.iter_mut() {
if !published_set.contains(name) {
continue;
}
*spec = registry_pinned_dependency_spec(spec)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== relevant locations =="
rg -n "published_set|dependency_spec_has_registry|inject_registry_into_manifest|registry_pinned_dependency_spec|package =" xtask/src/local_registry.rs

echo
echo "== file outline =="
ast-grep outline xtask/src/local_registry.rs --view expanded || true

Repository: EffortlessMetrics/adze-swarm

Length of output: 5546


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '599,720p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '888,1020p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '1025,1085p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 10585


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
text = Path('xtask/src/local_registry.rs').read_text()
for needle in [
    'package = "',
    'dependency_spec_has_registry',
    'manifest_missing_registry_for_workspace_deps',
    'inject_registry_into_manifest',
    'index_dependency(',
]:
    print(f'== {needle} ==')
    for i, line in enumerate(text.splitlines(), 1):
        if needle in line:
            start = max(1, i-5)
            end = min(len(text.splitlines()), i+25)
            for j in range(start, end+1):
                print(f'{j}:{text.splitlines()[j-1]}')
            print()
            break
PY

Repository: EffortlessMetrics/adze-swarm

Length of output: 4797


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "package\\s*=\\s*\"|published_set.contains\\(|target.*dependencies|target_keys|CargoDependency|package_name" xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 734


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('xtask/src/local_registry.rs')
lines = p.read_text().splitlines()
for start in [599, 645, 888, 1025]:
    print(f'## {start}')
    for i in range(start, min(start+45, len(lines))+1):
        print(f'{i}:{lines[i-1]}')
    print()
PY

Repository: EffortlessMetrics/adze-swarm

Length of output: 6822


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '599,720p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '888,1020p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '1025,1095p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 10915


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '100,130p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '930,1018p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 4597


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '100,125p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '430,520p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 4109


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '520,620p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '930,1035p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 7199


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "published_set|ordered_crates|BTreeSet::from|collect::<BTreeSet|package_patch_config_args|published_crates|CargoDependency \{" xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 1475


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '60,120p' xtask/src/local_registry.rs
printf '\n====\n'
sed -n '120,220p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 5796


Other (CWE-829): Inclusion of Functionality from Untrusted Control Sphere

Reachability: External

Use the effective package name when matching published deps xtask/src/local_registry.rs:599-686 — renamed deps like parser = { package = "adze-parser", ... } are skipped here because the check uses the table key instead of the dependency’s package name, so they can stay unpinned and fall back to the default registry. Apply the same lookup in the target-specific validation path too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@xtask/src/local_registry.rs` around lines 589 - 665, The dependency checks in
inject_registry_into_manifest and the corresponding target-specific path must
match published_set against each dependency’s effective package name, using the
package field when present and the table key otherwise. Apply this lookup
consistently before registry_pinned_dependency_spec and in the related
validation logic so renamed dependencies such as parser/package = "adze-parser"
are pinned correctly.

Comment on lines +701 to +760
fn repack_crate_with_manifest(
crate_path: &Path,
manifest_member: &str,
manifest: &str,
) -> Result<()> {
let extract_dir = tempfile::Builder::new()
.prefix("adze-local-crate-repack-")
.tempdir()
.context("creating crate repack extraction directory")?;
let status = Command::new("tar")
.args(["-xzf"])
.arg(crate_path)
.arg("-C")
.arg(extract_dir.path())
.status()
.with_context(|| format!("extracting {} for manifest rewrite", crate_path.display()))?;
if !status.success() {
bail!(
"failed to extract {} for manifest rewrite",
crate_path.display()
);
}

let manifest_path = extract_dir.path().join(manifest_member);
fs::write(&manifest_path, manifest).with_context(|| {
format!(
"writing registry-pinned manifest to {}",
manifest_path.display()
)
})?;

let crate_root = manifest_path
.parent()
.with_context(|| format!("missing crate root for {}", manifest_path.display()))?;
let crate_root_name = crate_root
.file_name()
.and_then(OsStr::to_str)
.with_context(|| format!("missing crate root name for {}", crate_root.display()))?;

let repacked_path = crate_path.with_extension("crate.repacked");
let status = Command::new("tar")
.args(["-czf"])
.arg(&repacked_path)
.arg("-C")
.arg(extract_dir.path())
.arg(crate_root_name)
.status()
.with_context(|| format!("repacking {}", crate_path.display()))?;
if !status.success() {
bail!("failed to repack {}", crate_path.display());
}
fs::rename(&repacked_path, crate_path).with_context(|| {
format!(
"replacing {} with registry-pinned package",
crate_path.display()
)
})?;
Ok(())
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

🧩 Analysis chain

🌐 Web query:

Are the tar and flate2 crates suitable for reading and rewriting a Cargo .crate archive's Cargo.toml in place?

💡 Result:

The tar and flate2 crates are not suitable for modifying a Cargo.crate archive in place because the underlying tar archive format and the Gzip compression format (used in.crate files) are stream-based and do not support random-access, in-place modification [1][2][3]. To update a Cargo.toml file within a.crate archive, you must follow a read-transform-write process: 1. Decompress the entire archive into a temporary directory [2][3]. 2. Locate and modify the Cargo.toml file using standard file operations or specialized manifest-parsing tools (such as cargo-manifest or those found within the Cargo source code) [4][5][6]. 3. Re-create the archive by streaming the files into a new.crate file (a.tar.gz archive) using tar::Builder and flate2::write::GzEncoder [1][5][7]. Because of the architectural limitations of these formats, any attempt to overwrite a file directly within the existing compressed stream without full reconstruction would result in a corrupted archive [7][8]. If your goal is to modify dependencies or experiment with external crates, it is standard practice to avoid modifying the.crate archive directly. Instead, you can use features like Cargo's [patch] section or tools designed for "hacking" or patching dependencies (e.g., cargo-rhack), which transparently redirect Cargo to use a local, mutable copy of the crate source code instead of the immutable, archived version [9][10][11].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## xtask/src/local_registry.rs (relevant section)\n'
sed -n '650,790p' xtask/src/local_registry.rs

printf '\n## search for tar / flate2 usage and platform hints\n'
rg -n '\bCommand::new\("tar"\)|\btar\b|flate2|ubuntu-latest|windows|macos|linux' xtask Cargo.toml .github -g '!target' || true

printf '\n## workspace/package metadata\n'
sed -n '1,220p' Cargo.toml

Repository: EffortlessMetrics/adze-swarm

Length of output: 11427


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## GitHub Actions workflows\n'
find .github/workflows -maxdepth 1 -type f \( -name '*.yml' -o -name '*.yaml' \) -print | sort

printf '\n## runs-on / xtask references\n'
rg -n 'runs-on:|xtask|local_registry|adze-local-crate-repack|tar"\)' .github xtask Cargo.toml -g '!target' || true

Repository: EffortlessMetrics/adze-swarm

Length of output: 15569


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## xtask/src/local_registry.rs around existing tar extraction helpers\n'
sed -n '500,590p' xtask/src/local_registry.rs

printf '\n## xtask/src/local_registry.rs around platform-specific code\n'
sed -n '800,890p' xtask/src/local_registry.rs

printf '\n## local_registry module declarations / tests\n'
sed -n '1,120p' xtask/src/local_registry.rs

Repository: EffortlessMetrics/adze-swarm

Length of output: 9874


Consider moving the full crate extract/rewrap flow off tar subprocesses. This helper still depends on tar, and the manifest-read path in the same module does too, so switching only this step to tar/flate2 would not remove the external dependency. An in-process tar/gzip implementation would make the xtask more portable and keep error handling in Rust.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@xtask/src/local_registry.rs` around lines 701 - 760, The crate packaging flow
should no longer depend on external tar subprocesses. Replace the extract,
manifest rewrite, and repack logic in repack_crate_with_manifest, together with
the related manifest-read path in the same module, with in-process Rust tar/gzip
handling using the project’s tar/flate2 support; preserve archive contents,
crate-root layout, and existing error context.

@EffortlessSteven
EffortlessSteven force-pushed the fix/856-sparse-registry-install branch 5 times, most recently from 7ce329a to 4e28f2a Compare July 25, 2026 17:26
Publish crates with git-index + legacy dl layout, inject registry
pins into packaged manifests, and install via `cargo install --index
file://… --token local` so Cargo resolves the named registry index.
Default receipt workflow to workspace version 0.9.0 until #325.

Co-authored-by: Cursor <cursoragent@cursor.com>
@EffortlessSteven
EffortlessSteven force-pushed the fix/856-sparse-registry-install branch from 4e28f2a to a96562e Compare July 25, 2026 17:28
EffortlessSteven and others added 2 commits July 25, 2026 13:38
Cargo rejects sparse+file:// in config.json dl; only the index URL uses
sparse+file. Keeps crate downloads on file:///{crate}/{version}/download.

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
sparse+file:// cannot fetch config.json on Linux (HTTP status 0). Use a
committed git index at file:// with plain file:// dl URLs and install via
--registry adze-local so manifest registry pins resolve.

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>

Copy link
Copy Markdown
Member Author

Queue review for #856: recommend closing this in favour of #971

I reproduced the install failure in an isolated two-crate registry that mirrors write_sparse_index_entry / write_registry_config, using a fresh CARGO_HOME per case so no stale index cache leaks between runs. Full table and method are in my review on #971.

The short version: the failure is not the index protocol. Every case I ran already used cargo install --registry adze-local against a git index at file://, and the top-level crate was still not found whenever the index dependency row carried registry: "adze-local". Cargo discards an index entry whose dependency row names a registry it cannot resolve as a URL, which is why the error surfaces as could not find adze-cli in registry — the entry, not the protocol, is what goes missing.

That means this PR lands on the failing case: it repacks manifests with registry = "adze-local" (necessary — without it the sibling resolves from crates.io) but leaves index_dependency writing registry: "adze-local" for same-registry deps. Install still fails. Only registry: null in the index row plus the manifest pin installs successfully.

#971 makes both changes, and additionally fixes CargoDependency::default_features never deserializing (cargo metadata emits uses_default_features), which currently mis-indexes ahash in adze and fixedbitset in adze-glr-core. It has its own blocker — it does not compile at 0f6a500 — but that is a two-line fix, noted on the PR.

One thing worth salvaging from here rather than losing: manifest_missing_registry_for_workspace_deps is a useful post-condition assert that #971 has no equivalent of. Worth porting across.

Also note 63d582e (workflow lane + whitelist row) already merged as a66af7b via #967, so that part of this diff is redundant either way.


Generated by Claude Code

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