From e29617c04ebe3097914fed02e6ce917f48a9dbd6 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sat, 10 Oct 2026 10:01:56 +0200 Subject: test(node): a name an LGPL file declares itself is its own binding The LGPL closure check excluded only names declared at the top level of the LGPL files, so keyring.js's `const state = () => ...`, local to createKeyring, read as a call to photo-sync.js's top-level `state` once that file was added. A name the file declares at any depth now shadows an AGPL global for that file. A real call into an AGPL module is still caught (checked by adding one to keyring.js). Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-node/tests/test_licensing.py | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'packages/meshbay-node/tests') diff --git a/packages/meshbay-node/tests/test_licensing.py b/packages/meshbay-node/tests/test_licensing.py index 68eb6bb..239633d 100644 --- a/packages/meshbay-node/tests/test_licensing.py +++ b/packages/meshbay-node/tests/test_licensing.py @@ -220,7 +220,14 @@ def test_the_lgpl_layer_depends_on_nothing_under_the_agpl(): if spec.startswith("node:") or "vendor" in spec: continue assert (f.parent / spec).resolve() in lgpl, f"{f.name} imports {spec}" + # A name the file declares itself, at any depth, is its own binding: + # keyring.js's `const state = () => ...` inside createKeyring was taken + # for photo-sync.js's top-level `state` once that file existed. + own = set(re.findall( + r"\b(?:function\*?\s+|const\s+|let\s+|var\s+|class\s+)([A-Za-z_$][\w$]*)", code)) for name, owner in agpl_globals.items(): + if name in own: + continue assert not re.search(rf"(?