@xemahq/entitlement-client 0.1.2 → 0.2.0
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/README.md +35 -15
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/entitlement-client.module.d.ts +1 -1
- package/dist/lib/entitlement-client.module.d.ts.map +1 -1
- package/dist/lib/entitlement-client.module.js +7 -7
- package/dist/lib/entitlement-client.module.js.map +1 -1
- package/dist/lib/entitlement.guard.d.ts +1 -1
- package/dist/lib/entitlement.guard.d.ts.map +1 -1
- package/dist/lib/entitlement.guard.js +2 -2
- package/dist/lib/entitlement.guard.js.map +1 -1
- package/dist/lib/entitlement.service.d.ts +17 -18
- package/dist/lib/entitlement.service.d.ts.map +1 -1
- package/dist/lib/entitlement.service.js +98 -74
- package/dist/lib/entitlement.service.js.map +1 -1
- package/dist/lib/installation-license.d.ts +85 -0
- package/dist/lib/installation-license.d.ts.map +1 -0
- package/dist/lib/installation-license.js +212 -0
- package/dist/lib/installation-license.js.map +1 -0
- package/dist/lib/installation-license.test.d.ts +2 -0
- package/dist/lib/installation-license.test.d.ts.map +1 -0
- package/dist/lib/installation-license.test.js +389 -0
- package/dist/lib/installation-license.test.js.map +1 -0
- package/dist/lib/license-refused.exception.d.ts +16 -0
- package/dist/lib/license-refused.exception.d.ts.map +1 -0
- package/dist/lib/license-refused.exception.js +121 -0
- package/dist/lib/license-refused.exception.js.map +1 -0
- package/dist/lib/license-warnings.d.ts +28 -0
- package/dist/lib/license-warnings.d.ts.map +1 -0
- package/dist/lib/license-warnings.js +173 -0
- package/dist/lib/license-warnings.js.map +1 -0
- package/dist/lib/license.testkit.d.ts +11 -0
- package/dist/lib/license.testkit.d.ts.map +1 -0
- package/dist/lib/license.testkit.js +47 -0
- package/dist/lib/license.testkit.js.map +1 -0
- package/package.json +18 -6
- package/LICENSE +0 -176
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation-license.d.ts","sourceRoot":"","sources":["../../src/lib/installation-license.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.InstallationLicense = exports.DISTRIBUTION_UNDECLARED_REFUSAL = exports.LicenseRefusalKind = exports.LICENSE_ENV_VAR = void 0;
|
|
4
|
+
exports.worstWarningSeverity = worstWarningSeverity;
|
|
5
|
+
exports.isUnprovisionedBuildRefusal = isUnprovisionedBuildRefusal;
|
|
6
|
+
const entitlement_1 = require("@xemahq/kernel-contracts/entitlement");
|
|
7
|
+
const license_verifier_1 = require("@xemahq/license-verifier");
|
|
8
|
+
const license_warnings_ts_1 = require("./license-warnings.js");
|
|
9
|
+
exports.LICENSE_ENV_VAR = 'XEMA_LICENSE';
|
|
10
|
+
var LicenseRefusalKind;
|
|
11
|
+
(function (LicenseRefusalKind) {
|
|
12
|
+
LicenseRefusalKind["Unverifiable"] = "unverifiable";
|
|
13
|
+
LicenseRefusalKind["NotEntitled"] = "not-entitled";
|
|
14
|
+
LicenseRefusalKind["DistributionUndeclared"] = "distribution-undeclared";
|
|
15
|
+
})(LicenseRefusalKind || (exports.LicenseRefusalKind = LicenseRefusalKind = {}));
|
|
16
|
+
exports.DISTRIBUTION_UNDECLARED_REFUSAL = {
|
|
17
|
+
kind: LicenseRefusalKind.DistributionUndeclared,
|
|
18
|
+
remediation: 'Mount the distribution lock (XEMA_DISTRIBUTION_LOCK_PATH) so this ' +
|
|
19
|
+
'deployment declares which Xema distribution it runs, or set ' +
|
|
20
|
+
'XEMA_DISTRIBUTION_ID explicitly.',
|
|
21
|
+
};
|
|
22
|
+
class InstallationLicense {
|
|
23
|
+
config;
|
|
24
|
+
verification;
|
|
25
|
+
highestObservedTimeMs;
|
|
26
|
+
constructor(config) {
|
|
27
|
+
this.config = config;
|
|
28
|
+
}
|
|
29
|
+
evaluate(query, options = {}) {
|
|
30
|
+
const effective = this.effective();
|
|
31
|
+
if (!effective.ok) {
|
|
32
|
+
return {
|
|
33
|
+
granted: false,
|
|
34
|
+
refusal: {
|
|
35
|
+
kind: LicenseRefusalKind.Unverifiable,
|
|
36
|
+
code: effective.code,
|
|
37
|
+
message: effective.message,
|
|
38
|
+
remediation: (0, license_warnings_ts_1.platformLicenseRemediation)(effective.code),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const decision = (0, license_verifier_1.evaluateEntitlement)(effective.license, query, this.stateOptions(options));
|
|
43
|
+
this.observe(decision.state.evaluatedAtMs);
|
|
44
|
+
if (decision.granted) {
|
|
45
|
+
return {
|
|
46
|
+
granted: true,
|
|
47
|
+
matched: decision.matched,
|
|
48
|
+
state: decision.state,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
granted: false,
|
|
53
|
+
refusal: {
|
|
54
|
+
kind: LicenseRefusalKind.NotEntitled,
|
|
55
|
+
reason: decision.reason,
|
|
56
|
+
state: decision.state,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
entitlementSet(options = {}) {
|
|
61
|
+
if (!this.effective().ok) {
|
|
62
|
+
return entitlement_1.COMMUNITY_ENTITLEMENT;
|
|
63
|
+
}
|
|
64
|
+
return (0, entitlement_1.projectEntitlementSet)((capabilityClassId) => this.evaluate({
|
|
65
|
+
kind: license_verifier_1.EntitlementKind.CapabilityClass,
|
|
66
|
+
id: capabilityClassId,
|
|
67
|
+
action: license_verifier_1.EntitlementAction.RunExisting,
|
|
68
|
+
}, options).granted);
|
|
69
|
+
}
|
|
70
|
+
editionQuery() {
|
|
71
|
+
const { distributionId } = this.config;
|
|
72
|
+
if (distributionId === null) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
kind: license_verifier_1.EntitlementKind.Distribution,
|
|
77
|
+
id: distributionId,
|
|
78
|
+
action: license_verifier_1.EntitlementAction.RunExisting,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
editionGate(options = {}) {
|
|
82
|
+
const query = this.editionQuery();
|
|
83
|
+
if (query === null) {
|
|
84
|
+
return { granted: false, refusal: exports.DISTRIBUTION_UNDECLARED_REFUSAL };
|
|
85
|
+
}
|
|
86
|
+
return this.evaluate(query, options);
|
|
87
|
+
}
|
|
88
|
+
biomeInstallGate(biomeId, options = {}) {
|
|
89
|
+
const edition = this.editionGate(options);
|
|
90
|
+
if (!edition.granted) {
|
|
91
|
+
return edition;
|
|
92
|
+
}
|
|
93
|
+
return this.evaluate({
|
|
94
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
95
|
+
id: biomeId,
|
|
96
|
+
action: license_verifier_1.EntitlementAction.Install,
|
|
97
|
+
}, options);
|
|
98
|
+
}
|
|
99
|
+
distributionEntitled(options = {}) {
|
|
100
|
+
return this.editionGate(options).granted;
|
|
101
|
+
}
|
|
102
|
+
posture(options = {}) {
|
|
103
|
+
const effective = this.effective();
|
|
104
|
+
if (!effective.ok) {
|
|
105
|
+
return {
|
|
106
|
+
licensed: false,
|
|
107
|
+
source: effective.source,
|
|
108
|
+
code: effective.code,
|
|
109
|
+
message: effective.message,
|
|
110
|
+
remediation: (0, license_warnings_ts_1.platformLicenseRemediation)(effective.code),
|
|
111
|
+
entitlement: entitlement_1.COMMUNITY_ENTITLEMENT,
|
|
112
|
+
distributionId: this.config.distributionId,
|
|
113
|
+
distributionEntitled: false,
|
|
114
|
+
warnings: [
|
|
115
|
+
{
|
|
116
|
+
code: license_warnings_ts_1.LicenseWarningCode.Unverifiable,
|
|
117
|
+
severity: license_warnings_ts_1.LicenseWarningSeverity.Critical,
|
|
118
|
+
message: `No license could be verified (${effective.code}): ` +
|
|
119
|
+
`${effective.message}. Enterprise features are off and new biome ` +
|
|
120
|
+
'installs are refused. Existing workloads keep running.',
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const state = (0, license_verifier_1.resolveLicenseState)(effective.license, this.stateOptions(options));
|
|
126
|
+
this.observe(state.evaluatedAtMs);
|
|
127
|
+
const distributionEntitled = this.distributionEntitled(options);
|
|
128
|
+
const warnings = (0, license_warnings_ts_1.licenseStateWarnings)(state);
|
|
129
|
+
if (this.config.distributionId === null) {
|
|
130
|
+
warnings.push({
|
|
131
|
+
code: license_warnings_ts_1.LicenseWarningCode.DistributionUndeclared,
|
|
132
|
+
severity: license_warnings_ts_1.LicenseWarningSeverity.Warning,
|
|
133
|
+
message: 'This deployment does not declare which distribution it is running ' +
|
|
134
|
+
'(no distribution lock is mounted), so the license cannot be checked ' +
|
|
135
|
+
'against an edition at all. Mount the distribution lock.',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
else if (!distributionEntitled) {
|
|
139
|
+
warnings.push({
|
|
140
|
+
code: license_warnings_ts_1.LicenseWarningCode.DistributionNotEntitled,
|
|
141
|
+
severity: license_warnings_ts_1.LicenseWarningSeverity.Critical,
|
|
142
|
+
message: `The license does not entitle this installation to run the ` +
|
|
143
|
+
`"${this.config.distributionId}" distribution. Mirroring the images ` +
|
|
144
|
+
'does not confer the right to run them (decision D6). New biome ' +
|
|
145
|
+
'installs and upgrades are refused; existing workloads keep running ' +
|
|
146
|
+
'and no data is touched.',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const { claims } = effective.license;
|
|
150
|
+
return {
|
|
151
|
+
licensed: true,
|
|
152
|
+
source: effective.source,
|
|
153
|
+
licenseId: claims.licenseId,
|
|
154
|
+
customerId: claims.subject.customerId,
|
|
155
|
+
customerName: claims.subject.customerName,
|
|
156
|
+
tier: claims.tier,
|
|
157
|
+
state,
|
|
158
|
+
entitlement: this.entitlementSet(options),
|
|
159
|
+
distributionId: this.config.distributionId,
|
|
160
|
+
distributionEntitled,
|
|
161
|
+
warnings,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
verifiedLicense() {
|
|
165
|
+
const effective = this.effective();
|
|
166
|
+
return effective.ok ? effective.license : undefined;
|
|
167
|
+
}
|
|
168
|
+
effective() {
|
|
169
|
+
this.verification ??= (0, license_verifier_1.resolveEffectiveLicense)({
|
|
170
|
+
customerLicense: this.config.customerLicense,
|
|
171
|
+
...(this.config.trustStore !== undefined
|
|
172
|
+
? { trustStore: this.config.trustStore }
|
|
173
|
+
: {}),
|
|
174
|
+
});
|
|
175
|
+
return this.verification;
|
|
176
|
+
}
|
|
177
|
+
stateOptions(options) {
|
|
178
|
+
return {
|
|
179
|
+
...(options.now !== undefined ? { now: options.now } : {}),
|
|
180
|
+
...(this.highestObservedTimeMs !== undefined
|
|
181
|
+
? { highestObservedTimeMs: this.highestObservedTimeMs }
|
|
182
|
+
: {}),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
observe(evaluatedAtMs) {
|
|
186
|
+
if (this.highestObservedTimeMs === undefined ||
|
|
187
|
+
evaluatedAtMs > this.highestObservedTimeMs) {
|
|
188
|
+
this.highestObservedTimeMs = evaluatedAtMs;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
exports.InstallationLicense = InstallationLicense;
|
|
193
|
+
function worstWarningSeverity(warnings) {
|
|
194
|
+
let worst;
|
|
195
|
+
for (const warning of warnings) {
|
|
196
|
+
if (worst === undefined ||
|
|
197
|
+
SEVERITY_ORDER[warning.severity] > SEVERITY_ORDER[worst]) {
|
|
198
|
+
worst = warning.severity;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return worst;
|
|
202
|
+
}
|
|
203
|
+
const SEVERITY_ORDER = {
|
|
204
|
+
[license_warnings_ts_1.LicenseWarningSeverity.Info]: 0,
|
|
205
|
+
[license_warnings_ts_1.LicenseWarningSeverity.Warning]: 1,
|
|
206
|
+
[license_warnings_ts_1.LicenseWarningSeverity.Critical]: 2,
|
|
207
|
+
};
|
|
208
|
+
function isUnprovisionedBuildRefusal(refusal) {
|
|
209
|
+
return (refusal.kind === LicenseRefusalKind.Unverifiable &&
|
|
210
|
+
refusal.code === license_verifier_1.LicenseVerificationFailureCode.TrustStoreEmpty);
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=installation-license.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation-license.js","sourceRoot":"","sources":["../../src/lib/installation-license.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installation-license.test.d.ts","sourceRoot":"","sources":["../../src/lib/installation-license.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const strict_1 = __importDefault(require("node:assert/strict"));
|
|
7
|
+
const node_test_1 = require("node:test");
|
|
8
|
+
const entitlement_1 = require("@xemahq/kernel-contracts/entitlement");
|
|
9
|
+
const license_verifier_1 = require("@xemahq/license-verifier");
|
|
10
|
+
const installation_license_ts_1 = require("./installation-license.ts");
|
|
11
|
+
const license_refused_exception_ts_1 = require("./license-refused.exception.ts");
|
|
12
|
+
const license_warnings_ts_1 = require("./license-warnings.ts");
|
|
13
|
+
const license_testkit_ts_1 = require("./license.testkit.ts");
|
|
14
|
+
const authority = (0, license_testkit_ts_1.createTestAuthority)();
|
|
15
|
+
const DISTRIBUTION_ID = 'core';
|
|
16
|
+
const GRANTED_BIOME = 'knowledge-base';
|
|
17
|
+
const UNGRANTED_BIOME = 'managed-llm-economy';
|
|
18
|
+
const IN_FORCE = (0, license_testkit_ts_1.at)('2026-06-01T00:00:00.000Z');
|
|
19
|
+
const EXPIRED_IN_GRACE = (0, license_testkit_ts_1.at)('2027-02-10T00:00:00.000Z');
|
|
20
|
+
const EXPIRED_RESTRICTED = (0, license_testkit_ts_1.at)('2027-02-01T00:00:00.000Z') + license_verifier_1.LICENSE_GRACE_PERIOD_MS + 24 * 60 * 60 * 1000;
|
|
21
|
+
async function installationFor(overrides = {}) {
|
|
22
|
+
return new installation_license_ts_1.InstallationLicense({
|
|
23
|
+
customerLicense: await (0, license_testkit_ts_1.mint)(authority, overrides),
|
|
24
|
+
distributionId: DISTRIBUTION_ID,
|
|
25
|
+
trustStore: authority.trustStore,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
function refusalOf(outcome) {
|
|
29
|
+
strict_1.default.equal(outcome.granted, false, 'expected the gate to refuse');
|
|
30
|
+
strict_1.default.ok(!outcome.granted);
|
|
31
|
+
return outcome.refusal;
|
|
32
|
+
}
|
|
33
|
+
function install(installation, biomeId, now) {
|
|
34
|
+
return installation.evaluate({
|
|
35
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
36
|
+
id: biomeId,
|
|
37
|
+
action: license_verifier_1.EntitlementAction.Install,
|
|
38
|
+
}, { now });
|
|
39
|
+
}
|
|
40
|
+
function runExisting(installation, biomeId, now) {
|
|
41
|
+
return installation.evaluate({
|
|
42
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
43
|
+
id: biomeId,
|
|
44
|
+
action: license_verifier_1.EntitlementAction.RunExisting,
|
|
45
|
+
}, { now });
|
|
46
|
+
}
|
|
47
|
+
(0, node_test_1.test)('an UNPROVISIONED build verifies nothing and grants nothing', async () => {
|
|
48
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
49
|
+
customerLicense: undefined,
|
|
50
|
+
distributionId: DISTRIBUTION_ID,
|
|
51
|
+
});
|
|
52
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
53
|
+
strict_1.default.equal(posture.licensed, false);
|
|
54
|
+
strict_1.default.ok(!posture.licensed);
|
|
55
|
+
strict_1.default.equal(posture.code, license_verifier_1.LicenseVerificationFailureCode.TrustStoreEmpty);
|
|
56
|
+
strict_1.default.equal(posture.source, license_verifier_1.LicenseSource.EmbeddedOpenSource);
|
|
57
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Community);
|
|
58
|
+
strict_1.default.deepEqual(posture.entitlement.features, {});
|
|
59
|
+
strict_1.default.equal(posture.distributionEntitled, false);
|
|
60
|
+
strict_1.default.deepEqual(posture.warnings.map((w) => w.code), [license_warnings_ts_1.LicenseWarningCode.Unverifiable]);
|
|
61
|
+
strict_1.default.match(posture.remediation, /never provisioned/);
|
|
62
|
+
const refusal = refusalOf(install(installation, GRANTED_BIOME, IN_FORCE));
|
|
63
|
+
strict_1.default.equal(refusal.kind, installation_license_ts_1.LicenseRefusalKind.Unverifiable);
|
|
64
|
+
strict_1.default.equal((0, installation_license_ts_1.isUnprovisionedBuildRefusal)(refusal), true);
|
|
65
|
+
});
|
|
66
|
+
(0, node_test_1.test)('an unprovisioned build refuses even a CUSTOMER license — the build is the defect', async () => {
|
|
67
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
68
|
+
customerLicense: await (0, license_testkit_ts_1.mint)(authority),
|
|
69
|
+
distributionId: DISTRIBUTION_ID,
|
|
70
|
+
});
|
|
71
|
+
const refusal = refusalOf(install(installation, GRANTED_BIOME, IN_FORCE));
|
|
72
|
+
strict_1.default.equal(refusal.kind, installation_license_ts_1.LicenseRefusalKind.Unverifiable);
|
|
73
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.Unverifiable);
|
|
74
|
+
strict_1.default.equal(refusal.code, license_verifier_1.LicenseVerificationFailureCode.TrustStoreEmpty);
|
|
75
|
+
});
|
|
76
|
+
(0, node_test_1.test)('a license signed by an UNTRUSTED authority is refused', async () => {
|
|
77
|
+
const other = (0, license_testkit_ts_1.createTestAuthority)();
|
|
78
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
79
|
+
customerLicense: await (0, license_testkit_ts_1.mint)(other),
|
|
80
|
+
distributionId: DISTRIBUTION_ID,
|
|
81
|
+
trustStore: authority.trustStore,
|
|
82
|
+
});
|
|
83
|
+
const refusal = refusalOf(install(installation, GRANTED_BIOME, IN_FORCE));
|
|
84
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.Unverifiable);
|
|
85
|
+
strict_1.default.equal(refusal.code, license_verifier_1.LicenseVerificationFailureCode.UnknownKeyId);
|
|
86
|
+
strict_1.default.equal((0, installation_license_ts_1.isUnprovisionedBuildRefusal)(refusal), false);
|
|
87
|
+
});
|
|
88
|
+
(0, node_test_1.test)('a license in force grants its biome, its distribution and its edition', async () => {
|
|
89
|
+
const installation = await installationFor();
|
|
90
|
+
const outcome = install(installation, GRANTED_BIOME, IN_FORCE);
|
|
91
|
+
strict_1.default.equal(outcome.granted, true);
|
|
92
|
+
strict_1.default.ok(outcome.granted);
|
|
93
|
+
strict_1.default.deepEqual(outcome.matched, {
|
|
94
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
95
|
+
id: GRANTED_BIOME,
|
|
96
|
+
});
|
|
97
|
+
strict_1.default.equal(installation.distributionEntitled({ now: IN_FORCE }), true);
|
|
98
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
99
|
+
strict_1.default.ok(posture.licensed);
|
|
100
|
+
strict_1.default.equal(posture.source, license_verifier_1.LicenseSource.Customer);
|
|
101
|
+
strict_1.default.equal(posture.customerId, 'acme');
|
|
102
|
+
strict_1.default.equal(posture.state.status, license_verifier_1.LicenseStatus.Active);
|
|
103
|
+
strict_1.default.equal(posture.state.stage, license_verifier_1.LicenseLifecycleStage.Valid);
|
|
104
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Enterprise);
|
|
105
|
+
strict_1.default.equal(posture.entitlement.features[entitlement_1.EntitlementKey.SsoOidcFederation], true);
|
|
106
|
+
strict_1.default.equal(posture.entitlement.features[entitlement_1.EntitlementKey.TeamsScim], undefined);
|
|
107
|
+
strict_1.default.deepEqual(posture.warnings, []);
|
|
108
|
+
strict_1.default.equal((0, installation_license_ts_1.worstWarningSeverity)(posture.warnings), undefined);
|
|
109
|
+
});
|
|
110
|
+
(0, node_test_1.test)('a license WITHOUT the enterprise-edition class is Community, whatever else it grants', async () => {
|
|
111
|
+
const installation = await installationFor({
|
|
112
|
+
entitlements: [
|
|
113
|
+
{ kind: license_verifier_1.EntitlementKind.Distribution, id: DISTRIBUTION_ID },
|
|
114
|
+
{ kind: license_verifier_1.EntitlementKind.Biome, id: GRANTED_BIOME },
|
|
115
|
+
{ kind: license_verifier_1.EntitlementKind.CapabilityClass, id: 'sso.oidc-federation' },
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
119
|
+
strict_1.default.ok(posture.licensed);
|
|
120
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Community);
|
|
121
|
+
strict_1.default.deepEqual(posture.entitlement.features, {});
|
|
122
|
+
strict_1.default.equal(install(installation, GRANTED_BIOME, IN_FORCE).granted, true);
|
|
123
|
+
});
|
|
124
|
+
(0, node_test_1.test)('a capability-class WILDCARD grants the edition and every feature key', async () => {
|
|
125
|
+
const installation = await installationFor({
|
|
126
|
+
entitlements: [
|
|
127
|
+
{ kind: license_verifier_1.EntitlementKind.Distribution, id: DISTRIBUTION_ID },
|
|
128
|
+
{ kind: license_verifier_1.EntitlementKind.CapabilityClass, id: '*' },
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
132
|
+
strict_1.default.ok(posture.licensed);
|
|
133
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Enterprise);
|
|
134
|
+
for (const key of Object.values(entitlement_1.EntitlementKey)) {
|
|
135
|
+
strict_1.default.equal(posture.entitlement.features[key], true, `expected ${key}`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
(0, node_test_1.test)('a biome the license does not name is refused with a NAMED reason', async () => {
|
|
139
|
+
const installation = await installationFor();
|
|
140
|
+
const refusal = refusalOf(install(installation, UNGRANTED_BIOME, IN_FORCE));
|
|
141
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
142
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.NoMatchingEntitlement);
|
|
143
|
+
strict_1.default.equal(refusal.state.status, license_verifier_1.LicenseStatus.Active);
|
|
144
|
+
const exception = new license_refused_exception_ts_1.LicenseRefusedException(refusal, {
|
|
145
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
146
|
+
id: UNGRANTED_BIOME,
|
|
147
|
+
action: license_verifier_1.EntitlementAction.Install,
|
|
148
|
+
});
|
|
149
|
+
const body = exception.getResponse();
|
|
150
|
+
strict_1.default.equal(exception.getStatus(), 403);
|
|
151
|
+
strict_1.default.equal(body['code'], license_refused_exception_ts_1.LicenseEnforcementErrorCode.LicenseNotEntitled);
|
|
152
|
+
strict_1.default.match(String(body['message']), new RegExp(UNGRANTED_BIOME));
|
|
153
|
+
strict_1.default.deepEqual(body['resource'], {
|
|
154
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
155
|
+
id: UNGRANTED_BIOME,
|
|
156
|
+
action: license_verifier_1.EntitlementAction.Install,
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
(0, node_test_1.test)('a wildcard biome grant covers a biome the license never names individually', async () => {
|
|
160
|
+
const installation = await installationFor({
|
|
161
|
+
entitlements: [
|
|
162
|
+
{ kind: license_verifier_1.EntitlementKind.Distribution, id: DISTRIBUTION_ID },
|
|
163
|
+
{ kind: license_verifier_1.EntitlementKind.Biome, id: '*' },
|
|
164
|
+
],
|
|
165
|
+
});
|
|
166
|
+
strict_1.default.equal(install(installation, UNGRANTED_BIOME, IN_FORCE).granted, true);
|
|
167
|
+
});
|
|
168
|
+
(0, node_test_1.test)('a grant never leaks across KINDS', async () => {
|
|
169
|
+
const installation = await installationFor({
|
|
170
|
+
entitlements: [{ kind: license_verifier_1.EntitlementKind.Biome, id: '*' }],
|
|
171
|
+
});
|
|
172
|
+
strict_1.default.equal(installation.distributionEntitled({ now: IN_FORCE }), false);
|
|
173
|
+
});
|
|
174
|
+
(0, node_test_1.test)('EXPIRED-IN-GRACE stays FULLY functional and warns', async () => {
|
|
175
|
+
const installation = await installationFor();
|
|
176
|
+
strict_1.default.equal(install(installation, GRANTED_BIOME, EXPIRED_IN_GRACE).granted, true);
|
|
177
|
+
strict_1.default.equal(runExisting(installation, GRANTED_BIOME, EXPIRED_IN_GRACE).granted, true);
|
|
178
|
+
const posture = installation.posture({ now: EXPIRED_IN_GRACE });
|
|
179
|
+
strict_1.default.ok(posture.licensed);
|
|
180
|
+
strict_1.default.equal(posture.state.status, license_verifier_1.LicenseStatus.Expired);
|
|
181
|
+
strict_1.default.equal(posture.state.stage, license_verifier_1.LicenseLifecycleStage.Grace);
|
|
182
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Enterprise);
|
|
183
|
+
strict_1.default.deepEqual(posture.warnings.map((w) => w.code), [license_warnings_ts_1.LicenseWarningCode.InGracePeriod]);
|
|
184
|
+
});
|
|
185
|
+
(0, node_test_1.test)('grace warnings ESCALATE as the window closes', async () => {
|
|
186
|
+
const installation = await installationFor();
|
|
187
|
+
const graceEnd = (0, license_testkit_ts_1.at)('2027-02-01T00:00:00.000Z') + license_verifier_1.LICENSE_GRACE_PERIOD_MS;
|
|
188
|
+
const early = installation.posture({ now: EXPIRED_IN_GRACE }).warnings;
|
|
189
|
+
const late = installation.posture({
|
|
190
|
+
now: graceEnd - 2 * 24 * 60 * 60 * 1000,
|
|
191
|
+
}).warnings;
|
|
192
|
+
strict_1.default.equal(early[0]?.severity, license_warnings_ts_1.LicenseWarningSeverity.Warning);
|
|
193
|
+
strict_1.default.equal(late[0]?.severity, license_warnings_ts_1.LicenseWarningSeverity.Critical);
|
|
194
|
+
strict_1.default.equal((0, installation_license_ts_1.worstWarningSeverity)(late), license_warnings_ts_1.LicenseWarningSeverity.Critical);
|
|
195
|
+
});
|
|
196
|
+
(0, node_test_1.test)('EXPIRED-RESTRICTED refuses new installs, keeps existing workloads running', async () => {
|
|
197
|
+
const installation = await installationFor();
|
|
198
|
+
const refusal = refusalOf(install(installation, GRANTED_BIOME, EXPIRED_RESTRICTED));
|
|
199
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
200
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.LicenseRestricted);
|
|
201
|
+
strict_1.default.equal(runExisting(installation, GRANTED_BIOME, EXPIRED_RESTRICTED).granted, true);
|
|
202
|
+
strict_1.default.equal(installation.distributionEntitled({ now: EXPIRED_RESTRICTED }), true);
|
|
203
|
+
const posture = installation.posture({ now: EXPIRED_RESTRICTED });
|
|
204
|
+
strict_1.default.ok(posture.licensed);
|
|
205
|
+
strict_1.default.equal(posture.state.stage, license_verifier_1.LicenseLifecycleStage.Restricted);
|
|
206
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Enterprise);
|
|
207
|
+
strict_1.default.deepEqual(posture.warnings.map((w) => w.code), [license_warnings_ts_1.LicenseWarningCode.Restricted]);
|
|
208
|
+
strict_1.default.match((0, license_refused_exception_ts_1.describeRefusal)(refusal, {
|
|
209
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
210
|
+
id: GRANTED_BIOME,
|
|
211
|
+
action: license_verifier_1.EntitlementAction.Install,
|
|
212
|
+
}), /Existing workloads keep running/);
|
|
213
|
+
});
|
|
214
|
+
(0, node_test_1.test)('UPGRADE is refused exactly where a new install is', async () => {
|
|
215
|
+
const installation = await installationFor();
|
|
216
|
+
const upgrade = (now) => installation.evaluate({
|
|
217
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
218
|
+
id: GRANTED_BIOME,
|
|
219
|
+
action: license_verifier_1.EntitlementAction.Upgrade,
|
|
220
|
+
}, { now });
|
|
221
|
+
strict_1.default.equal(upgrade(EXPIRED_IN_GRACE).granted, true);
|
|
222
|
+
strict_1.default.equal(upgrade(EXPIRED_RESTRICTED).granted, false);
|
|
223
|
+
});
|
|
224
|
+
(0, node_test_1.test)('REVOKED denies everything, including running what is already installed', async () => {
|
|
225
|
+
const installation = await installationFor({
|
|
226
|
+
status: license_verifier_1.LicenseStatus.Revoked,
|
|
227
|
+
});
|
|
228
|
+
for (const outcome of [
|
|
229
|
+
install(installation, GRANTED_BIOME, IN_FORCE),
|
|
230
|
+
runExisting(installation, GRANTED_BIOME, IN_FORCE),
|
|
231
|
+
]) {
|
|
232
|
+
const refusal = refusalOf(outcome);
|
|
233
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
234
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.LicenseRevoked);
|
|
235
|
+
}
|
|
236
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
237
|
+
strict_1.default.ok(posture.licensed);
|
|
238
|
+
strict_1.default.equal(posture.entitlement.edition, entitlement_1.Edition.Community);
|
|
239
|
+
strict_1.default.equal(posture.distributionEntitled, false);
|
|
240
|
+
strict_1.default.deepEqual(posture.warnings.map((w) => w.code), [
|
|
241
|
+
license_warnings_ts_1.LicenseWarningCode.Revoked,
|
|
242
|
+
license_warnings_ts_1.LicenseWarningCode.DistributionNotEntitled,
|
|
243
|
+
]);
|
|
244
|
+
});
|
|
245
|
+
(0, node_test_1.test)('SUSPENDED refuses new work but never stops running work', async () => {
|
|
246
|
+
const installation = await installationFor({
|
|
247
|
+
status: license_verifier_1.LicenseStatus.Suspended,
|
|
248
|
+
});
|
|
249
|
+
const refusal = refusalOf(install(installation, GRANTED_BIOME, IN_FORCE));
|
|
250
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
251
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.LicenseSuspended);
|
|
252
|
+
strict_1.default.equal(runExisting(installation, GRANTED_BIOME, IN_FORCE).granted, true);
|
|
253
|
+
strict_1.default.equal(installation.posture({ now: IN_FORCE }).warnings[0]?.code, license_warnings_ts_1.LicenseWarningCode.Suspended);
|
|
254
|
+
});
|
|
255
|
+
(0, node_test_1.test)('a license dated in the FUTURE is not yet in force', async () => {
|
|
256
|
+
const installation = await installationFor();
|
|
257
|
+
const beforeIssue = (0, license_testkit_ts_1.at)('2025-12-01T00:00:00.000Z');
|
|
258
|
+
const refusal = refusalOf(runExisting(installation, GRANTED_BIOME, beforeIssue));
|
|
259
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
260
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.LicenseNotYetValid);
|
|
261
|
+
strict_1.default.deepEqual(installation.posture({ now: beforeIssue }).warnings.map((w) => w.code), [
|
|
262
|
+
license_warnings_ts_1.LicenseWarningCode.NotYetValid,
|
|
263
|
+
license_warnings_ts_1.LicenseWarningCode.DistributionNotEntitled,
|
|
264
|
+
]);
|
|
265
|
+
});
|
|
266
|
+
(0, node_test_1.test)('expiry is announced BEFORE it happens', async () => {
|
|
267
|
+
const installation = await installationFor();
|
|
268
|
+
const tenDaysOut = (0, license_testkit_ts_1.at)('2027-01-22T00:00:00.000Z');
|
|
269
|
+
const posture = installation.posture({ now: tenDaysOut });
|
|
270
|
+
strict_1.default.ok(posture.licensed);
|
|
271
|
+
strict_1.default.equal(posture.state.stage, license_verifier_1.LicenseLifecycleStage.Valid);
|
|
272
|
+
strict_1.default.deepEqual(posture.warnings.map((w) => w.code), [license_warnings_ts_1.LicenseWarningCode.ExpiringSoon]);
|
|
273
|
+
strict_1.default.equal(install(installation, GRANTED_BIOME, tenDaysOut).granted, true);
|
|
274
|
+
});
|
|
275
|
+
(0, node_test_1.test)('a perpetual license never warns about expiry', async () => {
|
|
276
|
+
const installation = await installationFor({ expiresAt: null });
|
|
277
|
+
const farFuture = (0, license_testkit_ts_1.at)('2099-01-01T00:00:00.000Z');
|
|
278
|
+
strict_1.default.deepEqual(installation.posture({ now: farFuture }).warnings, []);
|
|
279
|
+
strict_1.default.equal(install(installation, GRANTED_BIOME, farFuture).granted, true);
|
|
280
|
+
});
|
|
281
|
+
(0, node_test_1.test)('a license for ANOTHER distribution does not entitle running this one', async () => {
|
|
282
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
283
|
+
customerLicense: await (0, license_testkit_ts_1.mint)(authority, {
|
|
284
|
+
entitlements: [{ kind: license_verifier_1.EntitlementKind.Distribution, id: 'appliance-base' }],
|
|
285
|
+
}),
|
|
286
|
+
distributionId: DISTRIBUTION_ID,
|
|
287
|
+
trustStore: authority.trustStore,
|
|
288
|
+
});
|
|
289
|
+
strict_1.default.equal(installation.distributionEntitled({ now: IN_FORCE }), false);
|
|
290
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
291
|
+
strict_1.default.ok(posture.licensed);
|
|
292
|
+
strict_1.default.equal(posture.distributionEntitled, false);
|
|
293
|
+
strict_1.default.ok(posture.warnings.some((w) => w.code === license_warnings_ts_1.LicenseWarningCode.DistributionNotEntitled));
|
|
294
|
+
strict_1.default.match(posture.warnings.at(-1)?.message ?? '', /Mirroring the images does not confer the right to run them/);
|
|
295
|
+
});
|
|
296
|
+
(0, node_test_1.test)('the install gate is a CONJUNCTION — an unentitled edition blocks an entitled biome', async () => {
|
|
297
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
298
|
+
customerLicense: await (0, license_testkit_ts_1.mint)(authority, {
|
|
299
|
+
entitlements: [
|
|
300
|
+
{ kind: license_verifier_1.EntitlementKind.Biome, id: '*' },
|
|
301
|
+
{ kind: license_verifier_1.EntitlementKind.Distribution, id: 'appliance-base' },
|
|
302
|
+
],
|
|
303
|
+
}),
|
|
304
|
+
distributionId: DISTRIBUTION_ID,
|
|
305
|
+
trustStore: authority.trustStore,
|
|
306
|
+
});
|
|
307
|
+
strict_1.default.equal(install(installation, GRANTED_BIOME, IN_FORCE).granted, true);
|
|
308
|
+
const refusal = refusalOf(installation.biomeInstallGate(GRANTED_BIOME, { now: IN_FORCE }));
|
|
309
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
310
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.NoMatchingEntitlement);
|
|
311
|
+
});
|
|
312
|
+
(0, node_test_1.test)('the install gate passes when BOTH the edition and the biome are entitled', async () => {
|
|
313
|
+
const installation = await installationFor();
|
|
314
|
+
strict_1.default.equal(installation.biomeInstallGate(GRANTED_BIOME, { now: IN_FORCE }).granted, true);
|
|
315
|
+
strict_1.default.equal(installation.biomeInstallGate(UNGRANTED_BIOME, { now: IN_FORCE }).granted, false);
|
|
316
|
+
});
|
|
317
|
+
(0, node_test_1.test)('an UNDECLARED distribution refuses installs and says how to fix the DEPLOYMENT', async () => {
|
|
318
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
319
|
+
customerLicense: await (0, license_testkit_ts_1.mint)(authority),
|
|
320
|
+
distributionId: null,
|
|
321
|
+
trustStore: authority.trustStore,
|
|
322
|
+
});
|
|
323
|
+
strict_1.default.equal(installation.distributionEntitled({ now: IN_FORCE }), false);
|
|
324
|
+
const refusal = refusalOf(installation.biomeInstallGate(GRANTED_BIOME, { now: IN_FORCE }));
|
|
325
|
+
strict_1.default.equal(refusal.kind, installation_license_ts_1.LicenseRefusalKind.DistributionUndeclared);
|
|
326
|
+
const body = new license_refused_exception_ts_1.LicenseRefusedException(refusal).getResponse();
|
|
327
|
+
strict_1.default.equal(body['code'], license_refused_exception_ts_1.LicenseEnforcementErrorCode.DistributionUndeclared);
|
|
328
|
+
strict_1.default.match(String(body['remediation']), /XEMA_DISTRIBUTION_LOCK_PATH/);
|
|
329
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
330
|
+
strict_1.default.ok(posture.licensed);
|
|
331
|
+
strict_1.default.deepEqual(posture.warnings.map((w) => w.code), [license_warnings_ts_1.LicenseWarningCode.DistributionUndeclared]);
|
|
332
|
+
});
|
|
333
|
+
(0, node_test_1.test)('a clock rollback is REPORTED and changes no decision', async () => {
|
|
334
|
+
const installation = await installationFor();
|
|
335
|
+
installation.posture({ now: IN_FORCE + 10_000 });
|
|
336
|
+
const posture = installation.posture({ now: IN_FORCE });
|
|
337
|
+
strict_1.default.ok(posture.licensed);
|
|
338
|
+
strict_1.default.equal(posture.state.clockRollbackDetected, true);
|
|
339
|
+
strict_1.default.ok(posture.warnings.some((w) => w.code === license_warnings_ts_1.LicenseWarningCode.ClockRollback));
|
|
340
|
+
strict_1.default.equal(install(installation, GRANTED_BIOME, IN_FORCE).granted, true);
|
|
341
|
+
});
|
|
342
|
+
(0, node_test_1.test)('a malformed resource id is refused rather than matched', async () => {
|
|
343
|
+
const installation = await installationFor();
|
|
344
|
+
const refusal = refusalOf(install(installation, 'not a valid id!', IN_FORCE));
|
|
345
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
346
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.MalformedQuery);
|
|
347
|
+
});
|
|
348
|
+
(0, node_test_1.test)('a wildcard cannot be QUERIED as if it were a resource', async () => {
|
|
349
|
+
const installation = await installationFor({
|
|
350
|
+
entitlements: [{ kind: license_verifier_1.EntitlementKind.Biome, id: '*' }],
|
|
351
|
+
});
|
|
352
|
+
const refusal = refusalOf(install(installation, '*', IN_FORCE));
|
|
353
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.NotEntitled);
|
|
354
|
+
strict_1.default.equal(refusal.reason, license_verifier_1.EntitlementDenialReason.MalformedQuery);
|
|
355
|
+
});
|
|
356
|
+
(0, node_test_1.test)('projectEntitlementSet grants NOTHING without the enterprise-edition class', () => {
|
|
357
|
+
const set = (0, entitlement_1.projectEntitlementSet)((id) => id !== entitlement_1.ENTERPRISE_EDITION_CAPABILITY_CLASS);
|
|
358
|
+
strict_1.default.equal(set.edition, entitlement_1.Edition.Community);
|
|
359
|
+
strict_1.default.deepEqual(set.features, {});
|
|
360
|
+
});
|
|
361
|
+
(0, node_test_1.test)('projectEntitlementSet honours only the classes the probe grants', () => {
|
|
362
|
+
const granted = new Set([
|
|
363
|
+
entitlement_1.ENTERPRISE_EDITION_CAPABILITY_CLASS,
|
|
364
|
+
entitlement_1.EntitlementKey.RolesCustom,
|
|
365
|
+
]);
|
|
366
|
+
const set = (0, entitlement_1.projectEntitlementSet)((id) => granted.has(id));
|
|
367
|
+
strict_1.default.equal(set.edition, entitlement_1.Edition.Enterprise);
|
|
368
|
+
strict_1.default.deepEqual(set.features, { [entitlement_1.EntitlementKey.RolesCustom]: true });
|
|
369
|
+
});
|
|
370
|
+
(0, node_test_1.test)('an unverifiable refusal renders a remediation, not an opaque failure', async () => {
|
|
371
|
+
const installation = new installation_license_ts_1.InstallationLicense({
|
|
372
|
+
customerLicense: 'not-a-license',
|
|
373
|
+
distributionId: DISTRIBUTION_ID,
|
|
374
|
+
trustStore: authority.trustStore,
|
|
375
|
+
});
|
|
376
|
+
const refusal = refusalOf(install(installation, GRANTED_BIOME, IN_FORCE));
|
|
377
|
+
strict_1.default.ok(refusal.kind === installation_license_ts_1.LicenseRefusalKind.Unverifiable);
|
|
378
|
+
strict_1.default.equal(refusal.code, license_verifier_1.LicenseVerificationFailureCode.MalformedToken);
|
|
379
|
+
const exception = new license_refused_exception_ts_1.LicenseRefusedException(refusal, {
|
|
380
|
+
kind: license_verifier_1.EntitlementKind.Biome,
|
|
381
|
+
id: GRANTED_BIOME,
|
|
382
|
+
action: license_verifier_1.EntitlementAction.Install,
|
|
383
|
+
});
|
|
384
|
+
const body = exception.getResponse();
|
|
385
|
+
strict_1.default.equal(body['code'], license_refused_exception_ts_1.LicenseEnforcementErrorCode.LicenseUnverifiable);
|
|
386
|
+
strict_1.default.equal(body['verificationFailure'], license_verifier_1.LicenseVerificationFailureCode.MalformedToken);
|
|
387
|
+
strict_1.default.match(String(body['remediation']), /XEMA_LICENSE/);
|
|
388
|
+
});
|
|
389
|
+
//# sourceMappingURL=installation-license.test.js.map
|