refactor(policy): rename "Project" policies to "Workspace" policies

Updates the terminology and configuration for the intermediate policy tier
from "Project" to "Workspace" to better align with the Gemini CLI ecosystem.

Key changes:
- Renamed `PROJECT_POLICY_TIER` to `WORKSPACE_POLICY_TIER`.
- Renamed `getProjectPoliciesDir` to `getWorkspacePoliciesDir`.
- Updated integrity scope from `project` to `workspace`.
- Updated UI dialogs and documentation.
- Renamed related test files.
This commit is contained in:
Abhijit Balaji
2026-02-17 11:08:10 -08:00
parent d8f1db6161
commit 8feff1cc9b
15 changed files with 141 additions and 141 deletions

View File

@@ -294,7 +294,7 @@ export async function parseArguments(
.option('accept-changed-policies', {
type: 'boolean',
description:
'Automatically accept changed project policies (use with caution).',
'Automatically accept changed workspace policies (use with caution).',
}),
)
// Register MCP subcommands
@@ -702,52 +702,52 @@ export async function loadCliConfig(
policyPaths: argv.policy,
};
let projectPoliciesDir: string | undefined;
let workspacePoliciesDir: string | undefined;
let policyUpdateConfirmationRequest:
| PolicyUpdateConfirmationRequest
| undefined;
if (trustedFolder) {
const potentialProjectPoliciesDir = new Storage(
const potentialWorkspacePoliciesDir = new Storage(
cwd,
).getProjectPoliciesDir();
).getWorkspacePoliciesDir();
const integrityManager = new PolicyIntegrityManager();
const integrityResult = await integrityManager.checkIntegrity(
'project',
'workspace',
cwd,
potentialProjectPoliciesDir,
potentialWorkspacePoliciesDir,
);
if (integrityResult.status === IntegrityStatus.MATCH) {
projectPoliciesDir = potentialProjectPoliciesDir;
workspacePoliciesDir = potentialWorkspacePoliciesDir;
} else if (
integrityResult.status === IntegrityStatus.NEW &&
integrityResult.fileCount === 0
) {
// No project policies found
projectPoliciesDir = undefined;
// No workspace policies found
workspacePoliciesDir = undefined;
} else {
// Policies changed or are new
if (argv.acceptChangedPolicies) {
debugLogger.warn(
'WARNING: Project policies changed or are new. Auto-accepting due to --accept-changed-policies flag.',
'WARNING: Workspace policies changed or are new. Auto-accepting due to --accept-changed-policies flag.',
);
await integrityManager.acceptIntegrity(
'project',
'workspace',
cwd,
integrityResult.hash,
);
projectPoliciesDir = potentialProjectPoliciesDir;
workspacePoliciesDir = potentialWorkspacePoliciesDir;
} else if (interactive) {
policyUpdateConfirmationRequest = {
scope: 'project',
scope: 'workspace',
identifier: cwd,
policyDir: potentialProjectPoliciesDir,
policyDir: potentialWorkspacePoliciesDir,
newHash: integrityResult.hash,
};
} else {
debugLogger.warn(
'WARNING: Project policies changed or are new. Loading default policies only. Use --accept-changed-policies to accept.',
'WARNING: Workspace policies changed or are new. Loading default policies only. Use --accept-changed-policies to accept.',
);
}
}
@@ -756,7 +756,7 @@ export async function loadCliConfig(
const policyEngineConfig = await createPolicyEngineConfig(
effectiveSettings,
approvalMode,
projectPoliciesDir,
workspacePoliciesDir,
);
policyEngineConfig.nonInteractive = !interactive;

View File

@@ -18,7 +18,7 @@ import { type Settings } from './settings.js';
export async function createPolicyEngineConfig(
settings: Settings,
approvalMode: ApprovalMode,
projectPoliciesDir?: string,
workspacePoliciesDir?: string,
): Promise<PolicyEngineConfig> {
// Explicitly construct PolicySettings from Settings to ensure type safety
// and avoid accidental leakage of other settings properties.
@@ -33,7 +33,7 @@ export async function createPolicyEngineConfig(
policySettings,
approvalMode,
undefined,
projectPoliciesDir,
workspacePoliciesDir,
);
}

View File

@@ -49,7 +49,7 @@ vi.mock('@google/gemini-cli-core', async () => {
};
});
describe('Project-Level Policy CLI Integration', () => {
describe('Workspace-Level Policy CLI Integration', () => {
const MOCK_CWD = process.cwd();
beforeEach(() => {
@@ -63,13 +63,13 @@ describe('Project-Level Policy CLI Integration', () => {
vi.mocked(ServerConfig.isHeadlessMode).mockReturnValue(false);
});
it('should have getProjectPoliciesDir on Storage class', () => {
it('should have getWorkspacePoliciesDir on Storage class', () => {
const storage = new ServerConfig.Storage(MOCK_CWD);
expect(storage.getProjectPoliciesDir).toBeDefined();
expect(typeof storage.getProjectPoliciesDir).toBe('function');
expect(storage.getWorkspacePoliciesDir).toBeDefined();
expect(typeof storage.getWorkspacePoliciesDir).toBe('function');
});
it('should pass projectPoliciesDir to createPolicyEngineConfig when folder is trusted', async () => {
it('should pass workspacePoliciesDir to createPolicyEngineConfig when folder is trusted', async () => {
vi.mocked(isWorkspaceTrusted).mockReturnValue({
isTrusted: true,
source: 'file',
@@ -88,7 +88,7 @@ describe('Project-Level Policy CLI Integration', () => {
);
});
it('should NOT pass projectPoliciesDir to createPolicyEngineConfig when folder is NOT trusted', async () => {
it('should NOT pass workspacePoliciesDir to createPolicyEngineConfig when folder is NOT trusted', async () => {
vi.mocked(isWorkspaceTrusted).mockReturnValue({
isTrusted: false,
source: 'file',
@@ -107,7 +107,7 @@ describe('Project-Level Policy CLI Integration', () => {
);
});
it('should NOT pass projectPoliciesDir if integrity is NEW but fileCount is 0', async () => {
it('should NOT pass workspacePoliciesDir if integrity is NEW but fileCount is 0', async () => {
vi.mocked(isWorkspaceTrusted).mockReturnValue({
isTrusted: true,
source: 'file',
@@ -131,7 +131,7 @@ describe('Project-Level Policy CLI Integration', () => {
);
});
it('should warn and NOT pass projectPoliciesDir if integrity MISMATCH in non-interactive mode', async () => {
it('should warn and NOT pass workspacePoliciesDir if integrity MISMATCH in non-interactive mode', async () => {
vi.mocked(isWorkspaceTrusted).mockReturnValue({
isTrusted: true,
source: 'file',
@@ -149,7 +149,7 @@ describe('Project-Level Policy CLI Integration', () => {
await loadCliConfig(settings, 'test-session', argv, { cwd: MOCK_CWD });
expect(debugLogger.warn).toHaveBeenCalledWith(
expect.stringContaining('Project policies changed or are new'),
expect.stringContaining('Workspace policies changed or are new'),
);
expect(ServerConfig.createPolicyEngineConfig).toHaveBeenCalledWith(
expect.anything(),
@@ -176,7 +176,7 @@ describe('Project-Level Policy CLI Integration', () => {
await loadCliConfig(settings, 'test-session', argv, { cwd: MOCK_CWD });
expect(mockAcceptIntegrity).toHaveBeenCalledWith(
'project',
'workspace',
MOCK_CWD,
'new-hash',
);
@@ -211,7 +211,7 @@ describe('Project-Level Policy CLI Integration', () => {
});
expect(config.getPolicyUpdateConfirmationRequest()).toEqual({
scope: 'project',
scope: 'workspace',
identifier: MOCK_CWD,
policyDir: expect.stringContaining(path.join('.gemini', 'policies')),
newHash: 'new-hash',
@@ -247,7 +247,7 @@ describe('Project-Level Policy CLI Integration', () => {
});
expect(config.getPolicyUpdateConfirmationRequest()).toEqual({
scope: 'project',
scope: 'workspace',
identifier: MOCK_CWD,
policyDir: expect.stringContaining(path.join('.gemini', 'policies')),
newHash: 'new-hash',

View File

@@ -23,14 +23,14 @@ describe('PolicyUpdateDialog', () => {
const { lastFrame } = renderWithProviders(
<PolicyUpdateDialog
onSelect={onSelect}
scope="project"
scope="workspace"
identifier="/test/path"
isRestarting={false}
/>,
);
const output = lastFrame();
expect(output).toContain('New or changed project policies detected');
expect(output).toContain('New or changed workspace policies detected');
expect(output).toContain('Location: /test/path');
expect(output).toContain('Accept and Load');
expect(output).toContain('Ignore');
@@ -41,7 +41,7 @@ describe('PolicyUpdateDialog', () => {
const { stdin } = renderWithProviders(
<PolicyUpdateDialog
onSelect={onSelect}
scope="project"
scope="workspace"
identifier="/test/path"
isRestarting={false}
/>,
@@ -62,7 +62,7 @@ describe('PolicyUpdateDialog', () => {
const { stdin } = renderWithProviders(
<PolicyUpdateDialog
onSelect={onSelect}
scope="project"
scope="workspace"
identifier="/test/path"
isRestarting={false}
/>,
@@ -86,7 +86,7 @@ describe('PolicyUpdateDialog', () => {
const { stdin } = renderWithProviders(
<PolicyUpdateDialog
onSelect={onSelect}
scope="project"
scope="workspace"
identifier="/test/path"
isRestarting={false}
/>,
@@ -106,7 +106,7 @@ describe('PolicyUpdateDialog', () => {
const { lastFrame } = renderWithProviders(
<PolicyUpdateDialog
onSelect={onSelect}
scope="project"
scope="workspace"
identifier="/test/path"
isRestarting={true}
/>,