@sema-agent/core 1.446.0 → 1.447.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.
@@ -1,19 +1,23 @@
1
1
  const ACTIVITY_ARG_MAX = 80;
2
2
  const SENSITIVE_KEY = /token|secret|key|password|passwd|credential|auth/i;
3
3
  const SECRET_PATTERNS = [
4
- /(?<![A-Za-z0-9])(?:sk|pk|rk|gh[opsur])[-_][A-Za-z0-9_-]{8,}/g,
5
- /(?<![A-Za-z0-9])AIza[A-Za-z0-9_-]{20,}/g,
6
- /(?<![A-Za-z0-9])xox[baprs]-[A-Za-z0-9-]{10,}/g,
7
- /(?<![A-Za-z0-9])AKIA[0-9A-Z]{12,}/g,
8
- /(?<![A-Za-z0-9])eyJ[A-Za-z0-9._-]{20,}/g,
9
- /-----BEGIN[ A-Z]*PRIVATE KEY-----/g,
10
- /(?<![A-Za-z0-9])Bearer\s+[A-Za-z0-9._~+/-]{8,}=*/gi,
11
- /(?<![A-Za-z0-9])(?:token|secret|key|password|passwd|credential|authorization)["']?\s*[=:]\s*["']?[^\s"';|&]{4,}/gi,
4
+ { re: /(?<![A-Za-z0-9])(?:sk|pk|rk|gh[opsur])[-_][A-Za-z0-9_-]{8,}/g, replace: "[redacted]" },
5
+ { re: /(?<![A-Za-z0-9])AIza[A-Za-z0-9_-]{20,}/g, replace: "[redacted]" },
6
+ { re: /(?<![A-Za-z0-9])xox[baprs]-[A-Za-z0-9-]{10,}/g, replace: "[redacted]" },
7
+ { re: /(?<![A-Za-z0-9])AKIA[0-9A-Z]{12,}/g, replace: "[redacted]" },
8
+ { re: /(?<![A-Za-z0-9])hf_[A-Za-z0-9]{20,}/g, replace: "[redacted]" },
9
+ { re: /(?<![A-Za-z0-9])eyJ[A-Za-z0-9._-]{20,}/g, replace: "[redacted]" },
10
+ { re: /-----BEGIN[ A-Z]*PRIVATE KEY-----[\s\S]*?(?:-----END[ A-Z]*PRIVATE KEY-----|$)/g, replace: "[redacted]" },
11
+ { re: /(?<![A-Za-z0-9])Bearer\s+[A-Za-z0-9._~+/-]{8,}=*/gi, replace: "[redacted]" },
12
+ {
13
+ re: /(?<![A-Za-z0-9])((?:token|secret|key|password|passwd|credential|authorization)["']?\s*[=:]\s*["']?)[^\s"';|&]{4,}/gi,
14
+ replace: "$1[redacted]",
15
+ },
12
16
  ];
13
17
  export function scrubSecrets(s) {
14
18
  let out = s;
15
- for (const p of SECRET_PATTERNS)
16
- out = out.replace(p, "[redacted]");
19
+ for (const { re, replace } of SECRET_PATTERNS)
20
+ out = out.replace(re, replace);
17
21
  return out;
18
22
  }
19
23
  function truncCodePoints(s) {
@@ -1,6 +1,7 @@
1
- const SECRET_ENV_RE = /(^|_)(KEY|TOKEN|SECRET|SECRETS|PASSWORD|PASSWD|CREDENTIAL|CREDENTIALS|PRIVATEKEY|APIKEY|ACCESS_KEY|SESSION_TOKEN)$/i;
1
+ const SECRET_ENV_RE = /(^|_)(KEY|TOKEN|SECRET|SECRETS|PASSWORD|PASSWD|CREDENTIAL|CREDENTIALS|PRIVATEKEY|APIKEY|ACCESS_KEY|SESSION_TOKEN)(?:_(?:\d+|ID))?$/i;
2
+ const SECRET_ENV_EXACT_NAMES = new Set(["DATABASE_URL", "CONNECTION_STRING", "DSN", "NPM_AUTH"]);
2
3
  export function isSecretEnvKey(key) {
3
- return SECRET_ENV_RE.test(key);
4
+ return SECRET_ENV_RE.test(key) || SECRET_ENV_EXACT_NAMES.has(key.toUpperCase());
4
5
  }
5
6
  export function scrubSecretEnv(env) {
6
7
  const out = {};
@@ -1,11 +1,22 @@
1
1
  import { delimitUntrusted } from "./untrusted-text.js";
2
2
  import { scrubSecrets } from "./arg-summary.js";
3
3
  const URI_SCHEME = String.raw `[A-Za-z][A-Za-z0-9+.\-_]{0,63}`;
4
- const CREDENTIALS_IN_AUTHORITY = new RegExp(String.raw `(${URI_SCHEME}:\/\/)(?:[^/\s"'@]*@)+`, "gi");
4
+ const CREDENTIALS_IN_AUTHORITY = new RegExp(String.raw `(${URI_SCHEME}:\/\/)((?:[^/\s"'@]*@)+)`, "gi");
5
5
  const URL_OF_ANY_PROTOCOL = new RegExp(String.raw `${URI_SCHEME}:\/\/[^\s"'\`]+`, "gi");
6
+ const BARE_USERNAME_MAX_LEN = 20;
7
+ function redactUserinfo(scheme, userinfoWithAt) {
8
+ const userinfo = userinfoWithAt.slice(0, -1);
9
+ if (userinfo.includes("@"))
10
+ return `${scheme}[redacted-credentials]@`;
11
+ const colonIdx = userinfo.indexOf(":");
12
+ if (colonIdx === -1) {
13
+ return userinfo.length >= BARE_USERNAME_MAX_LEN ? `${scheme}[redacted-credentials]@` : `${scheme}${userinfo}@`;
14
+ }
15
+ return `${scheme}${userinfo.slice(0, colonIdx)}:[redacted-credentials]@`;
16
+ }
6
17
  export function redactSecrets(s) {
7
18
  return scrubSecrets(s)
8
- .replace(CREDENTIALS_IN_AUTHORITY, "$1[redacted-credentials]@")
19
+ .replace(CREDENTIALS_IN_AUTHORITY, (_m, scheme, userinfo) => redactUserinfo(scheme, userinfo))
9
20
  .replace(/([?&#](?:sig|signature|sas|code)=)[^&\s"'#]+/gi, "$1[redacted]");
10
21
  }
11
22
  export function redactHostLeaks(s) {
@@ -13,6 +24,22 @@ export function redactHostLeaks(s) {
13
24
  .replace(URL_OF_ANY_PROTOCOL, "[redacted-url]")
14
25
  .replace(/(?:\/[A-Za-z0-9_.-]+){2,}/g, "[redacted-path]");
15
26
  }
27
+ const REDACTION_MARKER_RE = /\[redacted(?:-[a-z]+)?\]/g;
28
+ function countRedactionMarkers(s) {
29
+ return (s.match(REDACTION_MARKER_RE) ?? []).length;
30
+ }
31
+ function safeEllipsisTruncate(s, max) {
32
+ if (max < 1)
33
+ return "";
34
+ const budget = max - 1;
35
+ let out = "";
36
+ for (const codePoint of s) {
37
+ if (out.length + codePoint.length > budget)
38
+ break;
39
+ out += codePoint;
40
+ }
41
+ return out + "…";
42
+ }
16
43
  function boundedString(value, max, redact) {
17
44
  let s;
18
45
  try {
@@ -24,18 +51,32 @@ function boundedString(value, max, redact) {
24
51
  s = redact(s);
25
52
  if (s.length <= max)
26
53
  return s;
27
- let keep = max;
28
- let out = "";
29
- for (let i = 0; i < 4; i++) {
30
- out = `${s.slice(0, keep)}…[+${s.length - keep} chars]`;
31
- if (out.length <= max)
32
- break;
33
- if (keep === 0) {
34
- return max >= 1 ? `${s.slice(0, max - 1)}…` : "";
54
+ const totalMarkers = countRedactionMarkers(s);
55
+ const plainSuffix = (keepN) => `…[+${s.length - keepN} chars]`;
56
+ const enrichedSuffix = (keepN) => {
57
+ const lost = totalMarkers - countRedactionMarkers(s.slice(0, keepN));
58
+ return lost > 0 ? `…[+${s.length - keepN} chars, ${lost} redaction marker(s) among them]` : plainSuffix(keepN);
59
+ };
60
+ const converge = (suffixFor) => {
61
+ let keep = max;
62
+ let out = "";
63
+ for (let i = 0; i < 4; i++) {
64
+ out = `${s.slice(0, keep)}${suffixFor(keep)}`;
65
+ if (out.length <= max)
66
+ return out;
67
+ if (keep === 0)
68
+ return undefined;
69
+ keep = Math.max(0, keep - (out.length - max));
35
70
  }
36
- keep = Math.max(0, keep - (out.length - max));
71
+ return out.length <= max ? out : undefined;
72
+ };
73
+ const out = (totalMarkers > 0 ? converge(enrichedSuffix) : undefined) ?? converge(plainSuffix);
74
+ if (out === undefined) {
75
+ return safeEllipsisTruncate(s, max);
37
76
  }
38
- return out.length < s.length ? out : s;
77
+ if (out.length >= s.length)
78
+ return s;
79
+ return out;
39
80
  }
40
81
  export function boundedRedactedSummary(value, max) {
41
82
  return boundedString(value, max, redactSecrets);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "1.446.0",
3
+ "version": "1.447.0",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",