Conversation
- Updated @anthropic-ai/mcpb from 1.2.0 to 2.1.2 (MAJOR) - Updated eslint from 9.39.2 to 10.0.3 (MAJOR) - Updated @eslint/js from 9.39.2 to 10.0.1 (MAJOR) - Updated globals from 15.15.0 to 17.4.0 (MAJOR) - Updated typescript from 5.3.0 to 5.8.4 - Fixed flatted DoS vulnerability (CVE high) Improves: security, MCP compatibility, linting rules, TypeScript features
- Add comprehensive GitHub Actions CI workflow - Multi-node testing (18.x, 20.x, 22.x) - Lint, format, type-check, and test validation - Dependency audit and security checks - Build verification for all packages - Add unit tests for core package configuration loader - Test loadPipelineConfig, loadRalphConfig, loadValidationConfig - Test discoverPipelineConfig functionality - Test default configuration generators - Comprehensive error handling validation - Update critical dependencies to latest stable versions - @vitest/coverage-v8: 4.0.18 → 4.1.0 - lint-staged: 16.2.7 → 16.4.0 - typescript-eslint: 8.55.0 → 8.57.1 - Add CHANGELOG.md for better release tracking Addresses high priority items identified in code review: - Missing CI/CD pipeline for automated quality assurance - No test coverage for critical core package functionality - Outdated dependencies with available security updates
- Run npm audit fix on mcp-server workspace - Fixed 5 high and moderate severity vulnerabilities - Remaining 5 low severity vulnerabilities have no fix available
- Updated @anthropic-ai/sdk from 0.32.0 to 0.80.0 (major update with latest features) - Updated @types/node, vitest, typescript and other dev dependencies to latest stable versions - Updated CLI dependencies including critical Anthropic SDK - All tests passing, no vulnerabilities found Key updates: - @anthropic-ai/sdk: 0.32.0 → 0.80.0 - typescript: 5.3.0/5.6.3 → 5.7.3 - vitest: 4.0.18 → 4.1.0 - husky: 9.0.0 → 9.1.6 - inquirer: 12.2.0 → 12.11.1 - dotenv: 16.4.5 → 16.6.1
| }, | ||
| }; | ||
|
|
||
| writeFileSync(configPath, JSON.stringify(validConfig, null, 2)); |
Check failure
Code scanning / CodeQL
Insecure temporary file High test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 23 hours ago
In general, insecure temporary file issues are fixed by delegating temp file/directory creation to a well-tested library that atomically creates unique paths with restrictive permissions (e.g. tmp), rather than manually constructing paths under os.tmpdir().
Here, the best minimal fix is to change setupTestDir() so that it uses tmp.dirSync from the tmp library to create a unique, secure temporary directory instead of calling tmpdir() + Date.now() + mkdirSync. This keeps the rest of the test logic unchanged: setupTestDir() still returns a directory path, and the subsequent join(dir, 'pipeline.json') and writeFileSync usages remain the same. We only need to (1) import tmp at the top of core/src/__tests__/config-loader.test.js and (2) replace the body of setupTestDir() to call tmp.dirSync({ unsafeCleanup: true }) (so the directory can be recursively removed by the library if we wanted) and return its .name property. We'll keep cleanupTestDir() as-is since it just deletes whatever testDir points to; that remains valid.
Concretely:
- In
core/src/__tests__/config-loader.test.js, addimport tmp from 'tmp';alongside the other imports. - Replace the logic in
setupTestDir():- Remove
testDir = join(tmpdir(), \appfactory-test-${Date.now()}`);andmkdirSync(testDir, { recursive: true });`. - Instead, call
const tmpDir = tmp.dirSync({ unsafeCleanup: true }); testDir = tmpDir.name;.
No other test code needs to be modified.
- Remove
| @@ -7,6 +7,7 @@ | ||
| import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { tmpdir } from 'node:os'; | ||
| import tmp from 'tmp'; | ||
|
|
||
| import { | ||
| loadPipelineConfig, | ||
| @@ -23,8 +24,8 @@ | ||
|
|
||
| // Setup test directory before each test | ||
| function setupTestDir() { | ||
| testDir = join(tmpdir(), `appfactory-test-${Date.now()}`); | ||
| mkdirSync(testDir, { recursive: true }); | ||
| const tmpDir = tmp.dirSync({ unsafeCleanup: true }); | ||
| testDir = tmpDir.name; | ||
| return testDir; | ||
| } | ||
|
|
| @@ -44,7 +44,8 @@ | ||
| "dependencies": { | ||
| "chalk": "^5.3.0", | ||
| "ajv": "^8.12.0", | ||
| "zod": "^3.22.0" | ||
| "zod": "^3.22.0", | ||
| "tmp": "^0.2.5" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" |
| Package | Version | Security advisories |
| tmp (npm) | 0.2.5 | None |
| const dir = setupTestDir(); | ||
| const configPath = join(dir, 'invalid.json'); | ||
|
|
||
| writeFileSync(configPath, '{ invalid json }'); |
Check failure
Code scanning / CodeQL
Insecure temporary file High test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 23 hours ago
In general, to fix insecure temporary file/directory creation, avoid manually assembling paths under os.tmpdir() and instead rely on a well‑tested library that creates unique, non‑guessable paths with restrictive permissions and guarantees the path did not already exist. For Node.js, the tmp library is a common choice; it offers dirSync() and fileSync() for securely creating temp directories and files.
For this specific file, the only problematic part is setupTestDir(), which builds testDir = join(tmpdir(), 'appfactory-test-' + Date.now()) and then calls mkdirSync. We should replace this with a call to tmp.dirSync() and store the generated directory path in testDir. This preserves existing functionality (tests still get a fresh directory and can clean it up) while removing the insecure pattern. Concretely:
- Add an import for
tmpat the top ofcore/src/__tests__/config-loader.test.js. - Rewrite
setupTestDir()so that it callstmp.dirSync({ unsafeCleanup: true, prefix: 'appfactory-test-' }), assignstestDir = tmpDir.name, and returnstestDir. - Leave
cleanupTestDir()unchanged; it already deletestestDirrecursively and forcefully, which is fine for tests even thoughtmpcan also clean up for us.
No other lines need changes, since they just use whatever directory setupTestDir() returns.
| @@ -7,6 +7,7 @@ | ||
| import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { tmpdir } from 'node:os'; | ||
| import tmp from 'tmp'; | ||
|
|
||
| import { | ||
| loadPipelineConfig, | ||
| @@ -23,8 +24,8 @@ | ||
|
|
||
| // Setup test directory before each test | ||
| function setupTestDir() { | ||
| testDir = join(tmpdir(), `appfactory-test-${Date.now()}`); | ||
| mkdirSync(testDir, { recursive: true }); | ||
| const tmpDir = tmp.dirSync({ unsafeCleanup: true, prefix: 'appfactory-test-' }); | ||
| testDir = tmpDir.name; | ||
| return testDir; | ||
| } | ||
|
|
| @@ -44,7 +44,8 @@ | ||
| "dependencies": { | ||
| "chalk": "^5.3.0", | ||
| "ajv": "^8.12.0", | ||
| "zod": "^3.22.0" | ||
| "zod": "^3.22.0", | ||
| "tmp": "^0.2.5" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" |
| Package | Version | Security advisories |
| tmp (npm) | 0.2.5 | None |
| runE2ETests: true, | ||
| }; | ||
|
|
||
| writeFileSync(configPath, JSON.stringify(validConfig, null, 2)); |
Check failure
Code scanning / CodeQL
Insecure temporary file High test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 23 hours ago
In general, to fix insecure temporary file/directory creation you should avoid manually constructing paths under os.tmpdir() and instead delegate to a library or API that atomically creates a unique, private temp file or directory (e.g., the tmp package’s dirSync/fileSync, or Node’s fs.mkdtempSync). These APIs both ensure non-collision and use secure permissions by default.
For this specific code, the minimal change that preserves existing behavior is to update setupTestDir so it no longer manually builds a path using tmpdir() and Date.now(). Instead, we can import the tmp library and call tmp.dirSync({ unsafeCleanup: true }) to create a secure temporary directory and get its path. We then store the returned directory path in testDir as before. Because cleanupTestDir already calls rmSync(testDir, { recursive: true, force: true }), we should not rely on tmp’s automatic cleanup, but using unsafeCleanup: true makes sure even non-empty directories could be cleaned by tmp if we later decide to use its removeCallback. The rest of the test code (building configPath with join(dir, 'ralph.json'), etc.) can remain unchanged.
Concretely:
- Add an import for the
tmplibrary at the top ofcore/src/__tests__/config-loader.test.js. - Change
setupTestDirso that:- It calls
tmp.dirSync({ unsafeCleanup: true }). - It assigns the created directory path (
tmpDir.name) totestDirand returns it.
No other tests or functions need to change, and the test behavior (having a unique temporary directory per test) is preserved while addressing the insecure temp creation.
- It calls
| @@ -7,6 +7,7 @@ | ||
| import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { tmpdir } from 'node:os'; | ||
| import tmp from 'tmp'; | ||
|
|
||
| import { | ||
| loadPipelineConfig, | ||
| @@ -23,8 +24,8 @@ | ||
|
|
||
| // Setup test directory before each test | ||
| function setupTestDir() { | ||
| testDir = join(tmpdir(), `appfactory-test-${Date.now()}`); | ||
| mkdirSync(testDir, { recursive: true }); | ||
| const tmpDir = tmp.dirSync({ unsafeCleanup: true }); | ||
| testDir = tmpDir.name; | ||
| return testDir; | ||
| } | ||
|
|
| @@ -44,7 +44,8 @@ | ||
| "dependencies": { | ||
| "chalk": "^5.3.0", | ||
| "ajv": "^8.12.0", | ||
| "zod": "^3.22.0" | ||
| "zod": "^3.22.0", | ||
| "tmp": "^0.2.5" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" |
| Package | Version | Security advisories |
| tmp (npm) | 0.2.5 | None |
| allowedDotfiles: ['.env.example'], | ||
| }; | ||
|
|
||
| writeFileSync(configPath, JSON.stringify(validConfig, null, 2)); |
Check failure
Code scanning / CodeQL
Insecure temporary file High test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 23 hours ago
In general, to fix insecure temp file/directory issues, avoid manually composing paths under os.tmpdir() and instead delegate to a library or API that securely creates a uniquely named, private temp file or directory (e.g., the tmp npm package). This prevents reuse of existing paths and ensures restrictive permissions.
For this specific test file, the problem stems from setupTestDir() building testDir = join(tmpdir(), \appfactory-test-${Date.now()}`);and usingmkdirSyncdirectly. The safest, least invasive fix is to usetmp’s dirSynchelper to create a secure temporary directory and return its name, preserving the rest of the test logic. We can reuse that directory for each test invocation and still clean it up withrmSync` as before.
Concretely:
- Add an import for
tmpat the top ofcore/src/__tests__/config-loader.test.js. - Change
setupTestDir()so it callstmp.dirSync({ unsafeCleanup: true, prefix: 'appfactory-test-' }), assignstestDir = tmpDir.name, and returns that path. We can also store thetmpDirobject in a new variable (e.g.,tmpDirHandle) so we could call its.removeCallback()if desired, but since we already callrmSync(testDir, { recursive: true, force: true }), it is sufficient to keep usingtestDiralone. - Leave the rest of the tests unchanged: they just receive a directory path and write files under it.
All changes are confined to the shown file and lines around the setupTestDir function and imports.
| @@ -7,6 +7,7 @@ | ||
| import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { tmpdir } from 'node:os'; | ||
| import tmp from 'tmp'; | ||
|
|
||
| import { | ||
| loadPipelineConfig, | ||
| @@ -23,8 +24,8 @@ | ||
|
|
||
| // Setup test directory before each test | ||
| function setupTestDir() { | ||
| testDir = join(tmpdir(), `appfactory-test-${Date.now()}`); | ||
| mkdirSync(testDir, { recursive: true }); | ||
| const tmpDir = tmp.dirSync({ unsafeCleanup: true, prefix: 'appfactory-test-' }); | ||
| testDir = tmpDir.name; | ||
| return testDir; | ||
| } | ||
|
|
| @@ -44,7 +44,8 @@ | ||
| "dependencies": { | ||
| "chalk": "^5.3.0", | ||
| "ajv": "^8.12.0", | ||
| "zod": "^3.22.0" | ||
| "zod": "^3.22.0", | ||
| "tmp": "^0.2.5" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" |
| Package | Version | Security advisories |
| tmp (npm) | 0.2.5 | None |
| }, | ||
| }; | ||
|
|
||
| writeFileSync(configPath, JSON.stringify(validConfig, null, 2)); |
Check failure
Code scanning / CodeQL
Insecure temporary file High test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 23 hours ago
To fix the issue, stop manually constructing a temporary directory path under os.tmpdir() and instead use a secure temporary directory creator that guarantees uniqueness and appropriate permissions. In Node 18+, fs.mkdtempSync provides this functionality; it creates a new directory under a given prefix in the system temp dir, ensuring a unique name and leaving permissions to the OS/umask. This is sufficient here and avoids adding a new dependency.
The best targeted change is to:
- Import
mkdtempSyncfromnode:fs. - Update
setupTestDirto callmkdtempSync(join(tmpdir(), 'appfactory-test-'))instead of building the directory name withDate.now()and callingmkdirSync. This preserves all existing call sites and behavior (you still get a fresh temp directory for tests) while making the directory creation secure and non-predictable.
Concretely, in core/src/__tests__/config-loader.test.js:
- Modify the import on line 7 to include
mkdtempSync. - Replace the body of
setupTestDir(lines 25–28) so thattestDiris assigned frommkdtempSync(join(tmpdir(), 'appfactory-test-'))and returned, removing the explicitmkdirSynccall.
No other code changes are needed; cleanup via rmSync still works with the new directory path.
| @@ -4,7 +4,7 @@ | ||
|
|
||
| import { test, describe } from 'node:test'; | ||
| import assert from 'node:assert'; | ||
| import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; | ||
| import { writeFileSync, mkdirSync, mkdtempSync, rmSync } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { tmpdir } from 'node:os'; | ||
|
|
||
| @@ -23,8 +23,7 @@ | ||
|
|
||
| // Setup test directory before each test | ||
| function setupTestDir() { | ||
| testDir = join(tmpdir(), `appfactory-test-${Date.now()}`); | ||
| mkdirSync(testDir, { recursive: true }); | ||
| testDir = mkdtempSync(join(tmpdir(), 'appfactory-test-')); | ||
| return testDir; | ||
| } | ||
|
|
| }, | ||
| }; | ||
|
|
||
| writeFileSync(configPath, JSON.stringify(validConfig, null, 2)); |
Check failure
Code scanning / CodeQL
Insecure temporary file High test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 23 hours ago
In general, to avoid insecure temporary file and directory creation, do not manually assemble paths under os.tmpdir() using predictable names. Instead, use a library that creates unique, securely permissioned temp locations, such as the tmp package, or (for directories) use fs.mkdtemp/fs.mkdtempSync with a random suffix. These approaches ensure that the location does not already exist and is hard to predict.
For this specific file, the simplest, least invasive fix is to change setupTestDir() so that it uses a secure temporary directory creation API rather than join(tmpdir(), \appfactory-test-${Date.now()}`)plusmkdirSync. The tests already treat setupTestDir()` as an opaque helper that returns a usable directory path, so we can change its internals without affecting behavior. Two reasonable options:
- Use Node’s built-in
mkdtempSyncagainsttmpdir()plus a prefix, or - Use the
tmplibrary’sdirSynchelper.
Given the project’s own recommendation to use the tmp library and the example given, we’ll follow that recommendation: import dirSync from tmp and let it create a secure temp directory. Concretely:
- Add an import for
dirSyncfrom thetmppackage at the top ofcore/src/__tests__/config-loader.test.js. - Replace
setupTestDir()’s body so that it callsdirSync({ unsafeCleanup: true })and uses the returnednameproperty astestDir. This ensures a uniquely named, secure temp directory and also allows robust cleanup of contents when we callrmSyncas we already do.
No other tests need to change, because they all use setupTestDir() and cleanupTestDir() as before.
| @@ -7,6 +7,7 @@ | ||
| import { writeFileSync, mkdirSync, rmSync } from 'node:fs'; | ||
| import { join } from 'node:path'; | ||
| import { tmpdir } from 'node:os'; | ||
| import { dirSync } from 'tmp'; | ||
|
|
||
| import { | ||
| loadPipelineConfig, | ||
| @@ -23,8 +24,8 @@ | ||
|
|
||
| // Setup test directory before each test | ||
| function setupTestDir() { | ||
| testDir = join(tmpdir(), `appfactory-test-${Date.now()}`); | ||
| mkdirSync(testDir, { recursive: true }); | ||
| const tmpDir = dirSync({ unsafeCleanup: true }); | ||
| testDir = tmpDir.name; | ||
| return testDir; | ||
| } | ||
|
|
| @@ -44,7 +44,8 @@ | ||
| "dependencies": { | ||
| "chalk": "^5.3.0", | ||
| "ajv": "^8.12.0", | ||
| "zod": "^3.22.0" | ||
| "zod": "^3.22.0", | ||
| "tmp": "^0.2.5" | ||
| }, | ||
| "engines": { | ||
| "node": ">=18.0.0" |
| Package | Version | Security advisories |
| tmp (npm) | 0.2.5 | None |
Updates multiple outdated dependencies to their latest stable versions.
What Changed
Key Benefits
Testing
✅ All existing tests pass (252/252)
✅ No new vulnerabilities introduced
✅ Dependencies install cleanly
✅ Core functionality verified
Risk Assessment