@harness-engineering/orchestrator 0.2.3 → 0.2.4

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/index.js CHANGED
@@ -988,7 +988,41 @@ var StructuredLogger = class {
988
988
  }
989
989
  };
990
990
 
991
+ // src/workspace/config-scanner.ts
992
+ var import_node_fs = require("fs");
993
+ var import_node_path = require("path");
994
+ var import_core2 = require("@harness-engineering/core");
995
+ var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
996
+ function scanSingleFile(filePath, targetDir, scanner) {
997
+ if (!(0, import_node_fs.existsSync)(filePath)) return null;
998
+ let content;
999
+ try {
1000
+ content = (0, import_node_fs.readFileSync)(filePath, "utf8");
1001
+ } catch {
1002
+ return null;
1003
+ }
1004
+ const injectionFindings = (0, import_core2.scanForInjection)(content);
1005
+ const findings = (0, import_core2.mapInjectionFindings)(injectionFindings);
1006
+ const secFindings = scanner.scanContent(content, filePath);
1007
+ findings.push(...(0, import_core2.mapSecurityFindings)(secFindings, findings));
1008
+ return {
1009
+ file: (0, import_node_path.relative)(targetDir, filePath).replaceAll("\\", "/"),
1010
+ findings,
1011
+ overallSeverity: (0, import_core2.computeOverallSeverity)(findings)
1012
+ };
1013
+ }
1014
+ async function scanWorkspaceConfig(workspacePath) {
1015
+ const scanner = new import_core2.SecurityScanner((0, import_core2.parseSecurityConfig)({}));
1016
+ const results = [];
1017
+ for (const configFile of CONFIG_FILES) {
1018
+ const result = scanSingleFile((0, import_node_path.join)(workspacePath, configFile), workspacePath, scanner);
1019
+ if (result) results.push(result);
1020
+ }
1021
+ return { exitCode: (0, import_core2.computeScanExitCode)(results), results };
1022
+ }
1023
+
991
1024
  // src/orchestrator.ts
