Skip to content

fix: a missing mcpp.lock is named by emit sbom and --locked - #893

Open
NopeCharon wants to merge 1 commit into
mcpp-community:mainfrom
NopeCharon:fix/sbom-names-a-missing-lock
Open

NopeCharon wants to merge 1 commit into
mcpp-community:mainfrom
NopeCharon:fix/sbom-names-a-missing-lock

Conversation

@NopeCharon

@NopeCharon NopeCharon commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

mcpp::pm::load returns an empty Lockfile when mcpp.lock does not exist, and two callers took a successful load to mean the file was there, so the branches they wrote for a missing lock were never taken.

  • mcpp emit sbom wrote a root-only document with no note, although its own comment says this case is "NOT AN ERROR, AND NOT SILENCE EITHER". It now asks whether the file exists before loading it, and prints the note on the narration stream. Standard output stays the document.
  • mcpp build --locked reported every resolved package as (not in the lock) under "this resolution differs from mcpp.lock". It now gives the refusal that says the lock is missing and how to record one.

load keeps its meaning, because the build's own readers want an empty lock from a project that has none. docs/51-supported-versions.md states the note in both languages.

Closes #891.

Criteria

  • emit sbom with no lock prints the note and writes a root-only document. The new assertions in tests/e2e/333_named_runners_locked_and_sbom.sh state it. No build of the whole engine was possible on the host I had, so this ran on macOS arm64 against the real src/cli/cmd_sbom.cppm, src/pm/lock_io.cppm and modules/libs/src/toml.cppm compiled together, with stubs for the manifest loader and the CLI around them. Before the change: exit 0, no note, as the released 2026.11.5.1 binary also behaves. After it: exit 0, the note, components empty.
  • A lock that exists is unaffected. On the same setup, a populated lock gives its components and no note, a valid lock with no packages gives no note, and a corrupt lock exits 2 with "mcpp.lock exists but could not be read".
  • --locked with no lock gives the refusal that names it, and writes no lock. This did not run locally, since it needs a resolved dependency and a built engine. It is asserted in tests/e2e/333_named_runners_locked_and_sbom.sh, which passed on this PR's linux-e2e job (linux x86_64, self-host) with both new lines: --locked says a missing lock is missing and sbom says when no lock records the resolution. All of this PR's CI checks pass.
  • check_docs_style.sh, check_docs_structure.sh, check_version_pins.sh, check_file_lengths.sh, check_workflow_assertions.py pass locally. step13_lockfile is 391 lines by a text count, under the 400 of check_function_sizes.sh; that gate itself needs a compile database and is left to CI.

Intersections

New rule or feature Invariant it crosses Test at the crossing
emit sbom asks whether the lock exists Standard output is the document, narration goes to standard error The new section E assertions in e2e 333 parse stdout as JSON and read the note from stderr
The same A lock that cannot be read is an error, not "nothing recorded" The load failure branch is unchanged; run by hand as above, no e2e sits there
--locked refuses a missing lock --locked reports drift by name when a lock exists The existing 9.9.9 -> 0.0.1 assertions in e2e 333
The same The check runs only when the resolution has packages or indices, so a project with no dependencies still passes with no lock none: the guard around the check is unchanged, and no test sits at it

Compatibility

mcpp emit sbom with no lock gains one line on standard error; its document and exit code are unchanged. mcpp build --locked with no lock still fails, with a different message. No cache key or file format changes.

Checks before merging

  • bash .github/tools/check_docs_style.sh, check_docs_structure.sh and check_version_pins.sh pass.
  • python3 .github/tools/check_workflow_assertions.py passes (a step asserts what its name says).
  • No commit on the branch carries an attribution trailer:
    git log origin/main..HEAD -i --grep='Co-Authored-By' prints nothing.
  • The squash merge is given an explicit subject and body, so GitHub does not
    compose one from the branch's commits. Suggested subject: fix: a missing mcpp.lock is named by emit sbomand--locked``.

mcpp::pm::load returns an empty Lockfile when the file does not exist, and
two callers took a successful load to mean the file was there, so the
branches they wrote for a missing lock were never taken.

`mcpp emit sbom` wrote a root-only document, exit 0, without the note its
own comment requires: that document is true of a project with no
dependencies and false of one that was never built. It now asks whether
the file exists before loading it. The note goes to the narration stream,
so standard output stays the document.

`mcpp build --locked` reported every resolved package as "(not in the
lock)" under "this resolution differs from mcpp.lock", naming a file that
is not there. It now gives the refusal that says the lock is missing and
how to record one.

`load` keeps its meaning: the build's own readers want an empty lock from
a project that has none. A lock that exists behaves as before in both
commands, and one that cannot be read is still an error.

Tests: tests/e2e/333 runs `--locked` and `emit sbom` with the lock moved
aside. docs/51 states the note in both languages.

Closes mcpp-community#891

This branch has not been deployed

No deployments
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.

fix: emit sbom and --locked read a missing mcpp.lock as an empty one, so neither says it is missing

1 participant