Skip to content

Commit b8a7a64

Browse files
committed
Create FOSS license package during fossify
1 parent ab0c183 commit b8a7a64

3 files changed

Lines changed: 241 additions & 96 deletions

File tree

.github/workflows/devsh-foss-image.yml

Lines changed: 0 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -190,101 +190,6 @@ jobs:
190190
find /tmp/dist/bundle/programs/web.browser -type f -name "*.map" -delete || true
191191
du -sh /tmp/dist/bundle
192192
193-
- name: Install FOSS runtime license stub
194-
run: |
195-
set -euo pipefail
196-
for license_dir in \
197-
/tmp/dist/bundle/node_modules/@rocket.chat/license \
198-
/tmp/dist/bundle/programs/server/npm/node_modules/@rocket.chat/license
199-
do
200-
mkdir -p "${license_dir}/src/validation"
201-
cat > "${license_dir}/package.json" <<'JSON'
202-
{
203-
"name": "@rocket.chat/license",
204-
"version": "0.0.0-devsh-foss",
205-
"main": "index.js"
206-
}
207-
JSON
208-
cat > "${license_dir}/index.js" <<'JS'
209-
class DuplicatedLicenseError extends Error {
210-
constructor(message = 'Duplicated license') {
211-
super(message);
212-
this.name = 'DuplicatedLicense';
213-
}
214-
}
215-
216-
const noop = () => undefined;
217-
const noopAsync = async () => undefined;
218-
const falseSync = () => false;
219-
const falseAsync = async () => false;
220-
const emptyArray = () => [];
221-
222-
const License = {
223-
encryptedLicense: undefined,
224-
validateFormat: () => true,
225-
hasModule: falseSync,
226-
getModules: emptyArray,
227-
getExternalModules: emptyArray,
228-
getModuleDefinition: () => undefined,
229-
getTags: emptyArray,
230-
hasValidLicense: falseSync,
231-
getLicense: noopAsync,
232-
getGuestPermissions: noopAsync,
233-
shouldPreventAction: falseAsync,
234-
isLimitReached: falseAsync,
235-
onValidFeature: noop,
236-
onInvalidFeature: noop,
237-
onToggledFeature: noop,
238-
onModule: noop,
239-
onValidateLicense: noop,
240-
onInvalidateLicense: noop,
241-
onLimitReached: noop,
242-
onBehaviorTriggered: noop,
243-
onLicense: noop,
244-
getMaxActiveUsers: () => 0,
245-
getAppsConfig: () => ({}),
246-
getUnmodifiedLicenseAndModules: noop,
247-
overwriteClassOnLicense: (value) => value,
248-
setLicenseLimitCounter: noop,
249-
getCurrentValueForLicenseLimit: async () => 0,
250-
remove: noop,
251-
setLicense: falseAsync,
252-
revalidateLicense: noopAsync,
253-
sync: noopAsync
254-
};
255-
256-
const AirGappedRestriction = {
257-
restricted: false,
258-
computeRestriction: noopAsync,
259-
isWarningPeriod: falseSync,
260-
on: noop,
261-
off: noop
262-
};
263-
264-
const applyLicense = falseAsync;
265-
const applyLicenseOrRemove = falseAsync;
266-
267-
class LicenseManager {}
268-
class MockedLicenseBuilder {}
269-
270-
module.exports = {
271-
AirGappedRestriction,
272-
DuplicatedLicenseError,
273-
License,
274-
LicenseManager,
275-
MockedLicenseBuilder,
276-
applyLicense,
277-
applyLicenseOrRemove
278-
};
279-
JS
280-
cat > "${license_dir}/src/validation/validateLimit.js" <<'JS'
281-
module.exports = {
282-
validateLimit: () => false,
283-
validateWarnLimit: () => false
284-
};
285-
JS
286-
done
287-
288193
- name: Store Meteor bundle cache artifact
289194
if: steps.cache-bundle.outputs.cache-hit != 'true'
290195
run: |

