문서/API 및 웹훅/SARIF 통합

SARIF 통합

모든 코드 스캐닝 도구(CodeQL, Semgrep, Snyk, Checkmarx, Trivy, Bandit, GitLab SAST, OWASP ZAP)의 SARIF 출력을 SecureCodingHub로 푸시하세요. run의 고유한 CWE 각각은 커밋 작성자 계정의 과제가 되며 — 일반적으로 머지 후 몇 초 안에 생성됩니다.

왜 CI가 올바른 트리거인가

"모든 개발자가 동일한 OWASP Top 10 과정을 듣는" 일반적인 롤아웃은 완료율이 낮고 유지율은 더 낮습니다. CI 통합은 이 모델을 뒤집습니다: 교육은 문제를 도입한 개발자에게 구체적으로 할당되며, 그들이 필요로 하는 취약성 클래스에 대해 구체적으로 할당되고, 이를 노출한 머지와 연결된 14일 마감일이 있습니다. 그것이 감사관이 말하는 적시 보안 코딩 교육입니다.

엔드 투 엔드 작동 방식

1

SAST 도구가 CI 작업의 일부로 SARIF 2.1.0 파일을 생성합니다.

2

CI 단계가 커밋 메타데이터를 요청 헤더로 사용하여 파일을 /api/public/v1/sarifPOST합니다.

3

SecureCodingHub가 모든 result를 파싱하고, CWE 태그를 추출한 다음, 각각을 내부 CWE-주제 맵에서 조회합니다.

4

각 고유한 매핑된 주제에 대해, 이메일이 X-Commit-Author-Email와 일치하는 사용자에게 14일 마감일로 과제가 생성됩니다.

5

sarif.ingested 웹훅이 동기 응답이 반환하는 것과 동일한 페이로드와 함께 발사됩니다.

엔드포인트

POST /api/public/v1/sarif
Authorization: Bearer scs_live_…
Content-Type: application/json
X-Source: github-codeql
X-Repo: acme/payments-api
X-Branch: main
X-Commit-Sha: 9c2f4b8e0c1d…
X-Commit-Author-Email: jane.smith@acme.com

<SARIF 2.1.0 JSON body, up to 10 MB>

필수 범위: sarif:ingest.

요청 헤더

헤더필수의미
X-Source자유 형식 도구 식별자 — 예: github-codeql, snyk, semgrep-ci. 감사를 위해 기록됩니다.
X-Repo리포지토리 슬러그 (owner/name). 감사를 위해 기록됩니다.
X-Branch브랜치 이름. 감사를 위해 기록됩니다.
X-Commit-Sha권장커밋 해시. 24시간 멱등성을 위해 X-Repo와 함께 사용됩니다.
X-Commit-Author-Email권장커밋 작성자의 이메일. SecureCodingHub 사용자로 해결되며, 과제가 그들에게 첨부됩니다. 이메일이 사용자와 일치하지 않으면 run은 여전히 수집되지만 과제는 생성되지 않습니다.

응답

{
  "ingestionId": "7e4c9d09-86ca-4125-bbd8-7fae54c8f654",
  "findingsCount": 2,
  "uniqueCwes": ["CWE-79", "CWE-89"],
  "unmappedCwes": [],
  "assignmentsCreated": 12,
  "notes": []
}
  • findingsCount — 파싱된 result 항목의 총 수.
  • uniqueCwes — 모든 결과에서 언급된 CWE 집합.
  • unmappedCwes — 주제로 매핑할 수 없었던 CWE. 적용 범위 추가를 원하시면 지원으로 보내주세요.
  • assignmentsCreated — 새 과제 레코드 수(기존 중복은 건너뜁니다).
  • notes — 치명적이지 않은 경고(예: 잘못된 커밋 작성자 이메일 형식).

멱등성

동일한 SARIF 파일을 다시 수집하는 것은 안전합니다. 튜플 (organization, repo, commit_sha)이 멱등성 키입니다 — 24시간 윈도우 내의 중복은 원래 ingestionIdassignmentsCreated: 0와 함께 200를 반환합니다. 이는 동일한 커밋에서 다시 실행되는 CI 워크플로(리베이스, 수동 재실행, PR에 푸시)가 중복 과제를 쌓지 않음을 의미합니다.

GitHub Actions 예시

CodeQL 또는 Semgrep 작업이 results.sarif를 생성한 후 워크플로에 이 단계를 추가하세요:

