AthennaIO / AthennaIO/IoC

FacadeProxyHandler unconditionally imports @athenna/test in non-test environments, activating nock and breaking real HTTP connections

Open
#99 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
8
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Bug Description

`FacadeProxyHandler.js` performs a top-level `await Module.safeImport('@athenna/test')` at module load time, unconditionally — regardless of whether the application is running in a test environment. This causes `nock` (a dependency of `@athenna/test`) to activate its HTTP interceptors via `@mswjs/interceptors` on every application startup where `@athenna/test` is installed.

## Affected File

`src/facades/FacadeProxyHandler.ts` (compiled: `src/facades/FacadeProxyHandler.js`)

```js
// Line 12 — runs on every module load, in every environment
const athennaTest = await Module.safeImport('@athenna/test');
const Mock = athennaTest?.Mock;
```

## Root Cause Chain

1. Any facade (e.g. `Storage`, `Database`) is used in an artisan command
2. → `FacadeProxyHandler` module is loaded
3. → `Module.safeImport('@athenna/test')` runs unconditionally
4. → `@athenna/test/src/mocks/Mock.js` is loaded, which does `import nock from 'nock'`
5. → **nock v14 auto-activates `@mswjs/interceptors`** on import (by design — see nock's [own comment](https://github.com/nock/nock/blob/main/index.js): *"We always activate Nock on import"*)
6. → All subsequent HTTP/HTTPS connections go through `MockHttpSocket`
7. → Real TLS connections (e.g. AWS S3 SDK uploads) fail with `Error: read EINVAL`

## How to Reproduce

1. Have a project with `@athenna/test` as a **devDependency** (installed locally)
2. Use any Athenna facade (e.g. `Storage`) inside an artisan command
3. Run the command: `node artisan my:command`
4. Any real outbound HTTPS call made inside the command (e.g. AWS S3 SDK) fails with:

```
Error: read EINVAL
at tryReadStart (node:net:702:20)
at Socket._read (node:net:717:5)
at MockHttpSocket. (.../node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/MockHttpSocket.ts:165:12)
at TLSSocket. (.../node_modules/@mswjs/interceptors/src/interceptors/ClientRequest/MockHttpSocket.ts:293:14)
```

The AWS SDK metadata confirms it's a real outbound call being intercepted:
```json
{ "$metadata": { "attempts": 1, "totalRetryDelay": 0 } }
```

## Verification

Confirmed with CJS require tracing that nock is loaded via:

```
nock/index.js
← Module.safeImport('@athenna/test') [at FacadeProxyHandler.js:12]
← FacadeProxyHandler module load
← any Facade usage in the application
```

And confirmed that `nock.isActive()` returns `true` immediately after `@athenna/test` is imported — even with no test setup, no `nock()` calls, no `disableNetConnect()`.

## Proposed Fix

Only import `@athenna/test` when the application is actually running in test mode:

```ts
// src/facades/FacadeProxyHandler.ts

const isTestEnv = process.argv[2] === 'test' || process.env.APP_ENV === 'test';
const athennaTest = isTestEnv ? await Module.safeImport('@athenna/test') : null;
const Mock = athennaTest?.Mock;
```

Alternatively, a more robust check could use a dedicated env variable or the Athenna RC configuration.

## Environment

- `@athenna/ioc`: checked on latest (the `FacadeProxyHandler.js` in the published package has this code)
- `@athenna/test`: `^5.8.0`
- `nock`: `14.0.15` (auto-activates interceptors on import — this is intentional nock v14 behavior)
- `@mswjs/interceptors`: `0.41.9` (used by nock v14 under the hood)
- Node.js: `v22.8.0`

Contributor guide

Open the contributing guide

Research direction

Start with src/facades/FacadeProxyHandler.ts and trace the top-level Module.safeImport('@athenna/test') during facade loading. Reproduce the artisan command with @athenna/test installed and verify that non-test startup no longer activates nock or breaks real HTTPS connections, while test-mode mocking remains available.

Written by the indexing model from the issue text.

Assessment

Tech stack
node.js, typescript
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.