@atbash/sdk 0.3.7 → 0.3.9-dev.1

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 CHANGED
@@ -21,8 +21,8 @@ import { loadAgent, judgeAction } from "@atbash/sdk";
21
21
  const agent = loadAgent(process.env.ATBASH_AGENT_PRIVKEY!);
22
22
 
23
23
  // 2. Submit an action for judgment, before executing it.
24
- // The SDK signs and broadcasts log_tool_call to the Chromia chain
25
- // (private key stays local), then requests a verdict from the judge API.
24
+ // The SDK signs the transaction locally and sends it to the judge API.
25
+ // Private key stays on your machine never sent over HTTP.
26
26
  const result = await judgeAction(
27
27
  "Transfer $50,000 to external wallet 0xabc",
28
28
  "Outbound AML check — new recipient, over threshold",
@@ -50,10 +50,9 @@ Before this works, the agent must be onboarded at [atbash.ai](https://atbash.ai/
50
50
 
51
51
  `judgeAction()` performs a two-step flow:
52
52
 
53
- 1. **Sign on-chain** — signs and broadcasts a `log_tool_call` transaction to the Chromia blockchain using the agent's private key. The key never leaves your machine.
54
- 2. **Request verdict** — sends the resulting `tool_call_id` and `agent_pubkey` to the Atbash judge API. No private key is transmitted over HTTP.
53
+ 1. **Sign locally** — signs the transaction using the agent's private key. The key never leaves your machine.
54
+ 2. **Request verdict** — sends the signed transaction, `tool_call_id`, and `agent_pubkey` to the Atbash judge API. The server broadcasts it to the Chromia blockchain and returns a verdict.
55
55
 
56
- If you need finer control, you can call `logToolCall()` and the judge API separately.
57
56
 
58
57
  ### Don't have an agent yet?
59
58
 
@@ -75,12 +74,9 @@ const agent = loadAgent(privKey);
75
74
 
76
75
  ### Secret storage
77
76
 
78
- The private key is used to sign on-chain transactions locally. Treat it like any other long-lived credential:
79
-
80
- - Load it from an environment variable (`ATBASH_AGENT_PRIVKEY`) or a secret manager (AWS Secrets Manager, HashiCorp Vault, 1Password, etc.) — never hardcode it.
81
- - Never commit `.env` files containing the key. Add them to `.gitignore`.
82
- - If a key leaks, revoke the agent and create a new one in the [Atbash dashboard](https://atbash.ai/risk-engine/agents).
83
- - The SDK is **server-side only** — the key must never ship to a browser bundle.
77
+ - Load the private key from an environment variable (`ATBASH_AGENT_KEY`) or a secret manager never hardcode it.
78
+ - Never commit `.env` files containing the key.
79
+ - If a key leaks, stop using it and create a new agent in the [dashboard](https://atbash.ai/risk-engine/agents).
84
80
 
85
81
  ## Verdicts
86
82
 
@@ -107,7 +103,7 @@ judgeAction(
107
103
  ): Promise<JudgeResult>
108
104
  ```
109
105
 
110
- Submit an action for judgment before execution. Signs `log_tool_call` on-chain, then requests a verdict. Returns the verdict, reason, confidence, provider, latency, and tool call ID.
106
+ Submit an action for judgment before execution. Signs the transaction locally and sends it to the judge API for a verdict.
111
107
 
112
108
  ```ts
113
109
  interface AgentAuth {
@@ -154,12 +150,12 @@ logToolCall(
154
150
  ): Promise<LogToolCallResult>
155
151
  ```
156
152
 
157
- Sign `log_tool_call` on the Chromia chain. Returns `{ success, toolCallId, error? }`. Use this if you need to separate the on-chain logging step from the verdict request.
153
+ Sign the transaction locally. Returns `{ success, toolCallId, signedHex?, error? }`. Use this if you need to separate the signing step from the verdict request.
158
154
 
159
155
  ### Poll judgment status
160
156
 
161
157
  ```ts
162
- getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>
158
+ getJudgmentStatus(judgmentId: string, agentPubkey: string, opts?: ClientOpts): Promise<JudgmentStatus>
163
159
  ```
164
160
 
165
161
  Check whether a held action has been approved or rejected by an operator.
@@ -194,15 +190,15 @@ Functions that sign transactions and write to the Chromia blockchain.
194
190
 
195
191
  | Function | Use case |
196
192
  |----------|----------|
197
- | `judgeAction(action, context, auth, opts?)` | Sign `log_tool_call` on-chain + request a verdict from the judge API |
198
- | `logToolCall(action, context, auth, ...)` | Sign and broadcast `log_tool_call` to chain without requesting a verdict |
193
+ | `judgeAction(action, context, auth, opts?)` | Sign locally + request a verdict from the judge API |
194
+ | `logToolCall(action, context, auth, ...)` | Sign the transaction locally without requesting a verdict |
199
195
 
200
196
  ### Queries
201
197
 
202
198
  | Function | Use case |
203
199
  |----------|----------|
204
200
  | `checkAgentExists(pubkey, opts?)` | Check if an agent is onboarded before signing |
205
- | `getJudgmentStatus(judgmentId, opts?)` | Poll whether a held action has been approved or rejected |
201
+ | `getJudgmentStatus(judgmentId, agentPubkey, opts?)` | Poll whether a held action has been approved or rejected |
206
202
  | `getToolCalls(maxCount)` | List recent tool calls across all agents |
207
203
  | `getOrgToolCalls(orgName, maxCount)` | List tool calls for a specific org |
208
204
  | `getAgentToolCalls(pubkey, maxCount)` | List tool calls for a specific agent |
@@ -217,24 +213,78 @@ Functions that sign transactions and write to the Chromia blockchain.
217
213
 
218
214
  ## Configuration
219
215
 
220
- The SDK reads no environment variables and has no global state. Pass configuration explicitly:
216
+ You can pass configuration inline or use the built-in config module that reads from `~/.config/atbash/config.json`.
217
+
218
+ ### Inline
221
219
 
222
220
  ```ts
223
- // Custom endpoint
224
221
  const result = await judgeAction(action, context, auth, {
225
222
  endpoint: "https://your-instance.example.com",
223
+ provider: "openai",
224
+ model: "gpt-4o",
226
225
  });
226
+ ```
227
227
 
228
- // Custom provider (API keys are saved in the dashboard, not passed here)
229
- const result = await judgeAction(action, context, auth, {
228
+ ### Persistent config
229
+
230
+ Save configuration once — the SDK resolves values with priority: **flag > env var > config file**.
231
+
232
+ ```ts
233
+ import { saveUserConfig, resolve, loadAgent, judgeAction } from "@atbash/sdk";
234
+
235
+ // Save once
236
+ saveUserConfig({
237
+ agentKey: "9cd07a...",
238
+ orgName: "my_org",
230
239
  provider: "openai",
231
- model: "gpt-4o",
232
240
  });
233
241
 
242
+ // Then use resolve() anywhere
243
+ const agent = loadAgent(resolve("agentKey"));
244
+ const result = await judgeAction("Transfer $500", "finance", agent, {
245
+ provider: resolve("provider"), // omit to use the on-chain ATBASH judge
246
+ });
234
247
  ```
235
248
 
249
+ Config file location: `~/.config/atbash/config.json`
250
+
251
+ | Function | Purpose |
252
+ |----------|---------|
253
+ | `saveUserConfig(config)` | Write config to disk |
254
+ | `loadUserConfig()` | Read config from disk |
255
+ | `resolve(key, flagValue?)` | Resolve a value: flag > env > file > `""` |
256
+ | `getConfigPath()` | Returns the config file path |
257
+
258
+ | Config key | Env var |
259
+ |------------|--------|
260
+ | `agentKey` | `ATBASH_AGENT_KEY` |
261
+ | `orgName` | `ATBASH_ORG_NAME` |
262
+ | `judgeEndpoint` | `ATBASH_ENDPOINT` |
263
+ | `blockchainRid` | `ATBASH_BLOCKCHAIN_RID` |
264
+ | `provider` | `ATBASH_PROVIDER` |
265
+ | `providerModel` | `ATBASH_PROVIDER_MODEL` |
266
+
236
267
  > **Advanced:** The SDK connects to the default Atbash Chromia chain. To use a different chain, pass `chainOpts` with custom `nodeUrls` and `blockchainRid` in `JudgeOptions`.
237
268
 
269
+ ## Secret redaction
270
+
271
+ Before each `auditToolCall` signs anything, the SDK scans `args` and `context` for secret-shaped values (API keys, tokens, JWTs, PEM blocks, etc.) and replaces matches with `[REDACTED:<kind>]`. Redaction happens **before signing**, so secrets never reach the signed bytes, the request body, the on-chain log, or the prompt sent to the AI provider.
272
+
273
+ When the redactor fires, you'll see a warning via the configured `logger`:
274
+
275
+ ```
276
+ [atbash] redacted secrets before judge call { tool: "exec", count: 2, kinds: ["anthropic", "generic_token"] }
277
+ ```
278
+
279
+ Common `kinds`:
280
+
281
+ - `anthropic`, `openai`, `github`, `google`, `aws_access_key`, `stripe`, `slack`, `jwt`, `private_key_pem` — high-confidence vendor patterns; if you see these, a real secret was almost certainly in your input
282
+ - `context_secret` — a value next to a label like `api_key=`, `token:`, `password=`, etc.
283
+ - `generic_token` — long random-looking strings (32+ alphanumeric chars). Catches unknown-vendor secrets, but can also match UUIDs, content hashes, and other opaque identifiers. The judge sees `[REDACTED:generic_token]` instead of the original; for verdict purposes the shape of the action matters more than the exact ID, so this is generally safe — but worth knowing if you see it unexpectedly.
284
+ - `base64` — long base64-encoded values; can match legitimate image/file data
285
+
286
+ Redaction is silent at the consumer level — the SDK's caller still has the original arguments. Only what's sent to the judge (and persisted on chain via the verdict log) is scrubbed.
287
+
238
288
  ## Integration patterns
239
289
 
240
290
  ### Pre-execution gate
@@ -253,7 +303,7 @@ async function safeExecute(action: string, context: string, execute: () => Promi
253
303
  ```ts
254
304
  async function waitForApproval(toolCallId: string): Promise<string> {
255
305
  while (true) {
256
- const status = await getJudgmentStatus(toolCallId);
306
+ const status = await getJudgmentStatus(toolCallId, auth.pubkey);
257
307
  if (status.status === "answered") return status.verdict;
258
308
  if (status.status === "error") throw new Error(status.reason);
259
309
  await new Promise((r) => setTimeout(r, 5000));
package/dist/index.cjs CHANGED
@@ -40,6 +40,8 @@ __export(index_exports, {
40
40
  getAgentDetail: () => getAgentDetail,
41
41
  getAgentPolicy: () => getAgentPolicy,
42
42
  getAgentToolCalls: () => getAgentToolCalls,
43
+ getConfigDir: () => getConfigDir,
44
+ getConfigPath: () => getConfigPath,
43
45
  getHeldActionReviews: () => getHeldActionReviews,
44
46
  getJudgmentStatus: () => getJudgmentStatus,
45
47
  getOrgTierInfo: () => getOrgTierInfo,
@@ -53,8 +55,11 @@ __export(index_exports, {
53
55
  judgeAction: () => judgeAction,
54
56
  loadAgent: () => loadAgent,
55
57
  loadAgentFromFile: () => loadAgentFromFile,
58
+ loadUserConfig: () => loadUserConfig,
56
59
  logToolCall: () => logToolCall,
60
+ resolve: () => resolve,
57
61
  resolveKeyPath: () => resolveKeyPath,
62
+ saveUserConfig: () => saveUserConfig,
58
63
  toPubkeyHex: () => toPubkeyHex,
59
64
  validateJudgeEndpoint: () => validateJudgeEndpoint,
60
65
  verifyJudgeResponseSignature: () => verifyJudgeResponseSignature
@@ -93,7 +98,7 @@ function verifyJudgeResponseSignature(bodyBytes, signatureHex, pubKeyHex) {
93
98
 
94
99
  // src/client.ts
95
100
  var { createClient, encryption: encryption2, newSignatureProvider } = import_postchain_client2.default;
96
- var DEFAULT_ENDPOINT = "https://atbash.ai";
101
+ var DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
97
102
  var DEFAULT_CHROMIA_NODE_URLS = [
98
103
  "https://node6.testnet.chromia.com:7740",
99
104
  "https://node7.testnet.chromia.com:7740",
@@ -333,8 +338,8 @@ async function judgeAction(action, context = "", auth, opts) {
333
338
  on_chain: Boolean(data.on_chain)
334
339
  };
335
340
  }
336
- async function getJudgmentStatus(judgmentId, opts) {
337
- const url = `${baseUrl(opts)}/api/v1/judge?tool_call_id=${encodeURIComponent(judgmentId)}`;
341
+ async function getJudgmentStatus(judgmentId, agentPubkey, opts) {
342
+ const url = `${baseUrl(opts)}/api/v1/judge?tool_call_id=${encodeURIComponent(judgmentId)}&agent_pubkey=${encodeURIComponent(agentPubkey)}`;
338
343
  const data = await getJson(url, opts);
339
344
  return {
340
345
  status: normalizeStatus(data.status),
@@ -540,6 +545,77 @@ function loadAgentFromFile(keyPath) {
540
545
  return loadAgent(privKey);
541
546
  }
542
547
 
548
+ // src/redact-secrets.ts
549
+ var PATTERNS = [
550
+ { kind: "anthropic", re: /\bsk-ant-[A-Za-z0-9_-]{20,}/g },
551
+ { kind: "openai_project", re: /\bsk-proj-[A-Za-z0-9_-]{20,}/g },
552
+ { kind: "openai", re: /\bsk-[A-Za-z0-9]{20,}/g },
553
+ { kind: "github", re: /\b(?:gh[pousr]|github_pat)_[A-Za-z0-9_]{30,}/g },
554
+ { kind: "google", re: /\bAIza[0-9A-Za-z_-]{35}/g },
555
+ { kind: "google_oauth", re: /\bya29\.[0-9A-Za-z_-]{20,}/g },
556
+ {
557
+ kind: "aws_access_key",
558
+ re: /\b(?:AKIA|ASIA|AGPA|AROA|ANPA|ANVA|ASCA|AIDA|AIPA)[0-9A-Z]{16}\b/g
559
+ },
560
+ { kind: "stripe", re: /\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g },
561
+ { kind: "slack", re: /\bxox[abprseo]-[A-Za-z0-9-]{10,}/g },
562
+ {
563
+ kind: "slack_webhook",
564
+ re: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9]+\/B[A-Za-z0-9]+\/[A-Za-z0-9]{20,}/g
565
+ },
566
+ { kind: "sendgrid", re: /\bSG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g },
567
+ { kind: "twilio_sid", re: /\bAC[0-9a-fA-F]{32}\b/g },
568
+ { kind: "mailgun", re: /\bkey-[0-9a-f]{32}\b/g },
569
+ { kind: "npm_token", re: /\bnpm_[A-Za-z0-9]{36,}\b/g },
570
+ { kind: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g },
571
+ {
572
+ kind: "private_key_pem",
573
+ re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
574
+ },
575
+ {
576
+ kind: "aws_secret_key",
577
+ re: /(?:aws[_-]?secret|secret[_-]?access[_-]?key)["'\s:=]{1,10}[A-Za-z0-9/+=]{40}/gi
578
+ },
579
+ {
580
+ kind: "generic_token",
581
+ re: /\b(?=[A-Za-z0-9_-]*[0-9])(?=[A-Za-z0-9_-]*[A-Za-z])(?![0-9a-fA-F]+$)[A-Za-z0-9_-]{32,}\b/g
582
+ },
583
+ {
584
+ kind: "base64",
585
+ re: /(?<![A-Za-z0-9+/])(?=[A-Za-z0-9+/]*[+/])(?=[A-Za-z0-9+/]*[0-9])(?=[A-Za-z0-9+/]*[A-Za-z])[A-Za-z0-9+/]{40,}={0,2}(?![A-Za-z0-9+/=])/g
586
+ },
587
+ {
588
+ kind: "context_secret",
589
+ re: /(?<![A-Za-z0-9_])(?:api[_-]?key|api[_-]?secret|access[_-]?token|refresh[_-]?token|auth[_-]?token|client[_-]?secret|password|passwd|pwd|secret|token|credential|private[_-]?key)["']?\s*[:=]\s*["']?([A-Za-z0-9+/=._-]{12,})(?=["'\s,;)\]}>]|$)/gi,
590
+ groupOnly: true
591
+ },
592
+ {
593
+ kind: "bearer",
594
+ re: /(?<![A-Za-z0-9_])Bearer\s+([A-Za-z0-9._-]{20,})\b/gi,
595
+ groupOnly: true
596
+ }
597
+ ];
598
+ function redactSecrets(input) {
599
+ if (!input) return { redacted: input ?? "", found: [] };
600
+ const found = [];
601
+ let working = input;
602
+ for (const { kind, re, groupOnly } of PATTERNS) {
603
+ if (groupOnly) {
604
+ working = working.replace(re, (full, value) => {
605
+ if (typeof value !== "string" || !value) return full;
606
+ found.push({ kind, length: value.length });
607
+ return full.replace(value, `[REDACTED:${kind}]`);
608
+ });
609
+ } else {
610
+ working = working.replace(re, (m) => {
611
+ found.push({ kind, length: m.length });
612
+ return `[REDACTED:${kind}]`;
613
+ });
614
+ }
615
+ }
616
+ return { redacted: working, found };
617
+ }
618
+
543
619
  // src/factory.ts
544
620
  function createAtbashClient(config = {}) {
545
621
  const validated = validateJudgeEndpoint(config.judge);
@@ -576,9 +652,23 @@ function createAtbashClient(config = {}) {
576
652
  return fail("key load failed, blocking for safety");
577
653
  }
578
654
  const toolName = input.toolName || "unknown";
579
- const argsJson = stringifyArgs(input.args);
655
+ const argsRedaction = redactSecrets(stringifyArgs(input.args));
656
+ const ctxRedaction = redactSecrets(input.context ?? toolName);
657
+ const argsJson = argsRedaction.redacted;
580
658
  const actionText = truncate(argsJson);
581
- const contextText = input.context ?? toolName;
659
+ const contextText = ctxRedaction.redacted;
660
+ const totalRedactions = argsRedaction.found.length + ctxRedaction.found.length;
661
+ if (totalRedactions > 0) {
662
+ const kinds = [.../* @__PURE__ */ new Set([
663
+ ...argsRedaction.found.map((f) => f.kind),
664
+ ...ctxRedaction.found.map((f) => f.kind)
665
+ ])];
666
+ logger.warn?.("[atbash] redacted secrets before judge call", {
667
+ tool: toolName,
668
+ count: totalRedactions,
669
+ kinds
670
+ });
671
+ }
582
672
  try {
583
673
  logger.info?.("[atbash] judge API called", { tool: toolName });
584
674
  const result = await judgeAction(actionText, contextText, agent, {
@@ -648,6 +738,56 @@ function truncate(text) {
648
738
  if (text.length <= MAX_ACTION_LEN) return text;
649
739
  return text.slice(0, MAX_ACTION_LEN) + "\u2026";
650
740
  }
741
+
742
+ // src/user-config.ts
743
+ var import_node_fs2 = require("fs");
744
+ var import_node_os2 = require("os");
745
+ var import_node_path2 = require("path");
746
+ var ENV_MAP = {
747
+ agentKey: "ATBASH_AGENT_KEY",
748
+ orgName: "ATBASH_ORG_NAME",
749
+ judgeEndpoint: "ATBASH_ENDPOINT",
750
+ blockchainRid: "ATBASH_BLOCKCHAIN_RID",
751
+ provider: "ATBASH_PROVIDER",
752
+ providerModel: "ATBASH_PROVIDER_MODEL"
753
+ };
754
+ function getConfigDir() {
755
+ const home = process.env.HOME || (0, import_node_os2.homedir)() || "";
756
+ return (0, import_node_path2.join)(home, ".config", "atbash");
757
+ }
758
+ function getConfigPath() {
759
+ return (0, import_node_path2.join)(getConfigDir(), "config.json");
760
+ }
761
+ function loadUserConfig() {
762
+ try {
763
+ const p = getConfigPath();
764
+ if (!(0, import_node_fs2.existsSync)(p)) return {};
765
+ const raw = (0, import_node_fs2.readFileSync)(p, "utf-8").trim();
766
+ if (!raw) return {};
767
+ return JSON.parse(raw);
768
+ } catch (err) {
769
+ console.error("Failed to load config file", err);
770
+ return {};
771
+ }
772
+ }
773
+ function saveUserConfig(config) {
774
+ const dir = getConfigDir();
775
+ if (!(0, import_node_fs2.existsSync)(dir)) {
776
+ (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
777
+ }
778
+ (0, import_node_fs2.writeFileSync)(getConfigPath(), JSON.stringify(config, null, 2) + "\n", "utf-8");
779
+ }
780
+ function resolve(key, flagValue) {
781
+ if (flagValue) return flagValue;
782
+ const envName = ENV_MAP[key];
783
+ if (envName) {
784
+ const envVal = process.env[envName];
785
+ if (envVal) return envVal;
786
+ }
787
+ const fileVal = loadUserConfig()[key];
788
+ if (fileVal != null) return String(fileVal);
789
+ return "";
790
+ }
651
791
  // Annotate the CommonJS export names for ESM import in node:
652
792
  0 && (module.exports = {
653
793
  DEFAULT_BLOCKCHAIN_RID,
@@ -660,6 +800,8 @@ function truncate(text) {
660
800
  getAgentDetail,
661
801
  getAgentPolicy,
662
802
  getAgentToolCalls,
803
+ getConfigDir,
804
+ getConfigPath,
663
805
  getHeldActionReviews,
664
806
  getJudgmentStatus,
665
807
  getOrgTierInfo,
@@ -673,8 +815,11 @@ function truncate(text) {
673
815
  judgeAction,
674
816
  loadAgent,
675
817
  loadAgentFromFile,
818
+ loadUserConfig,
676
819
  logToolCall,
820
+ resolve,
677
821
  resolveKeyPath,
822
+ saveUserConfig,
678
823
  toPubkeyHex,
679
824
  validateJudgeEndpoint,
680
825
  verifyJudgeResponseSignature
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
2
- type Provider = "atbash" | "openai" | "google" | "microsoft" | "custom" | (string & {});
2
+ type Provider = "openai" | "google" | "microsoft" | "custom" | (string & {});
3
3
  type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
4
4
  type ActionType = "allow" | "hold_for_user_confirm" | "block" | (string & {});
5
5
  type PubkeyValue = string | Buffer | {
@@ -148,7 +148,7 @@ interface AtbashClientConfig {
148
148
  };
149
149
  }
150
150
 
151
- declare const DEFAULT_ENDPOINT = "https://atbash.ai";
151
+ declare const DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
152
152
  declare const DEFAULT_CHROMIA_NODE_URLS: string[];
153
153
  declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
154
154
  declare function isValidPrivateKey(hex: string): boolean;
@@ -176,7 +176,7 @@ declare function logToolCall(action: string, context: string, auth: AgentAuth, c
176
176
  toolArgsJson?: string;
177
177
  }, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
178
178
  declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
179
- declare function getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>;
179
+ declare function getJudgmentStatus(judgmentId: string, agentPubkey: string, opts?: ClientOpts): Promise<JudgmentStatus>;
180
180
  declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
181
181
  declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
182
182
  declare function getAgentToolCalls(agentPubkey: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
@@ -204,4 +204,18 @@ declare function verifyJudgeResponseSignature(bodyBytes: Uint8Array, signatureHe
204
204
  reason?: string;
205
205
  };
206
206
 
207
- export { type ActionType, type AgentAuth, type AgentPolicy, type AtbashClient, type AtbashClientConfig, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type Decision, type DecisionVerdict, type HeldAction, type HeldActionReview, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, createAtbashClient, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, logToolCall, resolveKeyPath, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
207
+ interface AtbashUserConfig {
208
+ agentKey?: string;
209
+ orgName?: string;
210
+ judgeEndpoint?: string;
211
+ blockchainRid?: string;
212
+ provider?: string;
213
+ providerModel?: string;
214
+ }
215
+ declare function getConfigDir(): string;
216
+ declare function getConfigPath(): string;
217
+ declare function loadUserConfig(): AtbashUserConfig;
218
+ declare function saveUserConfig(config: AtbashUserConfig): void;
219
+ declare function resolve(key: keyof AtbashUserConfig, flagValue?: string): string;
220
+
221
+ export { type ActionType, type AgentAuth, type AgentPolicy, type AtbashClient, type AtbashClientConfig, type AtbashUserConfig, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type Decision, type DecisionVerdict, type HeldAction, type HeldActionReview, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, createAtbashClient, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getConfigDir, getConfigPath, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, loadUserConfig, logToolCall, resolve, resolveKeyPath, saveUserConfig, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  type Verdict = "ALLOW" | "HOLD" | "BLOCK" | "No verdict";
2
- type Provider = "atbash" | "openai" | "google" | "microsoft" | "custom" | (string & {});
2
+ type Provider = "openai" | "google" | "microsoft" | "custom" | (string & {});
3
3
  type Tier = "audit" | "audit_plus" | "enforcement" | (string & {});
4
4
  type ActionType = "allow" | "hold_for_user_confirm" | "block" | (string & {});
5
5
  type PubkeyValue = string | Buffer | {
@@ -148,7 +148,7 @@ interface AtbashClientConfig {
148
148
  };
149
149
  }
150
150
 
151
- declare const DEFAULT_ENDPOINT = "https://atbash.ai";
151
+ declare const DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
152
152
  declare const DEFAULT_CHROMIA_NODE_URLS: string[];
153
153
  declare const DEFAULT_BLOCKCHAIN_RID = "25B41DF620C489349C54944496FF5C6E58CFCEFED0C51658780B67299D40E8ED";
154
154
  declare function isValidPrivateKey(hex: string): boolean;
@@ -176,7 +176,7 @@ declare function logToolCall(action: string, context: string, auth: AgentAuth, c
176
176
  toolArgsJson?: string;
177
177
  }, clientOpts?: ClientOpts): Promise<LogToolCallResult>;
178
178
  declare function judgeAction(action: string, context: string | undefined, auth: AgentAuth, opts?: JudgeOptions): Promise<JudgeResult>;
179
- declare function getJudgmentStatus(judgmentId: string, opts?: ClientOpts): Promise<JudgmentStatus>;
179
+ declare function getJudgmentStatus(judgmentId: string, agentPubkey: string, opts?: ClientOpts): Promise<JudgmentStatus>;
180
180
  declare function getToolCalls(maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
181
181
  declare function getOrgToolCalls(orgName: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
182
182
  declare function getAgentToolCalls(agentPubkey: string, maxCount: number, opts?: ClientOpts): Promise<ToolCallRecord[]>;
@@ -204,4 +204,18 @@ declare function verifyJudgeResponseSignature(bodyBytes: Uint8Array, signatureHe
204
204
  reason?: string;
205
205
  };
206
206
 
207
- export { type ActionType, type AgentAuth, type AgentPolicy, type AtbashClient, type AtbashClientConfig, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type Decision, type DecisionVerdict, type HeldAction, type HeldActionReview, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, createAtbashClient, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, logToolCall, resolveKeyPath, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
207
+ interface AtbashUserConfig {
208
+ agentKey?: string;
209
+ orgName?: string;
210
+ judgeEndpoint?: string;
211
+ blockchainRid?: string;
212
+ provider?: string;
213
+ providerModel?: string;
214
+ }
215
+ declare function getConfigDir(): string;
216
+ declare function getConfigPath(): string;
217
+ declare function loadUserConfig(): AtbashUserConfig;
218
+ declare function saveUserConfig(config: AtbashUserConfig): void;
219
+ declare function resolve(key: keyof AtbashUserConfig, flagValue?: string): string;
220
+
221
+ export { type ActionType, type AgentAuth, type AgentPolicy, type AtbashClient, type AtbashClientConfig, type AtbashUserConfig, type ChainOpts, type ClientOpts, DEFAULT_BLOCKCHAIN_RID, DEFAULT_CHROMIA_NODE_URLS, DEFAULT_ENDPOINT, type Decision, type DecisionVerdict, type HeldAction, type HeldActionReview, type JudgeEndpointConfig, type JudgeOptions, type JudgeResult, type JudgmentStatus, type JudgmentStatusState, type LogToolCallResult, type Provider, type PubkeyValue, type Tier, type TierInfo, type ToolCallFull, type ToolCallInput, type ToolCallRecord, type ValidatedEndpoint, type Verdict, checkAgentExists, createAtbashClient, derivePublicKey, generateKeyPair, getAgentDetail, getAgentPolicy, getAgentToolCalls, getConfigDir, getConfigPath, getHeldActionReviews, getJudgmentStatus, getOrgTierInfo, getOrgToolCalls, getPendingHeldActions, getSafetyStats, getToolCallCount, getToolCallFull, getToolCalls, isValidPrivateKey, judgeAction, loadAgent, loadAgentFromFile, loadUserConfig, logToolCall, resolve, resolveKeyPath, saveUserConfig, toPubkeyHex, validateJudgeEndpoint, verifyJudgeResponseSignature };
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ function verifyJudgeResponseSignature(bodyBytes, signatureHex, pubKeyHex) {
30
30
 
31
31
  // src/client.ts
32
32
  var { createClient, encryption: encryption2, newSignatureProvider } = postchain2;
33
- var DEFAULT_ENDPOINT = "https://atbash.ai";
33
+ var DEFAULT_ENDPOINT = "https://chromia-verified-ai-dev-two.vercel.app";
34
34
  var DEFAULT_CHROMIA_NODE_URLS = [
35
35
  "https://node6.testnet.chromia.com:7740",
36
36
  "https://node7.testnet.chromia.com:7740",
@@ -270,8 +270,8 @@ async function judgeAction(action, context = "", auth, opts) {
270
270
  on_chain: Boolean(data.on_chain)
271
271
  };
272
272
  }
273
- async function getJudgmentStatus(judgmentId, opts) {
274
- const url = `${baseUrl(opts)}/api/v1/judge?tool_call_id=${encodeURIComponent(judgmentId)}`;
273
+ async function getJudgmentStatus(judgmentId, agentPubkey, opts) {
274
+ const url = `${baseUrl(opts)}/api/v1/judge?tool_call_id=${encodeURIComponent(judgmentId)}&agent_pubkey=${encodeURIComponent(agentPubkey)}`;
275
275
  const data = await getJson(url, opts);
276
276
  return {
277
277
  status: normalizeStatus(data.status),
@@ -477,6 +477,77 @@ function loadAgentFromFile(keyPath) {
477
477
  return loadAgent(privKey);
478
478
  }
479
479
 
480
+ // src/redact-secrets.ts
481
+ var PATTERNS = [
482
+ { kind: "anthropic", re: /\bsk-ant-[A-Za-z0-9_-]{20,}/g },
483
+ { kind: "openai_project", re: /\bsk-proj-[A-Za-z0-9_-]{20,}/g },
484
+ { kind: "openai", re: /\bsk-[A-Za-z0-9]{20,}/g },
485
+ { kind: "github", re: /\b(?:gh[pousr]|github_pat)_[A-Za-z0-9_]{30,}/g },
486
+ { kind: "google", re: /\bAIza[0-9A-Za-z_-]{35}/g },
487
+ { kind: "google_oauth", re: /\bya29\.[0-9A-Za-z_-]{20,}/g },
488
+ {
489
+ kind: "aws_access_key",
490
+ re: /\b(?:AKIA|ASIA|AGPA|AROA|ANPA|ANVA|ASCA|AIDA|AIPA)[0-9A-Z]{16}\b/g
491
+ },
492
+ { kind: "stripe", re: /\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{20,}/g },
493
+ { kind: "slack", re: /\bxox[abprseo]-[A-Za-z0-9-]{10,}/g },
494
+ {
495
+ kind: "slack_webhook",
496
+ re: /https:\/\/hooks\.slack\.com\/services\/T[A-Za-z0-9]+\/B[A-Za-z0-9]+\/[A-Za-z0-9]{20,}/g
497
+ },
498
+ { kind: "sendgrid", re: /\bSG\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g },
499
+ { kind: "twilio_sid", re: /\bAC[0-9a-fA-F]{32}\b/g },
500
+ { kind: "mailgun", re: /\bkey-[0-9a-f]{32}\b/g },
501
+ { kind: "npm_token", re: /\bnpm_[A-Za-z0-9]{36,}\b/g },
502
+ { kind: "jwt", re: /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g },
503
+ {
504
+ kind: "private_key_pem",
505
+ re: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
506
+ },
507
+ {
508
+ kind: "aws_secret_key",
509
+ re: /(?:aws[_-]?secret|secret[_-]?access[_-]?key)["'\s:=]{1,10}[A-Za-z0-9/+=]{40}/gi
510
+ },
511
+ {
512
+ kind: "generic_token",
513
+ re: /\b(?=[A-Za-z0-9_-]*[0-9])(?=[A-Za-z0-9_-]*[A-Za-z])(?![0-9a-fA-F]+$)[A-Za-z0-9_-]{32,}\b/g
514
+ },
515
+ {
516
+ kind: "base64",
517
+ re: /(?<![A-Za-z0-9+/])(?=[A-Za-z0-9+/]*[+/])(?=[A-Za-z0-9+/]*[0-9])(?=[A-Za-z0-9+/]*[A-Za-z])[A-Za-z0-9+/]{40,}={0,2}(?![A-Za-z0-9+/=])/g
518
+ },
519
+ {
520
+ kind: "context_secret",
521
+ re: /(?<![A-Za-z0-9_])(?:api[_-]?key|api[_-]?secret|access[_-]?token|refresh[_-]?token|auth[_-]?token|client[_-]?secret|password|passwd|pwd|secret|token|credential|private[_-]?key)["']?\s*[:=]\s*["']?([A-Za-z0-9+/=._-]{12,})(?=["'\s,;)\]}>]|$)/gi,
522
+ groupOnly: true
523
+ },
524
+ {
525
+ kind: "bearer",
526
+ re: /(?<![A-Za-z0-9_])Bearer\s+([A-Za-z0-9._-]{20,})\b/gi,
527
+ groupOnly: true
528
+ }
529
+ ];
530
+ function redactSecrets(input) {
531
+ if (!input) return { redacted: input ?? "", found: [] };
532
+ const found = [];
533
+ let working = input;
534
+ for (const { kind, re, groupOnly } of PATTERNS) {
535
+ if (groupOnly) {
536
+ working = working.replace(re, (full, value) => {
537
+ if (typeof value !== "string" || !value) return full;
538
+ found.push({ kind, length: value.length });
539
+ return full.replace(value, `[REDACTED:${kind}]`);
540
+ });
541
+ } else {
542
+ working = working.replace(re, (m) => {
543
+ found.push({ kind, length: m.length });
544
+ return `[REDACTED:${kind}]`;
545
+ });
546
+ }
547
+ }
548
+ return { redacted: working, found };
549
+ }
550
+
480
551
  // src/factory.ts
481
552
  function createAtbashClient(config = {}) {
482
553
  const validated = validateJudgeEndpoint(config.judge);
@@ -513,9 +584,23 @@ function createAtbashClient(config = {}) {
513
584
  return fail("key load failed, blocking for safety");
514
585
  }
515
586
  const toolName = input.toolName || "unknown";
516
- const argsJson = stringifyArgs(input.args);
587
+ const argsRedaction = redactSecrets(stringifyArgs(input.args));
588
+ const ctxRedaction = redactSecrets(input.context ?? toolName);
589
+ const argsJson = argsRedaction.redacted;
517
590
  const actionText = truncate(argsJson);
518
- const contextText = input.context ?? toolName;
591
+ const contextText = ctxRedaction.redacted;
592
+ const totalRedactions = argsRedaction.found.length + ctxRedaction.found.length;
593
+ if (totalRedactions > 0) {
594
+ const kinds = [.../* @__PURE__ */ new Set([
595
+ ...argsRedaction.found.map((f) => f.kind),
596
+ ...ctxRedaction.found.map((f) => f.kind)
597
+ ])];
598
+ logger.warn?.("[atbash] redacted secrets before judge call", {
599
+ tool: toolName,
600
+ count: totalRedactions,
601
+ kinds
602
+ });
603
+ }
519
604
  try {
520
605
  logger.info?.("[atbash] judge API called", { tool: toolName });
521
606
  const result = await judgeAction(actionText, contextText, agent, {
@@ -585,6 +670,56 @@ function truncate(text) {
585
670
  if (text.length <= MAX_ACTION_LEN) return text;
586
671
  return text.slice(0, MAX_ACTION_LEN) + "\u2026";
587
672
  }
673
+
674
+ // src/user-config.ts
675
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync } from "fs";
676
+ import { homedir as homedir2 } from "os";
677
+ import { join as join2 } from "path";
678
+ var ENV_MAP = {
679
+ agentKey: "ATBASH_AGENT_KEY",
680
+ orgName: "ATBASH_ORG_NAME",
681
+ judgeEndpoint: "ATBASH_ENDPOINT",
682
+ blockchainRid: "ATBASH_BLOCKCHAIN_RID",
683
+ provider: "ATBASH_PROVIDER",
684
+ providerModel: "ATBASH_PROVIDER_MODEL"
685
+ };
686
+ function getConfigDir() {
687
+ const home = process.env.HOME || homedir2() || "";
688
+ return join2(home, ".config", "atbash");
689
+ }
690
+ function getConfigPath() {
691
+ return join2(getConfigDir(), "config.json");
692
+ }
693
+ function loadUserConfig() {
694
+ try {
695
+ const p = getConfigPath();
696
+ if (!existsSync(p)) return {};
697
+ const raw = readFileSync2(p, "utf-8").trim();
698
+ if (!raw) return {};
699
+ return JSON.parse(raw);
700
+ } catch (err) {
701
+ console.error("Failed to load config file", err);
702
+ return {};
703
+ }
704
+ }
705
+ function saveUserConfig(config) {
706
+ const dir = getConfigDir();
707
+ if (!existsSync(dir)) {
708
+ mkdirSync(dir, { recursive: true });
709
+ }
710
+ writeFileSync(getConfigPath(), JSON.stringify(config, null, 2) + "\n", "utf-8");
711
+ }
712
+ function resolve(key, flagValue) {
713
+ if (flagValue) return flagValue;
714
+ const envName = ENV_MAP[key];
715
+ if (envName) {
716
+ const envVal = process.env[envName];
717
+ if (envVal) return envVal;
718
+ }
719
+ const fileVal = loadUserConfig()[key];
720
+ if (fileVal != null) return String(fileVal);
721
+ return "";
722
+ }
588
723
  export {
589
724
  DEFAULT_BLOCKCHAIN_RID,
590
725
  DEFAULT_CHROMIA_NODE_URLS,
@@ -596,6 +731,8 @@ export {
596
731
  getAgentDetail,
597
732
  getAgentPolicy,
598
733
  getAgentToolCalls,
734
+ getConfigDir,
735
+ getConfigPath,
599
736
  getHeldActionReviews,
600
737
  getJudgmentStatus,
601
738
  getOrgTierInfo,
@@ -609,8 +746,11 @@ export {
609
746
  judgeAction,
610
747
  loadAgent,
611
748
  loadAgentFromFile,
749
+ loadUserConfig,
612
750
  logToolCall,
751
+ resolve,
613
752
  resolveKeyPath,
753
+ saveUserConfig,
614
754
  toPubkeyHex,
615
755
  validateJudgeEndpoint,
616
756
  verifyJudgeResponseSignature
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atbash/sdk",
3
- "version": "0.3.7",
3
+ "version": "0.3.9-dev.1",
4
4
  "description": "Atbash SDK — control boundary before the last irreversible step in an agent workflow",
5
5
  "homepage": "https://atbash.ai",
6
6
  "author": "Atbash",