- name: Send SARIF to SecureCodingHub
  if: always()
  run: |
    curl -sS -f -X POST \
      -H "Authorization: Bearer $SCH_API_KEY" \
      -H "Content-Type: application/json" \
      -H "X-Source: github-codeql" \
      -H "X-Repo: ${{ github.repository }}" \
      -H "X-Branch: ${{ github.ref_name }}" \
      -H "X-Commit-Sha: ${{ github.sha }}" \
      -H "X-Commit-Author-Email: ${{ github.event.head_commit.author.email }}" \
      --data-binary @results.sarif \
      https://api.limeplate.com/api/public/v1/sarif
  env:
    SCH_API_KEY: ${{ secrets.SCH_API_KEY }}

키를 리포지토리 또는 조직 시크릿에 저장하세요. if: always() 가드는 보안 작업이 빌드를 실패로 표시했더라도 결과가 전송되도록 보장합니다 — 이때가 교육 과제가 가장 발사되기를 원하는 시점입니다.

GitLab CI 예시

send_sarif_to_sch:
  stage: post-security
  image: curlimages/curl:latest
  needs: ["sast"]
  script:
    - >
      curl -sS -f -X POST
      -H "Authorization: Bearer $SCH_API_KEY"
      -H "Content-Type: application/json"
      -H "X-Source: gitlab-sast"
      -H "X-Repo: $CI_PROJECT_PATH"
      -H "X-Branch: $CI_COMMIT_BRANCH"
      -H "X-Commit-Sha: $CI_COMMIT_SHA"
      -H "X-Commit-Author-Email: $GITLAB_USER_EMAIL"
      --data-binary @gl-sast-report.json
      https://api.limeplate.com/api/public/v1/sarif
  rules:
    - if: $CI_COMMIT_BRANCH

GitLab SAST 보고서는 SARIF와 호환됩니다 — 변환이 필요하지 않습니다.

Semgrep 예시

semgrep ci --sarif --output results.sarif
curl -sS -f -X POST \
  -H "Authorization: Bearer $SCH_API_KEY" \
  -H "X-Source: semgrep" \
  -H "X-Repo: $REPO" \
  -H "X-Commit-Sha: $COMMIT" \
  -H "X-Commit-Author-Email: $AUTHOR_EMAIL" \
  --data-binary @results.sarif \
  https://api.limeplate.com/api/public/v1/sarif

CWE 적용 범위

SecureCodingHub는 현재 OWASP Top 10, OWASP API Security Top 10, OWASP Mobile Top 10 및 CWE Top 25를 교육 주제에 매핑합니다. 해당 집합 외부의 CWE ID로 태그된 결과는 응답의 unmappedCwes 목록에 나타납니다. SARIF 태그 측에서 허용하는 일반적인 형식:

  • external/cwe/cwe-89 (CodeQL 표준)
  • cwe-89
  • CWE-89
  • cwe:89

태그는 result.properties.tags와 해당하는 tool.driver.rules[].properties.tags 모두에서 읽힙니다.

본문 크기 상한

SARIF 엔드포인트는 압축되지 않은 최대 10 MB까지의 페이로드를 허용합니다. 단일 리포지토리에 대한 대부분의 실제 SAST 보고서는 이 한도보다 훨씬 적습니다. 한도를 초과하는 엔터프라이즈 규모의 monorepo 보고서가 있다면, 도구 드라이버별로 분할(드라이버당 하나의 SARIF run)하고 각 부분을 POST하세요 — 동일한 커밋 SHA 아래에서 멱등적입니다.

실패 모드

증상가능한 원인
assignmentsCreated: 0와 함께 200커밋 작성자 이메일이 조직의 사용자가 아니거나, 모든 CWE가 이미 할당되었습니다.
비어 있지 않은 unmappedCwes와 함께 200결과가 아직 교육 주제가 없는 CWE를 참조합니다. 목록을 지원팀으로 전달하세요.
400 empty_bodyCurl이 --data-binary @file.sarif를 누락했습니다.
413 body_too_largeSARIF가 10 MB를 초과합니다. 드라이버별로 분할하세요.
idempotency:로 시작하는 notes 항목과 함께 200동일한 (repo, commit)이 24시간 이내에 이미 수집되었습니다. 응답은 그 외에는 assignmentsCreated: 0와 함께 새 수집과 동일합니다 — 무시해도 안전합니다.