DEVSH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The `DevSH FOSS image` workflow builds a fully self-hosted FOSS Rocket.Chat imag
1818
3. Build shared packages.
1919
4. Run `yarn fossify`, which removes Enterprise and commercial source directories.
2020
5. Build the Meteor production bundle.
21-
6. Add the DevSH FOSS runtime stub for the license package expected by shared Community code paths.
21+
6. Keep a DevSH FOSS compatibility license package for shared Community code paths that import `@rocket.chat/license`.
2222
7. Build the Docker image.
2323
8. Publish immutable semver-compatible tags to `ghcr.io/devsh-graphics-programming/rocketchat-foss`.
2424

scripts/fossify.ts

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,250 @@ const rl = readline.createInterface({
88
output: process.stdout,
99
});
1010

11+
const licenseIndexTs = `export class DuplicatedLicenseError extends Error {
12+
\tconstructor(message = 'Duplicated license') {
13+
\t\tsuper(message);
14+
\t\tthis.name = 'DuplicatedLicense';
15+
\t}
16+
}
17+
18+
const noop = (..._args: unknown[]): undefined => undefined;
19+
const noopAsync = async (..._args: unknown[]): Promise<undefined> => undefined;
20+
const falseSync = (..._args: unknown[]): boolean => false;
21+
const falseAsync = async (..._args: unknown[]): Promise<boolean> => false;
22+
const emptyArray = (..._args: unknown[]): [] => [];
23+
24+
export const License = {
25+
\tencryptedLicense: undefined,
26+
\tvalidateFormat: (): boolean => true,
27+
\thasModule: falseSync,
28+
\tgetModules: emptyArray,
29+
\tgetExternalModules: emptyArray,
30+
\tgetModuleDefinition: noop,
31+
\tgetTags: emptyArray,
32+
\thasValidLicense: falseSync,
33+
\tgetLicense: noopAsync,
34+
\tgetGuestPermissions: noopAsync,
35+
\tshouldPreventAction: falseAsync,
36+
\tisLimitReached: falseAsync,
37+
\tonValidFeature: noop,
38+
\tonInvalidFeature: noop,
39+
\tonToggledFeature: noop,
40+
\tonModule: noop,
41+
\tonValidateLicense: noop,
42+
\tonInvalidateLicense: noop,
43+
\tonLimitReached: noop,
44+
\tonBehaviorTriggered: noop,
45+
\tonLicense: noop,
46+
\tgetMaxActiveUsers: (): number => 0,
47+
\tgetAppsConfig: (..._args: unknown[]) => ({}),
48+
\tgetUnmodifiedLicenseAndModules: noop,
49+
\toverwriteClassOnLicense: <T>(value: T): T => value,
50+
\tsetLicenseLimitCounter: noop,
51+
\tgetCurrentValueForLicenseLimit: async (..._args: unknown[]): Promise<number> => 0,
52+
\tremove: noop,
53+
\tsetLicense: falseAsync,
54+
\trevalidateLicense: noopAsync,
55+
\tsync: noopAsync,
56+
};
57+
58+
export type LicenseImp = typeof License;
59+
60+
export const AirGappedRestriction = {
61+
\trestricted: false,
62+
\tcomputeRestriction: noopAsync,
63+
\tisWarningPeriod: falseSync,
64+
\ton: noop,
65+
\toff: noop,
66+
};
67+
68+
export const applyLicense = falseAsync;
69+
export const applyLicenseOrRemove = falseAsync;
70+
71+
export class LicenseManager {}
72+
export class MockedLicenseBuilder {}
73+
`;
74+
75+
const licenseIndexJs = `class DuplicatedLicenseError extends Error {
76+
constructor(message = 'Duplicated license') {
77+
super(message);
78+
this.name = 'DuplicatedLicense';
79+
}
80+
}
81+
82+
const noop = (..._args) => undefined;
83+
const noopAsync = async (..._args) => undefined;
84+
const falseSync = (..._args) => false;
85+
const falseAsync = async (..._args) => false;
86+
const emptyArray = (..._args) => [];
87+
88+
const License = {
89+
encryptedLicense: undefined,
90+
validateFormat: () => true,
91+
hasModule: falseSync,
92+
getModules: emptyArray,
93+
getExternalModules: emptyArray,
94+
getModuleDefinition: noop,
95+
getTags: emptyArray,
96+
hasValidLicense: falseSync,
97+
getLicense: noopAsync,
98+
getGuestPermissions: noopAsync,
99+
shouldPreventAction: falseAsync,
100+
isLimitReached: falseAsync,
101+
onValidFeature: noop,
102+
onInvalidFeature: noop,
103+
onToggledFeature: noop,
104+
onModule: noop,
105+
onValidateLicense: noop,
106+
onInvalidateLicense: noop,
107+
onLimitReached: noop,
108+
onBehaviorTriggered: noop,
109+
onLicense: noop,
110+
getMaxActiveUsers: () => 0,
111+
getAppsConfig: (..._args) => ({}),
112+
getUnmodifiedLicenseAndModules: noop,
113+
overwriteClassOnLicense: (value) => value,
114+
setLicenseLimitCounter: noop,
115+
getCurrentValueForLicenseLimit: async (..._args) => 0,
116+
remove: noop,
117+
setLicense: falseAsync,
118+
revalidateLicense: noopAsync,
119+
sync: noopAsync,
120+
};
121+
122+
const AirGappedRestriction = {
123+
restricted: false,
124+
computeRestriction: noopAsync,
125+
isWarningPeriod: falseSync,
126+
on: noop,
127+
off: noop,
128+
};
129+
130+
const applyLicense = falseAsync;
131+
const applyLicenseOrRemove = falseAsync;
132+
133+
class LicenseManager {}
134+
class MockedLicenseBuilder {}
135+
136+
module.exports = {
137+
AirGappedRestriction,
138+
DuplicatedLicenseError,
139+
License,
140+
LicenseManager,
141+
MockedLicenseBuilder,
142+
applyLicense,
143+
applyLicenseOrRemove,
144+
};
145+
`;
146+
147+
const licenseIndexDts = `export declare class DuplicatedLicenseError extends Error {
148+
\tconstructor(message?: string);
149+
}
150+
151+
export declare const License: {
152+
\tencryptedLicense: undefined;
153+
\tvalidateFormat: (...args: any[]) => boolean;
154+
\thasModule: (...args: any[]) => boolean;
155+
\tgetModules: (...args: any[]) => [];
156+
\tgetExternalModules: (...args: any[]) => [];
157+
\tgetModuleDefinition: (...args: any[]) => undefined;
158+
\tgetTags: (...args: any[]) => [];
159+
\thasValidLicense: (...args: any[]) => boolean;
160+
\tgetLicense: (...args: any[]) => Promise<undefined>;
161+
\tgetGuestPermissions: (...args: any[]) => Promise<undefined>;
162+
\tshouldPreventAction: (...args: any[]) => Promise<boolean>;
163+
\tisLimitReached: (...args: any[]) => Promise<boolean>;
164+
\tonValidFeature: (...args: any[]) => undefined;
165+
\tonInvalidFeature: (...args: any[]) => undefined;
166+
\tonToggledFeature: (...args: any[]) => undefined;
167+
\tonModule: (...args: any[]) => undefined;
168+
\tonValidateLicense: (...args: any[]) => undefined;
169+
\tonInvalidateLicense: (...args: any[]) => undefined;
170+
\tonLimitReached: (...args: any[]) => undefined;
171+
\tonBehaviorTriggered: (...args: any[]) => undefined;
172+
\tonLicense: (...args: any[]) => undefined;
173+
\tgetMaxActiveUsers: (...args: any[]) => number;
174+
\tgetAppsConfig: (...args: any[]) => Record<string, never>;
175+
\tgetUnmodifiedLicenseAndModules: (...args: any[]) => undefined;
176+
\toverwriteClassOnLicense: <T>(value: T) => T;
177+
\tsetLicenseLimitCounter: (...args: any[]) => undefined;
178+
\tgetCurrentValueForLicenseLimit: (...args: any[]) => Promise<number>;
179+
\tremove: (...args: any[]) => undefined;
180+
\tsetLicense: (...args: any[]) => Promise<boolean>;
181+
\trevalidateLicense: (...args: any[]) => Promise<undefined>;
182+
\tsync: (...args: any[]) => Promise<undefined>;
183+
};
184+
185+
export type LicenseImp = typeof License;
186+
187+
export declare const AirGappedRestriction: {
188+
\trestricted: boolean;
189+
\tcomputeRestriction: (...args: any[]) => Promise<undefined>;
190+
\tisWarningPeriod: (...args: any[]) => boolean;
191+
\ton: (...args: any[]) => undefined;
192+
\toff: (...args: any[]) => undefined;
193+
};
194+
195+
export declare const applyLicense: (...args: any[]) => Promise<boolean>;
196+
export declare const applyLicenseOrRemove: (...args: any[]) => Promise<boolean>;
197+
198+
export declare class LicenseManager {}
199+
export declare class MockedLicenseBuilder {}
200+
`;
201+
202+
const validateLimitTs = `export const validateLimit = (..._args: unknown[]): boolean => false;
203+
export const validateWarnLimit = (..._args: unknown[]): boolean => false;
204+
`;
205+
206+
const validateLimitJs = `module.exports = {
207+
validateLimit: (..._args) => false,
208+
validateWarnLimit: (..._args) => false,
209+
};
210+
`;
211+
212+
const validateLimitDts = `export declare const validateLimit: (...args: any[]) => boolean;
213+
export declare const validateWarnLimit: (...args: any[]) => boolean;
214+
`;
215+
216+
const writeFile = async (path: string, content: string): Promise<void> => {
217+
await fs.writeFile(path, content, 'utf8');
218+
};
219+
220+
const writeFossLicensePackage = async (): Promise<void> => {
221+
const root = './ee/packages/license';
222+
await fs.mkdir(`${root}/src/validation`, { recursive: true });
223+
await fs.mkdir(`${root}/dist/validation`, { recursive: true });
224+
225+
await writeFile(
226+
`${root}/package.json`,
227+
`${JSON.stringify(
228+
{
229+
name: '@rocket.chat/license',
230+
version: '0.0.0-devsh-foss',
231+
private: true,
232+
main: './dist/index.js',
233+
typings: './dist/index.d.ts',
234+
files: ['/dist', '/src'],
235+
},
236+
null,
237+
'\t',
238+
)}\n`,
239+
);
240+
await writeFile(`${root}/src/index.ts`, licenseIndexTs);
241+
await writeFile(`${root}/dist/index.js`, licenseIndexJs);
242+
await writeFile(`${root}/dist/index.d.ts`, licenseIndexDts);
243+
await writeFile(`${root}/src/validation/validateLimit.ts`, validateLimitTs);
244+
await writeFile(`${root}/dist/validation/validateLimit.js`, validateLimitJs);
245+
await writeFile(`${root}/dist/validation/validateLimit.d.ts`, validateLimitDts);
246+
};
247+
11248
const fossify = async () => {
12249
console.log('Removing Premium Apps and Packages...');
13250
await fs.rmdir('./ee', removeOptions);
14251

252+
console.log('Writing FOSS license compatibility package...');
253+
await writeFossLicensePackage();
254+
15255
console.log('Removing Premium code in the main app...');
16256
await fs.rmdir('./apps/meteor/ee', removeOptions);
17257

0 commit comments

Comments
 (0)