Update model editor queries
This updates the model editor queries to the version that will be merged into the CodeQL repository. There are some slight changes to the output format, so we slightly need to change the BQRS decoding of those queries. The queries themselves were copied from the two PRs with some minor additions at the end since these were changes in core CodeQL library files.
This commit is contained in:
@@ -2,41 +2,72 @@ import { DecodedBqrsChunk } from "../common/bqrs-cli-types";
|
|||||||
import { Call, CallClassification, Method } from "./method";
|
import { Call, CallClassification, Method } from "./method";
|
||||||
import { ModeledMethodType } from "./modeled-method";
|
import { ModeledMethodType } from "./modeled-method";
|
||||||
import { parseLibraryFilename } from "./library";
|
import { parseLibraryFilename } from "./library";
|
||||||
|
import { Mode } from "./shared/mode";
|
||||||
|
import { ApplicationModeTuple, FrameworkModeTuple } from "./queries/query";
|
||||||
|
|
||||||
export function decodeBqrsToMethods(chunk: DecodedBqrsChunk): Method[] {
|
export function decodeBqrsToMethods(
|
||||||
|
chunk: DecodedBqrsChunk,
|
||||||
|
mode: Mode,
|
||||||
|
): Method[] {
|
||||||
const methodsByApiName = new Map<string, Method>();
|
const methodsByApiName = new Map<string, Method>();
|
||||||
|
|
||||||
chunk?.tuples.forEach((tuple) => {
|
chunk?.tuples.forEach((tuple) => {
|
||||||
const usage = tuple[0] as Call;
|
let usage: Call;
|
||||||
const signature = tuple[1] as string;
|
let packageName: string;
|
||||||
const supported = (tuple[2] as string) === "true";
|
let typeName: string;
|
||||||
let library = tuple[4] as string;
|
let methodName: string;
|
||||||
let libraryVersion: string | undefined = tuple[5] as string;
|
let methodParameters: string;
|
||||||
const type = tuple[6] as ModeledMethodType;
|
let supported: boolean;
|
||||||
const classification = tuple[8] as CallClassification;
|
let library: string;
|
||||||
|
let libraryVersion: string | undefined;
|
||||||
|
let type: ModeledMethodType;
|
||||||
|
let classification: CallClassification;
|
||||||
|
|
||||||
const [packageWithType, methodDeclaration] = signature.split("#");
|
if (mode === Mode.Application) {
|
||||||
|
[
|
||||||
|
usage,
|
||||||
|
packageName,
|
||||||
|
typeName,
|
||||||
|
methodName,
|
||||||
|
methodParameters,
|
||||||
|
supported,
|
||||||
|
library,
|
||||||
|
libraryVersion,
|
||||||
|
type,
|
||||||
|
classification,
|
||||||
|
] = tuple as ApplicationModeTuple;
|
||||||
|
} else {
|
||||||
|
[
|
||||||
|
usage,
|
||||||
|
packageName,
|
||||||
|
typeName,
|
||||||
|
methodName,
|
||||||
|
methodParameters,
|
||||||
|
supported,
|
||||||
|
library,
|
||||||
|
type,
|
||||||
|
] = tuple as FrameworkModeTuple;
|
||||||
|
|
||||||
const packageName = packageWithType.substring(
|
classification = CallClassification.Unknown;
|
||||||
0,
|
}
|
||||||
packageWithType.lastIndexOf("."),
|
|
||||||
);
|
|
||||||
const typeName = packageWithType.substring(
|
|
||||||
packageWithType.lastIndexOf(".") + 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
const methodName = methodDeclaration.substring(
|
if (!methodParameters.startsWith("(")) {
|
||||||
0,
|
// There's a difference in how the Java and C# queries return method parameters. In the C# query, the method
|
||||||
methodDeclaration.indexOf("("),
|
// parameters are returned without parentheses. In the Java query, the method parameters are returned with
|
||||||
);
|
// parentheses. Therefore, we'll just add them if we don't see them.
|
||||||
const methodParameters = methodDeclaration.substring(
|
methodParameters = `(${methodParameters})`;
|
||||||
methodDeclaration.indexOf("("),
|
}
|
||||||
);
|
|
||||||
|
const signature = `${packageName}.${typeName}#${methodName}${methodParameters}`;
|
||||||
|
|
||||||
// For Java, we'll always get back a .jar file, and the library version may be bad because not all library authors
|
// For Java, we'll always get back a .jar file, and the library version may be bad because not all library authors
|
||||||
// properly specify the version. Therefore, we'll always try to parse the name and version from the library filename
|
// properly specify the version. Therefore, we'll always try to parse the name and version from the library filename
|
||||||
// for Java.
|
// for Java.
|
||||||
if (library.endsWith(".jar") || libraryVersion === "") {
|
if (
|
||||||
|
library.endsWith(".jar") ||
|
||||||
|
libraryVersion === "" ||
|
||||||
|
libraryVersion === undefined
|
||||||
|
) {
|
||||||
const { name, version } = parseLibraryFilename(library);
|
const { name, version } = parseLibraryFilename(library);
|
||||||
library = name;
|
library = name;
|
||||||
if (version) {
|
if (version) {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export async function runExternalApiQueries(
|
|||||||
maxStep: externalApiQueriesProgressMaxStep,
|
maxStep: externalApiQueriesProgressMaxStep,
|
||||||
});
|
});
|
||||||
|
|
||||||
return decodeBqrsToMethods(bqrsChunk);
|
return decodeBqrsToMethods(bqrsChunk, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetResultsOptions = {
|
type GetResultsOptions = {
|
||||||
@@ -160,7 +160,5 @@ export async function readQueryResults({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function queryNameFromMode(mode: Mode): string {
|
function queryNameFromMode(mode: Mode): string {
|
||||||
return `FetchExternalApis${
|
return `${mode.charAt(0).toUpperCase() + mode.slice(1)}ModeEndpoints.ql`;
|
||||||
mode.charAt(0).toUpperCase() + mode.slice(1)
|
|
||||||
}Mode.ql`;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,130 +2,152 @@ import { Query } from "./query";
|
|||||||
|
|
||||||
export const fetchExternalApisQuery: Query = {
|
export const fetchExternalApisQuery: Query = {
|
||||||
applicationModeQuery: `/**
|
applicationModeQuery: `/**
|
||||||
* @name Usage of APIs coming from external libraries
|
* @name Fetch endpoints for use in the model editor (application mode)
|
||||||
* @description A list of 3rd party APIs used in the codebase.
|
* @description A list of 3rd party endpoints (methods and attributes) used in the codebase. Excludes test and generated code.
|
||||||
* @tags telemetry
|
* @kind table
|
||||||
* @kind problem
|
* @id csharp/utils/modeleditor/application-mode-endpoints
|
||||||
* @id cs/telemetry/fetch-external-apis
|
* @tags modeleditor endpoints application-mode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import csharp
|
import csharp
|
||||||
private import AutomodelVsCode
|
import ApplicationModeEndpointsQuery
|
||||||
|
import ModelEditor
|
||||||
|
|
||||||
class ExternalApi extends CallableMethod {
|
private Call aUsage(ExternalEndpoint api) { result.getTarget().getUnboundDeclaration() = api }
|
||||||
ExternalApi() {
|
|
||||||
this.isUnboundDeclaration() and
|
|
||||||
this.fromLibrary() and
|
|
||||||
this.(Modifiable).isEffectivelyPublic()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Call aUsage(ExternalApi api) { result.getTarget().getUnboundDeclaration() = api }
|
from ExternalEndpoint endpoint, boolean supported, Call usage, string type, string classification
|
||||||
|
|
||||||
from
|
|
||||||
ExternalApi api, string apiName, boolean supported, Call usage, string type, string classification
|
|
||||||
where
|
where
|
||||||
apiName = api.getApiName() and
|
supported = isSupported(endpoint) and
|
||||||
supported = isSupported(api) and
|
usage = aUsage(endpoint) and
|
||||||
usage = aUsage(api) and
|
type = supportedType(endpoint) and
|
||||||
type = supportedType(api) and
|
|
||||||
classification = methodClassification(usage)
|
classification = methodClassification(usage)
|
||||||
select usage, apiName, supported.toString(), "supported", api.dllName(), api.dllVersion(), type,
|
select usage, endpoint.getNamespace(), endpoint.getTypeName(), endpoint.getName(),
|
||||||
"type", classification, "classification"
|
endpoint.getParameterTypes(), supported, endpoint.dllName(), endpoint.dllVersion(), type,
|
||||||
|
classification
|
||||||
`,
|
`,
|
||||||
frameworkModeQuery: `/**
|
frameworkModeQuery: `/**
|
||||||
* @name Public methods
|
* @name Fetch endpoints for use in the model editor (framework mode)
|
||||||
* @description A list of APIs callable by consumers. Excludes test and generated code.
|
* @description A list of endpoints accessible (methods and attributes) for consumers of the library. Excludes test and generated code.
|
||||||
* @tags telemetry
|
* @kind table
|
||||||
* @kind problem
|
* @id csharp/utils/modeleditor/framework-mode-endpoints
|
||||||
* @id cs/telemetry/fetch-public-methods
|
* @tags modeleditor endpoints framework-mode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private import csharp
|
import csharp
|
||||||
private import dotnet
|
import FrameworkModeEndpointsQuery
|
||||||
private import semmle.code.csharp.frameworks.Test
|
import ModelEditor
|
||||||
private import AutomodelVsCode
|
|
||||||
|
|
||||||
class PublicMethod extends CallableMethod {
|
from PublicEndpointFromSource endpoint, boolean supported, string type
|
||||||
PublicMethod() { this.fromSource() and not this.getFile() instanceof TestFile }
|
|
||||||
}
|
|
||||||
|
|
||||||
from PublicMethod publicMethod, string apiName, boolean supported, string type
|
|
||||||
where
|
where
|
||||||
apiName = publicMethod.getApiName() and
|
supported = isSupported(endpoint) and
|
||||||
supported = isSupported(publicMethod) and
|
type = supportedType(endpoint)
|
||||||
type = supportedType(publicMethod)
|
select endpoint, endpoint.getNamespace(), endpoint.getTypeName(), endpoint.getName(),
|
||||||
select publicMethod, apiName, supported.toString(), "supported",
|
endpoint.getParameterTypes(), supported, endpoint.getFile().getBaseName(), type
|
||||||
publicMethod.getFile().getBaseName(), "library", type, "type", "unknown", "classification"
|
|
||||||
`,
|
`,
|
||||||
dependencies: {
|
dependencies: {
|
||||||
"AutomodelVsCode.qll": `/** Provides classes and predicates related to handling APIs for the VS Code extension. */
|
"ApplicationModeEndpointsQuery.qll": `private import csharp
|
||||||
|
|
||||||
private import csharp
|
|
||||||
private import dotnet
|
|
||||||
private import semmle.code.csharp.dispatch.Dispatch
|
|
||||||
private import semmle.code.csharp.dataflow.ExternalFlow
|
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||||
private import semmle.code.csharp.dataflow.FlowSummary
|
|
||||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
|
|
||||||
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
|
||||||
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
|
||||||
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
private import semmle.code.csharp.dataflow.internal.TaintTrackingPrivate
|
||||||
private import semmle.code.csharp.frameworks.Test
|
|
||||||
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
private import semmle.code.csharp.security.dataflow.flowsources.Remote
|
||||||
|
private import ModelEditor
|
||||||
pragma[nomagic]
|
|
||||||
private predicate isTestNamespace(Namespace ns) {
|
|
||||||
ns.getFullName()
|
|
||||||
.matches([
|
|
||||||
"NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A test library.
|
* A class of effectively public callables in library code.
|
||||||
*/
|
*/
|
||||||
class TestLibrary extends RefType {
|
class ExternalEndpoint extends Endpoint {
|
||||||
TestLibrary() { isTestNamespace(this.getNamespace()) }
|
ExternalEndpoint() { this.fromLibrary() }
|
||||||
|
|
||||||
|
/** Gets a node that is an input to a call to this API. */
|
||||||
|
private ArgumentNode getAnInput() {
|
||||||
|
result
|
||||||
|
.getCall()
|
||||||
|
.(DataFlowDispatch::NonDelegateDataFlowCall)
|
||||||
|
.getATarget(_)
|
||||||
|
.getUnboundDeclaration() = this
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a node that is an output from a call to this API. */
|
||||||
|
private DataFlow::Node getAnOutput() {
|
||||||
|
exists(Call c, DataFlowDispatch::NonDelegateDataFlowCall dc |
|
||||||
|
dc.getDispatchCall().getCall() = c and
|
||||||
|
c.getTarget().getUnboundDeclaration() = this
|
||||||
|
|
|
||||||
|
result = DataFlowDispatch::getAnOutNode(dc, _)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasSummary() {
|
||||||
|
Endpoint.super.hasSummary()
|
||||||
|
or
|
||||||
|
defaultAdditionalTaintStep(this.getAnInput(), _)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSource() {
|
||||||
|
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink() { sinkNode(this.getAnInput(), _) }
|
||||||
}
|
}
|
||||||
|
`,
|
||||||
|
"FrameworkModeEndpointsQuery.qll": `private import csharp
|
||||||
|
private import semmle.code.csharp.dataflow.ExternalFlow
|
||||||
|
private import semmle.code.csharp.frameworks.Test
|
||||||
|
private import ModelEditor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class of effectively public callables from source code.
|
||||||
|
*/
|
||||||
|
class PublicEndpointFromSource extends Endpoint {
|
||||||
|
PublicEndpointFromSource() { this.fromSource() and not this.getFile() instanceof TestFile }
|
||||||
|
|
||||||
|
override predicate isSource() { this instanceof SourceCallable }
|
||||||
|
|
||||||
|
override predicate isSink() { this instanceof SinkCallable }
|
||||||
|
}`,
|
||||||
|
"ModelEditor.qll": `/** Provides classes and predicates related to handling APIs for the VS Code extension. */
|
||||||
|
|
||||||
|
private import csharp
|
||||||
|
private import semmle.code.csharp.dataflow.FlowSummary
|
||||||
|
private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
|
||||||
|
private import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
||||||
|
private import semmle.code.csharp.frameworks.Test
|
||||||
|
|
||||||
/** Holds if the given callable is not worth supporting. */
|
/** Holds if the given callable is not worth supporting. */
|
||||||
private predicate isUninteresting(DotNet::Declaration c) {
|
private predicate isUninteresting(Callable c) {
|
||||||
c.getDeclaringType() instanceof TestLibrary or
|
c.getDeclaringType() instanceof TestLibrary or
|
||||||
c.(Constructor).isParameterless() or
|
c.(Constructor).isParameterless() or
|
||||||
c.getDeclaringType() instanceof AnonymousClass
|
c.getDeclaringType() instanceof AnonymousClass
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An callable method from either the C# Standard Library, a 3rd party library, or from the source.
|
* A callable method or accessor from either the C# Standard Library, a 3rd party library, or from the source.
|
||||||
*/
|
*/
|
||||||
class CallableMethod extends DotNet::Declaration {
|
class Endpoint extends Callable {
|
||||||
CallableMethod() {
|
Endpoint() {
|
||||||
this.(Modifiable).isEffectivelyPublic() and
|
[this.(Modifiable), this.(Accessor).getDeclaration()].isEffectivelyPublic() and
|
||||||
not isUninteresting(this)
|
not isUninteresting(this) and
|
||||||
|
this.isUnboundDeclaration()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the unbound type, name and parameter types of this API.
|
* Gets the namespace of this endpoint.
|
||||||
*/
|
|
||||||
bindingset[this]
|
|
||||||
private string getSignature() {
|
|
||||||
result =
|
|
||||||
nestedName(this.getDeclaringType().getUnboundDeclaration()) + "#" + this.getName() + "(" +
|
|
||||||
parameterQualifiedTypeNamesToString(this) + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the namespace of this API.
|
|
||||||
*/
|
*/
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
string getNamespace() { this.getDeclaringType().hasQualifiedName(result, _) }
|
string getNamespace() { this.getDeclaringType().hasQualifiedName(result, _) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the namespace and signature of this API.
|
* Gets the unbound type name of this endpoint.
|
||||||
*/
|
*/
|
||||||
bindingset[this]
|
bindingset[this]
|
||||||
string getApiName() { result = this.getNamespace() + "." + this.getSignature() }
|
string getTypeName() { result = nestedName(this.getDeclaringType().getUnboundDeclaration()) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parameter types of this endpoint.
|
||||||
|
*/
|
||||||
|
bindingset[this]
|
||||||
|
string getParameterTypes() { result = parameterQualifiedTypeNamesToString(this) }
|
||||||
|
|
||||||
private string getDllName() { result = this.getLocation().(Assembly).getName() }
|
private string getDllName() { result = this.getLocation().(Assembly).getName() }
|
||||||
|
|
||||||
@@ -143,44 +165,17 @@ class CallableMethod extends DotNet::Declaration {
|
|||||||
not exists(this.getDllVersion()) and result = ""
|
not exists(this.getDllVersion()) and result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a node that is an input to a call to this API. */
|
|
||||||
private ArgumentNode getAnInput() {
|
|
||||||
result
|
|
||||||
.getCall()
|
|
||||||
.(DataFlowDispatch::NonDelegateDataFlowCall)
|
|
||||||
.getATarget(_)
|
|
||||||
.getUnboundDeclaration() = this
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a node that is an output from a call to this API. */
|
|
||||||
private DataFlow::Node getAnOutput() {
|
|
||||||
exists(
|
|
||||||
Call c, DataFlowDispatch::NonDelegateDataFlowCall dc, DataFlowImplCommon::ReturnKindExt ret
|
|
||||||
|
|
|
||||||
dc.getDispatchCall().getCall() = c and
|
|
||||||
c.getTarget().getUnboundDeclaration() = this
|
|
||||||
|
|
|
||||||
result = ret.getAnOutNode(dc)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this API has a supported summary. */
|
/** Holds if this API has a supported summary. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate hasSummary() {
|
predicate hasSummary() { this instanceof SummarizedCallable }
|
||||||
this instanceof SummarizedCallable
|
|
||||||
or
|
|
||||||
defaultAdditionalTaintStep(this.getAnInput(), _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this API is a known source. */
|
/** Holds if this API is a known source. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate isSource() {
|
abstract predicate isSource();
|
||||||
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this API is a known sink. */
|
/** Holds if this API is a known sink. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate isSink() { sinkNode(this.getAnInput(), _) }
|
abstract predicate isSink();
|
||||||
|
|
||||||
/** Holds if this API is a known neutral. */
|
/** Holds if this API is a known neutral. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
@@ -195,23 +190,20 @@ class CallableMethod extends DotNet::Declaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSupported(CallableMethod callableMethod) {
|
boolean isSupported(Endpoint endpoint) {
|
||||||
callableMethod.isSupported() and result = true
|
if endpoint.isSupported() then result = true else result = false
|
||||||
or
|
|
||||||
not callableMethod.isSupported() and
|
|
||||||
result = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
string supportedType(CallableMethod method) {
|
string supportedType(Endpoint endpoint) {
|
||||||
method.isSink() and result = "sink"
|
endpoint.isSink() and result = "sink"
|
||||||
or
|
or
|
||||||
method.isSource() and result = "source"
|
endpoint.isSource() and result = "source"
|
||||||
or
|
or
|
||||||
method.hasSummary() and result = "summary"
|
endpoint.hasSummary() and result = "summary"
|
||||||
or
|
or
|
||||||
method.isNeutral() and result = "neutral"
|
endpoint.isNeutral() and result = "neutral"
|
||||||
or
|
or
|
||||||
not method.isSupported() and result = ""
|
not endpoint.isSupported() and result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
string methodClassification(Call method) {
|
string methodClassification(Call method) {
|
||||||
@@ -222,18 +214,51 @@ string methodClassification(Call method) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the nested name of the declaration.
|
* Gets the nested name of the type \`t\`.
|
||||||
*
|
*
|
||||||
* If the declaration is not a nested type, the result is the same as \`getName()\`.
|
* If the type is not a nested type, the result is the same as \`getName()\`.
|
||||||
* Otherwise the name of the nested type is prefixed with a \`+\` and appended to
|
* Otherwise the name of the nested type is prefixed with a \`+\` and appended to
|
||||||
* the name of the enclosing type, which might be a nested type as well.
|
* the name of the enclosing type, which might be a nested type as well.
|
||||||
*/
|
*/
|
||||||
private string nestedName(Declaration declaration) {
|
private string nestedName(Type t) {
|
||||||
not exists(declaration.getDeclaringType().getUnboundDeclaration()) and
|
not exists(t.getDeclaringType().getUnboundDeclaration()) and
|
||||||
result = declaration.getName()
|
result = t.getName()
|
||||||
or
|
or
|
||||||
nestedName(declaration.getDeclaringType().getUnboundDeclaration()) + "+" + declaration.getName() =
|
nestedName(t.getDeclaringType().getUnboundDeclaration()) + "+" + t.getName() = result
|
||||||
result
|
}
|
||||||
|
|
||||||
|
// Temporary copy of csharp/ql/src/Telemetry/TestLibrary.qll
|
||||||
|
|
||||||
|
pragma[nomagic]
|
||||||
|
private predicate isTestNamespace(Namespace ns) {
|
||||||
|
ns.getFullName()
|
||||||
|
.matches([
|
||||||
|
"NUnit.Framework%", "Xunit%", "Microsoft.VisualStudio.TestTools.UnitTesting%", "Moq%"
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test library.
|
||||||
|
*/
|
||||||
|
class TestLibrary extends RefType {
|
||||||
|
TestLibrary() { isTestNamespace(this.getNamespace()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Temporary copy of csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll
|
||||||
|
private import semmle.code.csharp.dataflow.internal.FlowSummaryImplSpecific
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callable where there exists a MaD sink model that applies to it.
|
||||||
|
*/
|
||||||
|
class SinkCallable extends Callable {
|
||||||
|
SinkCallable() { sinkElement(this, _, _, _) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A callable where there exists a MaD source model that applies to it.
|
||||||
|
*/
|
||||||
|
class SourceCallable extends Callable {
|
||||||
|
SourceCallable() { sourceElement(this, _, _, _) }
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,66 +2,113 @@ import { Query } from "./query";
|
|||||||
|
|
||||||
export const fetchExternalApisQuery: Query = {
|
export const fetchExternalApisQuery: Query = {
|
||||||
applicationModeQuery: `/**
|
applicationModeQuery: `/**
|
||||||
* @name Usage of APIs coming from external libraries
|
* @name Fetch endpoints for use in the model editor (application mode)
|
||||||
* @description A list of 3rd party APIs used in the codebase. Excludes test and generated code.
|
* @description A list of 3rd party endpoints (methods) used in the codebase. Excludes test and generated code.
|
||||||
* @tags telemetry
|
* @kind table
|
||||||
* @kind problem
|
* @id java/utils/modeleditor/application-mode-endpoints
|
||||||
* @id java/telemetry/fetch-external-apis
|
* @tags modeleditor endpoints application-mode
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java
|
|
||||||
import AutomodelVsCode
|
|
||||||
|
|
||||||
class ExternalApi extends CallableMethod {
|
|
||||||
ExternalApi() { not this.fromSource() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private Call aUsage(ExternalApi api) { result.getCallee().getSourceDeclaration() = api }
|
|
||||||
|
|
||||||
from
|
|
||||||
ExternalApi externalApi, string apiName, boolean supported, Call usage, string type,
|
|
||||||
string classification
|
|
||||||
where
|
|
||||||
apiName = externalApi.getApiName() and
|
|
||||||
supported = isSupported(externalApi) and
|
|
||||||
usage = aUsage(externalApi) and
|
|
||||||
type = supportedType(externalApi) and
|
|
||||||
classification = methodClassification(usage)
|
|
||||||
select usage, apiName, supported.toString(), "supported", externalApi.jarContainer(),
|
|
||||||
externalApi.jarVersion(), type, "type", classification, "classification"
|
|
||||||
`,
|
|
||||||
frameworkModeQuery: `/**
|
|
||||||
* @name Public methods
|
|
||||||
* @description A list of APIs callable by consumers. Excludes test and generated code.
|
|
||||||
* @tags telemetry
|
|
||||||
* @kind problem
|
|
||||||
* @id java/telemetry/fetch-public-methods
|
|
||||||
*/
|
|
||||||
|
|
||||||
import java
|
|
||||||
import AutomodelVsCode
|
|
||||||
|
|
||||||
class PublicMethodFromSource extends CallableMethod, ModelApi { }
|
|
||||||
|
|
||||||
from PublicMethodFromSource publicMethod, string apiName, boolean supported, string type
|
|
||||||
where
|
|
||||||
apiName = publicMethod.getApiName() and
|
|
||||||
supported = isSupported(publicMethod) and
|
|
||||||
type = supportedType(publicMethod)
|
|
||||||
select publicMethod, apiName, supported.toString(), "supported",
|
|
||||||
publicMethod.getCompilationUnit().getParentContainer().getBaseName(), "library", type, "type",
|
|
||||||
"unknown", "classification"
|
|
||||||
`,
|
|
||||||
dependencies: {
|
|
||||||
"AutomodelVsCode.qll": `/** Provides classes and predicates related to handling APIs for the VS Code extension. */
|
|
||||||
|
|
||||||
private import java
|
private import java
|
||||||
private import semmle.code.java.dataflow.DataFlow
|
private import ApplicationModeEndpointsQuery
|
||||||
|
private import ModelEditor
|
||||||
|
|
||||||
|
private Call aUsage(ExternalEndpoint endpoint) {
|
||||||
|
result.getCallee().getSourceDeclaration() = endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
from ExternalEndpoint endpoint, boolean supported, Call usage, string type, string classification
|
||||||
|
where
|
||||||
|
supported = isSupported(endpoint) and
|
||||||
|
usage = aUsage(endpoint) and
|
||||||
|
type = supportedType(endpoint) and
|
||||||
|
classification = usageClassification(usage)
|
||||||
|
select usage, endpoint.getPackageName(), endpoint.getTypeName(), endpoint.getName(),
|
||||||
|
endpoint.getParameterTypes(), supported, endpoint.jarContainer(), endpoint.jarVersion(), type,
|
||||||
|
classification
|
||||||
|
`,
|
||||||
|
frameworkModeQuery: `/**
|
||||||
|
* @name Fetch endpoints for use in the model editor (framework mode)
|
||||||
|
* @description A list of endpoints accessible (methods) for consumers of the library. Excludes test and generated code.
|
||||||
|
* @kind table
|
||||||
|
* @id java/utils/modeleditor/framework-mode-endpoints
|
||||||
|
* @tags modeleditor endpoints framework-mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import java
|
||||||
|
private import FrameworkModeEndpointsQuery
|
||||||
|
private import ModelEditor
|
||||||
|
|
||||||
|
from PublicEndpointFromSource endpoint, boolean supported, string type
|
||||||
|
where
|
||||||
|
supported = isSupported(endpoint) and
|
||||||
|
type = supportedType(endpoint)
|
||||||
|
select endpoint, endpoint.getPackageName(), endpoint.getTypeName(), endpoint.getName(),
|
||||||
|
endpoint.getParameterTypes(), supported,
|
||||||
|
endpoint.getCompilationUnit().getParentContainer().getBaseName(), type
|
||||||
|
`,
|
||||||
|
dependencies: {
|
||||||
|
"ApplicationModeEndpointsQuery.qll": `private import java
|
||||||
private import semmle.code.java.dataflow.ExternalFlow
|
private import semmle.code.java.dataflow.ExternalFlow
|
||||||
private import semmle.code.java.dataflow.FlowSources
|
private import semmle.code.java.dataflow.FlowSources
|
||||||
private import semmle.code.java.dataflow.FlowSummary
|
|
||||||
private import semmle.code.java.dataflow.internal.DataFlowPrivate
|
private import semmle.code.java.dataflow.internal.DataFlowPrivate
|
||||||
private import semmle.code.java.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
|
private import ModelEditor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class of effectively public callables in library code.
|
||||||
|
*/
|
||||||
|
class ExternalEndpoint extends Endpoint {
|
||||||
|
ExternalEndpoint() { not this.fromSource() }
|
||||||
|
|
||||||
|
/** Gets a node that is an input to a call to this API. */
|
||||||
|
private DataFlow::Node getAnInput() {
|
||||||
|
exists(Call call | call.getCallee().getSourceDeclaration() = this |
|
||||||
|
result.asExpr().(Argument).getCall() = call or
|
||||||
|
result.(ArgumentNode).getCall().asCall() = call
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a node that is an output from a call to this API. */
|
||||||
|
private DataFlow::Node getAnOutput() {
|
||||||
|
exists(Call call | call.getCallee().getSourceDeclaration() = this |
|
||||||
|
result.asExpr() = call or
|
||||||
|
result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate hasSummary() {
|
||||||
|
Endpoint.super.hasSummary()
|
||||||
|
or
|
||||||
|
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSource() {
|
||||||
|
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
||||||
|
}
|
||||||
|
|
||||||
|
override predicate isSink() { sinkNode(this.getAnInput(), _) }
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"FrameworkModeEndpointsQuery.qll": `private import java
|
||||||
|
private import semmle.code.java.dataflow.internal.DataFlowPrivate
|
||||||
|
private import semmle.code.java.dataflow.internal.FlowSummaryImplSpecific
|
||||||
|
private import semmle.code.java.dataflow.internal.ModelExclusions
|
||||||
|
private import ModelEditor
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class of effectively public callables from source code.
|
||||||
|
*/
|
||||||
|
class PublicEndpointFromSource extends Endpoint, ModelApi {
|
||||||
|
override predicate isSource() { sourceElement(this, _, _, _) }
|
||||||
|
|
||||||
|
override predicate isSink() { sinkElement(this, _, _, _) }
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"ModelEditor.qll": `/** Provides classes and predicates related to handling APIs for the VS Code extension. */
|
||||||
|
|
||||||
|
private import java
|
||||||
|
private import semmle.code.java.dataflow.ExternalFlow
|
||||||
|
private import semmle.code.java.dataflow.FlowSummary
|
||||||
private import semmle.code.java.dataflow.TaintTracking
|
private import semmle.code.java.dataflow.TaintTracking
|
||||||
private import semmle.code.java.dataflow.internal.ModelExclusions
|
private import semmle.code.java.dataflow.internal.ModelExclusions
|
||||||
|
|
||||||
@@ -75,17 +122,23 @@ private predicate isUninteresting(Callable c) {
|
|||||||
/**
|
/**
|
||||||
* A callable method from either the Standard Library, a 3rd party library or from the source.
|
* A callable method from either the Standard Library, a 3rd party library or from the source.
|
||||||
*/
|
*/
|
||||||
class CallableMethod extends Callable {
|
class Endpoint extends Callable {
|
||||||
CallableMethod() { not isUninteresting(this) }
|
Endpoint() { not isUninteresting(this) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets information about the external API in the form expected by the MaD modeling framework.
|
* Gets the package name of this endpoint.
|
||||||
*/
|
*/
|
||||||
string getApiName() {
|
string getPackageName() { result = this.getDeclaringType().getPackage().getName() }
|
||||||
result =
|
|
||||||
this.getDeclaringType().getPackage() + "." + this.getDeclaringType().nestedName() + "#" +
|
/**
|
||||||
this.getName() + paramsString(this)
|
* Gets the type name of this endpoint.
|
||||||
}
|
*/
|
||||||
|
string getTypeName() { result = this.getDeclaringType().nestedName() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parameter types of this endpoint.
|
||||||
|
*/
|
||||||
|
string getParameterTypes() { result = paramsString(this) }
|
||||||
|
|
||||||
private string getJarName() {
|
private string getJarName() {
|
||||||
result = this.getCompilationUnit().getParentContainer*().(JarFile).getBaseName()
|
result = this.getCompilationUnit().getParentContainer*().(JarFile).getBaseName()
|
||||||
@@ -113,43 +166,23 @@ class CallableMethod extends Callable {
|
|||||||
not exists(this.getJarVersion()) and result = ""
|
not exists(this.getJarVersion()) and result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets a node that is an input to a call to this API. */
|
|
||||||
private DataFlow::Node getAnInput() {
|
|
||||||
exists(Call call | call.getCallee().getSourceDeclaration() = this |
|
|
||||||
result.asExpr().(Argument).getCall() = call or
|
|
||||||
result.(ArgumentNode).getCall().asCall() = call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Gets a node that is an output from a call to this API. */
|
|
||||||
private DataFlow::Node getAnOutput() {
|
|
||||||
exists(Call call | call.getCallee().getSourceDeclaration() = this |
|
|
||||||
result.asExpr() = call or
|
|
||||||
result.(DataFlow::PostUpdateNode).getPreUpdateNode().(ArgumentNode).getCall().asCall() = call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this API has a supported summary. */
|
/** Holds if this API has a supported summary. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate hasSummary() {
|
predicate hasSummary() { this = any(SummarizedCallable sc).asCallable() }
|
||||||
this = any(SummarizedCallable sc).asCallable() or
|
|
||||||
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/** Holds if this API is a known source. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate isSource() {
|
abstract predicate isSource();
|
||||||
this.getAnOutput() instanceof RemoteFlowSource or sourceNode(this.getAnOutput(), _)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if this API is a known sink. */
|
/** Holds if this API is a known sink. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate isSink() { sinkNode(this.getAnInput(), _) }
|
abstract predicate isSink();
|
||||||
|
|
||||||
/** Holds if this API is a known neutral. */
|
/** Holds if this API is a known neutral. */
|
||||||
pragma[nomagic]
|
pragma[nomagic]
|
||||||
predicate isNeutral() {
|
predicate isNeutral() {
|
||||||
exists(string namespace, string type, string name, string signature, string kind, string provenance |
|
exists(string namespace, string type, string name, string signature |
|
||||||
neutralModel(namespace, type, name, signature, kind, provenance) and
|
neutralModel(namespace, type, name, signature, _, _) and
|
||||||
this = interpretElement(namespace, type, false, name, signature, "")
|
this = interpretElement(namespace, type, false, name, signature, "")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -163,108 +196,38 @@ class CallableMethod extends Callable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSupported(CallableMethod method) {
|
boolean isSupported(Endpoint endpoint) {
|
||||||
method.isSupported() and result = true
|
endpoint.isSupported() and result = true
|
||||||
or
|
or
|
||||||
not method.isSupported() and result = false
|
not endpoint.isSupported() and result = false
|
||||||
}
|
}
|
||||||
|
|
||||||
string supportedType(CallableMethod method) {
|
string supportedType(Endpoint endpoint) {
|
||||||
method.isSink() and result = "sink"
|
endpoint.isSink() and result = "sink"
|
||||||
or
|
or
|
||||||
method.isSource() and result = "source"
|
endpoint.isSource() and result = "source"
|
||||||
or
|
or
|
||||||
method.hasSummary() and result = "summary"
|
endpoint.hasSummary() and result = "summary"
|
||||||
or
|
or
|
||||||
method.isNeutral() and result = "neutral"
|
endpoint.isNeutral() and result = "neutral"
|
||||||
or
|
or
|
||||||
not method.isSupported() and result = ""
|
not endpoint.isSupported() and result = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
string methodClassification(Call method) {
|
string usageClassification(Call usage) {
|
||||||
isInTestFile(method.getLocation().getFile()) and result = "test"
|
isInTestFile(usage.getLocation().getFile()) and result = "test"
|
||||||
or
|
or
|
||||||
method.getFile() instanceof GeneratedFile and result = "generated"
|
usage.getFile() instanceof GeneratedFile and result = "generated"
|
||||||
or
|
or
|
||||||
not isInTestFile(method.getLocation().getFile()) and
|
not isInTestFile(usage.getLocation().getFile()) and
|
||||||
not method.getFile() instanceof GeneratedFile and
|
not usage.getFile() instanceof GeneratedFile and
|
||||||
result = "source"
|
result = "source"
|
||||||
}
|
}
|
||||||
|
|
||||||
// The below is a copy of https://github.com/github/codeql/blob/249f9f863db1e94e3c46ca85b49fb0ec32f8ca92/java/ql/lib/semmle/code/java/dataflow/internal/ModelExclusions.qll
|
// Temporarily copied from java/ql/lib/semmle/code/java/dataflow/internal/ModelExclusions.qll
|
||||||
// to avoid the use of internal modules.
|
predicate isInTestFile(File file) {
|
||||||
/** Holds if the given package \`p\` is a test package. */
|
|
||||||
pragma[nomagic]
|
|
||||||
private predicate isTestPackage(Package p) {
|
|
||||||
p.getName()
|
|
||||||
.matches([
|
|
||||||
"org.junit%", "junit.%", "org.mockito%", "org.assertj%",
|
|
||||||
"com.github.tomakehurst.wiremock%", "org.hamcrest%", "org.springframework.test.%",
|
|
||||||
"org.springframework.mock.%", "org.springframework.boot.test.%", "reactor.test%",
|
|
||||||
"org.xmlunit%", "org.testcontainers.%", "org.opentest4j%", "org.mockserver%",
|
|
||||||
"org.powermock%", "org.skyscreamer.jsonassert%", "org.rnorth.visibleassertions",
|
|
||||||
"org.openqa.selenium%", "com.gargoylesoftware.htmlunit%", "org.jboss.arquillian.testng%",
|
|
||||||
"org.testng%"
|
|
||||||
])
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A test library.
|
|
||||||
*/
|
|
||||||
class TestLibrary extends RefType {
|
|
||||||
TestLibrary() { isTestPackage(this.getPackage()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if the given file is a test file. */
|
|
||||||
private predicate isInTestFile(File file) {
|
|
||||||
file.getAbsolutePath().matches(["%/test/%", "%/guava-tests/%", "%/guava-testlib/%"]) and
|
file.getAbsolutePath().matches(["%/test/%", "%/guava-tests/%", "%/guava-testlib/%"]) and
|
||||||
not file.getAbsolutePath().matches("%/ql/test/%") // allows our test cases to work
|
not file.getAbsolutePath().matches(["%/ql/test/%", "%/ql/automodel/test/%"]) // allows our test cases to work
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if the given compilation unit's package is a JDK internal. */
|
|
||||||
private predicate isJdkInternal(CompilationUnit cu) {
|
|
||||||
cu.getPackage().getName().matches("org.graalvm%") or
|
|
||||||
cu.getPackage().getName().matches("com.sun%") or
|
|
||||||
cu.getPackage().getName().matches("sun%") or
|
|
||||||
cu.getPackage().getName().matches("jdk%") or
|
|
||||||
cu.getPackage().getName().matches("java2d%") or
|
|
||||||
cu.getPackage().getName().matches("build.tools%") or
|
|
||||||
cu.getPackage().getName().matches("propertiesparser%") or
|
|
||||||
cu.getPackage().getName().matches("org.jcp%") or
|
|
||||||
cu.getPackage().getName().matches("org.w3c%") or
|
|
||||||
cu.getPackage().getName().matches("org.ietf.jgss%") or
|
|
||||||
cu.getPackage().getName().matches("org.xml.sax%") or
|
|
||||||
cu.getPackage().getName().matches("com.oracle%") or
|
|
||||||
cu.getPackage().getName().matches("org.omg%") or
|
|
||||||
cu.getPackage().getName().matches("org.relaxng%") or
|
|
||||||
cu.getPackage().getName() = "compileproperties" or
|
|
||||||
cu.getPackage().getName() = "transparentruler" or
|
|
||||||
cu.getPackage().getName() = "genstubs" or
|
|
||||||
cu.getPackage().getName() = "netscape.javascript" or
|
|
||||||
cu.getPackage().getName() = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds if the given callable is not worth modeling. */
|
|
||||||
predicate isUninterestingForModels(Callable c) {
|
|
||||||
isInTestFile(c.getCompilationUnit().getFile()) or
|
|
||||||
isJdkInternal(c.getCompilationUnit()) or
|
|
||||||
c instanceof MainMethod or
|
|
||||||
c instanceof StaticInitializer or
|
|
||||||
exists(FunctionalExpr funcExpr | c = funcExpr.asMethod()) or
|
|
||||||
c.getDeclaringType() instanceof TestLibrary or
|
|
||||||
c.(Constructor).isParameterless()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class that represents all callables for which we might be
|
|
||||||
* interested in having a MaD model.
|
|
||||||
*/
|
|
||||||
class ModelApi extends SrcCallable {
|
|
||||||
ModelApi() {
|
|
||||||
this.fromSource() and
|
|
||||||
this.isEffectivelyPublic() and
|
|
||||||
not isUninterestingForModels(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
|
import { Call, CallClassification } from "../method";
|
||||||
|
import { ModeledMethodType } from "../modeled-method";
|
||||||
|
|
||||||
export type Query = {
|
export type Query = {
|
||||||
/**
|
/**
|
||||||
* The application query.
|
* The application query.
|
||||||
*
|
*
|
||||||
* It should select all usages of external APIs, and return the following result pattern:
|
* It should select all usages of external APIs, and return the following result pattern:
|
||||||
* - usage: the usage of the external API. This is an entity.
|
* - usage: the usage of the external API. This is an entity.
|
||||||
* - apiName: the name of the external API. This is a string.
|
* - packageName: the package name of the external API. This is a string.
|
||||||
* - supported: whether the external API is modeled. This should be a string representation of a boolean to satify the result pattern for a problem query.
|
* - typeName: the type name of the external API. This is a string.
|
||||||
* - "supported": a string literal. This is required to make the query a valid problem query.
|
* - methodName: the method name of the external API. This is a string.
|
||||||
|
* - methodParameters: the parameters of the external API. This is a string.
|
||||||
|
* - supported: whether the external API is modeled. This is a boolean.
|
||||||
* - libraryName: the name of the library that contains the external API. This is a string and usually the basename of a file.
|
* - libraryName: the name of the library that contains the external API. This is a string and usually the basename of a file.
|
||||||
* - libraryVersion: the version of the library that contains the external API. This is a string and can be empty if the version cannot be determined.
|
* - libraryVersion: the version of the library that contains the external API. This is a string and can be empty if the version cannot be determined.
|
||||||
* - type: the modeled kind of the method, either "sink", "source", "summary", or "neutral"
|
* - type: the modeled kind of the method, either "sink", "source", "summary", or "neutral"
|
||||||
* - "type": a string literal. This is required to make the query a valid problem query.
|
|
||||||
* - classification: the classification of the use of the method, either "source", "test", "generated", or "unknown"
|
* - classification: the classification of the use of the method, either "source", "test", "generated", or "unknown"
|
||||||
* - "classification: a string literal. This is required to make the query a valid problem query.
|
|
||||||
*/
|
*/
|
||||||
applicationModeQuery: string;
|
applicationModeQuery: string;
|
||||||
/**
|
/**
|
||||||
@@ -21,18 +24,40 @@ export type Query = {
|
|||||||
* It should select all methods that are callable by applications, which is usually all public methods (and constructors).
|
* It should select all methods that are callable by applications, which is usually all public methods (and constructors).
|
||||||
* The result pattern should be as follows:
|
* The result pattern should be as follows:
|
||||||
* - method: the method that is callable by applications. This is an entity.
|
* - method: the method that is callable by applications. This is an entity.
|
||||||
* - apiName: the name of the external API. This is a string.
|
* - packageName: the package name of the method. This is a string.
|
||||||
|
* - typeName: the type name of the method. This is a string.
|
||||||
|
* - methodName: the method name of the method. This is a string.
|
||||||
|
* - methodParameters: the parameters of the method. This is a string.
|
||||||
* - supported: whether this method is modeled. This should be a string representation of a boolean to satify the result pattern for a problem query.
|
* - supported: whether this method is modeled. This should be a string representation of a boolean to satify the result pattern for a problem query.
|
||||||
* - "supported": a string literal. This is required to make the query a valid problem query.
|
* - libraryName: the name of the file or library that contains the method. This is a string and usually the basename of a file.
|
||||||
* - libraryName: an arbitrary string. This is required to make it match the structure of the application query.
|
|
||||||
* - libraryVersion: an arbitrary string. This is required to make it match the structure of the application query.
|
|
||||||
* - type: the modeled kind of the method, either "sink", "source", "summary", or "neutral"
|
* - type: the modeled kind of the method, either "sink", "source", "summary", or "neutral"
|
||||||
* - "type": a string literal. This is required to make the query a valid problem query.
|
|
||||||
* - "unknown": a string literal. This is required to make it match the structure of the application query.
|
|
||||||
* - "classification: a string literal. This is required to make the query a valid problem query.
|
|
||||||
*/
|
*/
|
||||||
frameworkModeQuery: string;
|
frameworkModeQuery: string;
|
||||||
dependencies?: {
|
dependencies?: {
|
||||||
[filename: string]: string;
|
[filename: string]: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApplicationModeTuple = [
|
||||||
|
Call,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
boolean,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
ModeledMethodType,
|
||||||
|
CallClassification,
|
||||||
|
];
|
||||||
|
|
||||||
|
export type FrameworkModeTuple = [
|
||||||
|
Call,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
string,
|
||||||
|
boolean,
|
||||||
|
string,
|
||||||
|
ModeledMethodType,
|
||||||
|
];
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -152,7 +152,7 @@ describe("external api usage query", () => {
|
|||||||
expect(options.queryRunner.createQueryRun).toHaveBeenCalledWith(
|
expect(options.queryRunner.createQueryRun).toHaveBeenCalledWith(
|
||||||
"/a/b/c/src.zip",
|
"/a/b/c/src.zip",
|
||||||
{
|
{
|
||||||
queryPath: expect.stringMatching(/FetchExternalApis\S*\.ql/),
|
queryPath: expect.stringMatching(/\S*ModeEndpoints\.ql/),
|
||||||
quickEvalPosition: undefined,
|
quickEvalPosition: undefined,
|
||||||
quickEvalCountOnly: false,
|
quickEvalCountOnly: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ describe("setUpPack", () => {
|
|||||||
expect(queryFiles.sort()).toEqual(
|
expect(queryFiles.sort()).toEqual(
|
||||||
[
|
[
|
||||||
"codeql-pack.yml",
|
"codeql-pack.yml",
|
||||||
"FetchExternalApisApplicationMode.ql",
|
"ApplicationModeEndpoints.ql",
|
||||||
"FetchExternalApisFrameworkMode.ql",
|
"ApplicationModeEndpointsQuery.qll",
|
||||||
"AutomodelVsCode.qll",
|
"FrameworkModeEndpoints.ql",
|
||||||
|
"FrameworkModeEndpointsQuery.qll",
|
||||||
|
"ModelEditor.qll",
|
||||||
].sort(),
|
].sort(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -58,9 +60,7 @@ describe("setUpPack", () => {
|
|||||||
readFileSync(
|
readFileSync(
|
||||||
join(
|
join(
|
||||||
queryDir,
|
queryDir,
|
||||||
`FetchExternalApis${
|
`${mode.charAt(0).toUpperCase() + mode.slice(1)}ModeEndpoints.ql`,
|
||||||
mode.charAt(0).toUpperCase() + mode.slice(1)
|
|
||||||
}Mode.ql`,
|
|
||||||
),
|
),
|
||||||
"utf8",
|
"utf8",
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user