Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
},
"dependencies": {
"@ling-stack/browser-host": "workspace:*",
"@napi-rs/canvas": "1.0.11",
"@napi-rs/canvas": "1.0.13",
"@ling-stack/api-client": "workspace:*",
"@ling-stack/contracts": "workspace:*",
"@ling-stack/localization": "workspace:*",
Expand All @@ -63,7 +63,7 @@
"pdf-parse": "2.4.5",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"@napi-rs/keyring": "2.1.1",
"@napi-rs/keyring": "2.1.2",
"@ling-stack/core": "workspace:*"
},
"devDependencies": {
Expand Down
12 changes: 8 additions & 4 deletions apps/desktop/scripts/distribution/canvas-materials.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { existsSync, readFileSync } from "node:fs";
import { basename, join } from "node:path";

const sha256 = bytes => createHash("sha256").update(bytes).digest("hex");

/** Modern Canvas releases ship Cargo.lock and a supplier binary SBOM; older releases stay evidence-limited. */
const MODERN_CANVAS_VERSIONS = ["1.0.11", "1.0.13"];
const SUPPORTED_CANVAS_VERSIONS = ["0.1.80", ...MODERN_CANVAS_VERSIONS];
const json = value => `${JSON.stringify(value, null, 2)}\n`;
function original(file) {
const bytes = Buffer.from(file.contentBase64, "base64");
Expand All @@ -22,7 +26,7 @@ export function validateCanvasSourceMaterials(record, sourceBinding, metadata, s
original(file);
if (file.url !== `https://raw.githubusercontent.com/${record.repository}/${record.revision}/${file.path}`) throw new Error("distribution_canvas_source_origin_mismatch");
}
if (!["LICENSE", "Cargo.toml", ".gitmodules", ...(record.version === "1.0.11" ? ["Cargo.lock"] : [])].every(path => record.files.some(file => file.path === path))) throw new Error("distribution_canvas_source_contract_missing");
if (!["LICENSE", "Cargo.toml", ".gitmodules", ...(MODERN_CANVAS_VERSIONS.includes(record.version) ? ["Cargo.lock"] : [])].every(path => record.files.some(file => file.path === path))) throw new Error("distribution_canvas_source_contract_missing");
const deps = record.vendors.find(vendor => vendor.kind === "skia-source" && vendor.files.some(file => file.path === "DEPS"));
if (!deps || deps.version !== record.skiaRevision) throw new Error("distribution_canvas_skia_deps_missing");
const depsText = original(deps.files.find(file => file.path === "DEPS")).toString("utf8");
Expand All @@ -49,7 +53,7 @@ export function validateCanvasSourceMaterials(record, sourceBinding, metadata, s
} else if (file.url !== crate.url) throw new Error("distribution_canvas_crate_notice_origin_mismatch");
}
}
if (record.version === "1.0.11") {
if (MODERN_CANVAS_VERSIONS.includes(record.version)) {
if (!sbom || sbom.metadata?.component?.name !== metadata.name || sbom.metadata?.component?.version !== metadata.version
|| !sbom.components?.some(component => component.purl?.startsWith("pkg:cargo/") && component.hashes?.length)) throw new Error("distribution_canvas_supplier_sbom_missing_or_stale");
for (const component of sbom.components ?? []) {
Expand All @@ -65,7 +69,7 @@ export function validateCanvasSourceMaterials(record, sourceBinding, metadata, s
}

export function collectCanvasMaterials({ metadata, nativeDirectory, sourceBinding }, add, components) {
if (metadata.name !== "@napi-rs/canvas" || !["0.1.80", "1.0.11"].includes(metadata.version) || !nativeDirectory) return undefined;
if (metadata.name !== "@napi-rs/canvas" || !SUPPORTED_CANVAS_VERSIONS.includes(metadata.version) || !nativeDirectory) return undefined;
const manifest = JSON.parse(readFileSync(new URL("./vendor-notices/canvas-native-sources.json", import.meta.url)));
const record = manifest.entries.find(entry => entry.version === metadata.version);
const nativeMetadata = JSON.parse(readFileSync(join(nativeDirectory, "package.json")));
Expand Down Expand Up @@ -95,5 +99,5 @@ export function collectCanvasMaterials({ metadata, nativeDirectory, sourceBindin
reason: "historical_native_rust_resolution_not_published",
details: "Original Canvas source, fixed Skia source/vendor grants and source access are collected. The 0.1.80 supplier published neither Cargo.lock nor a binary SBOM; its historical Rust build graph cannot be reconstructed from public metadata. This collection does not claim a complete historical Rust dependency graph or a reproducible native build.",
}] : [];
return { licenseFiles, historicalRustResolutionPublished: record.version === "1.0.11", limitations };
return { licenseFiles, historicalRustResolutionPublished: MODERN_CANVAS_VERSIONS.includes(record.version), limitations };
}
211 changes: 65 additions & 146 deletions apps/desktop/scripts/distribution/notice-sources.json

Large diffs are not rendered by default.

5,253 changes: 5,253 additions & 0 deletions apps/desktop/scripts/distribution/vendor-notices/canvas-native-sources.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions apps/desktop/tests/distribution-native-vendor.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,17 @@ function canvasFixture(version) {
}

test("Canvas supplier records bind native SBOM crate hashes and retain old historical limits", t => {
for (const version of ["0.1.80", "1.0.11"]) {
for (const version of ["0.1.80", "1.0.11", "1.0.13"]) {
const { record, metadata, binding, sbom } = canvasFixture(version);
assert.equal(validateCanvasSourceMaterials(record, binding, metadata, version === "1.0.11" ? sbom : undefined), undefined);
assert.equal(validateCanvasSourceMaterials(record, binding, metadata, version !== "0.1.80" ? sbom : undefined), undefined);
const nativeDirectory = mkdtempSync(join(tmpdir(), "ling-canvas-source-test-"));
t.after(() => rmSync(nativeDirectory, { recursive: true, force: true }));
writeFileSync(join(nativeDirectory, "package.json"), JSON.stringify(metadata));
if (version === "1.0.11") writeFileSync(join(nativeDirectory, "sbom.cdx.json"), JSON.stringify(sbom));
if (version !== "0.1.80") writeFileSync(join(nativeDirectory, "sbom.cdx.json"), JSON.stringify(sbom));
const material = new Map(), components = [];
const result = collectCanvasMaterials({ metadata: { name: "@napi-rs/canvas", version }, nativeDirectory, sourceBinding: binding }, (path, bytes) => { material.set(path, bytes); return path; }, components);
assert.ok(result.licenseFiles.length > 20);
assert.equal(result.historicalRustResolutionPublished, version === "1.0.11");
assert.equal(result.historicalRustResolutionPublished, version !== "0.1.80");
assert.equal(result.limitations.length, version === "0.1.80" ? 1 : 0);
if (version === "0.1.80") {
assert.equal(record.crates.length, 0, "never substitute newer Rust crates for the historical binary");
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/tests/engine-secret-package.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import test from "node:test";
const packageJson = JSON.parse(await readFile(new URL("../package.json", import.meta.url), "utf8"));

test("desktop includes the bounded secret worker and pins the OS binding separately from the daemon", async () => {
assert.equal(packageJson.dependencies["@napi-rs/keyring"], "2.1.1");
assert.equal(packageJson.dependencies["@napi-rs/keyring"], "2.1.2");
assert.ok(packageJson.scripts.build.includes("pnpm build:engine-secret-worker"));
assert.ok(packageJson.scripts["build:engine-secret-worker"].includes("--external:@napi-rs/keyring"));
const worker = await readFile(new URL("../dist/daemon/engine-secret-worker.js", import.meta.url), "utf8");
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
"image-size"
],
"overrides": {
"@napi-rs/canvas": "1.0.11",
"@radix-ui/react-dismissable-layer@1.1.19": "1.1.20",
"@expo/cli>zod": "4.6.6",
"brace-expansion@>=1.0.0 <1.1.21": "1.1.21",
Expand Down
2 changes: 1 addition & 1 deletion packages/daemon/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"xlsx-populate": "1.21.0",
"@agentclientprotocol/sdk": "1.9.0",
"@anthropic-ai/sdk": "0.135.0",
"@napi-rs/keyring": "2.1.1",
"@napi-rs/keyring": "2.1.2",
"proper-lockfile": "4.1.2",
"smol-toml": "1.9.1"
},
Expand Down
Loading
Loading