From 961597fe6431452a8ba89d513b6ae236abcc2e9f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 19:58:48 +0900 Subject: [PATCH 1/4] test(supply-chain): define machine-readable license boundary --- src/licenseBoundary.test.ts | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/licenseBoundary.test.ts diff --git a/src/licenseBoundary.test.ts b/src/licenseBoundary.test.ts new file mode 100644 index 00000000..3c805525 --- /dev/null +++ b/src/licenseBoundary.test.ts @@ -0,0 +1,40 @@ +import { readFileSync } from 'node:fs'; +import { describe, expect, it } from 'vitest'; + +const CANONICAL_MIT_LICENSE = `MIT License + +Copyright (c) 2026 ContextualWisdomLab + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +`; + +describe('software and bundled-font license evidence', () => { + it('keeps the root software license as exact canonical MIT text', () => { + expect(readFileSync('LICENSE', 'utf8')).toBe(CANONICAL_MIT_LICENSE); + }); + + it('retains the bundled-font attribution and complete OFL terms separately', () => { + expect(readFileSync('src/fonts/NOTICE', 'utf8')).toContain( + 'SIL Open Font License, Version 1.1', + ); + expect(readFileSync('src/fonts/OFL.txt', 'utf8')).toContain( + 'SIL OPEN FONT LICENSE Version 1.1', + ); + }); +}); From c3ce70a527e19c06e41b7d82d369ee8fd5fa402d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 20:03:32 +0900 Subject: [PATCH 2/4] fix(supply-chain): separate bundled-font licensing --- LICENSE | 9 --------- 1 file changed, 9 deletions(-) diff --git a/LICENSE b/LICENSE index 84eff957..591bbf19 100644 --- a/LICENSE +++ b/LICENSE @@ -19,12 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ---- - -Bundled fonts (src/fonts/): the Noto Sans font families bundled with this -package are NOT covered by the MIT license above. They are licensed under the -SIL Open Font License, Version 1.1 (OFL-1.1) — a permissive, non-copyleft -license compatible with MIT. See src/fonts/OFL.txt for the full license text -and src/fonts/NOTICE for attribution. Fonts are content/assets, not linked -code; bundling and redistribution under OFL-1.1 is expressly permitted. From b2c6b6eb7b9638051688939b722a1094c97da013 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 12 Aug 2026 20:09:21 +0900 Subject: [PATCH 3/4] test(supply-chain): bind npm license evidence --- src/licenseBoundary.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/licenseBoundary.test.ts b/src/licenseBoundary.test.ts index 3c805525..56c75a10 100644 --- a/src/licenseBoundary.test.ts +++ b/src/licenseBoundary.test.ts @@ -24,6 +24,11 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. `; +interface PackageLicenseManifest { + readonly files?: readonly string[]; + readonly license?: string; +} + describe('software and bundled-font license evidence', () => { it('keeps the root software license as exact canonical MIT text', () => { expect(readFileSync('LICENSE', 'utf8')).toBe(CANONICAL_MIT_LICENSE); @@ -37,4 +42,15 @@ describe('software and bundled-font license evidence', () => { 'SIL OPEN FONT LICENSE Version 1.1', ); }); + + it('keeps both software and bundled-font license evidence in the npm package', () => { + const packageManifest = JSON.parse( + readFileSync('package.json', 'utf8'), + ) as PackageLicenseManifest; + + expect(packageManifest.license).toBe('MIT'); + expect(packageManifest.files).toEqual( + expect.arrayContaining(['LICENSE', 'src/fonts']), + ); + }); }); From 79c0ca643c012b6666dcbc37cefe16dc3d5575bf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 14 Aug 2026 20:28:17 +0900 Subject: [PATCH 4/4] test(supply-chain): verify packed license evidence --- src/licenseBoundary.test.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/licenseBoundary.test.ts b/src/licenseBoundary.test.ts index 56c75a10..8fcf93b9 100644 --- a/src/licenseBoundary.test.ts +++ b/src/licenseBoundary.test.ts @@ -1,3 +1,4 @@ +import { execFileSync } from 'node:child_process'; import { readFileSync } from 'node:fs'; import { describe, expect, it } from 'vitest'; @@ -29,6 +30,10 @@ interface PackageLicenseManifest { readonly license?: string; } +interface NpmPackDryRunEntry { + readonly files?: readonly { readonly path?: string }[]; +} + describe('software and bundled-font license evidence', () => { it('keeps the root software license as exact canonical MIT text', () => { expect(readFileSync('LICENSE', 'utf8')).toBe(CANONICAL_MIT_LICENSE); @@ -43,7 +48,7 @@ describe('software and bundled-font license evidence', () => { ); }); - it('keeps both software and bundled-font license evidence in the npm package', () => { + it('keeps both software and bundled-font license evidence in the npm package manifest', () => { const packageManifest = JSON.parse( readFileSync('package.json', 'utf8'), ) as PackageLicenseManifest; @@ -53,4 +58,26 @@ describe('software and bundled-font license evidence', () => { expect.arrayContaining(['LICENSE', 'src/fonts']), ); }); + + it('retains both license families in the actual npm packlist', () => { + const packMetadata = JSON.parse( + execFileSync( + 'npm', + ['pack', '--dry-run', '--json', '--ignore-scripts'], + { encoding: 'utf8' }, + ), + ) as readonly NpmPackDryRunEntry[]; + + expect(packMetadata).toHaveLength(1); + const packedPaths = packMetadata[0]?.files?.flatMap(({ path }) => + path === undefined ? [] : [path], + ) ?? []; + expect(packedPaths).toEqual( + expect.arrayContaining([ + 'LICENSE', + 'src/fonts/NOTICE', + 'src/fonts/OFL.txt', + ]), + ); + }); });