GittonGitton
ブログ一覧に戻る
philosophy

Gittonがこだわるセキュリティ設計

OSキーチェーンによる暗号化、プラグインサンドボックス、CSPによるXSS対策など、Gittonが実装するセキュリティ機能をソースコードとともに解説します。

Gittonがこだわるセキュリティ設計

AIがコードを書く時代のセキュリティ

Gittonを開発するにあたり、セキュリティは最初から設計の中心に据えた。

AIコーディングツールを使う開発者にとって、Gitクライアントは開発フローの要だ。リポジトリの認証情報、APIキー、コードの差分。これらすべてがGitクライアントを通過する。だからこそ、セキュリティには妥協しない。

この記事では、Gittonが実装しているセキュリティ機能を、実際のソースコードとともに解説する。

1. OSキーチェーンによるAPIキーの暗号化

AIプロバイダーのAPIキーは、平文でファイルに保存すべきではない。Gittonでは、ElectronのsafeStorage APIを使って、OS固有のセキュアストレージに保存している。

// src/main/crypto.ts
import { safeStorage } from 'electron'

export function encryptString(plainText: string): string {
  if (!plainText) return ''

  if (!safeStorage.isEncryptionAvailable()) {
    console.warn('Encryption is not available on this system')
    return Buffer.from(plainText).toString('base64')
  }

  const encrypted = safeStorage.encryptString(plainText)
  return encrypted.toString('base64')
}

macOSではKeychain、LinuxではlibSecret、WindowsではDPAPIが使われる。つまり、OSが提供する最も安全なストレージを利用している。

仮にGittonのデータベースファイルが流出しても、APIキーは暗号化されているため、そのままでは使えない。復号にはOSの認証が必要だ。

2. プラグインの権限システム

Gittonはプラグインで拡張できる。しかし、プラグインは潜在的なセキュリティリスクだ。悪意のあるプラグインがAPIキーを盗んだり、コードを外部に送信する可能性がある。

そこで、Androidアプリのようなパーミッションシステムを導入した。

// src/main/plugins/types.ts
export const PluginPermission = z.enum([
  'ui:sidebar',         // サイドバーにUIを追加
  'ui:settings',        // 設定タブを追加
  'settings:read',      // 設定の読み取り
  'settings:write',     // 設定の書き込み
  'network:fetch',      // HTTPリクエストの実行
  'git:read',           // リポジトリファイルの読み取り
  'git:write',          // リポジトリファイルの書き込み
  'git:hooks'           // Git hooksの管理
])

プラグインはpackage.jsonで必要な権限を宣言しなければならない。そして、新しくインストールされたプラグインはデフォルトで無効になる。

// src/main/plugins/manager.ts
// Register as a new plugin (disabled by default for security)
await queries.addPlugin({
  id,
  name: packageName,
  // ...
  enabled: false  // セキュリティのためデフォルトは無効
})

ユーザーが明示的に有効化しない限り、プラグインは動作しない。権限を確認してから有効化できる。

さらに、プラグインのアップデートで権限が変更された場合も検知する。

// 権限の変更を検出
const permissionChanged = !this.arePermissionsEqual(
  currentManifest.permissions,
  dbManifest.permissions
)

権限に変更がない場合は自動アップデート、権限が増えた場合はユーザーの再承認が必要になる。

3. CSPによるプラグインのサンドボックス

プラグインのUIはiframe内で動作する。ここでContent Security Policy(CSP)を適用し、悪意のあるスクリプトの実行を防いでいる。

// src/main/plugins/ui-server.ts
function generateNonce(): string {
  return crypto.randomBytes(16).toString('base64')
}

function buildCSPHeader(nonce: string): string {
  const allowedDomains = pluginManager.getAllAllowedDomains()

  // nonce-basedのCSPで、許可されたスクリプトのみ実行可能
  const scriptSrc = ["'self'", `'nonce-${nonce}'`, ...allowedDomains.script].join(' ')
  const connectSrc = ["'self'", 'https://api.github.com', ...allowedDomains.connect].join(' ')

  return [
    "default-src 'self'",
    `script-src ${scriptSrc}`,
    // ...
  ].join('; ')
}

