fix(build): mirror the Trivy Java DB — jar-bearing builds failed closed at the scan gate (#72)

This commit is contained in:
Lemon-miaow committed 2026-09-24 03:11:01 +08:00
1 parent 6e47730501
commit b14bacbfc6
9 files changed
+77 -30

No files matched your search

+2 -1
View File
@@ -423,7 +423,8 @@ func buildConfig(cfg *config.Config) build.Config {
MemLimit: cfg.Registry.BuildMemLimit,
// Empty keeps Trivy's own default; an install with builds points this at
// the internal DB mirror (see config.RegistryConfig.TrivyDBRepository).
TrivyDBRepository: cfg.Registry.TrivyDBRepository,
TrivyDBRepository: cfg.Registry.TrivyDBRepository,
TrivyJavaDBRepository: cfg.Registry.TrivyJavaDBRepository,
}
}
+1 -1
View File
@@ -2188,7 +2188,7 @@ persisted_registry_block() {
out="$(awk '
/^[[:space:]]*\[/ { sect = $0; next }
sect ~ /^[[:space:]]*\[registry\][[:space:]]*$/ &&
/^[[:space:]]*(kaniko_image|trivy_image|trivy_db_repository|build_cpu_limit|build_mem_limit|user_uploads_context)[[:space:]]*=/ { print }
/^[[:space:]]*(kaniko_image|trivy_image|trivy_db_repository|trivy_java_db_repository|build_cpu_limit|build_mem_limit|user_uploads_context)[[:space:]]*=/ { print }
sect ~ /^[[:space:]]*\[registry\.s3\][[:space:]]*$/ && /^[[:space:]]*[A-Za-z_]+[[:space:]]*=/ {
if (!s3hdr) { printf "[registry.s3]\n"; s3hdr = 1 }
print
+5
View File
@@ -878,6 +878,7 @@ url = "stale.invalid:5000"
build_namespace = "stale-ns"
kaniko_image = "registry.felis.svc:5000/mirror/kaniko-executor:v1.24.0"
trivy_db_repository = "registry.felis.svc:5000/mirror/trivy-db:2"
trivy_java_db_repository = "registry.felis.svc:5000/mirror/trivy-java-db:1"
[registry.s3]
endpoint = "https://s3.example"
@@ -905,6 +906,10 @@ run_write "$rdir/out.toml"
out="$(cat "$rdir/out.toml")"
expect "a re-run carries the build-lane executor mirrors" \
'kaniko_image = "registry.felis.svc:5000/mirror/kaniko-executor:v1.24.0"' "$out"
expect "a re-run carries the trivy vulnerability-DB mirror" \
'trivy_db_repository = "registry.felis.svc:5000/mirror/trivy-db:2"' "$out"
expect "a re-run carries the trivy java-DB mirror" \
'trivy_java_db_repository = "registry.felis.svc:5000/mirror/trivy-java-db:1"' "$out"
expect "a re-run carries the [registry.s3] uploads subtable" "[registry.s3]" "$out"
expect "the carried subtable keeps its keys" 'endpoint = "https://s3.example"' "$out"
expect "url stays installer-owned" 'url = "registry.felis.svc:5000"' "$out"
+6 -4
View File
@@ -57,10 +57,12 @@ A grep across `*.md` and `*.go` returns both sets; only the Go ones are seams.
build_cpu_limit / build_mem_limit` override them for mirrored or air-gapped
installs. Trivy's vulnerability DB is the same story, and now has its own knob:
`[registry] trivy_db_repository` points `--db-repository` at an internal mirror
(recipe in docs/troubleshooting.md §8e). Left unset on an egress-locked box the
scan step fails closed — Kaniko pushes, Trivy exits on the DB download — which
is the correct fail direction but leaves the build unfinished, so the mirror is
part of a production build install.
(recipe in docs/troubleshooting.md §8e); `trivy_java_db_repository` does the
same for the Java DB, which Trivy fetches so soon as the scanned image contains
a jar — i.e. for every real modpack build. Left unset on an egress-locked box
the scan step fails closed — Kaniko pushes, Trivy exits on the DB download —
which is the correct fail direction but leaves the build unfinished, so the
mirrors are part of a production build install.
## Built; only its I/O is unverifiable from this repo
+11
View File
@@ -411,6 +411,7 @@ build_namespace = "felis-build"
kaniko_image = "registry.felis.svc:5000/mirror/kaniko-executor:v1.24.0"
trivy_image = "registry.felis.svc:5000/mirror/trivy:0.74.0"
trivy_db_repository = "registry.felis.svc:5000/mirror/trivy-db:2"
trivy_java_db_repository = "registry.felis.svc:5000/mirror/trivy-java-db:1"
build_cpu_limit = "2"
build_mem_limit = "4Gi"
```
@@ -423,10 +424,13 @@ through the loopback hostPort the registry Deployment binds (docker treats
```sh
docker pull gcr.io/kaniko-project/executor:v1.24.0 # any versions you pin
docker pull aquasec/trivy:0.74.0
docker pull mirror.gcr.io/aquasec/trivy-java-db:1
docker tag gcr.io/kaniko-project/executor:v1.24.0 127.0.0.1:5000/mirror/kaniko-executor:v1.24.0
docker tag aquasec/trivy:0.74.0 127.0.0.1:5000/mirror/trivy:0.74.0
docker tag mirror.gcr.io/aquasec/trivy-java-db:1 127.0.0.1:5000/mirror/trivy-java-db:1
docker push 127.0.0.1:5000/mirror/kaniko-executor:v1.24.0
docker push 127.0.0.1:5000/mirror/trivy:0.74.0
docker push 127.0.0.1:5000/mirror/trivy-java-db:1
```
From another machine, port-forward the registry instead (`kubectl -n felis
@@ -469,6 +473,13 @@ registry's plain HTTP works for the DB pull exactly as it does for the scanned
image. Re-mirror the tag periodically (Trivy refreshes the DB several times a
day upstream; a stale mirror only means stale CVE data, never a failed gate).
`trivy_java_db_repository` is the same story one step lazier: Trivy downloads
the Java DB on demand the first time it scans an image containing Java
artifacts — every real modpack — and that download fails closed too. Mirror
`mirror.gcr.io/aquasec/trivy-java-db:1` alongside the vulnerability DB (commands
above); the Java DB refreshes far less often than the vulnerability DB, so a
one-off mirror is usually fine.
---
## 9. Registry push/pull failures (spec §15)
+19 -13
View File
@@ -225,6 +225,11 @@ type Config struct {
// egress lock denies — an install with builds must point this at an internal
// mirror (see config.RegistryConfig.TrivyDBRepository).
TrivyDBRepository string
// TrivyJavaDBRepository overrides where Trivy fetches its Java DB
// (--java-db-repository), downloaded lazily for images that contain Java
// artifacts — i.e. every real modpack. Same egress story as the
// vulnerability DB (see config.RegistryConfig.TrivyJavaDBRepository).
TrivyJavaDBRepository string
// KanikoImage / TrivyImage are the executor images.
KanikoImage string
TrivyImage string
@@ -359,19 +364,20 @@ func (b *Builder) Submit(ctx context.Context, req Request) (*Build, error) {
// jobParams projects a build + config onto the inputs jobspec.go renders.
func (b *Builder) jobParams(bld *Build, cfg Config) JobParams {
return JobParams{
BuildID: bld.ID,
ImageRef: bld.ImageRef,
ContextRef: bld.ContextRef,
Namespace: cfg.Namespace,
ServiceAccount: cfg.ServiceAccount,
RegistryURL: cfg.RegistryURL,
FelisImage: cfg.FelisImage,
TrivyDBRepository: cfg.TrivyDBRepository,
KanikoImage: cfg.KanikoImage,
TrivyImage: cfg.TrivyImage,
Deadline: cfg.Deadline,
CPULimit: cfg.CPULimit,
MemLimit: cfg.MemLimit,
BuildID: bld.ID,
ImageRef: bld.ImageRef,
ContextRef: bld.ContextRef,
Namespace: cfg.Namespace,
ServiceAccount: cfg.ServiceAccount,
RegistryURL: cfg.RegistryURL,
FelisImage: cfg.FelisImage,
TrivyDBRepository: cfg.TrivyDBRepository,
TrivyJavaDBRepository: cfg.TrivyJavaDBRepository,
KanikoImage: cfg.KanikoImage,
TrivyImage: cfg.TrivyImage,
Deadline: cfg.Deadline,
CPULimit: cfg.CPULimit,
MemLimit: cfg.MemLimit,
}
}
+13 -5
View File
@@ -82,11 +82,16 @@ type JobParams struct {
// --db-repository flag). Empty keeps Trivy's own default; see
// build.Config.TrivyDBRepository for why an in-cluster install sets it.
TrivyDBRepository string
KanikoImage string
TrivyImage string
Deadline time.Duration
CPULimit string
MemLimit string
// TrivyJavaDBRepository overrides Trivy's Java-DB source (the
// --java-db-repository flag), fetched lazily when the image contains Java
// artifacts; empty keeps Trivy's own default, which the build egress lock
// denies — a jar-bearing image then fails the scan.
TrivyJavaDBRepository string
KanikoImage string
TrivyImage string
Deadline time.Duration
CPULimit string
MemLimit string
}
// BuildJobName is the deterministic Job name for a build id.
@@ -257,6 +262,9 @@ func BuildJob(p JobParams) (*batchv1.Job, error) {
if p.TrivyDBRepository != "" {
trivyArgs = append(trivyArgs, "--db-repository", p.TrivyDBRepository)
}
if p.TrivyJavaDBRepository != "" {
trivyArgs = append(trivyArgs, "--java-db-repository", p.TrivyJavaDBRepository)
}
trivyArgs = append(trivyArgs, p.ImageRef)
trivy := corev1.Container{
Name: ContainerTrivy,
+11 -6
View File
@@ -204,9 +204,9 @@ func TestBuildJobKanikoPushesAndTrivyGates(t *testing.T) {
if !hasArg(trivy.Args, p.ImageRef) {
t.Errorf("trivy must scan the pushed ref %q, args=%v", p.ImageRef, trivy.Args)
}
// No DB repository configured: Trivy keeps its own default.
if hasArg(trivy.Args, "--db-repository") {
t.Errorf("unset TrivyDBRepository must not render --db-repository, args=%v", trivy.Args)
// No DB repositories configured: Trivy keeps its own defaults.
if hasArg(trivy.Args, "--db-repository") || hasArg(trivy.Args, "--java-db-repository") {
t.Errorf("unset DB repositories must not render --db-repository/--java-db-repository, args=%v", trivy.Args)
}
}
@@ -262,12 +262,14 @@ func TestBuildJobKanikoGetsOnlyUnpackCapabilities(t *testing.T) {
}
}
// A configured DB repository (the internal mirror) must reach Trivy as
// --db-repository: without it the scan tries the internet, which the build egress
// lock denies, and every build fails closed at the scan gate.
// Configured DB repositories (the internal mirrors) must reach Trivy as
// --db-repository / --java-db-repository: without them the scan tries the
// internet, which the build egress lock denies, and every build fails closed at
// the scan gate — the Java DB the moment the image contains a jar.
func TestBuildJobTrivyDBRepositoryOverride(t *testing.T) {
p := sampleJobParams()
p.TrivyDBRepository = "registry.felis.svc:5000/mirror/trivy-db:2"
p.TrivyJavaDBRepository = "registry.felis.svc:5000/mirror/trivy-java-db:1"
job, err := BuildJob(p)
if err != nil {
t.Fatalf("BuildJob: %v", err)
@@ -276,6 +278,9 @@ func TestBuildJobTrivyDBRepositoryOverride(t *testing.T) {
if !argPairPresent(trivy.Args, "--db-repository", p.TrivyDBRepository) {
t.Errorf("trivy args = %v, want --db-repository %s", trivy.Args, p.TrivyDBRepository)
}
if !argPairPresent(trivy.Args, "--java-db-repository", p.TrivyJavaDBRepository) {
t.Errorf("trivy args = %v, want --java-db-repository %s", trivy.Args, p.TrivyJavaDBRepository)
}
// The scanned image ref must stay the last argument.
if last := trivy.Args[len(trivy.Args)-1]; last != p.ImageRef {
t.Errorf("image ref must remain the last argument, args=%v", trivy.Args)
+9
View File
@@ -145,6 +145,15 @@ type RegistryConfig struct {
// default (only usable on an install that deliberately opens internet
// egress to the DB hosts).
TrivyDBRepository string `toml:"trivy_db_repository"`
// TrivyJavaDBRepository points Trivy at an OCI repository holding the Java
// DB (--java-db-repository). Trivy fetches it lazily whenever the scanned
// image contains Java artifacts — every real modpack image does — so on an
// egress-locked box the scan fails closed without this mirror exactly like
// the vulnerability DB. The supported shape is an internal mirror: copy
// mirror.gcr.io/aquasec/trivy-java-db:1 into this cluster's registry and
// set this to registry.<ns>.svc:5000/mirror/trivy-java-db:1 (recipe in
// docs/troubleshooting.md §8e). Empty keeps Trivy's own default.
TrivyJavaDBRepository string `toml:"trivy_java_db_repository"`
// UserUploadsContext is the object-store base under which a user-submitted
// modpack's Kaniko build context is pinned. It belongs to the §16 build
// subsystem's input domain (the build-context store), introduced by the