@gendigital/sage-opencode 0.9.0
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 +102 -0
- package/dist/bundled-dirs.d.ts +12 -0
- package/dist/bundled-dirs.d.ts.map +1 -0
- package/dist/bundled-dirs.js +29 -0
- package/dist/bundled-dirs.js.map +1 -0
- package/dist/error.d.ts +7 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +12 -0
- package/dist/error.js.map +1 -0
- package/dist/extractors.d.ts +6 -0
- package/dist/extractors.d.ts.map +1 -0
- package/dist/extractors.js +111 -0
- package/dist/extractors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +128 -0
- package/dist/index.js.map +1 -0
- package/dist/logger-adaptor.d.ts +15 -0
- package/dist/logger-adaptor.d.ts.map +1 -0
- package/dist/logger-adaptor.js +32 -0
- package/dist/logger-adaptor.js.map +1 -0
- package/dist/plugin-discovery.d.ts +12 -0
- package/dist/plugin-discovery.d.ts.map +1 -0
- package/dist/plugin-discovery.js +138 -0
- package/dist/plugin-discovery.js.map +1 -0
- package/dist/startup-scan.d.ts +7 -0
- package/dist/startup-scan.d.ts.map +1 -0
- package/dist/startup-scan.js +41 -0
- package/dist/startup-scan.js.map +1 -0
- package/dist/tool-handler.d.ts +14 -0
- package/dist/tool-handler.d.ts.map +1 -0
- package/dist/tool-handler.js +93 -0
- package/dist/tool-handler.js.map +1 -0
- package/package.json +60 -0
- package/resources/allowlists/trusted-installer-domains.yaml +55 -0
- package/resources/threats/LICENSE +45 -0
- package/resources/threats/commands.yaml +351 -0
- package/resources/threats/credentials.yaml +105 -0
- package/resources/threats/dummy.yaml +195 -0
- package/resources/threats/files.yaml +239 -0
- package/resources/threats/mac-commands.yaml +355 -0
- package/resources/threats/mac-credentials.yaml +99 -0
- package/resources/threats/mac-files.yaml +124 -0
- package/resources/threats/mac-obfuscation.yaml +92 -0
- package/resources/threats/mac-persistence.yaml +117 -0
- package/resources/threats/mac-supply-chain.yaml +40 -0
- package/resources/threats/mitre.yaml +810 -0
- package/resources/threats/obfuscation.yaml +98 -0
- package/resources/threats/persistence.yaml +87 -0
- package/resources/threats/prompt-injection.yaml +334 -0
- package/resources/threats/self-defense.yaml +55 -0
- package/resources/threats/supply_chain.yaml +15 -0
- package/resources/threats/urls.yaml +66 -0
- package/resources/threats/win-commands.yaml +785 -0
- package/resources/threats/win-credentials.yaml +128 -0
- package/resources/threats/win-files.yaml +124 -0
- package/resources/threats/win-obfuscation.yaml +205 -0
- package/resources/threats/win-persistence.yaml +100 -0
- package/resources/threats/win-supply-chain.yaml +15 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovers installed OpenCode plugins for plugin scanning.
|
|
3
|
+
* Scans NPM packages from config files and local plugin files.
|
|
4
|
+
*/
|
|
5
|
+
import { readdir, stat } from "node:fs/promises";
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
import { basename, join } from "node:path";
|
|
8
|
+
import { defaultBranding, getFileContent } from "@gendigital/sage-core";
|
|
9
|
+
/** Resolve XDG base directories with fallbacks to homedir defaults */
|
|
10
|
+
function getConfigHome() {
|
|
11
|
+
return process.env.XDG_CONFIG_HOME ?? join(homedir(), ".config");
|
|
12
|
+
}
|
|
13
|
+
function getCacheHome() {
|
|
14
|
+
return process.env.XDG_CACHE_HOME ?? join(homedir(), ".cache");
|
|
15
|
+
}
|
|
16
|
+
const PROJECT_CONFIG_NAME = "opencode.json";
|
|
17
|
+
/**
|
|
18
|
+
* Discover OpenCode plugins from all sources:
|
|
19
|
+
* 1. NPM packages from config files
|
|
20
|
+
* 2. Local plugin files (global + project)
|
|
21
|
+
*/
|
|
22
|
+
export async function discoverOpenCodePlugins(logger, projectDir, branding = defaultBranding) {
|
|
23
|
+
logger.debug(`${branding.name} plugin discovery: scanning OpenCode plugins`);
|
|
24
|
+
const plugins = [];
|
|
25
|
+
// 1. Discover NPM plugins from config files
|
|
26
|
+
const npmPlugins = await discoverNpmPlugins(logger, projectDir);
|
|
27
|
+
plugins.push(...npmPlugins);
|
|
28
|
+
// 2. Discover local plugin files (global)
|
|
29
|
+
const globalPluginsDir = join(getConfigHome(), "opencode", "plugins");
|
|
30
|
+
const globalPlugins = await discoverLocalPlugins(globalPluginsDir, "global", logger);
|
|
31
|
+
plugins.push(...globalPlugins);
|
|
32
|
+
// 3. Discover local plugin files (project)
|
|
33
|
+
if (projectDir) {
|
|
34
|
+
const projectPluginsDir = join(projectDir, ".opencode", "plugins");
|
|
35
|
+
const projectPlugins = await discoverLocalPlugins(projectPluginsDir, "project", logger);
|
|
36
|
+
plugins.push(...projectPlugins);
|
|
37
|
+
}
|
|
38
|
+
logger.info(`${branding.name} plugin discovery: found ${plugins.length} plugin(s)`);
|
|
39
|
+
return plugins;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Discover NPM plugins listed in config files
|
|
43
|
+
*/
|
|
44
|
+
async function discoverNpmPlugins(logger, projectDir) {
|
|
45
|
+
const plugins = [];
|
|
46
|
+
const pluginNames = new Set();
|
|
47
|
+
// Read global config
|
|
48
|
+
try {
|
|
49
|
+
const globalConfigPath = join(getConfigHome(), "opencode", "opencode.json");
|
|
50
|
+
const globalConfig = JSON.parse(await getFileContent(globalConfigPath));
|
|
51
|
+
const globalPlugins = (globalConfig.plugin ?? []);
|
|
52
|
+
for (const name of globalPlugins) {
|
|
53
|
+
pluginNames.add(name);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
logger.debug("Global OpenCode config not found or invalid");
|
|
58
|
+
}
|
|
59
|
+
// Read project config (overrides global)
|
|
60
|
+
if (projectDir) {
|
|
61
|
+
try {
|
|
62
|
+
const projectConfigPath = join(projectDir, PROJECT_CONFIG_NAME);
|
|
63
|
+
const projectConfig = JSON.parse(await getFileContent(projectConfigPath));
|
|
64
|
+
const projectPlugins = (projectConfig.plugin ?? []);
|
|
65
|
+
for (const name of projectPlugins) {
|
|
66
|
+
pluginNames.add(name);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
logger.debug("Project OpenCode config not found or invalid");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// For each plugin name, find it in node_modules
|
|
74
|
+
const npmCacheDir = join(getCacheHome(), "opencode", "node_modules");
|
|
75
|
+
for (const pluginName of pluginNames) {
|
|
76
|
+
try {
|
|
77
|
+
const installPath = join(npmCacheDir, pluginName);
|
|
78
|
+
const pkgJsonPath = join(installPath, "package.json");
|
|
79
|
+
const pkgJson = JSON.parse(await getFileContent(pkgJsonPath));
|
|
80
|
+
const stats = await stat(installPath);
|
|
81
|
+
const version = pkgJson.version ?? "unknown";
|
|
82
|
+
const key = `${pluginName}@${version}`;
|
|
83
|
+
plugins.push({
|
|
84
|
+
key,
|
|
85
|
+
installPath,
|
|
86
|
+
version,
|
|
87
|
+
lastUpdated: stats.mtime.toISOString(),
|
|
88
|
+
});
|
|
89
|
+
logger.debug(`Discovered NPM plugin: ${key}`, { installPath });
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
logger.warn(`NPM plugin listed in config but not found: ${pluginName}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return plugins;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Discover local plugin files (.js/.ts) in a directory
|
|
99
|
+
*/
|
|
100
|
+
async function discoverLocalPlugins(pluginsDir, context, logger) {
|
|
101
|
+
const plugins = [];
|
|
102
|
+
let entries;
|
|
103
|
+
try {
|
|
104
|
+
entries = await readdir(pluginsDir);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
logger.debug(`${context} plugins directory not found: ${pluginsDir}`);
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
const fullPath = join(pluginsDir, entry);
|
|
112
|
+
// Only scan .js and .ts files
|
|
113
|
+
if (!(entry.endsWith(".js") || entry.endsWith(".ts"))) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const stats = await stat(fullPath);
|
|
118
|
+
if (!stats.isFile())
|
|
119
|
+
continue;
|
|
120
|
+
// Use filename as plugin name
|
|
121
|
+
const name = basename(entry, entry.endsWith(".ts") ? ".ts" : ".js");
|
|
122
|
+
const version = `local-${stats.mtime.getTime()}`; // Synthetic version from mtime
|
|
123
|
+
const key = `${context}/${name}@${version}`;
|
|
124
|
+
plugins.push({
|
|
125
|
+
key,
|
|
126
|
+
installPath: fullPath,
|
|
127
|
+
version,
|
|
128
|
+
lastUpdated: stats.mtime.toISOString(),
|
|
129
|
+
});
|
|
130
|
+
logger.debug(`Discovered local plugin: ${key}`, { path: fullPath });
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
logger.warn(`Failed to read local plugin: ${entry}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return plugins;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=plugin-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-discovery.js","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup and session scan handlers for OpenCode.
|
|
3
|
+
* Thin wrapper over core's createScanHandler.
|
|
4
|
+
*/
|
|
5
|
+
import { type Branding, type Logger } from "@gendigital/sage-core";
|
|
6
|
+
export declare function createSessionScanHandler(logger: Logger, projectDir?: string, onResult?: (msg: string) => void, branding?: Branding): () => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=startup-scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-scan.d.ts","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACN,KAAK,QAAQ,EAGb,KAAK,MAAM,EACX,MAAM,uBAAuB,CAAC;AAmB/B,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,QAAQ,GAAE,QAA0B,GAClC,MAAM,OAAO,CAAC,IAAI,CAAC,CAiBrB"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Startup and session scan handlers for OpenCode.
|
|
3
|
+
* Thin wrapper over core's createScanHandler.
|
|
4
|
+
*/
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import { createScanHandler as coreScanHandler, defaultBranding, } from "@gendigital/sage-core";
|
|
7
|
+
import { getBundledDataDirs, getSageVersion } from "./bundled-dirs.js";
|
|
8
|
+
import { discoverOpenCodePlugins } from "./plugin-discovery.js";
|
|
9
|
+
/**
|
|
10
|
+
* OpenCode is published as an unbundled ESM plugin (tsc only). The model
|
|
11
|
+
* download worker therefore lives in the `@gendigital/sage-core` package
|
|
12
|
+
* as `dist/model-download-worker.js`. Resolve via `require.resolve` so we
|
|
13
|
+
* pick it up wherever pnpm/node placed it.
|
|
14
|
+
*/
|
|
15
|
+
function resolveModelDownloadWorkerPath() {
|
|
16
|
+
try {
|
|
17
|
+
const req = createRequire(import.meta.url);
|
|
18
|
+
return req.resolve("@gendigital/sage-core/dist/model-download-worker.js");
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function createSessionScanHandler(logger, projectDir, onResult, branding = defaultBranding) {
|
|
25
|
+
const { threatsDir, allowlistsDir } = getBundledDataDirs();
|
|
26
|
+
const version = getSageVersion();
|
|
27
|
+
return coreScanHandler({
|
|
28
|
+
logger,
|
|
29
|
+
context: "session",
|
|
30
|
+
discoverPlugins: () => discoverOpenCodePlugins(logger, projectDir, branding),
|
|
31
|
+
selfPrefix: "@gendigital/sage-opencode@",
|
|
32
|
+
threatsDir,
|
|
33
|
+
allowlistsDir,
|
|
34
|
+
version,
|
|
35
|
+
agentRuntime: "opencode",
|
|
36
|
+
branding,
|
|
37
|
+
onResult,
|
|
38
|
+
modelDownloadWorkerPath: resolveModelDownloadWorkerPath(),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=startup-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup-scan.js","sourceRoot":"","sources":["../src/startup-scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAEN,iBAAiB,IAAI,eAAe,EACpC,eAAe,GAEf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;;;GAKG;AACH,SAAS,8BAA8B;IACtC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3C,OAAO,GAAG,CAAC,OAAO,CAAC,qDAAqD,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,wBAAwB,CACvC,MAAc,EACd,UAAmB,EACnB,QAAgC,EAChC,WAAqB,eAAe;IAEpC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,kBAAkB,EAAE,CAAC;IAC3D,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IAEjC,OAAO,eAAe,CAAC;QACtB,MAAM;QACN,OAAO,EAAE,SAAS;QAClB,eAAe,EAAE,GAAG,EAAE,CAAC,uBAAuB,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC;QAC5E,UAAU,EAAE,4BAA4B;QACxC,UAAU;QACV,aAAa;QACb,OAAO;QACP,YAAY,EAAE,UAAU;QACxB,QAAQ;QACR,QAAQ;QACR,uBAAuB,EAAE,8BAA8B,EAAE;KACzD,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ApprovalStore, type Branding, type Logger } from "@gendigital/sage-core";
|
|
2
|
+
export interface ToolHandlerOptions {
|
|
3
|
+
showToast?: (msg: string, variant: "info" | "success" | "warning" | "error") => void;
|
|
4
|
+
}
|
|
5
|
+
export declare function createToolHandlers(logger: Logger, approvalStore: ApprovalStore, threatsDir: string, allowlistsDir: string, options?: ToolHandlerOptions, branding?: Branding): {
|
|
6
|
+
"tool.execute.before": (input: {
|
|
7
|
+
tool: string;
|
|
8
|
+
sessionID: string;
|
|
9
|
+
callID: string;
|
|
10
|
+
}, output: {
|
|
11
|
+
args: Record<string, unknown>;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=tool-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,EAOb,KAAK,MAAM,EACX,MAAM,uBAAuB,CAAC;AA+C/B,MAAM,WAAW,kBAAkB;IAClC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,KAAK,IAAI,CAAC;CACrF;AAED,wBAAgB,kBAAkB,CACjC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,aAAa,EAC5B,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE,kBAAkB,EAC5B,QAAQ,GAAE,QAA0B;mCAG5B;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,UAClD;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KACvC,OAAO,CAAC,IAAI,CAAC;EA+DhB"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { canonicalizeToolName, defaultBranding, formatAskMessage, formatDenyMessage, guardToolCall, } from "@gendigital/sage-core";
|
|
2
|
+
const OPENCODE_TOOL_MAP = {
|
|
3
|
+
bash: "Bash",
|
|
4
|
+
webfetch: "WebFetch",
|
|
5
|
+
write: "Write",
|
|
6
|
+
edit: "Edit",
|
|
7
|
+
read: "Read",
|
|
8
|
+
glob: "Glob",
|
|
9
|
+
grep: "Grep",
|
|
10
|
+
ls: "List",
|
|
11
|
+
codesearch: "CodeSearch",
|
|
12
|
+
websearch: "WebSearch",
|
|
13
|
+
question: "Question",
|
|
14
|
+
task: "Task",
|
|
15
|
+
read_lines: "ReadLines",
|
|
16
|
+
};
|
|
17
|
+
import { SageVerdictBlockError, SageVerdictError } from "./error.js";
|
|
18
|
+
import { extractFromOpenCodeTool } from "./extractors.js";
|
|
19
|
+
function asString(value) {
|
|
20
|
+
return typeof value === "string" ? value : undefined;
|
|
21
|
+
}
|
|
22
|
+
function normalizeToolInput(toolName, args) {
|
|
23
|
+
switch (toolName) {
|
|
24
|
+
case "write":
|
|
25
|
+
return {
|
|
26
|
+
...args,
|
|
27
|
+
file_path: asString(args.filePath) ?? asString(args.file_path) ?? "",
|
|
28
|
+
content: asString(args.content) ?? "",
|
|
29
|
+
};
|
|
30
|
+
case "edit":
|
|
31
|
+
return {
|
|
32
|
+
...args,
|
|
33
|
+
file_path: asString(args.filePath) ?? asString(args.file_path) ?? "",
|
|
34
|
+
new_string: asString(args.newString) ?? asString(args.new_string) ?? "",
|
|
35
|
+
};
|
|
36
|
+
default:
|
|
37
|
+
return args;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function createToolHandlers(logger, approvalStore, threatsDir, allowlistsDir, options, branding = defaultBranding) {
|
|
41
|
+
const beforeToolUse = async (input, output) => {
|
|
42
|
+
logger.debug(`tool.execute.before hook invoked (tool=${input.tool})`);
|
|
43
|
+
try {
|
|
44
|
+
const args = output.args ?? {};
|
|
45
|
+
const artifacts = extractFromOpenCodeTool(input.tool, args);
|
|
46
|
+
if (!artifacts || artifacts.length === 0) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const { verdict, actionId } = await guardToolCall({
|
|
50
|
+
sessionId: input.sessionID,
|
|
51
|
+
conversationId: input.sessionID,
|
|
52
|
+
agentRuntime: "opencode",
|
|
53
|
+
toolName: canonicalizeToolName(OPENCODE_TOOL_MAP, input.tool),
|
|
54
|
+
toolInput: normalizeToolInput(input.tool, args),
|
|
55
|
+
artifacts,
|
|
56
|
+
}, {
|
|
57
|
+
threatsDir,
|
|
58
|
+
allowlistsDir,
|
|
59
|
+
logger,
|
|
60
|
+
}, approvalStore);
|
|
61
|
+
if (verdict.decision === "allow") {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const toastMsg = verdict.decision === "deny"
|
|
66
|
+
? `${branding.name} blocked: ${verdict.reasons[0] ?? "Threat detected"} (${verdict.category})`
|
|
67
|
+
: `${branding.name} flagged: ${verdict.reasons[0] ?? "Action flagged"} (${verdict.category})`;
|
|
68
|
+
options?.showToast?.(toastMsg, verdict.severity === "critical" ? "error" : "warning");
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Toast failure is non-critical — never prevent enforcement
|
|
72
|
+
}
|
|
73
|
+
if (verdict.decision === "deny") {
|
|
74
|
+
throw new SageVerdictBlockError(formatDenyMessage(verdict, branding));
|
|
75
|
+
}
|
|
76
|
+
// ask — actionId is always set for ask verdicts
|
|
77
|
+
throw new SageVerdictBlockError(formatAskMessage(actionId, verdict, artifacts, branding));
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// Verdict errors are expected (blocks and asks); others are logged as fail-open
|
|
81
|
+
if (error instanceof SageVerdictError)
|
|
82
|
+
throw error;
|
|
83
|
+
logger.error(`${branding.name} opencode hook failed open`, {
|
|
84
|
+
error: String(error),
|
|
85
|
+
tool: input.tool,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
"tool.execute.before": beforeToolUse,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=tool-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gendigital/sage-opencode",
|
|
3
|
+
"license": "Apache-2.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"access": "public"
|
|
6
|
+
},
|
|
7
|
+
"version": "0.9.0",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"description": "Safety for Agents - ADR layer for OpenCode",
|
|
10
|
+
"homepage": "https://github.com/gendigitalinc/sage",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/gendigitalinc/sage.git",
|
|
14
|
+
"directory": "packages/opencode"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/gendigitalinc/sage/issues"
|
|
18
|
+
},
|
|
19
|
+
"main": "./dist/index.js",
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist/**",
|
|
28
|
+
"resources/**",
|
|
29
|
+
"package.json",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@gendigital/sage-core": "0.9.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@opencode-ai/plugin": "^1.2.10",
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"typescript": "^5.9.0",
|
|
40
|
+
"vitest": "^4.0.0"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"opencode",
|
|
47
|
+
"opencode-plugin",
|
|
48
|
+
"security",
|
|
49
|
+
"adr",
|
|
50
|
+
"agent-security",
|
|
51
|
+
"safety",
|
|
52
|
+
"malware-detection"
|
|
53
|
+
],
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "pnpm -C ../core build && pnpm run clean && pnpm run sync:assets && tsc",
|
|
56
|
+
"clean": "node ../../scripts/clean.mjs dist resources tsconfig.tsbuildinfo",
|
|
57
|
+
"sync:assets": "node scripts/sync-assets.mjs",
|
|
58
|
+
"test": "vitest run"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Trusted installer domains for Sage
|
|
2
|
+
#
|
|
3
|
+
# Pipe-to-shell commands (curl | bash) targeting these domains are suppressed
|
|
4
|
+
# from CLT-CMD-001, CLT-CMD-002, CLT-SUPPLY-001, and CLT-SUPPLY-004 heuristic matches.
|
|
5
|
+
#
|
|
6
|
+
# Only dedicated installer endpoints are listed here — generic hosting
|
|
7
|
+
# platforms (e.g. raw.githubusercontent.com) are deliberately excluded.
|
|
8
|
+
#
|
|
9
|
+
# Format: list of {domain, reason} entries. Domains are matched by suffix
|
|
10
|
+
# with dot boundary (e.g. "bun.sh" matches "cdn.bun.sh" but not "notbun.sh").
|
|
11
|
+
|
|
12
|
+
- domain: bun.sh
|
|
13
|
+
reason: Bun JavaScript runtime installer
|
|
14
|
+
|
|
15
|
+
- domain: astral.sh
|
|
16
|
+
reason: Astral tools (uv, ruff) installer
|
|
17
|
+
|
|
18
|
+
- domain: brew.sh
|
|
19
|
+
reason: Homebrew package manager installer
|
|
20
|
+
|
|
21
|
+
- domain: sh.rustup.rs
|
|
22
|
+
reason: Rust toolchain installer (rustup)
|
|
23
|
+
|
|
24
|
+
- domain: rustup.rs
|
|
25
|
+
reason: Rust toolchain installer (alternate domain)
|
|
26
|
+
|
|
27
|
+
- domain: get.docker.com
|
|
28
|
+
reason: Docker installer
|
|
29
|
+
|
|
30
|
+
- domain: install.python-poetry.org
|
|
31
|
+
reason: Python Poetry installer
|
|
32
|
+
|
|
33
|
+
- domain: get.volta.sh
|
|
34
|
+
reason: Volta Node.js version manager installer
|
|
35
|
+
|
|
36
|
+
- domain: volta.sh
|
|
37
|
+
reason: Volta Node.js version manager (alternate domain)
|
|
38
|
+
|
|
39
|
+
- domain: get.sdkman.io
|
|
40
|
+
reason: SDKMAN JVM toolchain manager installer
|
|
41
|
+
|
|
42
|
+
- domain: pyenv.run
|
|
43
|
+
reason: pyenv Python version manager installer
|
|
44
|
+
|
|
45
|
+
- domain: deno.land
|
|
46
|
+
reason: Deno runtime installer
|
|
47
|
+
|
|
48
|
+
- domain: get.pnpm.io
|
|
49
|
+
reason: pnpm package manager installer
|
|
50
|
+
|
|
51
|
+
- domain: nodesource.com
|
|
52
|
+
reason: Node.js binary distribution installer
|
|
53
|
+
|
|
54
|
+
- domain: ohmyz.sh
|
|
55
|
+
reason: Oh My Zsh shell framework installer
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Detection Rule License (DRL) 1.1
|
|
2
|
+
|
|
3
|
+
Copyright 2026 Gen Digital Inc.
|
|
4
|
+
|
|
5
|
+
Default author for all rules in this directory: Gen Digital Inc.
|
|
6
|
+
Individual rules may specify a different author in their "author" field.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this rule set and associated documentation files (the "Rules"), to deal in
|
|
12
|
+
the Rules without restriction, including without limitation the rights to use,
|
|
13
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
14
|
+
the Rules, and to permit persons to whom the Rules are furnished to do so,
|
|
15
|
+
subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
If you share the Rules (including in modified form), you must retain the
|
|
18
|
+
following if it is supplied within the Rules:
|
|
19
|
+
|
|
20
|
+
1. identification of the authors(s) ("author" field) of the Rule and any
|
|
21
|
+
others designated to receive attribution, in any reasonable manner
|
|
22
|
+
requested by the Rule author (including by pseudonym if designated).
|
|
23
|
+
|
|
24
|
+
2. a URI or hyperlink to the Rule set or explicit Rule to the extent
|
|
25
|
+
reasonably practicable
|
|
26
|
+
|
|
27
|
+
3. indicate the Rules are licensed under this Detection Rule License, and
|
|
28
|
+
include the text of, or the URI or hyperlink to, this Detection Rule
|
|
29
|
+
License to the extent reasonably practicable
|
|
30
|
+
|
|
31
|
+
If you use the Rules (including in modified form) on data, messages based on
|
|
32
|
+
matches with the Rules must retain the following if it is supplied within the
|
|
33
|
+
Rules:
|
|
34
|
+
|
|
35
|
+
1. identification of the authors(s) ("author" field) of the Rule and any
|
|
36
|
+
others designated to receive attribution, in any reasonable manner
|
|
37
|
+
requested by the Rule author (including by pseudonym if designated).
|
|
38
|
+
|
|
39
|
+
THE RULES ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
40
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
41
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
42
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
43
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
44
|
+
OUT OF OR IN CONNECTION WITH THE RULES OR THE USE OR OTHER DEALINGS IN THE
|
|
45
|
+
RULES.
|