@neurosec/sentry 1.0.20 → 1.1.1

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.
Files changed (192) hide show
  1. package/README.md +4 -0
  2. package/dist/api-auth.d.ts +31 -0
  3. package/dist/api-auth.d.ts.map +1 -0
  4. package/dist/api-auth.js +105 -0
  5. package/dist/api-auth.js.map +1 -0
  6. package/dist/api-auth.test.d.ts +2 -0
  7. package/dist/api-auth.test.d.ts.map +1 -0
  8. package/dist/api-auth.test.js +89 -0
  9. package/dist/api-auth.test.js.map +1 -0
  10. package/dist/api.d.ts +8 -7
  11. package/dist/api.d.ts.map +1 -1
  12. package/dist/api.js +141 -134
  13. package/dist/api.js.map +1 -1
  14. package/dist/cli.d.ts +1 -1
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +107 -14
  17. package/dist/cli.js.map +1 -1
  18. package/dist/cli.test.d.ts +2 -0
  19. package/dist/cli.test.d.ts.map +1 -0
  20. package/dist/cli.test.js +68 -0
  21. package/dist/cli.test.js.map +1 -0
  22. package/dist/config.d.ts +30 -0
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +68 -2
  25. package/dist/config.js.map +1 -1
  26. package/dist/config.test.d.ts +2 -0
  27. package/dist/config.test.d.ts.map +1 -0
  28. package/dist/config.test.js +121 -0
  29. package/dist/config.test.js.map +1 -0
  30. package/dist/discovery-win.d.ts +4 -0
  31. package/dist/discovery-win.d.ts.map +1 -0
  32. package/dist/discovery-win.js +153 -0
  33. package/dist/discovery-win.js.map +1 -0
  34. package/dist/discovery.d.ts.map +1 -1
  35. package/dist/discovery.js +23 -97
  36. package/dist/discovery.js.map +1 -1
  37. package/dist/discovery.test.js +18 -109
  38. package/dist/discovery.test.js.map +1 -1
  39. package/dist/enforcement/file-monitor.d.ts +9 -0
  40. package/dist/enforcement/file-monitor.d.ts.map +1 -1
  41. package/dist/enforcement/file-monitor.js +9 -2
  42. package/dist/enforcement/file-monitor.js.map +1 -1
  43. package/dist/enforcement/network-monitor.d.ts.map +1 -1
  44. package/dist/enforcement/network-monitor.js +350 -9
  45. package/dist/enforcement/network-monitor.js.map +1 -1
  46. package/dist/enforcement/network-monitor.test.d.ts +2 -0
  47. package/dist/enforcement/network-monitor.test.d.ts.map +1 -0
  48. package/dist/enforcement/network-monitor.test.js +52 -0
  49. package/dist/enforcement/network-monitor.test.js.map +1 -0
  50. package/dist/enforcement/policy-executor.d.ts +24 -1
  51. package/dist/enforcement/policy-executor.d.ts.map +1 -1
  52. package/dist/enforcement/policy-executor.js +213 -69
  53. package/dist/enforcement/policy-executor.js.map +1 -1
  54. package/dist/enforcement/policy-executor.test.d.ts +2 -0
  55. package/dist/enforcement/policy-executor.test.d.ts.map +1 -0
  56. package/dist/enforcement/policy-executor.test.js +46 -0
  57. package/dist/enforcement/policy-executor.test.js.map +1 -0
  58. package/dist/enforcement/target-validator.d.ts +37 -0
  59. package/dist/enforcement/target-validator.d.ts.map +1 -0
  60. package/dist/enforcement/target-validator.js +0 -0
  61. package/dist/enforcement/target-validator.js.map +1 -0
  62. package/dist/enforcement/target-validator.test.d.ts +2 -0
  63. package/dist/enforcement/target-validator.test.d.ts.map +1 -0
  64. package/dist/enforcement/target-validator.test.js +103 -0
  65. package/dist/enforcement/target-validator.test.js.map +1 -0
  66. package/dist/http-client.d.ts +35 -0
  67. package/dist/http-client.d.ts.map +1 -0
  68. package/dist/http-client.js +179 -0
  69. package/dist/http-client.js.map +1 -0
  70. package/dist/http-client.test.d.ts +2 -0
  71. package/dist/http-client.test.d.ts.map +1 -0
  72. package/dist/http-client.test.js +175 -0
  73. package/dist/http-client.test.js.map +1 -0
  74. package/dist/index.js +190 -114
  75. package/dist/index.js.map +1 -1
  76. package/dist/launcher.d.ts +33 -0
  77. package/dist/launcher.d.ts.map +1 -0
  78. package/dist/launcher.js +425 -0
  79. package/dist/launcher.js.map +1 -0
  80. package/dist/launcher.test.d.ts +2 -0
  81. package/dist/launcher.test.d.ts.map +1 -0
  82. package/dist/launcher.test.js +109 -0
  83. package/dist/launcher.test.js.map +1 -0
  84. package/dist/proxy/cert-manager.d.ts +24 -0
  85. package/dist/proxy/cert-manager.d.ts.map +1 -0
  86. package/dist/proxy/cert-manager.js +117 -0
  87. package/dist/proxy/cert-manager.js.map +1 -0
  88. package/dist/proxy/cert-manager.test.d.ts +2 -0
  89. package/dist/proxy/cert-manager.test.d.ts.map +1 -0
  90. package/dist/proxy/cert-manager.test.js +70 -0
  91. package/dist/proxy/cert-manager.test.js.map +1 -0
  92. package/dist/proxy/index.d.ts +61 -0
  93. package/dist/proxy/index.d.ts.map +1 -0
  94. package/dist/proxy/index.js +74 -0
  95. package/dist/proxy/index.js.map +1 -0
  96. package/dist/proxy/policy-enforcer.d.ts +30 -0
  97. package/dist/proxy/policy-enforcer.d.ts.map +1 -0
  98. package/dist/proxy/policy-enforcer.js +143 -0
  99. package/dist/proxy/policy-enforcer.js.map +1 -0
  100. package/dist/proxy/proxy-server.d.ts +42 -0
  101. package/dist/proxy/proxy-server.d.ts.map +1 -0
  102. package/dist/proxy/proxy-server.js +652 -0
  103. package/dist/proxy/proxy-server.js.map +1 -0
  104. package/dist/proxy/redaction-engine.d.ts +4 -0
  105. package/dist/proxy/redaction-engine.d.ts.map +1 -0
  106. package/dist/proxy/redaction-engine.js +50 -0
  107. package/dist/proxy/redaction-engine.js.map +1 -0
  108. package/dist/proxy/response-redaction.test.d.ts +2 -0
  109. package/dist/proxy/response-redaction.test.d.ts.map +1 -0
  110. package/dist/proxy/response-redaction.test.js +125 -0
  111. package/dist/proxy/response-redaction.test.js.map +1 -0
  112. package/dist/proxy/threat-engine.d.ts +22 -0
  113. package/dist/proxy/threat-engine.d.ts.map +1 -0
  114. package/dist/proxy/threat-engine.js +291 -0
  115. package/dist/proxy/threat-engine.js.map +1 -0
  116. package/dist/proxy/threat-engine.test.d.ts +2 -0
  117. package/dist/proxy/threat-engine.test.d.ts.map +1 -0
  118. package/dist/proxy/threat-engine.test.js +27 -0
  119. package/dist/proxy/threat-engine.test.js.map +1 -0
  120. package/dist/redirect/env-injector.d.ts +72 -0
  121. package/dist/redirect/env-injector.d.ts.map +1 -0
  122. package/dist/redirect/env-injector.js +177 -0
  123. package/dist/redirect/env-injector.js.map +1 -0
  124. package/dist/redirect/env-injector.test.d.ts +2 -0
  125. package/dist/redirect/env-injector.test.d.ts.map +1 -0
  126. package/dist/redirect/env-injector.test.js +91 -0
  127. package/dist/redirect/env-injector.test.js.map +1 -0
  128. package/dist/redirect/index.d.ts +3 -0
  129. package/dist/redirect/index.d.ts.map +1 -0
  130. package/dist/redirect/index.js +8 -0
  131. package/dist/redirect/index.js.map +1 -0
  132. package/dist/redirect/platform-redirect.d.ts +42 -0
  133. package/dist/redirect/platform-redirect.d.ts.map +1 -0
  134. package/dist/redirect/platform-redirect.js +229 -0
  135. package/dist/redirect/platform-redirect.js.map +1 -0
  136. package/dist/redirect/platform-redirect.test.d.ts +2 -0
  137. package/dist/redirect/platform-redirect.test.d.ts.map +1 -0
  138. package/dist/redirect/platform-redirect.test.js +76 -0
  139. package/dist/redirect/platform-redirect.test.js.map +1 -0
  140. package/dist/sandbox/index.d.ts +23 -2
  141. package/dist/sandbox/index.d.ts.map +1 -1
  142. package/dist/sandbox/index.js +24 -7
  143. package/dist/sandbox/index.js.map +1 -1
  144. package/dist/sandbox/linux-sandbox.d.ts +13 -2
  145. package/dist/sandbox/linux-sandbox.d.ts.map +1 -1
  146. package/dist/sandbox/linux-sandbox.js +61 -27
  147. package/dist/sandbox/linux-sandbox.js.map +1 -1
  148. package/dist/sandbox/macos-sandbox.d.ts +15 -4
  149. package/dist/sandbox/macos-sandbox.d.ts.map +1 -1
  150. package/dist/sandbox/macos-sandbox.js +36 -18
  151. package/dist/sandbox/macos-sandbox.js.map +1 -1
  152. package/dist/sandbox/sandbox-result.test.d.ts +2 -0
  153. package/dist/sandbox/sandbox-result.test.d.ts.map +1 -0
  154. package/dist/sandbox/sandbox-result.test.js +87 -0
  155. package/dist/sandbox/sandbox-result.test.js.map +1 -0
  156. package/dist/sandbox/windows-sandbox.d.ts +34 -0
  157. package/dist/sandbox/windows-sandbox.d.ts.map +1 -0
  158. package/dist/sandbox/windows-sandbox.js +161 -0
  159. package/dist/sandbox/windows-sandbox.js.map +1 -0
  160. package/dist/setup.d.ts.map +1 -1
  161. package/dist/setup.js +33 -43
  162. package/dist/setup.js.map +1 -1
  163. package/dist/skill-authz/skill-evaluator.d.ts +30 -0
  164. package/dist/skill-authz/skill-evaluator.d.ts.map +1 -1
  165. package/dist/skill-authz/skill-evaluator.js +161 -30
  166. package/dist/skill-authz/skill-evaluator.js.map +1 -1
  167. package/dist/skill-authz/skill-evaluator.test.d.ts +2 -0
  168. package/dist/skill-authz/skill-evaluator.test.d.ts.map +1 -0
  169. package/dist/skill-authz/skill-evaluator.test.js +127 -0
  170. package/dist/skill-authz/skill-evaluator.test.js.map +1 -0
  171. package/dist/telemetry.d.ts +2 -8
  172. package/dist/telemetry.d.ts.map +1 -1
  173. package/dist/telemetry.js +17 -147
  174. package/dist/telemetry.js.map +1 -1
  175. package/dist/types.d.ts +48 -105
  176. package/dist/types.d.ts.map +1 -1
  177. package/dist/types.js +34 -1
  178. package/dist/types.js.map +1 -1
  179. package/package.json +7 -3
  180. package/scripts/install-sentry-windows.ps1 +217 -0
  181. package/dist/action-logger.d.ts +0 -40
  182. package/dist/action-logger.d.ts.map +0 -1
  183. package/dist/action-logger.js +0 -252
  184. package/dist/action-logger.js.map +0 -1
  185. package/dist/agent-registry.d.ts +0 -24
  186. package/dist/agent-registry.d.ts.map +0 -1
  187. package/dist/agent-registry.js +0 -176
  188. package/dist/agent-registry.js.map +0 -1
  189. package/dist/anomaly-detector.d.ts +0 -26
  190. package/dist/anomaly-detector.d.ts.map +0 -1
  191. package/dist/anomaly-detector.js +0 -299
  192. package/dist/anomaly-detector.js.map +0 -1
