Skip to content

Commit 44d9872

Browse files
Merge pull request #36 from microsoft/bump-sharp-libvips-compliance
Bump sharp to 0.35.3 and bring compliance tooling up to date
2 parents f966f31 + 60e345b commit 44d9872

16 files changed

Lines changed: 1561 additions & 351 deletions

.github/workflows/non-windows.yml

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
build:
1414
name: ${{ matrix.os }}
1515
runs-on: ${{ matrix.os }}
16-
timeout-minutes: 20
16+
timeout-minutes: 45
1717
strategy:
1818
fail-fast: false
1919
matrix:
@@ -59,18 +59,47 @@ jobs:
5959
plutil -lint "$plist"
6060
6161
- run: npm ci
62-
- run: npm run compliance:licenses
62+
- name: Cache compliance source downloads
63+
uses: actions/cache@v4
64+
with:
65+
path: .compliance-cache
66+
key: compliance-${{ runner.os }}-${{ hashFiles('third_party/compliance-policy.json') }}
67+
restore-keys: compliance-${{ runner.os }}-
68+
69+
# macOS arm64 is a release target, so it must be able to produce the complete
70+
# corresponding-source bundle. Linux installs from source and only needs the
71+
# license inventory.
72+
- name: Prepare compliance materials (release target)
73+
if: runner.os == 'macOS'
74+
run: npm run compliance:prepare
75+
- name: Prepare compliance licenses (source-install platform)
76+
if: runner.os != 'macOS'
77+
run: npm run compliance:licenses
6378
- name: Verify platform license coverage
6479
run: |
6580
node --input-type=module -e "
6681
import { existsSync, readFileSync } from 'node:fs';
6782
const inventory = JSON.parse(readFileSync('.compliance/LICENSE-INVENTORY.json'));
6883
const libvips = inventory.packages.find(({ name }) =>
6984
name.startsWith('@img/sharp-libvips-'));
70-
if (!libvips || libvips.licenseSource !== 'licenses/LGPL-3.0.txt')
85+
if (!libvips || !libvips.licenseSource.includes('licenses/LGPL-3.0.txt'))
7186
throw new Error('Platform Sharp/libvips LGPL coverage is missing');
7287
if (!existsSync('.compliance/licenses/LGPL-3.0.txt'))
7388
throw new Error('Canonical LGPL-3.0 text is missing');
89+
const wasm = inventory.packages.find(({ name }) => name === '@img/sharp-wasm32');
90+
if (wasm) {
91+
for (const term of ['LICENSE', 'licenses/LGPL-3.0.txt', 'canonical SPDX MIT text'])
92+
if (!wasm.licenseSource.includes(term))
93+
throw new Error('@img/sharp-wasm32 license term ' + term + ' is unresolved');
94+
}
95+
const native = JSON.parse(readFileSync('.compliance/NATIVE-COMPONENTS.json'));
96+
if (native.packages.length !== 1)
97+
throw new Error('Exactly one native payload must be selected');
98+
if (!native.packages[0].name.endsWith('-' + process.arch))
99+
throw new Error('Native payload does not match the runner architecture');
100+
for (const excluded of native.excludedFromArtifacts)
101+
if (native.packages[0].name === excluded)
102+
throw new Error('An excluded WASM package was selected as the native payload');
74103
"
75104
- name: Verify optional window provider
76105
run: >-

.github/workflows/windows.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ jobs:
6767
architecture: ${{ matrix.arch }}
6868
cache: npm
6969

70+
- name: Cache compliance source downloads
71+
uses: actions/cache@v4
72+
with:
73+
path: .compliance-cache
74+
key: compliance-windows-${{ matrix.arch }}-${{ hashFiles('third_party/compliance-policy.json') }}
75+
restore-keys: compliance-windows-${{ matrix.arch }}-
76+
7077
- name: Install native dependencies
7178
shell: pwsh
7279
run: |

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ dist-electron
44
release
55
.compliance
66
.compliance-cache
7+
.compliance-review
78
*.log
89
.DS_Store
910

RELEASING.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ npm run compliance:prepare
8484
The pull request must pass:
8585

8686
- Windows x64 and ARM64 license, test, build, package, and architecture checks;
87-
- macOS and Ubuntu license, test, and build checks;
87+
- macOS full corresponding-source preparation, test, and build checks;
88+
- Ubuntu license, test, and build checks;
8889
- commit-pinned source-installer checks on Windows, macOS, and Ubuntu.
8990

9091
Resolve every compliance failure. Never disable or bypass a compliance check to
@@ -158,8 +159,13 @@ Do not commit the temporary release-notes file.
158159

159160
## 6. Optional binary release
160161

