mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Swift: Post-processing query for inline test expectations
This commit is contained in:
@@ -3,33 +3,6 @@
|
||||
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
||||
*/
|
||||
|
||||
private import swift as S
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
private module Impl implements InlineExpectationsTestSig {
|
||||
private newtype TExpectationComment = MkExpectationComment(S::SingleLineComment c)
|
||||
|
||||
/**
|
||||
* A class representing a line comment.
|
||||
* Unlike the `SingleLineComment` class, however, the string returned by `getContents` does _not_
|
||||
* include the preceding comment marker (`//`).
|
||||
*/
|
||||
class ExpectationComment extends TExpectationComment {
|
||||
S::SingleLineComment comment;
|
||||
|
||||
ExpectationComment() { this = MkExpectationComment(comment) }
|
||||
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = comment.getText().suffix(2) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = comment.toString() }
|
||||
|
||||
/** Gets the location of this comment. */
|
||||
Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
class Location = S::Location;
|
||||
}
|
||||
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
import Make<Impl>
|
||||
|
||||
21
swift/ql/test/TestUtilities/InlineExpectationsTestQuery.ql
Normal file
21
swift/ql/test/TestUtilities/InlineExpectationsTestQuery.ql
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @kind test-postprocess
|
||||
*/
|
||||
|
||||
private import swift
|
||||
private import codeql.util.test.InlineExpectationsTest as T
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
import T::TestPostProcessing
|
||||
import T::TestPostProcessing::Make<Impl, Input>
|
||||
|
||||
private module Input implements T::TestPostProcessing::InputSig<Impl> {
|
||||
string getRelativeUrl(Location location) {
|
||||
exists(File f, int startline, int startcolumn, int endline, int endcolumn |
|
||||
location.hasLocationInfo(_, startline, startcolumn, endline, endcolumn) and
|
||||
f = location.getFile()
|
||||
|
|
||||
result =
|
||||
f.getRelativePath() + ":" + startline + ":" + startcolumn + ":" + endline + ":" + endcolumn
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
private import swift as S
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
module Impl implements InlineExpectationsTestSig {
|
||||
private newtype TExpectationComment = MkExpectationComment(S::SingleLineComment c)
|
||||
|
||||
/**
|
||||
* A class representing a line comment.
|
||||
* Unlike the `SingleLineComment` class, however, the string returned by `getContents` does _not_
|
||||
* include the preceding comment marker (`//`).
|
||||
*/
|
||||
class ExpectationComment extends TExpectationComment {
|
||||
S::SingleLineComment comment;
|
||||
|
||||
ExpectationComment() { this = MkExpectationComment(comment) }
|
||||
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = comment.getText().suffix(2) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = comment.toString() }
|
||||
|
||||
/** Gets the location of this comment. */
|
||||
Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
class Location = S::Location;
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
queries/Security/CWE-094/UnsafeJsEval.ql
|
||||
query: queries/Security/CWE-094/UnsafeJsEval.ql
|
||||
postprocess: TestUtilities/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -175,17 +175,17 @@ func testAsync(_ sink: @escaping (String) async throws -> ()) {
|
||||
let url = URL(string: "http://example.com/")
|
||||
|
||||
try! await sink(localString) // GOOD: the HTML data is local
|
||||
try! await sink(try String(contentsOf: URL(string: "http://example.com/")!)) // BAD [NOT DETECTED - TODO]: HTML contains remote input, may access local secrets
|
||||
try! await sink(try! String(contentsOf: url!)) // BAD [NOT DETECTED - TODO]
|
||||
try! await sink(try String(contentsOf: URL(string: "http://example.com/")!)) // $ MISSING: Alert (HTML contains remote input, may access local secrets)
|
||||
try! await sink(try! String(contentsOf: url!)) // $ MISSING: Alert
|
||||
|
||||
try! await sink("console.log(" + localStringFragment + ")") // GOOD: the HTML data is local
|
||||
try! await sink("console.log(" + (try! String(contentsOf: url!)) + ")") // BAD [NOT DETECTED - TODO]
|
||||
try! await sink("console.log(" + (try! String(contentsOf: url!)) + ")") // $ MISSING: Alert
|
||||
|
||||
let localData = Data(localString.utf8)
|
||||
let remoteData = Data((try! String(contentsOf: url!)).utf8)
|
||||
|
||||
try! await sink(String(decoding: localData, as: UTF8.self)) // GOOD: the data is local
|
||||
try! await sink(String(decoding: remoteData, as: UTF8.self)) // BAD [NOT DETECTED - TODO]: the data is remote
|
||||
try! await sink(String(decoding: remoteData, as: UTF8.self)) // $ MISSING: Alert the data is remote
|
||||
|
||||
try! await sink("console.log(" + String(Int(localStringFragment) ?? 0) + ")") // GOOD: Primitive conversion
|
||||
try! await sink("console.log(" + String(Int(try! String(contentsOf: url!)) ?? 0) + ")") // GOOD: Primitive conversion
|
||||
@@ -201,17 +201,17 @@ func testSync(_ sink: @escaping (String) -> ()) {
|
||||
let url = URL(string: "http://example.com/")
|
||||
|
||||
sink(localString) // GOOD: the HTML data is local
|
||||
sink(try! String(contentsOf: URL(string: "http://example.com/")!)) // BAD: HTML contains remote input, may access local secrets
|
||||
sink(try! String(contentsOf: url!)) // BAD
|
||||
sink(try! String(contentsOf: URL(string: "http://example.com/")!)) // $ Source=source1 $ MISSING: Alert HTML contains remote input, may access local secrets
|
||||
sink(try! String(contentsOf: url!)) // $ Source=source2 $ MISSING: Alert
|
||||
|
||||
sink("console.log(" + localStringFragment + ")") // GOOD: the HTML data is local
|
||||
sink("console.log(" + (try! String(contentsOf: url!)) + ")") // BAD
|
||||
sink("console.log(" + (try! String(contentsOf: url!)) + ")") // $ Source=source3 $ MISSING: Alert
|
||||
|
||||
let localData = Data(localString.utf8)
|
||||
let remoteData = Data((try! String(contentsOf: url!)).utf8)
|
||||
let remoteData = Data((try! String(contentsOf: url!)).utf8) // $ Source=source4
|
||||
|
||||
sink(String(decoding: localData, as: UTF8.self)) // GOOD: the data is local
|
||||
sink(String(decoding: remoteData, as: UTF8.self)) // BAD: the data is remote
|
||||
sink(String(decoding: remoteData, as: UTF8.self)) // $ MISSING: Alert the data is remote
|
||||
|
||||
sink("console.log(" + String(Int(localStringFragment) ?? 0) + ")") // GOOD: Primitive conversion
|
||||
sink("console.log(" + String(Int(try! String(contentsOf: url!)) ?? 0) + ")") // GOOD: Primitive conversion
|
||||
@@ -224,7 +224,7 @@ func testUIWebView() {
|
||||
let webview = UIWebView()
|
||||
|
||||
testAsync { string in
|
||||
_ = await webview.stringByEvaluatingJavaScript(from: string) // BAD [NOT DETECTED]
|
||||
_ = await webview.stringByEvaluatingJavaScript(from: string) // $ MISSING: Alert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ func testWebView() {
|
||||
let webview = WebView()
|
||||
|
||||
testAsync { string in
|
||||
_ = await webview.stringByEvaluatingJavaScript(from: string) // BAD [NOT DETECTED]
|
||||
_ = await webview.stringByEvaluatingJavaScript(from: string) // $ MISSING: Alert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,22 +240,22 @@ func testWKWebView() {
|
||||
let webview = WKWebView()
|
||||
|
||||
testAsync { string in
|
||||
_ = try await webview.evaluateJavaScript(string) // BAD [NOT DETECTED]
|
||||
_ = try await webview.evaluateJavaScript(string) // $ MISSING: Alert
|
||||
}
|
||||
testAsync { string in
|
||||
await webview.evaluateJavaScript(string) { _, _ in } // BAD [NOT DETECTED]
|
||||
await webview.evaluateJavaScript(string) { _, _ in } // $ MISSING: Alert
|
||||
}
|
||||
testAsync { string in
|
||||
await webview.evaluateJavaScript(string, in: nil, in: WKContentWorld.defaultClient) { _ in } // BAD [NOT DETECTED]
|
||||
await webview.evaluateJavaScript(string, in: nil, in: WKContentWorld.defaultClient) { _ in } // $ MISSING: Alert
|
||||
}
|
||||
testAsync { string in
|
||||
_ = try await webview.evaluateJavaScript(string, contentWorld: .defaultClient) // BAD [NOT DETECTED]
|
||||
_ = try await webview.evaluateJavaScript(string, contentWorld: .defaultClient) // $ MISSING: Alert
|
||||
}
|
||||
testAsync { string in
|
||||
await webview.callAsyncJavaScript(string, in: nil, in: .defaultClient) { _ in () } // BAD [NOT DETECTED]
|
||||
await webview.callAsyncJavaScript(string, in: nil, in: .defaultClient) { _ in () } // $ MISSING: Alert
|
||||
}
|
||||
testAsync { string in
|
||||
_ = try await webview.callAsyncJavaScript(string, contentWorld: WKContentWorld.defaultClient) // BAD [NOT DETECTED]
|
||||
_ = try await webview.callAsyncJavaScript(string, contentWorld: WKContentWorld.defaultClient) // $ MISSING: Alert
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,10 +263,10 @@ func testWKUserContentController() {
|
||||
let ctrl = WKUserContentController()
|
||||
|
||||
testSync { string in
|
||||
ctrl.addUserScript(WKUserScript(source: string, injectionTime: .atDocumentStart, forMainFrameOnly: false)) // BAD (multiple sources)
|
||||
ctrl.addUserScript(WKUserScript(source: string, injectionTime: .atDocumentStart, forMainFrameOnly: false)) // $ Alert=source1 $ Alert=source2 $ Alert=source3 $ Alert=source4
|
||||
}
|
||||
testSync { string in
|
||||
ctrl.addUserScript(WKUserScript(source: string, injectionTime: .atDocumentEnd, forMainFrameOnly: true, in: .defaultClient)) // BAD (multiple sources)
|
||||
ctrl.addUserScript(WKUserScript(source: string, injectionTime: .atDocumentEnd, forMainFrameOnly: true, in: .defaultClient)) // $ Alert=source1 $ Alert=source2 $ Alert=source3 $ Alert=source4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,10 +274,10 @@ func testJSContext() {
|
||||
let ctx = JSContext()
|
||||
|
||||
testSync { string in
|
||||
_ = ctx.evaluateScript(string) // BAD (multiple sources)
|
||||
_ = ctx.evaluateScript(string) // $ Alert=source1 $ Alert=source2 $ Alert=source3 $ Alert=source4
|
||||
}
|
||||
testSync { string in
|
||||
_ = ctx.evaluateScript(string, withSourceURL: URL(string: "https://example.com")) // BAD (multiple sources)
|
||||
_ = ctx.evaluateScript(string, withSourceURL: URL(string: "https://example.com")) // $ Alert=source1 $ Alert=source2 $ Alert=source3 $ Alert=source4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,7 +288,7 @@ func testJSEvaluateScript() {
|
||||
defer { JSStringRelease(jsstr) }
|
||||
_ = JSEvaluateScript(
|
||||
/*ctx:*/ OpaquePointer(bitPattern: 0),
|
||||
/*script:*/ jsstr, // BAD (multiple sources)
|
||||
/*script:*/ jsstr, // $ Alert=source1 $ Alert=source2 $ Alert=source3 $ Alert=source4
|
||||
/*thisObject:*/ OpaquePointer(bitPattern: 0),
|
||||
/*sourceURL:*/ OpaquePointer(bitPattern: 0),
|
||||
/*startingLineNumber:*/ 0,
|
||||
@@ -302,7 +302,7 @@ func testJSEvaluateScript() {
|
||||
defer { JSStringRelease(jsstr) }
|
||||
_ = JSEvaluateScript(
|
||||
/*ctx:*/ OpaquePointer(bitPattern: 0),
|
||||
/*script:*/ jsstr, // BAD (multiple sources)
|
||||
/*script:*/ jsstr, // $ Alert=source1 $ Alert=source2 $ Alert=source3 $ Alert=source4
|
||||
/*thisObject:*/ OpaquePointer(bitPattern: 0),
|
||||
/*sourceURL:*/ OpaquePointer(bitPattern: 0),
|
||||
/*startingLineNumber:*/ 0,
|
||||
@@ -315,9 +315,9 @@ func testJSEvaluateScript() {
|
||||
func testQHelpExamples() {
|
||||
Task {
|
||||
let webview = WKWebView()
|
||||
let remoteData = try String(contentsOf: URL(string: "http://example.com/evil.json")!)
|
||||
let remoteData = try String(contentsOf: URL(string: "http://example.com/evil.json")!) // $ Source=source5
|
||||
|
||||
_ = try await webview.evaluateJavaScript("console.log(" + remoteData + ")") // BAD
|
||||
_ = try await webview.evaluateJavaScript("console.log(" + remoteData + ")") // $ Alert=source5
|
||||
|
||||
_ = try await webview.callAsyncJavaScript(
|
||||
"console.log(data)",
|
||||
|
||||
Reference in New Issue
Block a user