av9ash/GitBugs huggingface dataset:
Bug: Are hadoop committers used in Structured Streaming?
Status: Open | Priority: Major | Resolution: 
Created: 08/Mar/22 09:26
Affects Version/s: 3.2.1

At the company I work at we're using Spark Structured Streaming to sink messages on kafka to HDFS. We're in the late stages of migrating this component to instead sink messages to AWS S3, and in connection with that we hit upon a couple of issues regarding hadoop committers.

I've come to understand that the default "file" committer (documented [here|https://hadoop.apache.org/docs/stable/hadoop-aws/tools/hadoop-aws/committers.html#Switching_to_an_S3A_Committer]) is unsafe to use in S3, which is why [this page in the spark documentation|https://spark.apache.org/docs/3.2.1/cloud-integration.html] recommends using the "directory" (i.e. staging) committer, and in later versions of hadoop they also recommend to use the "magic" committer.

However, it's not clear whether spark structured streaming even use committers. There's no "_SUCCESS" file in destination (as compared to normal spark jobs), and the documentation regarding committers used in streaming is non-existent.

Can anyone please shed some light on this?
Bug: Use error classes in the execution errors of dictionary encoding
Status: In Progress | Priority: Major | Resolution: 
Created: 30/Mar/22 13:32
Affects Version/s: 3.4.0

Migrate the following errors in QueryExecutionErrors:
* useDictionaryEncodingWhenDictionaryOverflowError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryExecutionErrorsSuite.
Bug: Don't push down limit through window that's using percent_rank
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 21/Mar/22 12:29
Affects Version/s: 3.2.0

Expected result is obtained using Spark 3.1.2, but not 3.2.0, 3.2.1 or 3.3.0.

*Minimal reproducible example*
{code:java}
from pyspark.sql import SparkSession, functions as F, Window as W
spark = SparkSession.builder.getOrCreate()
 
df = spark.range(101).withColumn('pr', F.percent_rank().over(W.orderBy('id')))
df.show(3)
df.show(5) {code}
*Expected result*
{code:java}
+---+----+
| id|  pr|
+---+----+
|  0| 0.0|
|  1|0.01|
|  2|0.02|
+---+----+
only showing top 3 rows

+---+----+
| id|  pr|
+---+----+
|  0| 0.0|
|  1|0.01|
|  2|0.02|
|  3|0.03|
|  4|0.04|
+---+----+
only showing top 5 rows{code}
*Actual result*
{code:java}
+---+------------------+
| id|                pr|
+---+------------------+
|  0|               0.0|
|  1|0.3333333333333333|
|  2|0.6666666666666666|
+---+------------------+
only showing top 3 rows

+---+---+
| id| pr|
+---+---+
|  0|0.0|
|  1|0.2|
|  2|0.4|
|  3|0.6|
|  4|0.8|
+---+---+
only showing top 5 rows{code}
Bug: Use error classes in the compilation errors of column/attr resolving
Status: Open | Priority: Major | Resolution: 
Created: 29/Mar/22 19:03
Affects Version/s: 3.4.0

Migrate the following errors in QueryCompilationErrors:
* cannotResolveUserSpecifiedColumnsError
* cannotResolveStarExpandGivenInputColumnsError
* cannotResolveAttributeError
* cannotResolveColumnGivenInputColumnsError
* cannotResolveColumnNameAmongAttributesError
* cannotResolveColumnNameAmongFieldsError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryCompilationErrorsSuite.
Bug: Use error classes in the execution errors of save mode
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 30/Mar/22 13:37
Affects Version/s: 3.4.0

Migrate the following errors in QueryExecutionErrors:
* unsupportedSaveModeError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryExecutionErrorsSuite.
Bug: Use error classes in the compilation errors of generators
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 29/Mar/22 18:50
Affects Version/s: 3.4.0

Migrate the following errors in QueryCompilationErrors:
* nestedGeneratorError
* moreThanOneGeneratorError
* generatorOutsideSelectError
* generatorNotExpectedError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryCompilationErrorsSuite.
Bug: Add SupportsReportOrdering mix in interface for Scan
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 24/Mar/22 15:03
Affects Version/s: 3.3.0

