@gendigital/sage-opencode 0.9.0 → 0.10.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 +60 -71
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -17
- package/dist/index.js.map +1 -1
- package/dist/plugin-discovery.js +1 -1
- package/dist/plugin-discovery.js.map +1 -1
- package/dist/tool-handler.d.ts.map +1 -1
- package/dist/tool-handler.js +53 -4
- package/dist/tool-handler.js.map +1 -1
- package/package.json +3 -3
- package/resources/threats/prompt-injection.yaml +2 -1
- package/resources/threats/win-credentials.yaml +1 -1
- package/dist/logger-adaptor.d.ts +0 -15
- package/dist/logger-adaptor.d.ts.map +0 -1
- package/dist/logger-adaptor.js +0 -32
- package/dist/logger-adaptor.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,102 +1,91 @@
|
|
|
1
|
-
# Sage for
|
|
1
|
+
# Sage — Safety for Agents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/gendigitalinc/sage/main/images/logo-shaded.png" alt="Sage" width="250">
|
|
5
|
+
</p>
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
<p align="center">
|
|
8
|
+
Protect your AI coding agent from dangerous commands, malicious URLs, and harmful file operations.
|
|
9
|
+
</p>
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
- `webfetch` URLs
|
|
9
|
-
- File operations (`read`, `write`, `edit`, `ls`, `glob`, `grep`)
|
|
11
|
+
---
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
<p align="center">
|
|
14
|
+
<img src="https://raw.githubusercontent.com/gendigitalinc/sage/main/images/block-opencode-allow.gif" alt="Sage blocking a dangerous command in OpenCode" width="700">
|
|
15
|
+
</p>
|
|
12
16
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
Clone the repo, build the OpenCode package, then point OpenCode to this package path:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
git clone https://github.com/gendigitalinc/sage
|
|
19
|
-
cd sage
|
|
20
|
-
pnpm install
|
|
21
|
-
pnpm --filter @gendigital/sage-opencode run build
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Global config (`~/.config/opencode/opencode.json`):
|
|
17
|
+
## What is Sage?
|
|
25
18
|
|
|
26
|
-
|
|
27
|
-
{
|
|
28
|
-
"plugin": ["/absolute/path/to/sage/packages/opencode"]
|
|
29
|
-
}
|
|
30
|
-
```
|
|
19
|
+
Sage is a security layer for OpenCode. It intercepts tool calls — bash commands, URL fetches, file operations — and checks them for threats before they execute. If something looks dangerous, Sage blocks it or asks you to approve via OpenCode's native approval dialog.
|
|
31
20
|
|
|
32
|
-
## Behavior
|
|
33
21
|
|
|
34
|
-
|
|
35
|
-
- **ask** verdicts: blocked with an explicit `sage_approve` action ID
|
|
36
|
-
- **allow** verdicts: pass through
|
|
22
|
+
## What it protects against
|
|
37
23
|
|
|
38
|
-
|
|
24
|
+
- **Malicious URLs** — phishing, malware, and scam sites detected via cloud reputation
|
|
25
|
+
- **Dangerous commands** — reverse shells, pipe-to-curl, credential theft, data exfiltration
|
|
26
|
+
- **Prompt injection** — heuristics + a fine-tuned ML model detect injected instructions in fetched content
|
|
27
|
+
- **Suspicious file operations** — writes to sensitive paths, credential files, system configs
|
|
28
|
+
- **Supply-chain attacks** — malicious or typosquatted npm/PyPI packages
|
|
29
|
+
- **Compromised plugins** — automatic scanning of installed plugins at session start
|
|
39
30
|
|
|
40
|
-
|
|
31
|
+
## Install
|
|
41
32
|
|
|
42
|
-
|
|
43
|
-
2. Ask the user for explicit confirmation in chat
|
|
44
|
-
3. If approved, call:
|
|
33
|
+
Add the plugin to your OpenCode config (`~/.config/opencode/opencode.json`):
|
|
45
34
|
|
|
46
|
-
```
|
|
47
|
-
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"plugin": ["@gendigital/sage-opencode"]
|
|
38
|
+
}
|
|
48
39
|
```
|
|
49
40
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
## Session Startup Scanning
|
|
53
|
-
|
|
54
|
-
Sage automatically scans all installed OpenCode plugins when a new session starts.
|
|
41
|
+
Or [build from source](https://github.com/gendigitalinc/sage/blob/main/docs/getting-started.md#opencode).
|
|
55
42
|
|
|
56
|
-
|
|
43
|
+
> To verify it's working, ask your agent to run `echo __sage_test_deny_cmd_a75bf229__`. Sage should block this harmless canary command.
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
- **Local plugins**: Files in `~/.config/opencode/plugins/` (global)
|
|
60
|
-
- **Project plugins**: Files in `.opencode/plugins/` (project-specific)
|
|
45
|
+
## What Sage intercepts
|
|
61
46
|
|
|
62
|
-
|
|
47
|
+
Sage hooks into OpenCode's plugin system:
|
|
63
48
|
|
|
64
|
-
- **
|
|
65
|
-
- **
|
|
49
|
+
- **bash** — shell commands
|
|
50
|
+
- **write / edit** — file modifications
|
|
51
|
+
- **read** — file reads (sensitive paths)
|
|
52
|
+
- **webfetch** — URL fetches and downloads
|
|
53
|
+
- **ls / glob / grep** — file system operations
|
|
66
54
|
|
|
67
|
-
|
|
55
|
+
## How it works
|
|
68
56
|
|
|
69
|
-
|
|
70
|
-
2. **One-Shot**: Only injected once per session (not repeated)
|
|
71
|
-
3. **Agent Notification**: Agent sees threats and can inform user
|
|
72
|
-
4. **Console Logging**: Findings also logged to OpenCode console
|
|
57
|
+
When your agent makes a tool call, Sage evaluates it and returns a verdict:
|
|
73
58
|
|
|
74
|
-
|
|
59
|
+
| Verdict | What happens |
|
|
60
|
+
|---------|-------------|
|
|
61
|
+
| **Allow** | No threats detected — the action proceeds normally |
|
|
62
|
+
| **Ask** | Suspicious activity — OpenCode shows a native approval dialog |
|
|
63
|
+
| **Deny** | Threat detected — the action is blocked |
|
|
75
64
|
|
|
76
|
-
|
|
77
|
-
- Package metadata (package.json)
|
|
78
|
-
- Embedded URLs (checked against threat intelligence)
|
|
79
|
-
- Suspicious patterns (credentials, obfuscation, persistence)
|
|
65
|
+
For `ask` verdicts, Sage blocks the tool call and the agent calls `sage_approve({ actionId })`, which surfaces OpenCode's native approval dialog. If you approve, the agent retries the original tool call.
|
|
80
66
|
|
|
81
|
-
|
|
67
|
+
Sage is designed to fail open: if anything goes wrong internally, the action proceeds. Your agent is never blocked due to a Sage error.
|
|
82
68
|
|
|
83
|
-
|
|
84
|
-
- Fail-open philosophy: Errors don't block OpenCode
|
|
69
|
+
> **Note:** In `paranoid` sensitivity mode, `ask` verdicts are promoted to `deny` on OpenCode. This prevents prompt-injection attacks from auto-approving flagged actions.
|
|
85
70
|
|
|
86
|
-
|
|
71
|
+
## Configuration
|
|
87
72
|
|
|
88
|
-
|
|
73
|
+
Sage works out of the box with no configuration. To customize behavior, edit `~/.sage/config.json`:
|
|
89
74
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"sensitivity": "balanced",
|
|
78
|
+
"url_check": { "enabled": true },
|
|
79
|
+
"heuristics_enabled": true
|
|
80
|
+
}
|
|
94
81
|
```
|
|
95
82
|
|
|
96
|
-
|
|
83
|
+
See [Configuration](https://github.com/gendigitalinc/sage/blob/main/docs/configuration.md) for all options.
|
|
97
84
|
|
|
98
|
-
##
|
|
85
|
+
## Links
|
|
99
86
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
87
|
+
- [User Guide](https://github.com/gendigitalinc/sage/blob/main/docs/user-guide.md) — verify install, handle alerts, manage false positives
|
|
88
|
+
- [Configuration](https://github.com/gendigitalinc/sage/blob/main/docs/configuration.md) — all config options
|
|
89
|
+
- [Exceptions](https://github.com/gendigitalinc/sage/blob/main/docs/exceptions.md) — pattern-based allow/deny rules
|
|
90
|
+
- [Privacy](https://github.com/gendigitalinc/sage/blob/main/docs/privacy.md) — what data is sent, what stays local
|
|
91
|
+
- [GitHub](https://github.com/gendigitalinc/sage)
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAQlD,eAAO,MAAM,UAAU,EAAE,MAoKxB,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -2,17 +2,27 @@
|
|
|
2
2
|
* Sage OpenCode plugin.
|
|
3
3
|
* Intercepts tool calls and uses @gendigital/sage-core to enforce security verdicts.
|
|
4
4
|
*/
|
|
5
|
-
import { ApprovalStore, approveAction, loadConfig, resolveBranding } from "@gendigital/sage-core";
|
|
5
|
+
import { ApprovalStore, approveAction, createOperationalLogger, formatConfigurationWarnings, getConfigurationWarnings, loadConfig, resolveBranding, } from "@gendigital/sage-core";
|
|
6
6
|
import { tool } from "@opencode-ai/plugin/tool";
|
|
7
7
|
import { getBundledDataDirs } from "./bundled-dirs.js";
|
|
8
|
-
import { OpencodeLogger } from "./logger-adaptor.js";
|
|
9
8
|
import { createSessionScanHandler } from "./startup-scan.js";
|
|
10
9
|
import { createToolHandlers } from "./tool-handler.js";
|
|
11
10
|
const APPROVAL_STORE_CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes
|
|
12
11
|
export const SagePlugin = async ({ client, directory }) => {
|
|
13
|
-
const
|
|
14
|
-
const
|
|
12
|
+
const config = await loadConfig();
|
|
13
|
+
const operationalLogger = createOperationalLogger(config.operational_logging, "opencode");
|
|
14
|
+
const logger = operationalLogger.forComponent("plugin");
|
|
15
|
+
const toolLogger = operationalLogger.forComponent("tool-handler");
|
|
16
|
+
const scanLogger = operationalLogger.forComponent("startup-scan");
|
|
15
17
|
const branding = resolveBranding(config.brand_key, logger);
|
|
18
|
+
const warningMessage = formatConfigurationWarnings(await getConfigurationWarnings(undefined, logger), branding);
|
|
19
|
+
if (warningMessage) {
|
|
20
|
+
client.tui
|
|
21
|
+
.showToast({
|
|
22
|
+
body: { title: branding.name, message: warningMessage, variant: "warning", duration: 5000 },
|
|
23
|
+
})
|
|
24
|
+
.catch(() => { });
|
|
25
|
+
}
|
|
16
26
|
const { threatsDir, allowlistsDir } = getBundledDataDirs();
|
|
17
27
|
const approvalStore = new ApprovalStore();
|
|
18
28
|
// State: track findings per session for one-shot injection
|
|
@@ -24,7 +34,7 @@ export const SagePlugin = async ({ client, directory }) => {
|
|
|
24
34
|
approvalStore.cleanup();
|
|
25
35
|
}, APPROVAL_STORE_CLEANUP_INTERVAL_MS);
|
|
26
36
|
interval.unref?.();
|
|
27
|
-
const toolHandlers = createToolHandlers(
|
|
37
|
+
const toolHandlers = createToolHandlers(toolLogger, approvalStore, threatsDir, allowlistsDir, {
|
|
28
38
|
showToast: (msg, variant) => {
|
|
29
39
|
client.tui
|
|
30
40
|
.showToast({
|
|
@@ -68,8 +78,9 @@ export const SagePlugin = async ({ client, directory }) => {
|
|
|
68
78
|
synthetic: true,
|
|
69
79
|
};
|
|
70
80
|
message.parts.push(textPart);
|
|
71
|
-
logger.
|
|
72
|
-
|
|
81
|
+
logger.debug(`Injected sage plugin scan findings to user message`, {
|
|
82
|
+
sessionID,
|
|
83
|
+
findingsLength: findings.length,
|
|
73
84
|
});
|
|
74
85
|
pendingFindingsBySession.delete(sessionID);
|
|
75
86
|
},
|
|
@@ -85,7 +96,7 @@ export const SagePlugin = async ({ client, directory }) => {
|
|
|
85
96
|
return;
|
|
86
97
|
try {
|
|
87
98
|
logger.debug(`${branding.name}: starting session scan`, { sessionID });
|
|
88
|
-
const scanHandler = createSessionScanHandler(
|
|
99
|
+
const scanHandler = createSessionScanHandler(scanLogger, directory, (msg) => {
|
|
89
100
|
pendingFindingsBySession.set(sessionID, msg);
|
|
90
101
|
}, branding);
|
|
91
102
|
await scanHandler();
|
|
@@ -101,23 +112,38 @@ export const SagePlugin = async ({ client, directory }) => {
|
|
|
101
112
|
}
|
|
102
113
|
},
|
|
103
114
|
tool: {
|
|
104
|
-
// TODO: After the following PR merged to support client V2 in Opencode Plugin, gitleaks:allow
|
|
105
|
-
// use QuestionTools.ask to replace sage_approve tool
|
|
106
|
-
// PR: https://github.com/anomalyco/opencode/pull/12046
|
|
107
|
-
// Discussion: https://github.com/avast/sage/pull/21#discussion_r2873812399
|
|
108
115
|
sage_approve: tool({
|
|
109
|
-
description: `
|
|
116
|
+
description: `Review a ${branding.name}-flagged tool call. Shows a native approval dialog to the user. Call this immediately when ${branding.name} flags an action — do NOT ask the user in chat first.`,
|
|
110
117
|
args: {
|
|
111
118
|
actionId: tool.schema
|
|
112
119
|
.string()
|
|
113
|
-
.describe(`Action ID from ${branding.name}
|
|
114
|
-
approved: tool.schema.boolean().describe("true to approve, false to reject"),
|
|
120
|
+
.describe(`Action ID from ${branding.name} flagged message`),
|
|
115
121
|
},
|
|
116
|
-
async execute(args,
|
|
117
|
-
|
|
122
|
+
async execute(args, context) {
|
|
123
|
+
const pending = approvalStore.getPending(args.actionId);
|
|
124
|
+
if (!pending) {
|
|
125
|
+
return `No pending ${branding.name} approval found for this action ID.`;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
// "doom_loop" is the only permission OpenCode always gates with an ask dialog,
|
|
129
|
+
// bypassing wildcard `*: allow` defaults. If OpenCode changes this, the dialog silently stops appearing.
|
|
130
|
+
await context.ask({
|
|
131
|
+
permission: "doom_loop",
|
|
132
|
+
patterns: pending.artifacts.map((a) => `[${a.type}] ${a.value}`),
|
|
133
|
+
always: [],
|
|
134
|
+
metadata: {},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
logger.debug(`${branding.name}: approval dialog failed`, {
|
|
139
|
+
actionId: args.actionId,
|
|
140
|
+
error: String(error),
|
|
141
|
+
});
|
|
118
142
|
approvalStore.deletePending(args.actionId);
|
|
143
|
+
logger.debug("OpenCode approval rejected", { actionId: args.actionId });
|
|
119
144
|
return "Rejected by user.";
|
|
120
145
|
}
|
|
146
|
+
logger.info("OpenCode approval accepted", { actionId: args.actionId });
|
|
121
147
|
return approveAction(approvalStore, args.actionId, branding);
|
|
122
148
|
},
|
|
123
149
|
}),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin-discovery.js
CHANGED
|
@@ -35,7 +35,7 @@ export async function discoverOpenCodePlugins(logger, projectDir, branding = def
|
|
|
35
35
|
const projectPlugins = await discoverLocalPlugins(projectPluginsDir, "project", logger);
|
|
36
36
|
plugins.push(...projectPlugins);
|
|
37
37
|
}
|
|
38
|
-
logger.
|
|
38
|
+
logger.debug(`${branding.name} plugin discovery: found ${plugins.length} plugin(s)`);
|
|
39
39
|
return plugins;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-discovery.js","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAExE,sEAAsE;AACtE,SAAS,aAAa;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,YAAY;IACpB,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,mBAAmB,GAAG,eAAe,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC5C,MAAc,EACd,UAAmB,EACnB,WAAqB,eAAe;IAEpC,MAAM,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,IAAI,8CAA8C,CAAC,CAAC;IAE7E,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,4CAA4C;IAC5C,MAAM,UAAU,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChE,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;IAE5B,0CAA0C;IAC1C,MAAM,gBAAgB,GAAG,IAAI,CAAC,aAAa,EAAE,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;IACtE,MAAM,aAAa,GAAG,MAAM,oBAAoB,CAAC,gBAAgB,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrF,OAAO,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC;IAE/B,2CAA2C;IAC3C,IAAI,UAAU,EAAE,CAAC;QAChB,MAAM,iBAAiB,GAAG,IAAI,CAAC,UAAU,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;QACnE,MAAM,cAAc,GAAG,MAAM,oBAAoB,CAAC,iBAAiB,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;IACjC,CAAC;IAED,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"plugin-discovery.js","sourceRoot":"","sources":["../src/plugin-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +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,
|
|
1
|
+
{"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,aAAa,EAClB,KAAK,QAAQ,EAMb,KAAK,MAAM,EAEX,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;EAiHhB"}
|
package/dist/tool-handler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { canonicalizeToolName, defaultBranding,
|
|
1
|
+
import { canonicalizeToolName, defaultBranding, formatDenyMessage, guardToolCall, summarizeArtifacts, } from "@gendigital/sage-core";
|
|
2
2
|
const OPENCODE_TOOL_MAP = {
|
|
3
3
|
bash: "Bash",
|
|
4
4
|
webfetch: "WebFetch",
|
|
@@ -39,18 +39,37 @@ function normalizeToolInput(toolName, args) {
|
|
|
39
39
|
}
|
|
40
40
|
export function createToolHandlers(logger, approvalStore, threatsDir, allowlistsDir, options, branding = defaultBranding) {
|
|
41
41
|
const beforeToolUse = async (input, output) => {
|
|
42
|
-
|
|
42
|
+
const completeHook = (result, data = {}) => {
|
|
43
|
+
logger.debug("OpenCode tool hook completed", {
|
|
44
|
+
agentRuntime: "opencode",
|
|
45
|
+
hookType: "PreToolUse",
|
|
46
|
+
toolName: input.tool,
|
|
47
|
+
sessionId: input.sessionID,
|
|
48
|
+
toolUseId: input.callID,
|
|
49
|
+
result,
|
|
50
|
+
...data,
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
logger.debug("OpenCode tool hook started", {
|
|
54
|
+
agentRuntime: "opencode",
|
|
55
|
+
hookType: "PreToolUse",
|
|
56
|
+
toolName: input.tool,
|
|
57
|
+
sessionId: input.sessionID,
|
|
58
|
+
toolUseId: input.callID,
|
|
59
|
+
});
|
|
43
60
|
try {
|
|
44
61
|
const args = output.args ?? {};
|
|
45
62
|
const artifacts = extractFromOpenCodeTool(input.tool, args);
|
|
46
63
|
if (!artifacts || artifacts.length === 0) {
|
|
64
|
+
completeHook("skipped", { skippedReason: "no_artifacts" });
|
|
47
65
|
return;
|
|
48
66
|
}
|
|
67
|
+
const toolName = canonicalizeToolName(OPENCODE_TOOL_MAP, input.tool);
|
|
49
68
|
const { verdict, actionId } = await guardToolCall({
|
|
50
69
|
sessionId: input.sessionID,
|
|
51
70
|
conversationId: input.sessionID,
|
|
52
71
|
agentRuntime: "opencode",
|
|
53
|
-
toolName
|
|
72
|
+
toolName,
|
|
54
73
|
toolInput: normalizeToolInput(input.tool, args),
|
|
55
74
|
artifacts,
|
|
56
75
|
}, {
|
|
@@ -59,6 +78,13 @@ export function createToolHandlers(logger, approvalStore, threatsDir, allowlists
|
|
|
59
78
|
logger,
|
|
60
79
|
}, approvalStore);
|
|
61
80
|
if (verdict.decision === "allow") {
|
|
81
|
+
completeHook("evaluated", {
|
|
82
|
+
toolName,
|
|
83
|
+
decision: verdict.decision,
|
|
84
|
+
category: verdict.category,
|
|
85
|
+
severity: verdict.severity,
|
|
86
|
+
artifactsCount: artifacts.length,
|
|
87
|
+
});
|
|
62
88
|
return;
|
|
63
89
|
}
|
|
64
90
|
try {
|
|
@@ -71,10 +97,32 @@ export function createToolHandlers(logger, approvalStore, threatsDir, allowlists
|
|
|
71
97
|
// Toast failure is non-critical — never prevent enforcement
|
|
72
98
|
}
|
|
73
99
|
if (verdict.decision === "deny") {
|
|
100
|
+
completeHook("evaluated", {
|
|
101
|
+
toolName,
|
|
102
|
+
decision: verdict.decision,
|
|
103
|
+
category: verdict.category,
|
|
104
|
+
severity: verdict.severity,
|
|
105
|
+
artifactsCount: artifacts.length,
|
|
106
|
+
});
|
|
74
107
|
throw new SageVerdictBlockError(formatDenyMessage(verdict, branding));
|
|
75
108
|
}
|
|
76
109
|
// ask — actionId is always set for ask verdicts
|
|
77
|
-
|
|
110
|
+
const reasons = verdict.reasons.length > 0 ? verdict.reasons.slice(0, 3).join("; ") : verdict.category;
|
|
111
|
+
completeHook("evaluated", {
|
|
112
|
+
toolName,
|
|
113
|
+
decision: verdict.decision,
|
|
114
|
+
reasons: verdict.reasons,
|
|
115
|
+
category: verdict.category,
|
|
116
|
+
severity: verdict.severity,
|
|
117
|
+
artifactsCount: artifacts.length,
|
|
118
|
+
actionId,
|
|
119
|
+
});
|
|
120
|
+
throw new SageVerdictBlockError([
|
|
121
|
+
`${branding.name} flagged this action (${verdict.category}): ${reasons}`,
|
|
122
|
+
`Artifacts: ${summarizeArtifacts(artifacts)}`,
|
|
123
|
+
`Call sage_approve({ actionId: "${actionId}" }) to request approval from the user.`,
|
|
124
|
+
`After approval, retry the EXACT same tool call with identical arguments.`,
|
|
125
|
+
].join("\n"));
|
|
78
126
|
}
|
|
79
127
|
catch (error) {
|
|
80
128
|
// Verdict errors are expected (blocks and asks); others are logged as fail-open
|
|
@@ -84,6 +132,7 @@ export function createToolHandlers(logger, approvalStore, threatsDir, allowlists
|
|
|
84
132
|
error: String(error),
|
|
85
133
|
tool: input.tool,
|
|
86
134
|
});
|
|
135
|
+
completeHook("failed_open", { decision: "allow" });
|
|
87
136
|
}
|
|
88
137
|
};
|
|
89
138
|
return {
|
package/dist/tool-handler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,oBAAoB,EACpB,eAAe,EACf,
|
|
1
|
+
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.10.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"description": "Safety for Agents - ADR layer for OpenCode",
|
|
10
10
|
"homepage": "https://github.com/gendigitalinc/sage",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"LICENSE"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@
|
|
34
|
+
"@opencode-ai/plugin": "^1.14.48",
|
|
35
|
+
"@gendigital/sage-core": "0.10.0"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
37
|
-
"@opencode-ai/plugin": "^1.2.10",
|
|
38
38
|
"@types/node": "^22.0.0",
|
|
39
39
|
"typescript": "^5.9.0",
|
|
40
40
|
"vitest": "^4.0.0"
|
|
@@ -257,7 +257,8 @@
|
|
|
257
257
|
confidence: 0.85
|
|
258
258
|
action: block
|
|
259
259
|
case_insensitive: true
|
|
260
|
-
|
|
260
|
+
# Require a reasonably long hidden link target/title plus a high-signal PI phrase.
|
|
261
|
+
pattern: "\\[[^\\]]*\\]\\((?=[^)]{40,}\\))[^)]*(?:ignore\\s+previous\\s+instructions|forget\\s+instructions|system\\s+prompt|override\\s+instructions)[^)]*\\)"
|
|
261
262
|
match_on: content
|
|
262
263
|
title: "Structural injection: markdown link with hidden injection"
|
|
263
264
|
expires_at: null
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
severity: high
|
|
33
33
|
confidence: 0.80
|
|
34
34
|
action: require_approval
|
|
35
|
-
pattern: "
|
|
35
|
+
pattern: "(^|[^\\w-])(?:type|more|[Gg]et-[Cc]ontent)\\b.*\\.(?:env|credentials|pgpass|netrc)(?=$|[.\\s\"'`;&|)<>])"
|
|
36
36
|
match_on: command
|
|
37
37
|
title: "Reading credential file via type/more/Get-Content"
|
|
38
38
|
expires_at: null
|
package/dist/logger-adaptor.d.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bridges OpenCode's client logger to Sage's Logger interface.
|
|
3
|
-
*/
|
|
4
|
-
import type { Logger } from "@gendigital/sage-core";
|
|
5
|
-
import type { PluginInput } from "@opencode-ai/plugin";
|
|
6
|
-
export declare class OpencodeLogger implements Logger {
|
|
7
|
-
private client;
|
|
8
|
-
constructor(client: PluginInput["client"]);
|
|
9
|
-
debug(msg: string, data?: Record<string, unknown>): Promise<void>;
|
|
10
|
-
info(msg: string, data?: Record<string, unknown>): Promise<void>;
|
|
11
|
-
warn(msg: string, data?: Record<string, unknown>): Promise<void>;
|
|
12
|
-
error(msg: string, data?: Record<string, unknown>): Promise<void>;
|
|
13
|
-
private write;
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=logger-adaptor.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger-adaptor.d.ts","sourceRoot":"","sources":["../src/logger-adaptor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,qBAAa,cAAe,YAAW,MAAM;IAC5C,OAAO,CAAC,MAAM,CAAwB;gBAE1B,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC;IAI5B,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIjD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIhD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAIhD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;YAIhD,KAAK;CAUnB"}
|
package/dist/logger-adaptor.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bridges OpenCode's client logger to Sage's Logger interface.
|
|
3
|
-
*/
|
|
4
|
-
export class OpencodeLogger {
|
|
5
|
-
client;
|
|
6
|
-
constructor(client) {
|
|
7
|
-
this.client = client;
|
|
8
|
-
}
|
|
9
|
-
async debug(msg, data) {
|
|
10
|
-
await this.write("debug", msg, data).catch(() => { });
|
|
11
|
-
}
|
|
12
|
-
async info(msg, data) {
|
|
13
|
-
await this.write("info", msg, data).catch(() => { });
|
|
14
|
-
}
|
|
15
|
-
async warn(msg, data) {
|
|
16
|
-
await this.write("warn", msg, data).catch(() => { });
|
|
17
|
-
}
|
|
18
|
-
async error(msg, data) {
|
|
19
|
-
await this.write("error", msg, data).catch(() => { });
|
|
20
|
-
}
|
|
21
|
-
async write(level, msg, data) {
|
|
22
|
-
await this.client.app.log({
|
|
23
|
-
body: {
|
|
24
|
-
service: "sage-opencode",
|
|
25
|
-
level,
|
|
26
|
-
message: msg,
|
|
27
|
-
extra: data && typeof data === "object" ? data : undefined,
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=logger-adaptor.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger-adaptor.js","sourceRoot":"","sources":["../src/logger-adaptor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,OAAO,cAAc;IAClB,MAAM,CAAwB;IAEtC,YAAY,MAA6B;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAEM,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,IAA8B;QAC7D,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,IAA8B;QAC5D,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,GAAW,EAAE,IAA8B;QAC5D,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,KAAK,CAAC,GAAW,EAAE,IAA8B;QAC7D,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACtD,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,KAA0C,EAAE,GAAW,EAAE,IAAc;QAC1F,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YACzB,IAAI,EAAE;gBACL,OAAO,EAAE,eAAe;gBACxB,KAAK;gBACL,OAAO,EAAE,GAAG;gBACZ,KAAK,EAAE,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAE,IAAgC,CAAC,CAAC,CAAC,SAAS;aACvF;SACD,CAAC,CAAC;IACJ,CAAC;CACD"}
|