Codex Security TypeScript SDK
TypeScript에서 Codex Security 스캔을 실행하고, 대상과 제공업체를 선택하고, 결과를 검사하고, 스캔 수명 주기를 관리합니다.
Codex Security TypeScript SDK를 사용하여 애플리케이션 또는 개발자 도구에서 리포지토리와 코드 변경 사항에 대한 보안 스캔을 실행하세요. SDK는 형식이 지정된 발견 항목, 커버리지 세부 정보 및 스캔 아티팩트 경로를 반환합니다. 장시간 스캔을 위해 사전 검사, 비용 한도, 진행 상황 콜백 및 취소도 지원합니다.
SDK는 ECMAScript 모듈(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은 저장된 아티팩트를 검증하고
result.manifest.scan.status가 "completed"이면 ScanResult를 반환합니다. 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는 리포지토리, 경로, 커밋된 diff 및 작업 트리 대상을 지원합니다. 기본 대상은 전체 리포지토리입니다.
선택한 경로 스캔하기
리포지토리 내부 경로의 배열을 전달하세요.
const result = await security.run("/path/to/repository", {
target: ["services/billing", "packages/auth"],
});경로는 파일 또는 디렉터리를 지정할 수 있습니다. SDK는 각 경로를 리포지토리 내부에서 해석하고 중복을 제거합니다.
커밋된 변경 사항 스캔하기
DiffTarget.refs를 사용하여 로컬에서 사용할 수 있는 두 Git 리비전 사이의
커밋된 변경 사항을 스캔하세요.
const target = DiffTarget.refs({
base: "origin/main",
head: "HEAD",
});
const result = await security.run("/path/to/repository", { target });헤드의 기본값은 HEAD입니다. Diff 대상에서는 리포지토리 인수가
Git 작업 트리 루트여야 합니다.
작업 트리 스캔하기
DiffTarget.workingTree를 사용하여 기준 리비전을 상대로 스테이징된 변경 사항과
스테이징되지 않은 변경 사항을 스캔하세요.
const target = DiffTarget.workingTree({ base: "HEAD" });
const result = await security.run("/path/to/repository", { target });기준의 기본값은 HEAD입니다. diff 또는 작업 트리 스캔을 시작하기 전에
선택한 리비전을 가져오세요.
심층 모드 선택하기
더 폭넓은 검토가 필요한 리포지토리 또는 경로 스캔에는
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,
});심층 모드는 리포지토리와 경로 대상을 지원합니다. diff 및 작업 트리
스캔에는 표준 모드를 사용하세요. 선택적 설정은 동시에 실행되는 독립적인
표준 스캔 작업자 수, 작업자당 하위 에이전트 수, 새로운 발견 항목 없이
연속으로 완료되는 작업자 스캔 수, 작업자 실행의 총 횟수와 기간을 제어합니다. 이 설정에는
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 지원 객체로 반환합니다.
스캔 추적 또는 취소하기
스캔 시작, 작업자 진행 상황 및 연결 재시도를 보고하려면
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 |
중단으로 스캔이 정지되었으며 부분 출력이 남았을 수 있습니다. |