@@ -0,0 +1,229 @@
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
+ exports.PlatformRedirect = void 0;
7
+ const child_process_1 = require("child_process");
8
+ const os_1 = __importDefault(require("os"));
9
+ const logger_1 = require("../logger");
10
+ /**
11
+ * Platform-specific traffic redirect: divert outbound port-443 from agent
12
+ * processes to the local Sentry HTTPS proxy.
13
+ *
14
+ * Fixes vs prior implementation:
15
+ * - Linux (S-C13): no longer excludes root via `--uid-owner 0`. Many
16
+ * containerized agents run as root; excluding them silently bypassed
17
+ * enforcement. The new rule scopes by destination port + a marked
18
+ * packet match (when available) so root agents are captured but the
19
+ * Sentry daemon's own outbound calls are not (matched by setting a
20
+ * marker UID/GID when daemon socket() runs is out of scope; we instead
21
+ * skip traffic whose dest IP IS the proxy itself).
22
+ * - macOS (S-C14): previous rule used `on lo0` (loopback) which sees no
23
+ * outbound LAN traffic. New rule binds to the primary egress interface
24
+ * resolved at install time via `route -n get default`. Falls back to
25
+ * `pfctl -E` so the redirect anchor stays attached if pf is disabled.
26
+ * - All execs use execFileSync with array args — no shell interpolation.
27
+ */
28
+ class PlatformRedirect {
29
+ constructor(config) {
30
+ /** Records the exact rule arguments we installed so removeRedirect can undo them. */
31
+ this.installedRules = [];
32
+ this.config = config;
33
+ this.platform = os_1.default.platform();
34
+ }
35
+ async installRedirect() {
36
+ try {
37
+ switch (this.platform) {
38
+ case 'linux': return await this.installLinuxRedirect();
39
+ case 'darwin': return await this.installMacOSRedirect();
40
+ case 'win32': return await this.installWindowsRedirect();
41
+ default:
42
+ logger_1.logger.warn('No redirect support for platform', { platform: this.platform });
43
+ return false;
44
+ }
45
+ }
46
+ catch (err) {
47
+ logger_1.logger.error('Failed to install traffic redirect', {
48
+ platform: this.platform,
49
+ err: err.message,
50
+ });
51
+ return false;
52
+ }
53
+ }
54
+ async removeRedirect() {
55
+ try {
56
+ switch (this.platform) {
57
+ case 'linux': return await this.removeLinuxRedirect();
58
+ case 'darwin': return await this.removeMacOSRedirect();
59
+ case 'win32': return await this.removeWindowsRedirect();
60
+ default: return false;
61
+ }
62
+ }
63
+ catch (err) {
64
+ logger_1.logger.error('Failed to remove traffic redirect', {
65
+ platform: this.platform,
66
+ err: err.message,
67
+ });
68
+ return false;
69
+ }
70
+ }
71
+ /** Internal: visible for tests so we can snapshot the exact rule shape. */
72
+ _getInstalledRules() {
73
+ return [...this.installedRules];
74
+ }
75
+ // ── Linux ────────────────────────────────────────────────────────────────
76
+ async installLinuxRedirect() {
77
+ const iptables = this.resolveBin('iptables');
78
+ if (!iptables) {
79
+ logger_1.logger.warn('iptables not available; Linux redirect not installed');
80
+ return false;
81
+ }
82
+ const proxyPort = this.config.port;
83
+ // (S-C13) Redirect ALL outbound port-443 (regardless of UID) EXCEPT when
84
+ // destined for the proxy itself (avoids loops with the daemon's own
85
+ // upstream calls). We don't exclude root: containerized agents commonly
86
+ // run as root and were previously silently bypassed.
87
+ const args = [
88
+ '-t', 'nat',
89
+ '-A', 'OUTPUT',
90
+ '-p', 'tcp',
91
+ '--dport', '443',
92
+ '-m', 'addrtype', '!', '--dst-type', 'LOCAL',
93
+ '-j', 'REDIRECT',
94
+ '--to-port', String(proxyPort),
95
+ ];
96
+ try {
97
+ (0, child_process_1.execFileSync)(iptables, args, { timeout: 5000, stdio: 'ignore' });
98
+ this.installedRules.push({ kind: 'iptables', args });
99
+ logger_1.logger.info('Linux iptables redirect installed', { proxyPort, args });
100
+ return true;
101
+ }
102
+ catch (err) {
103
+ logger_1.logger.warn('iptables rule install failed (non-root?)', { err: err.message });
104
+ return false;
105
+ }
106
+ }
107
+ async removeLinuxRedirect() {
108
+ const iptables = this.resolveBin('iptables');
109
+ if (!iptables)
110
+ return false;
111
+ for (const rule of this.installedRules) {
112
+ if (rule.kind !== 'iptables')
113
+ continue;
114
+ const deleteArgs = rule.args.map((a) => (a === '-A' ? '-D' : a));
115
+ try {
116
+ (0, child_process_1.execFileSync)(iptables, deleteArgs, { timeout: 5000, stdio: 'ignore' });
117
+ }
118
+ catch { /* best effort */ }
119
+ }
120
+ this.installedRules = this.installedRules.filter((r) => r.kind !== 'iptables');
121
+ return true;
122
+ }
123
+ // ── macOS ────────────────────────────────────────────────────────────────
124
+ async installMacOSRedirect() {
125
+ const pfctl = this.resolveBin('pfctl');
126
+ if (!pfctl) {
127
+ logger_1.logger.warn('pfctl not available; macOS redirect not installed');
128
+ return false;
129
+ }
130
+ // (S-C14) Resolve the actual egress interface so we don't bind to lo0.
131
+ const iface = this.resolveDefaultInterface();
132
+ if (!iface) {
133
+ logger_1.logger.warn('Could not resolve default egress interface for pf redirect');
134
+ return false;
135
+ }
136
+ const proxyPort = this.config.port;
137
+ // We do NOT shell out via `bash -c "echo ... > file"` (S-C2 family).
138
+ // Use Node fs to write the anchor file directly.
139
+ const fs = require('fs');
140
+ const path = require('path');
141
+ const anchorPath = '/etc/neuroshield/pf-anchor.conf';
142
+ const rules = `# NeuroShield Sentry — redirect outbound 443 on ${iface} to local proxy\n` +
143
+ `rdr pass on ${iface} inet proto tcp from any to any port 443 -> 127.0.0.1 port ${proxyPort}\n`;
144
+ try {
145
+ fs.mkdirSync(path.dirname(anchorPath), { recursive: true });
146
+ fs.writeFileSync(anchorPath, rules, 'utf8');
147
+ }
148
+ catch (err) {
149
+ logger_1.logger.warn('Could not write pf anchor file (needs root)', {
150
+ anchorPath,
151
+ err: err.message,
152
+ });
153
+ return false;
154
+ }
155
+ try {
156
+ (0, child_process_1.execFileSync)(pfctl, ['-a', 'com.neuroshield/sentry', '-f', anchorPath], { timeout: 5000, stdio: 'ignore' });
157
+ (0, child_process_1.execFileSync)(pfctl, ['-E'], { timeout: 5000, stdio: 'ignore' });
158
+ this.installedRules.push({ kind: 'pf', args: ['-a', 'com.neuroshield/sentry', '-f', anchorPath] });
159
+ logger_1.logger.info('macOS pf redirect installed', { iface, proxyPort, anchorPath });
160
+ return true;
161
+ }
162
+ catch (err) {
163
+ logger_1.logger.warn('macOS pf redirect install failed (needs root)', { err: err.message });
164
+ return false;
165
+ }
166
+ }
167
+ async removeMacOSRedirect() {
168
+ const pfctl = this.resolveBin('pfctl');
169
+ if (!pfctl)
170
+ return false;
171
+ try {
172
+ (0, child_process_1.execFileSync)(pfctl, ['-a', 'com.neuroshield/sentry', '-F', 'all'], { timeout: 5000, stdio: 'ignore' });
173
+ }
174
+ catch { /* best effort */ }
175
+ this.installedRules = this.installedRules.filter((r) => r.kind !== 'pf');
176
+ return true;
177
+ }
178
+ resolveDefaultInterface() {
179
+ try {
180
+ const out = (0, child_process_1.execFileSync)('route', ['-n', 'get', 'default'], { timeout: 2000, encoding: 'utf8' });
181
+ const match = out.match(/interface:\s*(\S+)/);
182
+ return match ? match[1] : null;
183
+ }
184
+ catch {
185
+ return null;
186
+ }
187
+ }
188
+ // ── Windows ──────────────────────────────────────────────────────────────
189
+ async installWindowsRedirect() {
190
+ const netsh = this.resolveBin('netsh.exe') ?? 'netsh.exe';
191
+ try {
192
+ const proxyAddr = `127.0.0.1:${this.config.port}`;
193
+ (0, child_process_1.execFileSync)(netsh, ['winhttp', 'set', 'proxy', proxyAddr], { timeout: 5000, stdio: 'ignore' });
194
+ this.installedRules.push({ kind: 'winhttp', args: ['winhttp', 'set', 'proxy', proxyAddr] });
195
+ logger_1.logger.info('Windows WinHTTP proxy configured', { proxy: proxyAddr });
196
+ return true;
197
+ }
198
+ catch (err) {
199
+ logger_1.logger.warn('Windows WinHTTP proxy config failed', { err: err.message });
200
+ return false;
201
+ }
202
+ }
203
+ async removeWindowsRedirect() {
204
+ const netsh = this.resolveBin('netsh.exe') ?? 'netsh.exe';
205
+ try {
206
+ (0, child_process_1.execFileSync)(netsh, ['winhttp', 'reset', 'proxy'], { timeout: 5000, stdio: 'ignore' });
207
+ return true;
208
+ }
209
+ catch {
210
+ return false;
211
+ }
212
+ }
213
+ // ── shared ───────────────────────────────────────────────────────────────
214
+ resolveBin(name) {
215
+ for (const dir of ['/usr/sbin', '/sbin', '/usr/local/sbin', '/usr/bin', '/bin', 'C:\\Windows\\System32']) {
216
+ const candidate = dir + (dir.includes('\\') ? '\\' : '/') + name;
217
+ try {
218
+ (0, child_process_1.execFileSync)(candidate, ['--version'], { stdio: 'ignore', timeout: 2000 });
219
+ return candidate;
220
+ }
221
+ catch {
222
+ continue;
223
+ }
224
+ }
225
+ return null;
226
+ }
227
+ }
228
+ exports.PlatformRedirect = PlatformRedirect;
229
+ //# sourceMappingURL=platform-redirect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-redirect.js","sourceRoot":"","sources":["../../src/redirect/platform-redirect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=platform-redirect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-redirect.test.d.ts","sourceRoot":"","sources":["../../src/redirect/platform-redirect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
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
+ /**
7
+ * Snapshot-style tests for the redirect rule arguments. We can't actually
8
+ * exec iptables / pfctl in a unit test (would require root and a real
9
+ * netfilter / pf), so we assert the SHAPE of the arguments — the audit
10
+ * findings (S-C13: excludes-root, S-C14: lo0-only) are encoded as regressions
11
+ * we'd see in the arg arrays.
12
+ */
13
+ const vitest_1 = require("vitest");
14
+ const os_1 = __importDefault(require("os"));
15
+ const platform_redirect_1 = require("./platform-redirect");
16
+ function proxyConfig(port = 9081) {
17
+ return {
18
+ enabled: true, port, bindAddress: '127.0.0.1',
19
+ upstreamTimeoutMs: 0, maxBufferSizeMb: 0,
20
+ interceptHttps: false, certPath: '', keyPath: '',
21
+ allowedProviders: ['*'], blockLocalModels: false,
22
+ };
23
+ }
24
+ (0, vitest_1.describe)('PlatformRedirect rule shapes (S-C13 / S-C14)', () => {
25
+ (0, vitest_1.it)('Linux rule does NOT exclude root', async () => {
26
+ if (os_1.default.platform() !== 'linux')
27
+ return;
28
+ const r = new platform_redirect_1.PlatformRedirect(proxyConfig());
29
+ await r.installRedirect().catch(() => undefined);
30
+ const rules = r._getInstalledRules();
31
+ // We may not have iptables to install; assert only when at least one tried.
32
+ for (const rule of rules) {
33
+ const arg = rule.args.join(' ');
34
+ (0, vitest_1.expect)(arg).not.toMatch(/--uid-owner\s+0/);
35
+ (0, vitest_1.expect)(arg).not.toMatch(/!\s*--uid-owner\s+0/);
36
+ }
37
+ });
38
+ (0, vitest_1.it)('Linux rule destination match excludes local addresses (avoid daemon loop)', () => {
39
+ // We can inspect the SHAPE by calling install and then checking what was
40
+ // recorded. On non-Linux we simply assert that the install path doesn't
41
+ // throw uncaught errors.
42
+ const r = new platform_redirect_1.PlatformRedirect(proxyConfig());
43
+ (0, vitest_1.expect)(() => r.installRedirect().catch(() => undefined)).not.toThrow();
44
+ });
45
+ (0, vitest_1.it)('macOS does not bind to lo0 (S-C14)', async () => {
46
+ if (os_1.default.platform() !== 'darwin')
47
+ return;
48
+ const r = new platform_redirect_1.PlatformRedirect(proxyConfig());
49
+ await r.installRedirect().catch(() => undefined);
50
+ const rules = r._getInstalledRules();
51
+ for (const rule of rules) {
52
+ if (rule.kind !== 'pf')
53
+ continue;
54
+ // The anchor file path may include any interface; the resolved interface
55
+ // would be a real outbound iface (en0, en1, etc.) — NEVER lo0.
56
+ const anchorPath = rule.args[rule.args.indexOf('-f') + 1];
57
+ if (anchorPath) {
58
+ try {
59
+ const content = require('fs').readFileSync(anchorPath, 'utf8');
60
+ (0, vitest_1.expect)(content).not.toContain('on lo0 ');
61
+ }
62
+ catch {
63
+ // file may not exist if we lacked permission to write it
64
+ }
65
+ }
66
+ }
67
+ });
68
+ (0, vitest_1.it)('removeRedirect drops the matching rule from the installed list', async () => {
69
+ const r = new platform_redirect_1.PlatformRedirect(proxyConfig());
70
+ await r.installRedirect().catch(() => undefined);
71
+ await r.removeRedirect().catch(() => undefined);
72
+ // After remove, no rules should remain in the installedRules list
73
+ (0, vitest_1.expect)(r._getInstalledRules()).toHaveLength(0);
74
+ });
75
+ });
76
+ //# sourceMappingURL=platform-redirect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-redirect.test.js","sourceRoot":"","sources":["../../src/redirect/platform-redirect.test.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,34 @@
1
1
  import { TaggedProcess, SandboxProfile } from '../types';
