Documentation
¶
Index ¶
- Constants
- Variables
- func AppAccessURL(appName, accessDomain string) string
- func DependencyScanResultID(deploymentID string) string
- func IsDBStale(updatedAt *time.Time, now time.Time) bool
- func MatchStackCluster(stackClusterID, requested string) (string, error)
- func SASTDashboardURL(webBase, projectKey, reported string) string
- func SASTResultID(deploymentID string) string
- func SecretScanResultID(deploymentID string) string
- type AppType
- type BuildProfile
- type CICDGoldenPath
- type CICDTool
- type DependencyScanResult
- type DeployStep
- type Deployment
- type DeploymentStatus
- type GateResult
- func EvaluateGate(s *TrivyReportSummary, policy ScanPolicy) GateResult
- func GateFromStageAndReport(stageStatus string, report *TrivyReportSummary, policy ScanPolicy) (GateResult, bool)
- func GateResultFromStageStatus(status string) (GateResult, bool)
- func GateWhenReportMissing(stageStatus string) (GateResult, bool)
- func SASTGateFromStageAndReport(stageStatus string, r *SASTReport) (GateResult, bool)
- func SecretScanGate(stageStatus string, findings *int, policy ScanPolicy) (GateResult, bool)
- type ImageScanResult
- type Pipeline
- type PipelineSecurityList
- type PipelineSecuritySnapshot
- type PipelineStatus
- type PipelineTemplate
- type QualityGateStatus
- type RunSummary
- type SASTCondition
- type SASTGateAction
- type SASTMetrics
- type SASTReport
- type SASTResult
- type ScanPolicy
- type ScanReportRef
- type SecretDetectionAction
- type SecretFinding
- type SecretRuleCount
- type SecretScanReport
- type SecretScanResult
- type Severity
- type SeverityCounts
- type TemplateSource
- type TrivyReportSummary
- type UnreachableAction
Constants ¶
const ( // ExecutionModeStackIntegrated 는 스택의 컴포넌트가 실행을 맡는 일반 경로다. // CI 플랫폼이 빌드해 이미지 레지스트리에 올리고, CD 도구가 클러스터에 반영한다. ExecutionModeStackIntegrated = "stack_integrated" // ExecutionModeEmergencyDirect 는 스택 컴포넌트를 쓸 수 없을 때 플랫폼이 // 직접 빌드·배포하는 장애 대응 경로다. ExecutionModeEmergencyDirect = "emergency_direct" )
실행 모드. 어느 쪽이 이미지를 만들고 클러스터에 반영하는지를 가른다.
자세한 설계는 docs/20_아키텍처/Stack_CICD_통합모드_설계.md 와 Stack_CICD_긴급모드_설계.md 에 있다.
const MaxStoredSecretFindings = 200
MaxStoredSecretFindings 는 결과 하나에 남기는 탐지 위치의 상한이다. 건수(FindingsCount)와 규칙별 건수는 자르지 않는다 — 오탐 규칙 하나가 수천 건을 내도 행이 커지지 않게 위치만 자른다.
const SecretScanSkippedReport = `{"nullus_skipped":"policy_off"}`
SecretScanSkippedReport 는 스택 정책이 시크릿 탐지를 끈 실행이 남기는 리포트다. 탐지 없음([])과 구별해야 한다 — 같은 [] 를 남기면 나중에 정책을 켠 뒤의 동기화가 그 실행을 "통과" 로 기록한다. 산출물 업로드가 실패하지 않도록 파일은 남긴다. 스캐폴딩(scaffold/secret_scan.go)이 같은 값을 쓴다.
const StaleDBAge = shareddomain.StaleDBAge
StaleDBAge 는 취약점 DB 를 낡았다고 보는 나이다 (설계 §6.4).
Variables ¶
var ErrDeploymentNotFound = fmt.Errorf("deployment not found")
ErrDeploymentNotFound is returned when a deployment cannot be found.
var ErrGoldenPathAlreadyExists = fmt.Errorf("cicd golden path already exists")
ErrGoldenPathAlreadyExists 는 같은 ID 의 골든패스가 이미 있을 때 돌아온다.
var ErrGoldenPathInvalid = fmt.Errorf("cicd golden path invalid")
ErrGoldenPathInvalid 는 골든패스가 저장 규칙을 어길 때 돌아온다. 어느 필드인지는 감싼 메시지에 있다.
var ErrGoldenPathNotFound = fmt.Errorf("cicd golden path not found")
ErrGoldenPathNotFound 는 CI/CD 골든패스를 찾을 수 없을 때 돌아온다.
var ErrInvalidScanPolicy = errors.New("스캔 정책이 올바르지 않습니다")
ErrInvalidScanPolicy 는 정책 값이 허용 범위를 벗어났을 때의 오류다.
var ErrPipelineNotFound = fmt.Errorf("pipeline not found")
ErrPipelineNotFound is returned when a pipeline cannot be found.
var ErrStackClusterMismatch = errors.New("pipeline cluster must be the stack's cluster")
ErrStackClusterMismatch 는 스택에 묶인 앱에 스택과 다른 클러스터를 준 경우다. 스택의 CD 도구(Argo CD)는 자기 클러스터에만 배포하므로, 다른 클러스터는 배포 대상이 될 수 없다.
var ErrTemplateAlreadyExists = fmt.Errorf("pipeline template already exists")
ErrTemplateAlreadyExists 는 같은 ID 의 템플릿이 이미 있을 때 돌아온다.
var ErrTemplateInvalid = fmt.Errorf("pipeline template invalid")
ErrTemplateInvalid 는 템플릿이 저장 규칙을 어길 때 돌아온다. 어느 필드인지는 감싼 메시지에 있다.
var ErrTemplateNotFound = fmt.Errorf("pipeline template not found")
ErrTemplateNotFound is returned when a pipeline template cannot be found.
Functions ¶
func AppAccessURL ¶
AppAccessURL 은 배포된 앱의 외부 접속 주소다.
스캐폴딩이 만드는 HTTPRoute 의 hostname 과 같은 규칙에서 나온다 (scaffold/renderer.go 의 renderHTTPRoute: `<앱>.<도메인>`). 화면이 보여 주는 주소를 따로 적으면 한쪽이 바뀔 때 다른 쪽이 거짓말을 한다.
스택에 접근 도메인이 없으면 앱은 클러스터 안에서만 닿는다. 그때는 빈 값을 돌려준다 — 없는 주소를 지어내면 사용자는 열리지 않는 링크를 계속 누른다.
func DependencyScanResultID ¶ added in v0.6.0
DependencyScanResultID 는 실행 하나에 대응하는 의존성 스캔 결과 ID 다. 같은 실행을 다시 동기화해도 기록이 늘지 않는다.
func MatchStackCluster ¶ added in v0.6.0
MatchStackCluster 는 스택에 묶인 앱의 클러스터를 스택 클러스터와 맞춘다.
요청이 비어 있으면 스택 클러스터로 채우고, 다르면 ErrStackClusterMismatch 로 거절한다 — 조용히 바꾸면 요청한 쪽이 고른 클러스터가 거짓이 된다. 스택 클러스터를 모르면 요청을 그대로 둔다.
func SASTDashboardURL ¶ added in v0.6.0
SASTDashboardURL 은 사람이 열 SonarQube 프로젝트 화면 주소다.
스캐너가 리포트에 남기는 주소는 스캐너가 붙은 서버 주소(클러스터 내 서비스)라 브라우저에서 열리지 않는다 — 서버의 공개 주소 설정(sonar.core.serverBaseURL)이 있어도 그렇다(실측). 스택의 공개 주소(webBase)를 알면 그것으로 만들고, 모르면 리포트 주소를 쓰되 클러스터 안 주소는 버린다. 죽은 링크보다 없는 편이 낫다.
func SASTResultID ¶ added in v0.6.0
SASTResultID 는 실행 하나에 대응하는 분석 결과 ID 다. 같은 실행을 다시 동기화해도 기록이 늘지 않는다.
func SecretScanResultID ¶ added in v0.6.0
SecretScanResultID 는 실행 하나에 대응하는 시크릿 탐지 결과 ID 다.
Types ¶
type BuildProfile ¶ added in v0.6.0
type BuildProfile string
BuildProfile 은 가져온 원본을 어떻게 빌드하고 띄울지다.
원본 Dockerfile 을 그대로 쓸지, 플랫폼이 Dockerfile 을 대신 쓸지, 배포 매니페스트에 어떤 헬스 체크와 자원을 둘지를 한 이름으로 묶는다. 이름별 실제 값은 스캐폴딩 (adapter/scaffold)이 가진다 — 매니페스트 모양은 거기서 정한다.
const ( // BuildProfileRepository 는 원본 Dockerfile 을 그대로 쓰고 배포 설정은 기본값이다. BuildProfileRepository BuildProfile = "" // BuildProfileSpringBoot 는 원본 Dockerfile 을 쓰고, 없으면 플랫폼이 쓴다(Maven 으로 실행 jar → // JRE). JVM 에 맞춘 자원과 헬스 체크를 둔다. eGov 부트 샘플 v5.0.0 에는 Dockerfile 이 없다. BuildProfileSpringBoot BuildProfile = "spring-boot" // BuildProfileMavenWAR 는 플랫폼이 Dockerfile 을 쓴다(Maven 빌드 → Tomcat ROOT.war). // 미리 빌드한 WAR 를 복사하는 원본 Dockerfile 은 CI 의 `docker build .` 로 돌지 않는다. BuildProfileMavenWAR BuildProfile = "maven-war" )
func (BuildProfile) GeneratesDockerfile ¶ added in v0.6.0
func (p BuildProfile) GeneratesDockerfile() bool
GeneratesDockerfile 은 원본에 Dockerfile 이 없을 때 플랫폼이 만들 수 있는지다.
func (BuildProfile) IsValid ¶ added in v0.6.0
func (p BuildProfile) IsValid() bool
IsValid 는 아는 프로필인지 본다.
func (BuildProfile) ReplacesDockerfile ¶ added in v0.6.0
func (p BuildProfile) ReplacesDockerfile() bool
ReplacesDockerfile 은 원본에 Dockerfile 이 있어도 플랫폼 것으로 바꾸는지다.
type CICDGoldenPath ¶
type CICDGoldenPath struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Tools []CICDTool `json:"tools"`
EstimatedInstallTime int `json:"estimated_install_time"` // in minutes
RecommendedUseCase string `json:"recommended_use_case"`
MinResources string `json:"min_resources"`
CreatedAt time.Time `json:"created_at"`
}
CICDGoldenPath represents a verified CI/CD tool combination (Golden Path).
type CICDTool ¶
type CICDTool struct {
Category string `json:"category"` // ci_platform, cd_tool, monitoring, etc.
Name string `json:"name"` // GitLab CI, ArgoCD, Prometheus, etc.
HelmVersion string `json:"helm_version"`
AppVersion string `json:"app_version"`
}
CICDTool represents a tool in the CI/CD stack.
type DependencyScanResult ¶ added in v0.6.0
type DependencyScanResult struct {
ID string `json:"id"`
PipelineID string `json:"pipeline_id"`
DeploymentID string `json:"deployment_id"`
Scanner string `json:"scanner"`
ScannerVersion string `json:"scanner_version,omitempty"`
DBUpdatedAt *time.Time `json:"db_updated_at,omitempty"`
// Counts 는 리포트를 읽었을 때만 있다. nil 은 "모름" 이다 — 0 으로 채우면 "취약점 0건" 으로 읽힌다.
// 스택 정책의 ignore_unfixed 를 따른다(판정이 본 숫자와 같아야 한다).
Counts *SeverityCounts `json:"counts,omitempty"`
// Targets 는 검사한 락파일 수(리포트의 Results 수)다. nil 은 모름, 0 은 검사할 것이 없었다는 뜻이다 —
// 스캐폴딩은 락파일을 만들지 않아 "0 개 검사 · 통과" 가 흔하다(#79 §1). 통과와 가른다.
Targets *int `json:"targets,omitempty"`
GateResult GateResult `json:"gate_result"`
ReportURI string `json:"report_uri,omitempty"`
ScannedAt time.Time `json:"scanned_at"`
// ReportRef 는 CI 리포트를 다시 읽을 위치다. 화면에는 내보내지 않는다.
ReportRef *ScanReportRef `json:"-"`
}
DependencyScanResult 는 실행 하나의 의존성 취약점 스캔(SCA, trivy fs) 결과 요약이다 (nullus-plan#79, Security Dashboard 설계 §8 G1).
이미지 스캔과 같은 틀이다 — 요약 + 판정 + 원본 위치만 둔다. 원본 리포트는 CI 산출물로만 남는다.
type DeployStep ¶
type DeployStep struct {
Name string `json:"name"`
Status string `json:"status"`
Kind string `json:"kind"`
Message string `json:"message,omitempty"`
AppliedAt string `json:"applied_at,omitempty"`
Logs []string `json:"logs,omitempty"`
}
DeployStep tracks progress of a single resource application.
type Deployment ¶
type Deployment struct {
ID string `json:"id"`
PipelineID string `json:"pipeline_id"`
Version string `json:"version"`
Status DeploymentStatus `json:"status"`
Steps []DeployStep `json:"steps,omitempty"`
StartedAt time.Time `json:"started_at"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
DeployedBy string `json:"deployed_by"`
}
Deployment represents a single deployment run of a pipeline.
type DeploymentStatus ¶
type DeploymentStatus string
DeploymentStatus represents the status of a deployment run.
const ( DeploymentStatusPending DeploymentStatus = "pending" DeploymentStatusRunning DeploymentStatus = "running" DeploymentStatusSuccess DeploymentStatus = "success" DeploymentStatusFailed DeploymentStatus = "failed" DeploymentStatusRolledBack DeploymentStatus = "rolled_back" )
type GateResult ¶ added in v0.6.0
type GateResult string
GateResult 는 이미지 스캔 게이트의 판정이다.
const ( GateResultPass GateResult = "pass" GateResultWarn GateResult = "warn" GateResultBlock GateResult = "block" // GateResultError 는 판정할 수 없었다는 뜻이다(스캐너 도달 불가, 리포트 없음). // // 통과와 뭉치지 않는다 — 스캔이 못 돈 것과 취약점이 없는 것은 다르다. // 뭉치면 스캐너가 죽은 동안 모든 배포가 초록불로 지나간다. GateResultError GateResult = "error" )
func EvaluateGate ¶ added in v0.6.0
func EvaluateGate(s *TrivyReportSummary, policy ScanPolicy) GateResult
EvaluateGate 는 요약을 정책으로 판정한다.
리포트가 없으면 error 다 — 통과로 뭉치지 않는다.
func GateFromStageAndReport ¶ added in v0.6.0
func GateFromStageAndReport(stageStatus string, report *TrivyReportSummary, policy ScanPolicy) (GateResult, bool)
GateFromStageAndReport 는 스캔 단계 결과와 리포트로 판정한다.
단계 결과만으로는 "막혔다" 와 "스캔이 못 돌았다" 를 가를 수 없다 — Trivy 는 서버에 닿지 못해도 게이트와 같은 exit 1 로 끝난다. 리포트가 차단 사유를 담고 있을 때만 차단이다.
report 가 nil 이면 리포트를 모른다는 뜻이다(읽지 못함, 산출물 조회 미배선). 그때는 단계 결과를 따른다. 끝나지 않은 단계는 판정하지 않는다.
func GateResultFromStageStatus ¶ added in v0.6.0
func GateResultFromStageStatus(status string) (GateResult, bool)
GateResultFromStageStatus 는 리포트 없이 CI 단계 상태만으로 판정을 남긴다.
스캔 단계는 --exit-code 1 로 차단하므로 성공이면 통과, 실패면 차단이다. 그 밖의 상태(실행 중·대기·건너뜀·모름)는 판정하지 않는다 — 도는 중인 것을 통과로 적으면 안 된다.
func GateWhenReportMissing ¶ added in v0.6.0
func GateWhenReportMissing(stageStatus string) (GateResult, bool)
GateWhenReportMissing 은 리포트가 확실히 없을 때의 판정이다.
스캔 명령은 리포트부터 쓴다. 리포트가 없으면 스캔을 수행하지 못한 것이다.
- 실패: 스캐너에 닿지 못해 멈췄다 — 차단으로 세면 스캐너 장애가 "취약한 배포" 로 보인다.
- 성공: 스캐너 장애를 허용(allow)한 정책이 통과시켰다 — 통과로 적으면 스캔하지 않은 이미지가 "통과" 로 보인다.
어느 쪽이든 스캔했다는 근거가 없으므로 error 다.
func SASTGateFromStageAndReport ¶ added in v0.6.0
func SASTGateFromStageAndReport(stageStatus string, r *SASTReport) (GateResult, bool)
SASTGateFromStageAndReport 는 분석 단계 결과와 리포트로 판정한다.
단계 결과에는 스택 정책이 이미 반영돼 있다 — 경고 정책이면 게이트에 걸려도 성공, 장애 허용 정책이면 분석을 못 해도 성공이다. 그래서 단계 결과만으로는 셋을 가를 수 없고, 리포트의 스캐너 종료 코드가 "게이트에 걸렸다" 와 "분석을 못 했다" 를 가른다.
리포트가 없으면 판정하지 않는다. 리포트를 남기기 전에 만든 파이프라인의 실패를 차단으로 적으면, 분석기 장애가 "보안 문제로 막힌 배포" 로 보인다.
func SecretScanGate ¶ added in v0.6.0
func SecretScanGate(stageStatus string, findings *int, policy ScanPolicy) (GateResult, bool)
SecretScanGate 는 시크릿 탐지 단계 결과와 탐지 건수로 판정한다(설계 §8 G2 표).
gitleaks 리포트에는 종료 코드가 없어 추론한다. 스크립트(scaffold/secret_scan.go)는 탐지 시 정책에 따라 차단(exit 1)·경고(exit 0)하고, 스캔 자체를 못 하면 장애 정책을 따른다.
리포트 없음(findings nil) · 끝남 → error — 스캔했다는 근거가 없다(GateWhenReportMissing 과 같다) 탐지 > 0 · 실패 → block 탐지 > 0 · 성공 → warn — 경고 정책이 통과시켰다 탐지 0 · 성공 → pass 탐지 0 · 실패 → error — 탐지 없이 실패했다. 스캔이 실패한 것이다 스택 정책 off → 기록하지 않는다(대시보드의 "미적용")
끝나지 않은 단계(실행 중·대기·취소·건너뜀)는 판정하지 않는다.
type ImageScanResult ¶ added in v0.6.0
type ImageScanResult struct {
ID string `json:"id"`
PipelineID string `json:"pipeline_id"`
DeploymentID string `json:"deployment_id,omitempty"`
ImageRepository string `json:"image_repository,omitempty"`
ImageTag string `json:"image_tag,omitempty"`
// ImageDigest 에 결과를 붙인다 — 태그는 움직인다.
ImageDigest string `json:"image_digest,omitempty"`
ScanSource string `json:"scan_source"`
Scanner string `json:"scanner"`
ScannerVersion string `json:"scanner_version,omitempty"`
DBUpdatedAt *time.Time `json:"db_updated_at,omitempty"`
// Counts 는 리포트를 읽었을 때만 있다. nil 은 "모름" 이다 —
// 0 으로 채우면 "취약점 0건" 으로 읽힌다.
Counts *SeverityCounts `json:"counts,omitempty"`
GateResult GateResult `json:"gate_result"`
ReportURI string `json:"report_uri,omitempty"`
ScannedAt time.Time `json:"scanned_at"`
// ReportRef 는 CI 리포트를 다시 읽을 위치다. 취약점 목록은 볼 때 리포트를 다시
// 내려받아 만든다(원본은 DB 에 넣지 않는다, 설계 §8). 화면에는 내보내지 않는다.
ReportRef *ScanReportRef `json:"-"`
}
ImageScanResult 는 이미지 하나에 대한 스캔 결과 기록이다.
type Pipeline ¶
type Pipeline struct {
ID string `json:"id"`
Name string `json:"name"`
ExecutionMode string `json:"execution_mode,omitempty"`
TemplateID string `json:"template_id"`
OrgID string `json:"org_id"`
ClusterID string `json:"cluster_id"`
StackID string `json:"stack_id,omitempty"`
Namespace string `json:"namespace"`
AppType AppType `json:"app_type"`
GitRepoURL string `json:"git_repo_url"`
DockerfilePath string `json:"dockerfile_path,omitempty"`
DockerContext string `json:"docker_context,omitempty"`
EnvVars map[string]string `json:"env_vars,omitempty"`
Status PipelineStatus `json:"status"`
CreatedAt time.Time `json:"created_at"`
// Stages 는 이 파이프라인이 실제로 가진 단계다 (예: Build · ImageScan · Deploy).
//
// 템플릿의 stages 와 따로 둔다 — 이미지 스캔 같은 선택 단계는 파이프라인
// 단위로 켜고 끈다. 템플릿에만 두면 끈 파이프라인이 돌지도 않은 단계를
// 보여준다(마이그레이션 000070). 비어 있으면 모른다는 뜻이고, 화면은
// 템플릿으로 떨어진다 — 이 칸이 생기기 전에 만든 파이프라인이 그렇다.
Stages []string `json:"stages,omitempty"`
// Source 는 이 파이프라인의 저장소가 처음 가져온 원본이다. 원본을 가져오지 않았으면 nil 이다.
//
// 템플릿의 원본 커밋은 시간이 지나면 올라간다. 저장소가 어느 버전에서 시작했는지는
// 여기에만 남는다.
Source *TemplateSource `json:"source,omitempty"`
}
Pipeline represents a CI/CD pipeline configuration.
func (*Pipeline) DelegatesBuildToRunner ¶
DelegatesBuildToRunner 는 실행을 스택의 CI 러너가 맡는지다.
플랫폼이 직접 빌드·적용하는 경로는 API 서버가 host 에서 돌던 시절에 만들어졌다. 지금 API 는 파드 안에서 돌고 그 안에는 도커 데몬이 없다 — 직접 빌드는 성공할 수 없는 경로다. 스택에 묶인 파이프라인의 실행은 스택의 CI 플랫폼이 맡는다(통합모드 설계 3.2: "Nullus API 서버가 정상 실행 과정에서 직접 git clone, docker build, kind load, kubectl apply 를 수행하지 않는다").
Dockerfile 경로가 비어 있어도 마찬가지다. 스택에 묶였는데 플랫폼이 매니페스트를 직접 적용하면 CD 도구가 동기화하는 같은 리소스를 서로 덮어쓴다 — API 로 Dockerfile 경로 없이 만든 파이프라인이 그 경로로 새고 있었다. 긴급모드만 예외다.
func (*Pipeline) DeployClusterID ¶ added in v0.6.0
DeployClusterID 는 파이프라인의 앱이 실제로 서 있는 클러스터다. stackClusterID 는 묶인 스택의 클러스터이고, 모르면 빈 값이다.
스택에 묶인 파이프라인의 앱은 스택의 CD 도구가 올린다. Argo CD 의 Application 은 자기 클러스터(kubernetes.default.svc)를 향하고 Application 도 스택 클러스터에 적용되므로, 앱은 스택 클러스터에 선다 — 파이프라인에 어느 클러스터가 적혀 있든. 생성이 스택 클러스터만 받기 전에 만든 파이프라인에는 화면에서 고른 클러스터가 남아 있다.
플랫폼이 직접 적용한 경로(스택 없음·긴급 직접 배포)는 파이프라인의 클러스터에 올렸으니 그 값을 그대로 쓴다. 스택 클러스터를 모를 때도 저장된 값이 가장 나은 추정이다.
type PipelineSecurityList ¶ added in v0.6.0
type PipelineSecurityList struct {
Pipelines []*PipelineSecuritySnapshot
// Truncated 는 상한에 닿아 최근 만든 것부터 잘랐다는 뜻이다.
Truncated bool
}
PipelineSecurityList 는 조직 파이프라인의 단계별 최신 보안 결과다.
type PipelineSecuritySnapshot ¶ added in v0.6.0
type PipelineSecuritySnapshot struct {
PipelineID string
Name string
StackID string
ClusterID string
// Stages 는 파이프라인이 실제로 가진 단계다. 비어 있으면 모른다(단계 기록 전의 파이프라인).
Stages []string
// HasSecretScan · HasDependencyScan · HasSAST · HasImageScan 은 Stages 에 그 보안 단계가 있는지다.
// CI 마다 다른 표기(ImageScan · image-scan)를 단계 키로 맞춰 본 것이다. Stages 가 비면 모두 거짓이다.
HasSecretScan bool
HasDependencyScan bool
HasSAST bool
HasImageScan bool
// LatestRun 은 최근 실행이다. 실행이 없으면 nil 이다.
LatestRun *RunSummary
SecretScan *SecretScanResult
DependencyScan *DependencyScanResult
SAST *SASTResult
ImageScan *ImageScanResult
// RunVersions 는 결과 행이 가리키는 실행의 표시 번호(#42)다. 키는 deployment_id 다.
RunVersions map[string]string
// SecretDetection 은 스택 정책의 시크릿 탐지 동작이다(정책 행이 없으면 기본값 block). 스택에 묶이지
// 않은 파이프라인은 빈 값이다 — 정책이 없어 단계 유무로만 본다.
SecretDetection SecretDetectionAction
}
PipelineSecuritySnapshot 은 파이프라인 하나의 단계별 최신 보안 결과다(Security Dashboard 설계 §5).
결과 테이블은 cicd 가 소유한다. 대시보드(관측 모듈)는 테이블을 직접 읽지 않고 이 모양으로 받는다. 셀은 단계마다 그 단계의 최신 기록이다 — 앞 단계가 막으면 뒤 단계는 돌지 않으므로 최신 실행 하나의 결과만 보면 지금 돌고 있는 이미지의 CRITICAL 이 사라진다(설계 §2.1). 없는 결과는 nil 이다.
type PipelineStatus ¶
type PipelineStatus string
PipelineStatus represents the status of a pipeline.
const ( PipelineStatusActive PipelineStatus = "active" PipelineStatusInactive PipelineStatus = "inactive" )
type PipelineTemplate ¶
type PipelineTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
AppType AppType `json:"app_type"`
Stages []string `json:"stages"`
GitRepoURL string `json:"git_repo_url,omitempty"`
DockerfilePath string `json:"dockerfile_path,omitempty"`
DockerContext string `json:"docker_context,omitempty"`
EnvVars map[string]string `json:"env_vars,omitempty"`
CreatedBy string `json:"created_by,omitempty"`
// Source 가 있으면 파이프라인을 만들 때 이 원본을 새 저장소로 가져온다.
// 없으면 예전처럼 app_type 에 맞춘 스캐폴딩만 커밋한다.
Source *TemplateSource `json:"source,omitempty"`
}
PipelineTemplate represents a reusable CI/CD pipeline template.
func (*PipelineTemplate) Validate ¶ added in v0.6.0
func (t *PipelineTemplate) Validate() error
Validate 는 템플릿을 저장할 수 있는 모양인지 본다. 어기면 ErrTemplateInvalid 를 감싼다.
type QualityGateStatus ¶ added in v0.6.0
type QualityGateStatus string
QualityGateStatus 는 SonarQube 가 낸 Quality Gate 판정이다.
const ( QualityGateOK QualityGateStatus = "OK" QualityGateError QualityGateStatus = "ERROR" // QualityGateNone 은 게이트가 걸리지 않은 프로젝트다. QualityGateNone QualityGateStatus = "NONE" )
type RunSummary ¶ added in v0.6.0
type RunSummary struct {
DeploymentID string
Version string
Status DeploymentStatus
StartedAt time.Time
}
RunSummary 는 실행 하나의 요약이다.
type SASTCondition ¶ added in v0.6.0
type SASTCondition struct {
Metric string `json:"metric"`
Comparator string `json:"comparator,omitempty"`
Threshold string `json:"threshold,omitempty"`
Actual string `json:"actual,omitempty"`
// Status 는 OK 또는 ERROR 다.
Status string `json:"status"`
}
SASTCondition 은 Quality Gate 조건 하나의 평가 결과다.
type SASTGateAction ¶ added in v0.6.0
type SASTGateAction string
SASTGateAction 은 소스 정적 분석의 Quality Gate 가 실패했을 때의 동작이다.
const ( // SASTGateBlock 은 멈춘다. 기본값이다 — 이미지 스캔과 같다. SASTGateBlock SASTGateAction = "block" // SASTGateWarn 은 실패를 기록만 하고 통과시킨다. Quality Gate 를 막 도입한 팀이 // 기존 코드의 문제로 배포가 멈추지 않게 하는 길이다. SASTGateWarn SASTGateAction = "warn" )
type SASTMetrics ¶ added in v0.6.0
type SASTMetrics struct {
Bugs *int `json:"bugs,omitempty"`
Vulnerabilities *int `json:"vulnerabilities,omitempty"`
CodeSmells *int `json:"code_smells,omitempty"`
SecurityHotspots *int `json:"security_hotspots,omitempty"`
Coverage *float64 `json:"coverage,omitempty"`
DuplicatedLinesDensity *float64 `json:"duplicated_lines_density,omitempty"`
Ncloc *int `json:"ncloc,omitempty"`
}
SASTMetrics 는 프로젝트 전체 지표다. 응답에 없는 지표는 nil 이다.
type SASTReport ¶ added in v0.6.0
type SASTReport struct {
// ScannerExitCode 는 sonar-scanner 의 종료 코드다. 0 통과, 3 엔진 단계 실패(Quality Gate 실패
// 또는 분석 실패), 그 밖은 엔진을 띄우지도 못한 실패(서버 장애·인증 실패)다(실측).
ScannerExitCode int
// CETaskID 는 분석을 서버에 올렸을 때 생기는 작업 ID 다. 3 이 Quality Gate 실패인지 분석 실패인지는
// 이것으로 가른다 — 게이트 판정은 올린 분석에만 있다.
CETaskID string
ProjectKey string
AnalysisID string
DashboardURL string
QualityGateStatus QualityGateStatus
Conditions []SASTCondition
Metrics *SASTMetrics
}
SASTReport 는 파이프라인 SAST 잡이 남긴 리포트를 읽은 것이다.
func ParseSASTReport ¶ added in v0.6.0
func ParseSASTReport(raw []byte) (*SASTReport, error)
ParseSASTReport 는 SAST 잡이 남긴 리포트를 읽는다.
quality_gate·measures 는 SonarQube 응답을 그대로 담은 것이다. 스캐너 종료 코드가 없으면 판정의 근거가 없어 형식 오류로 본다.
type SASTResult ¶ added in v0.6.0
type SASTResult struct {
ID string `json:"id"`
PipelineID string `json:"pipeline_id"`
DeploymentID string `json:"deployment_id,omitempty"`
ProjectKey string `json:"project_key,omitempty"`
AnalysisID string `json:"analysis_id,omitempty"`
// QualityGateStatus 는 SonarQube 의 판정이다. 분석하지 못했으면 비어 있다.
QualityGateStatus QualityGateStatus `json:"quality_gate_status,omitempty"`
// GateResult 는 파이프라인 관점의 판정이다 — 같은 Quality Gate 실패도 스택 정책에 따라
// 차단·경고로 갈린다.
GateResult GateResult `json:"gate_result"`
Conditions []SASTCondition `json:"conditions,omitempty"`
// Metrics 는 분석했을 때만 있다. nil 은 "모름" 이다 — 0 으로 채우면 "문제 0건" 으로 읽힌다.
Metrics *SASTMetrics `json:"metrics,omitempty"`
DashboardURL string `json:"dashboard_url,omitempty"`
AnalyzedAt time.Time `json:"analyzed_at"`
}
SASTResult 는 실행 하나의 소스 정적 분석 결과 요약이다.
이미지 스캔처럼 요약·판정·위치만 둔다 — 이슈 목록 원본은 SonarQube 가 갖는다 (이미지 스캔 설계 §8 과 같은 범위). DashboardURL 로 SonarQube 화면을 연다.
type ScanPolicy ¶ added in v0.6.0
type ScanPolicy struct {
// BlockSeverity 이상의 취약점이 있으면 차단한다. 바로 아래 등급은 경고로 남긴다.
BlockSeverity Severity `json:"block_severity"`
// IgnoreUnfixed 가 참이면 수정본이 없는 취약점은 판정에서 뺀다.
IgnoreUnfixed bool `json:"ignore_unfixed"`
// OnScannerUnreachable 은 스캔을 수행하지 못했을 때의 동작이다. 소스 정적 분석을
// 수행하지 못했을 때(SonarQube 장애·인증 실패)도 이 값을 따른다.
OnScannerUnreachable UnreachableAction `json:"on_scanner_unreachable"`
// SASTOnGateFailure 는 소스 정적 분석의 Quality Gate 가 실패했을 때의 동작이다.
// 비어 있으면 차단이다(이 필드를 모르는 옛 클라이언트·저장 행).
SASTOnGateFailure SASTGateAction `json:"sast_on_gate_failure"`
// SecretDetection 은 시크릿 탐지 단계가 시크릿을 찾았을 때의 동작이다(block·warn·off).
// 비어 있으면 차단이다.
SecretDetection SecretDetectionAction `json:"secret_detection"`
}
ScanPolicy 는 스택 하나의 차단 기준이다.
스캐너가 스택마다 서고 장애 영향도 스택 하나로 막히므로 정책도 스택 단위다. 플랫폼이 CI 변수로 푸시하고, CI 가 그 값으로 스스로 판정한다.
func DefaultScanPolicy ¶ added in v0.6.0
func DefaultScanPolicy() ScanPolicy
DefaultScanPolicy 는 기본 차단 기준이다 (설계 §6).
CRITICAL 차단 · HIGH 경고 · 수정본 없는 것 제외 · 스캔 불가 시 차단. HIGH 까지 막으면 흔한 베이스 이미지로 첫 배포가 안 되고, 수정본 없는 CVE 로 막으면 사용자가 할 수 있는 일이 없다 — debian:11 은 CRITICAL 5건이 전부 unfixed 였다(실측).
func (ScanPolicy) SASTGateActionOrDefault ¶ added in v0.6.0
func (p ScanPolicy) SASTGateActionOrDefault() SASTGateAction
SASTGateActionOrDefault 는 비어 있으면 기본값(block)이다.
func (ScanPolicy) SecretDetectionOrDefault ¶ added in v0.6.0
func (p ScanPolicy) SecretDetectionOrDefault() SecretDetectionAction
SecretDetectionOrDefault 는 비어 있으면 기본값(block)이다 — 이 필드를 모르는 옛 클라이언트·저장 행.
func (ScanPolicy) TrivySeverities ¶ added in v0.6.0
func (p ScanPolicy) TrivySeverities() string
TrivySeverities 는 게이트 명령의 --severity 값이다.
Trivy 의 --severity 는 "이 등급만" 이다. "이 등급 이상" 을 뜻하려면 위 등급을 모두 적어야 한다 — HIGH 만 적으면 CRITICAL 이 통과한다.
func (ScanPolicy) UnreachableActionOrDefault ¶ added in v0.6.0
func (p ScanPolicy) UnreachableActionOrDefault() UnreachableAction
UnreachableActionOrDefault 는 비어 있으면 기본값(block)이다.
func (ScanPolicy) Validate ¶ added in v0.6.0
func (p ScanPolicy) Validate() error
Validate 는 저장·푸시 전에 정책 값을 확인한다.
모르는 값을 기본값으로 바꿔 받지 않는다. 오타(HIGHT)가 조용히 CRITICAL 로 바뀌면 운영자는 HIGH 를 막는 줄 알고 있게 된다.
type ScanReportRef ¶ added in v0.6.0
type ScanReportRef struct {
JobName string `json:"job_name"`
Branch string `json:"branch,omitempty"`
BuildID string `json:"build_id,omitempty"`
BuildNumber int `json:"build_number"`
StageID string `json:"stage_id,omitempty"`
StageName string `json:"stage_name,omitempty"`
Artifact string `json:"artifact,omitempty"`
Path string `json:"path"`
}
ScanReportRef 는 CI 가 남긴 스캔 리포트의 위치다.
CI 마다 산출물을 묶는 단위가 달라(GitLab 잡, GitHub 실행, Jenkins 빌드) 셋에 필요한 식별자를 모두 담는다.
type SecretDetectionAction ¶ added in v0.6.0
type SecretDetectionAction string
SecretDetectionAction 은 시크릿 탐지 단계(gitleaks)가 시크릿을 찾았을 때의 동작이다(nullus-plan#80).
이미지 스캔·SAST 와 달리 "끄기" 가 있다 — 스택에 설치하는 것이 없어 단계가 모든 파이프라인에 렌더되므로, 끄는 길은 정책이어야 한다. 끄면 단계는 돌되 바로 통과한다.
const ( // SecretDetectionBlock 은 멈춘다. 기본값이다 — 시크릿이 든 소스로 이미지를 만들어 올리는 것부터 막는다. SecretDetectionBlock SecretDetectionAction = "block" // SecretDetectionWarn 은 기록만 남기고 통과시킨다. 이력에 남은 옛 시크릿을 정리하는 동안의 길이다 — // 탐지 메시지의 폐기·회전 안내는 그대로 나온다. SecretDetectionWarn SecretDetectionAction = "warn" // SecretDetectionOff 는 탐지를 건너뛴다. 조직이 다른 수단(SCM push protection)으로 막을 때. SecretDetectionOff SecretDetectionAction = "off" )
type SecretFinding ¶ added in v0.6.0
type SecretFinding struct {
RuleID string `json:"rule_id"`
File string `json:"file"`
StartLine int `json:"start_line"`
// Commit 은 이력 검사(gitleaks git)일 때만 있다. 작업 트리 검사(gitleaks dir)는 커밋을 모른다.
Commit string `json:"commit,omitempty"`
Fingerprint string `json:"fingerprint"`
}
SecretFinding 은 탐지 하나의 위치다. 비밀값(gitleaks 의 Secret · Match)은 필드로 두지 않는다 — 둘 자리가 없으면 실수로라도 저장되지 않는다.
type SecretRuleCount ¶ added in v0.6.0
SecretRuleCount 는 규칙 하나의 탐지 건수다.
type SecretScanReport ¶ added in v0.6.0
type SecretScanReport struct {
// Count 는 전체 탐지 건수다.
Count int
// Rules 는 규칙별 건수다 — 건수가 많은 규칙부터, 같으면 규칙 이름 순.
Rules []SecretRuleCount
// Findings 는 리포트 순서대로 앞의 MaxStoredSecretFindings 건이다.
Findings []SecretFinding
// Skipped 는 정책 off 로 스캔하지 않은 실행의 리포트(SecretScanSkippedReport)라는 뜻이다. 기록하지 않는다.
Skipped bool
}
SecretScanReport 는 gitleaks JSON 리포트를 요약한 것이다.
func ParseGitleaksReport ¶ added in v0.6.0
func ParseGitleaksReport(raw []byte) (*SecretScanReport, error)
ParseGitleaksReport 는 gitleaks 의 JSON 리포트(--report-format json, 탐지 배열)를 요약한다.
탐지가 없으면 gitleaks 는 [] 를 쓴다. 정책 off 인 스크립트는 SecretScanSkippedReport 를 쓰고, 그것은 Skipped 로 돌려준다. 빈 파일이나 그 밖의 것은 형식 오류다 — 0 건으로 읽으면 깨진 리포트가 "탐지 없음" 이 된다. 이 표식 전에 스캐폴딩한 파이프라인은 off 에서도 [] 를 쓰므로, 정의를 갱신하기 전까지는 구별되지 않는다.
type SecretScanResult ¶ added in v0.6.0
type SecretScanResult struct {
ID string `json:"id"`
PipelineID string `json:"pipeline_id"`
DeploymentID string `json:"deployment_id"`
Scanner string `json:"scanner"`
ScannerVersion string `json:"scanner_version,omitempty"`
// FindingsCount 는 리포트를 읽었을 때만 있다. nil 은 "모름" 이다 — 0 으로 채우면 "탐지 없음" 으로 읽힌다.
FindingsCount *int `json:"findings_count,omitempty"`
// Rules 는 규칙별 탐지 건수다(잘리지 않는다). Findings 는 앞의 MaxStoredSecretFindings 건만이다.
Rules []SecretRuleCount `json:"rules"`
Findings []SecretFinding `json:"findings"`
GateResult GateResult `json:"gate_result"`
ReportURI string `json:"report_uri,omitempty"`
ScannedAt time.Time `json:"scanned_at"`
// ReportRef 는 CI 리포트를 다시 읽을 위치다. 화면에는 내보내지 않는다.
ReportRef *ScanReportRef `json:"-"`
}
SecretScanResult 는 실행 하나의 시크릿 탐지(gitleaks) 결과 요약이다 (nullus-plan#80, Security Dashboard 설계 §8 G2).
비밀값은 담지 않는다 — 탐지 위치(규칙 · 파일 · 줄 · 커밋 · Fingerprint)만 둔다. 이것만으로 무엇을 폐기·회전할지, 오탐이면 .gitleaksignore 에 무엇을 적을지 알 수 있다.
type SeverityCounts ¶ added in v0.6.0
type SeverityCounts = shareddomain.SeverityCounts
SeverityCounts 는 심각도별 취약점 건수다. 스택 모듈도 설치 이미지를 같은 어휘로 세므로 shared 가 소유한다.
type TemplateSource ¶ added in v0.6.0
type TemplateSource struct {
// RepoURL 은 원본 저장소 주소다(https).
RepoURL string `json:"repo_url"`
// Commit 은 가져올 커밋의 전체 SHA 다. 태그·브랜치는 받지 않는다 — 태그도 다시
// 찍힌다(eGov 웹 샘플의 v4.3.0 은 2025-03 릴리스인데 2026-05 커밋을 가리킨다).
Commit string `json:"commit"`
// Label 은 화면에 보일 버전 이름이다(예: v5.0.0). 가져올 대상을 정하지 않는다.
Label string `json:"label,omitempty"`
// BuildProfile 은 가져온 원본을 어떻게 빌드하고 띄울지다.
BuildProfile BuildProfile `json:"build_profile,omitempty"`
}
TemplateSource 는 템플릿이 새 저장소로 가져오는 외부 원본이다.
파이프라인을 만들 때 이 커밋의 파일을 그대로 복사해 앱 저장소의 첫 커밋으로 둔다. 원본을 따라가지 않는다 — 가져온 순간부터 그 저장소는 사용자 것이고, 새 버전은 템플릿의 Commit 을 올렸을 때 새로 만드는 파이프라인부터 들어온다.
파이프라인도 같은 값을 들고 있다. 템플릿의 Commit 은 시간이 지나면 올라가므로, 그 저장소가 어느 버전에서 시작했는지는 파이프라인 쪽에 따로 남아야 한다.
func (*TemplateSource) ShortCommit ¶ added in v0.6.0
func (s *TemplateSource) ShortCommit() string
ShortCommit 은 커밋 메시지와 화면에 쓸 짧은 SHA 다.
func (*TemplateSource) Validate ¶ added in v0.6.0
func (s *TemplateSource) Validate() error
Validate 는 원본을 가져올 수 있는 모양인지 본다. 어기면 ErrTemplateInvalid 를 감싼다.
type TrivyReportSummary ¶ added in v0.6.0
type TrivyReportSummary = shareddomain.TrivyReportSummary
TrivyReportSummary 는 Trivy JSON 리포트에서 판정에 필요한 것만 뽑은 것이다.
func ParseTrivyReport ¶ added in v0.6.0
func ParseTrivyReport(raw []byte) (*TrivyReportSummary, error)
ParseTrivyReport 는 Trivy JSON 리포트(SchemaVersion 2)를 요약한다.
type UnreachableAction ¶ added in v0.6.0
type UnreachableAction string
UnreachableAction 은 스캔을 수행하지 못했을 때(스캐너 도달 불가 등)의 동작이다.
const ( // UnreachableBlock 은 멈춘다. 기본값이다 — 스캐너가 죽은 동안 모든 배포가 // 초록불로 지나가는 것이 가장 나쁜 실패다 (설계 §6.1). UnreachableBlock UnreachableAction = "block" // UnreachableAllow 는 통과시킨다. 긴급 배포용 우회로다 — 우회로가 없으면 // 사람들은 파이프라인 자체를 우회한다. UnreachableAllow UnreachableAction = "allow" )