Skip to content

Commit

Permalink
Merge branch 'master' into 314-update-to-micronaut-41
Browse files Browse the repository at this point in the history
  • Loading branch information
munishchouhan authored Oct 10, 2024
2 parents f295c4e + da2f075 commit 2138744
Show file tree
Hide file tree
Showing 35 changed files with 456 additions and 324 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies {
implementation("jakarta.persistence:jakarta.persistence-api:3.0.0")
api 'io.seqera:lib-mail:1.1.0'
api 'io.seqera:wave-api:0.13.1'
api 'io.seqera:wave-api:0.13.2'
api 'io.seqera:wave-utils:0.14.1'
implementation("io.micronaut:micronaut-http-client")
implementation("io.micronaut:micronaut-jackson-databind")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package io.seqera.wave.service.mirror
package io.seqera.wave.configuration

import java.time.Duration

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class ScanConfig {
@Value('${wave.scan.retry-attempts:1}')
int retryAttempts

@Value('${wave.scan.status.duration:1h}')
@Value('${wave.scan.status.duration:5d}')
Duration statusDuration

@Value('${wave.scan.id.duration:7d}')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import io.seqera.wave.service.request.ContainerStatusService
import io.seqera.wave.service.request.TokenData
import io.seqera.wave.service.scan.ContainerScanService
import io.seqera.wave.service.validation.ValidationService
import io.seqera.wave.service.validation.ValidationServiceImpl
import io.seqera.wave.tower.PlatformId
import io.seqera.wave.tower.User
import io.seqera.wave.tower.auth.JwtAuth
Expand Down Expand Up @@ -241,14 +242,14 @@ class ContainerController {
throw new BadRequestException("Attribute `nameStrategy` is not allowed by legacy container endpoint")

// prevent the use of container file and freeze without a custom build repository
if( req.containerFile && req.freeze && !isCustomRepo0(req.buildRepository) && (!v2 || (v2 && !req.packages)))
if( req.containerFile && req.freeze && !validationService.isCustomRepo(req.buildRepository) && (!v2 || (v2 && !req.packages)))
throw new BadRequestException("Attribute `buildRepository` must be specified when using freeze mode [1]")

// prevent the use of container image and freeze without a custom build repository
if( req.containerImage && req.freeze && !isCustomRepo0(req.buildRepository) )
if( req.containerImage && req.freeze && !validationService.isCustomRepo(req.buildRepository) )
throw new BadRequestException("Attribute `buildRepository` must be specified when using freeze mode [2]")

if( v2 && req.packages && req.freeze && !isCustomRepo0(req.buildRepository) && !buildConfig.defaultPublicRepository )
if( v2 && req.packages && req.freeze && !validationService.isCustomRepo(req.buildRepository) && !buildConfig.defaultPublicRepository )
throw new BadRequestException("Attribute `buildRepository` must be specified when using freeze mode [3]")

if( v2 && req.packages ) {
Expand Down Expand Up @@ -281,18 +282,6 @@ class ContainerController {
return HttpResponse.ok(resp)
}

protected boolean isCustomRepo0(String repo) {
if( !repo )
return false
if( buildConfig.defaultPublicRepository && repo.startsWith(buildConfig.defaultPublicRepository) )
return false
if( buildConfig.defaultBuildRepository && repo.startsWith(buildConfig.defaultBuildRepository) )
return false
if( buildConfig.defaultCacheRepository && repo.startsWith(buildConfig.defaultCacheRepository) )
return false
return true
}

protected void storeContainerRequest0(SubmitContainerTokenRequest req, ContainerRequest data, TokenData token, String target, String ip) {
try {
final recrd = new WaveContainerRecord(req, data, target, ip, token.expiration)
Expand Down Expand Up @@ -456,7 +445,7 @@ class ContainerController {
scanId = build.scanId
mirrorFlag = false
}
else if( req.mirrorRegistry ) {
else if( req.mirror ) {
final mirror = makeMirrorRequest(req, identity, digest)
final track = checkMirror(mirror, identity, req.dryRun)
targetImage = track.targetImage
Expand Down Expand Up @@ -497,15 +486,23 @@ class ContainerController {
req.scanMode,
req.scanLevels,
scanOnRequest,
req.dryRun,
Instant.now()
)
}

protected MirrorRequest makeMirrorRequest(SubmitContainerTokenRequest request, PlatformId identity, String digest) {
final coords = ContainerCoordinates.parse(request.containerImage)
if( coords.registry == request.mirrorRegistry )
throw new BadRequestException("Source and target mirror registry as the same - offending value '${request.mirrorRegistry}'")
final targetImage = request.mirrorRegistry + '/' + coords.imageAndTag
final target = ContainerCoordinates.parse(request.buildRepository)
if( !coords.imageAndTag )
throw new BadRequestException("Missing mirror source image - offending value '${request.containerImage}'")
if( !target.registry )
throw new BadRequestException("Missing mirror target registry - offending value '${request.buildRepository}'")
if( coords.registry == target.registry )
throw new BadRequestException("Source and target mirror registries are the same - offending value '${request.buildRepository}'")
final targetImage = target.repository
? target.repository + '/' + coords.imageAndTag
: target.registry + '/' + coords.imageAndTag
final configJson = inspectService.credentialsConfigJson(null, request.containerImage, targetImage, identity)
final platform = request.containerPlatform
? ContainerPlatform.of(request.containerPlatform)
Expand Down Expand Up @@ -583,41 +580,45 @@ class ContainerController {
// check valid image name
msg = validationService.checkContainerName(req.containerImage)
if( msg ) throw new BadRequestException(msg)
// stop here for mirror request
if( req.mirror )
return
// check build repo
msg = validationService.checkBuildRepository(req.buildRepository, false)
if( !req.mirror )
msg = validationService.checkBuildRepository(req.buildRepository, ValidationServiceImpl.RepoType.Build)
if( msg ) throw new BadRequestException(msg)
// check cache repository
msg = validationService.checkBuildRepository(req.cacheRepository, true)
msg = validationService.checkBuildRepository(req.cacheRepository, ValidationServiceImpl.RepoType.Cache)
if( msg ) throw new BadRequestException(msg)
}

void validateMirrorRequest(SubmitContainerTokenRequest req, boolean v2) throws BadRequestException {
if( !req.mirrorRegistry )
if( !req.mirror )
return
// container mirror validation
if( !v2 )
throw new BadRequestException("Container mirroring requires the use of v2 API")
if( !req.containerImage )
throw new BadRequestException("Attribute `containerImage` is required when specifying `mirrorRegistry`")
throw new BadRequestException("Attribute `containerImage` is required when specifying `mirror` mode")
if( !req.towerAccessToken )
throw new BadRequestException("Container mirroring requires an authenticated request - specify the tower token attribute")
if( req.freeze )
throw new BadRequestException("Attribute `mirrorRegistry` and `freeze` conflict each other")
throw new BadRequestException("Attribute `mirror` and `freeze` conflict each other")
if( req.containerFile )
throw new BadRequestException("Attribute `mirrorRegistry` and `containerFile` conflict each other")
throw new BadRequestException("Attribute `mirror` and `containerFile` conflict each other")
if( req.containerIncludes )
throw new BadRequestException("Attribute `mirrorRegistry` and `containerIncludes` conflict each other")
throw new BadRequestException("Attribute `mirror` and `containerIncludes` conflict each other")
if( req.containerConfig )
throw new BadRequestException("Attribute `mirrorRegistry` and `containerConfig` conflict each other")
throw new BadRequestException("Attribute `mirror` and `containerConfig` conflict each other")
if( !req.buildRepository )
throw new BadRequestException("Attribute `buildRepository` is required when specifying `mirror` mode")
final coords = ContainerCoordinates.parse(req.containerImage)
if( coords.registry == req.mirrorRegistry )
throw new BadRequestException("Source and target mirror registry as the same - offending value '${req.mirrorRegistry}'")
def msg = validationService.checkMirrorRegistry(req.mirrorRegistry)
final target = ContainerCoordinates.parse(req.buildRepository)
if( coords.registry == target.registry )
throw new BadRequestException("Source and target mirror registry are the same - offending value '${req.buildRepository}'")
def msg = validationService.checkBuildRepository(req.buildRepository, ValidationServiceImpl.RepoType.Mirror)
if( msg )
throw new BadRequestException(msg)
if( !isCustomRepo0(req.mirrorRegistry) ) {
throw new BadRequestException("Not allowed mirror registry - offending value '${req.mirrorRegistry}'")
}
}

@Error(exception = AuthorizationException.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class ViewController {
binding.build_failed = result.exitStatus && result.exitStatus != 0
binding.build_in_progress = result.exitStatus == null
binding.build_exit_status = result.exitStatus
binding.build_user = (result.userName ?: '-') + " (ip: ${result.requestIp})"
binding.build_user = (result.userName ?: '-')
binding.build_time = formatTimestamp(result.startTime, result.offsetId) ?: '-'
binding.build_duration = formatDuration(result.duration) ?: '-'
binding.build_image = result.targetImage
Expand Down Expand Up @@ -247,7 +247,7 @@ class ViewController {
binding.mirror_id = data.mirror ? data.buildId : null
binding.mirror_url = data.mirror ? "$serverUrl/view/mirrors/${data.buildId}" : null
binding.mirror_cached = data.mirror ? !data.buildNew : null

binding.server_url = serverUrl
return HttpResponse.<Map<String,Object>>ok(binding)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import groovy.transform.CompileStatic
import io.seqera.wave.configuration.BlobCacheConfig
import io.seqera.wave.configuration.ScanConfig
import io.seqera.wave.service.builder.BuildRequest
import io.seqera.wave.service.mirror.MirrorConfig
import io.seqera.wave.configuration.MirrorConfig
import io.seqera.wave.service.mirror.MirrorRequest
import io.seqera.wave.service.scan.ScanRequest
import jakarta.inject.Inject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import io.kubernetes.client.openapi.models.V1Pod
import io.kubernetes.client.openapi.models.V1PodList
import io.seqera.wave.configuration.BlobCacheConfig
import io.seqera.wave.configuration.ScanConfig
import io.seqera.wave.service.mirror.MirrorConfig
import io.seqera.wave.configuration.MirrorConfig

/**
* Defines Kubernetes operations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ import io.seqera.wave.configuration.BlobCacheConfig
import io.seqera.wave.configuration.BuildConfig
import io.seqera.wave.configuration.ScanConfig
import io.seqera.wave.core.ContainerPlatform
import io.seqera.wave.service.mirror.MirrorConfig
import io.seqera.wave.configuration.MirrorConfig
import io.seqera.wave.service.scan.Trivy
import jakarta.inject.Inject
import jakarta.inject.Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

package io.seqera.wave.service.mirror

import io.seqera.wave.configuration.MirrorConfig

import java.time.Duration

import groovy.transform.CompileStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import groovy.json.JsonOutput
import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import io.micronaut.context.annotation.Value
import io.seqera.wave.service.mirror.MirrorConfig
import io.seqera.wave.configuration.MirrorConfig
import io.seqera.wave.service.mirror.MirrorRequest
import jakarta.inject.Inject
import jakarta.inject.Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import io.micronaut.context.annotation.Primary
import io.micronaut.context.annotation.Requires
import io.seqera.wave.exception.BadRequestException
import io.seqera.wave.service.k8s.K8sService
import io.seqera.wave.service.mirror.MirrorConfig
import io.seqera.wave.configuration.MirrorConfig
import io.seqera.wave.service.mirror.MirrorRequest
import jakarta.inject.Inject
import jakarta.inject.Singleton
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ interface PersistenceService {
*/
WaveScanRecord loadScanRecord(String scanId)

/**
* Check if a scan record exist
*
* @param scanId The Id of the scan to check
* @return {@code true} if the scan record with the specified id exists or {@code false} otherwise
*/
boolean existsScanRecord(String scanId)

/**
* Load a mirror state record
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ class LocalPersistenceService implements PersistenceService {
requestStore.get(token)
}

@Override
boolean existsScanRecord(String scanId) {
scanStore.containsKey(scanId)
}

@Override
void saveScanRecord(WaveScanRecord scanRecord) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,16 @@ class SurrealPersistenceService implements PersistenceService {
json.replaceFirst(/"vulnerabilities":\s*\[]/, value)
}

@Override
boolean existsScanRecord(String scanId) {
final statement = "SELECT count() FROM wave_scan where id == 'wave_scan:⟨$scanId⟩'"
final json = surrealDb.sqlAsString(getAuthorization(), statement)
final type = new TypeReference<ArrayList<SurrealResult<Map>>>() {}
final data= json ? JacksonHelper.fromJson(json, type) : null
final result = data && data[0].result ? data[0].result[0].count==1 : false
return result
}

@Override
WaveScanRecord loadScanRecord(String scanId) {
if( !scanId )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ class ContainerRequest {
String scanId
ScanMode scanMode
List<ScanLevel> scanLevels
Boolean scanOnRequest
boolean scanOnRequest
boolean dryRun
Instant creationTime

boolean durable() {
Expand Down Expand Up @@ -129,11 +130,15 @@ class ContainerRequest {
return creationTime
}

Boolean getScanOnRequest() {
scanOnRequest
boolean getScanOnRequest() {
return scanOnRequest
}

static ContainerRequest create(
boolean getDryRun() {
return dryRun
}

static ContainerRequest create(
PlatformId identity,
String containerImage,
String containerFile,
Expand All @@ -147,7 +152,8 @@ class ContainerRequest {
String scanId,
ScanMode scanMode,
List<ScanLevel> scanLevels,
Boolean scanOnRequest,
boolean scanOnRequest,
boolean dryRun,
Instant creationTime
)
{
Expand All @@ -167,6 +173,7 @@ class ContainerRequest {
scanMode,
scanLevels,
scanOnRequest,
dryRun,
creationTime
)
}
Expand All @@ -191,7 +198,8 @@ class ContainerRequest {
data.scanId as String,
data.scanMode as ScanMode,
data.scanLevels as List<ScanLevel>,
data.scanOnRequest as Boolean,
data.scanOnRequest as boolean,
data.dryRun as boolean,
data.creationTime as Instant
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,14 @@ class ContainerScanServiceImpl implements ContainerScanService, JobHandler<ScanE
@Override
void scanOnRequest(ContainerRequest request) {
try {
if( request.scanId && request.scanOnRequest ) {
if( request.scanId && request.scanOnRequest && !request.dryRun ) {
log.debug "Container scan required by scanOnRequest=$request"
scan(fromContainer(request))
}
else if( request.scanId && request.buildId && request.buildNew==false && !request.dryRun && !existsScan(request.scanId) ) {
log.debug "Container scan required by cached request=$request"
scan(fromContainer(request))
}
else {
log.trace "Container scan NOT required by scanOnRequest=$request"
}
Expand All @@ -149,6 +153,10 @@ class ContainerScanServiceImpl implements ContainerScanService, JobHandler<ScanE
return scanStore.get(scanId)
}

boolean existsScan(String scanId) {
return scanStore.get(scanId) ?: persistenceService.existsScanRecord(scanId)
}

@Override
WaveScanRecord getScanRecord(String scanId) {
try{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ interface ValidationService {

String checkContainerName(String name)

String checkBuildRepository(String repo, boolean cache)
String checkBuildRepository(String repo, ValidationServiceImpl.RepoType type)

String checkMirrorRegistry(String registry)
boolean isCustomRepo(String repo)

}
Loading

0 comments on commit 2138744

Please sign in to comment.