mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 23:56:07 +00:00
refactor: make auth profile runtime sqlite-addressed
This commit is contained in:
@@ -22,8 +22,9 @@ export {
|
||||
resolveAuthProfileOrder,
|
||||
} from "./auth-profiles/order.js";
|
||||
export {
|
||||
resolveAuthProfileStoreAgentDir,
|
||||
resolveAuthProfileStoreLocationForDisplay,
|
||||
resolveAuthStatePathForDisplay,
|
||||
resolveAuthStorePathForDisplay,
|
||||
} from "./auth-profiles/paths.js";
|
||||
export {
|
||||
dedupeProfileIds,
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
export { AUTH_PROFILE_FILENAME, AUTH_STATE_FILENAME } from "./path-constants.js";
|
||||
export {
|
||||
AUTH_PROFILE_FILENAME,
|
||||
AUTH_PROFILE_STORE_KV_SCOPE,
|
||||
AUTH_STATE_FILENAME,
|
||||
} from "./path-constants.js";
|
||||
|
||||
export const AUTH_STORE_VERSION = 1;
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from "./oauth-shared.js";
|
||||
import {
|
||||
OAUTH_REFRESH_LOCK_SCOPE,
|
||||
resolveAuthStorePath,
|
||||
resolveAuthProfileStoreKey,
|
||||
resolveOAuthRefreshLockKey,
|
||||
} from "./paths.js";
|
||||
import {
|
||||
@@ -323,7 +323,7 @@ export function createOAuthManager(adapter: OAuthManagerAdapter) {
|
||||
cfg?: OpenClawConfig;
|
||||
}): Promise<ResolvedOAuthAccess | null> {
|
||||
const ownerAgentDir = resolvePersistedAuthProfileOwnerAgentDir(params);
|
||||
const authPath = resolveAuthStorePath(ownerAgentDir);
|
||||
const ownerStoreKey = resolveAuthProfileStoreKey(ownerAgentDir);
|
||||
const refreshLockKey = resolveOAuthRefreshLockKey(params.provider, params.profileId);
|
||||
|
||||
try {
|
||||
@@ -452,8 +452,8 @@ export function createOAuthManager(adapter: OAuthManagerAdapter) {
|
||||
store.profiles[params.profileId] = refreshedCredentials;
|
||||
saveAuthProfileStore(store, ownerAgentDir);
|
||||
if (ownerAgentDir) {
|
||||
const mainPath = resolveAuthStorePath(undefined);
|
||||
if (mainPath !== authPath) {
|
||||
const mainStoreKey = resolveAuthProfileStoreKey(undefined);
|
||||
if (mainStoreKey !== ownerStoreKey) {
|
||||
await mirrorRefreshedCredentialIntoMainStore({
|
||||
profileId: params.profileId,
|
||||
refreshed: refreshedCredentials,
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export const AUTH_PROFILE_FILENAME = "auth-profiles.json";
|
||||
export const AUTH_STATE_FILENAME = "auth-state.json";
|
||||
export const AUTH_PROFILE_STORE_KV_SCOPE = "auth-profiles";
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { resolveOpenClawStateSqlitePath } from "../../state/openclaw-state-db.paths.js";
|
||||
import { resolveUserPath } from "../../utils.js";
|
||||
import { resolveDefaultAgentDir } from "../agent-scope-config.js";
|
||||
import { AUTH_PROFILE_FILENAME, AUTH_STATE_FILENAME } from "./path-constants.js";
|
||||
import {
|
||||
AUTH_PROFILE_FILENAME,
|
||||
AUTH_PROFILE_STORE_KV_SCOPE,
|
||||
AUTH_STATE_FILENAME,
|
||||
} from "./path-constants.js";
|
||||
|
||||
export function resolveAuthProfileStoreAgentDir(agentDir?: string): string {
|
||||
return resolveUserPath(agentDir ?? resolveDefaultAgentDir({}));
|
||||
}
|
||||
|
||||
export function resolveAuthProfileStoreKey(agentDir?: string): string {
|
||||
return resolveAuthProfileStoreAgentDir(agentDir);
|
||||
}
|
||||
|
||||
export function resolveAuthProfileStoreLocationForDisplay(
|
||||
agentDir?: string,
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
): string {
|
||||
return `${resolveOpenClawStateSqlitePath(env)}#kv/${AUTH_PROFILE_STORE_KV_SCOPE}/${resolveAuthProfileStoreKey(agentDir)}`;
|
||||
}
|
||||
|
||||
export function resolveAuthStorePath(agentDir?: string): string {
|
||||
const resolved = resolveUserPath(agentDir ?? resolveDefaultAgentDir({}));
|
||||
const resolved = resolveAuthProfileStoreAgentDir(agentDir);
|
||||
return path.join(resolved, AUTH_PROFILE_FILENAME);
|
||||
}
|
||||
|
||||
export function resolveAuthStatePath(agentDir?: string): string {
|
||||
const resolved = resolveUserPath(agentDir ?? resolveDefaultAgentDir({}));
|
||||
const resolved = resolveAuthProfileStoreAgentDir(agentDir);
|
||||
return path.join(resolved, AUTH_STATE_FILENAME);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export {
|
||||
resolveAuthProfileStoreAgentDir,
|
||||
resolveAuthProfileStoreKey,
|
||||
resolveAuthProfileStoreLocationForDisplay,
|
||||
resolveAuthStatePath,
|
||||
resolveAuthStatePathForDisplay,
|
||||
resolveAuthStorePath,
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
type OpenClawStateJsonValue,
|
||||
} from "../../state/openclaw-state-kv.js";
|
||||
import { normalizeProviderId } from "../provider-id.js";
|
||||
import { AUTH_STORE_VERSION, log } from "./constants.js";
|
||||
import { AUTH_PROFILE_STORE_KV_SCOPE, AUTH_STORE_VERSION, log } from "./constants.js";
|
||||
import {
|
||||
hasOAuthIdentity,
|
||||
hasUsableOAuthCredential,
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
normalizeAuthEmailToken,
|
||||
normalizeAuthIdentityToken,
|
||||
} from "./oauth-shared.js";
|
||||
import { resolveAuthStorePath } from "./paths.js";
|
||||
import { resolveAuthProfileStoreKey } from "./paths.js";
|
||||
import {
|
||||
coerceAuthProfileState,
|
||||
loadPersistedAuthProfileState,
|
||||
@@ -33,10 +33,10 @@ import type {
|
||||
ProfileUsageStats,
|
||||
} from "./types.js";
|
||||
|
||||
export const AUTH_PROFILE_STORE_KV_SCOPE = "auth-profiles";
|
||||
export { AUTH_PROFILE_STORE_KV_SCOPE } from "./constants.js";
|
||||
|
||||
export function authProfileStoreKey(agentDir?: string): string {
|
||||
return resolveAuthStorePath(agentDir);
|
||||
return resolveAuthProfileStoreKey(agentDir);
|
||||
}
|
||||
|
||||
type CredentialRejectReason = "non_object" | "invalid_type" | "missing_provider";
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { cloneAuthProfileStore } from "./clone.js";
|
||||
import { resolveAuthStorePath } from "./path-resolve.js";
|
||||
import { resolveAuthProfileStoreKey } from "./path-resolve.js";
|
||||
import type { AuthProfileStore } from "./types.js";
|
||||
|
||||
const runtimeAuthStoreSnapshots = new Map<string, AuthProfileStore>();
|
||||
|
||||
function resolveRuntimeStoreKey(agentDir?: string): string {
|
||||
return resolveAuthStorePath(agentDir);
|
||||
return resolveAuthProfileStoreKey(agentDir);
|
||||
}
|
||||
|
||||
export function getRuntimeAuthProfileStoreSnapshot(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { resolveAuthStorePath } from "./path-resolve.js";
|
||||
import { resolveAuthProfileStoreKey } from "./path-resolve.js";
|
||||
import { hasPersistedAuthProfileSecretsStore } from "./persisted.js";
|
||||
import { hasAnyRuntimeAuthProfileStoreSource } from "./runtime-snapshots.js";
|
||||
|
||||
@@ -10,9 +10,9 @@ export function hasAnyAuthProfileStoreSource(agentDir?: string): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const mainAuthPath = resolveAuthStorePath();
|
||||
if (agentDir && authPath !== mainAuthPath && hasPersistedAuthProfileSecretsStore(undefined)) {
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const mainStoreKey = resolveAuthProfileStoreKey();
|
||||
if (agentDir && storeKey !== mainStoreKey && hasPersistedAuthProfileSecretsStore(undefined)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { AUTH_STORE_VERSION, EXTERNAL_CLI_SYNC_TTL_MS } from "./constants.js";
|
||||
import { overlayExternalAuthProfiles, shouldPersistExternalAuthProfile } from "./external-auth.js";
|
||||
import type { ExternalCliAuthDiscovery } from "./external-cli-discovery.js";
|
||||
import { isSafeToAdoptMainStoreOAuthIdentity } from "./oauth-shared.js";
|
||||
import { resolveAuthStorePath } from "./paths.js";
|
||||
import { resolveAuthProfileStoreKey } from "./paths.js";
|
||||
import {
|
||||
buildPersistedAuthProfileSecretsStore,
|
||||
loadPersistedAuthProfileStoreEntry,
|
||||
@@ -70,9 +70,9 @@ function isInheritedMainOAuthCredential(params: {
|
||||
if (!params.agentDir || params.credential.type !== "oauth") {
|
||||
return false;
|
||||
}
|
||||
const authPath = resolveAuthStorePath(params.agentDir);
|
||||
const mainAuthPath = resolveAuthStorePath();
|
||||
if (authPath === mainAuthPath) {
|
||||
const storeKey = resolveAuthProfileStoreKey(params.agentDir);
|
||||
const mainStoreKey = resolveAuthProfileStoreKey();
|
||||
if (storeKey === mainStoreKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ function shouldUseMainOwnerForLocalOAuthCredential(params: {
|
||||
}
|
||||
|
||||
function resolveRuntimeAuthProfileStore(agentDir?: string): AuthProfileStore | null {
|
||||
const mainKey = resolveAuthStorePath(undefined);
|
||||
const requestedKey = resolveAuthStorePath(agentDir);
|
||||
const mainKey = resolveAuthProfileStoreKey(undefined);
|
||||
const requestedKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const mainStore = getRuntimeAuthProfileStoreSnapshot(undefined);
|
||||
const requestedStore = getRuntimeAuthProfileStoreSnapshot(agentDir);
|
||||
|
||||
@@ -142,10 +142,10 @@ function resolveRuntimeAuthProfileStore(agentDir?: string): AuthProfileStore | n
|
||||
}
|
||||
|
||||
function readCachedAuthProfileStore(params: {
|
||||
authPath: string;
|
||||
storeKey: string;
|
||||
authMtimeMs: number | null;
|
||||
}): AuthProfileStore | null {
|
||||
const cached = loadedAuthStoreCache.get(params.authPath);
|
||||
const cached = loadedAuthStoreCache.get(params.storeKey);
|
||||
if (!cached || cached.authMtimeMs !== params.authMtimeMs) {
|
||||
return null;
|
||||
}
|
||||
@@ -156,11 +156,11 @@ function readCachedAuthProfileStore(params: {
|
||||
}
|
||||
|
||||
function writeCachedAuthProfileStore(params: {
|
||||
authPath: string;
|
||||
storeKey: string;
|
||||
authMtimeMs: number | null;
|
||||
store: AuthProfileStore;
|
||||
}): void {
|
||||
loadedAuthStoreCache.set(params.authPath, {
|
||||
loadedAuthStoreCache.set(params.storeKey, {
|
||||
authMtimeMs: params.authMtimeMs,
|
||||
syncedAtMs: Date.now(),
|
||||
store: cloneAuthProfileStore(params.store),
|
||||
@@ -334,12 +334,12 @@ function loadAuthProfileStoreForAgent(
|
||||
options?: LoadAuthProfileStoreOptions,
|
||||
): AuthProfileStore {
|
||||
const readOnly = options?.readOnly === true;
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const persisted = loadPersistedAuthProfileStoreEntry(agentDir, { env: options?.env });
|
||||
const authMtimeMs = persisted?.updatedAt ?? null;
|
||||
if (!readOnly) {
|
||||
const cached = readCachedAuthProfileStore({
|
||||
authPath,
|
||||
storeKey,
|
||||
authMtimeMs,
|
||||
});
|
||||
if (cached) {
|
||||
@@ -350,7 +350,7 @@ function loadAuthProfileStoreForAgent(
|
||||
if (asStore) {
|
||||
if (!readOnly) {
|
||||
writeCachedAuthProfileStore({
|
||||
authPath,
|
||||
storeKey,
|
||||
authMtimeMs,
|
||||
store: asStore,
|
||||
});
|
||||
@@ -365,7 +365,7 @@ function loadAuthProfileStoreForAgent(
|
||||
|
||||
if (!readOnly) {
|
||||
writeCachedAuthProfileStore({
|
||||
authPath,
|
||||
storeKey,
|
||||
authMtimeMs,
|
||||
store,
|
||||
});
|
||||
@@ -378,10 +378,10 @@ export function loadAuthProfileStoreForRuntime(
|
||||
options?: LoadAuthProfileStoreOptions,
|
||||
): AuthProfileStore {
|
||||
const store = loadAuthProfileStoreForAgent(agentDir, options);
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const mainAuthPath = resolveAuthStorePath();
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const mainStoreKey = resolveAuthProfileStoreKey();
|
||||
const externalCli = resolveExternalCliOverlayOptions(options);
|
||||
if (!agentDir || authPath === mainAuthPath) {
|
||||
if (!agentDir || storeKey === mainStoreKey) {
|
||||
return overlayExternalAuthProfiles(store, {
|
||||
agentDir,
|
||||
...externalCli,
|
||||
@@ -409,9 +409,9 @@ export function loadAuthProfileStoreWithoutExternalProfiles(
|
||||
...(options?.env ? { env: options.env } : {}),
|
||||
};
|
||||
const store = loadAuthProfileStoreForAgent(agentDir, loadOptions);
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const mainAuthPath = resolveAuthStorePath();
|
||||
if (!agentDir || authPath === mainAuthPath) {
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const mainStoreKey = resolveAuthProfileStoreKey();
|
||||
if (!agentDir || storeKey === mainStoreKey) {
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -448,9 +448,9 @@ export function ensureAuthProfileStoreWithoutExternalProfiles(
|
||||
return runtimeStore;
|
||||
}
|
||||
const store = loadAuthProfileStoreForAgent(agentDir, options);
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const mainAuthPath = resolveAuthStorePath();
|
||||
if (!agentDir || authPath === mainAuthPath) {
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const mainStoreKey = resolveAuthProfileStoreKey();
|
||||
if (!agentDir || storeKey === mainStoreKey) {
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -468,9 +468,9 @@ export function findPersistedAuthProfileCredential(params: {
|
||||
return requestedProfile;
|
||||
}
|
||||
|
||||
const requestedPath = resolveAuthStorePath(params.agentDir);
|
||||
const mainPath = resolveAuthStorePath();
|
||||
if (requestedPath === mainPath) {
|
||||
const requestedKey = resolveAuthProfileStoreKey(params.agentDir);
|
||||
const mainKey = resolveAuthProfileStoreKey();
|
||||
if (requestedKey === mainKey) {
|
||||
return requestedProfile;
|
||||
}
|
||||
|
||||
@@ -485,9 +485,9 @@ export function resolvePersistedAuthProfileOwnerAgentDir(params: {
|
||||
return undefined;
|
||||
}
|
||||
const requestedStore = loadPersistedAuthProfileStore(params.agentDir);
|
||||
const requestedPath = resolveAuthStorePath(params.agentDir);
|
||||
const mainPath = resolveAuthStorePath();
|
||||
if (requestedPath === mainPath) {
|
||||
const requestedKey = resolveAuthProfileStoreKey(params.agentDir);
|
||||
const mainKey = resolveAuthProfileStoreKey();
|
||||
if (requestedKey === mainKey) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -508,9 +508,9 @@ export function resolvePersistedAuthProfileOwnerAgentDir(params: {
|
||||
export function ensureAuthProfileStoreForLocalUpdate(agentDir?: string): AuthProfileStore {
|
||||
const options: LoadAuthProfileStoreOptions = { syncExternalCli: false };
|
||||
const store = loadAuthProfileStoreForAgent(agentDir, options);
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const mainAuthPath = resolveAuthStorePath();
|
||||
if (!agentDir || authPath === mainAuthPath) {
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const mainStoreKey = resolveAuthProfileStoreKey();
|
||||
if (!agentDir || storeKey === mainStoreKey) {
|
||||
return store;
|
||||
}
|
||||
|
||||
@@ -565,10 +565,10 @@ function refreshAuthProfileStoreCache(
|
||||
agentDir?: string,
|
||||
options: OpenClawStateDatabaseOptions = {},
|
||||
): void {
|
||||
const authPath = resolveAuthStorePath(agentDir);
|
||||
const storeKey = resolveAuthProfileStoreKey(agentDir);
|
||||
const persisted = loadPersistedAuthProfileStoreEntry(agentDir, options);
|
||||
writeCachedAuthProfileStore({
|
||||
authPath,
|
||||
storeKey,
|
||||
authMtimeMs: persisted?.updatedAt ?? null,
|
||||
store,
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import path from "node:path";
|
||||
import { formatCliCommand } from "../cli/command-format.js";
|
||||
import { getRuntimeConfigSnapshot } from "../config/config.js";
|
||||
import type { ModelProviderAuthMode, ModelProviderConfig } from "../config/types.js";
|
||||
@@ -27,7 +26,8 @@ import {
|
||||
listProfilesForProvider,
|
||||
resolveApiKeyForProfile,
|
||||
resolveAuthProfileOrder,
|
||||
resolveAuthStorePathForDisplay,
|
||||
resolveAuthProfileStoreAgentDir,
|
||||
resolveAuthProfileStoreLocationForDisplay,
|
||||
} from "./auth-profiles.js";
|
||||
import * as cliCredentials from "./cli-credentials.js";
|
||||
import { resolveEnvApiKey, type EnvApiKeyResult } from "./model-auth-env.js";
|
||||
@@ -782,12 +782,12 @@ export async function resolveApiKeyForProvider(params: {
|
||||
}
|
||||
}
|
||||
|
||||
const authStorePath = resolveAuthStorePathForDisplay(params.agentDir);
|
||||
const resolvedAgentDir = path.dirname(authStorePath);
|
||||
const authStoreLocation = resolveAuthProfileStoreLocationForDisplay(params.agentDir);
|
||||
const resolvedAgentDir = resolveAuthProfileStoreAgentDir(params.agentDir);
|
||||
throw new Error(
|
||||
[
|
||||
`No API key found for provider "${provider}".`,
|
||||
`Auth store: ${authStorePath} (agentDir: ${resolvedAgentDir}).`,
|
||||
`Auth store: ${authStoreLocation} (agentDir: ${resolvedAgentDir}).`,
|
||||
`Configure auth for this agent (${formatCliCommand("openclaw agents add <id>")}) or copy only portable static auth profiles from the main agentDir.`,
|
||||
].join(" "),
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ vi.mock("../../agents/auth-profiles.js", () => ({
|
||||
},
|
||||
isProfileInCooldown: () => false,
|
||||
resolveAuthProfileDisplayLabel: ({ profileId }: { profileId: string }) => profileId,
|
||||
resolveAuthStorePathForDisplay: () => "/tmp/auth-profiles.json",
|
||||
resolveAuthProfileStoreLocationForDisplay: () => "/tmp/openclaw.sqlite#kv/auth-profiles/main",
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/model-selection.js", () => ({
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
isConfiguredAwsSdkAuthProfileForProvider,
|
||||
isProfileInCooldown,
|
||||
resolveAuthProfileDisplayLabel,
|
||||
resolveAuthStorePathForDisplay,
|
||||
resolveAuthProfileStoreLocationForDisplay,
|
||||
} from "../../agents/auth-profiles.js";
|
||||
import {
|
||||
ensureAuthProfileStore,
|
||||
@@ -200,7 +200,7 @@ export const resolveAuthLabel = async (
|
||||
});
|
||||
return {
|
||||
label: labels.join(", "),
|
||||
source: `auth-profiles.json: ${formatPath(resolveAuthStorePathForDisplay(agentDir))}`,
|
||||
source: `SQLite auth store: ${formatPath(resolveAuthProfileStoreLocationForDisplay(agentDir))}`,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ vi.mock("../../agents/auth-profiles.js", () => ({
|
||||
},
|
||||
resolveAuthProfileDisplayLabel: ({ profileId }: { profileId: string }) => profileId,
|
||||
resolveAuthProfileOrder: () => [],
|
||||
resolveAuthStorePathForDisplay: () => "/tmp/auth-profiles.json",
|
||||
resolveAuthProfileStoreLocationForDisplay: () => "/tmp/openclaw.sqlite#kv/auth-profiles/main",
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/auth-profiles/store.js", () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { resolveAuthStorePathForDisplay } from "../../agents/auth-profiles.js";
|
||||
import { resolveAuthProfileStoreLocationForDisplay } from "../../agents/auth-profiles.js";
|
||||
import { resolveAgentHarnessPolicy } from "../../agents/harness/selection.js";
|
||||
import {
|
||||
type ModelAliasIndex,
|
||||
@@ -438,7 +438,7 @@ export async function maybeHandleModelDirectiveInfo(params: {
|
||||
modelRefs.activeDiffers ? `Active: ${modelRefs.active.label} (runtime)` : null,
|
||||
`Default: ${defaultLabel}`,
|
||||
`Agent: ${params.activeAgentId}`,
|
||||
`Auth file: ${formatPath(resolveAuthStorePathForDisplay(params.agentDir))}`,
|
||||
`Auth store: ${formatPath(resolveAuthProfileStoreLocationForDisplay(params.agentDir))}`,
|
||||
].filter((line): line is string => Boolean(line));
|
||||
if (params.resetModelOverride) {
|
||||
lines.push(`(previous selection reset to default)`);
|
||||
|
||||
@@ -381,7 +381,7 @@ export function registerModelsCli(program: Command) {
|
||||
|
||||
auth
|
||||
.command("paste-token")
|
||||
.description("Paste a token into auth-profiles.json and update config")
|
||||
.description("Paste a token into the SQLite auth store and update config")
|
||||
.requiredOption("--provider <name>", "Provider id (e.g. anthropic)")
|
||||
.option("--profile-id <id>", "Auth profile id (default: <provider>:manual)")
|
||||
.option(
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import {
|
||||
resolveAgentDir,
|
||||
resolveAgentWorkspaceDir,
|
||||
@@ -9,7 +8,7 @@ import {
|
||||
buildPortableAuthProfileSecretsStoreForAgentCopy,
|
||||
ensureAuthProfileStore,
|
||||
} from "../agents/auth-profiles.js";
|
||||
import { resolveAuthStorePath } from "../agents/auth-profiles/paths.js";
|
||||
import { resolveAuthProfileStoreKey } from "../agents/auth-profiles/paths.js";
|
||||
import {
|
||||
hasPersistedAuthProfileSecretsStore,
|
||||
loadPersistedAuthProfileStore,
|
||||
@@ -280,14 +279,14 @@ export async function agentsAddCommand(
|
||||
const defaultAgentId = resolveDefaultAgentId(cfg);
|
||||
if (defaultAgentId !== agentId) {
|
||||
const sourceAgentDir = resolveAgentDir(cfg, defaultAgentId);
|
||||
const sourceAuthPath = resolveAuthStorePath(sourceAgentDir);
|
||||
const mainAuthPath = resolveAuthStorePath(undefined);
|
||||
const sourceAuthStoreKey = resolveAuthProfileStoreKey(sourceAgentDir);
|
||||
const mainAuthStoreKey = resolveAuthProfileStoreKey(undefined);
|
||||
const sameAuthPath =
|
||||
normalizeLowercaseStringOrEmpty(path.resolve(sourceAuthPath)) ===
|
||||
normalizeLowercaseStringOrEmpty(path.resolve(resolveAuthStorePath(agentDir)));
|
||||
normalizeLowercaseStringOrEmpty(sourceAuthStoreKey) ===
|
||||
normalizeLowercaseStringOrEmpty(resolveAuthProfileStoreKey(agentDir));
|
||||
const sourceIsInheritedMain =
|
||||
normalizeLowercaseStringOrEmpty(path.resolve(sourceAuthPath)) ===
|
||||
normalizeLowercaseStringOrEmpty(path.resolve(mainAuthPath));
|
||||
normalizeLowercaseStringOrEmpty(sourceAuthStoreKey) ===
|
||||
normalizeLowercaseStringOrEmpty(mainAuthStoreKey);
|
||||
if (
|
||||
!sameAuthPath &&
|
||||
hasPersistedAuthProfileSecretsStore(sourceAgentDir) &&
|
||||
|
||||
@@ -16,8 +16,10 @@ vi.mock("../../agents/auth-profiles/persisted.js", () => ({
|
||||
}));
|
||||
|
||||
vi.mock("../../agents/auth-profiles/paths.js", () => ({
|
||||
resolveAuthStorePathForDisplay: vi.fn((agentDir?: string) =>
|
||||
agentDir ? `${agentDir}/auth-profiles.json` : "/tmp/auth-profiles.json",
|
||||
resolveAuthProfileStoreLocationForDisplay: vi.fn((agentDir?: string) =>
|
||||
agentDir
|
||||
? `/tmp/openclaw.sqlite#kv/auth-profiles/${agentDir}`
|
||||
: "/tmp/openclaw.sqlite#kv/auth-profiles/main",
|
||||
),
|
||||
}));
|
||||
|
||||
@@ -140,7 +142,7 @@ describe("resolveProviderAuthOverview", () => {
|
||||
|
||||
expect(overview.effective).toEqual({
|
||||
kind: "profiles",
|
||||
detail: "/tmp/openclaw-agent-custom/auth-profiles.json",
|
||||
detail: "/tmp/openclaw.sqlite#kv/auth-profiles//tmp/openclaw-agent-custom",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -170,7 +172,7 @@ describe("resolveProviderAuthOverview", () => {
|
||||
|
||||
expect(overview.effective).toEqual({
|
||||
kind: "profiles",
|
||||
detail: "/tmp/auth-profiles.json",
|
||||
detail: "/tmp/openclaw.sqlite#kv/auth-profiles/main",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { formatRemainingShort } from "../../agents/auth-health.js";
|
||||
import { resolveAuthProfileDisplayLabel } from "../../agents/auth-profiles/display.js";
|
||||
import { resolveAuthStorePathForDisplay } from "../../agents/auth-profiles/paths.js";
|
||||
import { resolveAuthProfileStoreLocationForDisplay } from "../../agents/auth-profiles/paths.js";
|
||||
import { loadPersistedAuthProfileStore } from "../../agents/auth-profiles/persisted.js";
|
||||
import { listProfilesForProvider } from "../../agents/auth-profiles/profiles.js";
|
||||
import type { AuthProfileStore } from "../../agents/auth-profiles/types.js";
|
||||
@@ -135,7 +135,7 @@ export function resolveProviderAuthOverview(params: {
|
||||
return {
|
||||
kind: "profiles",
|
||||
detail: shortenHomePath(
|
||||
resolveAuthStorePathForDisplay(
|
||||
resolveAuthProfileStoreLocationForDisplay(
|
||||
resolveProfileSourceAgentDir({
|
||||
agentDir: params.agentDir,
|
||||
profileIds: profiles,
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
formatRemainingShort,
|
||||
} from "../../agents/auth-health.js";
|
||||
import { resolveAuthProfileOrder } from "../../agents/auth-profiles/order.js";
|
||||
import { resolveAuthStorePathForDisplay } from "../../agents/auth-profiles/paths.js";
|
||||
import { resolveAuthProfileStoreLocationForDisplay } from "../../agents/auth-profiles/paths.js";
|
||||
import { ensureAuthProfileStoreWithoutExternalProfiles as ensureAuthProfileStore } from "../../agents/auth-profiles/store.js";
|
||||
import type { AuthProfileCredential } from "../../agents/auth-profiles/types.js";
|
||||
import { resolveProfileUnusableUntilForDisplay } from "../../agents/auth-profiles/usage.js";
|
||||
@@ -618,7 +618,7 @@ export async function modelsStatusCommand(
|
||||
aliases,
|
||||
allowed,
|
||||
auth: {
|
||||
storePath: resolveAuthStorePathForDisplay(agentDir),
|
||||
storePath: resolveAuthProfileStoreLocationForDisplay(agentDir),
|
||||
shellEnvFallback: {
|
||||
enabled: shellFallbackEnabled,
|
||||
appliedKeys: applied,
|
||||
@@ -730,7 +730,7 @@ export async function modelsStatusCommand(
|
||||
`${label("Auth store")}${colorize(rich, theme.muted, ":")} ${colorize(
|
||||
rich,
|
||||
theme.info,
|
||||
shortenHomePath(resolveAuthStorePathForDisplay(agentDir)),
|
||||
shortenHomePath(resolveAuthProfileStoreLocationForDisplay(agentDir)),
|
||||
)}`,
|
||||
);
|
||||
runtime.log(
|
||||
|
||||
@@ -51,8 +51,9 @@ const mocks = vi.hoisted(() => {
|
||||
}),
|
||||
loadPersistedAuthProfileStore: vi.fn().mockReturnValue(store),
|
||||
resolveAuthProfileDisplayLabel: vi.fn(({ profileId }: { profileId: string }) => profileId),
|
||||
resolveAuthStorePathForDisplay: vi.fn(
|
||||
(agentDir?: string) => `${agentDir ?? "/tmp/openclaw-agent"}/auth-profiles.json`,
|
||||
resolveAuthProfileStoreLocationForDisplay: vi.fn(
|
||||
(agentDir?: string) =>
|
||||
`/tmp/openclaw.sqlite#kv/auth-profiles/${agentDir ?? "/tmp/openclaw-agent"}`,
|
||||
),
|
||||
resolveProfileUnusableUntilForDisplay: vi.fn().mockReturnValue(undefined),
|
||||
resolveEnvApiKey: vi.fn((provider: string) => {
|
||||
@@ -155,7 +156,7 @@ vi.mock("../../agents/auth-profiles/display.js", () => ({
|
||||
resolveAuthProfileDisplayLabel: mocks.resolveAuthProfileDisplayLabel,
|
||||
}));
|
||||
vi.mock("../../agents/auth-profiles/paths.js", () => ({
|
||||
resolveAuthStorePathForDisplay: mocks.resolveAuthStorePathForDisplay,
|
||||
resolveAuthProfileStoreLocationForDisplay: mocks.resolveAuthProfileStoreLocationForDisplay,
|
||||
}));
|
||||
vi.mock("../../agents/auth-profiles/persisted.js", () => ({
|
||||
loadPersistedAuthProfileStore: mocks.loadPersistedAuthProfileStore,
|
||||
@@ -368,7 +369,9 @@ describe("modelsStatusCommand auth overview", () => {
|
||||
expect(mocks.ensureAuthProfileStore).toHaveBeenCalled();
|
||||
expect(payload.defaultModel).toBe("anthropic/claude-opus-4-6");
|
||||
expect(payload.configPath).toBe("/tmp/openclaw-dev/openclaw.json");
|
||||
expect(payload.auth.storePath).toBe("/tmp/openclaw-agent/auth-profiles.json");
|
||||
expect(payload.auth.storePath).toBe(
|
||||
"/tmp/openclaw.sqlite#kv/auth-profiles//tmp/openclaw-agent",
|
||||
);
|
||||
expect(payload.auth.shellEnvFallback.enabled).toBe(true);
|
||||
expect(payload.auth.shellEnvFallback.appliedKeys).toContain("OPENAI_API_KEY");
|
||||
expect(payload.auth.missingProvidersInUse).toStrictEqual([]);
|
||||
@@ -431,7 +434,9 @@ describe("modelsStatusCommand auth overview", () => {
|
||||
expect(mocks.ensureAuthProfileStore).toHaveBeenCalledWith("/tmp/openclaw-isolated-agent");
|
||||
const payload = JSON.parse(String((localRuntime.log as Mock).mock.calls[0]?.[0]));
|
||||
expect(payload.agentDir).toBe("/tmp/openclaw-isolated-agent");
|
||||
expect(payload.auth.storePath).toBe("/tmp/openclaw-isolated-agent/auth-profiles.json");
|
||||
expect(payload.auth.storePath).toBe(
|
||||
"/tmp/openclaw.sqlite#kv/auth-profiles//tmp/openclaw-isolated-agent",
|
||||
);
|
||||
});
|
||||
|
||||
it("uses agent overrides and reports sources", async () => {
|
||||
@@ -462,7 +467,7 @@ describe("modelsStatusCommand auth overview", () => {
|
||||
).find((provider) => provider.provider === "openai-codex");
|
||||
expect(openAiCodex?.effective).toEqual({
|
||||
kind: "profiles",
|
||||
detail: "/tmp/openclaw-agent-custom/auth-profiles.json",
|
||||
detail: "/tmp/openclaw.sqlite#kv/auth-profiles//tmp/openclaw-agent-custom",
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -66,7 +66,7 @@ export {
|
||||
formatAuthDoctorHint,
|
||||
resolveAuthProfileEligibility,
|
||||
resolveAuthProfileOrder,
|
||||
resolveAuthStorePathForDisplay,
|
||||
resolveAuthProfileStoreLocationForDisplay,
|
||||
} from "../agents/auth-profiles.js";
|
||||
export type {
|
||||
ApiKeyCredential,
|
||||
|
||||
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { savePersistedAuthProfileSecretsStore } from "../agents/auth-profiles/persisted.js";
|
||||
import { writeStoredModelsConfigRaw } from "../agents/models-config-store.js";
|
||||
import { runSecretsAudit } from "./audit.js";
|
||||
|
||||
@@ -34,6 +35,17 @@ async function writeJsonFile(filePath: string, value: unknown): Promise<void> {
|
||||
await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
|
||||
}
|
||||
|
||||
function writeAuthProfileStore(fixture: AuditFixture, profiles: Record<string, unknown>): void {
|
||||
savePersistedAuthProfileSecretsStore(
|
||||
{
|
||||
version: 1,
|
||||
profiles,
|
||||
},
|
||||
fixture.agentDir,
|
||||
{ env: fixture.env },
|
||||
);
|
||||
}
|
||||
|
||||
async function writeExecResolverShellScript(params: {
|
||||
scriptPath: string;
|
||||
logPath: string;
|
||||
@@ -179,10 +191,7 @@ async function seedAuditFixture(fixture: AuditFixture): Promise<void> {
|
||||
await writeJsonFile(fixture.configPath, {
|
||||
models: { providers: seededProvider },
|
||||
});
|
||||
await writeJsonFile(fixture.authStorePath, {
|
||||
version: 1,
|
||||
profiles: Object.fromEntries(seededProfiles),
|
||||
});
|
||||
writeAuthProfileStore(fixture, Object.fromEntries(seededProfiles));
|
||||
writeStoredModelsConfigRaw(
|
||||
fixture.agentDir,
|
||||
`${JSON.stringify({
|
||||
@@ -280,11 +289,9 @@ describe("secrets audit", () => {
|
||||
});
|
||||
|
||||
it("reports malformed sidecar JSON as findings instead of crashing", async () => {
|
||||
await fs.writeFile(fixture.authStorePath, "{invalid-json", "utf8");
|
||||
await fs.writeFile(fixture.authJsonPath, "{invalid-json", "utf8");
|
||||
|
||||
const report = await runSecretsAudit({ env: fixture.env });
|
||||
expectFindingFile(report, fixture.authStorePath);
|
||||
expectFindingFile(report, fixture.authJsonPath);
|
||||
expectFindingCode(report, "REF_UNRESOLVED");
|
||||
});
|
||||
@@ -611,10 +618,7 @@ describe("secrets audit", () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
await writeJsonFile(fixture.authStorePath, {
|
||||
version: 1,
|
||||
profiles: {},
|
||||
});
|
||||
writeAuthProfileStore(fixture, {});
|
||||
await fs.writeFile(fixture.envPath, "", "utf8");
|
||||
|
||||
const report = await runSecretsAudit({ env: fixture.env });
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { resolveAuthProfileStoreLocationForDisplay } from "../agents/auth-profiles/paths.js";
|
||||
import { loadPersistedAuthProfileStore } from "../agents/auth-profiles/persisted.js";
|
||||
import {
|
||||
isNonSecretApiKeyMarker,
|
||||
isSecretRefHeaderValueMarker,
|
||||
@@ -32,7 +34,7 @@ import {
|
||||
import { isNonEmptyString, isRecord } from "./shared.js";
|
||||
import {
|
||||
listAgentModelCatalogDirs,
|
||||
listAuthProfileStorePaths,
|
||||
listAuthProfileStoreAgentDirs,
|
||||
listLegacyAuthJsonPaths,
|
||||
parseEnvAssignmentValue,
|
||||
readJsonObjectIfExists,
|
||||
@@ -262,30 +264,18 @@ function collectConfigSecrets(params: {
|
||||
}
|
||||
|
||||
function collectAuthStoreSecrets(params: {
|
||||
authStorePath: string;
|
||||
agentDir?: string;
|
||||
collector: AuditCollector;
|
||||
defaults?: SecretDefaults;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
}): void {
|
||||
if (!fs.existsSync(params.authStorePath)) {
|
||||
const authStoreLocation = resolveAuthProfileStoreLocationForDisplay(params.agentDir, params.env);
|
||||
const store = loadPersistedAuthProfileStore(params.agentDir, { env: params.env });
|
||||
if (!store || !isRecord(store.profiles)) {
|
||||
return;
|
||||
}
|
||||
params.collector.filesScanned.add(params.authStorePath);
|
||||
const parsedResult = readJsonObjectIfExists(params.authStorePath);
|
||||
if (parsedResult.error) {
|
||||
addFinding(params.collector, {
|
||||
code: "REF_UNRESOLVED",
|
||||
severity: "error",
|
||||
file: params.authStorePath,
|
||||
jsonPath: "<root>",
|
||||
message: `Invalid JSON in auth-profiles store: ${parsedResult.error}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const parsed = parsedResult.value;
|
||||
if (!parsed || !isRecord(parsed.profiles)) {
|
||||
return;
|
||||
}
|
||||
for (const entry of iterateAuthProfileCredentials(parsed.profiles)) {
|
||||
params.collector.filesScanned.add(authStoreLocation);
|
||||
for (const entry of iterateAuthProfileCredentials(store.profiles)) {
|
||||
if (entry.kind === "api_key" || entry.kind === "token") {
|
||||
const { ref } = resolveSecretInputRef({
|
||||
value: entry.value,
|
||||
@@ -294,7 +284,7 @@ function collectAuthStoreSecrets(params: {
|
||||
});
|
||||
if (ref) {
|
||||
params.collector.refAssignments.push({
|
||||
file: params.authStorePath,
|
||||
file: authStoreLocation,
|
||||
path: `profiles.${entry.profileId}.${entry.valueField}`,
|
||||
ref,
|
||||
expected: "string",
|
||||
@@ -306,7 +296,7 @@ function collectAuthStoreSecrets(params: {
|
||||
addFinding(params.collector, {
|
||||
code: "PLAINTEXT_FOUND",
|
||||
severity: "warn",
|
||||
file: params.authStorePath,
|
||||
file: authStoreLocation,
|
||||
jsonPath: `profiles.${entry.profileId}.${entry.valueField}`,
|
||||
message:
|
||||
entry.kind === "api_key"
|
||||
@@ -323,7 +313,7 @@ function collectAuthStoreSecrets(params: {
|
||||
addFinding(params.collector, {
|
||||
code: "LEGACY_RESIDUE",
|
||||
severity: "info",
|
||||
file: params.authStorePath,
|
||||
file: authStoreLocation,
|
||||
jsonPath: `profiles.${entry.profileId}`,
|
||||
message: "OAuth credentials are present (out of scope for static SecretRef migration).",
|
||||
provider: entry.provider,
|
||||
@@ -690,11 +680,12 @@ export async function runSecretsAudit(
|
||||
configPath,
|
||||
collector,
|
||||
});
|
||||
for (const authStorePath of listAuthProfileStorePaths(config, stateDir)) {
|
||||
for (const agentDir of listAuthProfileStoreAgentDirs(config, stateDir)) {
|
||||
collectAuthStoreSecrets({
|
||||
authStorePath,
|
||||
agentDir,
|
||||
collector,
|
||||
defaults,
|
||||
env,
|
||||
});
|
||||
}
|
||||
for (const agentDir of listAgentModelCatalogDirs(config, stateDir, env)) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { listAgentIds, resolveAgentDir } from "../agents/agent-scope.js";
|
||||
import { resolveAuthStorePath } from "../agents/auth-profiles/paths.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
|
||||
@@ -31,11 +30,3 @@ export function listAuthProfileStoreAgentDirs(config: OpenClawConfig, stateDir:
|
||||
|
||||
return [...dirs];
|
||||
}
|
||||
|
||||
export function listAuthProfileStorePaths(config: OpenClawConfig, stateDir: string): string[] {
|
||||
const paths = new Set<string>();
|
||||
for (const agentDir of listAuthProfileStoreAgentDirs(config, stateDir)) {
|
||||
paths.add(resolveUserPath(resolveAuthStorePath(agentDir)));
|
||||
}
|
||||
return [...paths];
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { listAgentIds, resolveAgentDir } from "../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { formatErrorMessage } from "../infra/errors.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { listAuthProfileStorePaths as listAuthProfileStorePathsFromAuthStorePaths } from "./auth-store-paths.js";
|
||||
import { listAuthProfileStoreAgentDirs as listAuthProfileStoreAgentDirsFromAuthStorePaths } from "./auth-store-paths.js";
|
||||
import { parseEnvValue } from "./shared.js";
|
||||
|
||||
function isJsonObject(value: unknown): value is Record<string, unknown> {
|
||||
@@ -15,8 +15,8 @@ export function parseEnvAssignmentValue(raw: string): string {
|
||||
return parseEnvValue(raw);
|
||||
}
|
||||
|
||||
export function listAuthProfileStorePaths(config: OpenClawConfig, stateDir: string): string[] {
|
||||
return listAuthProfileStorePathsFromAuthStorePaths(config, stateDir);
|
||||
export function listAuthProfileStoreAgentDirs(config: OpenClawConfig, stateDir: string): string[] {
|
||||
return listAuthProfileStoreAgentDirsFromAuthStorePaths(config, stateDir);
|
||||
}
|
||||
|
||||
export function listLegacyAuthJsonPaths(stateDir: string): string[] {
|
||||
|
||||
@@ -649,45 +649,6 @@ export async function collectStateDeepFilesystemFindings(params: {
|
||||
}
|
||||
|
||||
for (const agentId of ids) {
|
||||
const agentDir = path.join(params.stateDir, "agents", agentId, "agent");
|
||||
const authPath = path.join(agentDir, "auth-profiles.json");
|
||||
const authPerms = await inspectPathPermissions(authPath, {
|
||||
env: params.env,
|
||||
platform: params.platform,
|
||||
exec: params.execIcacls,
|
||||
});
|
||||
if (authPerms.ok) {
|
||||
if (authPerms.worldWritable || authPerms.groupWritable) {
|
||||
findings.push({
|
||||
checkId: "fs.auth_profiles.perms_writable",
|
||||
severity: "critical",
|
||||
title: "auth-profiles.json is writable by others",
|
||||
detail: `${formatPermissionDetail(authPath, authPerms)}; another user could inject credentials.`,
|
||||
remediation: formatPermissionRemediation({
|
||||
targetPath: authPath,
|
||||
perms: authPerms,
|
||||
isDir: false,
|
||||
posixMode: 0o600,
|
||||
env: params.env,
|
||||
}),
|
||||
});
|
||||
} else if (authPerms.worldReadable || authPerms.groupReadable) {
|
||||
findings.push({
|
||||
checkId: "fs.auth_profiles.perms_readable",
|
||||
severity: "warn",
|
||||
title: "auth-profiles.json is readable by others",
|
||||
detail: `${formatPermissionDetail(authPath, authPerms)}; auth-profiles.json contains API keys and OAuth tokens.`,
|
||||
remediation: formatPermissionRemediation({
|
||||
targetPath: authPath,
|
||||
perms: authPerms,
|
||||
isDir: false,
|
||||
posixMode: 0o600,
|
||||
env: params.env,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const agentDbPath = path.join(
|
||||
params.stateDir,
|
||||
"agents",
|
||||
|
||||
@@ -239,7 +239,7 @@ describe("security fix", () => {
|
||||
await expectTightenedStateAndConfigPerms(stateDir, configPath);
|
||||
});
|
||||
|
||||
it("collects permission targets for credentials + agent auth/sessions + include files", async () => {
|
||||
it("collects permission targets for credentials + SQLite state + include files", async () => {
|
||||
const stateDir = await createStateDir("includes");
|
||||
|
||||
const includesDir = path.join(stateDir, "includes");
|
||||
@@ -268,9 +268,6 @@ describe("security fix", () => {
|
||||
|
||||
const agentDir = path.join(stateDir, "agents", "main", "agent");
|
||||
await fs.mkdir(agentDir, { recursive: true });
|
||||
const authProfilesPath = path.join(agentDir, "auth-profiles.json");
|
||||
await fs.writeFile(authProfilesPath, "{}\n", "utf-8");
|
||||
await fs.chmod(authProfilesPath, 0o644);
|
||||
|
||||
const stateDbDir = path.join(stateDir, "state");
|
||||
await fs.mkdir(stateDbDir, { recursive: true });
|
||||
@@ -304,7 +301,6 @@ describe("security fix", () => {
|
||||
{ path: configPath, mode: 0o600, require: "file" },
|
||||
{ path: credsDir, mode: 0o700, require: "dir" },
|
||||
{ path: allowFromPath, mode: 0o600, require: "file" },
|
||||
{ path: authProfilesPath, mode: 0o600, require: "file" },
|
||||
{ path: stateDbDir, mode: 0o700, require: "dir" },
|
||||
{ path: stateDbPath, mode: 0o600, require: "file" },
|
||||
{ path: stateWalPath, mode: 0o600, require: "file" },
|
||||
|
||||
@@ -371,8 +371,6 @@ export async function collectSecurityPermissionTargets(params: {
|
||||
targets.push({ path: agentRoot, mode: 0o700, require: "dir" });
|
||||
targets.push({ path: agentDir, mode: 0o700, require: "dir" });
|
||||
|
||||
const authPath = path.join(agentDir, "auth-profiles.json");
|
||||
targets.push({ path: authPath, mode: 0o600, require: "file" });
|
||||
addSqlitePermissionTargets(
|
||||
targets,
|
||||
resolveOpenClawAgentSqlitePath({ agentId: normalizedAgentId, env: params.env }),
|
||||
|
||||
Reference in New Issue
Block a user