mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
Merge branch 'main' into rust-ti-implementing-type-method
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
## 2.0.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.0.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/controlflow/change-notes/released/2.0.7.md
Normal file
3
shared/controlflow/change-notes/released/2.0.7.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.0.7
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.6
|
||||
lastReleaseVersion: 2.0.7
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/controlflow
|
||||
version: 2.0.7-dev
|
||||
version: 2.0.8-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.0.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.0.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/dataflow/change-notes/released/2.0.7.md
Normal file
3
shared/dataflow/change-notes/released/2.0.7.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.0.7
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.6
|
||||
lastReleaseVersion: 2.0.7
|
||||
|
||||
@@ -530,6 +530,93 @@ module Make<
|
||||
}
|
||||
}
|
||||
|
||||
private predicate isNonLocalSummaryComponent(SummaryComponent c) {
|
||||
c instanceof TArgumentSummaryComponent or
|
||||
c instanceof TParameterSummaryComponent or
|
||||
c instanceof TReturnSummaryComponent
|
||||
}
|
||||
|
||||
private predicate isLocalSummaryComponent(SummaryComponent c) {
|
||||
not isNonLocalSummaryComponent(c)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `s` is a valid input stack, in the sense that we generate a data flow graph
|
||||
* that faithfully represents this flow, and lambda-tracking can be expected to track
|
||||
* lambdas to the relevant callbacks in practice.
|
||||
*/
|
||||
private predicate isSupportedInputStack(SummaryComponentStack s) {
|
||||
// Argument[n].*
|
||||
s.length() = 1 and
|
||||
s.head() instanceof TArgumentSummaryComponent
|
||||
or
|
||||
// Argument[n].ReturnValue.*
|
||||
s.length() = 2 and
|
||||
s.head() instanceof TReturnSummaryComponent and
|
||||
s.tail().head() instanceof TArgumentSummaryComponent
|
||||
or
|
||||
// Argument[n].Parameter[n].Content.*
|
||||
s.length() = 3 and
|
||||
s.head() instanceof TContentSummaryComponent and
|
||||
s.tail().head() instanceof TParameterSummaryComponent and
|
||||
s.drop(2).head() instanceof TArgumentSummaryComponent
|
||||
or
|
||||
isSupportedInputStack(s.tail()) and
|
||||
isLocalSummaryComponent(s.head())
|
||||
}
|
||||
|
||||
private predicate isSupportedOutputStack1(SummaryComponentStack s) {
|
||||
// ReturnValue.*
|
||||
s.length() = 1 and
|
||||
s.head() instanceof TReturnSummaryComponent
|
||||
or
|
||||
// Argument[n].Content.*
|
||||
s.length() = 2 and
|
||||
s.head() instanceof TContentSummaryComponent and
|
||||
s.tail().head() instanceof TArgumentSummaryComponent
|
||||
or
|
||||
// Argument[n].Parameter[n].*
|
||||
s.length() = 2 and
|
||||
s.head() instanceof TParameterSummaryComponent and
|
||||
s.tail().head() instanceof TArgumentSummaryComponent
|
||||
or
|
||||
isSupportedOutputStack1(s.tail()) and
|
||||
isLocalSummaryComponent(s.head())
|
||||
}
|
||||
|
||||
/** Like `isSupportedInputStack` but for output stacks. */
|
||||
private predicate isSupportedOutputStack(SummaryComponentStack s) {
|
||||
isSupportedOutputStack1(s)
|
||||
or
|
||||
// `Argument[n]` not followed by anything. Needs to be outside the recursion.
|
||||
s.length() = 1 and
|
||||
s.head() instanceof TArgumentSummaryComponent
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `callable` has an unsupported flow `input -> output`.
|
||||
*
|
||||
* `whichOne` indicates if the `input` or `output` contains the unsupported sequence.
|
||||
*/
|
||||
predicate unsupportedCallable(
|
||||
SummarizedCallableImpl callable, SummaryComponentStack input, SummaryComponentStack output,
|
||||
string whichOne
|
||||
) {
|
||||
callable.propagatesFlow(input, output, _, _) and
|
||||
(
|
||||
not isSupportedInputStack(input) and whichOne = "input"
|
||||
or
|
||||
not isSupportedOutputStack(output) and whichOne = "output"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `callable` has an unsupported flow.
|
||||
*/
|
||||
predicate unsupportedCallable(SummarizedCallableImpl callable) {
|
||||
unsupportedCallable(callable, _, _, _)
|
||||
}
|
||||
|
||||
private predicate summarySpec(string spec) {
|
||||
exists(SummarizedCallable c |
|
||||
c.propagatesFlow(spec, _, _, _)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/dataflow
|
||||
version: 2.0.7-dev
|
||||
version: 2.0.8-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/mad/change-notes/released/1.0.23.md
Normal file
3
shared/mad/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -11,6 +11,7 @@ private import codeql.dataflow.internal.ContentDataFlowImpl
|
||||
private import codeql.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
||||
private import codeql.util.Location
|
||||
private import ModelPrinting
|
||||
private import codeql.util.Unit
|
||||
|
||||
/**
|
||||
* Provides language-specific model generator parameters.
|
||||
@@ -72,14 +73,14 @@ signature module ModelGeneratorCommonInputSig<LocationSig Location, InputSig<Loc
|
||||
* `pos` of callable `c`.
|
||||
*/
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsOutput(Callable c, Lang::ParameterPosition p);
|
||||
string paramReturnNodeAsApproximateOutput(Callable c, Lang::ParameterPosition p);
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of return through parameter at position
|
||||
* `pos` of callable `c` when used in content flow.
|
||||
*/
|
||||
bindingset[c]
|
||||
string paramReturnNodeAsContentOutput(Callable c, Lang::ParameterPosition pos);
|
||||
string paramReturnNodeAsExactOutput(Callable c, Lang::ParameterPosition pos);
|
||||
|
||||
/**
|
||||
* Gets the enclosing callable of `ret`.
|
||||
@@ -94,13 +95,13 @@ signature module ModelGeneratorCommonInputSig<LocationSig Location, InputSig<Loc
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter `p`.
|
||||
*/
|
||||
string parameterAccess(Parameter p);
|
||||
string parameterApproximateAccess(Parameter p);
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter `p`
|
||||
* when used in content flow.
|
||||
*/
|
||||
string parameterContentAccess(Parameter p);
|
||||
string parameterExactAccess(Parameter p);
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the qualifier.
|
||||
@@ -225,8 +226,12 @@ module MakeModelGeneratorFactory<
|
||||
containerContent(c)
|
||||
}
|
||||
|
||||
private string getOutput(ReturnNodeExt node) {
|
||||
result = PrintReturnNodeExt<paramReturnNodeAsOutput/2>::getOutput(node)
|
||||
private string getApproximateOutput(ReturnNodeExt node) {
|
||||
result = PrintReturnNodeExt<paramReturnNodeAsApproximateOutput/2>::getOutput(node)
|
||||
}
|
||||
|
||||
private string getExactOutput(ReturnNodeExt node) {
|
||||
result = PrintReturnNodeExt<paramReturnNodeAsExactOutput/2>::getOutput(node)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -319,6 +324,16 @@ module MakeModelGeneratorFactory<
|
||||
DataFlowSummaryTargetApi() { not isUninterestingForDataFlowModels(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter `p`
|
||||
* when used in exact flow.
|
||||
*/
|
||||
private string parameterNodeAsExactInput(DataFlow::ParameterNode p) {
|
||||
result = parameterExactAccess(asParameter(p))
|
||||
or
|
||||
result = qualifierString() and p instanceof InstanceParameterNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides classes and predicates related to capturing summary models
|
||||
* based on heuristic data flow.
|
||||
@@ -335,21 +350,25 @@ module MakeModelGeneratorFactory<
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter node `p`.
|
||||
*/
|
||||
string parameterNodeAsInput(DataFlow::ParameterNode p) {
|
||||
result = parameterAccess(asParameter(p))
|
||||
private string parameterNodeAsApproximateInput(DataFlow::ParameterNode p) {
|
||||
result = parameterApproximateAccess(asParameter(p))
|
||||
or
|
||||
result = qualifierString() and p instanceof InstanceParameterNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
|
||||
*
|
||||
* The strings `input` and `output` represent the qualifier and the return value, respectively.
|
||||
*/
|
||||
private string captureQualifierFlow(DataFlowSummaryTargetApi api) {
|
||||
private string captureQualifierFlow(DataFlowSummaryTargetApi api, string input, string output) {
|
||||
exists(ReturnNodeExt ret |
|
||||
api = returnNodeEnclosingCallable(ret) and
|
||||
isOwnInstanceAccessNode(ret)
|
||||
) and
|
||||
result = ModelPrintingSummary::asLiftedValueModel(api, qualifierString(), "ReturnValue")
|
||||
input = qualifierString() and
|
||||
output = "ReturnValue" and
|
||||
result = ModelPrintingSummary::asLiftedValueModel(api, input, output)
|
||||
}
|
||||
|
||||
private int accessPathLimit0() { result = 2 }
|
||||
@@ -394,14 +413,22 @@ module MakeModelGeneratorFactory<
|
||||
override string toString() { result = "TaintStore(" + step + ")" }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow configuration for tracking flow through APIs.
|
||||
* The sources are the parameters of an API and the sinks are the return values (excluding `this`) and parameters.
|
||||
*
|
||||
* This can be used to generate Flow summaries for APIs from parameter to return.
|
||||
*/
|
||||
private module PropagateFlowConfig implements DataFlow::StateConfigSig {
|
||||
class FlowState = TaintState;
|
||||
private signature module PropagateFlowConfigInputSig {
|
||||
class FlowState;
|
||||
|
||||
FlowState initialState();
|
||||
|
||||
default predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
private module PropagateFlowConfig<PropagateFlowConfigInputSig PropagateFlowConfigInput>
|
||||
implements DataFlow::StateConfigSig
|
||||
{
|
||||
import PropagateFlowConfigInput
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source instanceof DataFlow::ParameterNode and
|
||||
@@ -410,7 +437,7 @@ module MakeModelGeneratorFactory<
|
||||
c instanceof DataFlowSummaryTargetApi and
|
||||
not isUninterestingForHeuristicDataFlowModels(c)
|
||||
) and
|
||||
state.(TaintRead).getStep() = 0
|
||||
state = initialState()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
@@ -421,9 +448,34 @@ module MakeModelGeneratorFactory<
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink instanceof ReturnNodeExt and
|
||||
not isOwnInstanceAccessNode(sink) and
|
||||
not exists(captureQualifierFlow(getAsExprEnclosingCallable(sink)))
|
||||
not exists(captureQualifierFlow(getAsExprEnclosingCallable(sink), _, _))
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep = PropagateFlowConfigInput::isAdditionalFlowStep/4;
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t))
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A module used to construct a data flow configuration for tracking taint-
|
||||
* flow through APIs.
|
||||
* The sources are the parameters of an API and the sinks are the return
|
||||
* values (excluding `this`) and parameters.
|
||||
*
|
||||
* This can be used to generate flow summaries for APIs from parameter to
|
||||
* return.
|
||||
*/
|
||||
module PropagateFlowConfigInputTaintInput implements PropagateFlowConfigInputSig {
|
||||
class FlowState = TaintState;
|
||||
|
||||
FlowState initialState() { result.(TaintRead).getStep() = 0 }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
@@ -445,51 +497,117 @@ module MakeModelGeneratorFactory<
|
||||
state1.(TaintRead).getStep() + 1 = state2.(TaintRead).getStep()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node n) {
|
||||
exists(Type t | t = n.(NodeExtended).getType() and not isRelevantType(t))
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
|
||||
}
|
||||
}
|
||||
|
||||
module PropagateFlow = TaintTracking::GlobalWithState<PropagateFlowConfig>;
|
||||
/**
|
||||
* A data flow configuration for tracking taint-flow through APIs.
|
||||
* The sources are the parameters of an API and the sinks are the return
|
||||
* values (excluding `this`) and parameters.
|
||||
*
|
||||
* This can be used to generate flow summaries for APIs from parameter to
|
||||
* return.
|
||||
*/
|
||||
private module PropagateTaintFlowConfig =
|
||||
PropagateFlowConfig<PropagateFlowConfigInputTaintInput>;
|
||||
|
||||
module PropagateTaintFlow = TaintTracking::GlobalWithState<PropagateTaintFlowConfig>;
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
* A module used to construct a data flow configuration for tracking
|
||||
* data flow through APIs.
|
||||
* The sources are the parameters of an API and the sinks are the return
|
||||
* values (excluding `this`) and parameters.
|
||||
*
|
||||
* This can be used to generate value-preserving flow summaries for APIs
|
||||
* from parameter to return.
|
||||
*/
|
||||
string captureThroughFlow0(
|
||||
module PropagateFlowConfigInputDataFlowInput implements PropagateFlowConfigInputSig {
|
||||
class FlowState = Unit;
|
||||
|
||||
FlowState initialState() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data flow configuration for tracking data flow through APIs.
|
||||
* The sources are the parameters of an API and the sinks are the return
|
||||
* values (excluding `this`) and parameters.
|
||||
*
|
||||
* This can be used to generate flow summaries for APIs from parameter to
|
||||
* return.
|
||||
*/
|
||||
private module PropagateDataFlowConfig =
|
||||
PropagateFlowConfig<PropagateFlowConfigInputDataFlowInput>;
|
||||
|
||||
module PropagateDataFlow = DataFlow::GlobalWithState<PropagateDataFlowConfig>;
|
||||
|
||||
predicate captureThroughFlow0(
|
||||
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt
|
||||
) {
|
||||
exists(string input, string output |
|
||||
getEnclosingCallable(p) = api and
|
||||
getEnclosingCallable(returnNodeExt) = api and
|
||||
input = parameterNodeAsInput(p) and
|
||||
output = getOutput(returnNodeExt) and
|
||||
input != output and
|
||||
result = ModelPrintingSummary::asLiftedTaintModel(api, input, output)
|
||||
)
|
||||
captureThroughFlow0(api, p, _, returnNodeExt, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there should be a summary of `api` specifying flow
|
||||
* from `p` (with summary component `input`) to `returnNodeExt` (with
|
||||
* summary component `output`).
|
||||
*
|
||||
* `preservesValue` is true if the summary is value-preserving, or `false`
|
||||
* otherwise.
|
||||
*/
|
||||
private predicate captureThroughFlow0(
|
||||
DataFlowSummaryTargetApi api, DataFlow::ParameterNode p, string input,
|
||||
ReturnNodeExt returnNodeExt, string output, boolean preservesValue
|
||||
) {
|
||||
(
|
||||
PropagateDataFlow::flow(p, returnNodeExt) and
|
||||
input = parameterNodeAsExactInput(p) and
|
||||
output = getExactOutput(returnNodeExt) and
|
||||
preservesValue = true
|
||||
or
|
||||
not PropagateDataFlow::flow(p, returnNodeExt) and
|
||||
PropagateTaintFlow::flow(p, returnNodeExt) and
|
||||
input = parameterNodeAsApproximateInput(p) and
|
||||
output = getApproximateOutput(returnNodeExt) and
|
||||
preservesValue = false
|
||||
) and
|
||||
getEnclosingCallable(p) = api and
|
||||
getEnclosingCallable(returnNodeExt) = api and
|
||||
input != output
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
|
||||
*
|
||||
* `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise.
|
||||
*/
|
||||
private string captureThroughFlow(DataFlowSummaryTargetApi api) {
|
||||
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt |
|
||||
PropagateFlow::flow(p, returnNodeExt) and
|
||||
result = captureThroughFlow0(api, p, returnNodeExt)
|
||||
)
|
||||
private string captureThroughFlow(
|
||||
DataFlowSummaryTargetApi api, string input, string output, boolean preservesValue
|
||||
) {
|
||||
preservesValue = max(boolean b | captureThroughFlow0(api, _, input, _, output, b)) and
|
||||
result = ModelPrintingSummary::asLiftedModel(api, input, output, preservesValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow `input` to
|
||||
* `output`. `preservesValue` is `true` if the summary is value-
|
||||
* preserving, and `false` otherwise.
|
||||
*/
|
||||
string captureFlow(
|
||||
DataFlowSummaryTargetApi api, string input, string output, boolean preservesValue
|
||||
) {
|
||||
result = captureQualifierFlow(api, input, output) and preservesValue = true
|
||||
or
|
||||
result = captureThroughFlow(api, input, output, preservesValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the summary model(s) of `api`, if there is flow from parameters to the
|
||||
* return value or parameter or if `api` is a fluent API.
|
||||
*
|
||||
* `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise.
|
||||
*/
|
||||
string captureFlow(DataFlowSummaryTargetApi api) {
|
||||
result = captureQualifierFlow(api) or
|
||||
result = captureThroughFlow(api)
|
||||
string captureFlow(DataFlowSummaryTargetApi api, boolean preservesValue) {
|
||||
result = captureFlow(api, _, _, preservesValue)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,7 +617,7 @@ module MakeModelGeneratorFactory<
|
||||
*/
|
||||
string captureNoFlow(DataFlowSummaryTargetApi api) {
|
||||
not exists(DataFlowSummaryTargetApi api0 |
|
||||
exists(captureFlow(api0)) and api0.lift() = api.lift()
|
||||
exists(captureFlow(api0, _)) and api0.lift() = api.lift()
|
||||
) and
|
||||
api.isRelevant() and
|
||||
result = ModelPrintingSummary::asNeutralSummaryModel(api)
|
||||
@@ -550,20 +668,6 @@ module MakeModelGeneratorFactory<
|
||||
private module ContentModelPrinting =
|
||||
Printing::ModelPrintingSummary<ContentModelPrintingInput>;
|
||||
|
||||
private string getContentOutput(ReturnNodeExt node) {
|
||||
result = PrintReturnNodeExt<paramReturnNodeAsContentOutput/2>::getOutput(node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the MaD string representation of the parameter `p`
|
||||
* when used in content flow.
|
||||
*/
|
||||
private string parameterNodeAsContentInput(DataFlow::ParameterNode p) {
|
||||
result = parameterContentAccess(asParameter(p))
|
||||
or
|
||||
result = qualifierString() and p instanceof InstanceParameterNode
|
||||
}
|
||||
|
||||
private string getContent(PropagateContentFlow::AccessPath ap, int i) {
|
||||
result = "." + printContent(ap.getAtIndex(i))
|
||||
}
|
||||
@@ -639,8 +743,8 @@ module MakeModelGeneratorFactory<
|
||||
PropagateContentFlow::AccessPath stores
|
||||
|
|
||||
apiFlow(this, parameter, reads, returnNodeExt, stores, _) and
|
||||
input = parameterNodeAsContentInput(parameter) + printReadAccessPath(reads) and
|
||||
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores)
|
||||
input = parameterNodeAsExactInput(parameter) + printReadAccessPath(reads) and
|
||||
output = getExactOutput(returnNodeExt) + printStoreAccessPath(stores)
|
||||
)
|
||||
) <= 3
|
||||
}
|
||||
@@ -847,8 +951,8 @@ module MakeModelGeneratorFactory<
|
||||
PropagateContentFlow::AccessPath reads, PropagateContentFlow::AccessPath stores
|
||||
|
|
||||
apiRelevantContentFlow(api, p, reads, returnNodeExt, stores, preservesValue) and
|
||||
input = parameterNodeAsContentInput(p) + printReadAccessPath(reads) and
|
||||
output = getContentOutput(returnNodeExt) + printStoreAccessPath(stores) and
|
||||
input = parameterNodeAsExactInput(p) + printReadAccessPath(reads) and
|
||||
output = getExactOutput(returnNodeExt) + printStoreAccessPath(stores) and
|
||||
input != output and
|
||||
validateAccessPath(reads) and
|
||||
validateAccessPath(stores) and
|
||||
@@ -861,18 +965,20 @@ module MakeModelGeneratorFactory<
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the content based summary model(s) of the API `api` (if there is flow from a parameter to
|
||||
* the return value or a parameter). `lift` is true, if the model should be lifted, otherwise false.
|
||||
* Gets the content based summary model(s) of the API `api` (if there is flow from `input` to
|
||||
* `output`). `lift` is true, if the model should be lifted, otherwise false.
|
||||
* `preservesValue` is `true` if the summary is value-preserving, and `false` otherwise.
|
||||
*
|
||||
* Models are lifted to the best type in case the read and store access paths do not
|
||||
* contain a field or synthetic field access.
|
||||
*/
|
||||
string captureFlow(ContentDataFlowSummaryTargetApi api, boolean lift) {
|
||||
exists(string input, string output, boolean preservesValue |
|
||||
captureFlow0(api, input, output, _, lift) and
|
||||
preservesValue = max(boolean p | captureFlow0(api, input, output, p, lift)) and
|
||||
result = ContentModelPrinting::asModel(api, input, output, preservesValue, lift)
|
||||
)
|
||||
string captureFlow(
|
||||
ContentDataFlowSummaryTargetApi api, string input, string output, boolean lift,
|
||||
boolean preservesValue
|
||||
) {
|
||||
captureFlow0(api, input, output, _, lift) and
|
||||
preservesValue = max(boolean p | captureFlow0(api, input, output, p, lift)) and
|
||||
result = ContentModelPrinting::asModel(api, input, output, preservesValue, lift)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,17 +991,32 @@ module MakeModelGeneratorFactory<
|
||||
* generate flow summaries using the heuristic based summary generator.
|
||||
*/
|
||||
string captureFlow(DataFlowSummaryTargetApi api, boolean lift) {
|
||||
result = ContentSensitive::captureFlow(api, lift)
|
||||
result = ContentSensitive::captureFlow(api, _, _, lift, _)
|
||||
or
|
||||
not exists(DataFlowSummaryTargetApi api0 |
|
||||
(api0 = api or api.lift() = api0) and
|
||||
exists(ContentSensitive::captureFlow(api0, false))
|
||||
or
|
||||
api0.lift() = api.lift() and
|
||||
exists(ContentSensitive::captureFlow(api0, true))
|
||||
) and
|
||||
result = Heuristic::captureFlow(api) and
|
||||
lift = true
|
||||
exists(boolean preservesValue, string input, string output |
|
||||
not exists(
|
||||
DataFlowSummaryTargetApi api0, string input0, string output0, boolean preservesValue0
|
||||
|
|
||||
// If the heuristic summary is taint-based, and we can generate a content-sensitive
|
||||
// summary then we omit generating the heuristic summary.
|
||||
preservesValue = false
|
||||
or
|
||||
// If they're both value-preserving then we only generate a heuristic summary if
|
||||
// we didn't generate a content-sensitive summary on the same input/output pair.
|
||||
preservesValue = true and
|
||||
preservesValue0 = true and
|
||||
input0 = input and
|
||||
output0 = output
|
||||
|
|
||||
(api0 = api or api.lift() = api0) and
|
||||
exists(ContentSensitive::captureFlow(api0, input0, output0, false, preservesValue0))
|
||||
or
|
||||
api0.lift() = api.lift() and
|
||||
exists(ContentSensitive::captureFlow(api0, input0, output0, true, preservesValue0))
|
||||
) and
|
||||
result = Heuristic::captureFlow(api, input, output, preservesValue) and
|
||||
lift = true
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1056,7 +1177,7 @@ module MakeModelGeneratorFactory<
|
||||
sourceNode(source, kind) and
|
||||
api = getEnclosingCallable(sink) and
|
||||
not irrelevantSourceSinkApi(getEnclosingCallable(source), api) and
|
||||
result = ModelPrintingSourceOrSink::asSourceModel(api, getOutput(sink), kind)
|
||||
result = ModelPrintingSourceOrSink::asSourceModel(api, getExactOutput(sink), kind)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,9 +96,11 @@ module ModelPrintingImpl<ModelPrintingLangSig Lang> {
|
||||
/**
|
||||
* Gets the lifted taint summary model for `api` with `input` and `output`.
|
||||
*/
|
||||
bindingset[input, output]
|
||||
string asLiftedTaintModel(Printing::SummaryApi api, string input, string output) {
|
||||
result = asModel(api, input, output, false, true)
|
||||
bindingset[input, output, preservesValue]
|
||||
string asLiftedModel(
|
||||
Printing::SummaryApi api, string input, string output, boolean preservesValue
|
||||
) {
|
||||
result = asModel(api, input, output, preservesValue, true)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/mad
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
3
shared/quantum/CHANGELOG.md
Normal file
3
shared/quantum/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.1
|
||||
|
||||
No user-facing changes.
|
||||
3
shared/quantum/change-notes/released/0.0.1.md
Normal file
3
shared/quantum/change-notes/released/0.0.1.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.1
|
||||
|
||||
No user-facing changes.
|
||||
2
shared/quantum/codeql-pack.release.yml
Normal file
2
shared/quantum/codeql-pack.release.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.1
|
||||
2625
shared/quantum/codeql/quantum/experimental/Model.qll
Normal file
2625
shared/quantum/codeql/quantum/experimental/Model.qll
Normal file
File diff suppressed because it is too large
Load Diff
7
shared/quantum/qlpack.yml
Normal file
7
shared/quantum/qlpack.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
name: codeql/quantum
|
||||
version: 0.0.2-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/util: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/rangeanalysis/change-notes/released/1.0.23.md
Normal file
3
shared/rangeanalysis/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/rangeanalysis
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/regex/change-notes/released/1.0.23.md
Normal file
3
shared/regex/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/regex
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.1.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.1.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/ssa/change-notes/released/1.1.2.md
Normal file
3
shared/ssa/change-notes/released/1.1.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.1.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.1.1
|
||||
lastReleaseVersion: 1.1.2
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/ssa
|
||||
version: 1.1.2-dev
|
||||
version: 1.1.3-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/threat-models/change-notes/released/1.0.23.md
Normal file
3
shared/threat-models/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/threat-models
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
library: true
|
||||
groups: shared
|
||||
dataExtensions:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/tutorial/change-notes/released/1.0.23.md
Normal file
3
shared/tutorial/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: codeql/tutorial
|
||||
description: Library for the CodeQL detective tutorials, helping new users learn to
|
||||
write CodeQL queries.
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/typeflow/change-notes/released/1.0.23.md
Normal file
3
shared/typeflow/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/typeflow
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 0.0.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.0.3
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/typeinference/change-notes/released/0.0.4.md
Normal file
3
shared/typeinference/change-notes/released/0.0.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.0.4
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.3
|
||||
lastReleaseVersion: 0.0.4
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/typeinference
|
||||
version: 0.0.4-dev
|
||||
version: 0.0.5-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.0.7
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.0.6
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/typetracking/change-notes/released/2.0.7.md
Normal file
3
shared/typetracking/change-notes/released/2.0.7.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.0.7
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.6
|
||||
lastReleaseVersion: 2.0.7
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/typetracking
|
||||
version: 2.0.7-dev
|
||||
version: 2.0.8-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/typos/change-notes/released/1.0.23.md
Normal file
3
shared/typos/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/typos
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 2.0.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 2.0.9
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/util/change-notes/released/2.0.10.md
Normal file
3
shared/util/change-notes/released/2.0.10.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 2.0.10
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 2.0.9
|
||||
lastReleaseVersion: 2.0.10
|
||||
|
||||
@@ -221,57 +221,154 @@ module Make<InputSig Input> {
|
||||
|
||||
/** Provides logic related to `Folder`s. */
|
||||
module Folder {
|
||||
pragma[nomagic]
|
||||
private Container getAChildContainer(Container c, string baseName) {
|
||||
result = c.getAChildContainer() and
|
||||
baseName = result.getBaseName()
|
||||
}
|
||||
|
||||
/** Holds if `relativePath` needs to be appended to `f`. */
|
||||
signature predicate shouldAppendSig(Folder f, string relativePath);
|
||||
|
||||
/** Provides the `append` predicate for appending a relative path onto a folder. */
|
||||
module Append<shouldAppendSig/2 shouldAppend> {
|
||||
pragma[nomagic]
|
||||
private string getComponent(string relativePath, int i) {
|
||||
shouldAppend(_, relativePath) and
|
||||
result = relativePath.replaceAll("\\", "/").regexpFind("[^/]+", i, _)
|
||||
private module Config implements ResolveSig {
|
||||
predicate shouldResolve(Container c, string name) { shouldAppend(c, name) }
|
||||
}
|
||||
|
||||
private int getNumberOfComponents(string relativePath) {
|
||||
result = strictcount(int i | exists(getComponent(relativePath, i)) | i)
|
||||
predicate append = Resolve<Config>::resolve/2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signature for modules to pass to `Resolve`.
|
||||
*/
|
||||
signature module ResolveSig {
|
||||
/**
|
||||
* Holds if `path` should be resolved to a file or folder, relative to `base`.
|
||||
*/
|
||||
predicate shouldResolve(Container base, string path);
|
||||
|
||||
/**
|
||||
* Gets an additional file or folder to consider a child of `base`.
|
||||
*/
|
||||
default Container getAnAdditionalChild(Container base, string name) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `component` may be treated as `.` if it does not match a child.
|
||||
*/
|
||||
default predicate isOptionalPathComponent(string component) { none() }
|
||||
|
||||
/**
|
||||
* Holds if globs should be interpreted in the paths being resolved.
|
||||
*
|
||||
* The following types of globs are supported:
|
||||
* - `*` (matches any child)
|
||||
* - `**` (matches any child recursively)
|
||||
* - Complex patterns like `foo-*.txt` are also supported
|
||||
*/
|
||||
default predicate allowGlobs() { none() }
|
||||
|
||||
/**
|
||||
* Gets an alternative path segment to try if `segment` did not match a child.
|
||||
*
|
||||
* The motivating use-case is to map compiler-generated file names back to their sources files,
|
||||
* for example, `foo.min.js` could be mapped to `foo.ts`.
|
||||
*/
|
||||
bindingset[segment]
|
||||
default string rewritePathSegment(string segment) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a mechanism for resolving file paths relative to a given directory.
|
||||
*/
|
||||
module Resolve<ResolveSig Config> {
|
||||
private import Config
|
||||
|
||||
pragma[nomagic]
|
||||
private string getPathSegment(string path, int n) {
|
||||
shouldResolve(_, path) and
|
||||
result = path.replaceAll("\\", "/").splitAt("/", n)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private string getPathSegmentAsGlobRegexp(string segment) {
|
||||
allowGlobs() and
|
||||
segment = getPathSegment(_, _) and
|
||||
segment.matches("%*%") and
|
||||
not segment = ["*", "**"] and // these are special-cased
|
||||
result = segment.regexpReplaceAll("[^a-zA-Z0-9*]", "\\\\$0").replaceAll("*", ".*")
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private int getNumPathSegment(string path) {
|
||||
result = strictcount(int n | exists(getPathSegment(path, n)))
|
||||
}
|
||||
|
||||
private Container getChild(Container base, string name) {
|
||||
result = getAChildContainer(base, name)
|
||||
or
|
||||
relativePath = "" and
|
||||
result = 0
|
||||
result = getAnAdditionalChild(base, name)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Container getAChildContainer(Container c, string baseName) {
|
||||
result = c.getAChildContainer() and
|
||||
baseName = result.getBaseName()
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private Container appendStep(Folder f, string relativePath, int i) {
|
||||
i = -1 and
|
||||
shouldAppend(f, relativePath) and
|
||||
result = f
|
||||
private Container resolve(Container base, string path, int n) {
|
||||
shouldResolve(base, path) and n = 0 and result = base
|
||||
or
|
||||
exists(Container mid, string comp |
|
||||
mid = appendStep(f, relativePath, i - 1) and
|
||||
comp = getComponent(relativePath, i) and
|
||||
if comp = ".."
|
||||
then result = mid.getParentContainer()
|
||||
else
|
||||
if comp = "."
|
||||
then result = mid
|
||||
else result = getAChildContainer(mid, comp)
|
||||
exists(Container current, string segment |
|
||||
current = resolve(base, path, n - 1) and
|
||||
segment = getPathSegment(path, n - 1)
|
||||
|
|
||||
result = getChild(current, segment)
|
||||
or
|
||||
segment = [".", ""] and
|
||||
result = current
|
||||
or
|
||||
segment = ".." and
|
||||
result = current.getParentContainer()
|
||||
or
|
||||
not exists(getChild(current, segment)) and
|
||||
(
|
||||
isOptionalPathComponent(segment) and
|
||||
result = current
|
||||
or
|
||||
result = getChild(current, rewritePathSegment(segment))
|
||||
)
|
||||
or
|
||||
allowGlobs() and
|
||||
(
|
||||
segment = "*" and
|
||||
result = getChild(current, _)
|
||||
or
|
||||
segment = "**" and // allow empty match
|
||||
result = current
|
||||
or
|
||||
exists(string name |
|
||||
result = getChild(current, name) and
|
||||
name.regexpMatch(getPathSegmentAsGlobRegexp(segment))
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Container current, string segment |
|
||||
current = resolve(base, path, n) and
|
||||
segment = getPathSegment(path, n)
|
||||
|
|
||||
// Follow child without advancing 'n'
|
||||
allowGlobs() and
|
||||
segment = "**" and
|
||||
result = getChild(current, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file or folder obtained by appending `relativePath` onto `f`.
|
||||
* Gets the file or folder that `path` resolves to when resolved from `base`.
|
||||
*
|
||||
* Only has results for the `(base, path)` pairs provided by `shouldResolve`
|
||||
* in the instantiation of this module.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Container append(Folder f, string relativePath) {
|
||||
exists(int last |
|
||||
last = getNumberOfComponents(relativePath) - 1 and
|
||||
result = appendStep(f, relativePath, last)
|
||||
)
|
||||
Container resolve(Container base, string path) {
|
||||
result = resolve(base, path, getNumPathSegment(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/util
|
||||
version: 2.0.10-dev
|
||||
version: 2.0.11-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies: null
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/xml/change-notes/released/1.0.23.md
Normal file
3
shared/xml/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/xml
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 1.0.22
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
3
shared/yaml/change-notes/released/1.0.23.md
Normal file
3
shared/yaml/change-notes/released/1.0.23.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 1.0.23
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 1.0.22
|
||||
lastReleaseVersion: 1.0.23
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/yaml
|
||||
version: 1.0.23-dev
|
||||
version: 1.0.24-dev
|
||||
groups: shared
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
|
||||
Reference in New Issue
Block a user