fix(gdrive): validate folder access, run config test, harden Drive API (#321)

* fix(gdrive): validate folder access, run config test, harden Drive API

Connection test and setup validation now verify folder_id resolves to an accessible Drive folder before counting Docs, via a shared verifyGdriveFolderAndCountDocs helper, so a wrong or unshared folder fails instead of passing with 0 docs.

Move gdrive-config.test.ts under test/ so Vitest's test/** glob actually runs it; escape folder_id in the Drive query; add retry/backoff on transient Google API responses; and record skipped non-Google-Doc files in the staged manifest.

* chore: sync uv.lock to ktx-daemon/ktx-sl 0.13.1
This commit is contained in:
Andrey Avtomonov 2026-06-28 01:02:37 +02:00 committed by GitHub
parent 5645dc4d28
commit ca231df5fe
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 346 additions and 65 deletions

View file

@ -0,0 +1,71 @@
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import {
gdriveConnectionToPullConfig,
parseGdriveConnectionConfig,
resolveGdriveServiceAccountKey,
} from '../../../src/context/connections/gdrive-config.js';
describe('standalone gdrive connection config', () => {
let tempDir: string;
beforeEach(async () => {
tempDir = await mkdtemp(join(tmpdir(), 'ktx-gdrive-config-'));
});
afterEach(async () => {
await rm(tempDir, { recursive: true, force: true });
});
it('parses config with safe defaults', () => {
const parsed = parseGdriveConnectionConfig({
driver: 'gdrive',
service_account_key_ref: 'file:/tmp/google-key.json', // pragma: allowlist secret
folder_id: 'folder-123',
});
expect(parsed).toEqual({
driver: 'gdrive',
service_account_key_ref: 'file:/tmp/google-key.json', // pragma: allowlist secret
folder_id: 'folder-123',
recursive: false,
});
});
it('requires file-based service account keys', () => {
expect(() =>
parseGdriveConnectionConfig({
driver: 'gdrive',
service_account_key_ref: 'env:GOOGLE_KEY', // pragma: allowlist secret
folder_id: 'folder-123',
}),
).toThrow('gdrive service_account_key_ref must use file:/path/to/key.json');
});
it('resolves service account key files', async () => {
const keyPath = join(tempDir, 'google-key.json');
await writeFile(keyPath, '{"client_email":"bot@example.com","private_key":"line-1"}\n', 'utf-8'); // pragma: allowlist secret
await expect(resolveGdriveServiceAccountKey(`file:${keyPath}`)).resolves.toContain('"client_email":"bot@example.com"');
});
it('converts config into adapter pull config', async () => {
const keyPath = join(tempDir, 'google-key.json');
await writeFile(keyPath, '{"client_email":"bot@example.com","private_key":"line-1"}\n', 'utf-8'); // pragma: allowlist secret
const pullConfig = await gdriveConnectionToPullConfig(
parseGdriveConnectionConfig({
driver: 'gdrive',
service_account_key_ref: `file:${keyPath}`, // pragma: allowlist secret
folder_id: 'folder-123',
recursive: true,
}),
);
expect(pullConfig).toEqual({
serviceAccountKey: '{"client_email":"bot@example.com","private_key":"line-1"}', // pragma: allowlist secret
folderId: 'folder-123',
recursive: true,
});
});
});