mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-12 22:14:22 +00:00
fix: restrict Codex usage cache permissions
This commit is contained in:
1 parent
62a4d44b58
commit
c630ce878e
2 files changed
+40
-2
No files matched your search
@@ -14,6 +14,8 @@ interface CodexNativeUsageCollectorOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CODEX_NATIVE_USAGE_CACHE_VERSION = 1;
|
const CODEX_NATIVE_USAGE_CACHE_VERSION = 1;
|
||||||
|
const SECURE_CACHE_DIR_MODE = 0o700;
|
||||||
|
const SECURE_CACHE_FILE_MODE = 0o600;
|
||||||
|
|
||||||
interface CachedRolloutFile {
|
interface CachedRolloutFile {
|
||||||
path: string;
|
path: string;
|
||||||
@@ -133,6 +135,14 @@ function isCodexNativeUsageCache(value: unknown): value is CodexNativeUsageCache
|
|||||||
return Object.values(value.files).every(isCachedRolloutFile);
|
return Object.values(value.files).every(isCachedRolloutFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function chmodBestEffort(targetPath: string, mode: number): void {
|
||||||
|
try {
|
||||||
|
fs.chmodSync(targetPath, mode);
|
||||||
|
} catch {
|
||||||
|
// Cache reads and writes remain best-effort on filesystems that do not support chmod.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function readUsageCache(
|
function readUsageCache(
|
||||||
cacheDir: string,
|
cacheDir: string,
|
||||||
includeCliproxySessions: boolean
|
includeCliproxySessions: boolean
|
||||||
@@ -153,11 +163,17 @@ function readUsageCache(
|
|||||||
|
|
||||||
function writeUsageCache(cacheDir: string, cache: CodexNativeUsageCache): void {
|
function writeUsageCache(cacheDir: string, cache: CodexNativeUsageCache): void {
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(cacheDir, { recursive: true });
|
fs.mkdirSync(cacheDir, { recursive: true, mode: SECURE_CACHE_DIR_MODE });
|
||||||
|
chmodBestEffort(cacheDir, SECURE_CACHE_DIR_MODE);
|
||||||
const cachePath = getCacheFilePath(cacheDir, cache.includeCliproxySessions);
|
const cachePath = getCacheFilePath(cacheDir, cache.includeCliproxySessions);
|
||||||
const tempPath = `${cachePath}.${process.pid}.tmp`;
|
const tempPath = `${cachePath}.${process.pid}.tmp`;
|
||||||
fs.writeFileSync(tempPath, JSON.stringify(cache), 'utf8');
|
fs.writeFileSync(tempPath, JSON.stringify(cache), {
|
||||||
|
encoding: 'utf8',
|
||||||
|
mode: SECURE_CACHE_FILE_MODE,
|
||||||
|
});
|
||||||
|
chmodBestEffort(tempPath, SECURE_CACHE_FILE_MODE);
|
||||||
fs.renameSync(tempPath, cachePath);
|
fs.renameSync(tempPath, cachePath);
|
||||||
|
chmodBestEffort(cachePath, SECURE_CACHE_FILE_MODE);
|
||||||
} catch {
|
} catch {
|
||||||
// Best-effort only.
|
// Best-effort only.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,6 +311,28 @@ describe('codex native usage collector', () => {
|
|||||||
expect(entries).toHaveLength(2);
|
expect(entries).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('writes native usage caches with owner-only permissions', async () => {
|
||||||
|
if (process.platform === 'win32') return;
|
||||||
|
|
||||||
|
writeCodexRollout(tempRoot);
|
||||||
|
const cacheDir = getCacheDir();
|
||||||
|
const previousUmask = process.umask(0o022);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await scanCodexNativeUsageEntries({
|
||||||
|
env: { CODEX_HOME: tempRoot },
|
||||||
|
homeDir: tempRoot,
|
||||||
|
cacheDir,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
process.umask(previousUmask);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachePath = path.join(cacheDir, 'codex-native-usage-v1.json');
|
||||||
|
expect(fs.statSync(cacheDir).mode & 0o777).toBe(0o700);
|
||||||
|
expect(fs.statSync(cachePath).mode & 0o777).toBe(0o600);
|
||||||
|
});
|
||||||
|
|
||||||
it('keeps default and include-cliproxy cache entries separate', async () => {
|
it('keeps default and include-cliproxy cache entries separate', async () => {
|
||||||
writeCodexRollout(tempRoot, { modelProvider: 'cliproxy' });
|
writeCodexRollout(tempRoot, { modelProvider: 'cliproxy' });
|
||||||
const cacheDir = getCacheDir();
|
const cacheDir = getCacheDir();
|
||||||
|
|||||||
Reference in new issue
Block a user