openpencil/apps/desktop/git/__tests__/ssh-keys.test.ts
Kayshen-X a7d73ebb62 feat(ai): pencil-style agentic design tool-loop, multi-chat tabs, #27 panel restyle
Built-in design generation now runs as an agentic MCP tool-loop (reusing the
agent-rs BuiltInProvider), gated behind OPENPENCIL_DESIGN_AGENT_LOOP / the
Settings experimental toggle; the orchestrator stays the default.

- design-agent system prompt + in-process design toolset (parity-locked with
  the MCP surface) + flag-gated Intent::Design routing
- spawn_agents execution as sequential sub-loops + live creation-mode badges
  (per-agent glow + 'N/M designing...' header)
- new MCP tools: get_guidelines, ToolSearch, get_screenshot, get_editor_state,
  export_nodes, spawn_agents; style-guide local audit
- #27 AI panel restyle: rounded tool cards + green check-rings, gray user
  bubbles, model-pill bottom toolbar, header, empty-state pills, the
  PARALLEL AGENTS (agent_team_size) 1x-6x chip dropdown
- multi-chat tabs: ChatSessions model (Deref-to-active) + tab row UI
  (switch / close / + / Cmd+T) with each run bound to its tab

Large checkpoint commit spanning the working tree (Rust shell crates).
2026-07-02 21:21:06 +08:00

76 lines
3.3 KiB
TypeScript

// apps/desktop/git/__tests__/ssh-keys.test.ts
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { promises as fsp } from 'node:fs';
import { join } from 'node:path';
import { createSshKeyManager, type SshKeyManager } from '../ssh-keys';
import { mkTempDir } from './test-helpers';
describe('ssh-keys', () => {
let temp: { dir: string; dispose: () => Promise<void> };
let manager: SshKeyManager;
beforeEach(async () => {
temp = await mkTempDir();
manager = createSshKeyManager({ sshDir: join(temp.dir, 'ssh') });
});
afterEach(async () => {
await temp.dispose();
});
it('generate produces a valid OpenSSH ed25519 public key with a SHA256 fingerprint', async () => {
const info = await manager.generate({ host: 'github.com', comment: 'kay@laptop' });
expect(info.publicKey.startsWith('ssh-ed25519 ')).toBe(true);
expect(info.publicKey.endsWith('kay@laptop')).toBe(true);
expect(info.fingerprint.startsWith('SHA256:')).toBe(true);
expect(info.privateKeyPath).toMatch(/\.pem$/);
// The private key file exists with mode 0600.
const stat = await fsp.stat(info.privateKeyPath);
// mode bits include the file type, mask for permissions only.
expect(stat.mode & 0o777).toBe(0o600);
});
it('list returns all generated keys', async () => {
const a = await manager.generate({ host: 'github.com', comment: 'a' });
const b = await manager.generate({ host: 'gitlab.com', comment: 'b' });
const all = await manager.list();
const ids = all.map((k) => k.id).sort();
expect(ids).toEqual([a.id, b.id].sort());
});
it('delete removes the key from the index and unlinks the private file', async () => {
const info = await manager.generate({ host: 'github.com', comment: 'k' });
await manager.delete(info.id);
const all = await manager.list();
expect(all).toHaveLength(0);
await expect(fsp.access(info.privateKeyPath)).rejects.toThrow();
});
it('delete is idempotent: deleting an unknown key is a no-op', async () => {
await expect(manager.delete('not-a-real-id')).resolves.toBeUndefined();
});
it('getPrivateKeyPath returns the absolute path for an existing key and throws for unknown', async () => {
const info = await manager.generate({ host: 'github.com', comment: 'k' });
expect(await manager.getPrivateKeyPath(info.id)).toBe(info.privateKeyPath);
await expect(manager.getPrivateKeyPath('not-real')).rejects.toThrow(/SSH key/);
});
it('import takes an existing PEM private key file and stores a copy', async () => {
// First generate one to get a real PEM file we can use as the "external" source.
const seeded = await manager.generate({ host: 'github.com', comment: 'seed' });
// Now create a fresh manager (different sshDir) and import the seeded private key.
const otherDir = join(temp.dir, 'other-ssh');
const other = createSshKeyManager({ sshDir: otherDir });
const imported = await other.import({
privateKeyPath: seeded.privateKeyPath,
host: 'gitlab.com',
});
expect(imported.publicKey.startsWith('ssh-ed25519 ')).toBe(true);
expect(imported.fingerprint).toBe(seeded.fingerprint); // same key → same fingerprint
expect(imported.privateKeyPath).not.toBe(seeded.privateKeyPath); // copied to new location
expect(imported.privateKeyPath.startsWith(otherDir)).toBe(true);
});
});