ポイントはnonce-based CSPを使っていること。'unsafe-inline'は使わない。

各リクエストごとに一意のnonceを生成し、そのnonceを持つスクリプトのみ実行を許可する。これにより、XSS攻撃でインラインスクリプトを注入されても実行されない。

4. パストラバーサル対策

プラグインがファイルにアクセスする際、プラグインディレクトリ外へのアクセスを防止している。

// src/main/plugins/ui-server.ts
// Security: ensure file is within plugin directory
const resolvedPath = path.resolve(filePath)
const pluginRoot = path.resolve(plugin.path)

if (!resolvedPath.startsWith(pluginRoot)) {
  res.writeHead(403, { 'Content-Type': 'text/plain' })
  res.end('Access denied')
  return
}

../../etc/passwdのようなパストラバーサル攻撃を試みても、プラグインディレクトリ外へのアクセスは403で拒否される。

5. contextBridgeによる安全なIPC

Electronアプリのセキュリティで最も重要なのが、メインプロセスとレンダラープロセス間の通信だ。Gittonでは、Electronが推奨するcontextBridge APIを使用している。

// src/preload/index.ts
import { contextBridge, ipcRenderer } from 'electron'

contextBridge.exposeInMainWorld('electronAPI', {
  minimize: () => ipcRenderer.invoke('window:minimize'),
  maximize: () => ipcRenderer.invoke('window:maximize'),
  // ...
})

contextBridge.exposeInMainWorld('terminalAPI', {
  create: (sessionId: string, cwd: string, shell?: string) =>
    ipcRenderer.invoke('terminal:create', { sessionId, cwd, shell }),
  // ...
})

直接ipcRendererをレンダラーに公開するのではなく、必要な機能だけをラップして公開している。これにより、レンダラープロセスが侵害されても、任意のIPCコールを実行することはできない。

6. AIコードレビューのセキュリティフォーカス

GittonのAIコードレビュー機能は、デフォルトでセキュリティ脆弱性の検出に焦点を当てている。

// src/main/ai/index.ts
export const DEFAULT_CODE_REVIEW_PROMPT = `You are an expert code reviewer...

## Focus areas:
- Security vulnerabilities (SQL injection, XSS, etc.)
- Potential bugs or logic errors
- Performance issues
- Missing error handling
- Resource leaks
- Race conditions
- Null/undefined safety
`

AIがコードを書く時代だからこそ、AIにセキュリティチェックをさせる。人間が見落としがちな脆弱性も、AIは見逃さない。

7. ローカルAI対応によるプライバシー保護

機密性の高いコードを外部APIに送信したくない場合もある。GittonはOllamaに対応しており、完全にローカルでAI機能を使用できる。

// src/main/ai/index.ts
case 'ollama': {
  const ollama = createOllama({
    baseURL: settings.ollamaBaseUrl || 'http://localhost:11434/api'
  })
  return ollama(modelName) as unknown as LanguageModel
}

Ollamaを使えば、コミットメッセージ生成もコードレビューも、すべてローカルで完結する。ネットワーク接続がなくても、AIによるセキュリティチェックが可能だ。

セキュリティは継続的な取り組み

これらのセキュリティ機能は、一度実装して終わりではない。

  • 依存パッケージの脆弱性スキャン
  • Electronのセキュリティアップデートの追従
  • 新しい攻撃手法への対応

セキュリティは継続的な取り組みだ。Gittonは、開発者が安心して使えるツールであり続けるために、セキュリティを最優先に開発を続けていく。

Gitton - The Git Client for Vibe Coding
Integrated terminal for AI coding tools. AI-powered commits, code reviews, and PR management.
/service/gitton

著者

steelydylan
steelydylan

WebデベロッパーでGittonの開発者。GitとAIを愛する開発者のためのツールを作っています。