@opensip-tools/fitness 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +40 -40
- package/.turbo/turbo-typecheck.log +1 -1
- package/dist/recipes/__tests__/check-config.test.js +21 -0
- package/dist/recipes/__tests__/check-config.test.js.map +1 -1
- package/dist/recipes/check-config.d.ts +3 -3
- package/dist/recipes/check-config.d.ts.map +1 -1
- package/dist/recipes/check-config.js +30 -13
- package/dist/recipes/check-config.js.map +1 -1
- package/package.json +3 -3
- package/src/recipes/__tests__/check-config.test.ts +22 -0
- package/src/recipes/check-config.ts +35 -13
package/.turbo/turbo-build.log
CHANGED
package/.turbo/turbo-test.log
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
1
|
|
|
2
|
-
> @opensip-tools/fitness@1.0.
|
|
2
|
+
> @opensip-tools/fitness@1.0.9 test /home/runner/work/opensip-tools/opensip-tools/packages/fitness/engine
|
|
3
3
|
> vitest run --passWithNoTests
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
[1m[7m[36m RUN [39m[27m[22m [36mv2.1.9 [39m[90m/home/runner/work/opensip-tools/opensip-tools/packages/fitness/engine[39m
|
|
7
7
|
|
|
8
|
-
[32m✓[39m src/__tests__/gate.test.ts [2m([22m[2m28 tests[22m[2m)[22m[90m
|
|
9
|
-
[32m✓[39m src/
|
|
10
|
-
[32m✓[39m src/
|
|
11
|
-
[32m✓[39m src/framework/__tests__/import-graph.test.ts [2m([22m[2m20 tests[22m[2m)[22m[33m
|
|
12
|
-
[33m[2m✓[22m[39m findStronglyConnectedComponents[2m > [22mhandles a deep graph without recursion blowing the stack [
|
|
13
|
-
[32m✓[39m src/plugins/__tests__/check-package-discovery.test.ts [2m([22m[2m16 tests[22m[2m)[22m[90m
|
|
14
|
-
[32m✓[39m src/recipes/__tests__/check-resolution.test.ts [2m([22m[2m14 tests[22m[2m)[22m[90m
|
|
15
|
-
[32m✓[39m src/__tests__/sarif.test.ts [2m([22m[2m15 tests[22m[2m)[22m[90m
|
|
16
|
-
[32m✓[39m src/plugins/__tests__/lang-domain.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m
|
|
17
|
-
[32m✓[39m src/framework/__tests__/result-builder.test.ts [2m([22m[2m25 tests[22m[2m)[22m[90m
|
|
18
|
-
[32m✓[39m src/framework/__tests__/scope-resolver.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m
|
|
19
|
-
[32m✓[39m src/plugins/__tests__/loader.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m
|
|
20
|
-
[33m[2m✓[22m[39m loadPlugin[2m > [22mregisters Check instances exported as named exports (no array wrapper) [
|
|
21
|
-
[32m✓[39m src/framework/__tests__/content-filter.test.ts [2m([22m[2m10 tests[22m[2m)[22m[90m
|
|
22
|
-
[32m✓[39m src/framework/__tests__/define-check.test.ts [2m([22m[2m17 tests[22m[2m)[22m[90m
|
|
23
|
-
[32m✓[39m src/framework/__tests__/file-cache.test.ts [2m([22m[2m15 tests[22m[2m)[22m[90m
|
|
24
|
-
[32m✓[39m src/framework/__tests__/path-matcher.test.ts [2m([22m[2m12 tests[22m[2m)[22m[90m
|
|
25
|
-
[32m✓[39m src/framework/__tests__/content-filter-dispatch.test.ts [2m([22m[2m6 tests[22m[2m)[22m[90m
|
|
26
|
-
[32m✓[39m src/recipes/__tests__/registry.test.ts [2m([22m[2m15 tests[22m[2m)[22m[90m
|
|
27
|
-
[32m✓[39m src/targets/__tests__/loader.test.ts [2m([22m[2m11 tests[22m[2m)[22m[90m
|
|
28
|
-
[32m✓[39m src/framework/__tests__/
|
|
29
|
-
[32m✓[39m src/framework/__tests__/
|
|
30
|
-
[32m✓[39m src/framework/__tests__/ast-utilities.test.ts [2m([22m[2m19 tests[22m[2m)[22m[90m
|
|
31
|
-
[32m✓[39m src/
|
|
32
|
-
[32m✓[39m src/
|
|
33
|
-
[32m✓[39m src/framework/__tests__/execution-context.test.ts [2m([22m[2m4 tests[22m[2m)[22m[90m
|
|
34
|
-
[32m✓[39m src/signalers/__tests__/loader.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m
|
|
35
|
-
[32m✓[39m src/recipes/__tests__/retry.test.ts [2m([22m[2m6 tests[22m[2m)[22m[90m
|
|
36
|
-
[32m✓[39m src/framework/__tests__/directive-parsing.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m
|
|
37
|
-
[32m✓[39m src/
|
|
38
|
-
[32m✓[39m src/
|
|
39
|
-
[32m✓[39m src/framework/__tests__/directive-inventory.test.ts [2m([22m[2m9 tests[22m[2m)[22m[90m
|
|
40
|
-
[32m✓[39m src/framework/__tests__/
|
|
41
|
-
[32m✓[39m src/framework/__tests__/
|
|
42
|
-
[32m✓[39m src/framework/__tests__/
|
|
43
|
-
[32m✓[39m src/
|
|
8
|
+
[32m✓[39m src/__tests__/gate.test.ts [2m([22m[2m28 tests[22m[2m)[22m[90m 230[2mms[22m[39m
|
|
9
|
+
[32m✓[39m src/framework/__tests__/registry.test.ts [2m([22m[2m24 tests[22m[2m)[22m[90m 65[2mms[22m[39m
|
|
10
|
+
[32m✓[39m src/recipes/__tests__/service.test.ts [2m([22m[2m28 tests[22m[2m)[22m[33m 709[2mms[22m[39m
|
|
11
|
+
[32m✓[39m src/framework/__tests__/import-graph.test.ts [2m([22m[2m20 tests[22m[2m)[22m[33m 865[2mms[22m[39m
|
|
12
|
+
[33m[2m✓[22m[39m findStronglyConnectedComponents[2m > [22mhandles a deep graph without recursion blowing the stack [33m642[2mms[22m[39m
|
|
13
|
+
[32m✓[39m src/plugins/__tests__/check-package-discovery.test.ts [2m([22m[2m16 tests[22m[2m)[22m[90m 298[2mms[22m[39m
|
|
14
|
+
[32m✓[39m src/recipes/__tests__/check-resolution.test.ts [2m([22m[2m14 tests[22m[2m)[22m[90m 43[2mms[22m[39m
|
|
15
|
+
[32m✓[39m src/__tests__/sarif.test.ts [2m([22m[2m15 tests[22m[2m)[22m[90m 48[2mms[22m[39m
|
|
16
|
+
[32m✓[39m src/plugins/__tests__/lang-domain.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m 138[2mms[22m[39m
|
|
17
|
+
[32m✓[39m src/framework/__tests__/result-builder.test.ts [2m([22m[2m25 tests[22m[2m)[22m[90m 97[2mms[22m[39m
|
|
18
|
+
[32m✓[39m src/framework/__tests__/scope-resolver.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m 264[2mms[22m[39m
|
|
19
|
+
[32m✓[39m src/plugins/__tests__/loader.test.ts [2m([22m[2m10 tests[22m[2m)[22m[33m 6358[2mms[22m[39m
|
|
20
|
+
[33m[2m✓[22m[39m loadPlugin[2m > [22mregisters Check instances exported as named exports (no array wrapper) [33m6076[2mms[22m[39m
|
|
21
|
+
[32m✓[39m src/framework/__tests__/content-filter.test.ts [2m([22m[2m10 tests[22m[2m)[22m[90m 41[2mms[22m[39m
|
|
22
|
+
[32m✓[39m src/framework/__tests__/define-check.test.ts [2m([22m[2m17 tests[22m[2m)[22m[90m 51[2mms[22m[39m
|
|
23
|
+
[32m✓[39m src/framework/__tests__/file-cache.test.ts [2m([22m[2m15 tests[22m[2m)[22m[90m 101[2mms[22m[39m
|
|
24
|
+
[32m✓[39m src/framework/__tests__/path-matcher.test.ts [2m([22m[2m12 tests[22m[2m)[22m[90m 151[2mms[22m[39m
|
|
25
|
+
[32m✓[39m src/framework/__tests__/content-filter-dispatch.test.ts [2m([22m[2m6 tests[22m[2m)[22m[90m 44[2mms[22m[39m
|
|
26
|
+
[32m✓[39m src/recipes/__tests__/registry.test.ts [2m([22m[2m15 tests[22m[2m)[22m[90m 78[2mms[22m[39m
|
|
27
|
+
[32m✓[39m src/targets/__tests__/loader.test.ts [2m([22m[2m11 tests[22m[2m)[22m[90m 74[2mms[22m[39m
|
|
28
|
+
[32m✓[39m src/framework/__tests__/strip-literals.test.ts [2m([22m[2m17 tests[22m[2m)[22m[90m 36[2mms[22m[39m
|
|
29
|
+
[32m✓[39m src/framework/__tests__/file-accessor.test.ts [2m([22m[2m11 tests[22m[2m)[22m[90m 162[2mms[22m[39m
|
|
30
|
+
[32m✓[39m src/framework/__tests__/ast-utilities.test.ts [2m([22m[2m19 tests[22m[2m)[22m[90m 81[2mms[22m[39m
|
|
31
|
+
[32m✓[39m src/targets/__tests__/target-registry.test.ts [2m([22m[2m11 tests[22m[2m)[22m[90m 23[2mms[22m[39m
|
|
32
|
+
[32m✓[39m src/recipes/__tests__/built-in-recipes.test.ts [2m([22m[2m14 tests[22m[2m)[22m[90m 37[2mms[22m[39m
|
|
33
|
+
[32m✓[39m src/framework/__tests__/execution-context.test.ts [2m([22m[2m4 tests[22m[2m)[22m[90m 100[2mms[22m[39m
|
|
34
|
+
[32m✓[39m src/signalers/__tests__/loader.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m 73[2mms[22m[39m
|
|
35
|
+
[32m✓[39m src/recipes/__tests__/retry.test.ts [2m([22m[2m6 tests[22m[2m)[22m[90m 31[2mms[22m[39m
|
|
36
|
+
[32m✓[39m src/framework/__tests__/directive-parsing.test.ts [2m([22m[2m8 tests[22m[2m)[22m[90m 13[2mms[22m[39m
|
|
37
|
+
[32m✓[39m src/recipes/__tests__/check-config.test.ts [2m([22m[2m5 tests[22m[2m)[22m[90m 12[2mms[22m[39m
|
|
38
|
+
[32m✓[39m src/targets/__tests__/resolver.test.ts [2m([22m[2m6 tests[22m[2m)[22m[90m 71[2mms[22m[39m
|
|
39
|
+
[32m✓[39m src/framework/__tests__/directive-inventory.test.ts [2m([22m[2m9 tests[22m[2m)[22m[90m 18[2mms[22m[39m
|
|
40
|
+
[32m✓[39m src/framework/__tests__/command-executor.test.ts [2m([22m[2m5 tests[22m[2m)[22m[90m 89[2mms[22m[39m
|
|
41
|
+
[32m✓[39m src/framework/__tests__/check-config.test.ts [2m([22m[2m6 tests[22m[2m)[22m[90m 31[2mms[22m[39m
|
|
42
|
+
[32m✓[39m src/framework/__tests__/severity-mapping.test.ts [2m([22m[2m13 tests[22m[2m)[22m[90m 28[2mms[22m[39m
|
|
43
|
+
[32m✓[39m src/framework/__tests__/register-helpers.test.ts [2m([22m[2m4 tests[22m[2m)[22m[90m 19[2mms[22m[39m
|
|
44
44
|
|
|
45
45
|
[2m Test Files [22m [1m[32m34 passed[39m[22m[90m (34)[39m
|
|
46
|
-
[2m Tests [22m [1m[
|
|
47
|
-
[2m Start at [22m
|
|
48
|
-
[2m Duration [22m
|
|
46
|
+
[2m Tests [22m [1m[32m428 passed[39m[22m[90m (428)[39m
|
|
47
|
+
[2m Start at [22m 22:05:49
|
|
48
|
+
[2m Duration [22m 25.18s[2m (transform 6.39s, setup 0ms, collect 23.57s, tests 10.48s, environment 37ms, prepare 12.94s)[22m
|
|
49
49
|
|
|
@@ -33,5 +33,26 @@ describe('getCheckConfig', () => {
|
|
|
33
33
|
const cfg = getCheckConfig('sample-check');
|
|
34
34
|
expect(cfg).toEqual({});
|
|
35
35
|
});
|
|
36
|
+
it('shares state with a separately-loaded copy of this module (multi-instance contract)', () => {
|
|
37
|
+
// Regression test for the multi-instance bug fixed in 1.0.9. The
|
|
38
|
+
// runtime frequently has TWO copies of `@opensip-tools/fitness`:
|
|
39
|
+
// the CLI's bundled copy (running the recipe service) and the
|
|
40
|
+
// plugin pack's resolved copy (running the check). Each copy has
|
|
41
|
+
// its own module-scope state; the prior `let currentRecipeCheckConfig`
|
|
42
|
+
// implementation made cross-copy state invisible. The fix moves
|
|
43
|
+
// the slot onto a `Symbol.for(...)` keyed `globalThis` entry so
|
|
44
|
+
// every copy reads + writes the same slot.
|
|
45
|
+
//
|
|
46
|
+
// Simulating "two copies" within one test: stash a value, look it
|
|
47
|
+
// up under the same well-known symbol from a separate import path
|
|
48
|
+
// (here: globalThis directly), and confirm the values match.
|
|
49
|
+
setCurrentRecipeCheckConfig({
|
|
50
|
+
'sample-check': { additionalEntries: ['cross-copy'] },
|
|
51
|
+
});
|
|
52
|
+
const KEY = Symbol.for('@opensip-tools/fitness/currentRecipeCheckConfig');
|
|
53
|
+
const slot = globalThis[KEY];
|
|
54
|
+
expect(slot).toBeDefined();
|
|
55
|
+
expect(slot['sample-check'].additionalEntries).toEqual(['cross-copy']);
|
|
56
|
+
});
|
|
36
57
|
});
|
|
37
58
|
//# sourceMappingURL=check-config.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-config.test.js","sourceRoot":"","sources":["../../../src/recipes/__tests__/check-config.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,oBAAoB,CAAA;AAM3B,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,6BAA6B,EAAE,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAG,cAAc,CAAe,UAAU,CAAC,CAAA;QACpD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,2BAA2B,CAAC;YAC1B,aAAa,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,CAAC,EAAE;SAC5C,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,cAAc,CAAe,SAAS,CAAC,CAAA;QACnD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,2BAA2B,CAAC;YAC1B,cAAc,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;SAClD,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,cAAc,CAAe,cAAc,CAAC,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,2BAA2B,CAAC;YAC1B,cAAc,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;SAClD,CAAC,CAAA;QACF,6BAA6B,EAAE,CAAA;QAC/B,MAAM,GAAG,GAAG,cAAc,CAAe,cAAc,CAAC,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"check-config.test.js","sourceRoot":"","sources":["../../../src/recipes/__tests__/check-config.test.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,EACL,cAAc,EACd,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,oBAAoB,CAAA;AAM3B,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,SAAS,CAAC,GAAG,EAAE;QACb,6BAA6B,EAAE,CAAA;IACjC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,GAAG,GAAG,cAAc,CAAe,UAAU,CAAC,CAAA;QACpD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,2BAA2B,CAAC;YAC1B,aAAa,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,CAAC,EAAE;SAC5C,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,cAAc,CAAe,SAAS,CAAC,CAAA;QACnD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,2BAA2B,CAAC;YAC1B,cAAc,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;SAClD,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,cAAc,CAAe,cAAc,CAAC,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,2BAA2B,CAAC;YAC1B,cAAc,EAAE,EAAE,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE;SAClD,CAAC,CAAA;QACF,6BAA6B,EAAE,CAAA;QAC/B,MAAM,GAAG,GAAG,cAAc,CAAe,cAAc,CAAC,CAAA;QACxD,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACzB,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qFAAqF,EAAE,GAAG,EAAE;QAC7F,iEAAiE;QACjE,iEAAiE;QACjE,8DAA8D;QAC9D,iEAAiE;QACjE,uEAAuE;QACvE,gEAAgE;QAChE,gEAAgE;QAChE,2CAA2C;QAC3C,EAAE;QACF,kEAAkE;QAClE,kEAAkE;QAClE,6DAA6D;QAC7D,2BAA2B,CAAC;YAC1B,cAAc,EAAE,EAAE,iBAAiB,EAAE,CAAC,YAAY,CAAC,EAAE;SACtD,CAAC,CAAA;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAA;QACzE,MAAM,IAAI,GAAI,UAAiD,CAAC,GAAG,CAAC,CAAA;QACpE,MAAM,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAA;QAC1B,MAAM,CAAE,IAA4D,CAAC,cAAc,CAAC,CAAC,iBAAiB,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;IACjI,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
@@ -28,13 +28,13 @@ import type { RecipeCheckConfigMap } from './types.js';
|
|
|
28
28
|
*/
|
|
29
29
|
export declare function getCheckConfig<T extends Record<string, unknown>>(slug: string): T;
|
|
30
30
|
/**
|
|
31
|
-
* Replace the
|
|
31
|
+
* Replace the global recipe config. Called by the recipe service at
|
|
32
32
|
* the start of a recipe run, before any check executes.
|
|
33
33
|
*/
|
|
34
34
|
export declare function setCurrentRecipeCheckConfig(config: RecipeCheckConfigMap | undefined): void;
|
|
35
35
|
/**
|
|
36
|
-
* Clear the
|
|
37
|
-
*
|
|
36
|
+
* Clear the global recipe config. Called by the recipe service at the end
|
|
37
|
+
* of a recipe run (success or failure).
|
|
38
38
|
*/
|
|
39
39
|
export declare function clearCurrentRecipeCheckConfig(): void;
|
|
40
40
|
//# sourceMappingURL=check-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-config.d.ts","sourceRoot":"","sources":["../../src/recipes/check-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"check-config.d.ts","sourceRoot":"","sources":["../../src/recipes/check-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAmCtD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAMjF;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,oBAAoB,GAAG,SAAS,GAAG,IAAI,CAE1F;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,IAAI,IAAI,CAEpD"}
|
|
@@ -16,16 +16,32 @@
|
|
|
16
16
|
* extend the safe-lists with project-specific names.
|
|
17
17
|
*/
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
19
|
+
* Process-shared current-recipe config. Populated by the recipe service at
|
|
20
20
|
* the start of a run and cleared at the end. Checks read from it lazily via
|
|
21
21
|
* {@link getCheckConfig}.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* `globalThis` (not module-local `let`) is load-bearing — the runtime
|
|
24
|
+
* frequently has TWO copies of `@opensip-tools/fitness` loaded:
|
|
25
|
+
*
|
|
26
|
+
* 1. The CLI's bundled copy (running the recipe service).
|
|
27
|
+
* 2. The plugin pack's resolved copy (running the check, calling
|
|
28
|
+
* `getCheckConfig(slug)`).
|
|
29
|
+
*
|
|
30
|
+
* Each copy has its own module-scope state, so a module-local `let` here
|
|
31
|
+
* means `setCurrentRecipeCheckConfig(...)` in copy 1 is invisible to
|
|
32
|
+
* `getCheckConfig(...)` in copy 2 — the recipe's `additionalSyncFunctions`
|
|
33
|
+
* (and every other per-check allowlist) silently never reaches the checks
|
|
34
|
+
* that read it. Storing the map on `globalThis` under a single well-known
|
|
35
|
+
* symbol means every copy reads + writes the same slot.
|
|
36
|
+
*
|
|
37
|
+
* The single-session contract still holds (the recipe service throws
|
|
38
|
+
* SESSION_IN_PROGRESS otherwise); the only thing that changes vs the prior
|
|
39
|
+
* design is the storage location, not the lifecycle.
|
|
27
40
|
*/
|
|
28
|
-
|
|
41
|
+
const GLOBAL_KEY = Symbol.for('@opensip-tools/fitness/currentRecipeCheckConfig');
|
|
42
|
+
function slot() {
|
|
43
|
+
return globalThis;
|
|
44
|
+
}
|
|
29
45
|
/**
|
|
30
46
|
* Read the per-check config slice for the given slug.
|
|
31
47
|
*
|
|
@@ -37,25 +53,26 @@ let currentRecipeCheckConfig;
|
|
|
37
53
|
* its own config interface.
|
|
38
54
|
*/
|
|
39
55
|
export function getCheckConfig(slug) {
|
|
40
|
-
|
|
56
|
+
const current = slot()[GLOBAL_KEY];
|
|
57
|
+
if (!current)
|
|
41
58
|
return {};
|
|
42
|
-
const entry =
|
|
59
|
+
const entry = current[slug];
|
|
43
60
|
if (!entry)
|
|
44
61
|
return {};
|
|
45
62
|
return entry;
|
|
46
63
|
}
|
|
47
64
|
/**
|
|
48
|
-
* Replace the
|
|
65
|
+
* Replace the global recipe config. Called by the recipe service at
|
|
49
66
|
* the start of a recipe run, before any check executes.
|
|
50
67
|
*/
|
|
51
68
|
export function setCurrentRecipeCheckConfig(config) {
|
|
52
|
-
|
|
69
|
+
slot()[GLOBAL_KEY] = config;
|
|
53
70
|
}
|
|
54
71
|
/**
|
|
55
|
-
* Clear the
|
|
56
|
-
*
|
|
72
|
+
* Clear the global recipe config. Called by the recipe service at the end
|
|
73
|
+
* of a recipe run (success or failure).
|
|
57
74
|
*/
|
|
58
75
|
export function clearCurrentRecipeCheckConfig() {
|
|
59
|
-
|
|
76
|
+
slot()[GLOBAL_KEY] = undefined;
|
|
60
77
|
}
|
|
61
78
|
//# sourceMappingURL=check-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-config.js","sourceRoot":"","sources":["../../src/recipes/check-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH
|
|
1
|
+
{"version":3,"file":"check-config.js","sourceRoot":"","sources":["../../src/recipes/check-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAA;AAMhF,SAAS,IAAI;IACX,OAAO,UAAmC,CAAA;AAC5C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAoC,IAAY;IAC5E,MAAM,OAAO,GAAG,IAAI,EAAE,CAAC,UAAU,CAAC,CAAA;IAClC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAO,CAAA;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,CAAC,KAAK;QAAE,OAAO,EAAO,CAAA;IAC1B,OAAO,KAAU,CAAA;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAwC;IAClF,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,MAAM,CAAA;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,6BAA6B;IAC3C,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,SAAS,CAAA;AAChC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensip-tools/fitness",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Fitness checks engine for OpenSIP Tools",
|
|
6
6
|
"repository": {
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"minimatch": "^10.0.0",
|
|
29
29
|
"typescript": "~5.7.0",
|
|
30
30
|
"zod": "^3.24.0",
|
|
31
|
-
"@opensip-tools/
|
|
32
|
-
"@opensip-tools/
|
|
31
|
+
"@opensip-tools/contracts": "1.0.9",
|
|
32
|
+
"@opensip-tools/core": "1.0.9"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/js-yaml": "^4.0.0",
|
|
@@ -48,4 +48,26 @@ describe('getCheckConfig', () => {
|
|
|
48
48
|
const cfg = getCheckConfig<SampleConfig>('sample-check')
|
|
49
49
|
expect(cfg).toEqual({})
|
|
50
50
|
})
|
|
51
|
+
|
|
52
|
+
it('shares state with a separately-loaded copy of this module (multi-instance contract)', () => {
|
|
53
|
+
// Regression test for the multi-instance bug fixed in 1.0.9. The
|
|
54
|
+
// runtime frequently has TWO copies of `@opensip-tools/fitness`:
|
|
55
|
+
// the CLI's bundled copy (running the recipe service) and the
|
|
56
|
+
// plugin pack's resolved copy (running the check). Each copy has
|
|
57
|
+
// its own module-scope state; the prior `let currentRecipeCheckConfig`
|
|
58
|
+
// implementation made cross-copy state invisible. The fix moves
|
|
59
|
+
// the slot onto a `Symbol.for(...)` keyed `globalThis` entry so
|
|
60
|
+
// every copy reads + writes the same slot.
|
|
61
|
+
//
|
|
62
|
+
// Simulating "two copies" within one test: stash a value, look it
|
|
63
|
+
// up under the same well-known symbol from a separate import path
|
|
64
|
+
// (here: globalThis directly), and confirm the values match.
|
|
65
|
+
setCurrentRecipeCheckConfig({
|
|
66
|
+
'sample-check': { additionalEntries: ['cross-copy'] },
|
|
67
|
+
})
|
|
68
|
+
const KEY = Symbol.for('@opensip-tools/fitness/currentRecipeCheckConfig')
|
|
69
|
+
const slot = (globalThis as unknown as Record<symbol, unknown>)[KEY]
|
|
70
|
+
expect(slot).toBeDefined()
|
|
71
|
+
expect((slot as { 'sample-check': { additionalEntries: string[] } })['sample-check'].additionalEntries).toEqual(['cross-copy'])
|
|
72
|
+
})
|
|
51
73
|
})
|
|
@@ -19,16 +19,37 @@
|
|
|
19
19
|
import type { RecipeCheckConfigMap } from './types.js'
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Process-shared current-recipe config. Populated by the recipe service at
|
|
23
23
|
* the start of a run and cleared at the end. Checks read from it lazily via
|
|
24
24
|
* {@link getCheckConfig}.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
26
|
+
* `globalThis` (not module-local `let`) is load-bearing — the runtime
|
|
27
|
+
* frequently has TWO copies of `@opensip-tools/fitness` loaded:
|
|
28
|
+
*
|
|
29
|
+
* 1. The CLI's bundled copy (running the recipe service).
|
|
30
|
+
* 2. The plugin pack's resolved copy (running the check, calling
|
|
31
|
+
* `getCheckConfig(slug)`).
|
|
32
|
+
*
|
|
33
|
+
* Each copy has its own module-scope state, so a module-local `let` here
|
|
34
|
+
* means `setCurrentRecipeCheckConfig(...)` in copy 1 is invisible to
|
|
35
|
+
* `getCheckConfig(...)` in copy 2 — the recipe's `additionalSyncFunctions`
|
|
36
|
+
* (and every other per-check allowlist) silently never reaches the checks
|
|
37
|
+
* that read it. Storing the map on `globalThis` under a single well-known
|
|
38
|
+
* symbol means every copy reads + writes the same slot.
|
|
39
|
+
*
|
|
40
|
+
* The single-session contract still holds (the recipe service throws
|
|
41
|
+
* SESSION_IN_PROGRESS otherwise); the only thing that changes vs the prior
|
|
42
|
+
* design is the storage location, not the lifecycle.
|
|
30
43
|
*/
|
|
31
|
-
|
|
44
|
+
const GLOBAL_KEY = Symbol.for('@opensip-tools/fitness/currentRecipeCheckConfig')
|
|
45
|
+
|
|
46
|
+
interface GlobalSlot {
|
|
47
|
+
[GLOBAL_KEY]?: RecipeCheckConfigMap | undefined
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function slot(): GlobalSlot {
|
|
51
|
+
return globalThis as unknown as GlobalSlot
|
|
52
|
+
}
|
|
32
53
|
|
|
33
54
|
/**
|
|
34
55
|
* Read the per-check config slice for the given slug.
|
|
@@ -41,24 +62,25 @@ let currentRecipeCheckConfig: RecipeCheckConfigMap | undefined
|
|
|
41
62
|
* its own config interface.
|
|
42
63
|
*/
|
|
43
64
|
export function getCheckConfig<T extends Record<string, unknown>>(slug: string): T {
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
const current = slot()[GLOBAL_KEY]
|
|
66
|
+
if (!current) return {} as T
|
|
67
|
+
const entry = current[slug]
|
|
46
68
|
if (!entry) return {} as T
|
|
47
69
|
return entry as T
|
|
48
70
|
}
|
|
49
71
|
|
|
50
72
|
/**
|
|
51
|
-
* Replace the
|
|
73
|
+
* Replace the global recipe config. Called by the recipe service at
|
|
52
74
|
* the start of a recipe run, before any check executes.
|
|
53
75
|
*/
|
|
54
76
|
export function setCurrentRecipeCheckConfig(config: RecipeCheckConfigMap | undefined): void {
|
|
55
|
-
|
|
77
|
+
slot()[GLOBAL_KEY] = config
|
|
56
78
|
}
|
|
57
79
|
|
|
58
80
|
/**
|
|
59
|
-
* Clear the
|
|
60
|
-
*
|
|
81
|
+
* Clear the global recipe config. Called by the recipe service at the end
|
|
82
|
+
* of a recipe run (success or failure).
|
|
61
83
|
*/
|
|
62
84
|
export function clearCurrentRecipeCheckConfig(): void {
|
|
63
|
-
|
|
85
|
+
slot()[GLOBAL_KEY] = undefined
|
|
64
86
|
}
|