161-
Binary publication is a separate decision. Build each artifact on its native
162-
operating system and architecture:
162+
Binary publication is a separate decision. The supported release targets are
163+
**Windows x64**, **Windows ARM64**, and **macOS arm64**; every other platform,
164+
including Linux and macOS x64, is a source install (see `INSTALL.md`). The
165+
compliance tooling refuses to prepare a redistributable bundle on an
166+
unsupported target.
167+
168+
Build each artifact on its native operating system and architecture:
163169

164170
```sh
165171
npm ci

THIRD-PARTY-NOTICES.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ Those components remain under their own terms; the generated
4949
codec library whose bundled notice identifies FFmpeg as **LGPL-2.1-or-later**.
5050
GPL portions require an explicit non-default FFmpeg build configuration.
5151
- Electron's `LICENSE.electron.txt` and `LICENSES.chromium.html` are retained in
52-
every packaged application.
52+
every packaged application. Chromium's notice file differs per platform, so it
53+
is reviewed separately for each release target.
5354
- The currently pinned source is Electron
5455
[`v43.1.1`](https://github.com/electron/electron/tree/v43.1.1), Chromium
5556
[`150.0.7871.114`](https://chromium.googlesource.com/chromium/src/+/150.0.7871.114),
@@ -69,12 +70,17 @@ Those components remain under their own terms; the generated
6970
**Apache-2.0 AND LGPL-3.0-or-later**; other platforms load the corresponding
7071
**LGPL-3.0-or-later** `@img/sharp-libvips-*` package.
7172
- The currently pinned source is Sharp
72-
[`v0.34.5`](https://github.com/lovell/sharp/tree/v0.34.5), its reproducible
73+
[`v0.35.3`](https://github.com/lovell/sharp/tree/v0.35.3), its reproducible
7374
packaging scripts
74-
[`sharp-libvips v1.2.4`](https://github.com/lovell/sharp-libvips/tree/v1.2.4),
75+
[`sharp-libvips v1.3.2`](https://github.com/lovell/sharp-libvips/tree/v1.3.2),
7576
and libvips
76-
[`v8.17.3`](https://github.com/libvips/libvips/tree/v8.17.3). The unpacked
77+
[`v8.18.3`](https://github.com/libvips/libvips/tree/v8.18.3). The unpacked
7778
native module remains replaceable in the packaged application.
79+
- Sharp also publishes a WebAssembly build, `@img/sharp-wasm32`, which npm
80+
installs on every platform because its FreeBSD and WebContainers wrappers
81+
declare the platform constraints. Skill Recorder never loads it and excludes it
82+
and its WASM-only runtime dependency `@emnapi/runtime` from every packaged
83+
artifact, so neither is distributed.
7884
- The native payload also contains libraries under MPL-2.0, MIT, BSD, ISC,
7985
fontconfig, FreeType, libpng, libtiff, zlib, and related permissive terms.
8086
The exact upstream table is distributed as

electron/frames/extractor.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import assert from "node:assert/strict";
22
import { existsSync } from "node:fs";
33
import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
4+
import { createRequire } from "node:module";
45
import { tmpdir } from "node:os";
56
import path from "node:path";
67
import test from "node:test";
@@ -169,3 +170,21 @@ test("FrameExtractor deduplicates identical source JPEGs without deleting retain
169170
assert.equal(reloaded.manifest.length, 1);
170171
assert.equal(existsSync(path.join(framesDir, reloaded.manifest[0].file)), true);
171172
});
173+
174+
test("sharp loads through the app's require path as a callable factory (guards sharp 0.35 export shape)", async () => {
175+
// The frame extractor loads sharp with createRequire(import.meta.url)("sharp"), which
176+
// resolves sharp's CommonJS "require" export condition. sharp 0.35 split its import and
177+
// require export shapes, so this guards that the require path stays a directly-callable
178+
// factory exposing the .extract().jpeg() pipeline the extractor depends on.
179+
const requireFromHere = createRequire(import.meta.url);
180+
const loaded = requireFromHere("sharp") as typeof sharp;
181+
assert.equal(typeof loaded, "function");
182+
const cropped = await loaded({
183+
create: { width: 8, height: 8, channels: 3, background: { r: 10, g: 20, b: 30 } },
184+
})
185+
.extract({ left: 1, top: 1, width: 4, height: 4 })
186+
.jpeg({ quality: 88 })
187+
.toBuffer();
188+
assert.ok(cropped.length > 0);
189+
});
190+

electron/frames/extractor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const log = createLogger("Frames");
1818
const require = createRequire(import.meta.url);
1919
const execFileAsync = promisify(execFile);
2020

21-
type Sharp = typeof import("sharp");
21+
type Sharp = (typeof import("sharp"))["default"];
2222
let sharpMod: Sharp | null | undefined;
2323
function sharp(): Sharp | null {
2424
if (sharpMod === undefined) {

0 commit comments

Comments
 (0)