Skip to content

fix(ci): commit Cargo.lock for reproducible builds#992

Merged
ohdearquant merged 4 commits into
mainfrom
fix-issue-920
Jul 17, 2026
Merged

fix(ci): commit Cargo.lock for reproducible builds#992
ohdearquant merged 4 commits into
mainfrom
fix-issue-920

Conversation

@ohdearquant

@ohdearquant ohdearquant commented Jul 14, 2026

Copy link
Copy Markdown
Owner

What changed

  • Dropped the Cargo.lock entry from .gitignore and committed crates/Cargo.lock.
  • Added a lockfile phase to scripts/ci.sh (cargo check --workspace --locked), wired into the CI workflow's full suite (runs on every push and PR).

Why

crates/Cargo.lock was gitignored, so dependency resolution floated per checkout: fresh clones and CI always resolved the latest semver-compatible versions, but an existing local checkout stayed pinned to whatever was resolved when its lockfile was first generated. Two consequences:

  • Security-advisory pins (e.g. the crossbeam-epoch 0.9.20 fix for RUSTSEC-2025-0119, reached transitively via rayon) could not land as a reviewable diff — there was nowhere in the repo to put the pin.
  • Existing local checkouts had no mechanism to detect that their resolution had drifted from what CI (and any fresh clone) was building.

For a binary-shipping repo, the standard guidance is to commit the lockfile: builds become reproducible, dependency state is auditable, and advisory bumps land as ordinary one-line PRs. The lockfile CI phase closes the other half of the gap — a manifest change that isn't matched by a Cargo.lock update now fails the build (--locked) instead of silently re-resolving and drifting again.

Trade-off — floating-lock canary

Committing the lock removes one incidental signal a floated lockfile provided: a fresh resolve would, on its own, surface a newly yanked or semver-broken transitive dependency the next time anyone resolved from scratch. That upstream-breakage visibility is recovered separately by #1072 (a scheduled weekly job that resolves with the lock ignored and reports drift), so the reproducibility win here does not cost us that early warning — it just moves it to a dedicated, scheduled check instead of an unpredictable side effect of every fresh checkout.

Test evidence

From crates/:

$ cargo check --workspace --locked
   ...
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 2m 13s

Verified the gate actually catches drift: reverting the crossbeam-epoch entry in Cargo.lock to 0.9.18 and re-running cargo check --workspace --locked fails with error: checksum for crossbeam-epoch v0.9.18 changed between lock files — confirming the committed lock is pinned to the patched version and that --locked rejects a mismatched lock instead of silently re-resolving.

Crate-scoped gate (touched crate closest to the issue's dependency path — khive-vamana pulls rayon -> crossbeam-epoch):

$ cargo test -p khive-vamana
test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

$ cargo clippy -p khive-vamana --all-targets -- -D warnings
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 1m 05s

$ cargo fmt -p khive-vamana -- --check
(no output — clean)

Closes #920

crates/Cargo.lock was gitignored, so dependency resolution floated
per-checkout: fresh clones and CI always resolved the latest
semver-compatible versions, but existing local checkouts stayed
pinned to whatever was resolved when their lockfile was first
generated. This meant security-advisory pins (e.g. the
crossbeam-epoch 0.9.20 fix for RUSTSEC-2025-0119) could not land as
a reviewable diff, and had no way to keep a local checkout's
resolution in sync with CI's.

- Drop the `Cargo.lock` entry from .gitignore and commit
  crates/Cargo.lock (crossbeam-epoch resolves to the patched 0.9.20).
- Add a `lockfile` phase to scripts/ci.sh running
  `cargo check --workspace --locked`, wired into the CI workflow's
  full suite, so a manifest change that isn't matched by a Cargo.lock
  update fails the build instead of silently re-resolving.

Closes #920

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ohdearquant
ohdearquant marked this pull request as ready for review July 17, 2026 07:05
@ohdearquant
ohdearquant enabled auto-merge (squash) July 17, 2026 07:05

@oceanwaves630 oceanwaves630 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved at b116449. Read the ci.yml/ci.sh/.gitignore diff: the lockfile phase runs first in run_all and on every PR's ubuntu leg (full suite), so a manifest change without a matching lock update fails at PR time rather than post-merge. Lock commit policy per the repo ruling; canary trade tracked in the referenced follow-up.

ohdearquant added a commit that referenced this pull request Jul 17, 2026
…1073)

GitHub's dependency-review-action tags sqlite-vec's dual MIT OR
Apache-2.0 license as LicenseRef-bad-mitapache-2.0 because its SPDX
parser cannot parse the combined license string. Both MIT and Apache-2.0
are already in the allow-list, and crates/deny.toml (cargo-deny) already
accepts sqlite-vec, so this is a redundant parse artifact rather than a
real license concern (0 vulnerabilities reported).

Committing crates/Cargo.lock (#992) exposes the full cargo tree to
dependency-review permanently, so this scoped purl exemption is durable
infrastructure, not a workaround. Mirrors the existing typing-extensions
exemption.

Co-authored-by: Leo <noreply@khive.ai>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions
github-actions Bot disabled auto-merge July 17, 2026 08:27
@ohdearquant
ohdearquant merged commit 65a5a51 into main Jul 17, 2026
23 checks passed
@ohdearquant
ohdearquant deleted the fix-issue-920 branch July 17, 2026 08:53
ohdearquant pushed a commit that referenced this pull request Jul 17, 2026
Catch feat-806 up to main (through #960/#970/#992). Sole conflict was the
khive_storage import in crates/khive-pack-kg/tests/integration.rs; resolved by
union: {Edge, EdgeRelation, Note, SqlStatement, SqlValue}.

Also apply codex round-1 fixes (APPROVE-WITH-FIXES, both Low):
- khive-db event_tests: add search_executed_rejects_absent_result_kind, covering
  the absent-result_kind rejection + atomic rollback (round 1 only tested an
  unknown result_kind value).
- khive-runtime integration: correct stale decode_recall_observations comment to
  decode_search_observations and document the result_kind (entity|note)
  substrate discriminator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

Build reproducibility: Cargo.lock is gitignored — security-advisory pins cannot land, local builds drift from CI

2 participants