bazis 0.117.1 → 0.118.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.
|
@@ -232,7 +232,7 @@ export class CodexAppServerClient implements CodexClient {
|
|
|
232
232
|
if (method === "account/updated") this.modelCache = undefined;
|
|
233
233
|
}, () => { this.clearLogin(); this.modelCache = undefined; });
|
|
234
234
|
const initialized = await client.request("initialize", {
|
|
235
|
-
clientInfo: { name: "bazis", title: "Bazis", version: "0.
|
|
235
|
+
clientInfo: { name: "bazis", title: "Bazis", version: "0.118.0" }, capabilities: { experimentalApi: true },
|
|
236
236
|
}, 15_000, signal);
|
|
237
237
|
if (resolve(text(initialized.codexHome, 4096)) !== this.paths.home) throw new CodexError("PROTOCOL_ERROR");
|
|
238
238
|
client.notify("initialized");
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { rememberSecretValue } from "../../../library/redaction";
|
|
2
|
+
|
|
1
3
|
const REDACTED = "***";
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -9,6 +11,8 @@ export class Secret {
|
|
|
9
11
|
|
|
10
12
|
public constructor(value: string) {
|
|
11
13
|
this.#value = value;
|
|
14
|
+
// Logs and errors drop the value even where it was pasted as plain text.
|
|
15
|
+
rememberSecretValue(value);
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
public reveal(): string {
|
|
@@ -607,7 +607,7 @@ function row(v: unknown): OwnedStoreRegistryRowV1 {
|
|
|
607
607
|
bad();
|
|
608
608
|
return Object.freeze(out as OwnedStoreRegistryRowV1);
|
|
609
609
|
}
|
|
610
|
-
export function validateOwnedStoreRegistryV1(rows: unknown,
|
|
610
|
+
export function validateOwnedStoreRegistryV1(rows: unknown, _defs: readonly OrmOwnedStoreDefinitionV1[]): readonly OwnedStoreRegistryRowV1[] {
|
|
611
611
|
const out = dense(rows, row, 4096);
|
|
612
612
|
const keys = new Set<string>();
|
|
613
613
|
for (const x of out) {
|
|
@@ -619,9 +619,9 @@ export function validateOwnedStoreRegistryV1(rows: unknown, defs: readonly OrmOw
|
|
|
619
619
|
if (keys.has(x.storeKey))
|
|
620
620
|
throw failure("ORM_OWNED_STORE_OWNERSHIP_CONFLICT");
|
|
621
621
|
keys.add(x.storeKey);
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
622
|
+
// A row that differs from the code (format version, scope) is refused by
|
|
623
|
+
// admission's assertCurrent, after the row is recorded for the explainer,
|
|
624
|
+
// so the message can name what changed.
|
|
625
625
|
}
|
|
626
626
|
for (let i = 0; i < out.length; i++)
|
|
627
627
|
for (let j = i + 1; j < out.length; j++) {
|
|
@@ -47,6 +47,42 @@ export function redactTraceValues<T>(values: readonly T[], options: SensitiveRed
|
|
|
47
47
|
return values.map(() => replacement);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
/** Values shorter than this are not remembered: masking them would hide ordinary words ("postgres"). */
|
|
51
|
+
export const MIN_REMEMBERED_SECRET_LENGTH = 10;
|
|
52
|
+
const rememberedSecrets = new Set<string>();
|
|
53
|
+
let longestFirst: readonly string[] = [];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Remembers a secret value: from now on every redaction removes it wherever it
|
|
57
|
+
* appears, also in plain text without a marker such as `password=`. `Secret`
|
|
58
|
+
* calls it for every configuration secret. Process-wide; values shorter than
|
|
59
|
+
* {@link MIN_REMEMBERED_SECRET_LENGTH} are recognised only by their shape.
|
|
60
|
+
*/
|
|
61
|
+
export function rememberSecretValue(value: string): void {
|
|
62
|
+
// A connection URL keeps naming its server: only its password is the secret,
|
|
63
|
+
// and the userinfo pattern already hides user:password@ in the URL itself.
|
|
64
|
+
const password = urlPassword(value);
|
|
65
|
+
if (password !== undefined) {
|
|
66
|
+
if (password !== "") rememberSecretValue(password);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (value.length < MIN_REMEMBERED_SECRET_LENGTH || rememberedSecrets.has(value)) return;
|
|
70
|
+
rememberedSecrets.add(value);
|
|
71
|
+
// A longer value first, so a secret that contains another one goes whole.
|
|
72
|
+
longestFirst = [...rememberedSecrets].sort((left, right) => right.length - left.length);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** The decoded password of a URL with userinfo (`""` for user only), or undefined for other values. */
|
|
76
|
+
function urlPassword(value: string): string | undefined {
|
|
77
|
+
if (!/^[a-z][a-z0-9+.-]*:\/\/[^\s/?#@]+@/i.test(value)) return undefined;
|
|
78
|
+
try {
|
|
79
|
+
const url = new URL(value);
|
|
80
|
+
return decodeURIComponent(url.password);
|
|
81
|
+
} catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
50
86
|
export function isSensitiveKey(key: string, options: SensitiveRedactionOptions = {}): boolean {
|
|
51
87
|
return keyIsSensitive(key, normalizeOptions(options));
|
|
52
88
|
}
|
|
@@ -177,7 +213,9 @@ function normalizeKey(key: string): string {
|
|
|
177
213
|
}
|
|
178
214
|
|
|
179
215
|
function redactText(value: string, replacement: string): string {
|
|
180
|
-
|
|
216
|
+
let text = value;
|
|
217
|
+
for (const secret of longestFirst) if (text.includes(secret)) text = text.replaceAll(secret, replacement);
|
|
218
|
+
return text
|
|
181
219
|
.replace(SECRET_TEXT_PATTERN, (_match, name: string, separator: string) => `${name}${separator}${replacement}`)
|
|
182
220
|
.replace(BEARER_TEXT_PATTERN, (_match, scheme: string) => `${scheme} ${replacement}`)
|
|
183
221
|
.replace(URL_USERINFO_PATTERN, (_match, scheme: string, userinfo: string) =>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bazis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.118.0",
|
|
4
4
|
"description": "Modular backend framework for Bun in TypeScript: DI wired by codegen, HTTP, a PostgreSQL ORM, JWT, WebSocket, agents and a CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alexander Alenin",
|