@solongate/proxy 0.83.5 → 0.83.6
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/hooks/audit.mjs +7 -4
- package/hooks/guard.bundled.mjs +4 -5
- package/hooks/guard.mjs +22 -9
- package/package.json +1 -1
package/hooks/audit.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { homedir } from 'node:os';
|
|
|
11
11
|
// Bump on every audit hook change. The cloud serves the newest version; the guard
|
|
12
12
|
// hook installs it on its next run (no re-login needed). See guard.mjs
|
|
13
13
|
// fetchAndInstallHook / maybeSelfUpdate.
|
|
14
|
-
const HOOK_VERSION =
|
|
14
|
+
const HOOK_VERSION = 24;
|
|
15
15
|
|
|
16
16
|
function loadEnvKey(dir) {
|
|
17
17
|
try {
|
|
@@ -375,9 +375,12 @@ function loadLocalLogs() {
|
|
|
375
375
|
const c = JSON.parse(readFileSync(f, 'utf-8'));
|
|
376
376
|
const l = c && c.security && c.security.localLogs;
|
|
377
377
|
if (l && l.enabled && typeof l.path === 'string' && l.path.trim()) return { path: l.path.trim() };
|
|
378
|
-
// A cache that
|
|
379
|
-
//
|
|
380
|
-
|
|
378
|
+
// A cache that carries the key at all has an ANSWER, and the answer is
|
|
379
|
+
// "not local" — including when it is null, which is what the refresh
|
|
380
|
+
// writes for a project with no security config. Requiring it to be
|
|
381
|
+
// truthy sent that case to the device-wide marker instead, so a stale
|
|
382
|
+
// marker kept ALLOW rows on disk after local logging was switched off.
|
|
383
|
+
if (c && 'security' in c) return null;
|
|
381
384
|
}
|
|
382
385
|
} catch { /* unreadable cache — fall through to the marker */ }
|
|
383
386
|
// No usable config (cold cache, or a refresh that failed while the key was
|
package/hooks/guard.bundled.mjs
CHANGED
|
@@ -6536,10 +6536,10 @@ import { resolve, join, dirname, isAbsolute } from "node:path";
|
|
|
6536
6536
|
import { homedir } from "node:os";
|
|
6537
6537
|
import { gunzipSync } from "node:zlib";
|
|
6538
6538
|
import { createHash } from "node:crypto";
|
|
6539
|
-
var HOOK_VERSION =
|
|
6539
|
+
var HOOK_VERSION = 72;
|
|
6540
6540
|
function localLogsOnly(security) {
|
|
6541
|
-
if (security
|
|
6542
|
-
const l = security.localLogs;
|
|
6541
|
+
if (security !== void 0) {
|
|
6542
|
+
const l = security && security.localLogs;
|
|
6543
6543
|
return !!(l && l.enabled && typeof l.path === "string" && l.path.trim());
|
|
6544
6544
|
}
|
|
6545
6545
|
try {
|
|
@@ -6813,8 +6813,7 @@ async function refreshPolicyCache() {
|
|
|
6813
6813
|
const body = await res.json();
|
|
6814
6814
|
if (typeof body?.self_protection_enabled === "boolean")
|
|
6815
6815
|
selfProtect = body.self_protection_enabled;
|
|
6816
|
-
|
|
6817
|
-
security = body.security;
|
|
6816
|
+
security = body?.security !== void 0 ? body.security : null;
|
|
6818
6817
|
if (body?.hook_versions && typeof body.hook_versions === "object")
|
|
6819
6818
|
hookVersions = body.hook_versions;
|
|
6820
6819
|
policy = body && body.policy ? body.policy : null;
|
package/hooks/guard.mjs
CHANGED
|
@@ -32,20 +32,28 @@ import { createHash } from 'node:crypto';
|
|
|
32
32
|
// the installed hook self-updates when the cloud version is higher (see
|
|
33
33
|
// maybeSelfUpdate). This is what makes guard fixes propagate without a manual
|
|
34
34
|
// reinstall — the same trust model as the OPA WASM this hook already runs.
|
|
35
|
-
const HOOK_VERSION =
|
|
35
|
+
const HOOK_VERSION = 72;
|
|
36
36
|
|
|
37
37
|
// True when local log storage is ON. In that mode logs are kept LOCAL ONLY and
|
|
38
38
|
// nothing is sent to the cloud audit log.
|
|
39
|
+
//
|
|
40
|
+
// `undefined` is the ONLY value that means "we do not know yet". `null` is an
|
|
41
|
+
// answer: it is what the refresh writes when the API returns no security block,
|
|
42
|
+
// i.e. this project has no local-log config, i.e. cloud. Treating null as
|
|
43
|
+
// unknown is what kept logs on the machine after local logging was switched
|
|
44
|
+
// off — the answer fell through to the device-wide marker, and that marker is
|
|
45
|
+
// shared by every agent on the box while the policy cache is per agent, so
|
|
46
|
+
// whichever one refreshed last decided where everybody's logs went.
|
|
39
47
|
function localLogsOnly(security) {
|
|
40
|
-
if (security
|
|
41
|
-
const l = security.localLogs;
|
|
48
|
+
if (security !== undefined) {
|
|
49
|
+
const l = security && security.localLogs;
|
|
42
50
|
return !!(l && l.enabled && typeof l.path === 'string' && l.path.trim());
|
|
43
51
|
}
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
52
|
+
// Genuinely unknown (cold start, unreadable cache): consult the persisted
|
|
53
|
+
// marker so a DENY is NEVER leaked to the cloud when this device is in
|
|
54
|
+
// local-only mode. Without this fallback the first call(s) before the policy
|
|
55
|
+
// cache warms POST the denial to the cloud and fire webhooks/alerts even
|
|
56
|
+
// though the user chose local-only.
|
|
49
57
|
try {
|
|
50
58
|
const m = JSON.parse(readFileSync(join(resolve(homedir(), '.solongate'), '.local-logs-mode.json'), 'utf-8'));
|
|
51
59
|
return !!(m && m.localOnly);
|
|
@@ -421,7 +429,12 @@ async function refreshPolicyCache() {
|
|
|
421
429
|
if (res.ok) {
|
|
422
430
|
const body = await res.json();
|
|
423
431
|
if (typeof body?.self_protection_enabled === 'boolean') selfProtect = body.self_protection_enabled;
|
|
424
|
-
|
|
432
|
+
// A successful answer REPLACES the security block rather than merging
|
|
433
|
+
// into it. Only overwriting when the field was present meant a config
|
|
434
|
+
// the API had stopped sending lived on in the cache forever — switch
|
|
435
|
+
// local logging off in the dashboard and this device kept writing to
|
|
436
|
+
// disk and kept skipping the cloud, with nothing to show why.
|
|
437
|
+
security = body?.security !== undefined ? body.security : null;
|
|
425
438
|
if (body?.hook_versions && typeof body.hook_versions === 'object') hookVersions = body.hook_versions;
|
|
426
439
|
policy = (body && body.policy) ? body.policy : null;
|
|
427
440
|
noteAuthResult(true);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.83.
|
|
3
|
+
"version": "0.83.6",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|