offrouter-core 0.5.1 → 0.6.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/dist/audit.d.ts +51 -2
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +60 -3
- package/dist/audit.js.map +1 -1
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +160 -1
- package/dist/config.js.map +1 -1
- package/dist/delegation.d.ts +40 -0
- package/dist/delegation.d.ts.map +1 -1
- package/dist/delegation.js +169 -8
- package/dist/delegation.js.map +1 -1
- package/dist/index.d.ts +27 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -7
- package/dist/index.js.map +1 -1
- package/dist/llm-judge.d.ts +41 -0
- package/dist/llm-judge.d.ts.map +1 -0
- package/dist/llm-judge.js +159 -0
- package/dist/llm-judge.js.map +1 -0
- package/dist/policy.d.ts +77 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +81 -0
- package/dist/policy.js.map +1 -1
- package/dist/provider-health.d.ts +129 -0
- package/dist/provider-health.d.ts.map +1 -0
- package/dist/provider-health.js +423 -0
- package/dist/provider-health.js.map +1 -0
- package/dist/providers/catalog-data.d.ts +7 -0
- package/dist/providers/catalog-data.d.ts.map +1 -1
- package/dist/providers/catalog-data.js +140 -53
- package/dist/providers/catalog-data.js.map +1 -1
- package/dist/providers/catalog.d.ts +3 -3
- package/dist/providers/catalog.d.ts.map +1 -1
- package/dist/providers/catalog.js +1 -0
- package/dist/providers/catalog.js.map +1 -1
- package/dist/proxy/anthropic-mapper.d.ts +585 -0
- package/dist/proxy/anthropic-mapper.d.ts.map +1 -0
- package/dist/proxy/anthropic-mapper.js +539 -0
- package/dist/proxy/anthropic-mapper.js.map +1 -0
- package/dist/proxy/anthropic-server.d.ts +24 -0
- package/dist/proxy/anthropic-server.d.ts.map +1 -0
- package/dist/proxy/anthropic-server.js +606 -0
- package/dist/proxy/anthropic-server.js.map +1 -0
- package/dist/proxy/classify.d.ts +17 -0
- package/dist/proxy/classify.d.ts.map +1 -0
- package/dist/proxy/classify.js +65 -0
- package/dist/proxy/classify.js.map +1 -0
- package/dist/proxy/responses-mapper.d.ts +15 -0
- package/dist/proxy/responses-mapper.d.ts.map +1 -1
- package/dist/proxy/responses-mapper.js +9 -2
- package/dist/proxy/responses-mapper.js.map +1 -1
- package/dist/proxy/responses-server.d.ts.map +1 -1
- package/dist/proxy/responses-server.js +14 -1
- package/dist/proxy/responses-server.js.map +1 -1
- package/dist/router.d.ts +36 -2
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +158 -23
- package/dist/router.js.map +1 -1
- package/dist/schemas.d.ts +115 -34
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +35 -0
- package/dist/schemas.js.map +1 -1
- package/dist/secret-scan.d.ts +40 -0
- package/dist/secret-scan.d.ts.map +1 -0
- package/dist/secret-scan.js +125 -0
- package/dist/secret-scan.js.map +1 -0
- package/dist/secrets.d.ts +77 -6
- package/dist/secrets.d.ts.map +1 -1
- package/dist/secrets.js +356 -32
- package/dist/secrets.js.map +1 -1
- package/dist/spend.d.ts +122 -0
- package/dist/spend.d.ts.map +1 -0
- package/dist/spend.js +279 -0
- package/dist/spend.js.map +1 -0
- package/dist/task-classifier.d.ts +45 -0
- package/dist/task-classifier.d.ts.map +1 -0
- package/dist/task-classifier.js +153 -0
- package/dist/task-classifier.js.map +1 -0
- package/dist/types.d.ts +46 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/usage-file.d.ts +2 -6
- package/dist/usage-file.d.ts.map +1 -1
- package/dist/usage-file.js +64 -6
- package/dist/usage-file.js.map +1 -1
- package/dist/usage.d.ts +64 -10
- package/dist/usage.d.ts.map +1 -1
- package/dist/usage.js +79 -5
- package/dist/usage.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outbound secret scanner for OffRouter V1.
|
|
3
|
+
*
|
|
4
|
+
* Scans prompt/message text once at the delegation choke point before any
|
|
5
|
+
* provider adapter is invoked. Reuses credential shapes from secrets.ts —
|
|
6
|
+
* does not maintain a parallel pattern catalog.
|
|
7
|
+
*
|
|
8
|
+
* Findings never carry raw matched values. Audit records get pattern names
|
|
9
|
+
* only; redacted excerpts are for in-process error/result envelopes.
|
|
10
|
+
*/
|
|
11
|
+
import { REDACTED, SECRET_PATTERNS } from "./secrets.js";
|
|
12
|
+
export const DEFAULT_OUTBOUND_SECRET_SCAN = "warn";
|
|
13
|
+
/**
|
|
14
|
+
* Thrown when policy.outboundSecretScan === "block" and findings are present.
|
|
15
|
+
* Message and `patternNames` name kinds only — never matched content.
|
|
16
|
+
*/
|
|
17
|
+
export class OutboundSecretBlockedError extends Error {
|
|
18
|
+
code = "outbound_secret_blocked";
|
|
19
|
+
patternNames;
|
|
20
|
+
constructor(patternNames) {
|
|
21
|
+
const unique = uniqueNames(patternNames);
|
|
22
|
+
const kinds = unique.join(", ");
|
|
23
|
+
super(`Outbound request blocked: content matched credential pattern(s): ${kinds}`);
|
|
24
|
+
this.name = "OutboundSecretBlockedError";
|
|
25
|
+
this.patternNames = unique;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const EXCERPT_CONTEXT_CHARS = 24;
|
|
29
|
+
/**
|
|
30
|
+
* Scan free text for known credential shapes.
|
|
31
|
+
* Returns findings with pattern names and redacted excerpts only.
|
|
32
|
+
*/
|
|
33
|
+
export function scanForSecrets(text) {
|
|
34
|
+
if (typeof text !== "string" || text.length === 0) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const findings = [];
|
|
38
|
+
// Track matched spans so a more-specific pattern (sk-ant-) wins over
|
|
39
|
+
// a later generic one (sk-) covering the same bytes.
|
|
40
|
+
const claimed = [];
|
|
41
|
+
for (const { name, pattern } of SECRET_PATTERNS) {
|
|
42
|
+
// Clone so concurrent/repeated scans cannot race shared lastIndex,
|
|
43
|
+
// and so we do not mutate the module-level regex object permanently
|
|
44
|
+
// beyond what redact() already does (it resets lastIndex each use).
|
|
45
|
+
const re = new RegExp(pattern.source, pattern.flags);
|
|
46
|
+
let match;
|
|
47
|
+
while ((match = re.exec(text)) !== null) {
|
|
48
|
+
const start = match.index;
|
|
49
|
+
const end = start + match[0].length;
|
|
50
|
+
if (end === start) {
|
|
51
|
+
// Zero-width guard — avoid infinite loop on broken patterns.
|
|
52
|
+
re.lastIndex = start + 1;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (overlapsAny(claimed, start, end)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
claimed.push({ start, end });
|
|
59
|
+
findings.push({
|
|
60
|
+
patternName: name,
|
|
61
|
+
redactedExcerpt: buildRedactedExcerpt(text, start, end),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return findings;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Join message contents (system/user/assistant/tool) for a single scan pass.
|
|
69
|
+
*/
|
|
70
|
+
export function collectOutboundText(messages) {
|
|
71
|
+
return messages
|
|
72
|
+
.map((m) => (typeof m.content === "string" ? m.content : ""))
|
|
73
|
+
.filter((c) => c.length > 0)
|
|
74
|
+
.join("\n");
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Apply scan mode to findings collected from outbound text.
|
|
78
|
+
* - "off": empty result, no throw
|
|
79
|
+
* - "warn": return findings (caller audits / attaches warnings)
|
|
80
|
+
* - "block": throw OutboundSecretBlockedError when findings exist
|
|
81
|
+
*/
|
|
82
|
+
export function enforceOutboundSecretScan(text, mode) {
|
|
83
|
+
const effective = mode ?? DEFAULT_OUTBOUND_SECRET_SCAN;
|
|
84
|
+
if (effective === "off") {
|
|
85
|
+
return [];
|
|
86
|
+
}
|
|
87
|
+
const findings = scanForSecrets(text);
|
|
88
|
+
if (findings.length === 0) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
if (effective === "block") {
|
|
92
|
+
throw new OutboundSecretBlockedError(findings.map((f) => f.patternName));
|
|
93
|
+
}
|
|
94
|
+
// warn
|
|
95
|
+
return findings;
|
|
96
|
+
}
|
|
97
|
+
function buildRedactedExcerpt(text, matchStart, matchEnd) {
|
|
98
|
+
const beforeStart = Math.max(0, matchStart - EXCERPT_CONTEXT_CHARS);
|
|
99
|
+
const afterEnd = Math.min(text.length, matchEnd + EXCERPT_CONTEXT_CHARS);
|
|
100
|
+
const before = text.slice(beforeStart, matchStart);
|
|
101
|
+
const after = text.slice(matchEnd, afterEnd);
|
|
102
|
+
const prefix = beforeStart > 0 ? "…" : "";
|
|
103
|
+
const suffix = afterEnd < text.length ? "…" : "";
|
|
104
|
+
// Surrounding context only — match replaced by the shared placeholder.
|
|
105
|
+
return `${prefix}${before}${REDACTED}${after}${suffix}`;
|
|
106
|
+
}
|
|
107
|
+
function overlapsAny(claimed, start, end) {
|
|
108
|
+
for (const c of claimed) {
|
|
109
|
+
if (start < c.end && end > c.start)
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
function uniqueNames(names) {
|
|
115
|
+
const seen = new Set();
|
|
116
|
+
const out = [];
|
|
117
|
+
for (const n of names) {
|
|
118
|
+
if (!seen.has(n)) {
|
|
119
|
+
seen.add(n);
|
|
120
|
+
out.push(n);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=secret-scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scan.js","sourceRoot":"","sources":["../src/secret-scan.ts"],"names":[],"mappings":"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"}
|
package/dist/secrets.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkdir, readFile, rename, unlink, writeFile, chmod } from "node:fs/promises";
|
|
2
|
-
|
|
2
|
+
import { type ExecFileOptions } from "node:child_process";
|
|
3
3
|
/** Placeholder substituted for secret material in log-safe strings. */
|
|
4
4
|
export declare const REDACTED: "[REDACTED]";
|
|
5
5
|
/**
|
|
@@ -28,10 +28,19 @@ export interface FileSecretStoreOptions {
|
|
|
28
28
|
/** Injectable file operations for failure-path tests. Defaults to node fs. */
|
|
29
29
|
fileSystem?: Partial<FileSecretStoreFileSystem>;
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Injectable execFile for KeychainSecretStore tests.
|
|
33
|
+
* Mirrors node:child_process execFile Promise form (promisified).
|
|
34
|
+
*/
|
|
35
|
+
export type KeychainExecFile = (file: string, args: readonly string[] | null | undefined, options?: ExecFileOptions) => Promise<{
|
|
36
|
+
stdout: string | Buffer;
|
|
37
|
+
stderr: string | Buffer;
|
|
38
|
+
}>;
|
|
31
39
|
export interface KeychainSecretStoreOptions {
|
|
32
40
|
/**
|
|
33
41
|
* Keychain/keyring service name. OffRouter only reads entries it wrote
|
|
34
42
|
* under this service — never foreign CLI credential stores.
|
|
43
|
+
* Full security `-s` value is `${service}:${scope}` (default scope "default").
|
|
35
44
|
*/
|
|
36
45
|
service?: string;
|
|
37
46
|
/**
|
|
@@ -39,6 +48,33 @@ export interface KeychainSecretStoreOptions {
|
|
|
39
48
|
* Full item name is `${accountPrefix}${providerId}`.
|
|
40
49
|
*/
|
|
41
50
|
accountPrefix?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Service scope segment appended after `service` (default "default").
|
|
53
|
+
* Final security service string: `${service}:${scope}`.
|
|
54
|
+
*/
|
|
55
|
+
scope?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Path to the non-secret provider-id index file used by listProviders().
|
|
58
|
+
* Defaults to `$OFFROUTER_HOME/keychain-index.json` (or `~/.offrouter/...`).
|
|
59
|
+
* Contains provider ids only — never secret values.
|
|
60
|
+
*/
|
|
61
|
+
indexPath?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Absolute path to the `security` binary. Defaults to `/usr/bin/security`.
|
|
64
|
+
*/
|
|
65
|
+
securityPath?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Override platform detection (tests). Defaults to `process.platform`.
|
|
68
|
+
*/
|
|
69
|
+
platform?: NodeJS.Platform;
|
|
70
|
+
/**
|
|
71
|
+
* Injectable execFile used to invoke `security`. Defaults to promisified
|
|
72
|
+
* child_process.execFile. Tests MUST inject a fake — never touch the real
|
|
73
|
+
* keychain in automated tests.
|
|
74
|
+
*/
|
|
75
|
+
execFile?: KeychainExecFile;
|
|
76
|
+
/** Injectable file operations for the non-secret index. */
|
|
77
|
+
fileSystem?: Partial<FileSecretStoreFileSystem>;
|
|
42
78
|
}
|
|
43
79
|
interface FileSecretStoreFileSystem {
|
|
44
80
|
mkdir: typeof mkdir;
|
|
@@ -48,6 +84,21 @@ interface FileSecretStoreFileSystem {
|
|
|
48
84
|
writeFile: typeof writeFile;
|
|
49
85
|
chmod: typeof chmod;
|
|
50
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Named credential shapes shared by log redaction and outbound secret scan.
|
|
89
|
+
* Patterns are intentionally conservative (long alphabetic payload)
|
|
90
|
+
* to avoid eating short unrelated tokens while still catching leaks.
|
|
91
|
+
*
|
|
92
|
+
* Each entry's `pattern` is a global RegExp; callers must reset lastIndex.
|
|
93
|
+
* More-specific prefixes (sk-ant-, sk-proj-) are listed before generic sk-
|
|
94
|
+
* so scanners can attribute the first match correctly.
|
|
95
|
+
*/
|
|
96
|
+
export interface SecretPatternDef {
|
|
97
|
+
/** Stable identifier for policy/audit (never includes matched content). */
|
|
98
|
+
name: string;
|
|
99
|
+
pattern: RegExp;
|
|
100
|
+
}
|
|
101
|
+
export declare const SECRET_PATTERNS: readonly SecretPatternDef[];
|
|
51
102
|
/**
|
|
52
103
|
* Standalone redaction for log/audit paths that do not hold a store.
|
|
53
104
|
* Optionally rejects known secret values (longest-first to avoid partials).
|
|
@@ -79,18 +130,38 @@ export declare class KeychainUnavailableError extends Error {
|
|
|
79
130
|
});
|
|
80
131
|
}
|
|
81
132
|
/**
|
|
82
|
-
*
|
|
133
|
+
* macOS Keychain-backed secret store.
|
|
134
|
+
*
|
|
135
|
+
* Uses `/usr/bin/security` via `child_process.execFile` (argv only — never a
|
|
136
|
+
* shell). OffRouter only reads entries it wrote under the namespaced service
|
|
137
|
+
* `${service}:${scope}` (default `offrouter:default`). Account names are
|
|
138
|
+
* `${accountPrefix}${providerId}` (default `provider:<id>`).
|
|
139
|
+
*
|
|
140
|
+
* Secret values are written via `security -i` (interactive command mode):
|
|
141
|
+
* a single `add-generic-password ... -U -X <hex>` line is sent on stdin. The
|
|
142
|
+
* process argv is only `security -i`, so the secret never appears in `ps`.
|
|
143
|
+
* (Bare `security add-generic-password -w` without a value reads `/dev/tty`,
|
|
144
|
+
* not a pipe — that path is intentionally avoided.)
|
|
145
|
+
*
|
|
146
|
+
* Listing cannot be done safely via `security dump-keychain` (it dumps the
|
|
147
|
+
* entire keychain). Instead, a non-secret index of provider ids is maintained
|
|
148
|
+
* at `indexPath` (default `$OFFROUTER_HOME/keychain-index.json`). The index
|
|
149
|
+
* never contains secret values and is written with mode 0600.
|
|
83
150
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* runs once keychain support lands; tests and dry runs use FileSecretStore.
|
|
151
|
+
* Non-darwin platforms throw KeychainUnavailableError with the same message
|
|
152
|
+
* shape historical callers expect (`OS keychain backend is not wired...`).
|
|
153
|
+
* Tests must inject `execFile` and must never touch the real keychain.
|
|
88
154
|
*/
|
|
89
155
|
export declare class KeychainSecretStore implements SecretStore {
|
|
90
156
|
#private;
|
|
91
157
|
readonly service: string;
|
|
92
158
|
readonly accountPrefix: string;
|
|
159
|
+
readonly scope: string;
|
|
160
|
+
readonly indexPath: string;
|
|
161
|
+
readonly securityPath: string;
|
|
93
162
|
constructor(options?: KeychainSecretStoreOptions);
|
|
163
|
+
/** security(1) `-s` service string: `offrouter:<scope>`. */
|
|
164
|
+
get securityService(): string;
|
|
94
165
|
get(providerId: string): Promise<string | undefined>;
|
|
95
166
|
set(providerId: string, secret: string): Promise<void>;
|
|
96
167
|
delete(providerId: string): Promise<void>;
|
package/dist/secrets.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,MAAM,EACN,SAAS,EACT,KAAK,EACN,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"secrets.d.ts","sourceRoot":"","sources":["../src/secrets.ts"],"names":[],"mappings":"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"}
|