2
2
  import { SentryConfig } from '../config';
3
+ /**
4
+ * Structured result returned by every sandbox backend.
5
+ *
6
+ * Honesty contract (replaces the prior boolean return that let backends claim
7
+ * success without applying anything):
8
+ * - `applied` MUST be true only if the kernel actually enforces at least one
9
+ * restriction listed in `features`.
10
+ * - `features` enumerates what was actually enforced (e.g. ['cgroup_cpu',
11
+ * 'cgroup_memory']). Empty array + applied=true is a bug.
12
+ * - `reason` describes WHY enforcement was partial / not applied — surfaced
13
+ * to telemetry so operators see degraded protection in the dashboard
14
+ * instead of a false "sandboxed" badge.
15
+ *
16
+ * Backends that cannot enforce on a running PID (macOS, fork-time-only Linux
17
+ * primitives) MUST return applied=false with a clear reason.
18
+ */
19
+ export interface SandboxResult {
20
+ applied: boolean;
21
+ features: string[];
22
+ reason?: string;
23
+ }
3
24
  export interface SandboxBackend {
4
- applySandbox(pid: number, profile: SandboxProfile, defaults: SentryConfig['sandboxDefaults']): Promise<boolean>;
25
+ applySandbox(pid: number, profile: SandboxProfile, defaults: SentryConfig['sandboxDefaults']): Promise<SandboxResult>;
5
26
  removeSandbox(pid: number): Promise<boolean>;
6
27
  isSandboxed(pid: number): Promise<boolean>;
7
28
  getSandboxStats(pid: number): Promise<Record<string, string | number> | null>;
8
29
  }
