Skip to content

✨ feat(mq-lang): add mq.lock integrity check for HTTP module imports#1977

Merged
harehare merged 6 commits into
mainfrom
feat/import-lockfile
Jul 10, 2026
Merged

✨ feat(mq-lang): add mq.lock integrity check for HTTP module imports#1977
harehare merged 6 commits into
mainfrom
feat/import-lockfile

Conversation

@harehare

@harehare harehare commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Summary

Records each fetched module URL's SHA-256 hash on first fetch, and rejects a later fetch of the same URL whose content no longer matches unless --refresh-modules is passed (which also updates the recorded hash) — making mutable-ref HTTP imports (HEAD/branch) reproducible across machines and CI, the same way package-lock.json/ deno.lock work.

  • New --lockfile / --no-lockfile CLI flags, and matching Engine/ModuleLoader/DefaultModuleResolver API.
  • --clear-cache/--refresh-modules also prune the corresponding mq.lock entries (all / mutable-ref only), independent of whether the check is currently enabled.
  • Concurrent access to mq.lock (e.g. mq-run's parallel file processing) is serialized via an OS-level advisory lock, and writes go through a temp-file-then-rename for atomicity.
  • Ported to the WASM/OPFS build (WasmFetcher), sharing the same ModuleLock data model and compute_hash implementation as the native fetcher so both backends produce identical hashes.

Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • ♻️ Refactor
  • 📝 Documentation
  • ⚡ Performance
  • ✅ Test
  • 📦 Build / dependencies
  • 👷 CI

Checklist

  • I ran cargo fmt and cargo clippy and addressed any warnings
  • I ran just test-all and all tests pass
  • I added or updated tests covering this change
  • I updated relevant documentation (/docs, crate README.md) if needed
  • I added a changelog entry if this is a user-facing change

Additional Context

harehare added 2 commits July 7, 2026 21:25
Records each fetched module URL's SHA-256 hash on first fetch, and
rejects a later fetch of the same URL whose content no longer
matches unless --refresh-modules is passed (which also updates the
recorded hash) — making mutable-ref HTTP imports (HEAD/branch)
reproducible across machines and CI, the same way package-lock.json/
deno.lock work.

- New --lockfile <PATH> / --no-lockfile CLI flags, and matching
  Engine/ModuleLoader/DefaultModuleResolver API.
- --clear-cache/--refresh-modules also prune the corresponding
  mq.lock entries (all / mutable-ref only), independent of whether
  the check is currently enabled.
- Concurrent access to mq.lock (e.g. mq-run's parallel file
  processing) is serialized via an OS-level advisory lock, and
  writes go through a temp-file-then-rename for atomicity.
- Ported to the WASM/OPFS build (WasmFetcher), sharing the same
  ModuleLock data model and compute_hash implementation as the
  native fetcher so both backends produce identical hashes.
@codspeed-hq

codspeed-hq Bot commented Jul 7, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing feat/import-lockfile (74d1a3a) with main (93ed796)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (b0cfda5) during the generation of this report, so 93ed796 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

check_lock cloned the entire ModuleLock map on each call just to read
it; operate on the mutex-guarded lock directly instead.
@harehare harehare force-pushed the feat/import-lockfile branch 2 times, most recently from 1e9e157 to 9099d41 Compare July 9, 2026 13:34
harehare added 3 commits July 9, 2026 23:28
Previously the mq.lock check only ran on network fetches, so a disk
cache hit bypassed it entirely. Since the module cache is shared per
machine while mq.lock is per project, a project whose lock file
expected different content than the local cache held would silently
run the cached version, and a project without an mq.lock never got
one created while modules were served from the cache.

- UreqFetcher: check the (sidecar-verified) cached hash against
  mq.lock on both cache-hit paths, recording new entries as on fetch.
- WasmFetcher: same check on OPFS cache hits, extracted into a shared
  check_opfs_lock helper.
- Mismatch errors now suggest the recovery that actually works per
  URL kind: --refresh-modules for mutable refs, --clear-cache for
  versioned (tagged) URLs whose cache --refresh-modules doesn't touch
  (clearHttpCache()/clearAllHttpCache() on WASM).
…he result

Keys the advisory lock file by the SHA-256 hash of mq.lock's absolute
path under mq-{hash}.lock in the system temp dir instead of a .flock
sidecar next to mq.lock, so distinct lock file paths never collide and
no stray file is left in the user's project. Also replaces the
(String, String) tuple returned by try_read_cache with a named
CachedModule struct.
Call lockfile::compute_hash directly instead of delegating through
UreqFetcher::compute_hash, and simplify super:: path references now
that http_import and lockfile are imported directly.
@harehare harehare merged commit 832061b into main Jul 10, 2026
11 checks passed
@harehare harehare deleted the feat/import-lockfile branch July 10, 2026 14:16
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