As {{SupportsReportPartitioning}} allows implementations of {{Scan}} provide Spark with information about the exiting partitioning of data read by a {{{}DataSourceV2{}}}, a similar mix in interface {{SupportsReportOrdering}} should provide order information.

This prevents Spark from sorting data if they already exhibit a certain order provided by the source.
Bug: Use error classes in the compilation errors of deserializer
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 29/Mar/22 18:53
Affects Version/s: 3.4.0

Migrate the following errors in QueryCompilationErrors:
* dataTypeMismatchForDeserializerError
* fieldNumberMismatchForDeserializerError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryCompilationErrorsSuite.
Bug: Week of month from a date is missing in spark3 for return values of 1 to 6
Status: Open | Priority: Major | Resolution: 
Created: 16/Mar/22 14:31
Affects Version/s: 3.1.2

In Spark2 we could use the date_format function with either the W or F flags to compute week of month from a date.  These are computing two different items, the W is having values from 1 to 6 and the F is having values from 1 to 5

Sample code and output of expected
df1 = spark.createDataFrame(
    [
        (1, date(2014, 3, 7)),
        (2, date(2014, 3, 8)),
        (3, date(2014, 3, 30)),
        (4, date(2014, 3, 31)),
        (5, date(2015, 3, 7)),
        (6, date(2015, 3, 8)),
        (7, date(2015, 3, 30)),
        (8, date(2015, 3, 31)),
    ],
    schema="a long, b date",
)
df1 = df1.withColumn("WEEKOFMONTH1-6", F.date_format(F.col("b"), "W"))
df1 = df1.withColumn("WEEKOFMONTH1-5", F.date_format(F.col("b"), "F"))
df1.show()



{+}--{-}{-}{+}--------{-}++{-}------------{-}{-}-------------+                                                                                                                        
| a|        b|WEEKOFMONTH1-6|WEEKOFMONTH1-5|

{+}--{-}{-}{+}--------{-}++{-}------------{-}{-}-------------+
| 1|2014-03-07|            2|            1|
| 2|2014-03-08|            2|            2|
| 3|2014-03-30|            6|            5|
| 4|2014-03-31|            6|            5|
| 5|2015-03-07|            1|            1|
| 6|2015-03-08|            2|            2|
| 7|2015-03-30|            5|            5|
| 8|2015-03-31|            5|            5|

{+}--{-}{-}{+}--------{-}++{-}------------{-}{-}-------------+

 

With the Spark3 having the spark.sql.legacy.timeParserPolicy set to 
EXCEPTION by default this throws an error:
Caused by: java.lang.IllegalArgumentException: All week-based patterns are unsupported since Spark 3.0, detected: W, Please use the SQL function EXTRACT instead
 
However from the EXTRACT function there is nothing available that is extracting the week of month for the values 1 to 6
 
