Now working as a vm.Script passing in all the Globals the proxy script needs

This commit is contained in:
2026-03-07 01:20:45 -06:00
parent 67b36f97ce
commit 1a6bd09b7b
4 changed files with 423 additions and 362 deletions

View File

@@ -1,35 +1,3 @@
<!--
Sync Impact Report:
Version: 1.11.0 → 1.12.0 (MINOR: Moved Google authentication config to global JSON objects)
Modified Principles:
- Section I.V: Added google-scopes.json to dynamic JSON objects examples
- Removed google.* configuration from config/default.json
- proxy.js Section 1 now reads ONLY from globalThis['service-account-key'] and globalThis['google-scopes']
- config/default.json now contains ONLY infrastructure (server, logging)
- proxy.js authentication is now 100% global-object-based with zero config dependency
Modified Files:
- Created global/google-scopes.json with scopes array setting
- Removed entire google section from config/default.json
- Updated proxy.js Section 1 (initializeServiceAccount) to use only global objects
- Updated server.js validateConfig() to validate new global objects
Breaking Changes:
- config.google.serviceAccountEmail removed (credentials are in global/service-account-key.json)
- config.google.serviceAccountKeyPath removed (always global/service-account-key.json)
- config.google.scopes removed (now in global/google-scopes.json)
- All Google authentication config now exclusively in global/ directory
Modified Sections:
- Section I.V: Updated examples list to include google-scopes
- Section I.IV: Clarified config/default.json contains ONLY infrastructure
Templates Status:
⚠ plan-template.md - Document global/ for ALL authentication and behavioral config
⚠ tasks-template.md - Never put auth, secrets, or behavioral config in config/default.json
✅ spec-template.md - No changes required
Follow-up TODOs:
- Update tests to mock globalThis['service-account-key'] and globalThis['google-scopes']
- Document scopes format in google-scopes.json.example
- Verify all config references removed from proxy.js Section 1
-->
# Proxy Scripts Constitution
## Core Principles
@@ -39,41 +7,51 @@ Follow-up TODOs:
**ALL business logic, data processing, authentication, and request handling MUST exist within the `proxy.js` file.** The `server.js` file should ONLY handle:
- HTTP server setup
- Configuration loading
- Global console replacement with custom logger
- Request delegation to `proxy.handleRequest()`
- Global object injection into isolated context
- Loading proxy.js via `vm.Script` and `vm.createContext`
- Per-request context creation with all necessary globals
**Rationale**: Monolithic architecture enables simple packaging as a single IVA Studio proxy script and prevents fragmentation of business logic across multiple files. ALL functionality must be in one place.
**Implementation via vm.Script**:
`proxy.js` MUST be loaded using Node.js `vm.Script` and executed in isolated contexts created per-request with `vm.createContext`. This ensures:
- Complete isolation from server.js module system
- All dependencies provided explicitly through context objects
- Zero ability to import/export modules
- Pure functional execution with injected dependencies
**Rationale**: Monolithic architecture enables simple packaging as a single IVA Studio proxy script and prevents fragmentation of business logic across multiple files. Using `vm.Script` enforces architectural boundaries at runtime, making it impossible for `proxy.js` to access Node.js module system or file system, ensuring ALL functionality exists in one isolated, dependency-injected file.
### I. Zero External Imports or Exports from `proxy.js` (NON-NEGOTIABLE)
`proxy.js` MUST have **ZERO import statements**. All dependencies MUST be provided as global objects by server.js.
`proxy.js` MUST have **ZERO import statements**. All dependencies MUST be provided through `vm.createContext` by server.js.
`proxy.js` MUST have **ZERO export statements**. The proxy.js file should be treated as a single function that receives (req, res) parameters and loaded as a route into the server.js file.
`proxy.js` MUST have **ZERO export statements**. The file MUST be pure JavaScript code executed in an isolated VM context.
**File system access** from `proxy.js` is **ABSOLUTELY PROHIBITED** under any circumstances. The `fs` module MUST NOT be imported into proxy.js.
**File system access** from `proxy.js` is **ABSOLUTELY PROHIBITED** under any circumstances. The `fs` module MUST NOT be accessible.
**External libraries** (axios, jwt, googleapis, etc.) MUST NOT be imported. Use globals provided by server.js instead.
**External libraries** (axios, jwt, googleapis, etc.) MUST NOT be imported. Dependencies are injected through VM context by server.js.
**Rationale**: Monolithic architecture requires ALL I/O operations and dependency injection to be centralized in server.js, ensuring proxy.js contains ONLY pure business logic.
**Rationale**: Using `vm.Script` and `vm.createContext` enforces architectural boundaries at the VM level. proxy.js runs in an isolated context with NO access to Node.js module system, file system, or process globals. ALL dependencies must be explicitly injected per-request through the context object, ensuring proxy.js contains ONLY pure business logic with zero capability for I/O operations.
**For data files that proxy.js needs** (service account keys, certificates, secrets):
1. Place JSON files in `global/` directory
2. server.js automatically loads them as global objects using the filename as the object name
3. proxy.js accesses them via `globalThis[objectName]`
2. server.js loads them at startup using `loadGlobalObjects()`
3. server.js injects them into VM context per-request via `vm.createContext`
4. proxy.js accesses them as simple variables in context (e.g., `google_drive_settings`)
**Example**:
- File: `global/service-account-key.json`
- Global: `globalThis['service-account-key']`
- Access in proxy.js: `const credentials = globalThis['service-account-key']`
- File: `global/google_drive_settings.json`
- Loading: server.js reads and assigns to `globalVariableContext.google_drive_settings`
- Injection: server.js adds `google_drive_settings: globalVariableContext.google_drive_settings` to context
- Access in proxy.js: Direct variable access `google_drive_settings.serviceAccount`
**Enforcement**:
- proxy.js MUST have NO `import` statements (file should start with comments, then code)
- During code review, verify first line of code is NOT an import
- Any `import` statement in proxy.js MUST be rejected immediately
- proxy.js MUST have NO `export` statements
- Any `export` statement in proxy.js MUST be rejected immediately
- All file operations MUST be in server.js, which then provides data via globals
- All external libraries MUST be provided as globals by server.js
- proxy.js MUST have NO `export` statements (no module.exports, no export keyword)
- Any `import` or `export` in proxy.js MUST be rejected immediately
- server.js MUST load proxy.js using `vm.Script` constructor
- server.js MUST execute via `script.runInContext(context)` with fresh context per request
- All dependencies injected through `vm.createContext({ ... })` context object
- VM isolation prevents access to require(), import(), fs, process, and Node.js globals
#### I.I What MUST Be in proxy.js
@@ -124,73 +102,109 @@ During code review and planning:
#### I.V Global Objects Provided by server.js
The `server.js` file MUST make the following objects available globally for use by `proxy.js`:
The `server.js` file MUST inject the following objects into VM context for use by `proxy.js`:
**Core Infrastructure Globals:**
**VM Context Injection Pattern:**
```javascript
// Create a context with all globals that proxy.js needs
const context = vm.createContext({
...globalVMContext,
...globalVariableContext,
req,
res,
});
script.runInContext(context);
```
**Core Infrastructure Context Variables:**
1. **console** - Custom logger from `logger.js`
- Purpose: Structured JSON logging
- Usage: `console.info()`, `console.debug()`, `console.error()`
- Replaces: Built-in console object
- Injected from: `globalVMContext.console`
2. **crypto** - Node.js crypto module
2. **crypto** - Web Crypto API (built-in)
- Purpose: UUID generation, cryptographic operations
- Usage: `crypto.randomUUID()`, etc.
- Note: Cannot use name 'crypto' due to Web Crypto API conflict
- Replaces: `import crypto from 'node:crypto'` in proxy.js
- Injected from: `globalVMContext.crypto`
- Note: Web Crypto API available by default in Node.js
3. **config** - Configuration object
- Purpose: Infrastructure settings ONLY (server host/port, logging level)
- Usage: `global.config.server.port`, `global.config.logging.level`
- Loaded: From `config/default.json` merged with ENV vars
- Usage: `config.server.port`, `config.logging.level`
- Injected from: `global.config`
- Loaded from: `config/default.json` merged with ENV vars
- **DOES NOT contain**: Authentication, secrets, API keys, behavioral config (use global/ instead)
4. **axios** - HTTP client library
- Purpose: Making HTTP requests to external APIs
- Usage: `axios.get(url)`, `axios.post(url, data)`
- Package: `axios`
- Replaces: `import axios from 'axios'` in proxy.js
- Injected from: `globalVMContext.axios`
5. **uuidv4** - UUID v4 generator
- Purpose: Generate RFC4122 compliant UUIDs
- Usage: `uuidv4()` returns string like "110ec58a-a0f2-4ac4-8393-c866d813b8d1"
- Package: `uuid` (v4 function only)
- Replaces: `import { v4 as uuidv4 } from 'uuid'` in proxy.js
- Injected from: `globalVMContext.uuidv4`
6. **jwt** - JSON Web Token library
- Purpose: Creating and verifying JWTs for authentication
- Usage: `jwt.sign(payload, secret)`, `jwt.verify(token, secret)`
- Package: `jsonwebtoken`
- Replaces: `import jwt from 'jsonwebtoken'` in proxy.js
- Injected from: `globalVMContext.jwt`
7. **xmlBuilder** - XML builder/generator
- Purpose: Constructing XML documents programmatically
- Usage: `xmlBuilder({ root: { child: 'value' } })`
- Package: `xmlbuilder2` (create function)
- Replaces: `import { create } from 'xmlbuilder2'` in proxy.js
- Injected from: `globalVMContext.xmlBuilder`
**Dynamic Data Globals:**
**Built-in Web APIs:**
8. **Dynamic JSON objects from global/ directory**
- Purpose: Authentication credentials, secrets, API keys, and behavioral configuration
- Pattern: Each `global/filename.json``globalThis['filename']`
- Examples:
- `global/service-account-key.json``globalThis['service-account-key']` (Service Account credentials with client_email and private_key)
- `global/google-scopes.json``globalThis['google-scopes']` (OAuth2 scopes array for Google APIs)
- `global/sitemap-config.json``globalThis['sitemap-config']` (Sitemap settings like maxUrls)
- `global/drive-query.json``globalThis['drive-query']` (Drive API query filter)
- `global/api-keys.json``globalThis['api-keys']` (API keys and secrets)
- Usage in proxy.js: `const creds = globalThis['service-account-key']`, `const scopes = globalThis['google-scopes']`
- Loaded: Automatically by server.js at startup using `loadGlobalObjects()`
- **Note**: ALL authentication, secrets, and behavioral configuration MUST be in global/, NEVER in config/default.json
8. **URLSearchParams** - URL query string parser (built-in)
- Purpose: Parse and manipulate URL query strings
- Usage: `new URLSearchParams(queryString)`
- Injected from: `globalVMContext.URLSearchParams`
9. **URL** - URL parser (built-in)
- Purpose: Parse and manipulate URLs
- Usage: `new URL(urlString)`
- Injected from: `globalVMContext.URL`
**Dynamic Data Context Variables:**
10. **Dynamic JSON objects from global/ directory**
- Purpose: Authentication credentials, secrets, API keys, and behavioral configuration
- Pattern: Each `global/filename.json` loaded by server.js → injected into context
- Examples:
- `global/google_drive_settings.json` → context var `google_drive_settings` (consolidated service account, scopes, drive query, sitemap config)
- `global/api-keys.json` → context var `api_keys` (API keys and secrets)
- `global/custom-config.json` → context var `custom_config` (behavioral settings)
- Usage in proxy.js: Direct variable access `google_drive_settings.serviceAccount`
- Loaded: By server.js at startup using `loadGlobalObjects()`
- Injected: Per-request via `vm.createContext({ objectName: globalVariableContext.objectName })`
- **Note**: ALL authentication, secrets, and behavioral configuration MUST be in global/, NEVER in config/default.json
**Request/Response Objects:**
11. **req** - HTTP IncomingMessage
- Purpose: Access request data (URL, method, headers, body)
- Injected fresh: Per-request from `http.createServer((req, res) => ...)`
12. **res** - HTTP ServerResponse
- Purpose: Send response to client
- Injected fresh: Per-request from `http.createServer((req, res) => ...)`
**Rationale**: Using `vm.createContext` for dependency injection achieves:
- **Runtime-enforced isolation** - proxy.js physically cannot access Node.js module system or file system
- **Zero imports possible** - VM context has no `require()` or `import()` capability
- **Explicit dependencies** - All available objects must be explicitly listed in context
- **Per-request isolation** - Fresh context per request prevents cross-request state leakage
- **Testing simplicity** - Mock entire context object instead of individual module imports
- **Clear contracts** - Context object documents every dependency proxy.js uses
- **Security boundaries** - VM sandbox prevents escape to underlying system
**Rationale**: Centralizing global setup and ALL file I/O in server.js achieves:
- **ZERO imports in proxy.js** - complete dependency injection pattern
- Consistent environment setup and library versions
- Easy testing (mock globals instead of mocking module imports)
- Clear separation: server.js = infrastructure & dependencies, proxy.js = pure business logic
- Single source of truth for dependency injection
- Direct REST API calls instead of heavyweight SDK wrappers
#### I.VI Logging
@@ -380,4 +394,4 @@ All pull requests, code reviews, and design discussions MUST verify compliance w
For runtime development guidance, refer to `.github/prompts/` and `.github/agents/` files which operationalize these principles into agent workflows.
**Version**: 1.11.0 | **Ratified**: 2026-03-05 | **Last Amended**: 2026-03-07
**Version**: 1.13.0 | **Ratified**: 2026-03-05 | **Last Amended**: 2026-03-07