9
30
  export declare function getProfileForFramework(frameworkId: string): SandboxProfile | null;
10
- export declare function applySandbox(process: TaggedProcess, config: SentryConfig): Promise<boolean>;
31
+ export declare function applySandbox(process: TaggedProcess, config: SentryConfig): Promise<SandboxResult>;
11
32
  export declare function removeSandbox(pid: number): Promise<boolean>;
12
33
  export declare function isSandboxed(pid: number): Promise<boolean>;
13
34
  export declare function getSandboxStats(pid: number): Promise<Record<string, string | number> | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,cAAc,EAA0B,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;CAC/E;AAyBD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAYjF;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAuBjG;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQjE;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/D;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAElG"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,cAAc,EAA0B,MAAM,UAAU,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAMzC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,CAAC,iBAAiB,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACtH,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;CAC/E;AA2BD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAYjF;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAoCvG;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQjE;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAE/D;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAElG"}
@@ -13,6 +13,7 @@ const types_1 = require("../types");
13
13
  const logger_1 = require("../logger");
14
14
  const linux_sandbox_1 = require("./linux-sandbox");
15
15
  const macos_sandbox_1 = require("./macos-sandbox");
16
+ const windows_sandbox_1 = require("./windows-sandbox");
16
17
  let backend = null;
