프로젝트
프로젝트는 포털이 인지하는 소스 추적 단위입니다. 스캔, 컴포넌트, 취약점, 라이선스 결과, 의무사항, 자동 생성된 NOTICE 파일을 보유합니다. 대부분의 워크플로우는 프로젝트 추가에서 시작합니다.
자체 서비스를 스캔하는 엔지니어와 팀 리드. 로그인 필요. 생성·아카이브는 프로젝트 소속 팀의 developer 이상, 가시성 변경은 team_admin 권한이 필요합니다.
프로젝트 구성 요소
| 필드 | 설명 |
|---|---|
| 이름 (Name) | 표시용 라벨(자유 텍스트). 유일할 필요는 없습니다 — 같은 팀의 두 프로젝트가 이름을 공유할 수 있고, 유일 키는 슬러그입니다. |
| 슬러그 (Slug) | URL-safe 식별자([a-z0-9-]+). 팀 내에서 유일하며, 중복 슬러그는 409로 거부됩니다. |
| 설명 (Description) | 선택. 프로젝트 목록과 Overview 탭에 노출되는 자유 텍스트 요약. |
| Git URL | 스캔 파이프라인이 클론할 git URL. HTTPS 지원. 사설 저장소는 URL에 자격증명을 포함해야 합니다 — 사설 저장소를 보세요. |
| 기본 브랜치 (Default branch) | 스캔 파이프라인이 체크아웃할 브랜치(기본값 main). 생성 후 Project Settings에서 수정. |
| 가시성 (Visibility) | team (v0.10.0 시점에서 허용되는 유일한 값 — 소속 팀 멤버만 조회). 생성 시 자동 설정되며 PATCH로만 변경 가능. |
| 소속 팀 (Owning team) | 프로젝트가 속한 팀. 글로벌 바에서 선택한 팀이 기본값이며, 여러 팀에 속해 있으면 생성 폼에서 바꿀 수 있습니다. |
프로젝트 추가 — UI
사이드바의 Projects 항목은 프로젝트 목록을 보여줍니다 — 소속 팀으로 닿는 모든 프로젝트, 상태 배지, severity 카운트, 인라인 Scan 액션, 그리고 n scans · m releases · last scan <상대 시간> 형식의 프로젝트별 컴팩트 메타 행:

메타 행 집계:
- scans — 프로젝트가 누적 실행한 스캔 총 개수(모든 상태, 아카이브된 실행 포함).
- releases — 프로젝트가 누적한 릴리스 스냅샷 수(릴리스 참고).
- last scan — 마지막 스캔이 종단 상태에 도달한 이후의 상대 시간. 첫 스캔이 완료되기 전까지는
—.
목록 엔드포인트가 세 필드를 한 번의 쿼리로 서버 측에서 집계하므로, 수백 개 프로젝트 포트폴리오에서도 행 렌더링 비용이 낮습니다.
-
로그인.
-
사이드바의 Projects 클릭.
-
우측 상단 New project 클릭.
-
폼 작성:
- 이름 (필수)
- 설명 (선택)
- Git URL (소스 스캔에 필수)
-
Create 클릭.

프로젝트의 Overview 탭으로 이동합니다. 여기서 첫 스캔을 실행할 수 있습니다 — 스캔 참고.

