Skip to content

Commit c6c6567

Browse files
committed
Add docs, fix some review comments
1 parent e15649a commit c6c6567

File tree

4 files changed

+62
-5
lines changed

4 files changed

+62
-5
lines changed

docs/esm.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Adding Zen to an ESM application
2+
3+
> [!WARNING]
4+
> The new instrumentation system with ESM support is still under active development and not suitable for production use.
5+
6+
Modify the start command of your application to include the Zen firewall:
7+
8+
```sh
9+
node -r @aikidosec/firewall/instrument your-app.js
10+
```
11+
12+
Alternatively, you can set the `NODE_OPTIONS` environment variable to include the Zen firewall:
13+
14+
```sh
15+
export NODE_OPTIONS='-r @aikidosec/firewall/instrument'
16+
```
17+
18+
> [!IMPORTANT]
19+
> Please also check the documentation on how to integrate Zen with your used web framework.
20+
21+
## Blocking mode
22+
23+
By default, the firewall will run in non-blocking mode. When it detects an attack, the attack will be reported to Aikido if the environment variable `AIKIDO_TOKEN` is set and continue executing the call.
24+
25+
You can enable blocking mode by setting the environment variable `AIKIDO_BLOCK` to `true`:
26+
27+
```sh
28+
AIKIDO_BLOCK=true node app.js
29+
```
30+
31+
It's recommended to enable this on your staging environment for a considerable amount of time before enabling it on your production environment (e.g. one week).
32+
33+
## Known issues
34+
35+
- The app might crash on startup if used together with some packages that use the Node.js Asynchronous Module Customization Hooks, like the tapjs test runner, due to bugs in Node.js itself.
36+
- Zen can not protect ESM sub-dependencies of a ESM package. For example if a ESM package `foo` imports a sub-dependency `bar` that is also an ESM package, Zen will not be able to protect the code in `bar`. This is because the V8 engine does not allow Node.js to observe the evaluation of inner ESM packages (yet).
37+
38+
Relevant links:
39+
40+
- [ERR_INVALID_RETURN_PROPERTY_VALUE when using module.register and module.registerHooks (#57327)](https://github.com/nodejs/node/issues/57327)
41+
- [module.registerHooks() tracking issue (#56241)](https://github.com/nodejs/node/issues/56241)
42+
- [TypeError when json file is required in hook and in the imported file (#57358)](https://github.com/nodejs/node/issues/57358)
43+
- [ERR_INTERNAL_ASSERTION: Unexpected module status 3 (#58515)](https://github.com/nodejs/node/issues/58515)
44+
- [Adding an evaluation hook for v8::Module](https://issues.chromium.org/u/1/issues/384413088)

library/agent/hooks/instrumentation/wrapBuiltinExports.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function wrapBuiltinExports(id: string, exports: unknown): unknown {
2323
try {
2424
const returnVal = interceptor(exports, pkgInfo);
2525
// If the interceptor returns a value, we want to use this value as the new exports
26-
if (typeof returnVal !== "undefined") {
26+
if (returnVal !== undefined) {
2727
exports = returnVal;
2828
}
2929
} catch (error) {

library/agent/hooks/wrapRequire.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ function executeInterceptors(
287287
try {
288288
const returnVal = interceptor(exports, wrapPackageInfo);
289289
// If the interceptor returns a value, we want to use this value as the new exports
290-
if (typeof returnVal !== "undefined") {
290+
if (returnVal !== undefined) {
291291
exports = returnVal;
292292
}
293293
} catch (error) {

scripts/build.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,20 @@ const {
88
verifyFileHash,
99
extractTar,
1010
} = require("./helpers/internals");
11-
const execAsync = promisify(exec);
11+
12+
// Helper to run exec async and pipe stdout/stderr
13+
async function execAsyncWithPipe(command, options) {
14+
const child = exec(command, options);
15+
child.stdout && child.stdout.pipe(process.stdout);
16+
child.stderr && child.stderr.pipe(process.stderr);
17+
return new Promise((resolve, reject) => {
18+
child.on("close", (code) => {
19+
if (code === 0) resolve();
20+
else reject(new Error(`Command failed: ${command} (exit code ${code})`));
21+
});
22+
child.on("error", reject);
23+
});
24+
}
1225

1326
// Zen Internals configuration
1427
const INTERNALS_VERSION = "v0.1.41";
@@ -37,7 +50,7 @@ async function main() {
3750
await dlZenInternals();
3851
await buildInstrumentationWasm();
3952

40-
await execAsync(`npm run build`, {
53+
await execAsyncWithPipe(`npm run build`, {
4154
cwd: libDir,
4255
});
4356

@@ -134,7 +147,7 @@ async function modifyDtsFilesAfterBuild() {
134147

135148
async function buildInstrumentationWasm() {
136149
// Build Instrumentation WASM
137-
await execAsync(
150+
await execAsyncWithPipe(
138151
`wasm-pack build --release --target nodejs --out-dir ${instrumentationWasmOutDir}`,
139152
{
140153
cwd: instrumentationWasmDir,

0 commit comments

Comments
 (0)