17
18
  function getBackend() {
18
19
  if (backend)
@@ -24,10 +25,13 @@ function getBackend() {
24
25
  else if (platform === 'darwin') {
25
26
  backend = new macos_sandbox_1.MacOSSandbox();
26
27
  }
28
+ else if (platform === 'win32') {
29
+ backend = new windows_sandbox_1.WindowsSandbox();
30
+ }
27
31
  else {
28
32
  logger_1.logger.warn('No sandbox backend for platform, using no-op', { platform });
29
33
  backend = {
30
- applySandbox: async () => false,
34
+ applySandbox: async () => ({ applied: false, features: [], reason: `platform ${platform} is not supported` }),
31
35
  removeSandbox: async () => false,
32
36
  isSandboxed: async () => false,
33
37
  getSandboxStats: async () => null,
@@ -49,27 +53,40 @@ function getProfileForFramework(frameworkId) {
49
53
  return null;
50
54
  }
51
55
  async function applySandbox(process, config) {
56
+ // Unknown agents now fall through to default-restrictive so they get
57
+ // SOMETHING applied rather than nothing (S-C15).
52
58
  const profileName = process.sandboxProfileName ?? 'default-restrictive';
53
59
  const profile = types_1.AGENT_SANDBOX_PROFILES.find(p => p.name === profileName)
54
- ?? getProfileForFramework('unknown');
60
+ ?? types_1.AGENT_SANDBOX_PROFILES.find(p => p.name === 'default-restrictive')
61
+ ?? null;
55
62
  if (!profile) {
56
63
  logger_1.logger.warn('No sandbox profile available for process', { pid: process.pid, framework: process.frameworkId });
57
- return false;
64
+ return { applied: false, features: [], reason: 'no profile available' };
58
65
  }
59
66
  const bk = getBackend();
60
67
  try {
61
68
  const result = await bk.applySandbox(process.pid, profile, config.sandboxDefaults);
62
- if (result) {
63
- logger_1.logger.info('Sandbox applied', { pid: process.pid, framework: process.frameworkId, profile: profile.name });
69
+ if (result.applied) {
70
+ logger_1.logger.info('Sandbox applied', {
71
+ pid: process.pid,
72
+ framework: process.frameworkId,
73
+ profile: profile.name,
74
+ features: result.features,
75
+ });
64
76
  }
65
77
  else {
66
- logger_1.logger.warn('Sandbox application returned false', { pid: process.pid, framework: process.frameworkId });
78
+ logger_1.logger.warn('Sandbox NOT applied telemetry will report unprotected', {
79
+ pid: process.pid,
80
+ framework: process.frameworkId,
81
+ profile: profile.name,
82
+ reason: result.reason,
83
+ });
67
84
  }
68
85
  return result;
69
86
  }
70
87
  catch (err) {
71
88
  logger_1.logger.error('Failed to apply sandbox', { pid: process.pid, framework: process.frameworkId, err: err.message });
72
- return false;
89
+ return { applied: false, features: [], reason: err.message };
73
90
  }
74
91
  }
75
92
  async function removeSandbox(pid) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sandbox/index.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,25 @@
1
1
  import { SandboxProfile } from '../types';
2
- import { SandboxBackend } from './index';
2
+ import { SandboxBackend, SandboxResult } from './index';
3
3
  export declare class LinuxSandbox implements SandboxBackend {
4
4
  private cgroupV2;
5
5
  constructor();
6
6
  private detectCgroupVersion;
7
+ /**
8
+ * Apply available cgroups limits to an existing PID. Linux kernel primitives
9
+ * for syscall filtering (seccomp), filesystem access (Landlock), and
10
+ * capability dropping all REQUIRE fork-time application — they cannot be
11
+ * retroactively applied to a running process. We report this honestly via
12
+ * the `features` array so telemetry doesn't claim coverage we don't have.
13
+ *
14
+ * For full per-process restrictions, deploy the agent through Sentry's
15
+ * launcher wrapper (planned), which forks → applies seccomp/Landlock/caps
16
+ * → exec()s the agent binary.
17
+ */
7
18
  applySandbox(pid: number, profile: SandboxProfile, defaults: {
8
19
  cpuMax: string;
9
20
  memoryMax: string;
10
21
  pidMax: number;
11
- }): Promise<boolean>;
22
+ }): Promise<SandboxResult>;
12
23
  private applyCgroupV2;
13
24
  private applyCgroupV1;
14
25
  private addPidToCgroup;
@@ -1 +1 @@
1
- {"version":3,"file":"linux-sandbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/linux-sandbox.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAMzC,qBAAa,YAAa,YAAW,cAAc;IACjD,OAAO,CAAC,QAAQ,CAAU;;IAM1B,OAAO,CAAC,mBAAmB;IAYrB,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC9D,OAAO,CAAC,OAAO,CAAC;YAuBL,aAAa;YA2Bb,aAAa;YA+Bb,cAAc;IActB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuB5C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IA2BnF,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,aAAa;CAKtB"}
1
+ {"version":3,"file":"linux-sandbox.d.ts","sourceRoot":"","sources":["../../src/sandbox/linux-sandbox.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAMxD,qBAAa,YAAa,YAAW,cAAc;IACjD,OAAO,CAAC,QAAQ,CAAU;;IAM1B,OAAO,CAAC,mBAAmB;IAY3B;;;;;;;;;;OAUG;IACG,YAAY,CAChB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC9D,OAAO,CAAC,aAAa,CAAC;YAyCX,aAAa;YA8Bb,aAAa;YA+Bb,cAAc;IActB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAuB5C,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1C,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC;IA2BnF,OAAO,CAAC,gBAAgB;IAexB,OAAO,CAAC,aAAa;CAKtB"}
@@ -26,68 +26,102 @@ class LinuxSandbox {
26
26
  return false;
27
27
  }
28
28
  }
29
+ /**
30
+ * Apply available cgroups limits to an existing PID. Linux kernel primitives
31
+ * for syscall filtering (seccomp), filesystem access (Landlock), and
32
+ * capability dropping all REQUIRE fork-time application — they cannot be
33
+ * retroactively applied to a running process. We report this honestly via
34
+ * the `features` array so telemetry doesn't claim coverage we don't have.
35
+ *
36
+ * For full per-process restrictions, deploy the agent through Sentry's
37
+ * launcher wrapper (planned), which forks → applies seccomp/Landlock/caps
38
+ * → exec()s the agent binary.
39
+ */
29
40
  async applySandbox(pid, profile, defaults) {
30
41
  const cgroupPath = path_1.default.join(CGROUP_ROOT, SENTRY_CGROUP_NAME, `sentry-${pid}`);
42
+ const features = [];
31
43
  try {
32
44
  await promises_1.default.mkdir(cgroupPath, { recursive: true });
33
45
  if (this.cgroupV2) {
34
- await this.applyCgroupV2(cgroupPath, pid, profile, defaults);
46
+ const v2Features = await this.applyCgroupV2(cgroupPath, pid, profile, defaults);
47
+ features.push(...v2Features);
35
48
  }
36
49
  else {
37
- await this.applyCgroupV1(cgroupPath, pid, profile, defaults);
50
+ const v1Features = await this.applyCgroupV1(cgroupPath, pid, profile, defaults);
51
+ features.push(...v1Features);
38
52
  }
39
- const applied = await this.addPidToCgroup(cgroupPath, pid);
40
- if (applied) {
41
- logger_1.logger.info('Linux sandbox configured', { pid, cgroupPath, profile: profile.name });
53
+ const moved = await this.addPidToCgroup(cgroupPath, pid);
54
+ if (!moved) {
55
+ return {
56
+ applied: false,
57
+ features: [],
58
+ reason: 'Could not move PID into cgroup (insufficient permissions or process exited)',
59
+ };
42
60
  }
43
- return applied;
61
+ logger_1.logger.info('Linux sandbox configured', { pid, cgroupPath, profile: profile.name, features });
62
+ const strictFeatures = features.filter(feature => /seccomp|landlock|cap/i.test(feature));
63
+ return {
64
+ applied: strictFeatures.length > 0,
65
+ features,
66
+ reason: features.length === 0
67
+ ? 'No cgroup controllers were available'
68
+ : strictFeatures.length > 0
69
+ ? 'Strict sandbox features applied'
70
+ : 'Applied cgroup resource controls only; seccomp/Landlock/capabilities require fork-time launch',
71
+ };
44
72
  }
45
73
  catch (err) {
46
74
  logger_1.logger.error('Linux sandbox failed', { pid, err: err.message });
47
- return false;
75
+ return { applied: false, features: [], reason: err.message };
48
76
  }
49
77
  }
50
- async applyCgroupV2(cgroupPath, pid, profile, defaults) {
78
+ async applyCgroupV2(cgroupPath, _pid, profile, defaults) {
79
+ const features = [];
51
80
  const cpuMax = profile.cpuMax || defaults.cpuMax;
52
81
  const memoryMax = profile.memoryMax || defaults.memoryMax;
53
82
  const pidMax = profile.pidMax || defaults.pidMax;
54
- await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'cpu.max'), `${cpuMax}\n`);
55
- await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'memory.max'), this.parseMemoryBytes(memoryMax).toString());
56
83
  try {
57
- await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'pids.max'), pidMax.toString());
84
+ await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'cpu.max'), `${cpuMax}\n`);
85
+ features.push('cgroup_v2_cpu');
58
86
  }
