├── .codespellignore ├── .editorconfig ├── .github ├── actions │ ├── deploy │ │ └── action.yml │ └── spelling │ │ └── allow.txt └── workflows │ ├── build-singularity.yml │ ├── build.yml │ ├── codespell.yml │ ├── pre-commit.yml.bak │ ├── security-submit-dependecy-graph.yml │ ├── seqera_docs_changelog.yml │ └── typespec.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .prettierignore ├── .prettierrc ├── LICENSE ├── Makefile ├── README.md ├── VERSION ├── build.gradle ├── buildSrc ├── build.gradle └── src │ └── main │ └── groovy │ ├── io.seqera.wave.groovy-application-conventions.gradle │ ├── io.seqera.wave.groovy-common-conventions.gradle │ ├── io.seqera.wave.groovy-library-conventions.gradle │ └── io.seqera.wave.java-library-conventions.gradle ├── changelog.txt ├── config.yml ├── container-request.json ├── debug.sh ├── docs.sh ├── docs ├── _images │ ├── wave_container_augmentation.png │ └── wave_container_build_failure_details.png ├── api.mdx ├── cli │ ├── index.mdx │ └── reference.mdx ├── configuration.mdx ├── faq.mdx ├── get-started.mdx ├── index.mdx ├── metrics.mdx ├── nextflow.mdx ├── provisioning.mdx ├── sidebar.json └── troubleshoot.mdx ├── gradle.properties ├── gradle ├── config │ └── groovyc.groovy └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── misc ├── image-config.json ├── image-config.v2.json ├── manifest-v1-319b8d4eca0fc0367d192941f221f7fcd29a6b96996c63cbf8931dbb66e53348.json ├── resp2.975f4b14f326b05db86e16de00144f9c12257553bba9484fed41f9b6f2257800.json ├── resp2.formatted.json ├── resp3.f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4.json ├── resp3.formatted.json ├── resp4.feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412.json ├── resp4.formatted.json └── tldr.md ├── reg.sh ├── run.sh ├── s5cmd ├── Dockerfile ├── Makefile └── dist.sh ├── settings.gradle ├── singularity ├── Dockerfile └── Makefile ├── src ├── main │ ├── groovy │ │ └── io │ │ │ └── seqera │ │ │ ├── util │ │ │ └── trace │ │ │ │ ├── TraceElapsedTime.groovy │ │ │ │ └── TraceElapsedTimeInterceptor.groovy │ │ │ └── wave │ │ │ ├── Application.groovy │ │ │ ├── Bootstrap.groovy │ │ │ ├── ErrorHandler.groovy │ │ │ ├── WaveDefault.groovy │ │ │ ├── auth │ │ │ ├── BasicAuthenticationProvider.groovy │ │ │ ├── MissingCredentials.groovy │ │ │ ├── RegistryAuth.groovy │ │ │ ├── RegistryAuthService.groovy │ │ │ ├── RegistryAuthServiceImpl.groovy │ │ │ ├── RegistryConfig.groovy │ │ │ ├── RegistryCredentials.groovy │ │ │ ├── RegistryCredentialsFactory.groovy │ │ │ ├── RegistryCredentialsFactoryImpl.groovy │ │ │ ├── RegistryCredentialsProvider.groovy │ │ │ ├── RegistryCredentialsProviderImpl.groovy │ │ │ ├── RegistryInfo.groovy │ │ │ ├── RegistryLookupCache.groovy │ │ │ ├── RegistryLookupException.groovy │ │ │ ├── RegistryLookupService.groovy │ │ │ ├── RegistryLookupServiceImpl.groovy │ │ │ ├── RegistryTokenStore.groovy │ │ │ └── RegistryUtils.groovy │ │ │ ├── configuration │ │ │ ├── BlobCacheConfig.groovy │ │ │ ├── BuildConfig.groovy │ │ │ ├── HttpClientConfig.groovy │ │ │ ├── JobManagerConfig.groovy │ │ │ ├── LimitConfig.groovy │ │ │ ├── MirrorConfig.groovy │ │ │ ├── ProxyCacheConfig.groovy │ │ │ ├── RateLimitConverter.groovy │ │ │ ├── RateLimiterConfig.groovy │ │ │ ├── RedisConfig.groovy │ │ │ ├── ScanConfig.groovy │ │ │ └── TokenConfig.groovy │ │ │ ├── controller │ │ │ ├── BuildController.groovy │ │ │ ├── ContainerController.groovy │ │ │ ├── ErrorController.groovy │ │ │ ├── InspectController.groovy │ │ │ ├── MetricsController.groovy │ │ │ ├── MirrorController.groovy │ │ │ ├── RegistryProxyController.groovy │ │ │ ├── ScanController.groovy │ │ │ ├── ServiceInfoController.groovy │ │ │ ├── ValidateController.groovy │ │ │ ├── ValidateRegistryCredsRequest.groovy │ │ │ └── ViewController.groovy │ │ │ ├── core │ │ │ ├── ContainerAugmenter.groovy │ │ │ ├── ContainerDigestPair.groovy │ │ │ ├── ContainerPath.groovy │ │ │ ├── ContainerPlatform.groovy │ │ │ ├── RegistryProxyService.groovy │ │ │ ├── RouteHandler.groovy │ │ │ └── RoutePath.groovy │ │ │ ├── cron │ │ │ └── ThreadMonitorCron.groovy │ │ │ ├── encoder │ │ │ ├── ByteArrayAdapter.groovy │ │ │ ├── DateTimeAdapter.groovy │ │ │ ├── EncodingStrategy.groovy │ │ │ ├── MoshiEncodeStrategy.groovy │ │ │ ├── MoshiSerializable.groovy │ │ │ ├── PathAdapter.groovy │ │ │ └── UriAdapter.groovy │ │ │ ├── exception │ │ │ ├── BadRequestException.groovy │ │ │ ├── BuildRuntimeException.groovy │ │ │ ├── BuildTimeoutException.groovy │ │ │ ├── DockerRegistryException.groovy │ │ │ ├── ForbiddenException.groovy │ │ │ ├── HttpError.groovy │ │ │ ├── HttpResponseException.groovy │ │ │ ├── HttpServerRetryableErrorException.groovy │ │ │ ├── NoSenderAvailException.groovy │ │ │ ├── NotFoundException.groovy │ │ │ ├── RegistryForwardException.groovy │ │ │ ├── RegistryUnauthorizedAccessException.groovy │ │ │ ├── ScanRuntimeException.groovy │ │ │ ├── SlowDownException.groovy │ │ │ ├── UnauthorizedException.groovy │ │ │ └── WaveException.groovy │ │ │ ├── exchange │ │ │ ├── DescribeWaveContainerResponse.groovy │ │ │ ├── EmptyBodyRequest.groovy │ │ │ ├── ErrorResponse.groovy │ │ │ ├── PairingRequest.groovy │ │ │ ├── PairingResponse.groovy │ │ │ └── RegistryErrorResponse.groovy │ │ │ ├── filter │ │ │ ├── DenyCrawlerFilter.groovy │ │ │ ├── DenyPathsFilter.groovy │ │ │ ├── FilterOrder.groovy │ │ │ ├── MetricsQueryParamValidationFilter.groovy │ │ │ ├── PullMetricsRequestsFilter.groovy │ │ │ ├── RateLimiterFilter.groovy │ │ │ ├── RateLimiterOptions.groovy │ │ │ ├── TraceContextFilter.groovy │ │ │ ├── TraceSlowEndpointFilter.java │ │ │ └── TraceSlowEndpointPublisher.java │ │ │ ├── http │ │ │ └── HttpClientFactory.groovy │ │ │ ├── metrics │ │ │ └── ExecutorsMetricsBinder.groovy │ │ │ ├── model │ │ │ └── ContainerCoordinates.groovy │ │ │ ├── proxy │ │ │ ├── ClientResponseException.groovy │ │ │ ├── DelegateResponse.groovy │ │ │ ├── ErrResponse.groovy │ │ │ ├── LoginRequest.groovy │ │ │ ├── LoginResponse.groovy │ │ │ ├── ProxyCache.groovy │ │ │ └── ProxyClient.groovy │ │ │ ├── ratelimit │ │ │ ├── AcquireRequest.groovy │ │ │ ├── RateLimiterService.groovy │ │ │ └── impl │ │ │ │ ├── SpillWayStorageFactory.groovy │ │ │ │ └── SpillwayRateLimiter.groovy │ │ │ ├── redis │ │ │ ├── JedisPoolMetricsBinder.groovy │ │ │ └── RedisFactory.groovy │ │ │ ├── service │ │ │ ├── ContainerRegistryKeys.groovy │ │ │ ├── CredentialServiceImpl.groovy │ │ │ ├── CredentialsService.groovy │ │ │ ├── UserService.groovy │ │ │ ├── UserServiceImpl.groovy │ │ │ ├── account │ │ │ │ ├── AccountService.groovy │ │ │ │ └── AccountServiceImpl.groovy │ │ │ ├── aws │ │ │ │ ├── AwsEcrAuthException.groovy │ │ │ │ ├── AwsEcrService.groovy │ │ │ │ ├── AwsMailProvider.groovy │ │ │ │ ├── ObjectStorageOperationsFactory.groovy │ │ │ │ ├── S3ClientFactory.groovy │ │ │ │ └── cache │ │ │ │ │ ├── AwsEcrAuthToken.groovy │ │ │ │ │ └── AwsEcrCache.groovy │ │ │ ├── blob │ │ │ │ ├── BlobCacheService.groovy │ │ │ │ ├── BlobEntry.groovy │ │ │ │ ├── BlobSigningService.groovy │ │ │ │ ├── BlobStateStore.groovy │ │ │ │ ├── BlobStoreImpl.groovy │ │ │ │ ├── TransferStrategy.groovy │ │ │ │ ├── impl │ │ │ │ │ ├── AwsS3PresignerFactory.groovy │ │ │ │ │ ├── BlobCacheServiceImpl.groovy │ │ │ │ │ ├── DockerTransferStrategy.groovy │ │ │ │ │ └── KubeTransferStrategy.groovy │ │ │ │ └── signing │ │ │ │ │ ├── AwsS3BlobSigningService.groovy │ │ │ │ │ ├── CloudflareBlobSigningService.groovy │ │ │ │ │ └── NoBlobSigningService.groovy │ │ │ ├── builder │ │ │ │ ├── BuildCounterStore.groovy │ │ │ │ ├── BuildEntry.groovy │ │ │ │ ├── BuildEvent.groovy │ │ │ │ ├── BuildFormat.groovy │ │ │ │ ├── BuildRequest.groovy │ │ │ │ ├── BuildResult.groovy │ │ │ │ ├── BuildStateStore.groovy │ │ │ │ ├── BuildStrategy.groovy │ │ │ │ ├── BuildTrack.groovy │ │ │ │ ├── ContainerBuildService.groovy │ │ │ │ ├── DockerBuildStrategy.groovy │ │ │ │ ├── FreezeService.groovy │ │ │ │ ├── FreezeServiceImpl.groovy │ │ │ │ ├── KubeBuildStrategy.groovy │ │ │ │ └── impl │ │ │ │ │ ├── BuildStateStoreImpl.groovy │ │ │ │ │ └── ContainerBuildServiceImpl.groovy │ │ │ ├── cleanup │ │ │ │ ├── CleanupConfig.groovy │ │ │ │ ├── CleanupService.groovy │ │ │ │ ├── CleanupServiceImpl.groovy │ │ │ │ ├── CleanupStore.groovy │ │ │ │ └── CleanupStrategy.groovy │ │ │ ├── counter │ │ │ │ ├── AbstractCounterStore.groovy │ │ │ │ ├── CounterStore.groovy │ │ │ │ └── impl │ │ │ │ │ ├── CounterProvider.groovy │ │ │ │ │ ├── LocalCounterProvider.groovy │ │ │ │ │ └── RedisCounterProvider.groovy │ │ │ ├── data │ │ │ │ ├── future │ │ │ │ │ ├── AbstractFutureStore.groovy │ │ │ │ │ ├── FutureHash.groovy │ │ │ │ │ ├── FutureStore.groovy │ │ │ │ │ └── impl │ │ │ │ │ │ ├── LocalFutureHash.groovy │ │ │ │ │ │ └── RedisFutureHash.groovy │ │ │ │ ├── queue │ │ │ │ │ ├── AbstractMessageQueue.groovy │ │ │ │ │ ├── MessageQueue.groovy │ │ │ │ │ └── impl │ │ │ │ │ │ ├── LocalMessageQueue.groovy │ │ │ │ │ │ └── RedisMessageQueue.groovy │ │ │ │ └── stream │ │ │ │ │ ├── AbstractMessageStream.groovy │ │ │ │ │ ├── MessageConsumer.groovy │ │ │ │ │ ├── MessageStream.groovy │ │ │ │ │ └── impl │ │ │ │ │ ├── LocalMessageStream.groovy │ │ │ │ │ └── RedisMessageStream.groovy │ │ │ ├── inclusion │ │ │ │ ├── ContainerInclusionImpl.groovy │ │ │ │ └── ContainerInclusionService.groovy │ │ │ ├── inspect │ │ │ │ ├── ContainerInspectService.groovy │ │ │ │ └── ContainerInspectServiceImpl.groovy │ │ │ ├── job │ │ │ │ ├── JobDispatcher.groovy │ │ │ │ ├── JobEntry.groovy │ │ │ │ ├── JobFactory.groovy │ │ │ │ ├── JobHandler.groovy │ │ │ │ ├── JobHelper.groovy │ │ │ │ ├── JobManager.groovy │ │ │ │ ├── JobOperation.groovy │ │ │ │ ├── JobPendingQueue.groovy │ │ │ │ ├── JobProcessingQueue.groovy │ │ │ │ ├── JobService.groovy │ │ │ │ ├── JobServiceImpl.groovy │ │ │ │ ├── JobSpec.groovy │ │ │ │ ├── JobState.groovy │ │ │ │ └── impl │ │ │ │ │ ├── DockerJobOperation.groovy │ │ │ │ │ └── K8sJobOperation.groovy │ │ │ ├── k8s │ │ │ │ ├── K8sClient.groovy │ │ │ │ ├── K8sClusterClient.groovy │ │ │ │ ├── K8sConfigClient.groovy │ │ │ │ ├── K8sService.groovy │ │ │ │ └── K8sServiceImpl.groovy │ │ │ ├── license │ │ │ │ ├── CheckTokenResponse.groovy │ │ │ │ ├── LicenceManRetryPredicate.groovy │ │ │ │ └── LicenseManClient.groovy │ │ │ ├── logs │ │ │ │ ├── BuildLogService.groovy │ │ │ │ └── BuildLogServiceImpl.groovy │ │ │ ├── mail │ │ │ │ ├── MailService.groovy │ │ │ │ ├── MailSpooler.groovy │ │ │ │ └── impl │ │ │ │ │ ├── MailServiceImpl.groovy │ │ │ │ │ └── MailSpoolerImpl.groovy │ │ │ ├── metric │ │ │ │ ├── MetricsConstants.groovy │ │ │ │ ├── MetricsCounterStore.groovy │ │ │ │ ├── MetricsService.groovy │ │ │ │ ├── impl │ │ │ │ │ └── MetricsServiceImpl.groovy │ │ │ │ └── model │ │ │ │ │ ├── GetOrgArchCountResponse.groovy │ │ │ │ │ └── GetOrgCountResponse.groovy │ │ │ ├── mirror │ │ │ │ ├── ContainerMirrorService.groovy │ │ │ │ ├── ContainerMirrorServiceImpl.groovy │ │ │ │ ├── MirrorEntry.groovy │ │ │ │ ├── MirrorRequest.groovy │ │ │ │ ├── MirrorResult.groovy │ │ │ │ ├── MirrorStateStore.groovy │ │ │ │ └── strategy │ │ │ │ │ ├── DockerMirrorStrategy.groovy │ │ │ │ │ ├── KubeMirrorStrategy.groovy │ │ │ │ │ └── MirrorStrategy.groovy │ │ │ ├── pairing │ │ │ │ ├── PairingRecord.groovy │ │ │ │ ├── PairingService.groovy │ │ │ │ ├── PairingServiceImpl.groovy │ │ │ │ ├── PairingStore.groovy │ │ │ │ └── socket │ │ │ │ │ ├── MessageSender.groovy │ │ │ │ │ ├── PairingChannel.groovy │ │ │ │ │ ├── PairingInboundStore.groovy │ │ │ │ │ ├── PairingOutboundQueue.groovy │ │ │ │ │ ├── PairingWebSocket.groovy │ │ │ │ │ └── msg │ │ │ │ │ ├── PairingHeartbeat.groovy │ │ │ │ │ ├── PairingMessage.groovy │ │ │ │ │ ├── PairingResponse.groovy │ │ │ │ │ ├── ProxyHttpRequest.groovy │ │ │ │ │ └── ProxyHttpResponse.groovy │ │ │ ├── persistence │ │ │ │ ├── PersistenceService.groovy │ │ │ │ ├── PostgresIgnore.groovy │ │ │ │ ├── WaveBuildRecord.groovy │ │ │ │ ├── WaveContainerRecord.groovy │ │ │ │ ├── WaveScanRecord.groovy │ │ │ │ ├── impl │ │ │ │ │ ├── LocalPersistenceService.groovy │ │ │ │ │ ├── RetryOnIOException.groovy │ │ │ │ │ ├── SurrealClient.groovy │ │ │ │ │ ├── SurrealPersistenceService.groovy │ │ │ │ │ └── SurrealResult.groovy │ │ │ │ ├── migrate │ │ │ │ │ ├── DataMigrationService.groovy │ │ │ │ │ ├── MigrationOnly.groovy │ │ │ │ │ └── cache │ │ │ │ │ │ ├── DataMigrateCache.groovy │ │ │ │ │ │ └── DataMigrateEntry.groovy │ │ │ │ └── postgres │ │ │ │ │ ├── Mapper.groovy │ │ │ │ │ ├── PostgresPersistentService.groovy │ │ │ │ │ ├── PostgresSchemaService.groovy │ │ │ │ │ └── data │ │ │ │ │ ├── BuildRepository.groovy │ │ │ │ │ ├── BuildRow.groovy │ │ │ │ │ ├── MirrorRepository.groovy │ │ │ │ │ ├── MirrorRow.groovy │ │ │ │ │ ├── RequestRepository.groovy │ │ │ │ │ ├── RequestRow.groovy │ │ │ │ │ ├── ScanRepository.groovy │ │ │ │ │ └── ScanRow.groovy │ │ │ ├── request │ │ │ │ ├── ContainerRequest.groovy │ │ │ │ ├── ContainerRequestService.groovy │ │ │ │ ├── ContainerRequestServiceImpl.groovy │ │ │ │ ├── ContainerRequestStore.groovy │ │ │ │ ├── ContainerRequestStoreImpl.groovy │ │ │ │ ├── ContainerState.groovy │ │ │ │ ├── ContainerStatusService.groovy │ │ │ │ ├── ContainerStatusServiceImpl.groovy │ │ │ │ └── TokenData.groovy │ │ │ ├── scan │ │ │ │ ├── ContainerScanService.groovy │ │ │ │ ├── ContainerScanServiceImpl.groovy │ │ │ │ ├── DockerScanStrategy.groovy │ │ │ │ ├── KubeScanStrategy.groovy │ │ │ │ ├── ScanEntry.groovy │ │ │ │ ├── ScanId.groovy │ │ │ │ ├── ScanIdStore.groovy │ │ │ │ ├── ScanRequest.groovy │ │ │ │ ├── ScanStateStore.groovy │ │ │ │ ├── ScanStrategy.groovy │ │ │ │ ├── ScanVulnerability.groovy │ │ │ │ ├── Trivy.groovy │ │ │ │ └── TrivyResultProcessor.groovy │ │ │ ├── stream │ │ │ │ ├── StreamService.groovy │ │ │ │ └── StreamServiceImpl.groovy │ │ │ └── validation │ │ │ │ ├── ValidationService.groovy │ │ │ │ ├── ValidationServiceImpl.groovy │ │ │ │ └── ValidationServiceProd.groovy │ │ │ ├── storage │ │ │ ├── DigestStore.java │ │ │ ├── DigestStoreFactory.java │ │ │ ├── DockerDigestStore.java │ │ │ ├── HttpDigestStore.java │ │ │ ├── ManifestCacheStore.groovy │ │ │ ├── Storage.java │ │ │ └── ZippedDigestStore.java │ │ │ ├── store │ │ │ ├── cache │ │ │ │ ├── AbstractTieredCache.groovy │ │ │ │ ├── L2TieredCache.groovy │ │ │ │ ├── RedisL2TieredCache.groovy │ │ │ │ ├── TieredCache.groovy │ │ │ │ └── TieredKey.groovy │ │ │ ├── range │ │ │ │ ├── AbstractRangeStore.groovy │ │ │ │ ├── RangeStore.groovy │ │ │ │ └── impl │ │ │ │ │ ├── LocalRangeProvider.groovy │ │ │ │ │ ├── RangeProvider.groovy │ │ │ │ │ └── RedisRangeProvider.groovy │ │ │ └── state │ │ │ │ ├── AbstractStateStore.groovy │ │ │ │ ├── CountParams.groovy │ │ │ │ ├── CountResult.groovy │ │ │ │ ├── RequestIdAware.groovy │ │ │ │ ├── StateEntry.groovy │ │ │ │ ├── StateStore.groovy │ │ │ │ └── impl │ │ │ │ ├── LocalStateProvider.groovy │ │ │ │ ├── RedisStateProvider.groovy │ │ │ │ └── StateProvider.groovy │ │ │ ├── tower │ │ │ ├── PlatformId.groovy │ │ │ ├── User.groovy │ │ │ ├── auth │ │ │ │ ├── JwtAuth.groovy │ │ │ │ ├── JwtAuthStore.groovy │ │ │ │ ├── JwtConfig.groovy │ │ │ │ ├── JwtMonitor.groovy │ │ │ │ └── JwtTimeStore.groovy │ │ │ ├── client │ │ │ │ ├── CredentialsDescription.groovy │ │ │ │ ├── GetCredentialsKeysResponse.groovy │ │ │ │ ├── GetServiceInfoResponse.groovy │ │ │ │ ├── GetUserInfoResponse.groovy │ │ │ │ ├── ListCredentialsResponse.groovy │ │ │ │ ├── TowerClient.groovy │ │ │ │ ├── cache │ │ │ │ │ └── ClientCache.groovy │ │ │ │ └── connector │ │ │ │ │ ├── HttpTowerConnector.groovy │ │ │ │ │ ├── JwtRefreshParams.groovy │ │ │ │ │ ├── TowerConnector.groovy │ │ │ │ │ └── WebSocketTowerConnector.groovy │ │ │ └── compute │ │ │ │ ├── ComputeEnv.groovy │ │ │ │ ├── DescribeWorkflowLaunchResponse.groovy │ │ │ │ └── WorkflowLaunch.groovy │ │ │ └── util │ │ │ ├── BucketTokenizer.groovy │ │ │ ├── BuildInfo.groovy │ │ │ ├── ContainerConfigFactory.groovy │ │ │ ├── ContainerHelper.groovy │ │ │ ├── CryptoHelper.groovy │ │ │ ├── CustomThreadFactory.groovy │ │ │ ├── DurationUtils.groovy │ │ │ ├── Escape.groovy │ │ │ ├── ExponentialAttempt.groovy │ │ │ ├── FusionVersionStringDeserializer.groovy │ │ │ ├── FutureUtils.groovy │ │ │ ├── JacksonHelper.groovy │ │ │ ├── K8sHelper.groovy │ │ │ ├── LoggerLevelFilter.java │ │ │ ├── NameVersionPair.groovy │ │ │ ├── RegHelper.groovy │ │ │ ├── Retryable.groovy │ │ │ ├── RuntimeInfo.groovy │ │ │ ├── StringUtils.groovy │ │ │ ├── TypeHelper.groovy │ │ │ └── Views.groovy │ ├── jib │ │ └── launch.sh │ └── resources │ │ ├── application-blobcache-dev.yml │ │ ├── application-buildlogs-aws-test.yml │ │ ├── application-dev-k8s.yml │ │ ├── application-dev.yml │ │ ├── application-licman.yml │ │ ├── application-mysql.yml │ │ ├── application-postgres.yml │ │ ├── application-prometheus.yml │ │ ├── application-rate-limit.yml │ │ ├── application-redis.yml │ │ ├── application-reserved-words.yml │ │ ├── application-surrealdb-legacy.yml │ │ ├── application-surrealdb.yml │ │ ├── application.yml │ │ ├── bootstrap-ec2.yml │ │ ├── bootstrap.yml │ │ ├── io │ │ └── seqera │ │ │ └── wave │ │ │ ├── assets │ │ │ ├── robots.txt │ │ │ ├── seqera-logo.png │ │ │ ├── wave-logo.png │ │ │ └── wave.ico │ │ │ ├── build-list.hbs │ │ │ ├── build-notification.html │ │ │ ├── build-view.hbs │ │ │ ├── container-view.hbs │ │ │ ├── inspect-view.hbs │ │ │ ├── mirror-view.hbs │ │ │ ├── scan-list.hbs │ │ │ └── scan-view.hbs │ │ └── logback.xml └── test │ ├── groovy │ ├── io │ │ └── seqera │ │ │ └── wave │ │ │ ├── ContainerConfigTest.groovy │ │ │ ├── auth │ │ │ ├── MissingCredentialsTest.groovy │ │ │ ├── RegistryAuthServiceTest.groovy │ │ │ ├── RegistryAuthTest.groovy │ │ │ ├── RegistryCredentialsFactoryImplTest.groovy │ │ │ ├── RegistryCredentialsProviderTest.groovy │ │ │ ├── RegistryInfoTest.groovy │ │ │ ├── RegistryLookupCacheTest.groovy │ │ │ ├── RegistryLookupServiceTest.groovy │ │ │ └── RegistryTokenStoreTest.groovy │ │ │ ├── configuration │ │ │ ├── BlobCacheConfigTest.groovy │ │ │ └── ScanConfigTest.groovy │ │ │ ├── controller │ │ │ ├── BuildConfigTest.groovy │ │ │ ├── BuildControllerTest.groovy │ │ │ ├── ContainerControllerHttpTest.groovy │ │ │ ├── ContainerControllerTest.groovy │ │ │ ├── CustomImageControllerTest.groovy │ │ │ ├── ErrorHandlingTest.groovy │ │ │ ├── InspectControllerTest.groovy │ │ │ ├── MetricsControllerTest.groovy │ │ │ ├── RegistryControllerLocalTest.groovy │ │ │ ├── RegistryControllerLookupFailureTest.groovy │ │ │ ├── RegistryControllerPullLimitTest.groovy │ │ │ ├── RegistryControllerRedisTest.groovy │ │ │ ├── ScanControllerTest.groovy │ │ │ ├── ServiceInfoControllerTest.groovy │ │ │ ├── ValidateCredsControllerTest.groovy │ │ │ └── ViewControllerTest.groovy │ │ │ ├── core │ │ │ ├── ContainerAugmenterTest.groovy │ │ │ ├── ContainerPathTest.groovy │ │ │ ├── ContainerPlatformTest.groovy │ │ │ ├── RegistryProxyServiceTest.groovy │ │ │ ├── RouteHandlerTest.groovy │ │ │ └── RoutePathTest.groovy │ │ │ ├── cron │ │ │ └── ThreadMonitorCronTest.groovy │ │ │ ├── encoder │ │ │ └── MoshiEncodingStrategyTest.groovy │ │ │ ├── exchange │ │ │ ├── BuildStatusResponseTest.groovy │ │ │ └── RegistryErrorResponseTest.groovy │ │ │ ├── filter │ │ │ ├── DenyCrawlerFilterTest.groovy │ │ │ ├── DenyPathsFilterTest.groovy │ │ │ ├── PullMetricsRequestsFilterTest.groovy │ │ │ └── TraceContextFilterTest.groovy │ │ │ ├── model │ │ │ └── ContainerCoordinatesTest.groovy │ │ │ ├── proxy │ │ │ ├── ProxyCacheTest.groovy │ │ │ ├── ProxyClientTest.groovy │ │ │ └── ProxyClientWithLocalRegistryTest.groovy │ │ │ ├── ratelimit │ │ │ ├── BuildServiceRateLimitTest.groovy │ │ │ ├── SpillwayMemoryRateLimiterTest.groovy │ │ │ ├── SpillwayRedisRateLimiterTest.groovy │ │ │ └── SpillwayRegistryControllerTest.groovy │ │ │ ├── redis │ │ │ └── RedisFactoryTest.groovy │ │ │ ├── service │ │ │ ├── CredentialsServiceTest.groovy │ │ │ ├── UserServiceTest.groovy │ │ │ ├── account │ │ │ │ └── AccountServiceTest.groovy │ │ │ ├── aws │ │ │ │ ├── AwsEcrServiceTest.groovy │ │ │ │ └── cache │ │ │ │ │ └── AwsEcrCacheTest.groovy │ │ │ ├── blob │ │ │ │ ├── BlobCacheInfoTest.groovy │ │ │ │ ├── BlobStateStoreImplTest.groovy │ │ │ │ ├── impl │ │ │ │ │ ├── BlobCacheServiceImplTest.groovy │ │ │ │ │ ├── BlobCacheServiceImplTest2.groovy │ │ │ │ │ ├── DockerTransferStrategyTest.groovy │ │ │ │ │ └── KubeTransferStrategyTest.groovy │ │ │ │ └── signing │ │ │ │ │ └── AwsS3BlobSigningServiceTest.groovy │ │ │ ├── builder │ │ │ │ ├── BuildEntryTest.groovy │ │ │ │ ├── BuildRequestTest.groovy │ │ │ │ ├── BuildResultTest.groovy │ │ │ │ ├── BuildStateStoreImplTest.groovy │ │ │ │ ├── BuildStoreLocalTest.groovy │ │ │ │ ├── BuildStoreRedisTest.groovy │ │ │ │ ├── BuildStrategyTest.groovy │ │ │ │ ├── ContainerBuildServiceLiveTest.groovy │ │ │ │ ├── ContainerBuildServiceTest.groovy │ │ │ │ ├── DockerBuildStrategyTest.groovy │ │ │ │ ├── FreezeServiceImplTest.groovy │ │ │ │ └── KubeBuildStrategyTest.groovy │ │ │ ├── cleanup │ │ │ │ ├── CleanupConfigTest.groovy │ │ │ │ ├── CleanupServiceTest.groovy │ │ │ │ └── CleanupStrategyTest.groovy │ │ │ ├── counter │ │ │ │ └── impl │ │ │ │ │ ├── LocalCounterProviderTest.groovy │ │ │ │ │ └── RedisCounterProviderTest.groovy │ │ │ ├── data │ │ │ │ ├── future │ │ │ │ │ ├── AbstractFutureStoreTest.groovy │ │ │ │ │ └── impl │ │ │ │ │ │ ├── LocalFutureHashTest.groovy │ │ │ │ │ │ └── RedisFutureHashTest.groovy │ │ │ │ ├── queue │ │ │ │ │ ├── AbstractMessageQueueLocalTest.groovy │ │ │ │ │ ├── AbstractMessageQueueRedisTest.groovy │ │ │ │ │ ├── LocalMessageQueueTest.groovy │ │ │ │ │ └── RedisMessageQueueTest.groovy │ │ │ │ └── stream │ │ │ │ │ ├── AbstractMessageStreamLocalTest.groovy │ │ │ │ │ ├── AbstractMessageStreamRedisTest.groovy │ │ │ │ │ ├── LocalMessageStreamTest.groovy │ │ │ │ │ ├── RedisMessageStreamTest.groovy │ │ │ │ │ ├── TestMessage.groovy │ │ │ │ │ └── TestStream.groovy │ │ │ ├── inclusion │ │ │ │ └── ContainerInclusionImplTest.groovy │ │ │ ├── inspect │ │ │ │ └── ContainerInspectServiceImplTest.groovy │ │ │ ├── job │ │ │ │ ├── JobFactoryTest.groovy │ │ │ │ ├── JobManagerTest.groovy │ │ │ │ ├── JobSpecTest.groovy │ │ │ │ ├── JobStateTest.groovy │ │ │ │ └── impl │ │ │ │ │ ├── DockerJobOperationTest.groovy │ │ │ │ │ └── K8SJobOperationTest.groovy │ │ │ ├── k8s │ │ │ │ └── K8sServiceImplTest.groovy │ │ │ ├── logs │ │ │ │ └── BuildLogsServiceTest.groovy │ │ │ ├── mail │ │ │ │ └── MailServiceImplTest.groovy │ │ │ ├── metric │ │ │ │ ├── MetricsCounterStoreLocalTest.groovy │ │ │ │ ├── MetricsCounterStoreRedisTest.groovy │ │ │ │ └── impl │ │ │ │ │ └── MetricsServiceImplTest.groovy │ │ │ ├── mirror │ │ │ │ ├── ContainerMirrorServiceTest.groovy │ │ │ │ ├── MirrorEntryTest.groovy │ │ │ │ ├── MirrorRequestTest.groovy │ │ │ │ ├── MirrorResultTest.groovy │ │ │ │ ├── MirrorStateStoreTest.groovy │ │ │ │ └── strategy │ │ │ │ │ ├── DockerMirrorStrategyTest.groovy │ │ │ │ │ └── MirrorStrategyTest.groovy │ │ │ ├── pairing │ │ │ │ ├── PairingServiceTest.groovy │ │ │ │ ├── PairingStoreTest.groovy │ │ │ │ └── PairingWebSocketTest.groovy │ │ │ ├── persistence │ │ │ │ ├── WaveBuildRecordTest.groovy │ │ │ │ ├── WaveContainerRecordTest.groovy │ │ │ │ ├── WaveScanRecordTest.groovy │ │ │ │ ├── impl │ │ │ │ │ └── SurrealPersistenceServiceTest.groovy │ │ │ │ ├── migrate │ │ │ │ │ ├── DataMigrationLockTest.groovy │ │ │ │ │ └── DataMigrationServiceTest.groovy │ │ │ │ └── postgres │ │ │ │ │ ├── MapperTest.groovy │ │ │ │ │ ├── PostgresPersistentServiceTest.groovy │ │ │ │ │ └── PostgresSchemaServiceTest.groovy │ │ │ ├── request │ │ │ │ ├── ContainerRequestServiceImplTest.groovy │ │ │ │ ├── ContainerRequestStoreImplTest.groovy │ │ │ │ ├── ContainerRequestTest.groovy │ │ │ │ ├── ContainerStatusServiceTest.groovy │ │ │ │ └── ContainerStatusTest.groovy │ │ │ ├── scan │ │ │ │ ├── ContainerScanServiceImplTest.groovy │ │ │ │ ├── ContainerScanStrategyTest.groovy │ │ │ │ ├── DockerScanStrategyTest.groovy │ │ │ │ ├── ScanEntryTest.groovy │ │ │ │ ├── ScanIdStoreLocalTest.groovy │ │ │ │ ├── ScanIdStoreRedisTest.groovy │ │ │ │ ├── ScanIdTest.groovy │ │ │ │ ├── ScanRequestTest.groovy │ │ │ │ ├── ScanStateStoreTest.groovy │ │ │ │ ├── ScanVulnerabilityTest.groovy │ │ │ │ └── TrivyResultProcessorTest.groovy │ │ │ ├── stream │ │ │ │ └── StreamServiceTest.groovy │ │ │ └── validation │ │ │ │ ├── ValidationServiceProdTest.groovy │ │ │ │ └── ValidationServiceTest.groovy │ │ │ ├── storage │ │ │ ├── DigestStoreFactoryTest.groovy │ │ │ ├── DockerDigestStoreTest.groovy │ │ │ ├── HttpDigestStoreTest.groovy │ │ │ ├── ManifestCacheStoreTest.groovy │ │ │ └── ZippedDigestStoreTest.groovy │ │ │ ├── store │ │ │ ├── cache │ │ │ │ ├── AbstractTieredCacheTest.groovy │ │ │ │ └── RedisL2TieredCacheTest.groovy │ │ │ ├── range │ │ │ │ ├── LocalRangeProviderTest.groovy │ │ │ │ └── RedisRangeProviderTest.groovy │ │ │ └── state │ │ │ │ ├── AbstractStateStoreTest.groovy │ │ │ │ ├── CountParamsTest.groovy │ │ │ │ └── impl │ │ │ │ ├── LocalStateProviderTest.groovy │ │ │ │ └── RedisStateProviderTest.groovy │ │ │ ├── test │ │ │ ├── AwsS3TestContainer.groovy │ │ │ ├── BaseTestContainerRegistry.groovy │ │ │ ├── DockerRegistryContainer.groovy │ │ │ ├── ManifestConst.groovy │ │ │ ├── RedisTestContainer.groovy │ │ │ ├── SecureDockerRegistryContainer.groovy │ │ │ ├── SurrealDBTestContainer.groovy │ │ │ └── TestHelper.groovy │ │ │ ├── tower │ │ │ ├── PlatformIdTest.groovy │ │ │ ├── auth │ │ │ │ ├── JwtAuthStoreTest.groovy │ │ │ │ ├── JwtAuthTest.groovy │ │ │ │ ├── JwtConfigTest.groovy │ │ │ │ ├── JwtTimeLocalTest.groovy │ │ │ │ └── JwtTimeRedisTest.groovy │ │ │ └── client │ │ │ │ ├── ListCredentialsDeserTest.groovy │ │ │ │ ├── TowerClientHttpTest.groovy │ │ │ │ ├── TowerClientTest.groovy │ │ │ │ ├── cache │ │ │ │ └── ClientCacheTest.groovy │ │ │ │ └── connector │ │ │ │ └── JwtRefreshParamsTest.groovy │ │ │ └── util │ │ │ ├── BucketTokenizerTest.groovy │ │ │ ├── BuildInfoTest.groovy │ │ │ ├── ContainerHelperTest.groovy │ │ │ ├── CryptoHelperTest.groovy │ │ │ ├── DurationUtilsTest.groovy │ │ │ ├── EscapeTest.groovy │ │ │ ├── ExponentialAttemptTest.groovy │ │ │ ├── FusionVersionStringDeserializerTest.groovy │ │ │ ├── K8sHelperTest.groovy │ │ │ ├── NameVersionPairTest.groovy │ │ │ ├── RegHelperTest.groovy │ │ │ ├── RetryableTest.groovy │ │ │ └── StringUtilsTest.groovy │ └── test │ │ └── RedisTestFactory.groovy │ └── resources │ ├── application-rate-limit.yml │ ├── application-test-deny-paths.yml │ ├── application-test.yml │ ├── foo │ ├── dummy.gzip │ ├── layer.json │ └── manifest_schema1.json │ ├── logback-test.xml │ ├── pack │ └── layers │ │ ├── layer.json │ │ ├── layer.tar │ │ └── layer.tar.gzip │ └── registry.password ├── tag-and-push.sh ├── test.sh └── typespec ├── Dockerfile ├── index.html ├── main.tsp ├── models ├── BuildStatusResponse.tsp ├── CondaOpts.tsp ├── CondaPackages.tsp ├── ContainerConfig.tsp ├── ContainerInspectConfig.tsp ├── ContainerInspectRequest.tsp ├── ContainerInspectResponse.tsp ├── ContainerLayer.tsp ├── ContainerMirrorResponse.tsp ├── ContainerPlatform.tsp ├── ContainerRequest.tsp ├── ContainerResponse.tsp ├── ContainerStatus.tsp ├── ContainerStatusResponse.tsp ├── Manifest.tsp ├── ManifestLayer.tsp ├── RootFS.tsp ├── ScanLevel.tsp ├── ScanMode.tsp ├── Status.tsp ├── User.tsp ├── ValidateRegistryCredsRequest.tsp ├── Vulnerability.tsp ├── WaveBuildRecord.tsp ├── WaveContainerRecord.tsp ├── WaveScanRecord.tsp └── models.tsp ├── package.json ├── routes.tsp ├── tag-and-push-openapi.sh └── tspconfig.yaml /.codespellignore: -------------------------------------------------------------------------------- 1 | carrer 2 | ser 3 | -------------------------------------------------------------------------------- /.github/actions/deploy/action.yml: -------------------------------------------------------------------------------- 1 | name: 'Deploy to cluster' 2 | inputs: 3 | app: 4 | required: true 5 | type: string 6 | container: 7 | required: true 8 | type: string 9 | namespace: 10 | required: true 11 | type: string 12 | aws-access-key-id: 13 | required: true 14 | type: string 15 | aws-secret-access-key: 16 | required: true 17 | type: string 18 | aws-region: 19 | required: true 20 | type: string 21 | kube-config-data: 22 | required: true 23 | type: string 24 | runs: 25 | using: "composite" 26 | steps: 27 | - name: Configure AWS credentials 28 | uses: aws-actions/configure-aws-credentials@v1 29 | with: 30 | aws-access-key-id: ${{ inputs.aws-access-key-id }} 31 | aws-secret-access-key: ${{ inputs.aws-secret-access-key }} 32 | aws-region: ${{ inputs.aws-region }} 33 | 34 | - name: Deploy to prod 35 | uses: kodermax/kubectl-aws-eks@master 36 | env: 37 | KUBE_CONFIG_DATA: ${{ inputs.kube-config-data }} 38 | with: 39 | args: set image deployment/${{inputs.app}} ${{inputs.app}}=${{inputs.container}}:$(cat VERSION) -n ${{inputs.namespace}} 40 | -------------------------------------------------------------------------------- /.github/actions/spelling/allow.txt: -------------------------------------------------------------------------------- 1 | NotIn 2 | -------------------------------------------------------------------------------- /.github/workflows/build-singularity.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish Singularity container image 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: 'Image version (e.g., 4.2.1-r4)' 8 | required: true 9 | default: '4.2.1-r4' 10 | 11 | jobs: 12 | build-and-push: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up Docker Buildx 19 | id: buildx 20 | uses: docker/setup-buildx-action@v3 21 | 22 | - name: Docker Login 23 | uses: docker/login-action@v3 24 | with: 25 | registry: public.cr.seqera.io 26 | username: ${{ vars.SEQERA_PUBLIC_CR_USERNAME }} 27 | password: ${{ secrets.SEQERA_PUBLIC_CR_PASSWORD }} 28 | 29 | - name: Build and Push Image to public.cr.seqera.io 30 | run: | 31 | cd singularity 32 | make build version=${{ github.event.inputs.version }} 33 | -------------------------------------------------------------------------------- /.github/workflows/codespell.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Codespell 3 | 4 | on: 5 | push: 6 | branches: [master] 7 | pull_request: 8 | branches: [master] 9 | 10 | permissions: 11 | contents: read 12 | 13 | jobs: 14 | codespell: 15 | name: Check for spelling errors 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | - name: Codespell 22 | uses: codespell-project/actions-codespell@v2 23 | with: 24 | only_warn: 1 25 | ignore_words_file: .codespellignore 26 | exclude_file: src/main/resources/application-reserved-words.yml 27 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml.bak: -------------------------------------------------------------------------------- 1 | name: Lint code 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | pre-commit: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-python@v3 12 | - uses: pre-commit/action@v3.0.0 13 | -------------------------------------------------------------------------------- /.github/workflows/security-submit-dependecy-graph.yml: -------------------------------------------------------------------------------- 1 | name: Generate and submit dependency graph for wave 2 | on: 3 | push: 4 | branches: ['master'] 5 | 6 | permissions: 7 | contents: write 8 | 9 | jobs: 10 | dependency-submission: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - uses: actions/setup-java@v4 15 | with: 16 | distribution: temurin 17 | java-version: 17 18 | 19 | - name: Generate and submit dependency graph for wave 20 | uses: gradle/actions/dependency-submission@v4 21 | with: 22 | dependency-resolution-task: "dependencies" 23 | additional-arguments: "--configuration runtimeClasspath" 24 | dependency-graph: generate-and-submit 25 | -------------------------------------------------------------------------------- /.github/workflows/typespec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Typespec_Validation 3 | 4 | on: 5 | push: 6 | branches: 7 | - '**' 8 | paths : 9 | - 'typespec/**' 10 | - VERSION 11 | pull_request: 12 | types: [opened, reopened, synchronize] 13 | paths: 14 | - 'typespec/**' 15 | - VERSION 16 | 17 | permissions: 18 | contents: read 19 | 20 | jobs: 21 | typespec_validation: 22 | name: validate typespec files 23 | runs-on: ubuntu-latest 24 | 25 | steps: 26 | - name : Checkout 27 | uses : actions/checkout@v4 28 | 29 | - name : Setup Node.js environment 30 | uses : actions/setup-node@v4 31 | with : 32 | node-version : '20.9.0' 33 | 34 | - name : Install tsp 35 | run : npm install -g @typespec/compiler@0.64.0 36 | 37 | - name : Validate tsp files 38 | run : | 39 | cd typespec 40 | tsp install 41 | tsp compile . 42 | 43 | - name: Configure AWS credentials 44 | uses: aws-actions/configure-aws-credentials@v1 45 | with: 46 | aws-access-key-id: ${{secrets.TOWER_CI_AWS_ACCESS}} 47 | aws-secret-access-key: ${{secrets.TOWER_CI_AWS_SECRET}} 48 | aws-region: eu-west-1 49 | 50 | - name : Login to Amazon ECR 51 | id : login-ecr 52 | uses : aws-actions/amazon-ecr-login@v1 53 | 54 | - name: Release OpenAPI docs 55 | if: "contains(github.event.head_commit.message, '[release]')" 56 | run: | 57 | bash typespec/tag-and-push-openapi.sh 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Thumbs.db 2 | .DS_Store 3 | .gradle 4 | .cache 5 | .nextflow* 6 | build/ 7 | packtar/ 8 | target/ 9 | out/ 10 | .idea 11 | *.iml 12 | *.ipr 13 | *.iws 14 | .nextflow* 15 | .project 16 | .settings 17 | .classpath 18 | .factorypath 19 | .layer/opt/fusion/fusionfs 20 | .layer/opt/goofys/goofys 21 | .layer/opt/geesefs 22 | .layer/opt/tini 23 | tower-reg.yml 24 | /wave.*.log 25 | wave.log 26 | build-workspace/ 27 | scan-workspace/ 28 | /k8s/dev/config-k3d.yml 29 | 30 | # Docs 31 | .vercel 32 | .cache 33 | site/ 34 | deployment-url.txt 35 | 36 | #typespec 37 | tsp-output/ 38 | node_modules/ 39 | package-lock.json 40 | 41 | # Seqera Docs clone 42 | seqeralabs-docs -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # Config for pre-commit: https://pre-commit.com/ 2 | --- 3 | minimum_pre_commit_version: "2.9.2" 4 | repos: 5 | - repo: meta 6 | hooks: 7 | - id: identity 8 | - id: check-hooks-apply 9 | 10 | - repo: https://github.com/pre-commit/mirrors-prettier 11 | rev: "v2.7.1" 12 | hooks: 13 | - id: prettier 14 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore everything 2 | /* 3 | 4 | # Except docs and markdown files 5 | !docs/ 6 | !*.md 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "useTabs": false 4 | } 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | config ?= runtimeClasspath 2 | 3 | ifdef module 4 | mm = :${module}: 5 | else 6 | mm = 7 | endif 8 | 9 | 10 | compile: 11 | ./gradlew assemble 12 | 13 | check: 14 | ./gradlew check 15 | 16 | image: 17 | ./gradlew jibDockerBuild 18 | 19 | push: 20 | # docker login 21 | docker login -u pditommaso -p ${DOCKER_PASSWORD} 22 | ./gradlew jib 23 | 24 | # 25 | # Show dependencies try `make deps config=runtime`, `make deps config=google` 26 | # 27 | deps: 28 | ./gradlew -q ${mm}dependencies --configuration ${config} 29 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.21.1 2 | -------------------------------------------------------------------------------- /buildSrc/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | plugins { 6 | // Support convention plugins written in Groovy. Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build. 7 | id 'groovy-gradle-plugin' 8 | } 9 | 10 | repositories { 11 | // Use the plugin portal to apply community plugins in convention plugins. 12 | gradlePluginPortal() 13 | } 14 | 15 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.seqera.wave.groovy-application-conventions.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | plugins { 6 | // Apply the common convention plugin for shared build configuration between library and application projects. 7 | id 'io.seqera.wave.groovy-common-conventions' 8 | 9 | // Apply the application plugin to add support for building a CLI application in Java. 10 | id 'application' 11 | } 12 | 13 | group = 'io.seqera' 14 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.seqera.wave.groovy-common-conventions.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | plugins { 6 | // Apply the groovy Plugin to add support for Groovy. 7 | id 'groovy' 8 | } 9 | 10 | repositories { 11 | // Use Maven Central for resolving dependencies. 12 | mavenCentral() 13 | } 14 | 15 | java { 16 | // these settings apply to all jvm tooling, including groovy 17 | toolchain { 18 | languageVersion = JavaLanguageVersion.of(21) 19 | } 20 | sourceCompatibility = 17 21 | targetCompatibility = 17 22 | } 23 | 24 | group = 'io.seqera' 25 | -------------------------------------------------------------------------------- /buildSrc/src/main/groovy/io.seqera.wave.groovy-library-conventions.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | */ 4 | 5 | plugins { 6 | // Apply the common convention plugin for shared build configuration between library and application projects. 7 | id 'io.seqera.wave.groovy-common-conventions' 8 | 9 | // Apply the java-library plugin for API and implementation separation. 10 | id 'java-library' 11 | // Micronaut minimal lib 12 | // https://micronaut-projects.github.io/micronaut-gradle-plugin/3.7.x/ 13 | id "io.micronaut.minimal.library" 14 | } 15 | 16 | micronaut { 17 | runtime("netty") 18 | testRuntime("spock2") 19 | processing { 20 | incremental(true) 21 | } 22 | } 23 | 24 | group = 'io.seqera' 25 | -------------------------------------------------------------------------------- /config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | wave: 3 | registries: 4 | default: docker.io 5 | docker.io: 6 | username: "${DOCKER_USER:}" 7 | password: "${DOCKER_PAT:}" 8 | quay.io: 9 | username: "${QUAY_USER:}" 10 | password: "${QUAY_PAT:}" 11 | 195996028523.dkr.ecr.eu-west-1.amazonaws.com: 12 | username : "${AWS_ACCESS_KEY_ID:}" 13 | password : "${AWS_SECRET_ACCESS_KEY:}" 14 | seqeralabs.azurecr.io: 15 | username : "${AZURECR_USER:}" 16 | password : "${AZURECR_PAT:}" 17 | ... 18 | -------------------------------------------------------------------------------- /container-request.json: -------------------------------------------------------------------------------- 1 | { 2 | "containerImage":"quay.io/nextflow/bash:latest", 3 | "containerConfig": { 4 | "layers": [ 5 | { 6 | "location": "https://s3.eu-west-1.amazonaws.com/nf-tower.dev/wave-layer.tar.gzip", 7 | "gzipDigest": "sha256:e9d6f29eecde29c12f0d32a1bc81aa9f4fcb76f8d813b8f1a37e8af5ee6b7657", 8 | "gzipSize": 13219265, 9 | "tarDigest": "sha256:2648cf125a9a4c4c5c9a2d3799b3a57983b5297442d7995746273c615bc4e316" 10 | } 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /debug.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Wave, containers provisioning service 3 | # Copyright (c) 2023-2024, Seqera Labs 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | export JVM_OPTS='-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8010' 20 | . ./run.sh 21 | -------------------------------------------------------------------------------- /docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Wave, containers provisioning service 4 | # Copyright (c) 2023-2024, Seqera Labs 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | docker run --rm -i -t -p 3000:3000 -v $PWD/docs:/home/node/app/docs \ 21 | cr.seqera.io/public/docs-previewer:latest 22 | -------------------------------------------------------------------------------- /docs/_images/wave_container_augmentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/docs/_images/wave_container_augmentation.png -------------------------------------------------------------------------------- /docs/_images/wave_container_build_failure_details.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/docs/_images/wave_container_build_failure_details.png -------------------------------------------------------------------------------- /docs/sidebar.json: -------------------------------------------------------------------------------- 1 | { 2 | "sidebar": [ 3 | { 4 | "type": "category", 5 | "label": "Wave", 6 | "collapsed": false, 7 | "items": [ 8 | "index", 9 | "get-started", 10 | "provisioning" 11 | ] 12 | }, 13 | "nextflow", 14 | { 15 | "type": "category", 16 | "label": "Developer tools", 17 | "collapsed": false, 18 | "items": [ 19 | "cli/index", 20 | "cli/reference", 21 | "api" 22 | ] 23 | }, 24 | "faq" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /docs/troubleshoot.mdx: -------------------------------------------------------------------------------- 1 | ## Troubleshoot guide 2 | 3 | 1. How to troubleshoot container build failure? 4 | 5 | If your container build fails, you can check the build details by checking the logs in build details email as shown in below screenshot. 6 | 7 | #### email screenshot: 8 | ![](_images/wave_container_build_failure_details.png) 9 | 10 | If there is nothing conclusive in logs, you can check the exit status, e.g. if it is 137 that means out of memory error. 11 | Wave run build process in kubernetes pod, you can check this [link](https://komodor.com/learn/exit-codes-in-containers-and-kubernetes-the-complete-guide/) for more details on exit codes. 12 | 13 | 2. How to solve buildkit error, while running wave build on docker desktop in mac os? 14 | 15 | #### error: 16 | ``` 17 | could not connect to unix:///run/user/1000/buildkit/buildkitd.sock after 10 trials 18 | ========== log ========== 19 | [rootlesskit:parent] error: failed to start the child: fork/exec /proc/self/exe: invalid argument 20 | sh: can't kill pid 14: No such process 21 | ``` 22 | 23 | #### Solution: 24 | - In case of wave cli use `--platform linux/arm64` flag with wave build command. 25 | - In case of API call use `containerPlatform: linux/arm64` in the request body. 26 | 27 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Wave, containers provisioning service 3 | # Copyright (c) 2023-2024, Seqera Labs 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | micronautVersion=4.8.2 20 | micronautEnvs=dev,mail,aws-ses 21 | -------------------------------------------------------------------------------- /gradle/config/groovyc.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | import groovy.transform.CompileStatic 20 | 21 | withConfig(configuration) { 22 | ast(CompileStatic) 23 | } 24 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /misc/image-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "architecture":"amd64", 3 | "config":{ 4 | "Hostname":"", 5 | "Domainname":"", 6 | "User":"", 7 | "AttachStdin":false, 8 | "AttachStdout":false, 9 | "AttachStderr":false, 10 | "Tty":false, 11 | "OpenStdin":false, 12 | "StdinOnce":false, 13 | "Env":[ 14 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 15 | ], 16 | "Cmd":[ 17 | "/bin/sh" 18 | ], 19 | "Image":"", 20 | "Volumes":null, 21 | "WorkingDir":"", 22 | "Entrypoint":null, 23 | "OnBuild":null, 24 | "Labels":{ 25 | 26 | } 27 | }, 28 | "container":"4be9f6b4406ec142e457fd7c43ff338511ab338b33585c30805ba2d5d3da29e3", 29 | "container_config":{ 30 | "Hostname":"4be9f6b4406e", 31 | "Domainname":"", 32 | "User":"", 33 | "AttachStdin":false, 34 | "AttachStdout":false, 35 | "AttachStderr":false, 36 | "Tty":false, 37 | "OpenStdin":false, 38 | "StdinOnce":false, 39 | "Env":[ 40 | "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" 41 | ], 42 | "Cmd":[ 43 | "/bin/sh" 44 | ], 45 | "Image":"bgruening/busybox-bash:0.1", 46 | "Volumes":null, 47 | "WorkingDir":"", 48 | "Entrypoint":null, 49 | "OnBuild":null, 50 | "Labels":{ 51 | 52 | } 53 | }, 54 | "created":"2020-01-24T15:39:30.564518517Z", 55 | "docker_version":"17.09.0-ce", 56 | "id":"f235879f79194a5e3d4b10c3b714c36669e8e98160ba73bd9b044fdec624ceaf", 57 | "os":"linux", 58 | "parent":"b7c0567175be2a551a8ed4e60d695d33347ebae5d8cfc4a5d0381e0ce3c34222" 59 | } 60 | -------------------------------------------------------------------------------- /misc/resp3.f54a58bc1aac5ea1a25d796ae155dc228b3f0e11d046ae276b39c4bf2f13d8c4.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 1469, 7 | "digest": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 2479, 13 | "digest": "sha256:2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /misc/resp3.formatted.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 2, 3 | "mediaType": "application/vnd.docker.distribution.manifest.v2+json", 4 | "config": { 5 | "mediaType": "application/vnd.docker.container.image.v1+json", 6 | "size": 1469, 7 | "digest": "sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412" 8 | }, 9 | "layers": [ 10 | { 11 | "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", 12 | "size": 2479, 13 | "digest": "sha256:2db29710123e3e53a794f2694094b9b4338aa9ee5c40b930cb8063a1be392c54" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /misc/resp4.feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412.json: -------------------------------------------------------------------------------- 1 | {"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/hello"],"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"8746661ca3c2f215da94e6d3f7dfdcafaff5ec0b21c9aff6af3dc379a82fbc72","container_config":{"Hostname":"8746661ca3c2","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"/hello\"]"],"Image":"sha256:b9935d4e8431fb1a7f0989304ec86b3329a99a25f5efdc7f09f3f8c41434ca6d","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":{}},"created":"2021-09-23T23:47:57.442225064Z","docker_version":"20.10.7","history":[{"created":"2021-09-23T23:47:57.098990892Z","created_by":"/bin/sh -c #(nop) COPY file:50563a97010fd7ce1ceebd1fa4f4891ac3decdf428333fb2683696f4358af6c2 in / "},{"created":"2021-09-23T23:47:57.442225064Z","created_by":"/bin/sh -c #(nop) CMD [\"/hello\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359"]}} -------------------------------------------------------------------------------- /reg.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Wave, containers provisioning service 3 | # Copyright (c) 2023-2024, Seqera Labs 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | ngrok http 9090 -hostname reg.ngrok.io 20 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Wave, containers provisioning service 3 | # Copyright (c) 2023-2024, Seqera Labs 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | mv wave.log wave.log.bak 20 | export AWS_REGION=${AWS_REGION:-'eu-west-1'} 21 | ./gradlew run --continuous --watch-fs 22 | -------------------------------------------------------------------------------- /s5cmd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | ARG version 3 | ADD dist.sh /dist.sh 4 | RUN apt update && apt install -y curl tar \ 5 | && curl -L $(sh -x /dist.sh ${version}) | tar -zx \ 6 | && cp s5cmd /usr/local/bin/s5cmd \ 7 | 8 | -------------------------------------------------------------------------------- /s5cmd/Makefile: -------------------------------------------------------------------------------- 1 | version ?= 2.2.2 2 | 3 | build: 4 | docker buildx build \ 5 | --push \ 6 | --platform linux/amd64,linux/arm64 \ 7 | --build-arg version=${version} \ 8 | --tag public.cr.seqera.io/wave/s5cmd:v${version} \ 9 | . 10 | -------------------------------------------------------------------------------- /s5cmd/dist.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Wave, containers provisioning service 5 | # Copyright (c) 2023-2024, Seqera Labs 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Affero General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU Affero General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU Affero General Public License 18 | # along with this program. If not, see . 19 | # 20 | 21 | arch=$(uname -m) 22 | 23 | case $arch in 24 | x86_64|amd64) 25 | echo "https://github.com/peak/s5cmd/releases/download/v$1/s5cmd_$1_Linux-64bit.tar.gz" 26 | ;; 27 | aarch64|arm64) 28 | echo "https://github.com/peak/s5cmd/releases/download/v$1/s5cmd_$1_Linux-arm64.tar.gz" 29 | ;; 30 | *) 31 | echo "Unknown architecture: $arch" 32 | ;; 33 | esac 34 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | // required to download the toolchain (jdk) from a remote repository 3 | // https://github.com/gradle/foojay-toolchains 4 | // https://docs.gradle.org/current/userguide/toolchains.html#sub:download_repositories 5 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0" 6 | } 7 | 8 | rootProject.name="wave" 9 | 10 | // only for development 11 | // clone https://github.com/seqeralabs/libseqera 12 | // in a sibling directory and include the build below 13 | //includeBuild('../libseqera') 14 | -------------------------------------------------------------------------------- /singularity/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.21.3 2 | ARG version 3 | RUN apk update 4 | RUN apk add singularity=${version} 5 | RUN apk add proot-static --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing/ 6 | 7 | RUN ln -s /usr/bin/proot.static /usr/bin/proot 8 | 9 | RUN addgroup -g 1000 builder 10 | 11 | RUN adduser \ 12 | -D \ 13 | -u 1000 \ 14 | -G builder \ 15 | -h /home/builder \ 16 | -s /bin/sh \ 17 | builder 18 | 19 | USER builder 20 | -------------------------------------------------------------------------------- /singularity/Makefile: -------------------------------------------------------------------------------- 1 | version ?= 4.2.1-r4 2 | 3 | build: 4 | docker buildx build \ 5 | --push \ 6 | --platform linux/amd64,linux/arm64 \ 7 | --build-arg version=${version} \ 8 | --tag public.cr.seqera.io/wave/singularity:v${version} \ 9 | . 10 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/auth/RegistryCredentials.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.auth 20 | 21 | /** 22 | * Simple container registry credentials interface 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface RegistryCredentials { 27 | 28 | String getUsername() 29 | String getPassword() 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/auth/RegistryCredentialsFactory.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.auth 20 | 21 | /** 22 | * Define service to create {@link RegistryCredentials} objects 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface RegistryCredentialsFactory { 27 | 28 | RegistryCredentials create(String registry, String userName, String password) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/auth/RegistryLookupException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.auth 20 | 21 | import groovy.transform.CompileStatic 22 | import io.seqera.wave.exception.WaveException 23 | /** 24 | * Generic registry authorization exception 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @CompileStatic 29 | class RegistryLookupException extends WaveException { 30 | RegistryLookupException(String message) { 31 | super(message) 32 | } 33 | 34 | RegistryLookupException(String message, Throwable t) { 35 | super(message, t) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/auth/RegistryLookupService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.auth 20 | 21 | /** 22 | * Lookup service for container registry 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface RegistryLookupService { 27 | 28 | /** 29 | * Given a registry name lookup for the corresponding 30 | * auth endpoint 31 | * 32 | * @param registry 33 | * The registry name e.g. {@code docker.io} or {@code quay.io} 34 | * @return The corresponding {@link RegistryAuth} object holding the realm URI and service info, 35 | * or {@code null} if nothing is found 36 | */ 37 | RegistryInfo lookup(String registry) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/auth/RegistryUtils.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.auth 20 | 21 | import java.net.http.HttpResponse 22 | 23 | import groovy.transform.CompileStatic 24 | import io.seqera.wave.WaveDefault 25 | /** 26 | * Utility class for registry functions 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @CompileStatic 31 | class RegistryUtils { 32 | 33 | static boolean isServerError(HttpResponse response) { 34 | response.statusCode() in WaveDefault.HTTP_SERVER_ERRORS 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/configuration/LimitConfig.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.configuration 20 | 21 | import java.time.Duration 22 | 23 | import groovy.transform.CompileStatic 24 | import groovy.transform.ToString 25 | /** 26 | * A simple bean to configure a max items per duration 27 | * 28 | * @author : jorge 29 | * 30 | */ 31 | @ToString(includePackage = false, includeNames = true) 32 | @CompileStatic 33 | class LimitConfig { 34 | int max 35 | Duration duration 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/configuration/RedisConfig.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.configuration 20 | 21 | import io.micronaut.context.annotation.ConfigurationProperties 22 | 23 | 24 | /** 25 | * Model Redis server configuration settings 26 | * 27 | * @author : jorge 28 | * 29 | */ 30 | @ConfigurationProperties('redis') 31 | interface RedisConfig { 32 | 33 | String getUri() 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/controller/ValidateRegistryCredsRequest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.controller 20 | 21 | import io.micronaut.core.annotation.Introspected 22 | import jakarta.validation.constraints.NotBlank 23 | 24 | @Introspected 25 | class ValidateRegistryCredsRequest { 26 | @NotBlank 27 | String userName 28 | @NotBlank 29 | String password 30 | @NotBlank 31 | String registry 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/core/ContainerDigestPair.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.core 20 | 21 | import groovy.transform.Canonical 22 | 23 | /** 24 | * Hold the container digest that originated the request and the 25 | * digest of the resolved container provisioned by wave 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @Canonical 30 | class ContainerDigestPair { 31 | /** 32 | * Digest of the source container image 33 | */ 34 | final String source 35 | 36 | /** 37 | * Digest of the augmented container image 38 | */ 39 | final String target 40 | } 41 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/encoder/ByteArrayAdapter.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.encoder 20 | 21 | import com.squareup.moshi.FromJson 22 | import com.squareup.moshi.ToJson 23 | import groovy.transform.CompileStatic 24 | 25 | /** 26 | * Moshi adapter for JSON serialization 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @CompileStatic 31 | class ByteArrayAdapter { 32 | 33 | @ToJson 34 | String serialize(byte[] data) { 35 | return Base64.getEncoder().encodeToString(data) 36 | } 37 | 38 | @FromJson 39 | byte[] deserialize(String data) { 40 | return Base64.getDecoder().decode(data) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/encoder/EncodingStrategy.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.encoder 20 | 21 | /** 22 | * Define JSON encode-decode core operations 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface EncodingStrategy { 27 | 28 | String encode(V value) 29 | 30 | V decode(String value) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/encoder/MoshiSerializable.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.encoder 20 | 21 | /** 22 | * Marker interface for Moshi serializable objects 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface MoshiSerializable { 27 | } 28 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/encoder/PathAdapter.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.encoder 20 | 21 | import java.nio.file.Path 22 | 23 | import com.squareup.moshi.FromJson 24 | import com.squareup.moshi.ToJson 25 | 26 | /** 27 | * Mosh adapter for {@link Path}. Only support default file system provider 28 | * 29 | * @author Paolo Di Tommaso 30 | */ 31 | class PathAdapter { 32 | 33 | @ToJson 34 | String serialize(Path path) { 35 | return path != null ? path.toString() : null 36 | } 37 | 38 | @FromJson 39 | Path deserialize(String data) { 40 | return data != null ? Path.of(data) : null 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/encoder/UriAdapter.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.encoder 20 | 21 | 22 | import com.squareup.moshi.FromJson 23 | import com.squareup.moshi.ToJson 24 | /** 25 | * Mosh adapter for {@link URI} class 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | class UriAdapter { 30 | 31 | @ToJson 32 | String serialize(URI uri) { 33 | return uri != null ? uri.toString() : null 34 | } 35 | 36 | @FromJson 37 | URI deserialize(String data) { 38 | return data != null ? URI.create(data) : null 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/BadRequestException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | /** 22 | * Base class for Wave exceptions 23 | */ 24 | class BadRequestException extends WaveException implements HttpError { 25 | 26 | BadRequestException() {} 27 | BadRequestException(String message) { super(message) } 28 | BadRequestException(String message, Throwable cause) { super(message, cause) } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/BuildRuntimeException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | /** 24 | * Exception thrown when the build fails for an expected condition 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @CompileStatic 29 | class BuildRuntimeException extends WaveException { 30 | 31 | BuildRuntimeException(String message, Throwable cause) { 32 | super(message, cause) 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/BuildTimeoutException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | 24 | /** 25 | * 26 | * Exception fired when the time to build an image is expired 27 | * 28 | * @author : jorge 29 | * 30 | */ 31 | @CompileStatic 32 | class BuildTimeoutException extends WaveException{ 33 | 34 | BuildTimeoutException(String message) { 35 | super(message) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/DockerRegistryException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | 22 | import groovy.transform.CompileStatic 23 | import groovy.util.logging.Slf4j 24 | import io.micronaut.http.HttpStatus 25 | /** 26 | * Hold a generic http error 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @Slf4j 31 | @CompileStatic 32 | class DockerRegistryException extends WaveException implements HttpError { 33 | 34 | final HttpStatus statusCode 35 | final String error 36 | 37 | DockerRegistryException(String message, int code, String error) { 38 | super(message) 39 | this.statusCode = HttpStatus.valueOf(code) 40 | this.error = error 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/ForbiddenException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | /** 24 | * Exception mapping to HTTP Forbidden error (403) 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @CompileStatic 29 | class ForbiddenException extends WaveException implements HttpError { 30 | 31 | ForbiddenException(String message) { 32 | super(message) 33 | } 34 | 35 | ForbiddenException(String message, Throwable cause) { 36 | super(message, cause) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/HttpError.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | /** 22 | * Marks exception used to return HTTP errors 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface HttpError { 27 | } 28 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/HttpServerRetryableErrorException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | /** 22 | * Capture a HTTP response error that should be manage retrying the HTTP request 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | class HttpServerRetryableErrorException extends IOException { 27 | 28 | HttpServerRetryableErrorException(String message) { 29 | super(message) 30 | } 31 | 32 | HttpServerRetryableErrorException(String message, Throwable t) { 33 | super(message,t) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/NoSenderAvailException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.InheritConstructors 22 | 23 | /** 24 | * Exception thrown when no sender is available for a Websocket target 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @InheritConstructors 29 | class NoSenderAvailException extends Exception { 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/NotFoundException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.InheritConstructors 23 | 24 | /** 25 | * Exception mapping to HTTP Not found error (404) 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @CompileStatic 30 | @InheritConstructors 31 | class NotFoundException extends WaveException implements HttpError { 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/ScanRuntimeException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | /** 24 | * Exception thrown when the scan fails for an expected condition 25 | * 26 | * @author Munish Chouhan 27 | */ 28 | @CompileStatic 29 | class ScanRuntimeException extends WaveException { 30 | ScanRuntimeException(String message, Throwable cause) { 31 | super(message, cause) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/SlowDownException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.InheritConstructors 23 | 24 | 25 | /** 26 | * @author : jorge 27 | * 28 | */ 29 | @CompileStatic 30 | @InheritConstructors 31 | class SlowDownException extends WaveException implements HttpError{ 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/UnauthorizedException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.InheritConstructors 23 | 24 | /** 25 | * Exception mapping to HTTP Unauthorized error (401) 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @CompileStatic 30 | @InheritConstructors 31 | class UnauthorizedException extends WaveException implements HttpError { 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exception/WaveException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exception 20 | /** 21 | * Marker interface to annotation exception bringing 22 | * a semantic message that can be visualised in the UI layer 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | abstract class WaveException extends RuntimeException { 27 | WaveException() {} 28 | 29 | WaveException(String message) { super(message) } 30 | 31 | WaveException(String message, Throwable cause) { super(message, cause) } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exchange/EmptyBodyRequest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exchange 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.TupleConstructor 23 | 24 | /** 25 | * Request with an empty body. To be OpenAPI complaint. 26 | * 27 | * @author Jordi Deu-Pons 28 | */ 29 | @CompileStatic 30 | @TupleConstructor 31 | final class EmptyBodyRequest { 32 | EmptyBodyRequest() { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exchange/ErrorResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exchange 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.TupleConstructor 23 | 24 | /** 25 | * Generic error response 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @CompileStatic 30 | @TupleConstructor 31 | final class ErrorResponse { 32 | String message 33 | 34 | ErrorResponse(String message) { 35 | this.message = message 36 | } 37 | 38 | static String of(String message) { 39 | new ErrorResponse(message) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/exchange/PairingResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.exchange 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | /** 24 | * Model the response for a remote service instance to register 25 | * itself as Wave credentials provider 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @CompileStatic 30 | class PairingResponse { 31 | String pairingId 32 | String publicKey 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/filter/FilterOrder.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.filter 20 | 21 | /** 22 | * Define the order of HTTP filters. The smaller number has higher priority 23 | * 24 | * {@link io.micronaut.core.order.Ordered} 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | interface FilterOrder { 29 | 30 | final int DENY_CRAWLER = -110 31 | final int DENY_PATHS = -100 32 | final int RATE_LIMITER = -50 33 | final int PULL_METRICS = 10 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/filter/RateLimiterOptions.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.filter 20 | 21 | 22 | import java.time.Duration 23 | 24 | import groovy.transform.CompileStatic 25 | import io.micronaut.context.annotation.ConfigurationProperties 26 | /** 27 | * Rate limiter config options 28 | * 29 | * @author Paolo Di Tommaso 30 | */ 31 | @CompileStatic 32 | @ConfigurationProperties("rate-limit.httpRequest") 33 | class RateLimiterOptions { 34 | 35 | Duration timeoutDuration 36 | 37 | Duration limitRefreshPeriod 38 | 39 | Integer limitForPeriod 40 | 41 | int statusCode 42 | 43 | void validate() { 44 | assert limitForPeriod>0, "Rate-limiter limitForPeriod must be greater than zero" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/proxy/ClientResponseException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.proxy 20 | 21 | import java.net.http.HttpRequest 22 | 23 | import groovy.transform.CompileStatic 24 | 25 | /** 26 | * Model an invalid response got by the registry client client 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @CompileStatic 31 | class ClientResponseException extends Exception { 32 | 33 | private HttpRequest request 34 | 35 | HttpRequest getRequest() { request } 36 | 37 | ClientResponseException(String message, HttpRequest request) { 38 | super(message) 39 | this.request = request 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/proxy/LoginRequest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.proxy 20 | 21 | import groovy.transform.Canonical 22 | import groovy.transform.CompileStatic 23 | 24 | /** 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @Canonical 29 | @CompileStatic 30 | class LoginRequest { 31 | String username 32 | String password 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/proxy/LoginResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.proxy 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | 25 | /** 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @ToString(includeNames = true, includePackage = false) 30 | @EqualsAndHashCode 31 | @CompileStatic 32 | class LoginResponse { 33 | String token 34 | String access_token 35 | Integer expires_in 36 | String issued_at 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/ratelimit/AcquireRequest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.ratelimit 20 | 21 | import groovy.transform.Canonical 22 | import groovy.transform.CompileStatic 23 | 24 | 25 | /** 26 | * A simple bean to contain the userId and Ip of a request 27 | * 28 | * @author : jorge 29 | * 30 | */ 31 | @Canonical 32 | @CompileStatic 33 | class AcquireRequest { 34 | 35 | /** 36 | * Principal key to use in the search. Can be null 37 | */ 38 | String user 39 | 40 | /** 41 | * Secondary key to use if principal is not present 42 | */ 43 | String ip 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/ratelimit/RateLimiterService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.ratelimit 20 | 21 | import io.seqera.wave.exception.SlowDownException 22 | 23 | 24 | /** 25 | * @author : jorge 26 | * 27 | */ 28 | interface RateLimiterService { 29 | 30 | void acquireBuild(AcquireRequest request) throws SlowDownException 31 | 32 | void acquirePull(AcquireRequest request) throws SlowDownException 33 | 34 | boolean acquireTimeoutCounter(String endpoint) 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/CredentialsService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service 20 | 21 | import io.seqera.wave.tower.PlatformId 22 | 23 | /** 24 | * Declare operations to access container registry credentials from Tower 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | interface CredentialsService { 29 | 30 | ContainerRegistryKeys findRegistryCreds(String registryName, PlatformId identity) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/UserService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service 20 | 21 | 22 | import io.seqera.wave.tower.User 23 | import io.seqera.wave.tower.auth.JwtAuth 24 | /** 25 | * Declare a service to access a Tower user 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | interface UserService { 30 | 31 | User getUserByAccessToken(String endpoint, JwtAuth auth) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/account/AccountService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.account 20 | 21 | /** 22 | * Defines the interface for checking account identity 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface AccountService { 27 | 28 | boolean isAuthorised(String username, String password) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/aws/AwsEcrAuthException.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.aws 20 | 21 | import groovy.transform.CompileStatic 22 | import io.seqera.wave.exception.WaveException 23 | 24 | /** 25 | * Exception thrown when there's a AWS ECR authorization failure 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @CompileStatic 30 | class AwsEcrAuthException extends WaveException { 31 | 32 | AwsEcrAuthException(String msg, Throwable t) { 33 | super(msg, t) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/aws/cache/AwsEcrAuthToken.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.aws.cache 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | import io.seqera.wave.encoder.MoshiSerializable 25 | /** 26 | * Model a tiered cache value for {@link AwsEcrCache} 27 | * 28 | * @author Munish Chouhan 29 | */ 30 | @CompileStatic 31 | @EqualsAndHashCode 32 | @ToString(includePackage = false, includeNames = true) 33 | class AwsEcrAuthToken implements MoshiSerializable { 34 | String value 35 | 36 | AwsEcrAuthToken(String value) { 37 | this.value = value 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/blob/BlobSigningService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.blob 20 | 21 | /** 22 | * Define the contract for creating signing URLs 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface BlobSigningService { 27 | 28 | String createSignedUri(String uri) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/blob/TransferStrategy.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.blob 20 | /** 21 | * Defines the contract to transfer a layer blob into a remote object storage 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface TransferStrategy { 26 | 27 | void launchJob(String jobName, List command) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/blob/signing/NoBlobSigningService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.blob.signing 20 | 21 | import groovy.transform.CompileStatic 22 | import io.micronaut.context.annotation.Requires 23 | import io.seqera.wave.service.blob.BlobSigningService 24 | import jakarta.inject.Singleton 25 | 26 | /** 27 | * Implements no url signing 28 | * 29 | * @author Paolo Di Tommaso 30 | */ 31 | @Requires(missingProperty = 'wave.blobCache.signing-strategy') 32 | @Singleton 33 | @CompileStatic 34 | class NoBlobSigningService implements BlobSigningService{ 35 | 36 | @Override 37 | String createSignedUri(String uri) { 38 | return uri 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/builder/BuildEvent.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.builder 20 | 21 | import groovy.transform.Canonical 22 | import groovy.transform.CompileStatic 23 | 24 | 25 | /** 26 | * An event fired when a build has been completed 27 | * 28 | * @author : jorge 29 | * 30 | */ 31 | @Canonical 32 | @CompileStatic 33 | class BuildEvent { 34 | 35 | BuildRequest request 36 | BuildResult result 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/builder/BuildFormat.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.builder 20 | 21 | /** 22 | * Define the container file format 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | enum BuildFormat { 27 | DOCKER, 28 | SINGULARITY 29 | 30 | String render() { 31 | this.toString().toLowerCase().capitalize() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/cleanup/CleanupService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.cleanup 20 | 21 | 22 | import io.seqera.wave.service.job.JobSpec 23 | /** 24 | * Define the contract for resources cleanup service 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | interface CleanupService { 29 | 30 | void cleanupJob(JobSpec job, Integer exitStatus) 31 | 32 | void cleanupScanId(String containerImage) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/counter/CounterStore.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.counter 20 | 21 | /** 22 | * Define the interface of a generic counter service 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface CounterStore { 27 | 28 | long inc(String key, long value) 29 | 30 | Long get(String key) 31 | 32 | /** 33 | * @param pattern 34 | * @return all the entries whose field matches 'pattern' 35 | */ 36 | Map getAllMatchingEntries(String pattern) 37 | } 38 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/counter/impl/CounterProvider.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.counter.impl 20 | /** 21 | * Contract interface for a generic distributed "counter" service 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface CounterProvider { 26 | 27 | long inc(String key, String field, long value) 28 | 29 | Long get(String key, String field) 30 | 31 | /** 32 | * 33 | * @param key 34 | * @param pattern 35 | * @return all the entries whose field matches 'pattern' 36 | */ 37 | Map getAllMatchingEntries(String key, String pattern) 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/inclusion/ContainerInclusionService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.inclusion 20 | 21 | import io.seqera.wave.api.SubmitContainerTokenRequest 22 | import io.seqera.wave.tower.PlatformId 23 | 24 | /** 25 | * Define the interface for the container inclusion service which takes care of expanding 26 | * a list of container names into a set of layers to the added to the target request 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | interface ContainerInclusionService { 31 | 32 | SubmitContainerTokenRequest addContainerInclusions(SubmitContainerTokenRequest request, PlatformId identity) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/job/JobEntry.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.job 20 | 21 | /** 22 | * Marker interface for a stored state entry associated with a job execution 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface JobEntry { 27 | boolean done() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/job/JobOperation.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.job 20 | /** 21 | * Define job operations contract 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface JobOperation { 26 | 27 | JobState status(JobSpec jobSpec) 28 | 29 | void cleanup(JobSpec jobSpec) 30 | 31 | void cleanup(String jobName) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/license/CheckTokenResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.license 20 | 21 | import java.time.Instant 22 | /** 23 | * Model the response for a License manager license token check request 24 | * 25 | * @author Munish Chouhan 26 | */ 27 | class CheckTokenResponse { 28 | String id // license ID 29 | Instant expiration // license expiration timestamp 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/logs/BuildLogService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.logs 20 | 21 | import groovy.transform.Canonical 22 | import io.micronaut.http.server.types.files.StreamedFile 23 | 24 | /** 25 | * Service to manage logs 26 | * 27 | * @author Munish Chouhan 28 | */ 29 | interface BuildLogService { 30 | 31 | @Canonical 32 | class BuildLog { 33 | String data 34 | boolean truncated 35 | } 36 | 37 | void storeLog(String buildId, String log) 38 | 39 | StreamedFile fetchLogStream(String buildId) 40 | 41 | BuildLog fetchLogString(String buildId) 42 | 43 | String fetchCondaLockString(String buildId) 44 | 45 | StreamedFile fetchCondaLockStream(String buildId) 46 | } 47 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/mail/MailService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.mail 20 | 21 | import io.seqera.wave.service.builder.BuildRequest 22 | import io.seqera.wave.service.builder.BuildResult 23 | /** 24 | * Implements mail notification service 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | interface MailService { 29 | 30 | void sendCompletionEmail(BuildRequest request, BuildResult result) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/mail/MailSpooler.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.mail 20 | 21 | import groovy.transform.CompileStatic 22 | import io.seqera.mail.Mail 23 | /** 24 | * Implements a Mail delivery service 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @CompileStatic 29 | interface MailSpooler { 30 | 31 | void sendMail(Mail mail) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/metric/MetricsCounterStore.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.metric 20 | 21 | import groovy.transform.CompileStatic 22 | import io.seqera.wave.service.counter.AbstractCounterStore 23 | import io.seqera.wave.service.counter.impl.CounterProvider 24 | import jakarta.inject.Singleton 25 | /** 26 | * Implement a persistent counter service for metrics 27 | * 28 | * @author Munish Chouhan 29 | */ 30 | @Singleton 31 | @CompileStatic 32 | class MetricsCounterStore extends AbstractCounterStore { 33 | 34 | MetricsCounterStore(CounterProvider provider) { 35 | super(provider) 36 | } 37 | 38 | @Override 39 | protected String getPrefix() { 40 | return 'metrics/v1' 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/metric/model/GetOrgArchCountResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.metric.model 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | /** 24 | * Model organisations counts with architecture response 25 | * 26 | * @author Munish Chouhan 27 | */ 28 | @CompileStatic 29 | class GetOrgArchCountResponse { 30 | String metric 31 | String arch 32 | Long count 33 | Map orgs 34 | 35 | GetOrgArchCountResponse(String metric, String arch, Long count, Map orgs) { 36 | this.metric = metric 37 | this.arch = arch 38 | this.count = count 39 | this.orgs = orgs 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/metric/model/GetOrgCountResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | package io.seqera.wave.service.metric.model 19 | 20 | import groovy.transform.CompileStatic 21 | 22 | /** 23 | * Model organisations counts response 24 | * 25 | * @author Munish Chouhan 26 | */ 27 | @CompileStatic 28 | class GetOrgCountResponse { 29 | String metric 30 | Long count 31 | Map orgs 32 | 33 | GetOrgCountResponse(String metric, Long count, Map orgs) { 34 | this.metric = metric 35 | this.count = count 36 | this.orgs = orgs 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/pairing/socket/MessageSender.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.pairing.socket 20 | /** 21 | * Interface modelling a generic message sender 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface MessageSender { 26 | 27 | void send(M message) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/pairing/socket/msg/PairingHeartbeat.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.pairing.socket.msg 20 | 21 | import groovy.transform.Canonical 22 | import groovy.transform.CompileStatic 23 | import groovy.transform.ToString 24 | 25 | /** 26 | * Model pairing heartbeat message 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @Canonical 31 | @CompileStatic 32 | @ToString(includePackage = false, includeNames = true) 33 | class PairingHeartbeat implements PairingMessage { 34 | String msgId 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/pairing/socket/msg/PairingResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.pairing.socket.msg 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.ToString 23 | 24 | /** 25 | * Model the response for a remote service instance to register 26 | * itself as Wave credentials provider 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @CompileStatic 31 | @ToString(includePackage = false, includeNames = true) 32 | class PairingResponse implements PairingMessage { 33 | String msgId 34 | String pairingId 35 | String publicKey 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/pairing/socket/msg/ProxyHttpRequest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.pairing.socket.msg 20 | 21 | import groovy.transform.Canonical 22 | import groovy.transform.CompileStatic 23 | import groovy.transform.ToString 24 | /** 25 | * Model a remote HTTP request send via WebSocket connection 26 | * 27 | * @author Jordi Deu-Pons 28 | */ 29 | @Canonical 30 | @CompileStatic 31 | @ToString(includePackage = false, includeNames = true) 32 | class ProxyHttpRequest implements PairingMessage { 33 | String msgId 34 | String method 35 | String uri 36 | String auth 37 | String body 38 | Map> headers 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/pairing/socket/msg/ProxyHttpResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.pairing.socket.msg 20 | 21 | 22 | import groovy.transform.Canonical 23 | import groovy.transform.CompileStatic 24 | import groovy.transform.ToString 25 | 26 | /** 27 | * Model a remote HTTP response send via WebSocket connection 28 | * 29 | * @author Jordi Deu-Pons 30 | */ 31 | @Canonical 32 | @CompileStatic 33 | @ToString(includePackage = false, includeNames = true) 34 | class ProxyHttpResponse implements PairingMessage { 35 | String msgId 36 | Integer status 37 | String body 38 | Map> headers 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/persistence/PostgresIgnore.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.persistence 20 | 21 | import java.lang.annotation.ElementType 22 | import java.lang.annotation.Retention 23 | import java.lang.annotation.RetentionPolicy 24 | import java.lang.annotation.Target 25 | 26 | /** 27 | * Marker annotation to ignore a field when serializing for PostgreSQL database 28 | * 29 | * @author Paolo Di Tommaso 30 | */ 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target([ElementType.FIELD]) 33 | @interface PostgresIgnore { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/persistence/impl/SurrealResult.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.persistence.impl 20 | 21 | /** 22 | * Model a Surreal Resultset 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | class SurrealResult { 27 | 28 | String time 29 | String status 30 | T[] result 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/persistence/migrate/MigrationOnly.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.persistence.migrate 20 | 21 | import java.lang.annotation.ElementType 22 | import java.lang.annotation.Retention 23 | import java.lang.annotation.RetentionPolicy 24 | import java.lang.annotation.Target 25 | 26 | /** 27 | * Marker annotation to annotate logic required for Surreal to Postgres migration 28 | * 29 | * @author Paolo Di Tommaso 30 | */ 31 | @Retention(RetentionPolicy.RUNTIME) 32 | @Target([ElementType.TYPE, ElementType.METHOD]) 33 | @interface MigrationOnly { 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/persistence/migrate/cache/DataMigrateEntry.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2025, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.persistence.migrate.cache 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | 25 | /** 26 | * Data migration entry 27 | * 28 | * @author Munish Chouhan 29 | */ 30 | @ToString(includeNames = true, includePackage = false) 31 | @EqualsAndHashCode 32 | @CompileStatic 33 | class DataMigrateEntry { 34 | String tableName 35 | int offset 36 | 37 | DataMigrateEntry(String tableName, int offset) { 38 | this.tableName = tableName 39 | this.offset = offset 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/request/ContainerRequestStore.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.request 20 | /** 21 | * Define the container request token persistence operations 22 | * 23 | * @author : jorge 24 | * 25 | */ 26 | interface ContainerRequestStore { 27 | 28 | void put(String key, ContainerRequest request) 29 | 30 | ContainerRequest get(String key) 31 | 32 | void remove(String key) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/request/ContainerStatusService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.request 20 | 21 | 22 | import io.seqera.wave.api.ContainerStatusResponse 23 | /** 24 | * Define the contract for container request status service 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | interface ContainerStatusService { 29 | 30 | ContainerStatusResponse getContainerStatus(String requestId) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/request/TokenData.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.request 20 | 21 | import java.time.Instant 22 | 23 | import groovy.transform.Canonical 24 | 25 | /** 26 | * Model container token 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @Canonical 31 | class TokenData { 32 | final String value 33 | final Instant expiration 34 | } 35 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/scan/Trivy.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.scan 20 | 21 | /** 22 | * Trivy constants 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface Trivy { 27 | 28 | static final public String CACHE_MOUNT_PATH = '/root/.cache/' 29 | 30 | static final public String CONFIG_MOUNT_PATH = '/root/.docker/config.json' 31 | 32 | static final public String OUTPUT_FILE_NAME = 'report.json' 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/stream/StreamService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.stream 20 | 21 | import io.seqera.wave.tower.PlatformId 22 | 23 | /** 24 | * Define the interface for remote resource steaming 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | interface StreamService { 29 | 30 | InputStream stream(String location, PlatformId identity) 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/service/validation/ValidationService.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.validation 20 | 21 | /** 22 | * Validation service 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface ValidationService { 27 | 28 | String checkEndpoint(String endpoint) 29 | 30 | String checkContainerName(String name) 31 | 32 | String checkBuildRepository(String repo, ValidationServiceImpl.RepoType type) 33 | 34 | boolean isCustomRepo(String repo) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/storage/DigestStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.storage; 20 | 21 | import java.io.Serializable; 22 | 23 | /** 24 | * Define the interface for a container layer digests caching 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | public interface DigestStore extends Serializable { 29 | 30 | byte[] getBytes() throws InterruptedException; 31 | String getMediaType(); 32 | String getDigest(); 33 | Integer getSize(); 34 | 35 | default String toLogString() { 36 | return toString(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/storage/Storage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.storage; 20 | 21 | 22 | import java.util.Optional; 23 | 24 | import io.seqera.wave.api.ContainerLayer; 25 | 26 | /** 27 | * @author : jorge 28 | **/ 29 | public interface Storage { 30 | 31 | Optional getManifest(String path); 32 | 33 | DigestStore saveManifest(String path, String manifest, String type, String digest); 34 | 35 | DigestStore saveManifest(String path, DigestStore store); 36 | 37 | Optional getBlob(String path); 38 | 39 | DigestStore saveBlob(String path, byte[] content, String type, String digest); 40 | 41 | DigestStore saveBlob(String path, ContainerLayer layer); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/cache/L2TieredCache.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.cache 20 | /** 21 | * Define the interface for 2nd level tired cache 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface L2TieredCache extends TieredCache { 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/cache/TieredKey.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.cache 20 | 21 | /** 22 | * Define the contract for key used by {@link TieredCache} caches 23 | * 24 | * @author Munish Chouhan 25 | */ 26 | interface TieredKey { 27 | 28 | String stableHash() 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/range/RangeStore.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.range 20 | /** 21 | * Define the contract for a storage range set similar to Redis `zrange` 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface RangeStore { 26 | 27 | void add(String member, double score) 28 | 29 | List getRange(double min, double max, int count) 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/range/impl/RangeProvider.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.range.impl 20 | /** 21 | * Contract for range store provider 22 | * 23 | * @author Paolo Di Tommaso 24 | */ 25 | interface RangeProvider { 26 | 27 | void add(String key, String member, double score) 28 | 29 | List getRange(String key, double min, double max, int count, boolean remove) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/state/CountParams.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.state 20 | 21 | import groovy.transform.Canonical 22 | 23 | /** 24 | * Model state store auto increment params 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @Canonical 29 | class CountParams { 30 | final String key 31 | final String field 32 | 33 | static CountParams of(String key) { 34 | final p=key.lastIndexOf('/') 35 | return p==-1 36 | ? new CountParams("counters/v1", key) 37 | : new CountParams(key.substring(0,p), key.substring(p+1)) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/state/CountResult.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.state 20 | 21 | import groovy.transform.Canonical 22 | 23 | /** 24 | * Model the result object of state auto-increment operation 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | @Canonical 29 | class CountResult { 30 | final Boolean succeed 31 | final V value 32 | final Integer count 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/state/RequestIdAware.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.state 20 | 21 | /** 22 | * Marker interface for record object that model long running operation state 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface RequestIdAware { 27 | 28 | String getRequestId() 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/store/state/StateEntry.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.state 20 | 21 | /** 22 | * Marker interface for a state store entry 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | interface StateEntry { 27 | K getKey() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/tower/client/GetServiceInfoResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.tower.client 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.ToString 23 | 24 | /** 25 | * Model Tower service info response 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | @ToString(includePackage = false, includeNames = true) 30 | @CompileStatic 31 | class GetServiceInfoResponse { 32 | 33 | @ToString(includePackage = false, includeNames = true) 34 | static class ServiceInfo { 35 | String version 36 | String apiVersion 37 | String commitId 38 | Boolean waveEnabled 39 | } 40 | 41 | ServiceInfo serviceInfo 42 | } 43 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/tower/client/GetUserInfoResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.tower.client 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | import io.seqera.wave.encoder.MoshiSerializable 25 | import io.seqera.wave.tower.User 26 | /** 27 | * Model a Tower user-info response 28 | * @author Paolo Di Tommaso 29 | */ 30 | @EqualsAndHashCode 31 | @ToString(includePackage = false, includeNames = true) 32 | @CompileStatic 33 | class GetUserInfoResponse implements MoshiSerializable { 34 | User user 35 | } 36 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/tower/client/ListCredentialsResponse.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.tower.client 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | import io.seqera.wave.encoder.MoshiSerializable 25 | 26 | @EqualsAndHashCode 27 | @ToString(includePackage = false, includeNames = true) 28 | @CompileStatic 29 | class ListCredentialsResponse implements MoshiSerializable { 30 | 31 | List credentials 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/tower/compute/ComputeEnv.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.tower.compute 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | import io.seqera.wave.encoder.MoshiSerializable 25 | 26 | /** 27 | * Model the response of compute environment from seqera platform 28 | * 29 | * @author Munish Chouhan 30 | */ 31 | @CompileStatic 32 | @EqualsAndHashCode 33 | @ToString(includePackage = false, includeNames = true) 34 | class ComputeEnv implements MoshiSerializable { 35 | String id 36 | String platform 37 | String credentialsId 38 | } 39 | 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/tower/compute/WorkflowLaunch.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.tower.compute 20 | 21 | import groovy.transform.CompileStatic 22 | import groovy.transform.EqualsAndHashCode 23 | import groovy.transform.ToString 24 | import io.seqera.wave.encoder.MoshiSerializable 25 | 26 | /** 27 | * Model the response of workflow launch response from seqera platform 28 | * 29 | * @author Munish Chouhan 30 | */ 31 | @CompileStatic 32 | @EqualsAndHashCode 33 | @ToString(includePackage = false, includeNames = true) 34 | class WorkflowLaunch implements MoshiSerializable { 35 | ComputeEnv computeEnv 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/util/FutureUtils.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.util 20 | 21 | import java.util.concurrent.CompletableFuture 22 | 23 | /** 24 | * Future class helpers 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | class FutureUtils { 29 | 30 | static CompletableFuture completeExceptionally(Throwable t) { 31 | final result = new CompletableFuture() 32 | result.completeExceptionally(t) 33 | return result 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/util/TypeHelper.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.util 20 | 21 | import java.lang.reflect.ParameterizedType 22 | import java.lang.reflect.Type 23 | 24 | import groovy.transform.CompileStatic 25 | 26 | /** 27 | * Helper class to handle Java types 28 | * 29 | * @author Paolo Di Tommaso 30 | */ 31 | @CompileStatic 32 | class TypeHelper { 33 | 34 | static Type getGenericType(Object object, int index) { 35 | final params = (ParameterizedType) (object.getClass().getGenericSuperclass()); 36 | return params.getActualTypeArguments()[index] 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/io/seqera/wave/util/Views.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.util 20 | 21 | import groovy.transform.CompileStatic 22 | 23 | /** 24 | * Implements Json views marker classes to be used with @JsonView annotation 25 | * 26 | * See https://www.baeldung.com/jackson-json-view-annotation 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @CompileStatic 31 | class Views { 32 | 33 | /** Marker class for public fields */ 34 | static abstract class Public { } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/jib/launch.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Wave, containers provisioning service 3 | # Copyright (c) 2023-2024, Seqera Labs 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | # Launch backend server 20 | [ "$WAVE_JVM_OPTS" ] && echo "Detected WAVE_JVM_OPTS=$WAVE_JVM_OPTS" 21 | exec java \ 22 | -Dfile.encoding=UTF-8 \ 23 | -Dcom.sun.security.enableAIAcaIssuers=true \ 24 | --add-opens java.base/java.lang=ALL-UNNAMED \ 25 | --add-opens java.base/java.math=ALL-UNNAMED \ 26 | --add-opens java.base/java.net=ALL-UNNAMED \ 27 | --add-opens java.base/java.text=ALL-UNNAMED \ 28 | --add-opens java.base/java.util=ALL-UNNAMED \ 29 | --add-opens java.base/java.util.concurrent=ALL-UNNAMED \ 30 | --add-opens java.base/java.io=ALL-UNNAMED \ 31 | --add-opens java.base/java.nio=ALL-UNNAMED \ 32 | --enable-native-access=ALL-UNNAMED \ 33 | ${WAVE_JVM_OPTS} \ 34 | -cp /app/resources:/app/classes:/app/libs/* \ 35 | io.seqera.wave.Application 36 | -------------------------------------------------------------------------------- /src/main/resources/application-blobcache-dev.yml: -------------------------------------------------------------------------------- 1 | wave: 2 | blobCache: 3 | enabled: true 4 | baseUrl: "https://nextflow-ci.s3.eu-west-1.amazonaws.com/blobs" 5 | storage: 6 | bucket: "s3://nextflow-ci/blobs" 7 | -------------------------------------------------------------------------------- /src/main/resources/application-buildlogs-aws-test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | wave: 3 | build: 4 | logs: 5 | path: "s3://nextflow-ci/test/l1" 6 | locks: 7 | path: "s3://nextflow-ci" 8 | ... 9 | -------------------------------------------------------------------------------- /src/main/resources/application-dev-k8s.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Use this environment to configure use a local Kubernetes cluster to build wave containers 3 | # 4 | # - add "dev-k8s" to the list of environments defined in the 'micronautEnvs' property in the "gradle.property" file 5 | # - create the directory "${HOME}/.wave/build-workspace" 6 | # - change the Kubernetes context in the config below with the one matching your installation 7 | # - create a namespace in your local Kubernetes cluster named "wave-local" 8 | # 9 | wave: 10 | build: 11 | debug: true 12 | workspace: "${HOME}/.wave/build-workspace" 13 | k8s: 14 | dns: 15 | servers: 16 | - "1.1.1.1" 17 | - "8.8.8.8" 18 | configPath: "${HOME}/.kube/config" 19 | context: 'docker-desktop' 20 | namespace: 'wave-local' 21 | storage: 22 | mountPath: "${HOME}/.wave/build-workspace" 23 | ... 24 | -------------------------------------------------------------------------------- /src/main/resources/application-dev.yml: -------------------------------------------------------------------------------- 1 | wave: 2 | debug: true 3 | scan: 4 | enabled: true 5 | failure: 6 | duration: '30s' 7 | build: 8 | workspace: 'build-workspace' 9 | logs: 10 | path: "${PWD}/build-workspace/logs" 11 | locks: 12 | path: "${PWD}/build-workspace/locks" 13 | metrics: 14 | enabled: true 15 | accounts: 16 | ### password checksum 'bar' 17 | foo: "fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9" 18 | jwt: 19 | refresh: 20 | interval: '10s' 21 | monitor: 22 | interval: '5s' 23 | cleanup: 24 | succeeded: '10s' 25 | failed: '45s' 26 | strategy: 'onsuccess' 27 | trace: 28 | local-persistence: 29 | threshold: 100 30 | surreal-persistence: 31 | threshold: 100 32 | proxy-service: 33 | threshold: 100 34 | --- 35 | endpoints: 36 | metrics: 37 | enabled: true 38 | --- 39 | # uses TOWER_xxx variable because the dev environment is expected to be 40 | # the same as of tower 41 | mail: 42 | from: "${TOWER_CONTACT_EMAIL:wave-app+dev@seqera.io}" 43 | --- 44 | logger: 45 | levels: 46 | io.seqera.wave.service.data: DEBUG 47 | io.seqera.wave.service.pairing: TRACE 48 | io.seqera.wave.service.job: DEBUG 49 | io.seqera.wave.service.k8s.K8sServiceImpl: TRACE 50 | io.seqera.wave.tower.client.connector: TRACE 51 | # io.seqera.wave.tower.client: 'TRACE' 52 | # io.seqera.wave.store.cache: 'TRACE' 53 | # io.seqera.wave.tower.auth: 'TRACE' 54 | # io.seqera.wave.core.RegistryProxyService: TRACE 55 | ... 56 | -------------------------------------------------------------------------------- /src/main/resources/application-licman.yml: -------------------------------------------------------------------------------- 1 | --- 2 | license: 3 | server: 4 | url: "${LICENSE_SERVER_URL:`http://localhost:7070`}" 5 | --- 6 | -------------------------------------------------------------------------------- /src/main/resources/application-mysql.yml: -------------------------------------------------------------------------------- 1 | --- 2 | datasources: 3 | default: 4 | dialect: MYSQL 5 | -------------------------------------------------------------------------------- /src/main/resources/application-postgres.yml: -------------------------------------------------------------------------------- 1 | wave: 2 | db: 3 | uri: "jdbc:postgresql://localhost:5432/postgres" 4 | user: "postgres" 5 | password: "" 6 | datasources: 7 | default: 8 | db-type: postgres 9 | dialect: POSTGRES 10 | driver-class-name: org.postgresql.Driver 11 | url: "${wave.db.uri}" 12 | username: "${wave.db.user}" 13 | password: "${wave.db.password}" 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/application-prometheus.yml: -------------------------------------------------------------------------------- 1 | micronaut: 2 | metrics: 3 | enabled: true 4 | export : 5 | prometheus : 6 | enabled : true 7 | step : PT1M 8 | descriptions : true 9 | binders: 10 | web: 11 | server: 12 | percentiles: "0.95,0.99" 13 | client: 14 | percentiles: "0.95,0.99" 15 | netty: 16 | queues: 17 | enabled: true 18 | bytebuf-allocators: 19 | enabled: true 20 | channels: 21 | enabled: true 22 | jdbc: 23 | enabled: true 24 | endpoints: 25 | prometheus: 26 | sensitive: false 27 | -------------------------------------------------------------------------------- /src/main/resources/application-rate-limit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | rate-limit: 3 | build: 4 | anonymous: 10/1h 5 | authenticated: 10/1m 6 | pull: 7 | anonymous: 100/1h 8 | authenticated: 100/1m 9 | timeout-errors: 10 | maxRate: 20/2m 11 | httpRequest: 12 | timeout-duration : 500ms 13 | limit-refresh-period : 1s 14 | limit-for-period : 100 15 | status-code : 429 16 | --- 17 | micronaut: 18 | caches: 19 | rate-limiter: 20 | expire-after-access: 10m 21 | ... 22 | -------------------------------------------------------------------------------- /src/main/resources/application-redis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | redis: 3 | uri: redis://${REDIS_HOST:redis}:${REDIS_PORT:6379} 4 | pool: 5 | enabled: true 6 | ... 7 | -------------------------------------------------------------------------------- /src/main/resources/application-surrealdb-legacy.yml: -------------------------------------------------------------------------------- 1 | --- 2 | surreal: 3 | legacy: 4 | ns: "seqera" 5 | db: "wave" 6 | url: "http://surrealdb:8000" 7 | user: "root" 8 | password: "root" 9 | ... 10 | -------------------------------------------------------------------------------- /src/main/resources/application-surrealdb.yml: -------------------------------------------------------------------------------- 1 | --- 2 | surreal: 3 | default: 4 | ns : "seqera" 5 | db : "wave" 6 | url: "http://surrealdb:8000" 7 | user: "root" 8 | password: "root" 9 | ... 10 | -------------------------------------------------------------------------------- /src/main/resources/bootstrap-ec2.yml: -------------------------------------------------------------------------------- 1 | micronaut: 2 | config-client: 3 | enabled: true 4 | aws: 5 | client: 6 | system-manager: 7 | parameterstore: 8 | enabled: true 9 | use-secure-parameters: true 10 | -------------------------------------------------------------------------------- /src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | micronaut: 2 | config-client: 3 | enabled: false 4 | aws: 5 | region: "${AWS_REGION:eu-west-1}" 6 | -------------------------------------------------------------------------------- /src/main/resources/io/seqera/wave/assets/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / 3 | -------------------------------------------------------------------------------- /src/main/resources/io/seqera/wave/assets/seqera-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/src/main/resources/io/seqera/wave/assets/seqera-logo.png -------------------------------------------------------------------------------- /src/main/resources/io/seqera/wave/assets/wave-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/src/main/resources/io/seqera/wave/assets/wave-logo.png -------------------------------------------------------------------------------- /src/main/resources/io/seqera/wave/assets/wave.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/src/main/resources/io/seqera/wave/assets/wave.ico -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/auth/RegistryTokenStoreTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.auth 20 | 21 | import spock.lang.Specification 22 | 23 | import io.micronaut.test.extensions.spock.annotation.MicronautTest 24 | import jakarta.inject.Inject 25 | 26 | /** 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @MicronautTest 31 | class RegistryTokenStoreTest extends Specification { 32 | 33 | @Inject RegistryTokenStore store 34 | 35 | def 'should return entry key' () { 36 | expect: 37 | store.key0('foo') == 'registry-token/v1:foo' 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/filter/TraceContextFilterTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.filter 20 | 21 | import spock.lang.Specification 22 | 23 | /** 24 | * 25 | * @author Paolo Di Tommaso 26 | */ 27 | class TraceContextFilterTest extends Specification { 28 | 29 | def 'should validate request id regex' () { 30 | expect: 31 | TraceContextFilter.getRequestId(PATH) == EXPECTED 32 | where: 33 | PATH | EXPECTED 34 | '/foo/bar' | null 35 | '/v2/wt/1234' | '1234' 36 | '/v2/wt/12ab/x/y/z' | '12ab' 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/account/AccountServiceTest.groovy: -------------------------------------------------------------------------------- 1 | package io.seqera.wave.service.account 2 | 3 | import spock.lang.Specification 4 | 5 | import io.micronaut.test.extensions.spock.annotation.MicronautTest 6 | import jakarta.inject.Inject 7 | 8 | /** 9 | * 10 | * @author Paolo Di Tommaso 11 | */ 12 | @MicronautTest 13 | class AccountServiceTest extends Specification { 14 | 15 | @Inject 16 | AccountService accountService 17 | 18 | 19 | def 'should validate auth service' () { 20 | expect: 21 | !accountService.isAuthorised(null,null) 22 | !accountService.isAuthorised('foo','foo') 23 | and: 24 | // check the config "application-test.yml" for these accounts 25 | accountService.isAuthorised('foo','hello') 26 | accountService.isAuthorised('bar','world') 27 | } 28 | 29 | def 'should digest string' () { 30 | given: 31 | def service = new AccountServiceImpl() 32 | expect: 33 | service.digest('hello') == '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824' 34 | service.digest('world') == '486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7' 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/cleanup/CleanupConfigTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.cleanup 20 | 21 | import spock.lang.Specification 22 | 23 | import java.time.Duration 24 | 25 | /** 26 | * 27 | * @author Paolo Di Tommaso 28 | */ 29 | class CleanupConfigTest extends Specification { 30 | 31 | def 'should get random delay' () { 32 | when: 33 | def d = Duration.ofSeconds(10) 34 | def config = new CleanupConfig(cleanupStartupDelay: d) 35 | then: 36 | config.cleanupStartupDelay == d 37 | and: 38 | config.cleanupStartupDelayRandomized >= d.dividedBy(2) 39 | config.cleanupStartupDelayRandomized < (d + d.dividedBy(2)) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/data/future/impl/LocalFutureHashTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.data.future.impl 20 | 21 | import spock.lang.Specification 22 | 23 | /** 24 | * 25 | * @author Paolo Di Tommaso 26 | */ 27 | class LocalFutureHashTest extends Specification { 28 | 29 | def 'should set and get a value' () { 30 | given: 31 | def queue = new LocalFutureHash() 32 | 33 | expect: 34 | queue.take('xyz') == null 35 | 36 | when: 37 | queue.put('xyz', 'hello', null) 38 | then: 39 | queue.take('xyz') == 'hello' 40 | and: 41 | queue.take('xyz') == null 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/data/stream/TestMessage.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.data.stream 20 | 21 | import groovy.transform.Canonical 22 | 23 | /** 24 | * 25 | * @author Paolo Di Tommaso 26 | */ 27 | @Canonical 28 | class TestMessage { 29 | String x 30 | String y 31 | } 32 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/data/stream/TestStream.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.data.stream 20 | 21 | import java.time.Duration 22 | 23 | /** 24 | * 25 | * @author Paolo Di Tommaso 26 | */ 27 | class TestStream extends AbstractMessageStream { 28 | 29 | TestStream(MessageStream target) { 30 | super(target) 31 | } 32 | 33 | @Override 34 | protected String name() { 35 | return 'test-stream' 36 | } 37 | 38 | @Override 39 | protected Duration pollInterval() { 40 | return Duration.ofSeconds(1) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/request/ContainerRequestStoreImplTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.request 20 | 21 | import spock.lang.Specification 22 | 23 | import io.micronaut.test.extensions.spock.annotation.MicronautTest 24 | import jakarta.inject.Inject 25 | 26 | /** 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @MicronautTest 31 | class ContainerRequestStoreImplTest extends Specification { 32 | 33 | @Inject ContainerRequestStoreImpl store 34 | 35 | def 'should return entry key' () { 36 | expect: 37 | store.key0('foo') == 'wave-tokens/v1:foo' 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/service/scan/ScanStateStoreTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.service.scan 20 | 21 | import spock.lang.Specification 22 | 23 | import io.micronaut.test.extensions.spock.annotation.MicronautTest 24 | import jakarta.inject.Inject 25 | 26 | /** 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @MicronautTest 31 | class ScanStateStoreTest extends Specification { 32 | 33 | @Inject ScanStateStore store 34 | 35 | def 'should return entry key' () { 36 | expect: 37 | store.key0('foo') == 'wave-scan/v1:foo' 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/storage/DockerDigestStoreTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.storage 20 | 21 | import spock.lang.Specification 22 | 23 | /** 24 | * 25 | * @author Paolo Di Tommaso 26 | */ 27 | class DockerDigestStoreTest extends Specification { 28 | 29 | def 'should create docker store' () { 30 | when: 31 | def store = new DockerDigestStore('docker://quay.io/v2/etc','some/media','sha256:12345', 100) 32 | then: 33 | store.location == 'docker://quay.io/v2/etc' 34 | store.mediaType == 'some/media' 35 | store.digest == 'sha256:12345' 36 | store.size == 100 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/storage/HttpDigestStoreTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.storage 20 | 21 | import spock.lang.Specification 22 | 23 | /** 24 | * 25 | * @author Paolo Di Tommaso 26 | */ 27 | class HttpDigestStoreTest extends Specification { 28 | 29 | def 'should create http store' () { 30 | when: 31 | def store = new HttpDigestStore('http://quay.io/v2/etc','some/media','sha256:12345', 100) 32 | then: 33 | store.location == 'http://quay.io/v2/etc' 34 | store.mediaType == 'some/media' 35 | store.digest == 'sha256:12345' 36 | store.size == 100 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/storage/ManifestCacheStoreTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.storage 20 | 21 | import spock.lang.Specification 22 | 23 | import io.micronaut.test.extensions.spock.annotation.MicronautTest 24 | import jakarta.inject.Inject 25 | 26 | /** 27 | * 28 | * @author Paolo Di Tommaso 29 | */ 30 | @MicronautTest 31 | class ManifestCacheStoreTest extends Specification { 32 | 33 | @Inject 34 | ManifestCacheStore store 35 | 36 | def 'should return entry key' () { 37 | expect: 38 | store.key0('foo') == 'wave-blobs/v1:foo' 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/storage/ZippedDigestStoreTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.storage 20 | 21 | import spock.lang.Specification 22 | /** 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | class ZippedDigestStoreTest extends Specification { 27 | 28 | def 'should load a lazy digest' () { 29 | given: 30 | def CONTENT = 'Hello world!' 31 | 32 | when: 33 | def digest = ZippedDigestStore.fromUncompressed(CONTENT.bytes, 'text', 'sha256:122345567890', 3000) 34 | then: 35 | digest.bytes == CONTENT.bytes 36 | digest.digest == 'sha256:122345567890' 37 | digest.mediaType == 'text' 38 | digest.size == 3000 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/store/state/CountParamsTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.store.state 20 | 21 | import spock.lang.Specification 22 | /** 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | class CountParamsTest extends Specification { 27 | 28 | def 'should split key'() { 29 | when: 30 | def result = CountParams.of(KEY) 31 | then: 32 | result == EXPECTED 33 | where: 34 | KEY | EXPECTED 35 | 'one' | new CountParams("counters/v1", "one") 36 | 'one/two' | new CountParams("one", "two") 37 | 'one/two/three' | new CountParams("one/two", "three") 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/tower/auth/JwtConfigTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.tower.auth 20 | 21 | import spock.lang.Specification 22 | 23 | import java.time.Duration 24 | /** 25 | * 26 | * @author Paolo Di Tommaso 27 | */ 28 | class JwtConfigTest extends Specification { 29 | 30 | def 'should get random delay' () { 31 | when: 32 | def d = Duration.ofSeconds(10) 33 | def config = new JwtConfig(monitorDelay: d) 34 | then: 35 | config.monitorDelay == d 36 | and: 37 | config.monitorDelayRandomized >= d.dividedBy(2) 38 | config.monitorDelayRandomized < (d + d.dividedBy(2)) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/test/groovy/io/seqera/wave/util/BuildInfoTest.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave, containers provisioning service 3 | * Copyright (c) 2023-2024, Seqera Labs 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Affero General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Affero General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Affero General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package io.seqera.wave.util 20 | 21 | import spock.lang.Specification 22 | /** 23 | * 24 | * @author Paolo Di Tommaso 25 | */ 26 | class BuildInfoTest extends Specification { 27 | 28 | def 'should load version and commit id' () { 29 | expect: 30 | BuildInfo.getName() == 'wave' 31 | BuildInfo.getVersion() 32 | BuildInfo.getCommitId() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/resources/application-rate-limit.yml: -------------------------------------------------------------------------------- 1 | --- 2 | rate-limit: 3 | build: 4 | anonymous: 2/1m 5 | authenticated: 2/1m 6 | pull: 7 | anonymous: 2/1m 8 | authenticated: 2/1m 9 | timeout-errors: 10 | maxRate: 2/1m 11 | -------------------------------------------------------------------------------- /src/test/resources/application-test-deny-paths.yml: -------------------------------------------------------------------------------- 1 | --- 2 | wave: 3 | denyPaths: 4 | - /container-token/token1 5 | ... 6 | -------------------------------------------------------------------------------- /src/test/resources/foo/dummy.gzip: -------------------------------------------------------------------------------- 1 | Hi -------------------------------------------------------------------------------- /src/test/resources/foo/layer.json: -------------------------------------------------------------------------------- 1 | { 2 | "entrypoint": [ 3 | "/opt/fusion/entry.sh" 4 | ], 5 | "workingDir": null, 6 | "cmd": null, 7 | "env": [ 8 | "FOO=bar" 9 | ], 10 | "layers": [ 11 | { 12 | "location": "replaced by the test", 13 | "gzipDigest": "sha256:3639efcd08abb273b1619e82e78c29a7df02c1051b1820e99fc395dcaa3326b8", 14 | "gzipSize": 2, 15 | "tarDigest": "sha256:fb27fedd4167ca99809b566b799e62ea930cee9f70ec35dc4bcb623dbb357788" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | false 25 | 26 | %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/test/resources/pack/layers/layer.json: -------------------------------------------------------------------------------- 1 | { 2 | "entrypoint": [ 3 | "/opt/fusion/entry.sh" 4 | ], 5 | "workingDir": null, 6 | "cmd": null, 7 | "env": [ 8 | "FOO=bar" 9 | ], 10 | "append": { 11 | "location": "layer.tar.gzip", 12 | "gzipDigest": "sha256:fe73ccd62aa94aefddad4544b6436c718df9b7aff8cfcc6eb8cf9a2d833869ce", 13 | "gzipSize": 13233364, 14 | "tarDigest": "sha256:9da8322478e34933f34ab4e6ac22097dc7a52bd3c074b0e50948e8fcb3a56897" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/resources/pack/layers/layer.tar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/src/test/resources/pack/layers/layer.tar -------------------------------------------------------------------------------- /src/test/resources/pack/layers/layer.tar.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seqeralabs/wave/3e729804b83629bc70fb63c980d50d5efbc5ab7b/src/test/resources/pack/layers/layer.tar.gzip -------------------------------------------------------------------------------- /src/test/resources/registry.password: -------------------------------------------------------------------------------- 1 | # user test, password test generated with `htpasswd -Bc registry.password test` 2 | test:$2y$05$/NvxvGb9Q.UqL2e6Itko9.0udleyunDegp/HklqQ...wImLupWhEK 3 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Wave, containers provisioning service 3 | # Copyright (c) 2023-2024, Seqera Labs 4 | # 5 | # This program is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Affero General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU Affero General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Affero General Public License 16 | # along with this program. If not, see . 17 | # 18 | 19 | ./gradlew test --tests 'ProxyClientTest' 20 | -------------------------------------------------------------------------------- /typespec/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginxinc/nginx-unprivileged:alpine 2 | 3 | # Copy index.html and openapi.yaml to the Nginx html directory 4 | COPY index.html /usr/share/nginx/html/openapi/index.html 5 | COPY tsp-output/@typespec/openapi3/openapi.yaml /usr/share/nginx/html/openapi/openapi.yaml 6 | 7 | # Expose port 8080 8 | EXPOSE 8080 9 | 10 | CMD ["nginx", "-g", "daemon off;"] 11 | -------------------------------------------------------------------------------- /typespec/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Wave API Documentation 7 | 8 | 9 | 10 |
11 | 12 | 13 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /typespec/main.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | import "@typespec/rest"; 3 | import "@typespec/openapi3"; 4 | import "@typespec/versioning"; 5 | import "./routes.tsp"; 6 | -------------------------------------------------------------------------------- /typespec/models/BuildStatusResponse.tsp: -------------------------------------------------------------------------------- 1 | import "./Status.tsp"; 2 | 3 | @doc("Response payload for build status.") 4 | @example(#{ 5 | id:"6c084f2e43f86a78_1", 6 | status:Status.COMPLETED, 7 | startTime:"2024-04-09T20:31:35.355423Z", 8 | duration: "123.914989000", 9 | succeeded: true 10 | } 11 | ) 12 | model BuildStatusResponse { 13 | duration: string; 14 | id: string; 15 | startTime: string; 16 | status: Status; 17 | succeeded: boolean; 18 | } 19 | -------------------------------------------------------------------------------- /typespec/models/CondaOpts.tsp: -------------------------------------------------------------------------------- 1 | @doc("Options for Conda environments.") 2 | @example(#{ 3 | basePackages: "python=3.8", 4 | commands: #["pip install bwa", "pip install salmon"], 5 | mambaImage: "mambaorg/micromamba:0.15.3" 6 | }) 7 | model CondaOpts { 8 | @doc("Names of base packages.") 9 | basePackages: string; 10 | @doc("Command to be included in the container.") 11 | commands: string[]; 12 | @doc("Name of the docker image used to build Conda containers.") 13 | mambaImage: string; 14 | } 15 | -------------------------------------------------------------------------------- /typespec/models/CondaPackages.tsp: -------------------------------------------------------------------------------- 1 | import "./CondaOpts.tsp"; 2 | 3 | @doc("Package configurations for container builds.") 4 | model CondaPackages { 5 | @doc("Conda channels to search for packages.") 6 | channels: string[]; 7 | condaOpts?: CondaOpts; 8 | @doc("Conda packages to install.") 9 | entries: string[]; 10 | @doc("The package environment file encoded as a base64 string.") 11 | environment?: string; 12 | @doc("This represents the type of package builder. Use `CONDA`.") 13 | type: "CONDA"; 14 | } 15 | -------------------------------------------------------------------------------- /typespec/models/ContainerConfig.tsp: -------------------------------------------------------------------------------- 1 | import "./ContainerLayer.tsp"; 2 | 3 | @doc("Configuration details for a container.") 4 | @example(#{ 5 | cmd: #["echo", "hello"], 6 | entrypoint: #["/bin/sh"], 7 | env: #["FOO=bar"], 8 | layers: #[ 9 | #{ 10 | gzipDigest: "sha256:1234567890abcdef", 11 | gzipSize: "1234", 12 | location: "https://seqera.io/layer.tar.gz", 13 | skipHashing: false, 14 | tarDigest: "sha256:abcdef1234567890" 15 | } 16 | ], 17 | workingDir: "/app" 18 | }) 19 | model ContainerConfig { 20 | @doc("The launch command to be used by the Wave container, e.g., `['echo', 'Hello world']` (optional).") 21 | cmd: string[]; 22 | @doc("The container entrypoint command, e.g., `['/bin/bash']`.") 23 | entrypoint: string[]; 24 | @doc("The environment variables to be defined in the Wave container, e.g., `['FOO=one','BAR=two']` (optional).") 25 | env: string[]; 26 | layers: ContainerLayer[]; 27 | @doc("The work directory to be used in the Wave container, e.g., `/some/work/dir` (optional).") 28 | workingDir: string; 29 | } 30 | -------------------------------------------------------------------------------- /typespec/models/ContainerInspectConfig.tsp: -------------------------------------------------------------------------------- 1 | import "./RootFS.tsp"; 2 | 3 | @doc("Configuration details of a container.") 4 | @example(#{ 5 | architecture: "linux/amd64", 6 | config: #{ 7 | attachStdin: false, 8 | attachStdout: true, 9 | attachStderr: true, 10 | tty: false, 11 | env: #["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"], 12 | cmd: #["sh"], 13 | image: "alpine:latest" 14 | }, 15 | container: "docker.io/alpine:latest", 16 | created: "2021-06-10T15:00:00.000000000Z", 17 | rootfs: #{ 18 | diff_ids: #["sha256:1234567890abcdef"], 19 | type: "layers" 20 | } 21 | }) 22 | model ContainerInspectConfig { 23 | architecture: string; 24 | config: { 25 | attachStdin: boolean; 26 | attachStdout: boolean; 27 | attachStderr: boolean; 28 | tty: boolean; 29 | env: string[]; 30 | cmd: string[]; 31 | image: string; 32 | }; 33 | container: string; 34 | created: string; 35 | rootfs: RootFS; 36 | } 37 | -------------------------------------------------------------------------------- /typespec/models/ContainerInspectRequest.tsp: -------------------------------------------------------------------------------- 1 | @doc("Request payload for inspecting a container.") 2 | @example(#{ 3 | containerImage: "docker.io/alpine:latest", 4 | towerAccessToken: "1234567890abcdef", 5 | towerEndpoint: "https://api.cloud.seqera.io", 6 | towerWorkspaceId: 1234567890 7 | }) 8 | model ContainerInspectRequest { 9 | @doc("Name of the container to be inpected, e.g., `docker.io/library/ubuntu:latest`") 10 | containerImage: string; 11 | @doc("Access token of the user account granting the access to the Seqera Platform service specified via `towerEndpoint` (optional). ") 12 | towerAccessToken: string; 13 | @doc("Seqera Platform service endpoint from where container registry credentials are retrieved (optional). Default `https://api.cloud.seqera.io`. ") 14 | towerEndpoint: string; 15 | @doc("ID of the Seqera Platform workspace from where the container registry credentials are retrieved (optional). When omitted the personal workspace is used.") 16 | towerWorkspaceId: int64; 17 | } 18 | -------------------------------------------------------------------------------- /typespec/models/ContainerLayer.tsp: -------------------------------------------------------------------------------- 1 | @doc("Represents a layer in a container image.") 2 | @example(#{ 3 | gzipDigest: "sha256:1234567890abcdef", 4 | gzipSize: "123456", 5 | location: "https://example.com/image.tar.gz", 6 | skipHashing: false, 7 | tarDigest: "sha256:abcdef1234567890" 8 | }) 9 | model ContainerLayer { 10 | @doc("The SHA256 checksum of the provided layer tar gzip file, e.g., `sha256:a7c724b02...`.") 11 | gzipDigest: string; 12 | @doc("The size in bytes of the the provided layer tar gzip file.") 13 | gzipSize: string; 14 | @doc("Specifies a container image layer stored as a tar.gz file (optional). Either a HTTP URL to the file or a base64 encoded string prefixed with `data:`.") 15 | location: string; 16 | @doc("If true, the layer tar file will not be hashed.") 17 | skipHashing: boolean; 18 | @doc("The SHA256checksum of the provided tar file, e.g., `sha256:a7c724b02...`.") 19 | tarDigest: string; 20 | } 21 | -------------------------------------------------------------------------------- /typespec/models/ContainerMirrorResponse.tsp: -------------------------------------------------------------------------------- 1 | import "./ContainerPlatform.tsp"; 2 | import "./Status.tsp"; 3 | 4 | @doc("Response payload for container mirroring.") 5 | @example(#{ 6 | mirrorId: "6c084f2e43f86a78_1", 7 | digest: "sha256:1234567890abcdef", 8 | sourceImage: "docker.io/alpine:latest", 9 | targetImage: "docker.io/alpine:latest", 10 | platform: #{ 11 | os: "LINUX", 12 | arch: "AMD64", 13 | variant: "v1" 14 | }, 15 | creationTime: "2024-04-09T20:31:35.355423Z", 16 | status: Status.COMPLETED, 17 | duration: "123.914989000", 18 | exitCode: 0, 19 | logs: "Successfully mirrored image." 20 | }) 21 | model ContainerMirrorResponse { 22 | mirrorId: string; 23 | digest: string; 24 | sourceImage: string; 25 | targetImage: string; 26 | platform: ContainerPlatform; 27 | creationTime: string; 28 | status: Status; 29 | duration: string; 30 | exitCode: int32; 31 | logs: string; 32 | } 33 | -------------------------------------------------------------------------------- /typespec/models/ContainerPlatform.tsp: -------------------------------------------------------------------------------- 1 | @doc("Represents os platform of a container.") 2 | @example(#{ 3 | os: "linux", 4 | arch: "amd64", 5 | variant: "v1" 6 | }) 7 | model ContainerPlatform { 8 | os: string; 9 | arch: string; 10 | variant?: string; 11 | } 12 | 13 | enum Architecture { 14 | ARM64, 15 | AARCH64, 16 | AMD64, 17 | X86_64, 18 | X86_64_ALT, 19 | ARM 20 | } 21 | 22 | enum OS { 23 | LINUX, 24 | WINDOWS, 25 | MACOS 26 | } 27 | -------------------------------------------------------------------------------- /typespec/models/ContainerResponse.tsp: -------------------------------------------------------------------------------- 1 | import "./ContainerStatus.tsp"; 2 | 3 | @doc("Response payload for container token creation.") 4 | @example(#{ 5 | containerToken:"732b73aa17c8", 6 | targetImage:"wave.seqera.io/wt/732b73aa17c8/build/dev:salmon_bwa--5e49881e6ad74121", 7 | expiration:"2024-04-09T21:19:01.715321Z", 8 | buildId:"5e49881e6ad74121_1", 9 | cached:false, 10 | freeze:false, 11 | mirror:false, 12 | requestId:"5e49881e6ad74121", 13 | scanId:"5e49881e6ad74121", 14 | containerImage:"docker.io/build/dev:salmon_bwa--5e49881e6ad74121", 15 | status:ContainerStatus.PENDING 16 | }) 17 | model ContainerResponse { 18 | @doc("Unique identifier for the build.") 19 | buildId: string; 20 | @doc("Indicates if the build is cached.") 21 | cached: boolean; 22 | @doc("Container image to be used.") 23 | containerImage: string; 24 | @doc("Token to access the container.") 25 | containerToken: string; 26 | @doc("The expiration timestamp of the Wave container using ISO-8601 format.") 27 | expiration: string; 28 | @doc("Indicates if the build is pushed to user container registry.") 29 | freeze: boolean; 30 | @doc("Indicates if its a mirror request.") 31 | mirror: boolean; 32 | @doc("Unique identifier for the request.") 33 | requestId: string; 34 | @doc("Unique identifier for the scan.") 35 | scanId: string; 36 | @doc("Status of the container build.") 37 | status: ContainerStatus; 38 | @doc("The Wave container image name") 39 | targetImage: string; 40 | } 41 | -------------------------------------------------------------------------------- /typespec/models/ContainerStatus.tsp: -------------------------------------------------------------------------------- 1 | enum ContainerStatus { 2 | PENDING, 3 | BUILDING, 4 | SCANNING, 5 | DONE 6 | } 7 | -------------------------------------------------------------------------------- /typespec/models/ContainerStatusResponse.tsp: -------------------------------------------------------------------------------- 1 | import "./ContainerStatus.tsp"; 2 | 3 | @doc("Response payload for container status.") 4 | @example(#{ 5 | id:"6c084f2e43f86a78", 6 | buildId:"6c084f2e43f86a78_1", 7 | status:ContainerStatus.DONE, 8 | creationTime:"2024-04-09T20:31:35.355423Z", 9 | detailsUri:"https://wave.seqera.io/view/builds/6c084f2e43f86a78_1", 10 | duration:"123.914989000", 11 | succeeded:true, 12 | scanId:"6c084f2e43f86a78_1", 13 | }) 14 | model ContainerStatusResponse { 15 | id: string; 16 | status: ContainerStatus; 17 | buildId: string; 18 | mirrorId?: string; 19 | scanId: string; 20 | vulnerabilities?: Record; 21 | succeeded: boolean; 22 | reason?: string; 23 | detailsUri: string; 24 | creationTime: string; 25 | duration: string; 26 | } 27 | 28 | model vulnerability { 29 | severity: string; 30 | count: int32 31 | } 32 | -------------------------------------------------------------------------------- /typespec/models/Manifest.tsp: -------------------------------------------------------------------------------- 1 | import "./ManifestLayer.tsp"; 2 | 3 | @doc("Manifest details of a container.") 4 | @example(#{ 5 | config: #{ 6 | digest: "sha256:6c084f2e43f86a78", 7 | mediaType: "application/vnd.docker.container.image.v1+json", 8 | size: 1234 9 | }, 10 | layers: #[ 11 | #{ 12 | digest: "sha256:6c084f2e43f86a78", 13 | mediaType: "application/vnd.docker.container.image.v1+json", 14 | size: 1234 15 | } 16 | ], 17 | mediaType: "application/vnd.docker.container.image.v1+json", 18 | schemaVersion: 2 19 | }) 20 | model Manifest { 21 | config: { 22 | digest: string; 23 | mediaType: string; 24 | size: int64; 25 | }; 26 | layers: ManifestLayer[]; 27 | mediaType: string; 28 | schemaVersion: int32; 29 | } 30 | -------------------------------------------------------------------------------- /typespec/models/ManifestLayer.tsp: -------------------------------------------------------------------------------- 1 | @doc("Manifest layer details of a container.") 2 | @example(#{ 3 | digest: "sha256:6c084f2e43f86a78", 4 | mediaType: "application/vnd.docker.container.image.v1+json", 5 | size: 1234 6 | }) 7 | model ManifestLayer { 8 | digest: string; 9 | mediaType: string; 10 | size: int64; 11 | } 12 | -------------------------------------------------------------------------------- /typespec/models/RootFS.tsp: -------------------------------------------------------------------------------- 1 | @doc("Details about the root filesystem of a container.") 2 | @example(#{ 3 | diff_ids: #[ 4 | "sha256:6c084f2e43f86a78", 5 | "sha256:6c084f2e43f86a78" 6 | ], 7 | type: "layers" 8 | }) 9 | model RootFS { 10 | diff_ids: string[]; 11 | type: string; 12 | } 13 | -------------------------------------------------------------------------------- /typespec/models/ScanLevel.tsp: -------------------------------------------------------------------------------- 1 | enum ScanLevel { 2 | LOW, 3 | MEDIUM, 4 | HIGH, 5 | CRITICAL 6 | } 7 | -------------------------------------------------------------------------------- /typespec/models/ScanMode.tsp: -------------------------------------------------------------------------------- 1 | enum ScanMode{ 2 | none, 3 | async, 4 | required 5 | } 6 | -------------------------------------------------------------------------------- /typespec/models/Status.tsp: -------------------------------------------------------------------------------- 1 | enum Status { 2 | PENDING, 3 | COMPLETED 4 | } 5 | -------------------------------------------------------------------------------- /typespec/models/User.tsp: -------------------------------------------------------------------------------- 1 | @doc("Wave USer details") 2 | @example(#{ 3 | id: 1, 4 | userName: "test", 5 | email: "test@seqera.io" 6 | }) 7 | model User { 8 | id: int64; 9 | userName: string; 10 | email: string; 11 | } 12 | -------------------------------------------------------------------------------- /typespec/models/ValidateRegistryCredsRequest.tsp: -------------------------------------------------------------------------------- 1 | @doc("request payload of validate credentials request") 2 | @example(#{ 3 | password: "password", 4 | registry: "docker.io/wave", 5 | userName: "username" 6 | }) 7 | model ValidateRegistryCredsRequest { 8 | password: string; 9 | registry: string; 10 | userName: string; 11 | } 12 | -------------------------------------------------------------------------------- /typespec/models/Vulnerability.tsp: -------------------------------------------------------------------------------- 1 | @doc("Scan Vulnerability details") 2 | @example(#{ 3 | fixedVersion: "1.0.0", 4 | id: "CVE-2021-1234", 5 | installedVersion: "0.9.0", 6 | pkgName: "test", 7 | primaryUrl: "https://test.com", 8 | severity: "high", 9 | title: "test" 10 | }) 11 | model Vulnerability { 12 | fixedVersion: string; 13 | id: string; 14 | installedVersion: string; 15 | pkgName: string; 16 | primaryUrl: string; 17 | severity: string; 18 | title: string; 19 | } 20 | -------------------------------------------------------------------------------- /typespec/models/WaveBuildRecord.tsp: -------------------------------------------------------------------------------- 1 | @doc("Wave container build details") 2 | model WaveBuildRecord { 3 | buildId: string; 4 | condaFile: string; 5 | digest: string; 6 | dockerFile: string; 7 | duration: int64; 8 | exitStatus: int32; 9 | format: "docker" | "sif"; 10 | offsetId: string; 11 | platform: string; 12 | requestIp: string; 13 | scanId: string; 14 | startTime: string; 15 | succeeded: boolean; 16 | targetImage: string; 17 | userEmail: string; 18 | userId: int64; 19 | userName: string; 20 | } 21 | -------------------------------------------------------------------------------- /typespec/models/WaveContainerRecord.tsp: -------------------------------------------------------------------------------- 1 | import "./User.tsp"; 2 | 3 | @doc("Wave container details") 4 | model WaveContainerRecord { 5 | user: User; 6 | workspaceId: int64; 7 | containerImage?: string; 8 | containerFile?: string; 9 | containerConfig: ContainerConfig; 10 | condaFile?: string; 11 | platform?: string; 12 | towerEndpoint?: string; 13 | buildRepository?: string; 14 | cacheRepository?: string; 15 | fingerprint?: string; 16 | timestamp: string; 17 | zoneId?: string; 18 | ipAddress?: string; 19 | sourceImage?: string; 20 | sourceDigest?: string; 21 | waveImage?: string; 22 | waveDigest?: string; 23 | expiration: string; 24 | buildId?: string; 25 | buildNew?: boolean; 26 | freeze?: boolean; 27 | fusionVersion?: string; 28 | } 29 | -------------------------------------------------------------------------------- /typespec/models/WaveScanRecord.tsp: -------------------------------------------------------------------------------- 1 | import "./Vulnerability.tsp"; 2 | 3 | @doc("Response Payload for wave scan") 4 | model WaveScanRecord { 5 | buildId: string; 6 | duration: int64; 7 | containerImage: string; 8 | id: string; 9 | startTime: string; 10 | status: string; 11 | vulnerabilities: Vulnerability[]; 12 | } 13 | -------------------------------------------------------------------------------- /typespec/models/models.tsp: -------------------------------------------------------------------------------- 1 | import "./ContainerRequest.tsp"; 2 | import "./ContainerResponse.tsp"; 3 | import "./BuildStatusResponse.tsp"; 4 | import "./ContainerInspectRequest.tsp"; 5 | import "./ContainerInspectResponse.tsp"; 6 | import "./WaveScanRecord.tsp"; 7 | import "./WaveBuildRecord.tsp"; 8 | import "./ValidateRegistryCredsRequest.tsp"; 9 | import "./WaveContainerRecord.tsp"; 10 | import "./ContainerMirrorResponse.tsp"; 11 | import "./ContainerStatusResponse.tsp"; 12 | -------------------------------------------------------------------------------- /typespec/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wave", 3 | "version": "1.16.7", 4 | "type": "module", 5 | "dependencies": { 6 | "@typespec/compiler": "0.64.0", 7 | "@typespec/http": "0.64.0", 8 | "@typespec/openapi3": "0.64.0", 9 | "@typespec/rest": "0.64.0" 10 | }, 11 | "private": true 12 | } 13 | -------------------------------------------------------------------------------- /typespec/tag-and-push-openapi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Wave, containers provisioning service 4 | # Copyright (c) 2023-2024, Seqera Labs 5 | # 6 | # This program is free software: you can redistribute it and/or modify 7 | # it under the terms of the GNU Affero General Public License as published by 8 | # the Free Software Foundation, either version 3 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU Affero General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU Affero General Public License 17 | # along with this program. If not, see . 18 | # 19 | 20 | # Tag and and push the the GitHub repo and Docker images 21 | 22 | set -e 23 | set -x 24 | 25 | SED=sed 26 | [[ $(uname) == Darwin ]] && SED=gsed 27 | 28 | RELEASE=${RELEASE:-$(git show -s --format='%s' | $SED -rn 's/.*\[(release)\].*/\1/p')} 29 | 30 | if [[ $RELEASE ]]; then 31 | TAG=v$(cat VERSION) 32 | version=$(cat VERSION) 33 | 34 | cd typespec 35 | sed -i "s/version: 0.0.0/version: $version/" "tsp-output/@typespec/openapi3/openapi.yaml" 36 | 37 | docker build -t 195996028523.dkr.ecr.eu-west-1.amazonaws.com/wave/openapi:$version . 38 | docker push 195996028523.dkr.ecr.eu-west-1.amazonaws.com/wave/openapi:$version 39 | fi 40 | -------------------------------------------------------------------------------- /typespec/tspconfig.yaml: -------------------------------------------------------------------------------- 1 | emit: 2 | - "@typespec/openapi3" 3 | options: 4 | "@typespec/openapi3": 5 | output-file: openapi.yaml 6 | --------------------------------------------------------------------------------