@gendigital/sage-opencode 0.13.0 → 0.15.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 +14 -2
- package/dist/extractors.d.ts +7 -0
- package/dist/extractors.d.ts.map +1 -1
- package/dist/extractors.js +89 -16
- package/dist/extractors.js.map +1 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +36 -320
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.cjs +425 -98
- package/dist/mcp-server.cjs.map +4 -4
- package/dist/plugin-discovery.d.ts +7 -0
- package/dist/plugin-discovery.d.ts.map +1 -1
- package/dist/plugin-discovery.js +46 -11
- package/dist/plugin-discovery.js.map +1 -1
- package/dist/shared.d.ts +63 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +352 -0
- package/dist/shared.js.map +1 -0
- package/dist/tool-handler.d.ts +6 -0
- package/dist/tool-handler.d.ts.map +1 -1
- package/dist/tool-handler.js +22 -4
- package/dist/tool-handler.js.map +1 -1
- package/dist/v2-types.d.ts +95 -0
- package/dist/v2-types.d.ts.map +1 -0
- package/dist/v2-types.js +10 -0
- package/dist/v2-types.js.map +1 -0
- package/dist/v2.d.ts +24 -0
- package/dist/v2.d.ts.map +1 -0
- package/dist/v2.js +151 -0
- package/dist/v2.js.map +1 -0
- package/index.js +3 -0
- package/package.json +4 -3
- package/resources/threats/credentials.yaml +1 -1
- package/resources/threats/dummy.yaml +37 -4
- package/resources/threats/prompt-injection.yaml +13 -0
package/dist/tool-handler.js
CHANGED
|
@@ -13,26 +13,40 @@ export const OPENCODE_TOOL_MAP = {
|
|
|
13
13
|
question: "Question",
|
|
14
14
|
task: "Task",
|
|
15
15
|
read_lines: "ReadLines",
|
|
16
|
+
// OpenCode v2 tool names
|
|
17
|
+
shell: "Bash",
|
|
18
|
+
patch: "ApplyPatch",
|
|
19
|
+
subagent: "Task",
|
|
16
20
|
};
|
|
17
21
|
import { SageVerdictBlockError, SageVerdictError } from "./error.js";
|
|
18
|
-
import { extractFromOpenCodeTool } from "./extractors.js";
|
|
22
|
+
import { extractFromOpenCodeTool, openCodeFilePath, openCodePatchTexts } from "./extractors.js";
|
|
19
23
|
function asString(value) {
|
|
20
24
|
return typeof value === "string" ? value : undefined;
|
|
21
25
|
}
|
|
22
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Map OpenCode argument names onto the Claude-style keys core reads
|
|
28
|
+
* (`file_path`, `new_string`, and `patch` for ApplyPatch AMSI scans and
|
|
29
|
+
* content snapshots).
|
|
30
|
+
*/
|
|
31
|
+
export function normalizeToolInput(toolName, args) {
|
|
23
32
|
switch (toolName) {
|
|
24
33
|
case "write":
|
|
25
34
|
return {
|
|
26
35
|
...args,
|
|
27
|
-
file_path:
|
|
36
|
+
file_path: openCodeFilePath(args) || (asString(args.file_path) ?? ""),
|
|
28
37
|
content: asString(args.content) ?? "",
|
|
29
38
|
};
|
|
30
39
|
case "edit":
|
|
31
40
|
return {
|
|
32
41
|
...args,
|
|
33
|
-
file_path:
|
|
42
|
+
file_path: openCodeFilePath(args) || (asString(args.file_path) ?? ""),
|
|
34
43
|
new_string: asString(args.newString) ?? asString(args.new_string) ?? "",
|
|
35
44
|
};
|
|
45
|
+
case "patch":
|
|
46
|
+
return {
|
|
47
|
+
...args,
|
|
48
|
+
patch: asString(args.patch) ?? asString(args.patchText) ?? "",
|
|
49
|
+
};
|
|
36
50
|
default:
|
|
37
51
|
return args;
|
|
38
52
|
}
|
|
@@ -59,6 +73,10 @@ export function createToolHandlers(logger, approvalStore, threatsDir, trustedDom
|
|
|
59
73
|
});
|
|
60
74
|
try {
|
|
61
75
|
const args = output.args ?? {};
|
|
76
|
+
if (input.tool === "patch" && openCodePatchTexts(args).length > 1) {
|
|
77
|
+
completeHook("blocked", { skippedReason: "conflicting_patch_fields" });
|
|
78
|
+
throw new SageVerdictBlockError(`${branding.name} blocked this patch: patchText and patch contain different content.`);
|
|
79
|
+
}
|
|
62
80
|
// E2E payload-drift capture (drift loop). OpenCode is an in-process
|
|
63
81
|
// ESM plugin (not MCP, not a CJS hook), so the "raw wire" payload is the
|
|
64
82
|
// in-proc tool-call shape OpenCode hands us. Namespaced opencode-* so it
|
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,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,aAAa,EAEb,SAAS,EACT,kBAAkB,GAClB,MAAM,uBAAuB,CAAC;AAE/B,MAAM,CAAC,MAAM,iBAAiB,GAAsC;IACnE,IAAI,EAAE,MAAM;IACZ,QAAQ,EAAE,UAAU;IACpB,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE,MAAM;IACZ,EAAE,EAAE,MAAM;IACV,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,WAAW;IACtB,QAAQ,EAAE,UAAU;IACpB,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,WAAW;
|
|
1
|
+
{"version":3,"file":"tool-handler.js","sourceRoot":"","sources":["../src/tool-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local structural types for the OpenCode v2 plugin API.
|
|
3
|
+
*
|
|
4
|
+
* Structural subset of the OpenCode v2 Promise plugin API, checked against
|
|
5
|
+
* the 2.1.4 server plugin documentation. Declared locally so the package can
|
|
6
|
+
* retain its v1 SDK dependency. Re-check these shapes when updating v2 support.
|
|
7
|
+
*/
|
|
8
|
+
/** OpenCode v2 version these types were last checked against. */
|
|
9
|
+
export declare const V2_SDK_TYPES_VERSION = "2.1.4";
|
|
10
|
+
export interface V2Registration {
|
|
11
|
+
readonly dispose: () => Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/** Subset of v2 `ToolContext` passed to tool `execute`. */
|
|
14
|
+
export interface V2ToolContext {
|
|
15
|
+
readonly sessionID: string;
|
|
16
|
+
readonly agent: string;
|
|
17
|
+
readonly messageID: string;
|
|
18
|
+
readonly id: string;
|
|
19
|
+
readonly [key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
export interface V2ToolResult {
|
|
22
|
+
content?: unknown;
|
|
23
|
+
metadata?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
export interface V2PermissionEvaluation {
|
|
26
|
+
readonly action: string;
|
|
27
|
+
effect: "allow" | "ask" | "deny";
|
|
28
|
+
}
|
|
29
|
+
export interface V2PermissionAssertInput {
|
|
30
|
+
readonly sessionID: string;
|
|
31
|
+
readonly agent: string;
|
|
32
|
+
readonly source: {
|
|
33
|
+
readonly type: "tool";
|
|
34
|
+
readonly messageID: string;
|
|
35
|
+
readonly id: string;
|
|
36
|
+
};
|
|
37
|
+
readonly action: string;
|
|
38
|
+
readonly resources: readonly string[];
|
|
39
|
+
readonly save: readonly string[];
|
|
40
|
+
}
|
|
41
|
+
export interface V2ToolInfo {
|
|
42
|
+
readonly name?: string;
|
|
43
|
+
readonly description: string;
|
|
44
|
+
readonly input: unknown;
|
|
45
|
+
readonly options?: {
|
|
46
|
+
readonly codemode?: boolean;
|
|
47
|
+
};
|
|
48
|
+
readonly execute: (input: unknown, context: V2ToolContext) => Promise<V2ToolResult>;
|
|
49
|
+
}
|
|
50
|
+
export interface V2ToolEditor {
|
|
51
|
+
get(id: string): V2ToolInfo | undefined;
|
|
52
|
+
add(tool: V2ToolInfo): void;
|
|
53
|
+
}
|
|
54
|
+
export interface V2McpEditor {
|
|
55
|
+
get(name: string): unknown;
|
|
56
|
+
set(name: string, config: Record<string, unknown>): void;
|
|
57
|
+
}
|
|
58
|
+
export interface V2ToolExecuteBefore {
|
|
59
|
+
tool: string;
|
|
60
|
+
readonly sessionID: string;
|
|
61
|
+
readonly id: string;
|
|
62
|
+
input: unknown;
|
|
63
|
+
}
|
|
64
|
+
/** Structural subset of the v2 promise plugin `Context` Sage relies on. */
|
|
65
|
+
export interface V2PluginContext {
|
|
66
|
+
readonly location?: {
|
|
67
|
+
readonly directory?: string;
|
|
68
|
+
};
|
|
69
|
+
readonly tool: {
|
|
70
|
+
readonly transform: (callback: (editor: V2ToolEditor) => void) => Promise<V2Registration>;
|
|
71
|
+
readonly hook: (name: "execute.before", callback: (event: V2ToolExecuteBefore) => Promise<void> | void) => Promise<V2Registration>;
|
|
72
|
+
};
|
|
73
|
+
readonly permission: {
|
|
74
|
+
readonly assert: (input: V2PermissionAssertInput) => Promise<void>;
|
|
75
|
+
readonly hook: (name: "evaluate", callback: (event: V2PermissionEvaluation) => Promise<void> | void) => Promise<V2Registration>;
|
|
76
|
+
};
|
|
77
|
+
readonly mcp?: {
|
|
78
|
+
readonly transform: (callback: (editor: V2McpEditor) => void) => Promise<V2Registration>;
|
|
79
|
+
};
|
|
80
|
+
readonly session?: {
|
|
81
|
+
readonly hook: (name: "prompt", callback: (event: {
|
|
82
|
+
readonly sessionID: string;
|
|
83
|
+
}) => Promise<void> | void) => Promise<V2Registration>;
|
|
84
|
+
};
|
|
85
|
+
/** Not part of the v2 server context today; used if a future host exposes it. */
|
|
86
|
+
readonly toast?: {
|
|
87
|
+
show(options: {
|
|
88
|
+
title?: string;
|
|
89
|
+
message: string;
|
|
90
|
+
variant?: string;
|
|
91
|
+
duration?: number;
|
|
92
|
+
}): void;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=v2-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-types.d.ts","sourceRoot":"","sources":["../src/v2-types.ts"],"names":[],"mappings":"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"}
|
package/dist/v2-types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local structural types for the OpenCode v2 plugin API.
|
|
3
|
+
*
|
|
4
|
+
* Structural subset of the OpenCode v2 Promise plugin API, checked against
|
|
5
|
+
* the 2.1.4 server plugin documentation. Declared locally so the package can
|
|
6
|
+
* retain its v1 SDK dependency. Re-check these shapes when updating v2 support.
|
|
7
|
+
*/
|
|
8
|
+
/** OpenCode v2 version these types were last checked against. */
|
|
9
|
+
export const V2_SDK_TYPES_VERSION = "2.1.4";
|
|
10
|
+
//# sourceMappingURL=v2-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2-types.js","sourceRoot":"","sources":["../src/v2-types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAO,CAAC"}
|
package/dist/v2.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode v2 (opencode2 / `@opencode-ai/core`) adapter.
|
|
3
|
+
*
|
|
4
|
+
* v2 loads the package's default export as `{ id, setup }` and calls
|
|
5
|
+
* `setup(context)` with domain APIs instead of v1's hooks object. This adapter
|
|
6
|
+
* maps those domains onto the shared Sage controller:
|
|
7
|
+
* - `tool.hook("execute.before")` → Sage tool interception. Throwing from the
|
|
8
|
+
* hook fails just that tool call with the thrown message (the turn continues),
|
|
9
|
+
* which is the v1 block semantics, so the same `SageVerdictBlockError` works.
|
|
10
|
+
* - `tool.transform` → registers `sage_approve`, which requests a native
|
|
11
|
+
* permission prompt through `permission.assert`.
|
|
12
|
+
* - `permission.hook("evaluate")` → forces Sage approval requests to ask.
|
|
13
|
+
* - `mcp.transform` → registers the Sage MCP server unless `sage` exists.
|
|
14
|
+
* - `session.hook("prompt")` → per-session plugin/skill scan.
|
|
15
|
+
*
|
|
16
|
+
* The v2 API types live in `v2-types.ts` (see there for the SDK version they
|
|
17
|
+
* mirror); every payload is validated before use (fail open).
|
|
18
|
+
*/
|
|
19
|
+
import type { V2PluginContext } from "./v2-types.js";
|
|
20
|
+
export type { V2McpEditor, V2PluginContext, V2ToolContext, V2ToolEditor, V2ToolExecuteBefore, V2ToolInfo, V2ToolResult, } from "./v2-types.js";
|
|
21
|
+
export declare const SAGE_APPROVE_TOOL = "sage_approve";
|
|
22
|
+
/** OpenCode v2 plugin `setup`. Returns a cleanup that disposes registrations. */
|
|
23
|
+
export declare function setupV2(context: V2PluginContext): Promise<() => Promise<void>>;
|
|
24
|
+
//# sourceMappingURL=v2.d.ts.map
|
package/dist/v2.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2.d.ts","sourceRoot":"","sources":["../src/v2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAWH,OAAO,KAAK,EAAE,eAAe,EAA8B,MAAM,eAAe,CAAC;AAEjF,YAAY,EACX,WAAW,EACX,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,UAAU,EACV,YAAY,GACZ,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AA0ChD,iFAAiF;AACjF,wBAAsB,OAAO,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAuGpF"}
|
package/dist/v2.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode v2 (opencode2 / `@opencode-ai/core`) adapter.
|
|
3
|
+
*
|
|
4
|
+
* v2 loads the package's default export as `{ id, setup }` and calls
|
|
5
|
+
* `setup(context)` with domain APIs instead of v1's hooks object. This adapter
|
|
6
|
+
* maps those domains onto the shared Sage controller:
|
|
7
|
+
* - `tool.hook("execute.before")` → Sage tool interception. Throwing from the
|
|
8
|
+
* hook fails just that tool call with the thrown message (the turn continues),
|
|
9
|
+
* which is the v1 block semantics, so the same `SageVerdictBlockError` works.
|
|
10
|
+
* - `tool.transform` → registers `sage_approve`, which requests a native
|
|
11
|
+
* permission prompt through `permission.assert`.
|
|
12
|
+
* - `permission.hook("evaluate")` → forces Sage approval requests to ask.
|
|
13
|
+
* - `mcp.transform` → registers the Sage MCP server unless `sage` exists.
|
|
14
|
+
* - `session.hook("prompt")` → per-session plugin/skill scan.
|
|
15
|
+
*
|
|
16
|
+
* The v2 API types live in `v2-types.ts` (see there for the SDK version they
|
|
17
|
+
* mirror); every payload is validated before use (fail open).
|
|
18
|
+
*/
|
|
19
|
+
import { ApprovalUnavailableError, approvalPatterns, createSageController, SAGE_MCP_SERVER_NAME, sageMcpServerConfig, } from "./shared.js";
|
|
20
|
+
export const SAGE_APPROVE_TOOL = "sage_approve";
|
|
21
|
+
const SAGE_APPROVAL_ACTION = "sage_approval";
|
|
22
|
+
function isRecord(value) {
|
|
23
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
function createApproveTool(sage, plugin) {
|
|
26
|
+
return {
|
|
27
|
+
name: SAGE_APPROVE_TOOL,
|
|
28
|
+
description: sage.approveToolDescription,
|
|
29
|
+
input: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
actionId: { type: "string", description: sage.approveArgDescription },
|
|
33
|
+
},
|
|
34
|
+
required: ["actionId"],
|
|
35
|
+
additionalProperties: false,
|
|
36
|
+
},
|
|
37
|
+
// The approval dialog must be driven by the model directly, not from a
|
|
38
|
+
// code-mode script.
|
|
39
|
+
options: { codemode: false },
|
|
40
|
+
async execute(input, context) {
|
|
41
|
+
const actionId = isRecord(input) && typeof input.actionId === "string" ? input.actionId : "";
|
|
42
|
+
const result = await sage.resolveApproval(actionId, async (pending) => {
|
|
43
|
+
if (!plugin.permission || typeof plugin.permission.assert !== "function") {
|
|
44
|
+
throw new ApprovalUnavailableError("OpenCode v2 permission API is unavailable");
|
|
45
|
+
}
|
|
46
|
+
await plugin.permission.assert({
|
|
47
|
+
sessionID: context.sessionID,
|
|
48
|
+
agent: context.agent,
|
|
49
|
+
source: { type: "tool", messageID: context.messageID, id: context.id },
|
|
50
|
+
action: SAGE_APPROVAL_ACTION,
|
|
51
|
+
resources: [`${actionId}: ${approvalPatterns(pending).join(", ")}`],
|
|
52
|
+
save: [],
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
return { content: result };
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** OpenCode v2 plugin `setup`. Returns a cleanup that disposes registrations. */
|
|
60
|
+
export async function setupV2(context) {
|
|
61
|
+
const toast = context.toast;
|
|
62
|
+
const createNotifier = toast && typeof toast.show === "function"
|
|
63
|
+
? (branding) => (message, variant, duration) => {
|
|
64
|
+
try {
|
|
65
|
+
toast.show({ title: branding.name, message, variant, duration });
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Notifications are best-effort
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
: undefined;
|
|
72
|
+
const sage = await createSageController({
|
|
73
|
+
directory: context.location?.directory ?? process.cwd(),
|
|
74
|
+
createNotifier,
|
|
75
|
+
host: "v2",
|
|
76
|
+
});
|
|
77
|
+
const registrations = [];
|
|
78
|
+
if (!context.permission || typeof context.permission.hook !== "function") {
|
|
79
|
+
throw new Error("OpenCode v2 permission hook is required for Sage approvals");
|
|
80
|
+
}
|
|
81
|
+
registrations.push(await context.permission.hook("evaluate", (event) => {
|
|
82
|
+
if (event.action === SAGE_APPROVAL_ACTION && event.effect === "allow")
|
|
83
|
+
event.effect = "ask";
|
|
84
|
+
}));
|
|
85
|
+
registrations.push(await context.tool.hook("execute.before", async (event) => {
|
|
86
|
+
// Unexpected shapes fail open: Sage never blocks a call it can't read.
|
|
87
|
+
if (!isRecord(event) || typeof event.tool !== "string")
|
|
88
|
+
return;
|
|
89
|
+
let args;
|
|
90
|
+
let unrecognizedReason = "not_an_object";
|
|
91
|
+
if (isRecord(event.input)) {
|
|
92
|
+
args = event.input;
|
|
93
|
+
}
|
|
94
|
+
else if (typeof event.input === "string") {
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(event.input);
|
|
97
|
+
if (isRecord(parsed))
|
|
98
|
+
args = parsed;
|
|
99
|
+
else
|
|
100
|
+
unrecognizedReason = "json_not_an_object";
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
unrecognizedReason = "invalid_json";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (!args) {
|
|
107
|
+
sage.logger.warn("OpenCode v2 tool input has unrecognized shape", {
|
|
108
|
+
tool: event.tool,
|
|
109
|
+
sessionID: event.sessionID,
|
|
110
|
+
callID: event.id,
|
|
111
|
+
inputType: Array.isArray(event.input)
|
|
112
|
+
? "array"
|
|
113
|
+
: event.input === null
|
|
114
|
+
? "null"
|
|
115
|
+
: typeof event.input,
|
|
116
|
+
reason: unrecognizedReason,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
await sage.beforeToolUse({
|
|
120
|
+
tool: event.tool,
|
|
121
|
+
sessionID: typeof event.sessionID === "string" ? event.sessionID : "unknown",
|
|
122
|
+
callID: typeof event.id === "string" ? event.id : "",
|
|
123
|
+
}, { args: args ?? {} });
|
|
124
|
+
}));
|
|
125
|
+
registrations.push(await context.tool.transform((editor) => {
|
|
126
|
+
if (!editor.get(SAGE_APPROVE_TOOL)) {
|
|
127
|
+
editor.add(createApproveTool(sage, context));
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
if (context.mcp) {
|
|
131
|
+
registrations.push(await context.mcp.transform((editor) => {
|
|
132
|
+
// Never clobber a user-supplied `sage` server.
|
|
133
|
+
if (editor.get(SAGE_MCP_SERVER_NAME) !== undefined)
|
|
134
|
+
return;
|
|
135
|
+
editor.set(SAGE_MCP_SERVER_NAME, sageMcpServerConfig());
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
if (context.session) {
|
|
139
|
+
registrations.push(await context.session.hook("prompt", (event) => {
|
|
140
|
+
const sessionID = isRecord(event) && typeof event.sessionID === "string" ? event.sessionID : "";
|
|
141
|
+
// Don't hold up the prompt on the scan.
|
|
142
|
+
void sage.scanSession(sessionID).catch((error) => {
|
|
143
|
+
sage.logger.debug("Session scan failed", { error: String(error) });
|
|
144
|
+
});
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
return async () => {
|
|
148
|
+
await Promise.allSettled(registrations.map((r) => r.dispose()));
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=v2.js.map
|
package/dist/v2.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v2.js","sourceRoot":"","sources":["../src/v2.ts"],"names":[],"mappings":"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"}
|
package/index.js
ADDED
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
7
|
-
"version": "0.
|
|
7
|
+
"version": "0.15.0",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"description": "Safety for Agents - ADR layer for OpenCode",
|
|
10
10
|
"homepage": "https://github.com/gendigitalinc/sage",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
}
|
|
25
25
|
},
|
|
26
26
|
"files": [
|
|
27
|
+
"index.js",
|
|
27
28
|
"dist/**",
|
|
28
29
|
"resources/**",
|
|
29
30
|
"package.json",
|
|
@@ -32,8 +33,8 @@
|
|
|
32
33
|
],
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"@opencode-ai/plugin": "^1.14.48",
|
|
35
|
-
"@gendigital/sage-core": "0.
|
|
36
|
-
"@gendigital/sage-mcp": "0.
|
|
36
|
+
"@gendigital/sage-core": "0.15.0",
|
|
37
|
+
"@gendigital/sage-mcp": "0.15.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
39
40
|
"@types/node": "^22.0.0",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
category: secrets
|
|
10
10
|
severity: critical
|
|
11
11
|
confidence: 0.80
|
|
12
|
-
pattern: "(sk-[a-zA-Z0-9_-]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|ghp_[0-9a-zA-Z]{36}|gho_[0-9a-zA-Z]{36}|glpat-[0-9a-zA-Z_-]{20,}|xox[baprs]-[0-9a-zA-Z-]+)"
|
|
12
|
+
pattern: "\\b(sk-[a-zA-Z0-9_-]{20,}|sk-proj-[a-zA-Z0-9_-]{20,}|AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z_-]{35}|ghp_[0-9a-zA-Z]{36}|gho_[0-9a-zA-Z]{36}|glpat-[0-9a-zA-Z_-]{20,}|xox[baprs]-[0-9a-zA-Z-]+)"
|
|
13
13
|
match_on: [command, content]
|
|
14
14
|
title: "Known API key prefix detected"
|
|
15
15
|
expires_at: null
|
|
@@ -19,6 +19,9 @@
|
|
|
19
19
|
# WebFetch/Bash url ✓ ✓ ✓
|
|
20
20
|
# WebFetch/Bash domain ✓ — —
|
|
21
21
|
#
|
|
22
|
+
# Submit-only (flags: ["submit_only"], allow + capped non-blocking telemetry):
|
|
23
|
+
# Bash (command), Write/Edit/Read (file_path)
|
|
24
|
+
#
|
|
22
25
|
# The file_path rules also cover Read, Delete, Glob, and LS tools
|
|
23
26
|
# (they produce the same artifact type).
|
|
24
27
|
# The url rules also cover URLs embedded in Bash commands and file content.
|
|
@@ -84,7 +87,6 @@
|
|
|
84
87
|
title: "[TEST] Canary log-only command"
|
|
85
88
|
expires_at: null
|
|
86
89
|
revoked: false
|
|
87
|
-
flags: ["report"]
|
|
88
90
|
|
|
89
91
|
# ─── File-path patterns (Write / Edit / Read / Delete tools) ────────
|
|
90
92
|
|
|
@@ -123,7 +125,6 @@
|
|
|
123
125
|
title: "[TEST] Canary log-only file path"
|
|
124
126
|
expires_at: null
|
|
125
127
|
revoked: false
|
|
126
|
-
flags: ["report"]
|
|
127
128
|
|
|
128
129
|
# ─── Content patterns (Write / Edit tools — file body) ──────────────
|
|
129
130
|
|
|
@@ -162,7 +163,6 @@
|
|
|
162
163
|
title: "[TEST] Canary log-only content"
|
|
163
164
|
expires_at: null
|
|
164
165
|
revoked: false
|
|
165
|
-
flags: ["report"]
|
|
166
166
|
|
|
167
167
|
# ─── URL patterns (WebFetch / Bash / Write content) ─────────────────
|
|
168
168
|
# Uses .test TLD (RFC 2606 reserved, never resolves) for safety.
|
|
@@ -202,7 +202,6 @@
|
|
|
202
202
|
title: "[TEST] Canary log-only URL"
|
|
203
203
|
expires_at: null
|
|
204
204
|
revoked: false
|
|
205
|
-
flags: ["report"]
|
|
206
205
|
|
|
207
206
|
# ─── Domain pattern (verifies domain→url routing in heuristics) ─────
|
|
208
207
|
|
|
@@ -217,3 +216,37 @@
|
|
|
217
216
|
title: "[TEST] Canary deny domain"
|
|
218
217
|
expires_at: null
|
|
219
218
|
revoked: false
|
|
219
|
+
|
|
220
|
+
# ─── Submit-only patterns (telemetry, never block) ──────────────────
|
|
221
|
+
#
|
|
222
|
+
# `flags: ["submit_only"]` removes the rule from the verdict entirely and
|
|
223
|
+
# instead submits a non-blocking event to /v2/heuristic, capped at one submit
|
|
224
|
+
# per rule per client per 24h (packages/core/src/submit-limits.ts). The
|
|
225
|
+
# confidence is deliberately deny-level so a regression that lets the flag
|
|
226
|
+
# leak into the verdict shows up as a deny.
|
|
227
|
+
|
|
228
|
+
- id: "DUMMY-CMD-SUBMIT-001"
|
|
229
|
+
version: 1
|
|
230
|
+
detection_name: "CMD:SageTestCommandSubmit-A [Tst]"
|
|
231
|
+
category: testing
|
|
232
|
+
severity: critical
|
|
233
|
+
confidence: 0.95
|
|
234
|
+
pattern: "diagmark_cmd_d7e7127e"
|
|
235
|
+
match_on: command
|
|
236
|
+
title: "[TEST] Canary submit-only command"
|
|
237
|
+
expires_at: null
|
|
238
|
+
revoked: false
|
|
239
|
+
flags: ["submit_only"]
|
|
240
|
+
|
|
241
|
+
- id: "DUMMY-FILE-SUBMIT-001"
|
|
242
|
+
version: 1
|
|
243
|
+
detection_name: "FN:SageTestFileSubmit-A [Tst]"
|
|
244
|
+
category: testing
|
|
245
|
+
severity: critical
|
|
246
|
+
confidence: 0.95
|
|
247
|
+
pattern: "diagmark_file_57871281"
|
|
248
|
+
match_on: file_path
|
|
249
|
+
title: "[TEST] Canary submit-only file path"
|
|
250
|
+
expires_at: null
|
|
251
|
+
revoked: false
|
|
252
|
+
flags: ["submit_only"]
|
|
@@ -440,3 +440,16 @@
|
|
|
440
440
|
expires_at: null
|
|
441
441
|
revoked: false
|
|
442
442
|
# Source: ATR-2026-00097 (pattern unchanged from upstream). Covers zh-CN, zh-TW, ja, ko.
|
|
443
|
+
|
|
444
|
+
- id: "CLT-PI-094"
|
|
445
|
+
version: 1
|
|
446
|
+
detection_name: "Other:SagePromptInjection-CP [Heur]"
|
|
447
|
+
category: prompt_injection
|
|
448
|
+
severity: warning
|
|
449
|
+
confidence: 0.70
|
|
450
|
+
case_insensitive: true
|
|
451
|
+
pattern: "\\b(?:disregard|ignore|forget|override)\\s+(?:all\\s+|any\\s+)?(?:your|the|my)\\s+system\\s+(?:prompt|message|instructions?)\\b"
|
|
452
|
+
match_on: content
|
|
453
|
+
title: "Instruction override: disregard system prompt"
|
|
454
|
+
expires_at: null
|
|
455
|
+
revoked: false
|