Codex Security TypeScript SDK
TypeScript から Codex Security スキャンを実行し、対象とプロバイダーを選択して結果を確認し、スキャンのライフサイクルを管理します。
Codex Security TypeScript SDK を使用すると、アプリケーションや開発者向けツールからリポジトリやコード変更に対するセキュリティスキャンを実行できます。SDK は、型付けされた検出結果、カバレッジの詳細、スキャンアーティファクトへのパスを返します。長時間のスキャン向けに、 事前チェック、コスト制限、進行状況コールバック、キャンセルもサポートしています。
SDK は ECMAScript modules(ESM)を使用し、Node.js 24 または 26、あるいは 22.13.0 以降の Node.js 22 でサーバー側で動作します。スキャンには Python 3.10 以降も必要です。
Python 3.10 では、tomli パッケージも必要です。
SDK をセットアップする
SDK をインストールします。
npm install @openai/codex-securityスキャンを開始する前に、OPENAI_API_KEY または CODEX_API_KEY を設定するか、
既存のファイルベースの Codex サインインを使用するか、別のプロバイダーを設定します。Amazon Bedrock は AWS の認証情報を使用します。OpenRouter と Fireworks は、プロバイダー固有の API key と設定を使用します。
最良の結果を得るには、Trusted Access for Cyber の認証を受けたアカウントを使用してください。サインインや API key の提供だけでは、 Trusted Access は付与されません。
スキャンを実行する
SDK はローカルのオペレーティングシステムの権限で実行され、承認を求めて一時停止することはありません。スキャンプロセスは環境を継承する場合があるため、無関係な認証情報を開始前に削除してください。ローカルスキャンの権限を参照してください。
この例を scan.mjs として保存します。パスを置き換えて標準リポジトリスキャンを実行し、作業が完了したらクライアントを閉じます。outputDir を渡して、包含する Git ワークツリーの外部にある非公開の結果ディレクトリを指定してください。
outputDir を省略すると、Codex Security は独自の永続状態ディレクトリに結果を保存します。結果にはソースコードの抜粋や脆弱性の詳細が含まれる場合があります。閲覧できるユーザーと保存期間を設定してください。
const security = new CodexSecurity();
try {
const result = await security.run("/path/to/repository", {
outputDir: "/path/outside/repository/results",
});
console.log(result.reportPath);
console.log(result.manifest.scan.status);
console.log(result.findings.findings.length);
} finally {
await security.close();
}Node.js で実行します。
node scan.mjsこの例は、レポートのパス、スキャンステータス、指摘事項の件数を出力します。レポートを開いて証拠を確認してください。件数はリポジトリやスキャンによって異なるため、想定件数を使って連携が機能しているかを確認しないでください。
run は保存された成果物を検証し、ScanResult を返します。その条件は、
result.manifest.scan.status が "completed" であることです。result.coverage で、レビュー済みの対象領域、除外項目、保留された作業を確認してください。完了したスキャンにも、カバレッジの不足が残る場合があります。ランタイム、入力、結果の整合性に関する問題があると、
エラーがスローされる場合があります。
以降の例では、開いている security クライアントを再利用し、close() を
finally 内に残してランタイムを解放します。追加のインポートは、
scan.mjs の先頭に記述してください。
事前チェックで入力を確認する
スキャンを開始する前に、preflight を使用して、リポジトリ、対象、モード、ナレッジベース文書、
出力先、Codex 設定を確認します。
const plan = await security.preflight("/path/to/repository", {
target: ["services/billing", "packages/auth"],
knowledgeBasePaths: ["/path/to/architecture.md"],
outputDir: "/path/outside/repository/results",
});
console.log(plan.repository);
console.log(plan.target.kind);
console.log(plan.mode);
console.log(plan.outputDir);プリフライトは、Codex の起動、認証情報の読み込み、 Python やプラグインの利用可否の確認を行わずに、ローカルの入力をチェックします。プリフライトが成功しても、スキャンの認証や起動が可能であることを保証するものではありません。
既存の結果ディレクトリのアーカイブをプレビューするには、
archiveExisting: true を設定します。
const plan = await security.preflight("/path/to/repository", {
outputDir: "/path/outside/repository/results",
archiveExisting: true,
});
console.log(plan.archiveDir);返される archiveDir は、アーカイブ名をプレビューしたものです。run は独自の一意な保存先を生成するため、最終的なパスは異なる場合があります。実際のアーカイブパスは onOutputArchived で取得します。
await security.run("/path/to/repository", {
outputDir: "/path/outside/repository/results",
archiveExisting: true,
onOutputArchived(archiveDir) {
console.log("Archived results:", archiveDir);
},
});スキャンは以前の結果をアーカイブし、空の出力ディレクトリで開始します。
スキャン対象を選択する
SDK は、リポジトリ、パス、コミット済みの差分、作業ツリー を対象としてサポートします。 デフォルトの対象はリポジトリ全体です。
選択したパスをスキャンする
リポジトリ内のパスを配列として渡します。
const result = await security.run("/path/to/repository", {
target: ["services/billing", "packages/auth"],
});パスにはファイルまたはディレクトリを指定できます。SDK は各パスをリポジトリ内で解決し、 重複を削除します。
コミット済みの変更をスキャンする
ローカルで利用できる 2 つの Git リビジョン間の コミット済み変更をスキャンするには、
DiffTarget.refs を使用します。
const target = DiffTarget.refs({
base: "origin/main",
head: "HEAD",
});
const result = await security.run("/path/to/repository", { target });head のデフォルトは HEAD です。差分を対象とする場合は、リポジトリ引数に
Git ワークツリー のルートを指定する必要があります。
作業ツリー をスキャンする
base リビジョンを基準に、ステージ済みおよび未ステージ の変更をスキャンするには、
DiffTarget.workingTree を使用します。
const target = DiffTarget.workingTree({ base: "HEAD" });
const result = await security.run("/path/to/repository", { target });base のデフォルトは HEAD です。差分または 作業ツリー のスキャンを開始する前に、
選択したリビジョンを取得してください。
deep モードを選択する
より広範なレビューが必要なリポジトリまたはパスのスキャンでは、mode: "deep" を設定します。
const result = await security.run("/path/to/repository", {
target: ["services/billing"],
mode: "deep",
workers: 2,
subagents: 0,
stopAfterNoNew: 3,
maxDiscoveryRuns: 10,
maxTimeHours: 1.5,
});deep モードはリポジトリとパスを対象としてサポートします。差分および作業ツリー のスキャンでは standard モードを使用してください。オプション設定では、同時に実行する独立した
standard スキャンワーカー数、ワーカーごとのサブエージェント数、新しい検出結果がない状態で連続して完了できるワーカースキャン数、ワーカー実行の合計回数と実行時間を制御します。これらには
mode: "deep" が必要です。
maxTimeHours のデフォルトは 96 で、96 以下の正の数値を指定できます。時間は小数でも指定できます。期限に達すると、Codex Security は未完了のワーカーを停止し、完了したスキャン結果を保持して、最終レポートに集約します。保留された作業や未解決の疑問点は result.coverage で確認してください。
セキュリティナレッジベースを追加する
アーキテクチャ文書、脅威モデル、セキュリティポリシーを
knowledgeBasePaths で渡します。
const result = await security.run("/path/to/repository", {
knowledgeBasePaths: [
"/path/to/architecture.md",
"/path/to/security-policies",
],
});SDK はファイルまたはディレクトリを受け付け、ディレクトリを再帰的に検索します。
サポートされる文書形式は、.md、.markdown、.txt、.pdf、.docx です。
SDK はリンクされた入力パスを拒否し、リンクされたディレクトリエントリをスキップして、
抽出した文書の内容を保存済みのスキャン結果には含めません。
スキャンとフォローアップの指示を追加する
スキャンの焦点を絞るには scanPrompt、フォローアップを依頼するには postScanPrompt を使用します。
const result = await security.run("/path/to/repository", {
scanPrompt: "Focus on tenant isolation and authorization checks.",
postScanPrompt: "Write confirmed findings to post-scan-summary.md.",
});フォローアップが失敗した場合、SDK は完了済みのスキャンを保持し、
onWarning を通じてエラーを報告します。また、フォローアップによって変更された完了済みのスキャンアーティファクトを復元します。
スキャン予算を設定する
推定モデルコストが上限を超えたときにスキャンを停止するには、maxCostUsd を設定します。
スキャン実行中のコストを追跡するには、onCost を使用します。
const result = await security.run("/path/to/repository", {
maxCostUsd: 5,
onCost(cost) {
console.log(cost.estimatedUsd);
},
});
console.log(result.cost?.estimatedUsd);この制限は支出の見積もりであり、厳密な上限ではないため、すでに実行中のリクエストは上限をわずかに超えて完了する場合があります。
Codex Security が完了したワーカーの結果を集約した後にディープスキャンが上限に達した場合、run は
manifest.scan.status が "completed" に設定された結果を返し、予算に関する警告を
onWarning 経由で通知できます。未完了の作業は result.coverage で確認してください。
スキャンが有効な完了結果を生成できない場合、run は
ScanCostLimitExceededError をスローし、利用可能な出力をすべて保持します。
スキャン結果を操作する
ScanResult は、構造化された文書、スキャンメタデータ、アーティファクトのパスを公開します。
| プロパティ | 内容 |
|---|---|
manifest |
対象、範囲、生成元、成果物の記録を含む、確定済みのスキャンマニフェスト。 |
findings |
現在のスキャンの指摘事項。指摘事項のオブジェクトは findings.findings から読み取ります。 |
repositoryFindings |
スキャン履歴が利用可能な場合の、リポジトリのスキャン全体にわたる未解決の指摘事項。 |
coverage |
レビュー済みの対象領域、除外項目、保留された作業、未解決の疑問点。 |
scanDir |
スキャンディレクトリ。 |
threadId |
スキャンの Codex スレッド識別子。 |
turnResult |
ターンのステータス、応答、利用可能な使用量メタデータ。 |
cost |
モデルとトークンの推定費用。利用できない場合は null。 |
reportPath |
report.md へのパス。 |
manifestPath |
scan-manifest.json へのパス。 |
findingsPath |
findings.json へのパス。 |
coveragePath |
coverage.json へのパス。 |
artifactsDir |
補助成果物のディレクトリ。 |
sarifPath |
生成された SARIF のパス。SARIF が存在しない場合は null。 |
pluginVersion |
スキャンの生成元によって記録されたバージョン。 |
後続のスキャンで同じプラグインを必須にするには、
expectedPluginVersion: result.pluginVersion を渡します。インストール済みのプラグインのバージョンが異なる場合、SDK はスキャンを拒否します。
構造化された検出結果とカバレッジを直接使用します。
for (const finding of result.findings.findings) {
const location = finding.locations[0];
if (location === undefined) continue;
console.log(
finding.severity.level,
`${location.path}:${location.startLine}`,
finding.title
);
}
for (const deferred of result.coverage.deferred) {
console.log(deferred.id, deferred.reason);
}検出結果には、オプションの codeEvidence、rootCause、validation、
attackPath、remediationTests、preventiveControls フィールドが含まれる場合があります。
リポジトリ全体の検出結果では、confirmedInLatestScan によって、
最新のスキャンで検出されたものと、以前から未解決のまま残っているものを区別できます。
for (const finding of result.repositoryFindings ?? []) {
console.log(finding.title, finding.confirmedInLatestScan);
}新しい結果には coverage.completeness は含まれません。manifest.scan.status を使用して実行ステータスを確認し、保留された対象領域、除外項目、未解決の疑問点を coverage で確認して、スキャンがレビューした範囲を把握してください。
result.toJSON() は、マニフェスト、リポジトリおよび現在のスキャンの検出結果、
カバレッジ、スキャンとスレッドの識別子、reportPath、artifactsDir、
sarifPath、コスト、ターンメタデータを、JSON に変換できる 1 つのオブジェクトとして返します。
スキャンを追跡またはキャンセルする
スキャンの開始、ワーカーの進行状況、接続の再試行を報告するには、
ScanOptions コールバックを渡します。
const result = await security.run("/path/to/repository", {
outputDir: "/path/outside/repository/results",
onScanStarted() {
console.log("Scan started");
},
onProgress(progress) {
console.log(progress.phase, progress.filesCompleted, progress.filesTotal);
},
onWorkerStatus(status) {
console.log(status.kind, status);
},
onSessionEvent(session) {
console.log(session.threadId, session.worker, session.event["type"]);
},
onReconnect(attempt, maxAttempts) {
console.log(`Reconnect attempt ${attempt} of ${maxAttempts}`);
},
onObserverError(observer, error) {
console.error(`${observer} failed`, error);
},
});
console.log(result.reportPath);リクエストまたはジョブコントローラーから AbortSignal を渡して、スキャンをキャンセルします。この例では、30 分経過してもスキャンが実行中の場合に中断し、保存済みの出力が格納されているディレクトリを出力します。
try {
await security.run("/path/to/repository", {
outputDir: "/path/outside/repository/results",
signal: AbortSignal.timeout(30 * 60 * 1000),
});
} catch (error) {
if (error instanceof ScanInterruptedError) {
console.error(error.scanDir);
} else {
throw error;
}
}中断されたスキャンでは、scanDir に部分的な出力が残る場合があります。結果の調査が必要な場合は、そのディレクトリを保持してください。
スキャンのセットアップ進捗を表示するアプリケーションでは、ScanOptions
ライフサイクルコールバックも使用できます。
| コールバック | 呼び出されるタイミング |
|---|---|
onAuthentication(authentication) |
スキャンで認証方法が選択されたとき。 |
onOutputArchived(archiveDir) |
既存の結果がアーカイブディレクトリに移動されたとき。 |
onOutputDirReady(scanDir) |
非公開のスキャンディレクトリの準備が整ったとき。 |
onScanStarted() |
スキャンのセットアップが完了し、実行が開始されたとき。 |
onTrustedAccessStatus(status) |
Trusted Access のステータスを利用できるようになったとき。 |
onReconnect(attempt, maxAttempts) |
切断されたスキャンストリームを SDK が再試行するとき。 |
onActivity(activity) |
コマンド、ツール、推論ステップ、メッセージが更新されたとき。 |
onProgress(progress) |
スキャンフェーズまたはレビュー済みファイル数が変化したとき。 |
onWorkerStatus(status) |
ワーカーの事前チェックまたはディスパッチのステータスが変化したとき。 |
onSessionEvent(session) |
スキャンまたはワーカーセッションがイベントを発行したとき。 |
onCost(cost) |
更新された推定スキャンコストを利用できるようになったとき。 |
onWarning(warning) |
スキャンが警告を報告したとき。 |
onObserverError(observer, error) |
別のスキャンライフサイクルコールバックでエラーが発生したとき。 |
Trusted Access のステータスは、granted、not_granted、unknown のいずれかです。アクセスがない場合や不明な場合にも、onWarning がトリガーされます。
onSessionEvent は編集されていないイベントを受け取るため、ソースコードや認証情報が含まれる可能性があります。共有ログやほかのサービスに送信する前にフィルタリングしてください。
ランタイムと認証情報を設定する
特定のプラグイン、インタープリター、または Codex の設定が必要な場合は、ランタイム設定を渡します。使用する認証情報でアクセスできるモデルを選んでください。ChatGPT サインインを使用する場合は、GPT-6.1 Sol の利用可否を確認してから、 次の例を使用してください。
const security = new CodexSecurity({
pluginPath: "/path/to/codex-security-plugin",
pythonPath: "/path/to/python",
codexOverrides: {
model: "gpt-6.1-sol",
model_reasoning_effort: "medium",
},
});pluginPath はプラグインのディレクトリまたは ZIP を受け付けます。pythonPath はプラグインのインタープリターを選択します。codexOverrides は、サポートされる値を分離された
Codex 設定にマージします。スキャンでは、デフォルトで extra-high の推論エフォート を指定した
gpt-5.6-sol を使用します。別のモデルまたは推論エフォート を使用するには、codexOverrides で
model と model_reasoning_effort を設定します。Amazon
Bedrock を使用するには、
codexOverrides で model_provider と model を設定します。
codexOverrides では、スキャンのファイルシステムアクセスを制限したり、
承認ポリシーを変更したりできません。ローカルスキャンの権限を参照してください。
OpenRouter または Fireworks では、対応する API key と完全なプロバイダー設定も codexOverrides に指定します。たとえば、
OPENROUTER_API_KEY を設定し、OpenRouter を構成します。
const security = new CodexSecurity({
codexOverrides: {
model: "anthropic/claude-sonnet-4.5",
model_provider: "openrouter",
model_providers: {
openrouter: {
name: "OpenRouter",
base_url: "https://openrouter.ai/api/v1",
env_key: "OPENROUTER_API_KEY",
wire_api: "responses",
},
},
},
});Fireworks の場合は、両方の openrouter キーを fireworks に変更し、name を
Fireworks AI に、env_key を FIREWORKS_API_KEY に設定します。また、
https://api.fireworks.ai/inference/v1 を base_url として使用し、Fireworks のモデルを選択します。
クライアントは、サポートされる認証方法も公開しています。
| メソッド | 用途 |
|---|---|
loginApiKey(apiKey) |
API key で分離されたランタイムを認証します。 |
loginChatGPT() |
ブラウザーのサインインフローを開始し、ログインハンドルを返します。 |
loginChatGPTDeviceCode() |
デバイスコードのサインインフローを開始し、ログインハンドルを返します。 |
account() |
現在の認証状態を返します。 |
logout() |
分離された認証をクリアします。 |
ログインハンドルは、waitForInstructions、authUrl、verificationUrl、
userCode、wait、cancel を提供し、アプリケーションが選択されたサインインフローを提示して完了できるようにします。SDK は、ファイルに保存された Codex のサインインを再利用できます。API key は
CI とサーバー側の自動化に使用してください。
API key と保存済みのサインインの両方を利用できる場合、SDK はデフォルトで API key を使用します。代わりに ChatGPT のサインインを使用するには、スキャン用に選択します。
const result = await security.run("/path/to/repository", {
auth: "chatgpt",
});環境変数の API key を必須にするには、auth: "api-key" を設定します。preflight は同じ auth オプションを受け付けます。
スキャンエラーを処理する
アプリケーションで実行可能な対応に合った、エクスポート済みのエラークラスを catch します。
| エラー | 意味 |
|---|---|
AuthenticationRequiredError |
スキャンにサポート対象の認証情報が必要です。 |
ConfigurationError |
Codex 設定またはオーバーライドが適切ではありません。 |
InvalidTargetError |
リポジトリ、パス、モード、または Git の対象が適切ではありません。 |
OutputDirectoryError |
出力先またはその権限が適切ではありません。 |
OutputInsideProtectedRootError |
出力ディレクトリがスキャン対象のリポジトリまたは ワークツリー内にあります。 |
PluginPythonUnavailableError |
使用可能な Python インタープリターがありません。 |
PluginBootstrapError |
プラグインランタイムを起動できませんでした。 |
ScanCostLimitExceededError |
スキャンが推定コスト上限を超えました。 |
IncompleteScanError |
必要な結果を生成する前にスキャンが終了しました。 |
ContractValidationError |
完了したスキャンが構造化契約エラーを返しました。 |
ScanInterruptedError |
中断によってスキャンが停止し、部分的な出力が残っている可能性があります。 |
続いて、CLI クイックスタート、CI ガイド、または CLI リファレンスを参照してください。