2025-09-18 13:44:23 -07:00
|
|
|
/**
|
|
|
|
|
* @license
|
|
|
|
|
* Copyright 2025 Google LLC
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
type PolicyEngineConfig,
|
2025-10-28 09:20:57 -07:00
|
|
|
type ApprovalMode,
|
2025-10-21 11:45:33 -07:00
|
|
|
type PolicyEngine,
|
|
|
|
|
type MessageBus,
|
2025-11-03 15:41:00 -08:00
|
|
|
type PolicySettings,
|
|
|
|
|
createPolicyEngineConfig as createCorePolicyEngineConfig,
|
|
|
|
|
createPolicyUpdater as createCorePolicyUpdater,
|
2026-02-19 16:16:03 -08:00
|
|
|
PolicyIntegrityManager,
|
|
|
|
|
IntegrityStatus,
|
|
|
|
|
Storage,
|
|
|
|
|
type PolicyUpdateConfirmationRequest,
|
|
|
|
|
writeToStderr,
|
2025-09-18 13:44:23 -07:00
|
|
|
} from '@google/gemini-cli-core';
|
2025-11-03 15:41:00 -08:00
|
|
|
import { type Settings } from './settings.js';
|
2025-10-28 09:20:57 -07:00
|
|
|
|
|
|
|
|
export async function createPolicyEngineConfig(
|
2025-09-18 13:44:23 -07:00
|
|
|
settings: Settings,
|
|
|
|
|
approvalMode: ApprovalMode,
|
2026-02-19 16:16:03 -08:00
|
|
|
workspacePoliciesDir?: string,
|
2025-10-28 09:20:57 -07:00
|
|
|
): Promise<PolicyEngineConfig> {
|
2025-11-03 15:41:00 -08:00
|
|
|
// Explicitly construct PolicySettings from Settings to ensure type safety
|
|
|
|
|
// and avoid accidental leakage of other settings properties.
|
|
|
|
|
const policySettings: PolicySettings = {
|
|
|
|
|
mcp: settings.mcp,
|
|
|
|
|
tools: settings.tools,
|
|
|
|
|
mcpServers: settings.mcpServers,
|
2026-02-12 16:25:23 -08:00
|
|
|
policyPaths: settings.policyPaths,
|
2026-02-19 16:16:03 -08:00
|
|
|
workspacePoliciesDir,
|
2025-09-18 13:44:23 -07:00
|
|
|
};
|
2025-11-03 15:41:00 -08:00
|
|
|
|
|
|
|
|
return createCorePolicyEngineConfig(policySettings, approvalMode);
|
2025-09-18 13:44:23 -07:00
|
|
|
}
|
2025-10-21 11:45:33 -07:00
|
|
|
|
|
|
|
|
export function createPolicyUpdater(
|
|
|
|
|
policyEngine: PolicyEngine,
|
|
|
|
|
messageBus: MessageBus,
|
|
|
|
|
) {
|
2025-11-03 15:41:00 -08:00
|
|
|
return createCorePolicyUpdater(policyEngine, messageBus);
|
2025-10-28 09:20:57 -07:00
|
|
|
}
|
2026-02-19 16:16:03 -08:00
|
|
|
|
|
|
|
|
export interface WorkspacePolicyState {
|
|
|
|
|
workspacePoliciesDir?: string;
|
|
|
|
|
policyUpdateConfirmationRequest?: PolicyUpdateConfirmationRequest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resolves the workspace policy state by checking folder trust and policy integrity.
|
|
|
|
|
*/
|
|
|
|
|
export async function resolveWorkspacePolicyState(options: {
|
|
|
|
|
cwd: string;
|
|
|
|
|
trustedFolder: boolean;
|
|
|
|
|
interactive: boolean;
|
|
|
|
|
}): Promise<WorkspacePolicyState> {
|
|
|
|
|
const { cwd, trustedFolder, interactive } = options;
|
|
|
|
|
|
|
|
|
|
let workspacePoliciesDir: string | undefined;
|
|
|
|
|
let policyUpdateConfirmationRequest:
|
|
|
|
|
| PolicyUpdateConfirmationRequest
|
|
|
|
|
| undefined;
|
|
|
|
|
|
|
|
|
|
if (trustedFolder) {
|
|
|
|
|
const potentialWorkspacePoliciesDir = new Storage(
|
|
|
|
|
cwd,
|
|
|
|
|
).getWorkspacePoliciesDir();
|
|
|
|
|
const integrityManager = new PolicyIntegrityManager();
|
|
|
|
|
const integrityResult = await integrityManager.checkIntegrity(
|
|
|
|
|
'workspace',
|
|
|
|
|
cwd,
|
|
|
|
|
potentialWorkspacePoliciesDir,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (integrityResult.status === IntegrityStatus.MATCH) {
|
|
|
|
|
workspacePoliciesDir = potentialWorkspacePoliciesDir;
|
|
|
|
|
} else if (
|
|
|
|
|
integrityResult.status === IntegrityStatus.NEW &&
|
|
|
|
|
integrityResult.fileCount === 0
|
|
|
|
|
) {
|
|
|
|
|
// No workspace policies found
|
|
|
|
|
workspacePoliciesDir = undefined;
|
|
|
|
|
} else if (interactive) {
|
|
|
|
|
// Policies changed or are new, and we are in interactive mode
|
|
|
|
|
policyUpdateConfirmationRequest = {
|
|
|
|
|
scope: 'workspace',
|
|
|
|
|
identifier: cwd,
|
|
|
|
|
policyDir: potentialWorkspacePoliciesDir,
|
|
|
|
|
newHash: integrityResult.hash,
|
|
|
|
|
};
|
|
|
|
|
} else {
|
|
|
|
|
// Non-interactive mode: warn and automatically accept/load
|
|
|
|
|
await integrityManager.acceptIntegrity(
|
|
|
|
|
'workspace',
|
|
|
|
|
cwd,
|
|
|
|
|
integrityResult.hash,
|
|
|
|
|
);
|
|
|
|
|
workspacePoliciesDir = potentialWorkspacePoliciesDir;
|
|
|
|
|
// debugLogger.warn here doesn't show up in the terminal. It is showing up only in debug mode on the debug console
|
|
|
|
|
writeToStderr(
|
|
|
|
|
'WARNING: Workspace policies changed or are new. Automatically accepting and loading them in non-interactive mode.\n',
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { workspacePoliciesDir, policyUpdateConfirmationRequest };
|
|
|
|
|
}
|