argusqa-os 9.8.0 → 9.8.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.
package/README.md CHANGED
@@ -62,7 +62,7 @@ Argus scans your app and either posts findings to Slack or opens a local `report
62
62
 
63
63
  ## What Argus Catches
64
64
 
65
- 32 analysis engines, 140 distinct issue types, zero test-file maintenance:
65
+ 32 analysis engines, 149 distinct issue types, zero test-file maintenance:
66
66
 
67
67
  | Category | What it detects |
68
68
  |---|---|
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argusqa-os",
3
- "version": "9.8.0",
3
+ "version": "9.8.1",
4
4
  "mcpName": "io.github.ironclawdevs27/argus",
5
5
  "description": "Argus — AI-powered automated dev-testing platform using Chrome DevTools MCP and Claude Code",
6
6
  "keywords": [
@@ -76,10 +76,10 @@
76
76
  "zod": "^4.4.3"
77
77
  },
78
78
  "devDependencies": {
79
- "@vitest/coverage-v8": "^4.1.8",
79
+ "@vitest/coverage-v8": "^4.1.9",
80
80
  "c8": "^11.0.0",
81
81
  "fast-check": "^4.8.0",
82
82
  "istanbul-lib-coverage": "^3.2.2",
83
- "vitest": "^4.1.8"
83
+ "vitest": "^4.1.9"
84
84
  }
85
85
  }
package/src/cli/init.js CHANGED
@@ -288,7 +288,9 @@ async function main() {
288
288
  const targetsContent = generateTargetsJs(finalRoutes, { framework, sourceDir, envFile: envFilePath });
289
289
 
290
290
  try {
291
- fs.writeFileSync('.env', envContent, { flag: 'wx', encoding: 'utf8' });
291
+ // .env holds Slack / GitHub / Figma tokens + the auth password — create it owner-only
292
+ // (0600) so credentials are never world-readable on shared / POSIX / CI hosts.
293
+ fs.writeFileSync('.env', envContent, { flag: 'wx', encoding: 'utf8', mode: 0o600 });
292
294
  tick('Wrote .env');
293
295
  } catch (err) {
294
296
  if (err.code === 'EEXIST') {
@@ -31,7 +31,6 @@ const logger = childLogger('import-graph');
31
31
 
32
32
  // Source extensions we parse + resolve, in resolution-preference order.
33
33
  export const SOURCE_EXTS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'];
34
- const SOURCE_EXT_SET = new Set(SOURCE_EXTS);
35
34
  const INDEX_BASENAMES = SOURCE_EXTS.map(e => `index${e}`);
36
35
 
37
36
  // Stylesheet (asset) extensions tracked as LEAF nodes in the graph (PR_VALIDATOR C3): a changed
@@ -243,8 +242,15 @@ export function buildImportGraph(rootDir) {
243
242
 
244
243
  let src;
245
244
  try {
246
- if (fs.statSync(file).size > MAX_FILE_BYTES) continue; // skip giant files
247
- src = fs.readFileSync(file, 'utf8');
245
+ // Open once and stat/read the SAME descriptor — avoids a stat→read TOCTOU on `file`
246
+ // (CodeQL js/file-system-race). The size guard still skips pathologically large files.
247
+ const fd = fs.openSync(file, 'r');
248
+ try {
249
+ if (fs.fstatSync(fd).size > MAX_FILE_BYTES) continue; // skip giant files
250
+ src = fs.readFileSync(fd, 'utf8');
251
+ } finally {
252
+ fs.closeSync(fd);
253
+ }
248
254
  } catch { continue; }
249
255
 
250
256
  for (const spec of parseImports(src)) {
@@ -366,8 +366,6 @@ export function mapFilesToRoutesDeep(changedFiles, routes, { sourceDir } = {}) {
366
366
  if (!routeFileToPaths.has(file)) routeFileToPaths.set(file, new Set());
367
367
  routeFileToPaths.get(file).add(rp);
368
368
  }
369
- const routeFileSet = new Set(routeFileToPaths.keys());
370
-
371
369
  // Resolve every changed app file to the route paths it can affect.
372
370
  const resolvedPaths = new Set();
373
371
  for (const f of appFiles) {
@@ -112,8 +112,13 @@ export async function saveSession(browser, sessionFile) {
112
112
 
113
113
  const tmpFile = `${sessionFile}.tmp`;
114
114
  try {
115
- fs.writeFileSync(tmpFile, JSON.stringify(state, null, 2), 'utf8');
115
+ // Session state holds cookies + Web Storage (auth material), so write it owner-only
116
+ // (0600) — never world-readable on shared / POSIX / CI hosts. Hardening for the Socket
117
+ // supply-chain note on this module. chmod after rename is best-effort (no-op on Windows,
118
+ // where file access is ACL-based rather than POSIX mode bits).
119
+ fs.writeFileSync(tmpFile, JSON.stringify(state, null, 2), { encoding: 'utf8', mode: 0o600 });
116
120
  fs.renameSync(tmpFile, sessionFile);
121
+ try { fs.chmodSync(sessionFile, 0o600); } catch { /* mode bits unsupported on this platform */ }
117
122
  } catch (err) {
118
123
  throw new Error(`[ARGUS] saveSession: failed to write session file "${sessionFile}": ${err.message}`);
119
124
  }