codiedev 0.9.47 → 0.9.49

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/dist/codie.js CHANGED
@@ -172,10 +172,12 @@ function installBrandWordmarkUnsafe(runtime) {
172
172
  async function runNonInteractive(runtime, runtimeArgs, env) {
173
173
  const detached = process.platform !== "win32";
174
174
  const child = (0, child_process_1.spawn)(runtime, runtimeArgs, {
175
- stdio: ["inherit", "pipe", "pipe"],
175
+ stdio: ["pipe", "pipe", "pipe"],
176
176
  env,
177
177
  detached,
178
178
  });
179
+ if (child.stdin)
180
+ process.stdin.pipe(child.stdin);
179
181
  const signalChild = (signal) => {
180
182
  if (detached && child.pid) {
181
183
  try {
@@ -261,11 +263,15 @@ async function runNonInteractive(runtime, runtimeArgs, env) {
261
263
  stderrGate.push(Buffer.from(chunk), Boolean(blockReason));
262
264
  });
263
265
  child.once("error", (error) => {
266
+ if (child.stdin)
267
+ process.stdin.unpipe(child.stdin);
264
268
  process.removeListener("SIGINT", forwardInterrupt);
265
269
  process.removeListener("SIGTERM", forwardTermination);
266
270
  reject(error);
267
271
  });
268
272
  child.once("close", (status) => {
273
+ if (child.stdin)
274
+ process.stdin.unpipe(child.stdin);
269
275
  process.removeListener("SIGINT", forwardInterrupt);
270
276
  process.removeListener("SIGTERM", forwardTermination);
271
277
  stdoutGate.finish(Boolean(blockReason));
@@ -9,6 +9,7 @@ const securityDeepScan_1 = require("../securityDeepScan");
9
9
  const utils_1 = require("../utils");
10
10
  const securityDoctor_1 = require("../securityDoctor");
11
11
  const securityFeature_1 = require("../securityFeature");
12
+ const SECURITY_USAGE = "Usage: codiedev security <doctor|pilot|inventory|scan|sync|rollback> [--json] [--deep] [--connect-mcp] [--supply-chain] [--no-upload] [--yes]";
12
13
  function printPilot(json) {
13
14
  const report = (0, securityPilot_1.runSyntheticSecurityPilot)();
14
15
  if (json) {
@@ -40,6 +41,10 @@ function printDoctor(json, companyId) {
40
41
  async function runSecurityCommand(args) {
41
42
  const subcommand = args.find((arg) => !arg.startsWith("-")) ?? "doctor";
42
43
  const json = args.includes("--json");
44
+ if (args.includes("--help") || args.includes("-h") || subcommand === "help") {
45
+ console.log(SECURITY_USAGE);
46
+ return;
47
+ }
43
48
  const connectedConfig = (0, utils_1.readConfig)();
44
49
  const requiresEntitlement = !["pilot", "self-test"].includes(subcommand);
45
50
  if (requiresEntitlement && (!connectedConfig || !(0, securityFeature_1.isAgentSecurityEnabled)(connectedConfig))) {
@@ -144,7 +149,7 @@ async function runSecurityCommand(args) {
144
149
  ? printDoctor(json, connectedConfig.companyId)
145
150
  : false;
146
151
  if (!["pilot", "self-test", "doctor", "status"].includes(subcommand)) {
147
- console.error("Usage: codiedev security <doctor|pilot|inventory|scan|sync|rollback> [--json] [--deep] [--connect-mcp] [--supply-chain] [--no-upload] [--yes]");
152
+ console.error(SECURITY_USAGE);
148
153
  }
149
154
  if (!ok)
150
155
  process.exitCode = 1;
package/dist/security.js CHANGED
@@ -81,6 +81,13 @@ function effectivePolicyAction(policy, category, fallback, source, input) {
81
81
  const configured = policy.rules[category] ?? fallback;
82
82
  return policy.enforcementMode === "alert" && configured === "block" ? "alert" : configured;
83
83
  }
84
+ function policyActionPrefix(action) {
85
+ if (action === "block")
86
+ return "Codie blocked";
87
+ if (action === "alert")
88
+ return "Codie detected";
89
+ return "Codie detected but allowed";
90
+ }
84
91
  const SECRET_KEY = /(?:api[_-]?key|access[_-]?token|auth[_-]?token|password|passwd|secret|private[_-]?key|client[_-]?secret)/i;
85
92
  const SECRET_VALUE_PATTERNS = [
86
93
  /\b(?:sk|rk|pk)-(?:live|test|proj)?[-_A-Za-z0-9]{16,}\b/g,
@@ -131,7 +138,7 @@ function evaluatePromptSecurity(prompt, policy, source) {
131
138
  return {
132
139
  action,
133
140
  category: "secret_in_prompt",
134
- reason: "Codie blocked this prompt because it appears to contain an API key, password, or credential. Remove the secret value and reference the environment variable by name instead (for example, $OPENAI_API_KEY).",
141
+ reason: policyActionPrefix(action) + " this prompt because it appears to contain an API key, password, or credential. Remove the secret value and reference the environment variable by name instead (for example, $OPENAI_API_KEY).",
135
142
  };
136
143
  }
137
144
  function serializedToolInput(input) {
@@ -196,18 +203,20 @@ function evaluateToolSecurity(input, phase, policy, source, sessionContext) {
196
203
  if (!serialized)
197
204
  return { action: "allow" };
198
205
  if (destructiveTargetOutsideWorkspace(serialized, input.cwd)) {
206
+ const action = effectivePolicyAction(policy, "destructive_outside_workspace", "block", source, input);
199
207
  return {
200
- action: effectivePolicyAction(policy, "destructive_outside_workspace", "block", source, input),
208
+ action,
201
209
  category: "destructive_outside_workspace",
202
- reason: "Codie blocked a destructive command targeting files outside the approved workspace.",
210
+ reason: policyActionPrefix(action) + " a destructive command targeting files outside the approved workspace.",
203
211
  };
204
212
  }
205
213
  const hasNetworkEgress = /\b(?:curl|wget)\b|https?:\/\//i.test(serialized);
206
214
  if (hasNetworkEgress && containsSecretValue(serialized)) {
215
+ const action = effectivePolicyAction(policy, "secret_exfiltration", "block", source, input);
207
216
  return {
208
- action: effectivePolicyAction(policy, "secret_exfiltration", "block", source, input),
217
+ action,
209
218
  category: "secret_exfiltration",
210
- reason: "Codie blocked a command that would send credential material to an external destination.",
219
+ reason: policyActionPrefix(action) + " a command that would send credential material to an external destination.",
211
220
  };
212
221
  }
213
222
  if (hasNetworkEgress &&
@@ -221,17 +230,19 @@ function evaluateToolSecurity(input, phase, policy, source, sessionContext) {
221
230
  }
222
231
  const writeOperation = isWriteOperation(input, serialized);
223
232
  if (writeOperation && SENSITIVE_PATH.test(serialized)) {
233
+ const action = effectivePolicyAction(policy, "sensitive_file_write", "block", source, input);
224
234
  return {
225
- action: effectivePolicyAction(policy, "sensitive_file_write", "block", source, input),
235
+ action,
226
236
  category: "sensitive_file_write",
227
- reason: "Codie blocked a write to a credential-bearing file.",
237
+ reason: policyActionPrefix(action) + " a write to a credential-bearing file.",
228
238
  };
229
239
  }
230
240
  if (writeOperation && PROTECTED_AGENT_CONFIG.test(serialized)) {
241
+ const action = effectivePolicyAction(policy, "protected_agent_config_write", "block", source, input);
231
242
  return {
232
- action: effectivePolicyAction(policy, "protected_agent_config_write", "block", source, input),
243
+ action,
233
244
  category: "protected_agent_config_write",
234
- reason: "Codie blocked an agent from modifying its own hooks, policy, MCP, or instruction configuration.",
245
+ reason: policyActionPrefix(action) + " an agent modifying its own hooks, policy, MCP, or instruction configuration.",
235
246
  };
236
247
  }
237
248
  const server = mcpServerName(input);
@@ -313,10 +313,18 @@ function collectCodexToml(filePath, homeDir, workspace, components) {
313
313
  if (!raw)
314
314
  return;
315
315
  const text = raw.toString("utf8");
316
- const sections = [...text.matchAll(/^\[mcp_servers\.(["']?)([^\]"']+)\1\]\s*$([\s\S]*?)(?=^\[|\s*$)/gm)];
317
- for (const section of sections) {
318
- const name = section[2].trim();
319
- const body = section[3].trim();
316
+ const lines = text.split(/\r?\n/);
317
+ for (let index = 0; index < lines.length; index += 1) {
318
+ const section = lines[index].match(/^\s*\[mcp_servers\.(?:"([^"]+)"|'([^']+)'|([^\]]+))\]\s*(?:#.*)?$/);
319
+ if (!section)
320
+ continue;
321
+ const name = (section[1] ?? section[2] ?? section[3] ?? "").trim();
322
+ const bodyLines = [];
323
+ for (index += 1; index < lines.length && !/^\s*\[/.test(lines[index]); index += 1) {
324
+ bodyLines.push(lines[index]);
325
+ }
326
+ index -= 1;
327
+ const body = bodyLines.join("\n").trim();
320
328
  components.push(makeComponent({
321
329
  kind: "mcp-server", name, sourcePath: filePath, homeDir, workspace,
322
330
  content: body, findings: commandFindings(body),
@@ -443,11 +451,13 @@ function buildSecurityInventory(options = {}) {
443
451
  path.join(homeDir, ".config", "opencode", "opencode.jsonc"),
444
452
  path.join(homeDir, ".config", "Code", "User", "mcp.json"),
445
453
  path.join(homeDir, ".config", "Cursor", "User", "mcp.json"),
454
+ path.join(homeDir, ".codex", "hooks.json"),
446
455
  path.join(homeDir, "Library", "Application Support", "Code", "User", "mcp.json"),
447
456
  path.join(homeDir, "Library", "Application Support", "Cursor", "User", "mcp.json"),
448
457
  path.join(homeDir, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
449
458
  path.join(workspace, ".mcp.json"), path.join(workspace, ".cursor", "mcp.json"),
450
459
  path.join(workspace, ".vscode", "mcp.json"),
460
+ path.join(workspace, ".codex", "hooks.json"),
451
461
  path.join(workspace, ".claude", "settings.json"), path.join(workspace, ".claude", "settings.local.json"),
452
462
  path.join(workspace, "opencode.json"), path.join(workspace, "opencode.jsonc"),
453
463
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codiedev",
3
- "version": "0.9.47",
3
+ "version": "0.9.49",
4
4
  "description": "Connect Claude Code, Codex, Cursor, OpenCode, or VS Code Copilot to Codiedev for team session capture and artifact collaboration — and run the governed Codie harness",
5
5
  "bin": {
6
6
  "codiedev": "dist/cli.js",
@@ -12,6 +12,7 @@
12
12
  "dev": "tsc --watch",
13
13
  "prepublishOnly": "tsc",
14
14
  "test": "vitest run",
15
+ "test:security-beta": "vitest run src/__tests__/security.test.ts src/__tests__/securityCommandEntitlement.test.ts src/__tests__/securityDeepScan.test.ts src/__tests__/securityDoctor.test.ts src/__tests__/securityEntitlementInstall.test.ts src/__tests__/securityFeature.test.ts src/__tests__/securityInstall.test.ts src/__tests__/securityInventory.test.ts src/__tests__/securityPilot.test.ts src/__tests__/securityPolicy.test.ts src/__tests__/securitySession.test.ts src/__tests__/codexHookTrust.test.ts src/__tests__/codieSecurityAdapterWiring.test.ts && tsc && node dist/cli.js security pilot --json",
15
16
  "test:security-pilot": "vitest run src/__tests__/security.test.ts src/__tests__/securityInstall.test.ts src/__tests__/securityPilot.test.ts src/__tests__/codieSecurityAdapterWiring.test.ts && tsc && node dist/cli.js security pilot --json",
16
17
  "test:watch": "vitest"
17
18
  },