기본 브랜치(main), 가시성(team), 소속 팀(글로벌 바에서 선택한 팀)은 서버에서 자동 설정되며 Project Settings에서 확인 가능합니다.
프로젝트 상세 탭 구성
상세 페이지의 탭은 왼쪽→오른쪽 순서로 다음과 같습니다.
| 탭 | 보여주는 내용 |
|---|---|
| Overview | 리스크 두 축(Security + License), 빌드 게이트 판정, Project info 카드(Git URL, default branch, 소속 팀, 생성 시각, 마지막 스캔 시각), 최근 스캔. |
| Releases | 종단 스캔별 프로젝트 스냅샷 — 스냅샷 목록, "View snapshot" 핀 액션, 릴리스 간 diff 진입점. Releases 탭 참고. |
| Components | 스캔이 발견한 모든 컴포넌트. 컴포넌트·라이선스 참고. |
| Vulnerabilities | 열린/트리아지된 CVE 결과. 취약점 참고. |
| Licenses | 같은 데이터를 SPDX 식별자·티어 기준으로 본 뷰. |
| Obligations | 컴포넌트별 의무사항 + NOTICE 파일 생성. 컴포넌트·라이선스 → 의무사항 참고. |
| SBOM | CycloneDX / SPDX 익스포트, byte-stable. SBOM 참고. |
| Reports | NOTICE / SBOM / Vuln-PDF / VEX 생성 카드 + 프로젝트의 통합 다운로드·익스포트 이력. Reports 탭 참고. |
| Source | 최근 성공한 스캔에서 fetch 된 first-party 소스 트리. 파일 단위 라이선스 결과 하이라이팅. 탭 재정렬로 Reports 와 Remediation 사이로 이동. |
| Remediation | 최근 스캔 기준 컴포넌트별 업그레이드 권고. 선택적 npm 자동 PR 플로 포함. |
| Settings | 프로젝트 메타데이터, 아카이브 액션, CI 연동 헬퍼. |
Source 탭은 이전에 Licenses 바로 뒤에 있었으나, 데이터 출력 클러스터(SBOM / Reports / Source) 가 연속되도록 Reports 오른쪽으로 이동했습니다. 북마크와 ?tab=source 딥링크는 슬러그가 동일하므로 계속 동작합니다.
프로젝트 추가 — API
curl -sS -X POST https://trustedoss.example.com/v1/projects \
-H "Authorization: Bearer ${TRUSTEDOSS_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"team_id": "8f0c1e2a-...팀 UUID...",
"name": "checkout-service",
"slug": "checkout-service",
"description": "Storefront checkout service",
"git_url": "https://github.com/acme/checkout-service.git"
}' | jq .
응답에 프로젝트 UUID가 포함됩니다 — GitHub Action의 project-id 입력값과 GitLab CI 변수에 사용하므로 보관하세요.
필수 필드: team_id, name, slug. 선택: description, git_url, default_branch, visibility. 스키마는 알 수 없는 필드를 거부합니다(extra="forbid"). team_id나 slug를 빠뜨리면 422(missing: body.team_id)가 반환됩니다.
team_id 찾기: UI의 프로젝트 생성 폼에는 팀 선택기가 있어 UUID를 직접 입력할 필요가 없습니다. API에서는 로그인한 모든 사용자가 GET /auth/me로 자기 팀을 읽습니다(auth 라우터는 /v1이 아니라 /auth에 마운트됩니다) — 응답의 memberships[] 배열 각 항목에 team_id·team_name과 해당 팀에서의 role이 담깁니다. (GET /v1/admin/teams도 팀 목록을 주지만 super-admin 전용이라 team_admin이 호출하면 404입니다.) 이번 릴리스에서 team_id는 세션에서 도출되지 않으며 요청 본문에 담아야 합니다.
가시성
team(v0.10.0 기본값이자 유일하게 허용되는 값) — 소속 팀 멤버만 프로젝트·스캔·결과를 볼 수 있습니다.
가시성은 생성 시 자동으로 설정됩니다. PATCH는 현재 team 외의 값을 거부합니다. 모든 PATCH 호출에서 감사 로그가 행위자를 기록합니다.
organization(조직 전체 읽기) 가용 시점은 로드맵 참고.
아카이브
- 아카이브 — 프로젝트와 그 이력·스캔·결과는 유지하되 기본 목록에서 숨기고 새 스캔을 막습니다. 서비스가 종료되었지만 컴플라이언스 추적이 필요한 경우에 유용합니다.
DELETE /v1/projects/{id}는 soft-delete(아카이브)를 수행합니다. 영구 삭제 동작은 현재 노출되지 않으며, 감사 로그 항목은 어떤 경우에도 유지됩니다.
아카이브 동작은 Project Settings → Archive에 있으며, 사고 방지를 위해 인라인 확인 스트립을 사용합니다.
사설 저장소
소스 스캔은 워커 컨테이너 안에서 저장소를 클론합니다. 현재 릴리스에서 지원되는 인증 옵션:
- HTTPS + Personal Access Token — URL을
https://<token>@github.com/acme/checkout-service.git형태로 설정. 토큰은git_url의 일부로 저장되며, 읽기 엔드포인트가 평문으로 반환하지 않습니다.
현재 지원되는 자격증명 모델은 git URL 에 PAT 를 임베드한 HTTPS
(https://<token>@github.com/acme/payment-service.git) 뿐입니다.
PAT 는 프로젝트 행에 영구 저장됩니다(읽기 엔드포인트가 평문 PAT 를
절대 반환하지 않으며, git_url 은 감사 로그에서 마스킹됩니다).
함의:
- 유출된 DB 스냅샷은 임베드된 모든 PAT 를 함께 유출합니다. read-only scope 의 단기 PAT 를 사용하세요.
- SSH key 와 GitHub-App 설치는 로드맵 항목입니다; 그때까지 적극적으로 회전하세요.
SSH 배포 키는 로드맵을 보세요.
거버넌스 밴드
프로젝트 헤더와 탭 사이에 다섯 개 타일이 있습니다. 어느 탭에서 작업하든 프로젝트의 현재 상태를 이동 없이 읽게 하려는 것입니다.
| 타일 | 내용 |
|---|---|
| 리스크 스코어 | Overview 탭의 종합 점수와 같은 계산 — 보안 축과 라이선스 축 중 나쁜 쪽. |
| 빌드 게이트 | 지금 CI 가 내릴 판정: 통과, 차단(차단 건수와 함께, Vulnerabilities 탭으로 이동), 스캔한 적 없음. |
| KEV 기한 | CISA 조치 기한과 대조한 알려진 악용 finding. 기한 초과와 일주일 내로 나뉩니다. |
| 대기 중인 승인 | 이 프로젝트에서 아직 pending·under_review 인 컴포넌트 승인. |
| critical 추이 | 최근 성공한 스캔 몇 회의 critical 수와 그 변화량. 스캔이 두 번 미만이면 선을 그리지 않습니다. 점 하나는 추세가 아닙니다. |
모든 숫자는 제품의 다른 곳에서 그 값을 소유한 서비스가 만듭니다. 밴드가 바로 아래 탭과 다른 값을 말할 수 없다는 뜻입니다. 두 상태는 의도적으로 구분합니다. 성공한 스캔이 없는 프로젝트는 통과가 아니라 "스캔한 적 없음"으로 표시하고, 밴드를 불러오지 못하면 0 을 그리는 대신 실패했다고 밝힙니다. 없는 답이지 안심시키는 답이 아닙니다.
리스크 점수
Overview 탭은 이제 하나의 합산 점수 대신 두 개의 리스크 축을 게이지에 표시합니다. 두 가지 실패 모드를 독립적으로 읽을 수 있도록 분리했습니다.
- Security risk (보안 리스크) — 프로젝트의 열린 취약점 구성에 따라 결정됩니다. 밴드(Critical / High / Medium / Low / Info) 는 가장 심각한 열린 finding 이 정합니다. 밴드 내 점수는
n / (n + 4)로 스케일(비포화 — finding 이 더 많아진다고 밴드를 한 단계 올리지 못함). - License risk (라이선스 리스크) — 프로젝트의 라이선스 티어 구성에 따라 결정됩니다. Forbidden 라이선스가 밴드를 지배. Conditional 행은 밴드 내 점수를 올리지만 단독으로
Critical로 승격하지 않습니다(이전의 "Conditional 컴포넌트 하나라도 있으면 Risk 100" 동작은 W1 에서 제거).
기존 단일 risk_score 필드는 빌드 게이트와 CI 연동의 하위 호환을 위해 API 에서 max(security_axis, license_axis) 로 계속 노출됩니다. UI 는 두 축 분해를 사용합니다.
두 축 모두 매 스캔 후, 그리고 매 CVE 재탐지 후 갱신됩니다. 절대적 SLA 가 아닌 포트폴리오 내 상대 지표로 읽으세요 — 프로젝트로 들어가면 축별 분해도가 보입니다.
W1 이전에 찍은 스크린샷은 단일 게이지("Risk")를 보여줍니다. 두 축 카드가 이를 대체합니다. 옛 단일 점수와 새 두 축 중 어느 쪽도 단순 비교할 수 없으므로, 업그레이드 이후 포트폴리오 기준으로 재설정하세요.