From 22331acfcf831c9a0129a0e3187c6d6f55d1d851 Mon Sep 17 00:00:00 2001 From: Marko Lahma Date: Wed, 29 Jul 2026 14:15:18 +0300 Subject: [PATCH] Verify Jint's host contracts on every test run The scripting integration defines several Jint extension points: the ContentWrapper objects override GetOwnProperty, and the engine trusts the answer without re-verifying it on the hot path. A hook that contradicts another therefore fails silently in production - a key vanishes from every enumeration, or a read resolves on the prototype for a property that exists - which is the class of bug no assertion in this repository would catch. Jint 4.15.3 exposes its host-contract verifiers to the shipped Release package through an AppContext switch, where before they were compiled out unless you built the engine from source in Debug. A module initializer sets it for this test assembly, so the verifiers run against the same NuGet package production uses and report a violation as an ordinary test failure. It must be set before the first use of any Jint type, which is exactly what a module initializer guarantees. Confirmed live rather than assumed: with a deliberately wrong ProbeOwnProperty the run fails with "ContentFieldObject.ProbeOwnProperty answered 'iv' with Missing but its GetOwnProperty reports Enumerable". Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016uV6H9cTntzsoKiaJRBn4f --- .../JintHostContractVerification.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/JintHostContractVerification.cs diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/JintHostContractVerification.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/JintHostContractVerification.cs new file mode 100644 index 000000000..3fe8ea3b0 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/TestHelpers/JintHostContractVerification.cs @@ -0,0 +1,35 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Runtime.CompilerServices; + +namespace Squidex.Domain.Apps.Core.TestHelpers; + +/// +/// Turns on Jint's host-contract verifiers for this test assembly. +/// +/// +/// The scripting integration defines several Jint extension points - the ContentWrapper objects override +/// GetOwnProperty and ProbeOwnProperty, and the engine trusts both without re-verifying them on the hot +/// path. A hook that contradicts another therefore fails silently in production: a key vanishes from every +/// enumeration, or a read resolves on the prototype for a property that exists. With the switch on, Jint +/// recomputes the answer the fast paths exist to avoid and throws on the first disagreement, so these tests +/// are the checker. +/// +/// It has to be set before the first use of any Jint type - the flag is read once at type initialization - +/// which is what the module initializer guarantees. Never turn it on in production: the verifiers +/// deliberately redo the work they check. +/// +/// +internal static class JintHostContractVerification +{ + [ModuleInitializer] + internal static void Enable() + { + AppContext.SetSwitch("Jint.EnableHostContractVerification", true); + } +}