From 2821a76cc1ad0d7812bb15f429b88055c5d9b675 Mon Sep 17 00:00:00 2001 From: Piotr Limanowski Date: Wed, 3 Jan 2024 11:39:46 +0100 Subject: [PATCH] Add mandatory SLULA license acceptance flag (close #405) Since introducing a new license we need to explicitly check if the user has accepted the terms. Therefore a new flag is added. By default it is set to false but can be overrided by either: - setting `license.accept = true` in the config file - setting `env ACCEPT_LIMITED_USE_LICENSE=true` - appending `-Dlicense.accept=true` --- .../telemetry/sender_config/config.hocon | 1 + .../sender_config/config_disabled.hocon | 1 + .../ssc-collector-config/config.hocon | 1 + core/src/main/resources/reference.conf | 5 +++++ .../Config.scala | 19 ++++++++++++++++++- .../Run.scala | 17 +++++++++++++---- .../ConfigParserSpec.scala | 3 ++- .../TestUtils.scala | 3 ++- examples/config.kafka.extended.hocon | 5 +++++ examples/config.kafka.minimal.hocon | 4 ++++ examples/config.kinesis.extended.hocon | 5 +++++ examples/config.kinesis.minimal.hocon | 4 ++++ examples/config.nsq.extended.hocon | 5 +++++ examples/config.nsq.minimal.hocon | 7 +++++-- examples/config.pubsub.extended.hocon | 5 +++++ examples/config.pubsub.minimal.hocon | 4 ++++ examples/config.sqs.extended.hocon | 5 +++++ examples/config.sqs.minimal.hocon | 3 +++ examples/config.stdout.extended.hocon | 5 +++++ examples/config.stdout.minimal.hocon | 3 +++ kafka/src/it/resources/collector.hocon | 1 + .../KafkaConfigSpec.scala | 3 ++- .../collector-cookie-anonymous.hocon | 1 + .../collector-cookie-attributes-1.hocon | 1 + .../collector-cookie-attributes-2.hocon | 1 + .../resources/collector-cookie-domain.hocon | 1 + .../resources/collector-cookie-fallback.hocon | 1 + .../collector-cookie-no-domain.hocon | 1 + .../it/resources/collector-custom-paths.hocon | 1 + .../collector-doNotTrackCookie-disabled.hocon | 1 + .../collector-doNotTrackCookie-enabled.hocon | 1 + kinesis/src/it/resources/collector.hocon | 1 + .../sinks/KinesisConfigSpec.scala | 3 ++- .../NsqConfigSpec.scala | 3 ++- pubsub/src/it/resources/collector.hocon | 1 + .../ConfigSpec.scala | 3 ++- .../SqsConfigSpec.scala | 3 ++- 37 files changed, 118 insertions(+), 14 deletions(-) diff --git a/.github/workflows/integration_tests/telemetry/sender_config/config.hocon b/.github/workflows/integration_tests/telemetry/sender_config/config.hocon index 9979af681..96dcc7f10 100644 --- a/.github/workflows/integration_tests/telemetry/sender_config/config.hocon +++ b/.github/workflows/integration_tests/telemetry/sender_config/config.hocon @@ -1,5 +1,6 @@ # 'collector' contains configuration options for the main Scala collector. collector { + license { accept = true } # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = "9292" diff --git a/.github/workflows/integration_tests/telemetry/sender_config/config_disabled.hocon b/.github/workflows/integration_tests/telemetry/sender_config/config_disabled.hocon index 30885a8fc..e3dd731eb 100644 --- a/.github/workflows/integration_tests/telemetry/sender_config/config_disabled.hocon +++ b/.github/workflows/integration_tests/telemetry/sender_config/config_disabled.hocon @@ -1,5 +1,6 @@ # 'collector' contains configuration options for the main Scala collector. collector { + license { accept = true } # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = "10292" diff --git a/.github/workflows/ssc-collector-config/config.hocon b/.github/workflows/ssc-collector-config/config.hocon index 2137caead..10e6b6df9 100644 --- a/.github/workflows/ssc-collector-config/config.hocon +++ b/.github/workflows/ssc-collector-config/config.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = 0.0.0.0 port = 12345 diff --git a/core/src/main/resources/reference.conf b/core/src/main/resources/reference.conf index 1a91ba19b..be3b75e40 100644 --- a/core/src/main/resources/reference.conf +++ b/core/src/main/resources/reference.conf @@ -1,4 +1,9 @@ { + license { + accept = false + accept = ${?ACCEPT_LIMITED_USE_LICENSE} + } + paths {} p3p { diff --git a/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Config.scala b/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Config.scala index e32609f81..90210f959 100644 --- a/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Config.scala +++ b/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Config.scala @@ -37,7 +37,8 @@ case class Config[+SinkConfig]( networking: Config.Networking, enableDefaultRedirect: Boolean, redirectDomains: Set[String], - preTerminationPeriod: FiniteDuration + preTerminationPeriod: FiniteDuration, + license: Config.License ) object Config { @@ -152,7 +153,22 @@ object Config { idleTimeout: FiniteDuration ) + case class FlexBoolean(value: Boolean) + object FlexBoolean { + implicit def toBoolean(b: FlexBoolean): Boolean = b.value + } + object License { + def apply(accept: Boolean): License = License(FlexBoolean(accept)) + } + case class License( + accept: FlexBoolean + ) + implicit def decoder[SinkConfig: Decoder]: Decoder[Config[SinkConfig]] = { + implicit val flexBooleanDecoder: Decoder[FlexBoolean] = { + val truthy = Set("true", "yes", "on", "1") + Decoder.decodeBoolean.map(s => FlexBoolean(s)).or(Decoder.decodeString.map(s => FlexBoolean(truthy(s)))) + } implicit val p3p = deriveDecoder[P3P] implicit val crossDomain = deriveDecoder[CrossDomain] implicit val sameSite: Decoder[SameSite] = Decoder.instance { cur => @@ -177,6 +193,7 @@ object Config { implicit val ssl = deriveDecoder[SSL] implicit val telemetry = deriveDecoder[Telemetry] implicit val networking = deriveDecoder[Networking] + implicit val license = deriveDecoder[License] implicit val sinkConfig = newDecoder[SinkConfig].or(legacyDecoder[SinkConfig]) implicit val streams = deriveDecoder[Streams[SinkConfig]] diff --git a/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Run.scala b/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Run.scala index 70c9a80b4..75a9e4096 100644 --- a/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Run.scala +++ b/core/src/main/scala/com.snowplowanalytics.snowplow.collector.core/Run.scala @@ -54,15 +54,24 @@ object Run { telemetryInfo: TelemetryInfo[F, SinkConfig], path: Option[Path] ): F[ExitCode] = { + val licenseNotAccepted = ExitCode(2) val eitherT = for { config <- ConfigParser.fromPath[F, SinkConfig](path) + _ <- EitherT.cond[F](config.license.accept.value == true, ExitCode.Success, licenseNotAccepted) _ <- EitherT.right[ExitCode](fromConfig(appInfo, mkSinks, telemetryInfo, config)) } yield ExitCode.Success - eitherT.merge.handleErrorWith { e => - Logger[F].error(e)("Exiting") >> - prettyLogException(e).as(ExitCode.Error) - } + eitherT + .merge + .ensure( + new RuntimeException( + "License not accepted. Configure license acceptance to continue. See docs for more details." + ) + )(_ != licenseNotAccepted) + .handleErrorWith { e => + Logger[F].error(e)("Exiting") >> + prettyLogException(e).as(ExitCode.Error) + } } private def fromConfig[F[_]: Async: Tracking, SinkConfig]( diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ConfigParserSpec.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ConfigParserSpec.scala index 310df4365..3f25aeea5 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ConfigParserSpec.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/ConfigParserSpec.scala @@ -52,7 +52,8 @@ class ConfigParserSpec extends Specification with CatsEffect { .copy[SinkConfig]( paths = Map.empty[String, String], streams = expectedStreams, - ssl = TestUtils.testConfig.ssl.copy(enable = true) + ssl = TestUtils.testConfig.ssl.copy(enable = true), + license = Config.License(false) ) ConfigParser.fromPath[IO, SinkConfig](Some(path)).value.map(_ should beRight(expected)) diff --git a/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/TestUtils.scala b/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/TestUtils.scala index 3e4695687..81a3c4941 100644 --- a/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/TestUtils.scala +++ b/core/src/test/scala/com.snowplowanalytics.snowplow.collector.core/TestUtils.scala @@ -131,6 +131,7 @@ object TestUtils { moduleVersion = None, instanceId = None, autoGeneratedId = None - ) + ), + license = License(accept = true) ) } diff --git a/examples/config.kafka.extended.hocon b/examples/config.kafka.extended.hocon index 26ef30b22..029ad7f63 100644 --- a/examples/config.kafka.extended.hocon +++ b/examples/config.kafka.extended.hocon @@ -12,6 +12,11 @@ # 'collector' contains configuration options for the main Scala collector. collector { + # Full license text available in LICENSE.md + license { + accept = true + } + # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = 8080 diff --git a/examples/config.kafka.minimal.hocon b/examples/config.kafka.minimal.hocon index 1547b5c1e..cc7c5a869 100644 --- a/examples/config.kafka.minimal.hocon +++ b/examples/config.kafka.minimal.hocon @@ -1,4 +1,8 @@ collector { + license { + accept = true + } + interface = "0.0.0.0" port = 8080 diff --git a/examples/config.kinesis.extended.hocon b/examples/config.kinesis.extended.hocon index d5f619633..d9a201786 100644 --- a/examples/config.kinesis.extended.hocon +++ b/examples/config.kinesis.extended.hocon @@ -12,6 +12,11 @@ # 'collector' contains configuration options for the main Scala collector. collector { + # Full license text available in LICENSE.md + license { + accept = true + } + # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = 8080 diff --git a/examples/config.kinesis.minimal.hocon b/examples/config.kinesis.minimal.hocon index 9501390a5..30ee8f174 100644 --- a/examples/config.kinesis.minimal.hocon +++ b/examples/config.kinesis.minimal.hocon @@ -1,4 +1,8 @@ collector { + license { + accept = true + } + interface = "0.0.0.0" port = 8080 diff --git a/examples/config.nsq.extended.hocon b/examples/config.nsq.extended.hocon index 9f5a7ee67..6659981b6 100644 --- a/examples/config.nsq.extended.hocon +++ b/examples/config.nsq.extended.hocon @@ -12,6 +12,11 @@ # 'collector' contains configuration options for the main Scala collector. collector { + # Full license text available in LICENSE.md + license { + accept = true + } + # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = 8080 diff --git a/examples/config.nsq.minimal.hocon b/examples/config.nsq.minimal.hocon index 2b7afa7ca..f3cafd6dc 100644 --- a/examples/config.nsq.minimal.hocon +++ b/examples/config.nsq.minimal.hocon @@ -1,4 +1,7 @@ collector { + license { + accept = true + } interface = "0.0.0.0" port = 8080 @@ -6,8 +9,8 @@ collector { good { name = "good" host = "nsqHost" - } - + } + bad { name = "bad" host = "nsqHost" diff --git a/examples/config.pubsub.extended.hocon b/examples/config.pubsub.extended.hocon index c69d76db6..af640045d 100644 --- a/examples/config.pubsub.extended.hocon +++ b/examples/config.pubsub.extended.hocon @@ -12,6 +12,11 @@ # 'collector' contains configuration options for the main Scala collector. collector { + # Full license text available in LICENSE.md + license { + accept = true + } + # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = 8080 diff --git a/examples/config.pubsub.minimal.hocon b/examples/config.pubsub.minimal.hocon index b6fdb8d05..fec7ef8a3 100644 --- a/examples/config.pubsub.minimal.hocon +++ b/examples/config.pubsub.minimal.hocon @@ -1,4 +1,8 @@ collector { + license { + accept = true + } + interface = "0.0.0.0" port = 8080 diff --git a/examples/config.sqs.extended.hocon b/examples/config.sqs.extended.hocon index e47d3fbc6..04b7a28cc 100644 --- a/examples/config.sqs.extended.hocon +++ b/examples/config.sqs.extended.hocon @@ -7,6 +7,11 @@ # 'collector' contains configuration options for the main Scala collector. collector { + # Full license text available in LICENSE.md + license { + accept = true + } + # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = 8080 diff --git a/examples/config.sqs.minimal.hocon b/examples/config.sqs.minimal.hocon index 9501390a5..137baa0af 100644 --- a/examples/config.sqs.minimal.hocon +++ b/examples/config.sqs.minimal.hocon @@ -1,4 +1,7 @@ collector { + license { + accept = true + } interface = "0.0.0.0" port = 8080 diff --git a/examples/config.stdout.extended.hocon b/examples/config.stdout.extended.hocon index 92b5ef8b8..6175e3bd0 100644 --- a/examples/config.stdout.extended.hocon +++ b/examples/config.stdout.extended.hocon @@ -12,6 +12,11 @@ # 'collector' contains configuration options for the main Scala collector. collector { + # Full license text available in LICENSE.md + license { + accept = true + } + # The collector runs as a web service specified on the following interface and port. interface = "0.0.0.0" port = 8080 diff --git a/examples/config.stdout.minimal.hocon b/examples/config.stdout.minimal.hocon index 3b2e212d6..4b318e039 100644 --- a/examples/config.stdout.minimal.hocon +++ b/examples/config.stdout.minimal.hocon @@ -1,4 +1,7 @@ collector { + license { + accept = true + } interface = "0.0.0.0" port = 8080 diff --git a/kafka/src/it/resources/collector.hocon b/kafka/src/it/resources/collector.hocon index 2468a977b..afdf83333 100644 --- a/kafka/src/it/resources/collector.hocon +++ b/kafka/src/it/resources/collector.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kafka/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/KafkaConfigSpec.scala b/kafka/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/KafkaConfigSpec.scala index fa3e0b1a7..453585dda 100644 --- a/kafka/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/KafkaConfigSpec.scala +++ b/kafka/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/KafkaConfigSpec.scala @@ -156,6 +156,7 @@ object KafkaConfigSpec { networking = Config.Networking( maxConnections = 1024, idleTimeout = 610.seconds - ) + ), + license = Config.License(accept = true) ) } diff --git a/kinesis/src/it/resources/collector-cookie-anonymous.hocon b/kinesis/src/it/resources/collector-cookie-anonymous.hocon index 14f4ed802..41edde52f 100644 --- a/kinesis/src/it/resources/collector-cookie-anonymous.hocon +++ b/kinesis/src/it/resources/collector-cookie-anonymous.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-cookie-attributes-1.hocon b/kinesis/src/it/resources/collector-cookie-attributes-1.hocon index e661116da..d67d6695c 100644 --- a/kinesis/src/it/resources/collector-cookie-attributes-1.hocon +++ b/kinesis/src/it/resources/collector-cookie-attributes-1.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-cookie-attributes-2.hocon b/kinesis/src/it/resources/collector-cookie-attributes-2.hocon index 14f4ed802..41edde52f 100644 --- a/kinesis/src/it/resources/collector-cookie-attributes-2.hocon +++ b/kinesis/src/it/resources/collector-cookie-attributes-2.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-cookie-domain.hocon b/kinesis/src/it/resources/collector-cookie-domain.hocon index 4a7eaee7c..cc4a991ae 100644 --- a/kinesis/src/it/resources/collector-cookie-domain.hocon +++ b/kinesis/src/it/resources/collector-cookie-domain.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-cookie-fallback.hocon b/kinesis/src/it/resources/collector-cookie-fallback.hocon index 8c9c874f6..be55026e2 100644 --- a/kinesis/src/it/resources/collector-cookie-fallback.hocon +++ b/kinesis/src/it/resources/collector-cookie-fallback.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-cookie-no-domain.hocon b/kinesis/src/it/resources/collector-cookie-no-domain.hocon index 14f4ed802..41edde52f 100644 --- a/kinesis/src/it/resources/collector-cookie-no-domain.hocon +++ b/kinesis/src/it/resources/collector-cookie-no-domain.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-custom-paths.hocon b/kinesis/src/it/resources/collector-custom-paths.hocon index a39c6d87d..0d291144a 100644 --- a/kinesis/src/it/resources/collector-custom-paths.hocon +++ b/kinesis/src/it/resources/collector-custom-paths.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-doNotTrackCookie-disabled.hocon b/kinesis/src/it/resources/collector-doNotTrackCookie-disabled.hocon index 6f6f54155..36c210b16 100644 --- a/kinesis/src/it/resources/collector-doNotTrackCookie-disabled.hocon +++ b/kinesis/src/it/resources/collector-doNotTrackCookie-disabled.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector-doNotTrackCookie-enabled.hocon b/kinesis/src/it/resources/collector-doNotTrackCookie-enabled.hocon index 0604641ae..9873cb528 100644 --- a/kinesis/src/it/resources/collector-doNotTrackCookie-enabled.hocon +++ b/kinesis/src/it/resources/collector-doNotTrackCookie-enabled.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/it/resources/collector.hocon b/kinesis/src/it/resources/collector.hocon index 0183b1258..7feb06585 100644 --- a/kinesis/src/it/resources/collector.hocon +++ b/kinesis/src/it/resources/collector.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/kinesis/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/sinks/KinesisConfigSpec.scala b/kinesis/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/sinks/KinesisConfigSpec.scala index 1fda5e82a..d96e9ebdc 100644 --- a/kinesis/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/sinks/KinesisConfigSpec.scala +++ b/kinesis/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/sinks/KinesisConfigSpec.scala @@ -184,7 +184,8 @@ object KinesisConfigSpec { moduleVersion = None, instanceId = None, autoGeneratedId = None - ) + ), + license = Config.License(accept = true) ) } diff --git a/nsq/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/NsqConfigSpec.scala b/nsq/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/NsqConfigSpec.scala index 5986caebd..6ff188447 100644 --- a/nsq/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/NsqConfigSpec.scala +++ b/nsq/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/NsqConfigSpec.scala @@ -155,6 +155,7 @@ object NsqConfigSpec { networking = Config.Networking( maxConnections = 1024, idleTimeout = 610.seconds - ) + ), + license = Config.License(accept = true) ) } diff --git a/pubsub/src/it/resources/collector.hocon b/pubsub/src/it/resources/collector.hocon index d964fbe56..08533efbd 100644 --- a/pubsub/src/it/resources/collector.hocon +++ b/pubsub/src/it/resources/collector.hocon @@ -1,4 +1,5 @@ collector { + license { accept = true } interface = "0.0.0.0" port = ${PORT} diff --git a/pubsub/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/ConfigSpec.scala b/pubsub/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/ConfigSpec.scala index 8a513f9e0..a1c806db3 100644 --- a/pubsub/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/ConfigSpec.scala +++ b/pubsub/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/ConfigSpec.scala @@ -176,7 +176,8 @@ object ConfigSpec { moduleVersion = None, instanceId = None, autoGeneratedId = None - ) + ), + license = Config.License(accept = true) ) } diff --git a/sqs/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/SqsConfigSpec.scala b/sqs/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/SqsConfigSpec.scala index 4958f00c1..31b23eea0 100644 --- a/sqs/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/SqsConfigSpec.scala +++ b/sqs/src/test/scala/com.snowplowanalytics.snowplow.collectors.scalastream/SqsConfigSpec.scala @@ -164,7 +164,8 @@ object SqsConfigSpec { moduleVersion = None, instanceId = None, autoGeneratedId = None - ) + ), + license = Config.License(accept = true) ) }