59
- catch {
60
- // pids controller may not be enabled
87
+ catch { /* controller unavailable */ }
88
+ try {
89
+ await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'memory.max'), this.parseMemoryBytes(memoryMax).toString());
90
+ features.push('cgroup_v2_memory');
61
91
  }
62
- const ioFile = path_1.default.join(cgroupPath, 'io.max');
92
+ catch { /* controller unavailable */ }
63
93
  try {
64
- await promises_1.default.writeFile(ioFile, '8:0 rbps=104857600 wbps=52428800\n');
94
+ await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'pids.max'), pidMax.toString());
95
+ features.push('cgroup_v2_pids');
65
96
  }
66
- catch {
67
- // io controller may not be available
97
+ catch { /* pids controller may not be enabled */ }
98
+ try {
99
+ await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'io.max'), '8:0 rbps=104857600 wbps=52428800\n');
100
+ features.push('cgroup_v2_io');
68
101
  }
102
+ catch { /* io controller may not be available */ }
103
+ return features;
69
104
  }
70
- async applyCgroupV1(cgroupPath, pid, profile, defaults) {
105
+ async applyCgroupV1(cgroupPath, _pid, profile, defaults) {
106
+ const features = [];
71
107
  const memoryMax = profile.memoryMax || defaults.memoryMax;
72
108
  try {
73
109
  await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'memory.limit_in_bytes'), this.parseMemoryBytes(memoryMax).toString());
110
+ features.push('cgroup_v1_memory');
74
111
  }
75
- catch {
76
- // memory controller may not be mounted
77
- }
112
+ catch { /* memory controller may not be mounted */ }
78
113
  try {
79
114
  const cpuCfsQuota = this.parseCpuQuota(profile.cpuMax || defaults.cpuMax);
80
115
  await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'cpu.cfs_quota_us'), cpuCfsQuota.toString());
116
+ features.push('cgroup_v1_cpu');
81
117
  }
82
- catch {
83
- // cpu controller may not be mounted
84
- }
118
+ catch { /* cpu controller may not be mounted */ }
85
119
  try {
86
120
  await promises_1.default.writeFile(path_1.default.join(cgroupPath, 'pids.max'), (profile.pidMax || defaults.pidMax).toString());
121
+ features.push('cgroup_v1_pids');
87
122
  }
88
- catch {
89
- // pids controller may not be mounted
90
- }
123
+ catch { /* pids controller may not be mounted */ }
124
+ return features;
91
125
  }
92
126
  async addPidToCgroup(cgroupPath, pid) {
93
127
  const procsFile = path_1.default.join(cgroupPath, 'cgroup.procs');