1025
+ var import_core4 = require("@harness-engineering/core");
992
1026
  var Orchestrator = class extends import_node_events.EventEmitter {
993
1027
  state;
994
1028
  config;
@@ -1113,6 +1147,42 @@ var Orchestrator = class extends import_node_events.EventEmitter {
1113
1147
  const workspaceResult = await this.workspace.ensureWorkspace(issue.identifier);
1114
1148
  if (!workspaceResult.ok) throw workspaceResult.error;
1115
1149
  const workspacePath = workspaceResult.value;
1150
+ const scanResult = await scanWorkspaceConfig(workspacePath);
1151
+ if (scanResult.exitCode === 2) {
1152
+ const findingSummary = scanResult.results.flatMap((r) => r.findings.filter((f) => f.severity === "high")).map((f) => `${f.ruleId}: ${f.message}`).join("; ");
1153
+ this.logger.error(
1154
+ `Config scan blocked dispatch for ${issue.identifier}: ${findingSummary}`,
1155
+ { issueId: issue.id }
1156
+ );
1157
+ await this.emitWorkerExit(
1158
+ issue.id,
1159
+ "error",
1160
+ attempt,
1161
+ `Config scan found high-severity injection patterns: ${findingSummary}`
1162
+ );
1163
+ return;
1164
+ }
1165
+ if (scanResult.exitCode === 1) {
1166
+ const findings = scanResult.results.flatMap(
1167
+ (r) => r.findings.filter((f) => f.severity === "medium").map((f) => ({
1168
+ ruleId: f.ruleId,
1169
+ severity: f.severity,
1170
+ match: f.match,
1171
+ ...f.line !== void 0 ? { line: f.line } : {}
1172
+ }))
1173
+ );
1174
+ (0, import_core4.writeTaint)(
1175
+ workspacePath,
1176
+ issue.id,
1177
+ "Medium-severity injection patterns found in workspace config files",
1178
+ findings,
1179
+ "orchestrator:scan-config"
1180
+ );
1181
+ this.logger.warn(
1182
+ `Config scan found medium-severity patterns for ${issue.identifier}. Session tainted.`,
1183
+ { issueId: issue.id }
1184
+ );
1185
+ }
1116
1186
  const hookResult = await this.hooks.beforeRun(workspacePath);
1117
1187
  if (!hookResult.ok) throw hookResult.error;
1118
1188
  const prompt = await this.renderer.render(this.promptTemplate, {
package/dist/index.mjs CHANGED
@@ -939,7 +939,49 @@ var StructuredLogger = class {
939
939
  }
940
940
  };
941
941
 
942
+ // src/workspace/config-scanner.ts
943
+ import { existsSync, readFileSync } from "fs";
944
+ import { join as join2, relative } from "path";
945
+ import {
946
+ scanForInjection,
947
+ SecurityScanner,
948
+ parseSecurityConfig,
949
+ mapInjectionFindings,
950
+ mapSecurityFindings,
951
+ computeOverallSeverity,
952
+ computeScanExitCode
953
+ } from "@harness-engineering/core";
954
+ var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".gemini/settings.json", "skill.yaml"];
955
+ function scanSingleFile(filePath, targetDir, scanner) {
956
+ if (!existsSync(filePath)) return null;
957
+ let content;
958
+ try {
959
+ content = readFileSync(filePath, "utf8");
960
+ } catch {
961
+ return null;
962
+ }
963
+ const injectionFindings = scanForInjection(content);
964
+ const findings = mapInjectionFindings(injectionFindings);
965
+ const secFindings = scanner.scanContent(content, filePath);
966
+ findings.push(...mapSecurityFindings(secFindings, findings));
967
+ return {
968
+ file: relative(targetDir, filePath).replaceAll("\\", "/"),
969
+ findings,
970
+ overallSeverity: computeOverallSeverity(findings)
971
+ };
972
+ }
973
+ async function scanWorkspaceConfig(workspacePath) {
974
+ const scanner = new SecurityScanner(parseSecurityConfig({}));
975
+ const results = [];
976
+ for (const configFile of CONFIG_FILES) {
977
+ const result = scanSingleFile(join2(workspacePath, configFile), workspacePath, scanner);
978
+ if (result) results.push(result);
979
+ }
980
+ return { exitCode: computeScanExitCode(results), results };
981
+ }
982
+
942
983
  // src/orchestrator.ts
984
+ import { writeTaint } from "@harness-engineering/core";
943
985
  var Orchestrator = class extends EventEmitter {
944
986
  state;
945
987
  config;
@@ -1064,6 +1106,42 @@ var Orchestrator = class extends EventEmitter {
1064
1106
  const workspaceResult = await this.workspace.ensureWorkspace(issue.identifier);
1065
1107
  if (!workspaceResult.ok) throw workspaceResult.error;
1066
1108
  const workspacePath = workspaceResult.value;
1109
+ const scanResult = await scanWorkspaceConfig(workspacePath);
1110
+ if (scanResult.exitCode === 2) {
1111
+ const findingSummary = scanResult.results.flatMap((r) => r.findings.filter((f) => f.severity === "high")).map((f) => `${f.ruleId}: ${f.message}`).join("; ");
1112
+ this.logger.error(
1113
+ `Config scan blocked dispatch for ${issue.identifier}: ${findingSummary}`,
1114
+ { issueId: issue.id }
1115
+ );
1116
+ await this.emitWorkerExit(
1117
+ issue.id,
1118
+ "error",
1119
+ attempt,
1120
+ `Config scan found high-severity injection patterns: ${findingSummary}`
1121
+ );
1122
+ return;
1123
+ }
1124
+ if (scanResult.exitCode === 1) {
1125
+ const findings = scanResult.results.flatMap(
1126
+ (r) => r.findings.filter((f) => f.severity === "medium").map((f) => ({
1127
+ ruleId: f.ruleId,
1128
+ severity: f.severity,
1129
+ match: f.match,
1130
+ ...f.line !== void 0 ? { line: f.line } : {}
1131
+ }))
1132
+ );
1133
+ writeTaint(
1134
+ workspacePath,
1135
+ issue.id,
1136
+ "Medium-severity injection patterns found in workspace config files",
1137
+ findings,
1138
+ "orchestrator:scan-config"
1139
+ );
1140
+ this.logger.warn(
1141
+ `Config scan found medium-severity patterns for ${issue.identifier}. Session tainted.`,
1142
+ { issueId: issue.id }
1143
+ );
1144
+ }
1067
1145
  const hookResult = await this.hooks.beforeRun(workspacePath);
1068
1146
  if (!hookResult.ok) throw hookResult.error;
1069
1147
  const prompt = await this.renderer.render(this.promptTemplate, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harness-engineering/orchestrator",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Orchestrator daemon for dispatching coding agents to issues",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -41,8 +41,8 @@
41
41
  "chokidar": "^3.5.3",
42
42
  "ink": "^4.4.1",
43
43
  "react": "^18.2.0",
44
- "@harness-engineering/core": "0.13.1",
45
- "@harness-engineering/types": "0.3.1"
44
+ "@harness-engineering/core": "0.16.0",
45
+ "@harness-engineering/types": "0.6.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/node": "^22.0.0",