Version 1.0.0
Supply chain: what can be verified
The CycloneDX bill of materials, the VEX record and its justification rule, the scans and their cadence, the "zero network egress symbol" check on the built artifact, signatures and delivery.
This page describes the software supply chain artifacts and checks, along with the path of the file or workflow that produces them. Every claim points to something a buyer can verify directly. Each release ships with its bill of materials (SBOM), its exploitability statement (VEX) and its signatures (security white paper V3, section 9.1). The areas the white paper does not cover are described in What remains to be built.
The software bill of materials (CycloneDX SBOM)
Section titled “The software bill of materials (CycloneDX SBOM)”The .github/workflows/sbom-release.yml workflow produces a CycloneDX bill of
materials of all npm dependencies in the repository, generated by Trivy on a
pinned version:
trivy fs --format cyclonedx --output source.cdx.json ./The document is attached to the release under an addressable, versioned name,
lemniscate-source-<tag>.cdx.json, and delivered with it. It covers the gateway
services, the extensions and their dependencies, and you can load it into your
vulnerability management tools (security white paper V3, section 9.1). It is not
committed: it is a reproducible derivative of a pinned version, which you can
replay with another tool and compare.
A guard precedes the attachment. The workflow fails if the document does not
declare bomFormat: CycloneDX, if it has no specification version, or if it
contains no components. The component count is written to the job summary.
The mechanism checks itself: any change to this workflow or to the Trivy
installation triggers a generation and a validation of the bill of materials. The
attachment step triggers on the release event: a bill of materials accompanies
every release.
The VEX record and its justification rule
Section titled “The VEX record and its justification rule”A scanner that returns a list of vulnerabilities against a bill of materials
does not say which ones reach the product. The answer to “you have N CVEs,
justify them” lives in security/vex/, as versioned OpenVEX documents.
These documents are committed. They are traced human decisions: the git history says who justified what, and when. The VEX statement is generated for each release and delivered with it: for every vulnerability published against a dependency, it says whether the product is affected and what is being done (security white paper V3, section 9.1).
The justification validator
Section titled “The justification validator”The security/lib/vex.ts validator rejects any not_affected statement that
lacks one of the five justifications from the CISA reference list:
component_not_presentvulnerable_code_not_presentvulnerable_code_not_in_execute_pathvulnerable_code_cannot_be_controlled_by_adversaryinline_mitigations_already_exist
The rejection happens before the scanner consumes the record. No CVE is removed
from a report without an acceptable justification, and that guarantee does not
depend on the behavior of a third-party tool. It is covered by
security/vex/vex-validation.test.ts.
The check also applies to the real record, not only to fixtures:
security/vex/vex-dir-compliance.test.ts validates security/vex/ as committed. A
non-compliant statement fails continuous integration.
The exploitability judgment
Section titled “The exploitability judgment”The exploitability judgment is human. No automated reachability analysis is used
(decision D3 of specs/2026-07-29-sbom-vex/spec.md). Two reasons are recorded:
the credible engines for JavaScript and TypeScript are services hosted in the
United States, which rules them out for a product aimed at isolated
environments; and their failure mode is the false negative, that is, a false
claim of compliance.
The scans and their cadence
Section titled “The scans and their cadence”| Check | File | Trigger | Effect |
|---|---|---|---|
| Differential OSV on a change proposal | .github/workflows/osv-scanner-pr.yml | on every proposal | blocking if it introduces one |
| OSV, full repository | scripts/cron-local/jobs/osv-scan.sh | Monday 11:00, on the publisher workstation | report and count, reported to the publisher |
| Secrets (Trivy) | scripts/cron-local/jobs/trivy-secret.sh | Monday 11:30, on the publisher workstation | report and count, reported to the publisher |
| Container images (Trivy) | scripts/cron-local/jobs/trivy-image.sh | Monday 12:00, on the publisher workstation | local build then scan |
| Dependencies after VEX suppression (Trivy) | scripts/cron-local/jobs/trivy-vex.sh | Monday 12:30, on the publisher workstation | residual list, each removal justified |
The four scheduled scans run on the publisher workstation, under systemd timers
declared in scripts/cron-local/schedule.yaml, on a clean copy of main. Each one
ends with a message sent to a person: a scan that found nothing says so, and a
scan that could not measure fails. The .github/workflows/trivy-secret-scan.yml, trivy-image-scan.yml and
trivy-vex-scan.yml workflows keep a manual trigger; the last two also
test themselves on a proposal that modifies them.
The differential gate runs two scans, one on the target branch and one on the current branch, and fails only if the change introduces a vulnerability. Inherited debt does not block current work; a regression does not pass. The check does not depend on any paid forge feature.
The “after VEX suppression” scan consumes the repository documents: its output is
the list of what remains to be handled, each removal backed by a document
justified and signed by an identifiable author. Its behavior is verified against
a vulnerability pinned in security/vex/vex-suppression.integration.test.ts.
The secrets scan is exercised by a canary:
security/trivy/secret-scan.integration.test.ts plants a dummy secret and
checks that it is detected.
A dedicated job, .github/workflows/security-checks.yml, runs the type checking and
tests of the security/ package on every proposal that touches it.
Toolchain integrity
Section titled “Toolchain integrity”A scanner downloaded without verification defeats the purpose of the scan. Three rules apply:
- Trivy is pinned by version and verified by fingerprint. The
.github/actions/install-trivy/action.ymlaction centralizes the version for all security workflows and compares the archive against the checksum file published in the same release before running it. No moving tag, nolatest(identifierSEC-9.3-04). - Third-party actions in the security workflows are pinned by commit fingerprint, with the version in a comment.
- Dependencies are installed by
npm ciagainst the lock files, which validates the integrity fingerprint of every installed package.
The “zero network egress symbol” check on the built artifact
Section titled “The “zero network egress symbol” check on the built artifact”This check does not apply to the sources but to the delivered binary. It can be verified without access to the code.
Lemniscate is built according to a deployment profile chosen at build time, not
through a runtime setting: in the on-premise artifact, the network egress layer is
not disabled, it is absent from the module graph. A guarantee that depends on a
setting can be falsified by a configuration change; this one can be falsified by
inspecting the artifact.
npm run build --prefix extensions/clinpm run esbuild-base --prefix extensions/vscode(cd gui && NODE_OPTIONS=--max-old-space-size=6144 npx vite build)npm run build --prefix llm-gatewaynpm run build --prefix gateway-adminThe script knows six deployable units: cli, vscode, gui,
llm-gateway, gateway-admin and intellij. With no option, it inspects all of
them; the repeatable --composant option restricts the inspection to the named
components. A component that is requested but not built is not judged compliant:
it is reported as absent, and the check fails. The invocation below names the
five JavaScript units; the JetBrains plugin, which requires a Gradle build, is
inspected outside continuous integration.
node scripts/verify-onprem-artifact.mjs \ --composant cli --composant vscode --composant gui \ --composant llm-gateway --composant gateway-adminThe script applies four independent checks:
- The symbols present in the text of the built artifacts: domains, project keys, library names. This is the only angle a third party can verify without reading the source code.
- The entries of the esbuild build manifests. A minified bundle may no longer carry the name of the package it embeds; the manifest lists every module that entered the graph. This second angle survives minification.
- The inventory of deployable units: the appearance of an undeclared unit fails the check.
- The absence of any call, at module load, to a deployment profile boundary, that is, a point where network egress is substituted.
This check has no disable option and no exception list. The acceptance criterion
of arbitration AR-03 (specs/securite/arbitrages.md) is zero occurrences. A symbol
that reappears is removed from the module graph; it does not go on a waiver
list.
The check runs in .github/workflows/pr.yaml on every change proposal: the two
checks that read the sources run on every proposal, with the --sans-artefacts
option, and the inspection of the built artifacts runs in the job that builds
them. The script itself is covered by scripts/verify-onprem-artifact.test.mjs.
The detail of the flows, on the product side, is described in Where the data goes.
Signatures
Section titled “Signatures”No artifact is delivered without a signature. The container images, including the session image, and the workstation components are signed. The signing key is handed to you with the first delivery, and its fingerprint is communicated to you over a separate channel, which lets you detect a substitution. Updates are then verified offline, before installation (security white paper V3, sections 9.1 and 9.3).
When a release is published, the signature is applied by cosign
(.github/actions/sign-release-blobs). It also covers the CycloneDX bill of
materials of the sources and the delivery manifest, which lists every
installable file with its SHA-256 fingerprint. The signatures are attached to the
release, alongside the artifacts.
Delivery and updates
Section titled “Delivery and updates”Artifacts reach you by one of two paths (security white paper V3, section 9.3):
- in connected mode, they are pushed into your private registry;
- in isolated mode, they are delivered on media, as a signed archive, with the bill of materials and the VEX statement.
In both cases, installation starts with verifying the signatures using the key you hold. Your team then applies the installation or the update: neither the services nor the extensions update themselves, and the product does not depend on any external service. The previous version is kept for a rollback.
The escape scenarios
Section titled “The escape scenarios”A battery of escape scenarios is run before each delivery, in six families: network egress from the sandbox, reading or writing outside the repository copy, modifying a file executed by a third party, injecting instructions through a repository file, resource exhaustion, bypassing the command policy. The execution report is attached to the release, in the same way as the bill of materials and the VEX statement, and a regression blocks publication. You can replay these scenarios on your deployment (security white paper V3, section 9.2).
Reporting a vulnerability
Section titled “Reporting a vulnerability”The channel is SECURITY.md, at the root of the repository: report by email to
security@lemniscate-tech.com, with no public issue opened, including a
description, reproduction steps, an impact assessment and any mitigations.
It is a reporting channel, not a bug bounty program. What it does not cover is described in What remains to be built.
Summary of obtainable artifacts
Section titled “Summary of obtainable artifacts”- Signed artifacts, verifiable offline with the key handed to you.
- A CycloneDX bill of materials of the sources, generated and validated per release.
- The escape scenario report run against the delivered release.
- A versioned OpenVEX record, where every exclusion carries an author, a date and a justification from the CISA reference list; the removal is refused by the repository code if the justification is missing.
- Reproducible scan reports: blocking differential gate, weekly full scan, secrets, images, dependencies after VEX suppression.
- A published disclosure policy, with a dedicated channel.
- A “zero network egress symbol” check run on the built artifact, verifiable by a third party without access to the source code.
- A traceable proof method: 286
SEC-*identifiers, statuses backed byfichier:ligneevidence, dated arbitrations with the options they ruled out (compliance posture).