The Spark3 mentions they define our own patterns  located at [https://spark.apache.org/docs/3.2.1/sql-ref-datetime-pattern.html] that are implemented via DateTimeFormatter under the hood: 
[https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html]
 
That site is listing both W and F for week of month
 W week-of-month number 4
 F week-of-month number 3
 
However only F is implemented on the datetime pattern reference
 
Is there another way we can compute this week of month for values 1 to 6 by still using the builtin with Spark3?  Currently we have to set the spark.sql.legacy.timeParserPolicy to LEGACY in order to run this
 
Thank you,
 
Kevin
Bug: Encryption algorithms should be used with secure mode and padding scheme
Status: Resolved | Priority: Major | Resolution: Not A Problem
Created: 05/Mar/22 14:25
Affects Version/s: 3.3.0

I have scanned java files with Sonarqube and in https://github.com/apache/spark/blob/master/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java


{code:java}
try {
      if (mode.equalsIgnoreCase("ECB") &&
          (padding.equalsIgnoreCase("PKCS") || padding.equalsIgnoreCase("DEFAULT"))) {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
{code}


Encryption operation mode and the padding scheme should be chosen appropriately to guarantee data confidentiality, integrity and authenticity:

For block cipher encryption algorithms (like AES):
The GCM (Galois Counter Mode) mode which works internally with zero/no padding scheme, is recommended, as it is designed to provide both data authenticity (integrity) and confidentiality. Other similar modes are CCM, CWC, EAX, IAPM and OCB.
The CBC (Cipher Block Chaining) mode by itself provides only data confidentiality, it’s recommended to use it along with Message Authentication Code or similar to achieve data authenticity (integrity) too and thus to prevent padding oracle attacks.
The ECB (Electronic Codebook) mode doesn’t provide serious message confidentiality: under a given key any given plaintext block always gets encrypted to the same ciphertext block. This mode should not be used.
For RSA encryption algorithm, the recommended padding scheme is OAEP.



[OWASP Top 10 2021|https://owasp.org/Top10/A02_2021-Cryptographic_Failures/] Category A2 - Cryptographic Failures

[OWASP Top 10 2017|https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration.html] Category A6 - Security Misconfiguration

[Mobile AppSec|https://mobile-security.gitbook.io/masvs/security-requirements/0x08-v3-cryptography_verification_requirements] Verification Standard - Cryptography Requirements

[OWASP Mobile Top 10 2016|https://owasp.org/www-project-mobile-top-10/2016-risks/m5-insufficient-cryptography] Category M5 - Insufficient Cryptography

[MITRE, CWE-327|https://cwe.mitre.org/data/definitions/327.html]  - Use of a Broken or Risky Cryptographic Algorithm

[CERT, MSC61-J.|https://wiki.sei.cmu.edu/confluence/display/java/MSC61-J.+Do+not+use+insecure+or+weak+cryptographic+algorithms] - Do not use insecure or weak cryptographic algorithms

[SANS Top 25|https://www.sans.org/top25-software-errors/#cat3] - Porous Defenses
Bug: OffsetWindowFunctionFrameBase cannot find the offset row whose input is not null
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 25/Mar/22 09:09
Affects Version/s: 3.3.0

select x, nth_value(x, 5) IGNORE NULLS over (order by x rows between unbounded preceding and current row)
from (select explode(sequence(1, 3)) x)

returns
null
null
3

But it should returns
null
null
null
Bug: Non-deterministic UDF executed multiple times when combined with withField
Status: Open | Priority: Major | Resolution: 
Created: 09/Mar/22 18:11
Affects Version/s: 3.3.0

When adding fields to a result of a non-deterministic UDF, that returns a struct, then that UDF is executed multiple times (once per field) for each row.

In this UT df1 passes, but df2 fails with something like:
"279751724 did not equal -1023188908"

{code}
  test("SPARK-XXXXX: non-deterministic UDF should be called once when adding fields") {
    val nondeterministicUDF = udf((s: Int) => {
      val r = Random.nextInt()
      // Both values should be the same
      GroupByKey(r, r)
    }).asNondeterministic()

    val df1 = spark.range(5).select(nondeterministicUDF($"id"))
    df1.collect().foreach {
      row => assert(row.getStruct(0).getInt(0) == row.getStruct(0).getInt(1))
    }

    val df2 = spark.range(5).select(nondeterministicUDF($"id").withField("new", lit(7)))
    df2.collect().foreach {
      row => assert(row.getStruct(0).getInt(0) == row.getStruct(0).getInt(1))
    }
  }
{code}
Bug: Support nested generic case classes
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 29/Mar/22 07:03
Affects Version/s: 3.3.0

Spark fail to derive schemas when using nested case class with generic parameters. 

Example

{code:java}
case class GenericData[A](
    genericField: A)
{code}

Will derive a correct schema for `GenericData[Int]` but if the classes are nested e.g.

{code:java}
case class NestedGeneric[T](
  generic: GenericData[T])
{code}

it will fail to derive a schema for `NestedGeneric[Int]`.
Bug: Support Kueue: K8s-native Job Queueing
Status: Open | Priority: Major | Resolution: 
Created: 03/Mar/22 03:31
Affects Version/s: 3.4.0

There are several ways to run Spark on K8s including vanilla `spark-submit` with built-in  `KubernetesClusterManager`, `spark-submit` with custom `ExternalClusterManager`, CRD-based operators (like spark-on-k8s-operator), custom K8s `schedulers`, custom `standalone pod definitions`, and so on.

This issue is tracking K8s-native Job Queueing related work.
 * [https://github.com/kubernetes-sigs/kueue]
{code}
metadata:
  generateName: sample-job-
  annotations:
    kueue.k8s.io/queue-name: main
{code}

The best case is Apache Spark users use it in the future via pod templates or existing configuration. In other words, we don't need to do anything and close this JIRA without any patches.

*Documentation*
- https://github.com/kubernetes-sigs/kueue/tree/main/docs

*Release History*
- https://github.com/kubernetes-sigs/kueue/releases/tag/v0.1.0
Bug: Improve the test coverage for PySpark
Status: Open | Priority: Major | Resolution: 
Created: 10/Mar/22 05:42
Affects Version/s: 3.3.0

Currently, PySpark test coverage is around 91% according to codecov report: [https://app.codecov.io/gh/apache/spark|https://app.codecov.io/gh/apache/spark]

Since there are still 9% missing tests, so I think it would be great to improve our test coverage.

Of course we might not target to 100%, but as much as possible, to the level that we can currently cover with CI.
Bug: Add option for partial nested field writes with nullable fields.
Status: Open | Priority: Major | Resolution: 
Created: 03/Mar/22 17:39
Affects Version/s: 3.3.0

If a nested field has nullable entries a user shouldn't have to specify all of the fields, instead the nullable fields can have the default value of null. This will allow for more effective schema migration. We might want to put this behind a feature flag though.
Bug: Use error classes in the compilation errors of SHOW CREATE TABLE
Status: Open | Priority: Major | Resolution: 
Created: 29/Mar/22 18:59
Affects Version/s: 3.4.0

Migrate the following errors in QueryCompilationErrors:
* showCreateTableAsSerdeNotSupportedForV2TablesError
* showCreateTableNotSupportedOnTempView
* showCreateTableFailToExecuteUnsupportedFeatureError
* showCreateTableNotSupportTransactionalHiveTableError
* showCreateTableFailToExecuteUnsupportedConfError
* showCreateTableAsSerdeNotAllowedOnSparkDataSourceTableError
* showCreateTableOrViewFailToExecuteUnsupportedFeatureError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryCompilationErrorsSuite.
Bug: Optimizer generates error when using inner join along with sequence
Status: Resolved | Priority: Major | Resolution: Resolved
Created: 27/Mar/22 19:04
Affects Version/s: 3.1.2

This issue occurred in a more complex scenario, so I've broken it down into a simple case.

{*}Steps to reproduce{*}: Execute the following example. The code should run without errors, but instead a *java.lang.IllegalArgumentException: Illegal sequence boundaries: 4 to 2 by 1* is thrown.
{code:java}
package com.example

import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._

object SparkIssue {
    def main(args: Array[String]): Unit = {

        val spark = SparkSession
            .builder()
            .master("local[*]")
            .getOrCreate()

        val dfA = spark
            .createDataFrame(Seq((1, 1), (2, 4)))
            .toDF("a1", "a2")

        val dfB = spark
            .createDataFrame(Seq((1, 5), (2, 2)))
            .toDF("b1", "b2")

        dfA.join(dfB, dfA("a1") === dfB("b1"), "inner")
            .where(col("a2") < col("b2"))
            .withColumn("x", explode(sequence(col("a2"), col("b2"), lit(1))))
            .show()

        spark.stop()

    }
}
{code}

When I look at the Optimized Logical Plan I can see that the Inner Join and the Filter are brought together, with an additional check for an empty Sequence. The exception is thrown because the Sequence check is executed before the Filter.
{code:java}
== Parsed Logical Plan ==
'Project [a1#4, a2#5, b1#12, b2#13, explode(sequence('a2, 'b2, Some(1), None)) AS x#24]
+- Filter (a2#5 < b2#13)
   +- Join Inner, (a1#4 = b1#12)
      :- Project [_1#0 AS a1#4, _2#1 AS a2#5]
      :  +- LocalRelation [_1#0, _2#1]
      +- Project [_1#8 AS b1#12, _2#9 AS b2#13]
         +- LocalRelation [_1#8, _2#9]

== Analyzed Logical Plan ==
a1: int, a2: int, b1: int, b2: int, x: int
Project [a1#4, a2#5, b1#12, b2#13, x#25]
+- Generate explode(sequence(a2#5, b2#13, Some(1), Some(Europe/Berlin))), false, [x#25]
   +- Filter (a2#5 < b2#13)
      +- Join Inner, (a1#4 = b1#12)
         :- Project [_1#0 AS a1#4, _2#1 AS a2#5]
         :  +- LocalRelation [_1#0, _2#1]
         +- Project [_1#8 AS b1#12, _2#9 AS b2#13]
            +- LocalRelation [_1#8, _2#9]

== Optimized Logical Plan ==
Generate explode(sequence(a2#5, b2#13, Some(1), Some(Europe/Berlin))), false, [x#25]
+- Join Inner, (((size(sequence(a2#5, b2#13, Some(1), Some(Europe/Berlin)), true) > 0) AND (a2#5 < b2#13)) AND (a1#4 = b1#12))
   :- LocalRelation [a1#4, a2#5]
   +- LocalRelation [b1#12, b2#13]

== Physical Plan ==
Generate explode(sequence(a2#5, b2#13, Some(1), Some(Europe/Berlin))), [a1#4, a2#5, b1#12, b2#13], false, [x#25]
+- *(1) BroadcastHashJoin [a1#4], [b1#12], Inner, BuildRight, ((size(sequence(a2#5, b2#13, Some(1), Some(Europe/Berlin)), true) > 0) AND (a2#5 < b2#13)), false
   :- *(1) LocalTableScan [a1#4, a2#5]
   +- BroadcastExchange HashedRelationBroadcastMode(List(cast(input[0, int, false] as bigint)),false), [id=#15]
      +- LocalTableScan [b1#12, b2#13]
{code}
Bug: Use error classes in the compilation errors of function args
Status: In Progress | Priority: Major | Resolution: 
Created: 29/Mar/22 19:07
Affects Version/s: 3.4.0

Migrate the following errors in QueryCompilationErrors:
* invalidFunctionArgumentsError
* invalidFunctionArgumentNumberError
* functionAcceptsOnlyOneArgumentError
* secondArgumentNotDoubleLiteralError
* functionCannotProcessInputError
* v2FunctionInvalidInputTypeLengthError
* secondArgumentInFunctionIsNotBooleanLiteralError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryCompilationErrorsSuite.
Bug: Spark does not use SessionManager
Status: Open | Priority: Major | Resolution: 
Created: 29/Mar/22 19:44
Affects Version/s: 3.2.1

Spark's failure to use a `SessionManager` causes `java.lang.IllegalStateException: No SessionManager` that prevents Spark UI from being used with [org.keycloak.adapters.servlet.KeycloakOIDCFilter|#_servlet_filter_adapter] as the `spark.ui.filters` class.

 

Sample logs:

 
{code:java}
spark_1 | 22/03/29 18:43:24 INFO KeycloakDeployment: Loaded URLs from http://REDACTED/auth/realms/master/.well-known/openid-configuration
spark_1 | 22/03/29 18:43:24 WARN HttpChannel: /
spark_1 | java.lang.IllegalStateException: No SessionManager{code}
 

Configuration:

 

 
{code:java}
spark.ui.filters=org.keycloak.adapters.servlet.KeycloakOIDCFilter
spark.acls.enable=true
spark.admin.acls=*
spark.ui.view.acls=*
spark.org.keycloak.adapters.servlet.KeycloakOIDCFilter.param.keycloak.config.file=/opt/bitnami/spark/conf/spark-keycloak.json
 
{code}
 

Above `spark-keycloak.json` contains configuration generated in the Keycloak admin console. We can see that Spark gets as far as allowing the KeycloakOIDCFilter class to read this file and initiate communication with keycloak.

 

This IllegalStateException exception emanates from Jetty:

 

[https://github.com/eclipse/jetty.project/blob/ae5c8e34e7dd4f5cce5f649e48469ba3bbc51d91/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java#L1524]

 

It appears that Spark's `ServletContextHandler` has the ability to use a `SessionManager` but doesn't. This seems to be a blocker that prevents integration with Keycloak entirely.
Bug: Use error classes in the compilation errors of not allowed DESC PARTITION
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 29/Mar/22 18:56
Affects Version/s: 3.4.0

Migrate the following errors in QueryCompilationErrors:
* descPartitionNotAllowedOnTempView
* descPartitionNotAllowedOnView
* descPartitionNotAllowedOnViewError

onto use error classes. Throw an implementation of SparkThrowable. Also write a test per every error in QueryCompilationErrorsSuite.
Bug: PrometheusServlet exports gauges with null values
Status: In Progress | Priority: Major | Resolution: 
Created: 03/Mar/22 19:54
Affects Version/s: 3.2.1

[PrometheusServlet|#L63] exports gauges with value null as {{{}gauge_name{} null{}}}. This can for instance happen if one initializes a [DefaultSettableGauge|https://www.javadoc.io/static/io.dropwizard.metrics/metrics-core/4.2.0-beta.3/com/codahale/metrics/DefaultSettableGauge.html] without a default value. Null values are not scraped by Prometheus as null is not a valid floating point value. A null value prevents any metrics from being scraped and the endpoint will be considered to be down by Prometheus. A solution could be to omit listing the gauge if its value is null.
Bug: NPE with unpersisting memory-only RDD with RDD fetching from shuffle service enabled
Status: Resolved | Priority: Major | Resolution: Fixed
Created: 24/Mar/22 00:00
Affects Version/s: 3.2.1

If you have RDD fetching from shuffle service enabled, memory-only cached RDDs will fail to unpersist.

 

 
{code:java}
// spark.shuffle.service.fetch.rdd.enabled=true
val df = spark.range(5)
  .persist(StorageLevel.MEMORY_ONLY)
df.count()
df.unpersist(true)
{code}
Bug: Cipher Block Chaining IVs should be unpredictable
Status: Resolved | Priority: Major | Resolution: Not A Problem
Created: 05/Mar/22 14:10
Affects Version/s: 3.3.0

I have scanned java files with Sonarqube and in https://github.com/apache/spark/blob/master/common/network-common/src/main/java/org/apache/spark/network/crypto/TransportCipher.java 


{code:java}
 @VisibleForTesting
  CryptoOutputStream createOutputStream(WritableByteChannel ch) throws IOException {
    return new CryptoOutputStream(cipher, conf, ch, key, new IvParameterSpec(outIv));

@VisibleForTesting
  CryptoInputStream createInputStream(ReadableByteChannel ch) throws IOException {
    return new CryptoInputStream(cipher, conf, ch, key, new IvParameterSpec(inIv));
{code}

When encrypting data with the Cipher Block Chaining (CBC) mode an Initialization Vector (IV) is used to randomize the encryption, ie under a given key the same plaintext doesn’t always produce the same ciphertext. The IV doesn’t need to be secret but should be unpredictable to avoid "Chosen-Plaintext Attack".

To generate Initialization Vectors, NIST recommends to use a secure random number generator.


[OWASP Top 10 2021|https://owasp.org/Top10/A02_2021-Cryptographic_Failures/] Category A2 - Cryptographic Failures

[OWASP Top 10|https://owasp.org/www-project-top-ten/2017/A6_2017-Security_Misconfiguration.html] 2017 Category A6 - Security Misconfiguration

[MITRE, CWE-329|https://cwe.mitre.org/data/definitions/329.html] - CWE-329: Not Using an Unpredictable IV with CBC Mode

[MITRE, CWE-330|https://cwe.mitre.org/data/definitions/330.html] - Use of Insufficiently Random Values

[NIST, SP-800-38A|https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf] - Recommendation for Block Cipher Modes of Operation

Derived from FindSecBugs [rule STATIC_IV|https://find-sec-bugs.github.io/bugs.htm#STATIC_IV]