diff --git a/ql/lib/codeql-pack.lock.yml b/ql/lib/codeql-pack.lock.yml index bbefa58..ace9219 100644 --- a/ql/lib/codeql-pack.lock.yml +++ b/ql/lib/codeql-pack.lock.yml @@ -9,10 +9,12 @@ dependencies: version: 1.0.12 codeql/ssa: version: 1.0.12 + codeql/threat-models: + version: 1.0.25 codeql/typetracking: version: 1.0.12 codeql/util: version: 1.0.12 codeql/yaml: - version: 1.0.23 + version: 1.0.25 compiled: false diff --git a/ql/lib/codeql/bicep/DataFlow.qll b/ql/lib/codeql/bicep/DataFlow.qll new file mode 100644 index 0000000..be422d1 --- /dev/null +++ b/ql/lib/codeql/bicep/DataFlow.qll @@ -0,0 +1,16 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) data flow analyses. + */ + + import codeql.Locations + + /** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) data flow analyses. + */ + module DataFlow { + private import codeql.dataflow.DataFlow + import DataFlowMake + import Public + } \ No newline at end of file diff --git a/ql/lib/codeql/bicep/ast/Resources.qll b/ql/lib/codeql/bicep/ast/Resources.qll index f3cc72a..a50a928 100644 --- a/ql/lib/codeql/bicep/ast/Resources.qll +++ b/ql/lib/codeql/bicep/ast/Resources.qll @@ -96,6 +96,8 @@ class Resource extends TResource { Identifier getIdentifier() { result = resource.getIdentifier() } + ResourceDeclaration getResourceDeclaration() { result = resource } + string getName() { exists(StringLiteral name | name = resource.getProperty("name") and diff --git a/ql/lib/codeql/bicep/ast/Stmts.qll b/ql/lib/codeql/bicep/ast/Stmts.qll index 482c258..07e5b99 100644 --- a/ql/lib/codeql/bicep/ast/Stmts.qll +++ b/ql/lib/codeql/bicep/ast/Stmts.qll @@ -141,7 +141,9 @@ class UserDefinedFunction extends AstNode instanceof UserDefinedFunctionImpl { */ class Parameter extends AstNode instanceof ParameterImpl { /** Gets the name of the parameter. */ - Idents getName() { result = ParameterImpl.super.getName() } + Idents getIdentifier() { result = ParameterImpl.super.getName() } + + string getName() { result = this.getIdentifier().getName() } /** Gets the type of the parameter. */ Type getType() { result = ParameterImpl.super.getType() } diff --git a/ql/lib/codeql/bicep/ast/Variables.qll b/ql/lib/codeql/bicep/ast/Variables.qll index 10cc798..40eb306 100644 --- a/ql/lib/codeql/bicep/ast/Variables.qll +++ b/ql/lib/codeql/bicep/ast/Variables.qll @@ -1,8 +1,10 @@ /** * Bicep variable declarations. */ + private import bicep private import AstNodes +private import Calls private import Idents private import Stmts private import codeql.bicep.controlflow.BasicBlocks as BasicBlocks @@ -14,13 +16,205 @@ private import internal.VariableDeclaration * A VariableDeclaration unknown AST node. */ class VariableDeclaration extends AstNode instanceof VariableDeclarationImpl { - /** - * Gets the identifier of the variable declaration. - */ - Idents getIdentifier() { result = VariableDeclarationImpl.super.getIdentifier() } - - /** - * Gets the initializer expression of the variable declaration. - */ - Expr getInitializer() { result = VariableDeclarationImpl.super.getInitializer() } + /** + * Gets the identifier of the variable declaration. + */ + Idents getIdentifier() { result = VariableDeclarationImpl.super.getIdentifier() } + + /** + * Gets the initializer expression of the variable declaration. + */ + Expr getInitializer() { result = VariableDeclarationImpl.super.getInitializer() } +} + +private predicate variableDecl(AstNode node, string name) { + exists(ParameterDeclaration param | + param.getName() = name and + node = param + ) + or + exists(VariableDeclaration vardelc | + vardelc.getIdentifier().getName() = name and + node = vardelc + ) + or + exists(Resource resource | + resource.getIdentifier().getName() = name and + node = resource.getResourceDeclaration() + ) + or + exists(OutputDeclaration output | + output.getIdentifier().getName() = name and + node = output + ) +} + +/** + * Variable represents a variable defination. + */ +class Variable extends MkVariable { + private AstNode node; + private string name; + + Variable() { this = MkVariable(node, name) } + + string getName() { result = name } + + string toString() { result = "Variable[" + name + "]" } + + AstNode getAstNode() { result = node } + + /** + * Get the location of this variable. + */ + Location getLocation() { result = node.getLocation() } + + /** + * Geta the inner variable of this variable. + */ + VariableAccess getAnAccess() { result.getVariable() = this } + + /** + * Gets the type of this variable, if any. + */ + Type getType() { + result = this.getParameter().getType() + or + result = this.getOutput().getType() + } + + /** + * Gets the parameter of this variable, if any. + */ + ParameterDeclaration getParameter() { + exists(ParameterDeclaration param | + param.getName() = this.getName() and + param.getEnclosingCfgScope() = this.getEnclosingCfgScope() and + result = param + ) + } + + /** + * Gets the variable declaration of this variable, if any. + */ + OutputDeclaration getOutput() { + exists(OutputDeclaration output | + output.getIdentifier().getName() = this.getName() and + output.getEnclosingCfgScope() = this.getEnclosingCfgScope() and + result = output + ) + } + + /** + * Gets the enclosing scope of this variable, if any. + */ + CfgScope getEnclosingCfgScope() { result = node.getEnclosingCfgScope() } + + // Expr getInitializer() { } + string getAPrimaryQlClass() { result = "Variable" } +} + +private predicate access(AstNode node, Variable v, string name) { + exists(Identifier ident | + ident.getName() = name and + // Make sure they are not in a declare statement + not ident.getParent() instanceof VariableDeclaration and + // not ident.getParent() instanceof ParameterDeclaration and + // not ident.getParent() instanceof OutputDeclaration and + // Make sure they are in the same scope + ident.getName() = v.getName() and + ident.getEnclosingCfgScope() = v.getEnclosingCfgScope() and + ident = node + ) } + +/** + * VariableAccess is a class that represents the access to a variable. + */ +class VariableAccess extends MkVariableAccess, TVariableAccess { + private string name; + private AstNode node; + private Variable v; + + VariableAccess() { this = MkVariableAccess(node, v, name) } + + string getName() { result = name } + + AstNode getAstNode() { result = node } + + Variable getVariable() { result = v } + + string toString() { result = "VariableAccess[" + name + "]" } + + /** + * Get the location of this variable. + */ + Location getLocation() { result = node.getLocation() } + + /** + * Gets the type of this variable, if any. + */ + Type getType() { result = this.getVariable().getType() } + + /** + * Gets the enclosing scope of this variable, if any. + */ + CfgScope getEnclosingCfgScope() { result = v.getEnclosingCfgScope() } + + string getAPrimaryQlClass() { result = "VariableAccess" } +} + +class VariableWriteAccess extends VariableAccess { + VariableWriteAccess() { + // Parameter + this.getAstNode().getParent() instanceof ParameterDeclaration + or + // SET + this.getAstNode().getParent() instanceof VariableDeclaration + or + this.getAstNode().getParent() instanceof ResourceDeclaration + or + // Output + this.getAstNode().getParent() instanceof OutputDeclaration + } + + override string getAPrimaryQlClass() { result = "VariableWrite" } +} + +class VariableReadAccess extends VariableAccess { + VariableReadAccess() { not this instanceof VariableWriteAccess } + + override string getAPrimaryQlClass() { result = "VariableRead" } +} + +/** + * Holds if the variable is written too. + */ +// private predicate variableWrite(Variable node) { +// exists(Parameter param | +// param.getName() = node.getName() and +// param.getEnclosingCfgScope() = node.getEnclosingCfgScope() +// ) +// } +cached +private module Cached { + cached + newtype TVariable = + TResource(Resource resource, string name) { resource.getIdentifier().getName() = name } or + TVariableDecl(VariableDeclaration varDecl, string name) { + varDecl.getIdentifier().getName() = name + } or + TParameter(ParameterDeclaration param, string name) { param.getName() = name } or + TOutput(OutputDeclaration output, string name) { output.getIdentifier().getName() = name } or + MkVariable(AstNode definingNode, string name) { variableDecl(definingNode, name) } + + cached + newtype TVariableAccess = + TIdent(Identifier ident, string name) { ident.getName() = name } or + MkVariableAccess(AstNode node, Variable v, string name) { variableAccess(node, v, name) } + + cached + predicate variableAccess(AstNode node, Variable v, string name) { access(node, v, name) } +} + +private import Cached diff --git a/ql/lib/codeql/bicep/dataflow/DataFlow.qll b/ql/lib/codeql/bicep/dataflow/DataFlow.qll new file mode 100644 index 0000000..8be32cd --- /dev/null +++ b/ql/lib/codeql/bicep/dataflow/DataFlow.qll @@ -0,0 +1,5 @@ +private import codeql.dataflow.DataFlow +private import codeql.bicep.AST +private import codeql.bicep.CFG as Cfg +private import codeql.bicep.dataflow.Ssa as Ssa +private import codeql.Locations diff --git a/ql/lib/codeql/bicep/dataflow/Ssa.qll b/ql/lib/codeql/bicep/dataflow/Ssa.qll new file mode 100644 index 0000000..830332a --- /dev/null +++ b/ql/lib/codeql/bicep/dataflow/Ssa.qll @@ -0,0 +1,42 @@ +/** + * Provides the module `Ssa` for working with static single assignment (SSA) form. + */ + +/** + * Provides classes for working with static single assignment (SSA) form. + */ +module Ssa { + private import bicep + private import codeql.bicep.controlflow.BasicBlocks + private import codeql.bicep.controlflow.ControlFlowGraph + private import codeql.bicep.controlflow.internal.ControlFlowGraphImpl as CfgImpl + private import internal.SsaImpl as SsaImpl + + class Variable = SsaImpl::SsaInput::SourceVariable; + + class Definition extends SsaImpl::Definition { + final CfgNode getControlFlowNode() { + exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i)) + } + + final CfgNode getARead() { result = SsaImpl::getARead(this) } + + final CfgNode getAFirstRead() { SsaImpl::firstRead(this, result) } + } + + class WriteDefinition extends Definition, SsaImpl::WriteDefinition { + final CfgNode getControlFlowNode() { + exists(BasicBlock bb, int i | this.definesAt(_, bb, i) | result = bb.getNode(i)) + } + + final CfgNode getARead() { result = SsaImpl::getARead(this) } + + cached + override Location getLocation() { + exists(BasicBlock bb, int i | + this.definesAt(_, bb, i) and + result = bb.getNode(i).getLocation() + ) + } + } +} \ No newline at end of file diff --git a/ql/lib/codeql/bicep/dataflow/internal/SsaImpl.qll b/ql/lib/codeql/bicep/dataflow/internal/SsaImpl.qll new file mode 100644 index 0000000..9b8228e --- /dev/null +++ b/ql/lib/codeql/bicep/dataflow/internal/SsaImpl.qll @@ -0,0 +1,101 @@ +private import bicep +private import codeql.bicep.controlflow.BasicBlocks as BasicBlocks +private import BasicBlocks +private import codeql.bicep.controlflow.ControlFlowGraph +private import codeql.bicep.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl +private import codeql.ssa.Ssa as SsaImplCommon + +/** Holds if `write` writes to variable `v`. */ +predicate variableWrite(AstNode write, Variable v) { + exists(VariableWriteAccess access | + access.getAstNode() = write and + access.getVariable() = v + ) +} + +module SsaInput implements SsaImplCommon::InputSig { + class BasicBlock = BasicBlocks::BasicBlock; + + class ControlFlowNode = CfgNode; + + class ExitBasicBlock = BasicBlocks::ExitBasicBlock; + + BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } + + BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + + /** + * A variable amenable to SSA construction. + */ + class SourceVariable extends Variable { + SourceVariable() { + // Only variables that have accesses + exists(VariableAccess access | this.getAnAccess() = access) + } + } + + predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + variableWriteActual(bb, i, v, bb.getNode(i)) and + certain = true + } + + predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(VariableAccess va | + bb.getNode(i).getAstNode() = va.getAstNode() and + va = v.getAnAccess() + ) and + certain = true + } +} + +import SsaImplCommon::Make as Impl + +class Definition = Impl::Definition; + +class WriteDefinition = Impl::WriteDefinition; + +class UncertainWriteDefinition = Impl::UncertainWriteDefinition; + +class PhiDefinition = Impl::PhiNode; + +module Consistency = Impl::Consistency; + +/** Holds if `v` is read at index `i` in basic block `bb`. */ +private predicate variableReadActual(BasicBlock bb, int i, Variable v) { + exists(VariableAccess read | + read instanceof VariableReadAccess and + read.getVariable() = v and + read.getAstNode() = bb.getNode(i).getAstNode() + ) +} + +cached +private module Cached { + cached + CfgNode getARead(Definition def) { + exists(Variable v, BasicBlock bb, int i | + Impl::ssaDefReachesRead(v, def, bb, i) and + variableReadActual(bb, i, v) and + result = bb.getNode(i) + ) + } + + cached + predicate firstRead(Definition def, CfgNode read) { + // TODO: Get first node + exists(BasicBlock bb, int i | read = bb.getNode(i)) + } + + /** + * Holds if `v` is written at index `i` in basic block `bb`, and the corresponding + * write access node in the CFG is `write`. + */ + cached + predicate variableWriteActual(BasicBlock bb, int i, Variable v, CfgNode write) { + bb.getNode(i) = write and + variableWrite(write.getAstNode(), v) + } +} + +import Cached +private import codeql.bicep.dataflow.Ssa diff --git a/ql/lib/qlpack.yml b/ql/lib/qlpack.yml index daf73d4..d12a7cb 100644 --- a/ql/lib/qlpack.yml +++ b/ql/lib/qlpack.yml @@ -8,6 +8,7 @@ dependencies: codeql/yaml: "^1.0.0" codeql/controlflow: "^1.0.0" codeql/dataflow: "^1.1.0" + codeql/threat-models: "^1.0.0" codeql/regex: "^1.0.0" codeql/ssa: "^1.0.0" dbscheme: bicep.dbscheme diff --git a/ql/src/codeql-pack.lock.yml b/ql/src/codeql-pack.lock.yml index 9e1c9be..ace9219 100644 --- a/ql/src/codeql-pack.lock.yml +++ b/ql/src/codeql-pack.lock.yml @@ -9,10 +9,12 @@ dependencies: version: 1.0.12 codeql/ssa: version: 1.0.12 + codeql/threat-models: + version: 1.0.25 codeql/typetracking: version: 1.0.12 codeql/util: version: 1.0.12 codeql/yaml: - version: 1.0.20 + version: 1.0.25 compiled: false diff --git a/ql/test/codeql-pack.lock.yml b/ql/test/codeql-pack.lock.yml index 9e1c9be..ace9219 100644 --- a/ql/test/codeql-pack.lock.yml +++ b/ql/test/codeql-pack.lock.yml @@ -9,10 +9,12 @@ dependencies: version: 1.0.12 codeql/ssa: version: 1.0.12 + codeql/threat-models: + version: 1.0.25 codeql/typetracking: version: 1.0.12 codeql/util: version: 1.0.12 codeql/yaml: - version: 1.0.20 + version: 1.0.25 compiled: false diff --git a/ql/test/library-tests/ast/Variables.expected b/ql/test/library-tests/ast/Variables.expected new file mode 100644 index 0000000..537c5b1 --- /dev/null +++ b/ql/test/library-tests/ast/Variables.expected @@ -0,0 +1,150 @@ +variables +| conditions.bicep:1:1:1:39 | Variable[enableStorageAccount] | +| conditions.bicep:2:1:2:54 | Variable[storageAccountName] | +| conditions.bicep:4:1:12:1 | Variable[storageAccount] | +| data.bicep:2:1:6:1 | Variable[multiLineArray] | +| data.bicep:8:1:8:43 | Variable[singleLineArray] | +| data.bicep:10:1:11:10 | Variable[mixedArray] | +| data.bicep:13:1:13:28 | Variable[exampleArray] | +| data.bicep:14:1:14:41 | Variable[firstElement] | +| data.bicep:15:1:15:41 | Variable[thirdElement] | +| data.bicep:17:1:17:13 | Variable[index] | +| data.bicep:18:1:18:46 | Variable[secondElement] | +| data.bicep:21:1:21:29 | Variable[exampleBool] | +| data.bicep:24:1:24:24 | Variable[exampleInt] | +| data.bicep:27:1:27:92 | Variable[singleLineObject] | +| data.bicep:29:1:34:1 | Variable[multiLineObject] | +| data.bicep:36:1:37:12 | Variable[mixedObject] | +| data.bicep:41:1:41:25 | Variable[myVar] | +| data.bicep:43:1:43:62 | Variable[storageName] | +| data.bicep:46:1:46:24 | Variable[myVar] | +| data.bicep:49:1:50:9 | Variable[myVar2] | +| data.bicep:53:1:55:3 | Variable[myVar3] | +| data.bicep:58:1:62:3 | Variable[myVar4] | +| sample.bicep:1:1:1:48 | Variable[location] | +| sample.bicep:2:1:2:80 | Variable[storageAccountName] | +| sample.bicep:3:1:3:28 | Variable[vmName] | +| sample.bicep:4:1:4:40 | Variable[adminUsername] | +| sample.bicep:5:1:5:43 | Variable[adminPassword] | +| sample.bicep:6:1:6:32 | Variable[vnetName] | +| sample.bicep:7:1:7:36 | Variable[subnetName] | +| sample.bicep:8:1:8:40 | Variable[publicIpName] | +| sample.bicep:9:1:9:30 | Variable[nicName] | +| sample.bicep:11:1:21:1 | Variable[storageAccount] | +| sample.bicep:23:1:41:1 | Variable[vnet] | +| sample.bicep:43:1:49:1 | Variable[publicIp] | +| sample.bicep:51:1:70:1 | Variable[nic] | +| sample.bicep:72:1:103:1 | Variable[vm] | +variableAccess +| conditions.bicep:1:1:1:39 | Variable[enableStorageAccount] | conditions.bicep:1:7:1:26 | VariableAccess[enableStorageAccount] | +| conditions.bicep:1:1:1:39 | Variable[enableStorageAccount] | conditions.bicep:4:78:4:97 | VariableAccess[enableStorageAccount] | +| conditions.bicep:2:1:2:54 | Variable[storageAccountName] | conditions.bicep:2:7:2:24 | VariableAccess[storageAccountName] | +| conditions.bicep:2:1:2:54 | Variable[storageAccountName] | conditions.bicep:5:9:5:26 | VariableAccess[storageAccountName] | +| conditions.bicep:4:1:12:1 | Variable[storageAccount] | conditions.bicep:4:10:4:23 | VariableAccess[storageAccount] | +| data.bicep:13:1:13:28 | Variable[exampleArray] | data.bicep:14:27:14:38 | VariableAccess[exampleArray] | +| data.bicep:13:1:13:28 | Variable[exampleArray] | data.bicep:15:27:15:38 | VariableAccess[exampleArray] | +| data.bicep:13:1:13:28 | Variable[exampleArray] | data.bicep:18:28:18:39 | VariableAccess[exampleArray] | +| data.bicep:14:1:14:41 | Variable[firstElement] | data.bicep:14:8:14:19 | VariableAccess[firstElement] | +| data.bicep:15:1:15:41 | Variable[thirdElement] | data.bicep:15:8:15:19 | VariableAccess[thirdElement] | +| data.bicep:17:1:17:13 | Variable[index] | data.bicep:18:41:18:45 | VariableAccess[index] | +| data.bicep:18:1:18:46 | Variable[secondElement] | data.bicep:18:8:18:20 | VariableAccess[secondElement] | +| data.bicep:21:1:21:29 | Variable[exampleBool] | data.bicep:21:7:21:17 | VariableAccess[exampleBool] | +| data.bicep:24:1:24:24 | Variable[exampleInt] | data.bicep:24:7:24:16 | VariableAccess[exampleInt] | +| data.bicep:27:1:27:92 | Variable[singleLineObject] | data.bicep:27:7:27:22 | VariableAccess[singleLineObject] | +| data.bicep:29:1:34:1 | Variable[multiLineObject] | data.bicep:29:7:29:21 | VariableAccess[multiLineObject] | +| data.bicep:36:1:37:12 | Variable[mixedObject] | data.bicep:36:7:36:17 | VariableAccess[mixedObject] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:1:7:1:14 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:13:3:13:10 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:13:13:13:20 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:25:3:25:10 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:25:13:25:20 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:45:3:45:10 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:45:13:45:20 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:53:3:53:10 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:53:13:53:20 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:74:3:74:10 | VariableAccess[location] | +| sample.bicep:1:1:1:48 | Variable[location] | sample.bicep:74:13:74:20 | VariableAccess[location] | +| sample.bicep:2:1:2:80 | Variable[storageAccountName] | sample.bicep:2:7:2:24 | VariableAccess[storageAccountName] | +| sample.bicep:2:1:2:80 | Variable[storageAccountName] | sample.bicep:12:9:12:26 | VariableAccess[storageAccountName] | +| sample.bicep:3:1:3:28 | Variable[vmName] | sample.bicep:3:7:3:12 | VariableAccess[vmName] | +| sample.bicep:3:1:3:28 | Variable[vmName] | sample.bicep:73:9:73:14 | VariableAccess[vmName] | +| sample.bicep:3:1:3:28 | Variable[vmName] | sample.bicep:80:21:80:26 | VariableAccess[vmName] | +| sample.bicep:4:1:4:40 | Variable[adminUsername] | sample.bicep:4:7:4:19 | VariableAccess[adminUsername] | +| sample.bicep:4:1:4:40 | Variable[adminUsername] | sample.bicep:81:7:81:19 | VariableAccess[adminUsername] | +| sample.bicep:4:1:4:40 | Variable[adminUsername] | sample.bicep:81:22:81:34 | VariableAccess[adminUsername] | +| sample.bicep:5:1:5:43 | Variable[adminPassword] | sample.bicep:5:7:5:19 | VariableAccess[adminPassword] | +| sample.bicep:5:1:5:43 | Variable[adminPassword] | sample.bicep:82:7:82:19 | VariableAccess[adminPassword] | +| sample.bicep:5:1:5:43 | Variable[adminPassword] | sample.bicep:82:22:82:34 | VariableAccess[adminPassword] | +| sample.bicep:6:1:6:32 | Variable[vnetName] | sample.bicep:6:7:6:14 | VariableAccess[vnetName] | +| sample.bicep:6:1:6:32 | Variable[vnetName] | sample.bicep:24:9:24:16 | VariableAccess[vnetName] | +| sample.bicep:7:1:7:36 | Variable[subnetName] | sample.bicep:7:7:7:16 | VariableAccess[subnetName] | +| sample.bicep:7:1:7:36 | Variable[subnetName] | sample.bicep:34:15:34:24 | VariableAccess[subnetName] | +| sample.bicep:8:1:8:40 | Variable[publicIpName] | sample.bicep:8:7:8:18 | VariableAccess[publicIpName] | +| sample.bicep:8:1:8:40 | Variable[publicIpName] | sample.bicep:44:9:44:20 | VariableAccess[publicIpName] | +| sample.bicep:9:1:9:30 | Variable[nicName] | sample.bicep:9:7:9:13 | VariableAccess[nicName] | +| sample.bicep:9:1:9:30 | Variable[nicName] | sample.bicep:52:9:52:15 | VariableAccess[nicName] | +| sample.bicep:11:1:21:1 | Variable[storageAccount] | sample.bicep:11:10:11:23 | VariableAccess[storageAccount] | +| sample.bicep:23:1:41:1 | Variable[vnet] | sample.bicep:23:10:23:13 | VariableAccess[vnet] | +| sample.bicep:23:1:41:1 | Variable[vnet] | sample.bicep:60:17:60:20 | VariableAccess[vnet] | +| sample.bicep:43:1:49:1 | Variable[publicIp] | sample.bicep:43:10:43:17 | VariableAccess[publicIp] | +| sample.bicep:43:1:49:1 | Variable[publicIp] | sample.bicep:64:17:64:24 | VariableAccess[publicIp] | +| sample.bicep:51:1:70:1 | Variable[nic] | sample.bicep:51:10:51:12 | VariableAccess[nic] | +| sample.bicep:51:1:70:1 | Variable[nic] | sample.bicep:98:15:98:17 | VariableAccess[nic] | +| sample.bicep:72:1:103:1 | Variable[vm] | sample.bicep:72:10:72:11 | VariableAccess[vm] | +variableRead +| conditions.bicep:4:78:4:97 | VariableAccess[enableStorageAccount] | +| conditions.bicep:5:9:5:26 | VariableAccess[storageAccountName] | +| data.bicep:14:27:14:38 | VariableAccess[exampleArray] | +| data.bicep:15:27:15:38 | VariableAccess[exampleArray] | +| data.bicep:18:28:18:39 | VariableAccess[exampleArray] | +| data.bicep:18:41:18:45 | VariableAccess[index] | +| sample.bicep:12:9:12:26 | VariableAccess[storageAccountName] | +| sample.bicep:13:3:13:10 | VariableAccess[location] | +| sample.bicep:13:13:13:20 | VariableAccess[location] | +| sample.bicep:24:9:24:16 | VariableAccess[vnetName] | +| sample.bicep:25:3:25:10 | VariableAccess[location] | +| sample.bicep:25:13:25:20 | VariableAccess[location] | +| sample.bicep:34:15:34:24 | VariableAccess[subnetName] | +| sample.bicep:44:9:44:20 | VariableAccess[publicIpName] | +| sample.bicep:45:3:45:10 | VariableAccess[location] | +| sample.bicep:45:13:45:20 | VariableAccess[location] | +| sample.bicep:52:9:52:15 | VariableAccess[nicName] | +| sample.bicep:53:3:53:10 | VariableAccess[location] | +| sample.bicep:53:13:53:20 | VariableAccess[location] | +| sample.bicep:60:17:60:20 | VariableAccess[vnet] | +| sample.bicep:64:17:64:24 | VariableAccess[publicIp] | +| sample.bicep:73:9:73:14 | VariableAccess[vmName] | +| sample.bicep:74:3:74:10 | VariableAccess[location] | +| sample.bicep:74:13:74:20 | VariableAccess[location] | +| sample.bicep:80:21:80:26 | VariableAccess[vmName] | +| sample.bicep:81:7:81:19 | VariableAccess[adminUsername] | +| sample.bicep:81:22:81:34 | VariableAccess[adminUsername] | +| sample.bicep:82:7:82:19 | VariableAccess[adminPassword] | +| sample.bicep:82:22:82:34 | VariableAccess[adminPassword] | +| sample.bicep:98:15:98:17 | VariableAccess[nic] | +variableWrite +| conditions.bicep:1:7:1:26 | VariableAccess[enableStorageAccount] | +| conditions.bicep:2:7:2:24 | VariableAccess[storageAccountName] | +| conditions.bicep:4:10:4:23 | VariableAccess[storageAccount] | +| data.bicep:14:8:14:19 | VariableAccess[firstElement] | +| data.bicep:15:8:15:19 | VariableAccess[thirdElement] | +| data.bicep:18:8:18:20 | VariableAccess[secondElement] | +| data.bicep:21:7:21:17 | VariableAccess[exampleBool] | +| data.bicep:24:7:24:16 | VariableAccess[exampleInt] | +| data.bicep:27:7:27:22 | VariableAccess[singleLineObject] | +| data.bicep:29:7:29:21 | VariableAccess[multiLineObject] | +| data.bicep:36:7:36:17 | VariableAccess[mixedObject] | +| sample.bicep:1:7:1:14 | VariableAccess[location] | +| sample.bicep:2:7:2:24 | VariableAccess[storageAccountName] | +| sample.bicep:3:7:3:12 | VariableAccess[vmName] | +| sample.bicep:4:7:4:19 | VariableAccess[adminUsername] | +| sample.bicep:5:7:5:19 | VariableAccess[adminPassword] | +| sample.bicep:6:7:6:14 | VariableAccess[vnetName] | +| sample.bicep:7:7:7:16 | VariableAccess[subnetName] | +| sample.bicep:8:7:8:18 | VariableAccess[publicIpName] | +| sample.bicep:9:7:9:13 | VariableAccess[nicName] | +| sample.bicep:11:10:11:23 | VariableAccess[storageAccount] | +| sample.bicep:23:10:23:13 | VariableAccess[vnet] | +| sample.bicep:43:10:43:17 | VariableAccess[publicIp] | +| sample.bicep:51:10:51:12 | VariableAccess[nic] | +| sample.bicep:72:10:72:11 | VariableAccess[vm] | diff --git a/ql/test/library-tests/ast/Variables.ql b/ql/test/library-tests/ast/Variables.ql new file mode 100644 index 0000000..4fd6e1f --- /dev/null +++ b/ql/test/library-tests/ast/Variables.ql @@ -0,0 +1,9 @@ +private import bicep + +query predicate variables(Variable var) { any() } + +query predicate variableAccess(Variable var, VariableAccess access) { var.getAnAccess() = access } + +query predicate variableRead(VariableReadAccess reada) { any() } + +query predicate variableWrite(VariableWriteAccess writeAccess) { any() } diff --git a/ql/test/library-tests/calls/Parameters.ql b/ql/test/library-tests/calls/Parameters.ql index ab94a78..37f868d 100644 --- a/ql/test/library-tests/calls/Parameters.ql +++ b/ql/test/library-tests/calls/Parameters.ql @@ -5,6 +5,6 @@ query predicate parameters(Parameter parameter) { } query predicate parameter(Parameter param, Identifier name, string type) { - param.getName() = name and + param.getIdentifier() = name and param.getType().getType() = type }