Merge branch 'main' into redsun82/rust-analyzer-update

This commit is contained in:
Paolo Tranquilli
2025-03-25 18:29:39 +01:00
committed by GitHub
112 changed files with 7700 additions and 1079 deletions

22
.github/workflows/go-tests-rtjo.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: "Go: Run RTJO Tests"
on:
pull_request:
types:
- labeled
permissions:
contents: read
jobs:
test-linux:
if: "github.repository_owner == 'github' && github.event.label.name == 'Run: RTJO Language Tests'"
name: RTJO Test Linux (Ubuntu)
runs-on: ubuntu-latest-xl
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Run tests
uses: ./go/actions/test
with:
run-code-checks: true
dynamic-join-order-mode: all

40
.github/workflows/ruby-qltest-rtjo.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: "Ruby: Run RTJO Language Tests"
on:
pull_request:
types:
- opened
- synchronize
- reopened
- labeled
env:
CARGO_TERM_COLOR: always
defaults:
run:
working-directory: ruby
permissions:
contents: read
jobs:
qltest-rtjo:
if: "github.repository_owner == 'github' && github.event.label.name == 'Run: RTJO Language Tests'"
runs-on: ubuntu-latest-xl
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/fetch-codeql
- uses: ./ruby/actions/create-extractor-pack
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: ruby-qltest
- name: Run QL tests
run: |
codeql test run --dynamic-join-order-mode=all --threads=0 --ram 50000 --search-path "${{ github.workspace }}" --check-databases --check-undefined-labels --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
env:
GITHUB_TOKEN: ${{ github.token }}

View File

@@ -0,0 +1,5 @@
---
category: fix
---
* The query `actions/code-injection/medium` now produces alerts for injection
vulnerabilities on `pull_request` events.

View File

@@ -30,6 +30,9 @@ extensions:
- ["pull_request_review_comment", "github.event.review"]
- ["pull_request_review_comment", "github.head_ref"]
- ["pull_request_review_comment", "github.event.changes"]
- ["pull_request", "github.event.pull_request"]
- ["pull_request", "github.head_ref"]
- ["pull_request", "github.event.changes"]
- ["pull_request_target", "github.event.pull_request"]
- ["pull_request_target", "github.head_ref"]
- ["pull_request_target", "github.event.changes"]

View File

@@ -12,6 +12,7 @@ extensions:
- ["pull_request_comment"]
- ["pull_request_review"]
- ["pull_request_review_comment"]
- ["pull_request"]
- ["pull_request_target"]
- ["workflow_run"] # depending on branch filter
- ["workflow_call"] # depending on caller

View File

@@ -400,6 +400,7 @@ nodes
| .github/workflows/level0.yml:44:20:44:49 | github.event.issue.body | semmle.label | github.event.issue.body |
| .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body |
| .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch |
| .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body |
| .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
| .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body |
| .github/workflows/pull_request_review.yml:9:19:9:61 | github.event.pull_request.head.label | semmle.label | github.event.pull_request.head.label |
@@ -629,6 +630,7 @@ nodes
| .github/workflows/test19.yml:124:9:129:6 | Run Step: title3 [title] | semmle.label | Run Step: title3 [title] |
| .github/workflows/test19.yml:125:14:128:50 | TITLE=$(gh issue view "$ISSUE_NUMBER" --json title,author)\nTITLE=$(echo $TITLE \| jq -r '.title')\necho "title=$TITLE" >> "$GITHUB_OUTPUT"\n | semmle.label | TITLE=$(gh issue view "$ISSUE_NUMBER" --json title,author)\nTITLE=$(echo $TITLE \| jq -r '.title')\necho "title=$TITLE" >> "$GITHUB_OUTPUT"\n |
| .github/workflows/test19.yml:129:21:129:52 | steps.title3.outputs.title | semmle.label | steps.title3.outputs.title |
| .github/workflows/test20.yml:15:54:15:94 | github.event.pull_request.head.ref | semmle.label | github.event.pull_request.head.ref |
| .github/workflows/test21.yml:22:35:22:73 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
| .github/workflows/test21.yml:23:36:23:74 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
| .github/workflows/test21.yml:24:50:24:88 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |

View File

@@ -400,6 +400,7 @@ nodes
| .github/workflows/level0.yml:44:20:44:49 | github.event.issue.body | semmle.label | github.event.issue.body |
| .github/workflows/level0.yml:69:35:69:66 | github.event.comment.body | semmle.label | github.event.comment.body |
| .github/workflows/level1.yml:37:38:37:81 | github.event.workflow_run.head_branch | semmle.label | github.event.workflow_run.head_branch |
| .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | semmle.label | github.event.pull_request.body |
| .github/workflows/pull_request_review.yml:7:19:7:56 | github.event.pull_request.title | semmle.label | github.event.pull_request.title |
| .github/workflows/pull_request_review.yml:8:19:8:55 | github.event.pull_request.body | semmle.label | github.event.pull_request.body |
| .github/workflows/pull_request_review.yml:9:19:9:61 | github.event.pull_request.head.label | semmle.label | github.event.pull_request.head.label |
@@ -629,6 +630,7 @@ nodes
| .github/workflows/test19.yml:124:9:129:6 | Run Step: title3 [title] | semmle.label | Run Step: title3 [title] |
| .github/workflows/test19.yml:125:14:128:50 | TITLE=$(gh issue view "$ISSUE_NUMBER" --json title,author)\nTITLE=$(echo $TITLE \| jq -r '.title')\necho "title=$TITLE" >> "$GITHUB_OUTPUT"\n | semmle.label | TITLE=$(gh issue view "$ISSUE_NUMBER" --json title,author)\nTITLE=$(echo $TITLE \| jq -r '.title')\necho "title=$TITLE" >> "$GITHUB_OUTPUT"\n |
| .github/workflows/test19.yml:129:21:129:52 | steps.title3.outputs.title | semmle.label | steps.title3.outputs.title |
| .github/workflows/test20.yml:15:54:15:94 | github.event.pull_request.head.ref | semmle.label | github.event.pull_request.head.ref |
| .github/workflows/test21.yml:22:35:22:73 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
| .github/workflows/test21.yml:23:36:23:74 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
| .github/workflows/test21.yml:24:50:24:88 | github.event.head_commit.message | semmle.label | github.event.head_commit.message |
@@ -706,6 +708,7 @@ subpaths
| .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job2.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job2.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} |
| .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | .github/workflows/inter-job4.yml:22:9:26:6 | Uses Step: source | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job4.yml:44:20:44:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} |
| .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/inter-job5.yml:45:20:45:53 | needs.job1.outputs.job_output | ${{needs.job1.outputs.job_output}} |
| .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/priv_pull_request.yml:14:21:14:57 | github.event.pull_request.body | ${{ github.event.pull_request.body }} |
| .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:7:19:7:57 | github.event.commits[11].message | ${{ github.event.commits[11].message }} |
| .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:8:19:8:62 | github.event.commits[11].author.email | ${{ github.event.commits[11].author.email }} |
| .github/workflows/push.yml:9:19:9:61 | github.event.commits[11].author.name | .github/workflows/push.yml:9:19:9:61 | github.event.commits[11].author.name | .github/workflows/push.yml:9:19:9:61 | github.event.commits[11].author.name | Potential code injection in $@, which may be controlled by an external user. | .github/workflows/push.yml:9:19:9:61 | github.event.commits[11].author.name | ${{ github.event.commits[11].author.name }} |

View File

@@ -109,7 +109,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
if (checkNugetFeedResponsiveness && !CheckFeeds(out explicitFeeds))
{
// todo: we could also check the reachability of the inherited nuget feeds, but to use those in the fallback we would need to handle authentication too.
var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds(explicitFeeds);
var unresponsiveMissingPackageLocation = DownloadMissingPackagesFromSpecificFeeds([], explicitFeeds);
return unresponsiveMissingPackageLocation is null
? []
: [unresponsiveMissingPackageLocation];
@@ -166,11 +166,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
.ToList();
assemblyLookupLocations.UnionWith(paths.Select(p => new AssemblyLookupLocation(p)));
LogAllUnusedPackages(dependencies);
var usedPackageNames = GetAllUsedPackageDirNames(dependencies);
var missingPackageLocation = checkNugetFeedResponsiveness
? DownloadMissingPackagesFromSpecificFeeds(explicitFeeds)
: DownloadMissingPackages();
? DownloadMissingPackagesFromSpecificFeeds(usedPackageNames, explicitFeeds)
: DownloadMissingPackages(usedPackageNames);
if (missingPackageLocation is not null)
{
@@ -297,21 +297,21 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
compilationInfoContainer.CompilationInfos.Add(("Failed project restore with package source error", nugetSourceFailures.ToString()));
}
private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds(HashSet<string>? feedsFromNugetConfigs)
private AssemblyLookupLocation? DownloadMissingPackagesFromSpecificFeeds(IEnumerable<string> usedPackageNames, HashSet<string>? feedsFromNugetConfigs)
{
var reachableFallbackFeeds = GetReachableFallbackNugetFeeds(feedsFromNugetConfigs);
if (reachableFallbackFeeds.Count > 0)
{
return DownloadMissingPackages(fallbackNugetFeeds: reachableFallbackFeeds);
return DownloadMissingPackages(usedPackageNames, fallbackNugetFeeds: reachableFallbackFeeds);
}
logger.LogWarning("Skipping download of missing packages from specific feeds as no fallback Nuget feeds are reachable.");
return null;
}
private AssemblyLookupLocation? DownloadMissingPackages(IEnumerable<string>? fallbackNugetFeeds = null)
private AssemblyLookupLocation? DownloadMissingPackages(IEnumerable<string> usedPackageNames, IEnumerable<string>? fallbackNugetFeeds = null)
{
var alreadyDownloadedPackages = GetRestoredPackageDirectoryNames(PackageDirectory.DirInfo);
var alreadyDownloadedPackages = usedPackageNames.Select(p => p.ToLowerInvariant());
var alreadyDownloadedLegacyPackages = GetRestoredLegacyPackageNames();
var notYetDownloadedPackages = new HashSet<PackageReference>(fileContent.AllPackages);
@@ -418,17 +418,23 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
return nugetConfig;
}
private void LogAllUnusedPackages(DependencyContainer dependencies)
private IEnumerable<string> GetAllUsedPackageDirNames(DependencyContainer dependencies)
{
var allPackageDirectories = GetAllPackageDirectories();
logger.LogInfo($"Restored {allPackageDirectories.Count} packages");
logger.LogInfo($"Found {dependencies.Packages.Count} packages in project.assets.json files");
allPackageDirectories
.Where(package => !dependencies.Packages.Contains(package))
var usage = allPackageDirectories.Select(package => (package, isUsed: dependencies.Packages.Contains(package)));
usage
.Where(package => !package.isUsed)
.Order()
.ForEach(package => logger.LogDebug($"Unused package: {package}"));
.ForEach(package => logger.LogDebug($"Unused package: {package.package}"));
return usage
.Where(package => package.isUsed)
.Select(package => package.package);
}
private ICollection<string> GetAllPackageDirectories()

View File

@@ -4,7 +4,7 @@ source https://api.nuget.org/v3/index.json
# behave like nuget in choosing transitive dependency versions
strategy: max
nuget Basic.CompilerLog.Util
nuget Basic.CompilerLog.Util 0.9.8
nuget Mono.Posix.NETStandard
nuget Newtonsoft.Json
nuget xunit

12
csharp/paket.lock generated
View File

@@ -3,12 +3,12 @@ STRATEGY: MAX
RESTRICTION: == net9.0
NUGET
remote: https://api.nuget.org/v3/index.json
Basic.CompilerLog.Util (0.9.4)
Basic.CompilerLog.Util (0.9.8)
MessagePack (>= 2.5.187)
Microsoft.CodeAnalysis (>= 4.11)
Microsoft.CodeAnalysis.CSharp (>= 4.11)
Microsoft.CodeAnalysis.VisualBasic (>= 4.11)
Microsoft.Extensions.ObjectPool (>= 9.0)
Microsoft.CodeAnalysis (>= 4.12)
Microsoft.CodeAnalysis.CSharp (>= 4.12)
Microsoft.CodeAnalysis.VisualBasic (>= 4.12)
Microsoft.Extensions.ObjectPool (>= 9.0.2)
MSBuild.StructuredLogger (>= 2.2.243)
System.Buffers (>= 4.6)
Humanizer.Core (2.14.1)
@@ -96,7 +96,7 @@ NUGET
System.Reflection.Metadata (>= 8.0)
System.Threading.Channels (>= 7.0)
Microsoft.CodeCoverage (17.12)
Microsoft.Extensions.ObjectPool (9.0)
Microsoft.Extensions.ObjectPool (9.0.3)
Microsoft.NET.StringTools (17.12.6)
Microsoft.NET.Test.Sdk (17.12)
Microsoft.CodeCoverage (>= 17.12)

4
csharp/paket.main.bzl generated

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved dependency resolution in `build-mode: none` extraction to handle failing `dotnet restore` processes that managed to download a subset of the dependencies before the failure.

View File

@@ -30,6 +30,8 @@ The following properties are supported by all query files:
+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``@id`` | ``<text>`` | A sequence of words composed of lowercase letters or digits, delimited by ``/`` or ``-``, identifying and classifying the query. Each query must have a **unique** ID. To ensure this, it may be helpful to use a fixed structure for each ID. For example, the standard CodeQL queries have the following format: ``<language>/<brief-description>``. |
+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``@previous-id`` | ``<text>`` | Indicates that query results were previously reported on a different query. The previous id should be a sequence of words composed of lowercase letters or digits, delimited by ``/`` or ``-``, identifying and classifying the previous query. |
+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ``@kind`` | | ``problem`` | Identifies the query is an alert (``@kind problem``) or a path (``@kind path-problem``). For more information on these query types, see ":doc:`About CodeQL queries <about-codeql-queries>`." |
| | | ``path-problem`` | |
+-----------------------+---------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

View File

@@ -93,6 +93,10 @@ Note, `@id` properties should be consistent for queries that highlight the same
* `@id java/tainted-format-string`
* `@id cpp/tainted-format-string`
#### Query previous ID `@previous-id`
Queries with alerts that used to be reported on a different query should also have an `@previous-id` property to refer back to the query where the alerts were originally reported. For example, if alerts from `java/query-one` are now reported on `java/query-two`, then the metadata for `java/query-two` should contain: `@previous-id java/query-one`.
### Query type `@kind`
@@ -113,7 +117,7 @@ Alert queries (`@kind problem` or `path-problem`) support two further properties
* `medium`
* `high`
* `very-high`
* `@problem.severity`defines the likelihood that an alert, either security-related or not, causes an actual problem such as incorrect program behavior:
* `@problem.severity`defines the likelihood that an alert, either security-related or not, causes an actual problem such as incorrect program behavior:
* `error`an issue that is likely to cause incorrect program behavior, for example a crash or vulnerability.
* `warning`an issue that indicates a potential problem in the code, or makes the code fragile if another (unrelated) part of code is changed.
* `recommendation`an issue where the code behaves correctly, but it could be improved.

View File

@@ -52,9 +52,9 @@ ql/lib/go.dbscheme.stats: ql/lib/go.dbscheme build/stats/src.stamp extractor
codeql dataset measure -o $@ build/stats/database/db-go
test: all build/testdb/check-upgrade-path
codeql test run -j0 ql/test --search-path .. --consistency-queries ql/test/consistency --compilation-cache=$(cache)
codeql test run -j0 ql/test --search-path .. --consistency-queries ql/test/consistency --compilation-cache=$(cache) --dynamic-join-order-mode=$(rtjo)
# use GOOS=linux because GOOS=darwin GOARCH=386 is no longer supported
env GOOS=linux GOARCH=386 codeql$(EXE) test run -j0 ql/test/query-tests/Security/CWE-681 --search-path .. --consistency-queries ql/test/consistency --compilation-cache=$(cache)
env GOOS=linux GOARCH=386 codeql$(EXE) test run -j0 ql/test/query-tests/Security/CWE-681 --search-path .. --consistency-queries ql/test/consistency --compilation-cache=$(cache) --dynamic-join-order-mode=$(rtjo)
cd extractor; $(BAZEL) test ...
bash extractor-smoke-test/test.sh || (echo "Extractor smoke test FAILED"; exit 1)

View File

@@ -9,6 +9,10 @@ inputs:
description: Whether to run formatting, code and qhelp generation checks
required: false
default: false
dynamic-join-order-mode:
description: Value of the --dynamic-join-order-mode flag to pass to the codeql test command
required: false
default: "none"
runs:
using: composite
steps:
@@ -74,4 +78,4 @@ runs:
shell: bash
run: |
cd go
make test cache="${{ steps.query-cache.outputs.cache-dir }}"
make test cache="${{ steps.query-cache.outputs.cache-dir }}" rtjo=${{ inputs.dynamic-join-order-mode }}

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* `database` source models have been added for v1 and v2 of the `github.com/couchbase/gocb` package.

View File

@@ -9,6 +9,32 @@ extensions:
- ["gocb2", "github.com/couchbase/gocb/v2"]
- ["gocb2", "gopkg.in/couchbase/gocb.v2"]
- ["gocb2", "github.com/couchbaselabs/gocb/v2"]
- addsTo:
pack: codeql/go-all
extensible: sourceModel
data:
- ["group:gocb1", "Cluster", True, "ExecuteAnalyticsQuery", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb1", "Cluster", True, "ExecuteN1qlQuery", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb1", "Cluster", True, "ExecuteSearchQuery", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Cluster", True, "AnalyticsQuery", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Cluster", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "Get", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "GetAndLock", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "GetAndTouch", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "GetAnyReplica", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "LookupIn", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "LookupInAllReplicas", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "LookupInAnyReplica", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Collection", True, "Scan", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Scope", True, "AnalyticsQuery", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "Scope", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "TransactionAttemptContext", True, "Get", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "TransactionAttemptContext", True, "GetReplicaFromPreferredServerGroup", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "TransactionAttemptContext", True, "Insert", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "TransactionAttemptContext", True, "Query", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "TransactionAttemptContext", True, "Replace", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "ViewIndexManager", True, "GetAllDesignDocuments", "", "", "ReturnValue[0]", "database", "manual"]
- ["group:gocb2", "ViewIndexManager", True, "GetDesignDocument", "", "", "ReturnValue[0]", "database", "manual"]
- addsTo:
pack: codeql/go-all
extensible: sinkModel
@@ -27,6 +53,9 @@ extensions:
data:
- ["group:gocb1", "", False, "NewAnalyticsQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "", False, "NewN1qlQuery", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "AnalyticsResults", True, "One", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb1", "AnalyticsResults", True, "Next", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb1", "AnalyticsResults", True, "NextBytes", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "AnalyticsQuery", True, "ContextId", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "AnalyticsQuery", True, "Deferred", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "AnalyticsQuery", True, "Pretty", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
@@ -43,3 +72,30 @@ extensions:
- ["group:gocb1", "N1qlQuery", True, "ReadOnly", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "N1qlQuery", True, "ScanCap", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "N1qlQuery", True, "Timeout", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "QueryResults", True, "One", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb1", "QueryResults", True, "Next", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb1", "QueryResults", True, "NextBytes", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb1", "SearchResults", True, "Hits", "", "", "Argument[receiver]", "ReturnValue.ArrayElement", "taint", "manual"]
- ["group:gocb2", "AnalyticsResult", True, "One", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "AnalyticsResult", True, "Raw", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "AnalyticsResult", True, "Row", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "AnalyticsResultRaw", True, "NextBytes", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "GetResult", True, "Content", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "LookupInAllReplicasResult", True, "Next", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "LookupInResult", True, "ContentAt", "", "", "Argument[receiver]", "Argument[1]", "taint", "manual"]
- ["group:gocb2", "MutateInResult", True, "ContentAt", "", "", "Argument[receiver]", "Argument[1]", "taint", "manual"]
- ["group:gocb2", "QueryResult", True, "One", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "QueryResult", True, "Raw", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "QueryResult", True, "Row", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "QueryResultRaw", True, "NextBytes", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "ScanResult", True, "Next", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "ScanResultItem", True, "Content", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "SearchResult", True, "Raw", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "SearchResult", True, "Row", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "SearchResultRaw", True, "NextBytes", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "TransactionGetResult", True, "Content", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "TransactionQueryResult", True, "One", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "TransactionQueryResult", True, "Row", "", "", "Argument[receiver]", "Argument[0]", "taint", "manual"]
- ["group:gocb2", "ViewResult", True, "Raw", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "ViewResult", True, "Row", "", "", "Argument[receiver]", "ReturnValue", "taint", "manual"]
- ["group:gocb2", "ViewResultRaw", True, "NextBytes", "", "", "Argument[receiver]", "ReturnValue[0]", "taint", "manual"]

View File

@@ -357,6 +357,23 @@ module RegexpReplaceFunction {
class LoggerCall extends DataFlow::Node instanceof LoggerCall::Range {
/** Gets a node that is a part of the logged message. */
DataFlow::Node getAMessageComponent() { result = super.getAMessageComponent() }
/**
* Gets a node whose value is a part of the logged message.
*
* Components corresponding to the format specifier "%T" are excluded as
* their type is logged rather than their value.
*/
DataFlow::Node getAValueFormattedMessageComponent() {
result = this.getAMessageComponent() and
not exists(string formatSpecifier |
result = this.(StringOps::Formatting::StringFormatCall).getOperand(_, formatSpecifier) and
// We already know that `formatSpecifier` starts with `%`, so we check
// that it ends with `T` to confirm that it is `%T` or possibly some
// variation on it.
formatSpecifier.matches("%T")
)
}
}
/** Provides a class for modeling new logging APIs. */

View File

@@ -40,7 +40,7 @@ module CleartextLogging {
* An argument to a logging mechanism.
*/
class LoggerSink extends Sink {
LoggerSink() { this = any(LoggerCall log).getAMessageComponent() }
LoggerSink() { this = any(LoggerCall log).getAValueFormattedMessageComponent() }
}
/**

View File

@@ -35,7 +35,7 @@ module LogInjection {
/** An argument to a logging mechanism. */
class LoggerSink extends Sink {
LoggerSink() { this = any(LoggerCall log).getAMessageComponent() }
LoggerSink() { this = any(LoggerCall log).getAValueFormattedMessageComponent() }
}
/**

View File

@@ -138,7 +138,9 @@ predicate privateUrlFlowsToAuthCodeUrlCall(DataFlow::CallNode call) {
module FlowToPrintConfig implements DataFlow::ConfigSig {
additional predicate isSinkCall(DataFlow::Node sink, DataFlow::CallNode call) {
exists(LoggerCall logCall | call = logCall | sink = logCall.getAMessageComponent())
exists(LoggerCall logCall | call = logCall |
sink = logCall.getAValueFormattedMessageComponent()
)
}
predicate isSource(DataFlow::Node source) { source = any(AuthCodeUrl m).getACall().getResult() }

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* False positives in "Log entries created from user input" (`go/log-injection`) and "Clear-text logging of sensitive information" (`go/clear-text-logging`) which involved the verb `%T` in a format specifier have been fixed. As a result, some users may also see more alerts from the "Use of constant `state` value in OAuth 2.0 URL" (`go/constant-oauth2-state`) query.

View File

@@ -4,14 +4,20 @@ import ModelValidation
import utils.test.InlineExpectationsTest
module LoggerTest implements TestSig {
string getARelevantTag() { result = "logger" }
string getARelevantTag() { result = ["type-logger", "logger"] }
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(LoggerCall log |
log.getLocation() = location and
element = log.toString() and
value = log.getAMessageComponent().toString() and
tag = "logger"
(
value = log.getAValueFormattedMessageComponent().toString() and
tag = "logger"
or
value = log.getAMessageComponent().toString() and
not value = log.getAValueFormattedMessageComponent().toString() and
tag = "type-logger"
)
)
}
}

View File

@@ -30,6 +30,13 @@ func glogTest() {
glog.Warningf(fmt, text) // $ logger=fmt logger=text
glog.Warningln(text) // $ logger=text
// components corresponding to the format specifier "%T" are not considered vulnerable
glog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
glog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Error(text) // $ logger=text
klog.ErrorDepth(0, text) // $ logger=text
klog.Errorf(fmt, text) // $ logger=fmt logger=text
@@ -50,4 +57,11 @@ func glogTest() {
klog.WarningDepth(0, text) // $ logger=text
klog.Warningf(fmt, text) // $ logger=fmt logger=text
klog.Warningln(text) // $ logger=text
// components corresponding to the format specifier "%T" are not considered vulnerable
klog.Errorf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Exitf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
klog.Warningf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}

View File

@@ -32,4 +32,8 @@ func logrusCalls() {
logrus.Panicln(text) // $ logger=text
logrus.Infof(fmt, text) // $ logger=fmt logger=text
logrus.FatalFn(fn) // $ logger=fn
// components corresponding to the format specifier "%T" are not considered vulnerable
logrus.Infof("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
logrus.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}

View File

@@ -3,6 +3,8 @@ package main
const fmt = "formatted %s string"
const text = "test"
func main() {
var v []byte
func main() {
stdlib()
}

View File

@@ -17,6 +17,11 @@ func stdlib() {
logger.Printf(fmt, text) // $ logger=fmt logger=text
logger.Println(text) // $ logger=text
// components corresponding to the format specifier "%T" are not considered vulnerable
logger.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
logger.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
logger.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
log.SetPrefix("prefix: ")
log.Fatal(text) // $ logger=text
log.Fatalf(fmt, text) // $ logger=fmt logger=text
@@ -27,4 +32,9 @@ func stdlib() {
log.Print(text) // $ logger=text
log.Printf(fmt, text) // $ logger=fmt logger=text
log.Println(text) // $ logger=text
// components corresponding to the format specifier "%T" are not considered vulnerable
log.Fatalf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
log.Panicf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
log.Printf("%s: found type %T", text, v) // $ logger="%s: found type %T" logger=text type-logger=v
}

View File

@@ -1,9 +1,57 @@
module test
go 1.22.5
go 1.24
require (
gorm.io/gorm v1.23.0
github.com/astaxie/beego v1.12.3
github.com/beego/beego/v2 v2.3.5
github.com/couchbase/gocb v1.6.7
github.com/couchbase/gocb/v2 v2.9.4
github.com/jmoiron/sqlx v1.4.0
go.mongodb.org/mongo-driver/mongo v1.17.2
github.com/rqlite/gorqlite v0.0.0-20250128004930-114c7828b55a
go.mongodb.org/mongo-driver v1.17.3
gorm.io/gorm v1.25.12
)
require (
github.com/couchbase/gocbcore/v10 v10.5.4 // indirect
github.com/couchbase/gocbcoreps v0.1.3 // indirect
github.com/couchbase/goprotostellar v1.0.2 // indirect
github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/text v0.17.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/couchbase/gocbcore.v7 v7.1.18 // indirect
gopkg.in/couchbaselabs/gocbconnstr.v1 v1.0.4 // indirect
gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.4 // indirect
gopkg.in/couchbaselabs/jsonx.v1 v1.0.1 // indirect
)

View File

@@ -1,5 +1,8 @@
package test
//go:generate depstubber -vendor github.com/astaxie/beego/orm Ormer NewOrm
//go:generate depstubber -vendor github.com/beego/beego/v2/client/orm DB,DQL,Ormer NewOrm
import (
oldOrm "github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"

View File

@@ -0,0 +1,57 @@
package test
//go:generate depstubber -vendor github.com/couchbase/gocb Cluster,AnalyticsResults,QueryResults,SearchResults
import "github.com/couchbase/gocb"
func test_couchbase_gocb_v1_Cluster(cluster *gocb.Cluster, aq *gocb.AnalyticsQuery, n1ql *gocb.N1qlQuery, sq *gocb.SearchQuery) {
// Analytics
r1, err := cluster.ExecuteAnalyticsQuery(aq, nil) // $ source
if err != nil {
return
}
var user1, user2 User
r1.One(&user1)
sink(user1) // $ hasTaintFlow="user1"
for r1.Next(user2) {
sink(user2) // $ hasTaintFlow="user2"
}
var b1 []byte
b1 = r1.NextBytes()
sink(b1) // $ hasTaintFlow="b1"
// N1QL
r2, err := cluster.ExecuteN1qlQuery(n1ql, nil) // $ source
if err != nil {
return
}
var user3, user4 User
r2.One(&user3)
sink(user3) // $ hasTaintFlow="user3"
for r2.Next(user4) {
sink(user4) // $ hasTaintFlow="user4"
}
var b2 []byte
b2 = r2.NextBytes()
sink(b2) // $ hasTaintFlow="b2"
// Search
r3, err := cluster.ExecuteSearchQuery(sq) // $ source
if err != nil {
return
}
hit := r3.Hits()[0]
sink(hit) // $ hasTaintFlow="hit"
}

View File

@@ -0,0 +1,247 @@
package test
//go:generate depstubber -vendor github.com/couchbase/gocb/v2 AnalyticsResult,AnalyticsResultRaw,Cluster,Collection,ExistsResult,GetResult,LookupInReplicaResult,LookupInResult,MutateInResult,MutationResult,QueryResult,QueryResultRaw,Result,ScanResult,ScanResultItem,Scope,SearchResult,SearchResultRaw,TransactionAttemptContext,TransactionGetResult,TransactionQueryResult,ViewIndexManager,ViewResult,ViewResultRaw
import "github.com/couchbase/gocb/v2"
func test_couchbase_gocb_v2_Cluster(cluster *gocb.Cluster) {
r1, err := cluster.AnalyticsQuery("SELECT * FROM `travel-sample`", nil) // $ source
if err != nil {
return
}
for r1.Next() {
var name1, name2 string
r1.One(&name1)
sink(name1) // $ hasTaintFlow="name1"
r1.Row(&name2)
sink(name2) // $ hasTaintFlow="name2"
b := r1.Raw().NextBytes()
sink(b) // $ hasTaintFlow="b"
}
r2, err := cluster.Query("SELECT * FROM `travel-sample`", nil) // $ source
if err != nil {
return
}
for r2.Next() {
var name1, name2 string
r2.One(&name1)
sink(name1) // $ hasTaintFlow="name1"
r2.Row(&name2)
sink(name2) // $ hasTaintFlow="name2"
b := r2.Raw().NextBytes()
sink(b) // $ hasTaintFlow="b"
}
}
func test_couchbase_gocb_v2_Scope(scope *gocb.Scope) {
r1, err := scope.AnalyticsQuery("SELECT * FROM `travel-sample`", nil) // $ source
if err != nil {
return
}
for r1.Next() {
var name1, name2 string
r1.One(&name1)
sink(name1) // $ hasTaintFlow="name1"
r1.Row(&name2)
sink(name2) // $ hasTaintFlow="name2"
b := r1.Raw().NextBytes()
sink(b) // $ hasTaintFlow="b"
}
r2, err := scope.Query("SELECT * FROM `travel-sample`", nil) // $ source
if err != nil {
return
}
for r2.Next() {
var name1, name2 string
r2.One(&name1)
sink(name1) // $ hasTaintFlow="name1"
r2.Row(&name2)
sink(name2) // $ hasTaintFlow="name2"
b := r2.Raw().NextBytes()
sink(b) // $ hasTaintFlow="b"
}
}
func test_couchbase_gocb_v2_Collection(coll *gocb.Collection) {
type User struct {
Name string
}
var user User
r1, err := coll.Get("documentID", nil) // $ source
if err != nil {
return
}
r1.Content(&user)
sink(user) // $ hasTaintFlow="user"
r2, err := coll.GetAndLock("documentID", 30, nil) // $ source
if err != nil {
return
}
sink(r2) // $ hasTaintFlow="r2"
r3, err := coll.GetAndTouch("documentID", 30, nil) // $ source
if err != nil {
return
}
var user3 User
r3.Content(&user3)
sink(user3) // $ hasTaintFlow="user3"
r4, err := coll.GetAnyReplica("documentID", nil) // $ source
if err != nil {
return
}
sink(r4) // $ hasTaintFlow="r4"
r5, err := coll.LookupIn("documentID", []gocb.LookupInSpec{}, nil) // $ source
if err != nil {
return
}
var user5 User
r5.ContentAt(0, &user5)
sink(user5) // $ hasTaintFlow="user5"
r6, err := coll.LookupInAllReplicas("documentID", []gocb.LookupInSpec{}, nil) // $ source
if err != nil {
return
}
var user6 User
r6.Next().ContentAt(0, &user6)
sink(user6) // $ hasTaintFlow="user6"
r7, err := coll.LookupInAnyReplica("documentID", []gocb.LookupInSpec{}, nil) // $ source
if err != nil {
return
}
var user7 User
r7.ContentAt(0, &user7)
sink(user7) // $ hasTaintFlow="user7"
r8, err := coll.Scan(nil, nil) // $ source
if err != nil {
return
}
var user8 User
r8.Next().Content(&user8)
sink(user8) // $ hasTaintFlow="user8"
}
func test_couchbase_gocb_v2_TransactionAttemptContext(tam *gocb.TransactionAttemptContext, coll *gocb.Collection) {
r1, err := tam.Get(coll, "documentID") // $ source
if err != nil {
return
}
var user User
r1.Content(&user)
sink(user) // $ hasTaintFlow="user"
r2, err := tam.GetReplicaFromPreferredServerGroup(coll, "documentID") // $ source
if err != nil {
return
}
var user2 User
r2.Content(&user2)
sink(user2) // $ hasTaintFlow="user2"
var user3 User
r3, err := tam.Insert(coll, "documentID", &user3) // $ source
if err != nil {
return
}
var user4 User
r3.Content(&user4)
sink(user4) // $ hasTaintFlow="user4"
r4, err := tam.Query("SELECT * FROM `travel-sample`", nil) // $ source
if err != nil {
return
}
for r4.Next() {
var user5 User
r4.One(&user5)
sink(user5) // $ hasTaintFlow="user5"
var user6 User
r4.Row(&user6)
sink(user6) // $ hasTaintFlow="user6"
}
r5, err := tam.Replace(r3, user4) // $ source
if err != nil {
return
}
sink(r5) // $ hasTaintFlow="r5"
}
func test_couchbase_gocb_v2_ViewIndexManager(v *gocb.ViewIndexManager) {
doc, err := v.GetDesignDocument("name", 0, nil) // $ source
if err != nil {
return
}
sink(doc) // $ hasTaintFlow="doc"
docs, err := v.GetAllDesignDocuments(0, nil) // $ source
if err != nil {
return
}
sink(docs) // $ hasTaintFlow="docs"
}

View File

@@ -1,5 +1,7 @@
package test
//go:generate depstubber -vendor gorm.io/gorm Association,ConnPool,DB
import "gorm.io/gorm"
// test querying an Association

View File

@@ -1,5 +1,7 @@
package test
//go:generate depstubber -vendor github.com/jmoiron/sqlx Conn,DB,NamedStmt,Stmt,Tx Get,GetContext,NamedQuery,NamedQueryContext,Select,SelectContext
import (
"context"

View File

@@ -2,7 +2,7 @@
// This is a simple stub for github.com/beego/beego/v2/client/orm, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/beego/beego/v2/client/orm (exports: DQL,DB,Ormer; functions: NewOrm)
// Source: github.com/beego/beego/v2/client/orm (exports: DB,DQL,Ormer; functions: NewOrm)
// Package orm is a stub of github.com/beego/beego/v2/client/orm, generated by depstubber.
package orm
@@ -56,30 +56,10 @@ func (_ *Condition) OrNotCond(_ *Condition) *Condition {
}
type DB struct {
RWMutex *sync.RWMutex
DB *sql.DB
*sync.RWMutex
DB *sql.DB
}
func (_ DB) Lock() {}
func (_ DB) RLock() {}
func (_ DB) RLocker() sync.Locker {
return nil
}
func (_ DB) RUnlock() {}
func (_ DB) TryLock() bool {
return false
}
func (_ DB) TryRLock() bool {
return false
}
func (_ DB) Unlock() {}
func (_ *DB) Begin() (*sql.Tx, error) {
return nil, nil
}

View File

@@ -1,26 +0,0 @@
package sqlx
import (
"context"
"database/sql"
)
type Conn struct {
*sql.Conn
}
func (c *Conn) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
return nil
}
func (c *Conn) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
return nil
}
func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
return nil
}
func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
return nil, nil
}

View File

@@ -1,52 +0,0 @@
package sqlx
import (
"context"
"database/sql"
)
type DB struct {
*sql.DB
// Mapper *reflectx.Mapper
}
func (db *DB) Get(dest interface{}, query string, args ...interface{}) error {
return nil
}
func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
return nil
}
func (db *DB) QueryRowx(query string, args ...interface{}) *Row {
return nil
}
func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
return nil
}
func (db *DB) Queryx(query string, args ...interface{}) (*Rows, error) {
return nil, nil
}
func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
return nil, nil
}
func (db *DB) Select(dest interface{}, query string, args ...interface{}) error {
return nil
}
func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
return nil
}
func (db *DB) NamedQuery(query string, arg interface{}) (*Rows, error) {
return nil, nil
}
func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) {
return nil, nil
}

View File

@@ -1,60 +0,0 @@
package sqlx
import (
"context"
"database/sql"
)
type NamedStmt struct {
Params []string
QueryString string
Stmt *sql.Stmt
}
func (s *NamedStmt) Get(dest interface{}, args ...interface{}) error {
return nil
}
func (s *NamedStmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
return nil
}
func (s *NamedStmt) QueryRow(args ...interface{}) *Row {
return nil
}
func (s *NamedStmt) QueryRowContext(ctx context.Context, args ...interface{}) *Row {
return nil
}
func (s *NamedStmt) Query(args ...interface{}) (*Rows, error) {
return nil, nil
}
func (s *NamedStmt) QueryContext(ctx context.Context, args ...interface{}) (*Rows, error) {
return nil, nil
}
func (s *NamedStmt) QueryRowx(args ...interface{}) *Row {
return nil
}
func (s *NamedStmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
return nil
}
func (s *NamedStmt) Queryx(args ...interface{}) (*Rows, error) {
return nil, nil
}
func (s *NamedStmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
return nil, nil
}
func (s *NamedStmt) Select(dest interface{}, args ...interface{}) error {
return nil
}
func (s *NamedStmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
return nil
}

View File

@@ -1,21 +0,0 @@
package sqlx
type Row struct {
// Mapper *reflectx.Mapper
}
func (r *Row) MapScan(dest map[string]interface{}) error {
return nil
}
func (r *Row) StructScan(dest interface{}) error {
return nil
}
func (r *Row) SliceScan(dest []interface{}) error {
return nil
}
func (r *Row) Scan(dest ...interface{}) error {
return nil
}

View File

@@ -1,22 +0,0 @@
package sqlx
import "database/sql"
type Rows struct {
*sql.Rows
// Mapper *reflectx.Mapper
// contains filtered or unexported fields
}
func (r *Rows) MapScan(dest map[string]interface{}) error {
return nil
}
func (r *Rows) StructScan(dest interface{}) error {
return nil
}
func (r *Rows) SliceScan(dest []interface{}) error {
return nil
}

View File

@@ -1,42 +0,0 @@
package sqlx
import (
"context"
"database/sql"
)
type Stmt struct {
*sql.Stmt
}
func (s *Stmt) Get(dest interface{}, args ...interface{}) error {
return nil
}
func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
return nil
}
func (s *Stmt) QueryRowx(args ...interface{}) *Row {
return nil
}
func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
return nil
}
func (s *Stmt) Queryx(args ...interface{}) (*Rows, error) {
return nil, nil
}
func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
return nil, nil
}
func (s *Stmt) Select(dest interface{}, args ...interface{}) error {
return nil
}
func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
return nil
}

View File

@@ -1,67 +1,530 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for github.com/jmoiron/sqlx, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: github.com/jmoiron/sqlx (exports: Conn,DB,NamedStmt,Stmt,Tx; functions: Get,GetContext,NamedQuery,NamedQueryContext,Select,SelectContext)
// Package sqlx is a stub of github.com/jmoiron/sqlx, generated by depstubber.
package sqlx
import (
"context"
"database/sql"
context "context"
sql "database/sql"
)
type ColScanner interface {
Columns() ([]string, error)
Scan(dest ...interface{}) error
Err() error
type Conn struct {
*sql.Conn
Mapper interface{}
}
type Execer interface {
Exec(query string, args ...interface{}) (sql.Result, error)
func (_ Conn) BeginTx(_ context.Context, _ *sql.TxOptions) (*sql.Tx, error) {
return nil, nil
}
type ExecerContext interface {
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
func (_ Conn) Close() error {
return nil
}
func (_ Conn) ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error) {
return nil, nil
}
func (_ Conn) PingContext(_ context.Context) error {
return nil
}
func (_ Conn) PrepareContext(_ context.Context, _ string) (*sql.Stmt, error) {
return nil, nil
}
func (_ Conn) QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error) {
return nil, nil
}
func (_ Conn) QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row {
return nil
}
func (_ Conn) Raw(_ func(interface{}) error) error {
return nil
}
func (_ *Conn) BeginTxx(_ context.Context, _ *sql.TxOptions) (*Tx, error) {
return nil, nil
}
func (_ *Conn) GetContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *Conn) PreparexContext(_ context.Context, _ string) (*Stmt, error) {
return nil, nil
}
func (_ *Conn) QueryRowxContext(_ context.Context, _ string, _ ...interface{}) *Row {
return nil
}
func (_ *Conn) QueryxContext(_ context.Context, _ string, _ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *Conn) Rebind(_ string) string {
return ""
}
func (_ *Conn) SelectContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
type DB struct {
*sql.DB
Mapper interface{}
}
func (_ *DB) BeginTxx(_ context.Context, _ *sql.TxOptions) (*Tx, error) {
return nil, nil
}
func (_ *DB) Beginx() (*Tx, error) {
return nil, nil
}
func (_ *DB) BindNamed(_ string, _ interface{}) (string, []interface{}, error) {
return "", nil, nil
}
func (_ *DB) Connx(_ context.Context) (*Conn, error) {
return nil, nil
}
func (_ *DB) DriverName() string {
return ""
}
func (_ *DB) Get(_ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *DB) GetContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *DB) MapperFunc(_ func(string) string) {}
func (_ *DB) MustBegin() *Tx {
return nil
}
func (_ *DB) MustBeginTx(_ context.Context, _ *sql.TxOptions) *Tx {
return nil
}
func (_ *DB) MustExec(_ string, _ ...interface{}) sql.Result {
return nil
}
func (_ *DB) MustExecContext(_ context.Context, _ string, _ ...interface{}) sql.Result {
return nil
}
func (_ *DB) NamedExec(_ string, _ interface{}) (sql.Result, error) {
return nil, nil
}
func (_ *DB) NamedExecContext(_ context.Context, _ string, _ interface{}) (sql.Result, error) {
return nil, nil
}
func (_ *DB) NamedQuery(_ string, _ interface{}) (*Rows, error) {
return nil, nil
}
func (_ *DB) NamedQueryContext(_ context.Context, _ string, _ interface{}) (*Rows, error) {
return nil, nil
}
func (_ *DB) PrepareNamed(_ string) (*NamedStmt, error) {
return nil, nil
}
func (_ *DB) PrepareNamedContext(_ context.Context, _ string) (*NamedStmt, error) {
return nil, nil
}
func (_ *DB) Preparex(_ string) (*Stmt, error) {
return nil, nil
}
func (_ *DB) PreparexContext(_ context.Context, _ string) (*Stmt, error) {
return nil, nil
}
func (_ *DB) QueryRowx(_ string, _ ...interface{}) *Row {
return nil
}
func (_ *DB) QueryRowxContext(_ context.Context, _ string, _ ...interface{}) *Row {
return nil
}
func (_ *DB) Queryx(_ string, _ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *DB) QueryxContext(_ context.Context, _ string, _ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *DB) Rebind(_ string) string {
return ""
}
func (_ *DB) Select(_ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *DB) SelectContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *DB) Unsafe() *DB {
return nil
}
type Ext interface {
Queryer
Execer
BindNamed(_ string, _ interface{}) (string, []interface{}, error)
DriverName() string
Exec(_ string, _ ...interface{}) (sql.Result, error)
Query(_ string, _ ...interface{}) (*sql.Rows, error)
QueryRowx(_ string, _ ...interface{}) *Row
Queryx(_ string, _ ...interface{}) (*Rows, error)
Rebind(_ string) string
}
type ExtContext interface {
QueryerContext
ExecerContext
// contains filtered or unexported methods
BindNamed(_ string, _ interface{}) (string, []interface{}, error)
DriverName() string
ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error)
QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error)
QueryRowxContext(_ context.Context, _ string, _ ...interface{}) *Row
QueryxContext(_ context.Context, _ string, _ ...interface{}) (*Rows, error)
Rebind(_ string) string
}
func Get(_ Queryer, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func GetContext(_ context.Context, _ QueryerContext, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func NamedQuery(_ Ext, _ string, _ interface{}) (*Rows, error) {
return nil, nil
}
func NamedQueryContext(_ context.Context, _ ExtContext, _ string, _ interface{}) (*Rows, error) {
return nil, nil
}
type NamedStmt struct {
Params []string
QueryString string
Stmt *Stmt
}
func (_ *NamedStmt) Close() error {
return nil
}
func (_ *NamedStmt) Exec(_ interface{}) (sql.Result, error) {
return nil, nil
}
func (_ *NamedStmt) ExecContext(_ context.Context, _ interface{}) (sql.Result, error) {
return nil, nil
}
func (_ *NamedStmt) Get(_ interface{}, _ interface{}) error {
return nil
}
func (_ *NamedStmt) GetContext(_ context.Context, _ interface{}, _ interface{}) error {
return nil
}
func (_ *NamedStmt) MustExec(_ interface{}) sql.Result {
return nil
}
func (_ *NamedStmt) MustExecContext(_ context.Context, _ interface{}) sql.Result {
return nil
}
func (_ *NamedStmt) Query(_ interface{}) (*sql.Rows, error) {
return nil, nil
}
func (_ *NamedStmt) QueryContext(_ context.Context, _ interface{}) (*sql.Rows, error) {
return nil, nil
}
func (_ *NamedStmt) QueryRow(_ interface{}) *Row {
return nil
}
func (_ *NamedStmt) QueryRowContext(_ context.Context, _ interface{}) *Row {
return nil
}
func (_ *NamedStmt) QueryRowx(_ interface{}) *Row {
return nil
}
func (_ *NamedStmt) QueryRowxContext(_ context.Context, _ interface{}) *Row {
return nil
}
func (_ *NamedStmt) Queryx(_ interface{}) (*Rows, error) {
return nil, nil
}
func (_ *NamedStmt) QueryxContext(_ context.Context, _ interface{}) (*Rows, error) {
return nil, nil
}
func (_ *NamedStmt) Select(_ interface{}, _ interface{}) error {
return nil
}
func (_ *NamedStmt) SelectContext(_ context.Context, _ interface{}, _ interface{}) error {
return nil
}
func (_ *NamedStmt) Unsafe() *NamedStmt {
return nil
}
type Queryer interface {
Query(query string, args ...interface{}) (*sql.Rows, error)
Queryx(query string, args ...interface{}) (*Rows, error)
QueryRowx(query string, args ...interface{}) *Row
Query(_ string, _ ...interface{}) (*sql.Rows, error)
QueryRowx(_ string, _ ...interface{}) *Row
Queryx(_ string, _ ...interface{}) (*Rows, error)
}
type QueryerContext interface {
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row
QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error)
QueryRowxContext(_ context.Context, _ string, _ ...interface{}) *Row
QueryxContext(_ context.Context, _ string, _ ...interface{}) (*Rows, error)
}
func NamedQuery(e Ext, query string, arg interface{}) (*Rows, error) {
return e.Queryx(query, arg)
type Row struct {
Mapper interface{}
}
func NamedQueryContext(ctx context.Context, e ExtContext, query string, arg interface{}) (*Rows, error) {
return e.QueryxContext(ctx, query, arg)
func (_ *Row) ColumnTypes() ([]*sql.ColumnType, error) {
return nil, nil
}
func Get(q Queryer, dest interface{}, query string, args ...interface{}) error {
func (_ *Row) Columns() ([]string, error) {
return nil, nil
}
func (_ *Row) Err() error {
return nil
}
func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
func (_ *Row) MapScan(_ map[string]interface{}) error {
return nil
}
func Select(q Queryer, dest interface{}, query string, args ...interface{}) error {
func (_ *Row) Scan(_ ...interface{}) error {
return nil
}
func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
func (_ *Row) SliceScan() ([]interface{}, error) {
return nil, nil
}
func (_ *Row) StructScan(_ interface{}) error {
return nil
}
type Rows struct {
*sql.Rows
Mapper interface{}
}
func (_ *Rows) MapScan(_ map[string]interface{}) error {
return nil
}
func (_ *Rows) SliceScan() ([]interface{}, error) {
return nil, nil
}
func (_ *Rows) StructScan(_ interface{}) error {
return nil
}
func Select(_ Queryer, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func SelectContext(_ context.Context, _ QueryerContext, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
type Stmt struct {
*sql.Stmt
Mapper interface{}
}
func (_ *Stmt) Get(_ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Stmt) GetContext(_ context.Context, _ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Stmt) MustExec(_ ...interface{}) sql.Result {
return nil
}
func (_ *Stmt) MustExecContext(_ context.Context, _ ...interface{}) sql.Result {
return nil
}
func (_ *Stmt) QueryRowx(_ ...interface{}) *Row {
return nil
}
func (_ *Stmt) QueryRowxContext(_ context.Context, _ ...interface{}) *Row {
return nil
}
func (_ *Stmt) Queryx(_ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *Stmt) QueryxContext(_ context.Context, _ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *Stmt) Select(_ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Stmt) SelectContext(_ context.Context, _ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Stmt) Unsafe() *Stmt {
return nil
}
type Tx struct {
*sql.Tx
Mapper interface{}
}
func (_ *Tx) BindNamed(_ string, _ interface{}) (string, []interface{}, error) {
return "", nil, nil
}
func (_ *Tx) DriverName() string {
return ""
}
func (_ *Tx) Get(_ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *Tx) GetContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *Tx) MustExec(_ string, _ ...interface{}) sql.Result {
return nil
}
func (_ *Tx) MustExecContext(_ context.Context, _ string, _ ...interface{}) sql.Result {
return nil
}
func (_ *Tx) NamedExec(_ string, _ interface{}) (sql.Result, error) {
return nil, nil
}
func (_ *Tx) NamedExecContext(_ context.Context, _ string, _ interface{}) (sql.Result, error) {
return nil, nil
}
func (_ *Tx) NamedQuery(_ string, _ interface{}) (*Rows, error) {
return nil, nil
}
func (_ *Tx) NamedStmt(_ *NamedStmt) *NamedStmt {
return nil
}
func (_ *Tx) NamedStmtContext(_ context.Context, _ *NamedStmt) *NamedStmt {
return nil
}
func (_ *Tx) PrepareNamed(_ string) (*NamedStmt, error) {
return nil, nil
}
func (_ *Tx) PrepareNamedContext(_ context.Context, _ string) (*NamedStmt, error) {
return nil, nil
}
func (_ *Tx) Preparex(_ string) (*Stmt, error) {
return nil, nil
}
func (_ *Tx) PreparexContext(_ context.Context, _ string) (*Stmt, error) {
return nil, nil
}
func (_ *Tx) QueryRowx(_ string, _ ...interface{}) *Row {
return nil
}
func (_ *Tx) QueryRowxContext(_ context.Context, _ string, _ ...interface{}) *Row {
return nil
}
func (_ *Tx) Queryx(_ string, _ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *Tx) QueryxContext(_ context.Context, _ string, _ ...interface{}) (*Rows, error) {
return nil, nil
}
func (_ *Tx) Rebind(_ string) string {
return ""
}
func (_ *Tx) Select(_ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *Tx) SelectContext(_ context.Context, _ interface{}, _ string, _ ...interface{}) error {
return nil
}
func (_ *Tx) Stmtx(_ interface{}) *Stmt {
return nil
}
func (_ *Tx) StmtxContext(_ context.Context, _ interface{}) *Stmt {
return nil
}
func (_ *Tx) Unsafe() *Tx {
return nil
}

View File

@@ -1,47 +0,0 @@
package sqlx
import (
"context"
"database/sql"
)
type Tx struct {
*sql.Tx
}
func (tx *Tx) Get(dest interface{}, args ...interface{}) error {
return nil
}
func (tx *Tx) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
return nil
}
func (tx *Tx) QueryRowx(args ...interface{}) *Row {
return nil
}
func (tx *Tx) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
return nil
}
func (tx *Tx) Queryx(args ...interface{}) (*Rows, error) {
return nil, nil
}
func (tx *Tx) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
return nil, nil
}
func (tx *Tx) Select(dest interface{}, args ...interface{}) error {
return nil
}
func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
return nil
}
func (tx *Tx) NamedQuery(query string, arg interface{}) (*Rows, error) {
return nil, nil
}

View File

@@ -1,77 +1,878 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for gorm.io/gorm, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: gorm.io/gorm (exports: Association,ConnPool,DB; functions: )
// Package gorm is a stub of gorm.io/gorm, generated by depstubber.
package gorm
import (
"context"
"database/sql"
context "context"
sql "database/sql"
reflect "reflect"
strings "strings"
sync "sync"
time "time"
)
type DB struct{}
func (db *DB) Find(dest interface{}, conds ...interface{}) *DB {
return db
}
func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB {
return db
}
func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) *DB {
return db
}
func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) *DB {
return db
}
func (db *DB) First(dest interface{}, conds ...interface{}) *DB {
return db
}
func (db *DB) Model(value interface{}) *DB {
return db
}
func (db *DB) Last(dest interface{}, conds ...interface{}) *DB {
return db
}
func (db *DB) Pluck(column string, dest interface{}) *DB {
return db
}
func (db *DB) Take(dest interface{}, conds ...interface{}) *DB {
return db
}
func (db *DB) Scan(dest interface{}) *DB {
return db
}
func (db *DB) ScanRows(rows *sql.Rows, result interface{}) error {
return nil
}
func (db *DB) Row() *sql.Row {
return nil
}
func (db *DB) Rows() (*sql.Rows, error) {
return nil, nil
}
type Association struct {
DB *DB
DB *DB
Relationship interface{}
Unscope bool
Error error
}
func (a *Association) Find(dest interface{}) *Association {
return a
func (_ *Association) Append(_ ...interface{}) error {
return nil
}
func (_ *Association) Clear() error {
return nil
}
func (_ *Association) Count() int64 {
return 0
}
func (_ *Association) Delete(_ ...interface{}) error {
return nil
}
func (_ *Association) Find(_ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Association) Replace(_ ...interface{}) error {
return nil
}
func (_ *Association) Unscoped() *Association {
return nil
}
type ColumnType interface {
AutoIncrement() (bool, bool)
ColumnType() (string, bool)
Comment() (string, bool)
DatabaseTypeName() string
DecimalSize() (int64, int64, bool)
DefaultValue() (string, bool)
Length() (int64, bool)
Name() string
Nullable() (bool, bool)
PrimaryKey() (bool, bool)
ScanType() reflect.Type
Unique() (bool, bool)
}
type Config struct {
SkipDefaultTransaction bool
NamingStrategy interface{}
FullSaveAssociations bool
Logger interface{}
NowFunc func() time.Time
DryRun bool
PrepareStmt bool
DisableAutomaticPing bool
DisableForeignKeyConstraintWhenMigrating bool
IgnoreRelationshipsWhenMigrating bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
QueryFields bool
CreateBatchSize int
TranslateError bool
PropagateUnscoped bool
ClauseBuilders map[string]interface{}
ConnPool ConnPool
Dialector
Plugins map[string]Plugin
}
func (_ Config) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ Config) DataTypeOf(_ interface{}) string {
return ""
}
func (_ Config) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ Config) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ Config) Initialize(_ *DB) error {
return nil
}
func (_ Config) Migrator(_ *DB) Migrator {
return nil
}
func (_ Config) Name() string {
return ""
}
func (_ Config) QuoteTo(_ interface{}, _ string) {}
func (_ *Config) AfterInitialize(_ *DB) error {
return nil
}
func (_ *Config) Apply(_ *Config) error {
return nil
}
type ConnPool interface {
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error)
PrepareContext(_ context.Context, _ string) (*sql.Stmt, error)
QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error)
QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row
}
type Model interface{}
type DB struct {
*Config
Error error
RowsAffected int64
Statement *Statement
}
func (_ DB) AfterInitialize(_ *DB) error {
return nil
}
func (_ DB) Apply(_ *Config) error {
return nil
}
func (_ DB) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ DB) DataTypeOf(_ interface{}) string {
return ""
}
func (_ DB) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ DB) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ DB) Initialize(_ *DB) error {
return nil
}
func (_ DB) Name() string {
return ""
}
func (_ DB) QuoteTo(_ interface{}, _ string) {}
func (_ *DB) AddError(_ error) error {
return nil
}
func (_ *DB) Assign(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Association(_ string) *Association {
return nil
}
func (_ *DB) Attrs(_ ...interface{}) *DB {
return nil
}
func (_ *DB) AutoMigrate(_ ...interface{}) error {
return nil
}
func (_ *DB) Begin(_ ...*sql.TxOptions) *DB {
return nil
}
func (_ *DB) Callback() interface{} {
return nil
}
func (_ *DB) Clauses(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Commit() *DB {
return nil
}
func (_ *DB) Connection(_ func(*DB) error) error {
return nil
}
func (_ *DB) Count(_ *int64) *DB {
return nil
}
func (_ *DB) Create(_ interface{}) *DB {
return nil
}
func (_ *DB) CreateInBatches(_ interface{}, _ int) *DB {
return nil
}
func (_ *DB) DB() (*sql.DB, error) {
return nil, nil
}
func (_ *DB) Debug() *DB {
return nil
}
func (_ *DB) Delete(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Distinct(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Exec(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Find(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB {
return nil
}
func (_ *DB) First(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FirstOrCreate(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FirstOrInit(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ *DB) Group(_ string) *DB {
return nil
}
func (_ *DB) Having(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) InnerJoins(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) InstanceGet(_ string) (interface{}, bool) {
return nil, false
}
func (_ *DB) InstanceSet(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) Joins(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Last(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Limit(_ int) *DB {
return nil
}
func (_ *DB) MapColumns(_ map[string]string) *DB {
return nil
}
func (_ *DB) Migrator() Migrator {
return nil
}
func (_ *DB) Model(_ interface{}) *DB {
return nil
}
func (_ *DB) Not(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Offset(_ int) *DB {
return nil
}
func (_ *DB) Omit(_ ...string) *DB {
return nil
}
func (_ *DB) Or(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Order(_ interface{}) *DB {
return nil
}
func (_ *DB) Pluck(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) Preload(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Raw(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Rollback() *DB {
return nil
}
func (_ *DB) RollbackTo(_ string) *DB {
return nil
}
func (_ *DB) Row() *sql.Row {
return nil
}
func (_ *DB) Rows() (*sql.Rows, error) {
return nil, nil
}
func (_ *DB) Save(_ interface{}) *DB {
return nil
}
func (_ *DB) SavePoint(_ string) *DB {
return nil
}
func (_ *DB) Scan(_ interface{}) *DB {
return nil
}
func (_ *DB) ScanRows(_ *sql.Rows, _ interface{}) error {
return nil
}
func (_ *DB) Scopes(_ ...func(*DB) *DB) *DB {
return nil
}
func (_ *DB) Select(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Session(_ *Session) *DB {
return nil
}
func (_ *DB) Set(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) SetupJoinTable(_ interface{}, _ string, _ interface{}) error {
return nil
}
func (_ *DB) Table(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Take(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) ToSQL(_ func(*DB) *DB) string {
return ""
}
func (_ *DB) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error {
return nil
}
func (_ *DB) Unscoped() *DB {
return nil
}
func (_ *DB) Update(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) UpdateColumn(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) UpdateColumns(_ interface{}) *DB {
return nil
}
func (_ *DB) Updates(_ interface{}) *DB {
return nil
}
func (_ *DB) Use(_ Plugin) error {
return nil
}
func (_ *DB) Where(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) WithContext(_ context.Context) *DB {
return nil
}
type Dialector interface {
BindVarTo(_ interface{}, _ *Statement, _ interface{})
DataTypeOf(_ interface{}) string
DefaultValueOf(_ interface{}) interface{}
Explain(_ string, _ ...interface{}) string
Initialize(_ *DB) error
Migrator(_ *DB) Migrator
Name() string
QuoteTo(_ interface{}, _ string)
}
type Index interface {
Columns() []string
Name() string
Option() string
PrimaryKey() (bool, bool)
Table() string
Unique() (bool, bool)
}
type Migrator interface {
AddColumn(_ interface{}, _ string) error
AlterColumn(_ interface{}, _ string) error
AutoMigrate(_ ...interface{}) error
ColumnTypes(_ interface{}) ([]ColumnType, error)
CreateConstraint(_ interface{}, _ string) error
CreateIndex(_ interface{}, _ string) error
CreateTable(_ ...interface{}) error
CreateView(_ string, _ ViewOption) error
CurrentDatabase() string
DropColumn(_ interface{}, _ string) error
DropConstraint(_ interface{}, _ string) error
DropIndex(_ interface{}, _ string) error
DropTable(_ ...interface{}) error
DropView(_ string) error
FullDataTypeOf(_ interface{}) interface{}
GetIndexes(_ interface{}) ([]Index, error)
GetTables() ([]string, error)
GetTypeAliases(_ string) []string
HasColumn(_ interface{}, _ string) bool
HasConstraint(_ interface{}, _ string) bool
HasIndex(_ interface{}, _ string) bool
HasTable(_ interface{}) bool
MigrateColumn(_ interface{}, _ interface{}, _ ColumnType) error
MigrateColumnUnique(_ interface{}, _ interface{}, _ ColumnType) error
RenameColumn(_ interface{}, _ string, _ string) error
RenameIndex(_ interface{}, _ string, _ string) error
RenameTable(_ interface{}, _ interface{}) error
TableType(_ interface{}) (TableType, error)
}
type Plugin interface {
Initialize(_ *DB) error
Name() string
}
type Session struct {
DryRun bool
PrepareStmt bool
NewDB bool
Initialized bool
SkipHooks bool
SkipDefaultTransaction bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
FullSaveAssociations bool
PropagateUnscoped bool
QueryFields bool
Context context.Context
Logger interface{}
NowFunc func() time.Time
CreateBatchSize int
}
type Statement struct {
*DB
TableExpr interface{}
Table string
Model interface{}
Unscoped bool
Dest interface{}
ReflectValue reflect.Value
Clauses map[string]interface{}
BuildClauses []string
Distinct bool
Selects []string
Omits []string
ColumnMapping map[string]string
Joins []interface{}
Preloads map[string][]interface{}
Settings sync.Map
ConnPool ConnPool
Schema interface{}
Context context.Context
RaiseErrorOnNotFound bool
SkipHooks bool
SQL strings.Builder
Vars []interface{}
CurDestIndex int
}
func (_ Statement) AddError(_ error) error {
return nil
}
func (_ Statement) AfterInitialize(_ *DB) error {
return nil
}
func (_ Statement) Apply(_ *Config) error {
return nil
}
func (_ Statement) Assign(_ ...interface{}) *DB {
return nil
}
func (_ Statement) Association(_ string) *Association {
return nil
}
func (_ Statement) Attrs(_ ...interface{}) *DB {
return nil
}
func (_ Statement) AutoMigrate(_ ...interface{}) error {
return nil
}
func (_ Statement) Begin(_ ...*sql.TxOptions) *DB {
return nil
}
func (_ Statement) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ Statement) Callback() interface{} {
return nil
}
func (_ Statement) Commit() *DB {
return nil
}
func (_ Statement) Connection(_ func(*DB) error) error {
return nil
}
func (_ Statement) Count(_ *int64) *DB {
return nil
}
func (_ Statement) Create(_ interface{}) *DB {
return nil
}
func (_ Statement) CreateInBatches(_ interface{}, _ int) *DB {
return nil
}
func (_ Statement) DataTypeOf(_ interface{}) string {
return ""
}
func (_ Statement) Debug() *DB {
return nil
}
func (_ Statement) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ Statement) Delete(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Exec(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ Statement) Find(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB {
return nil
}
func (_ Statement) First(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FirstOrCreate(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FirstOrInit(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ Statement) Group(_ string) *DB {
return nil
}
func (_ Statement) Having(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Initialize(_ *DB) error {
return nil
}
func (_ Statement) InnerJoins(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) InstanceGet(_ string) (interface{}, bool) {
return nil, false
}
func (_ Statement) InstanceSet(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) Last(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Limit(_ int) *DB {
return nil
}
func (_ Statement) MapColumns(_ map[string]string) *DB {
return nil
}
func (_ Statement) Migrator() Migrator {
return nil
}
func (_ Statement) Name() string {
return ""
}
func (_ Statement) Not(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Offset(_ int) *DB {
return nil
}
func (_ Statement) Omit(_ ...string) *DB {
return nil
}
func (_ Statement) Or(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Order(_ interface{}) *DB {
return nil
}
func (_ Statement) Pluck(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) Preload(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Raw(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Rollback() *DB {
return nil
}
func (_ Statement) RollbackTo(_ string) *DB {
return nil
}
func (_ Statement) Row() *sql.Row {
return nil
}
func (_ Statement) Rows() (*sql.Rows, error) {
return nil, nil
}
func (_ Statement) Save(_ interface{}) *DB {
return nil
}
func (_ Statement) SavePoint(_ string) *DB {
return nil
}
func (_ Statement) Scan(_ interface{}) *DB {
return nil
}
func (_ Statement) ScanRows(_ *sql.Rows, _ interface{}) error {
return nil
}
func (_ Statement) Scopes(_ ...func(*DB) *DB) *DB {
return nil
}
func (_ Statement) Select(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Session(_ *Session) *DB {
return nil
}
func (_ Statement) Set(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) SetupJoinTable(_ interface{}, _ string, _ interface{}) error {
return nil
}
func (_ Statement) Take(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) ToSQL(_ func(*DB) *DB) string {
return ""
}
func (_ Statement) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error {
return nil
}
func (_ Statement) Update(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) UpdateColumn(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) UpdateColumns(_ interface{}) *DB {
return nil
}
func (_ Statement) Updates(_ interface{}) *DB {
return nil
}
func (_ Statement) Use(_ Plugin) error {
return nil
}
func (_ Statement) Where(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) WithContext(_ context.Context) *DB {
return nil
}
func (_ *Statement) AddClause(_ interface{}) {}
func (_ *Statement) AddClauseIfNotExists(_ interface{}) {}
func (_ *Statement) AddVar(_ interface{}, _ ...interface{}) {}
func (_ *Statement) Build(_ ...string) {}
func (_ *Statement) BuildCondition(_ interface{}, _ ...interface{}) []interface{} {
return nil
}
func (_ *Statement) Changed(_ ...string) bool {
return false
}
func (_ *Statement) Parse(_ interface{}) error {
return nil
}
func (_ *Statement) ParseWithSpecialTableName(_ interface{}, _ string) error {
return nil
}
func (_ *Statement) Quote(_ interface{}) string {
return ""
}
func (_ *Statement) QuoteTo(_ interface{}, _ interface{}) {}
func (_ *Statement) SelectAndOmitColumns(_ bool, _ bool) (map[string]bool, bool) {
return nil, false
}
func (_ *Statement) SetColumn(_ string, _ interface{}, _ ...bool) {}
func (_ *Statement) WriteByte(_ byte) error {
return nil
}
func (_ *Statement) WriteQuoted(_ interface{}) {}
func (_ *Statement) WriteString(_ string) (int, error) {
return 0, nil
}
type TableType interface {
Comment() (string, bool)
Name() string
Schema() string
Type() string
}
type ViewOption struct {
Replace bool
CheckOption string
Query *DB
}

View File

@@ -1,9 +1,144 @@
# gorm.io/gorm v1.23.0
# github.com/astaxie/beego v1.12.3
## explicit
gorm.io/gorm
github.com/astaxie/beego/orm
# github.com/beego/beego/v2 v2.3.5
## explicit
github.com/beego/beego/v2/client/orm
# github.com/couchbase/gocb v1.6.7
## explicit
github.com/couchbase/gocb
# github.com/couchbase/gocb/v2 v2.9.4
## explicit
github.com/couchbase/gocb/v2
# github.com/jmoiron/sqlx v1.4.0
## explicit
github.com/jmoiron/sqlx
# go.mongodb.org/mongo-driver/mongo v1.17.2
# github.com/rqlite/gorqlite v0.0.0-20250128004930-114c7828b55a
## explicit
github.com/rqlite/gorqlite
# go.mongodb.org/mongo-driver v1.17.3
## explicit
go.mongodb.org/mongo-driver/mongo
# gorm.io/gorm v1.25.12
## explicit
gorm.io/gorm
# github.com/couchbase/gocbcore/v10 v10.5.4
## explicit
github.com/couchbase/gocbcore/v10
# github.com/couchbase/gocbcoreps v0.1.3
## explicit
github.com/couchbase/gocbcoreps
# github.com/couchbase/goprotostellar v1.0.2
## explicit
github.com/couchbase/goprotostellar
# github.com/couchbaselabs/gocbconnstr/v2 v2.0.0-20240607131231-fb385523de28
## explicit
github.com/couchbaselabs/gocbconnstr/v2
# github.com/go-logr/logr v1.4.1
## explicit
github.com/go-logr/logr
# github.com/go-logr/stdr v1.2.2
## explicit
github.com/go-logr/stdr
# github.com/golang/snappy v0.0.4
## explicit
github.com/golang/snappy
# github.com/google/uuid v1.6.0
## explicit
github.com/google/uuid
# github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
## explicit
github.com/grpc-ecosystem/go-grpc-middleware
# github.com/hashicorp/golang-lru v0.5.4
## explicit
github.com/hashicorp/golang-lru
# github.com/jinzhu/inflection v1.0.0
## explicit
github.com/jinzhu/inflection
# github.com/jinzhu/now v1.1.5
## explicit
github.com/jinzhu/now
# github.com/klauspost/compress v1.16.7
## explicit
github.com/klauspost/compress
# github.com/montanaflynn/stats v0.7.1
## explicit
github.com/montanaflynn/stats
# github.com/opentracing/opentracing-go v1.2.0
## explicit
github.com/opentracing/opentracing-go
# github.com/pkg/errors v0.9.1
## explicit
github.com/pkg/errors
# github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18
## explicit
github.com/shiena/ansicolor
# github.com/valyala/bytebufferpool v1.0.0
## explicit
github.com/valyala/bytebufferpool
# github.com/xdg-go/pbkdf2 v1.0.0
## explicit
github.com/xdg-go/pbkdf2
# github.com/xdg-go/scram v1.1.2
## explicit
github.com/xdg-go/scram
# github.com/xdg-go/stringprep v1.0.4
## explicit
github.com/xdg-go/stringprep
# github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78
## explicit
github.com/youmark/pkcs8
# go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0
## explicit
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc
# go.opentelemetry.io/otel v1.24.0
## explicit
go.opentelemetry.io/otel
# go.opentelemetry.io/otel/metric v1.24.0
## explicit
go.opentelemetry.io/otel/metric
# go.opentelemetry.io/otel/trace v1.24.0
## explicit
go.opentelemetry.io/otel/trace
# go.uber.org/multierr v1.11.0
## explicit
go.uber.org/multierr
# go.uber.org/zap v1.27.0
## explicit
go.uber.org/zap
# golang.org/x/crypto v0.26.0
## explicit
golang.org/x/crypto
# golang.org/x/net v0.24.0
## explicit
golang.org/x/net
# golang.org/x/sync v0.8.0
## explicit
golang.org/x/sync
# golang.org/x/sys v0.23.0
## explicit
golang.org/x/sys
# golang.org/x/text v0.17.0
## explicit
golang.org/x/text
# google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda
## explicit
google.golang.org/genproto/googleapis/rpc
# google.golang.org/grpc v1.63.2
## explicit
google.golang.org/grpc
# google.golang.org/protobuf v1.34.2
## explicit
google.golang.org/protobuf
# gopkg.in/couchbase/gocbcore.v7 v7.1.18
## explicit
gopkg.in/couchbase/gocbcore.v7
# gopkg.in/couchbaselabs/gocbconnstr.v1 v1.0.4
## explicit
gopkg.in/couchbaselabs/gocbconnstr.v1
# gopkg.in/couchbaselabs/gojcbmock.v1 v1.0.4
## explicit
gopkg.in/couchbaselabs/gojcbmock.v1
# gopkg.in/couchbaselabs/jsonx.v1 v1.0.1
## explicit
gopkg.in/couchbaselabs/jsonx.v1

View File

@@ -30,52 +30,54 @@ import (
func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
username := req.URL.Query()["username"][0]
slice := []any{"username", username}
password := req.URL.Query()["password"][0]
formatString := req.URL.Query()["formatString"][0]
testFlag := req.URL.Query()["testFlag"][0]
slice := []any{"username", username}
{
fmt.Print(username) // $ hasTaintFlow="username"
fmt.Printf(username) // $ hasTaintFlow="username"
fmt.Println(username) // $ hasTaintFlow="username"
fmt.Fprint(nil, username) // Fprint functions are only loggers if they target stdout/stderr
fmt.Fprintf(nil, username)
fmt.Fprintln(nil, username)
fmt.Print(username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
fmt.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
fmt.Println(username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
fmt.Fprint(nil, username, password) // Fprint functions are only loggers if they target stdout/stderr
fmt.Fprintf(nil, formatString, username, password)
fmt.Fprintln(nil, username, password)
}
// log
{
log.Print("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Printf("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Println("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Print("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
log.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
log.Println("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
if testFlag == "true" {
log.Fatal("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Fatal("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "true" {
log.Fatalf("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Fatalf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "true" {
log.Fatalln("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Fatalln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "true" {
log.Panic("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Panic("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "true" {
log.Panicf("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Panicf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
}
if testFlag == "true" {
log.Panicln("user %s logged in.\n", username) // $ hasTaintFlow="username"
log.Panicln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
logger := log.Default()
logger.Print("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Printf("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Println("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Fatal("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Fatalf("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Fatalln("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Panic("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Panicf("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Panicln("user %s logged in.\n", username) // $ hasTaintFlow="username"
logger.Print("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
logger.Printf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
logger.Println("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
logger.Fatal("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
logger.Fatalf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
logger.Fatalln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
logger.Panic("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
logger.Panicf(formatString, username, password) // $ hasTaintFlow="formatString" hasTaintFlow="username" hasTaintFlow="password"
logger.Panicln("user is logged in:", username, password) // $ hasTaintFlow="username" hasTaintFlow="password"
}
// k8s.io/klog
{
@@ -421,7 +423,6 @@ func handler(req *http.Request, ctx *goproxy.ProxyCtx) {
simpleLogger.Tracew("%s", username) // $ hasTaintFlow="username"
simpleLogger.Debugw("%s %s", slice...) // $ hasTaintFlow="slice"
}
}
type Logger interface {
@@ -514,8 +515,12 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
verbose.Infof("user %q logged in.\n", username)
klog.Infof("user %q logged in.\n", username)
klog.Errorf("user %q logged in.\n", username)
klog.Fatalf("user %q logged in.\n", username)
klog.Exitf("user %q logged in.\n", username)
if testFlag == " true" {
klog.Fatalf("user %q logged in.\n", username)
}
if testFlag == " true" {
klog.Exitf("user %q logged in.\n", username)
}
}
// elazarl/goproxy
{
@@ -529,16 +534,24 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
glog.Infof("user %q logged in.\n", username)
glog.Errorf("user %q logged in.\n", username)
glog.Fatalf("user %q logged in.\n", username)
glog.Exitf("user %q logged in.\n", username)
if testFlag == " true" {
glog.Fatalf("user %q logged in.\n", username)
}
if testFlag == " true" {
glog.Exitf("user %q logged in.\n", username)
}
}
// sirupsen/logrus
{
logrus.Debugf("user %q logged in.\n", username)
logrus.Errorf("user %q logged in.\n", username)
logrus.Fatalf("user %q logged in.\n", username)
if testFlag == " true" {
logrus.Fatalf("user %q logged in.\n", username)
}
logrus.Infof("user %q logged in.\n", username)
logrus.Panicf("user %q logged in.\n", username)
if testFlag == " true" {
logrus.Panicf("user %q logged in.\n", username)
}
logrus.Printf("user %q logged in.\n", username)
logrus.Tracef("user %q logged in.\n", username)
logrus.Warnf("user %q logged in.\n", username)
@@ -548,10 +561,14 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
entry := logrus.WithFields(fields)
entry.Debugf("user %q logged in.\n", username)
entry.Errorf("user %q logged in.\n", username)
entry.Fatalf("user %q logged in.\n", username)
if testFlag == " true" {
entry.Fatalf("user %q logged in.\n", username)
}
entry.Infof("user %q logged in.\n", username)
entry.Logf(0, "user %q logged in.\n", username)
entry.Panicf("user %q logged in.\n", username)
if testFlag == " true" {
entry.Panicf("user %q logged in.\n", username)
}
entry.Printf("user %q logged in.\n", username)
entry.Tracef("user %q logged in.\n", username)
entry.Warnf("user %q logged in.\n", username)
@@ -560,10 +577,14 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
logger := entry.Logger
logger.Debugf("user %q logged in.\n", username)
logger.Errorf("user %q logged in.\n", username)
logger.Fatalf("user %q logged in.\n", username)
if testFlag == " true" {
logger.Fatalf("user %q logged in.\n", username)
}
logger.Infof("user %q logged in.\n", username)
logger.Logf(0, "user %q logged in.\n", username)
logger.Panicf("user %q logged in.\n", username)
if testFlag == " true" {
logger.Panicf("user %q logged in.\n", username)
}
logger.Printf("user %q logged in.\n", username)
logger.Tracef("user %q logged in.\n", username)
logger.Warnf("user %q logged in.\n", username)
@@ -599,8 +620,12 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
verbose.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
klog.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
klog.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
klog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
klog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
klog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
if testFlag == " true" {
klog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
}
// elazarl/goproxy
{
@@ -614,16 +639,24 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
glog.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
glog.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
glog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
glog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
glog.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
if testFlag == " true" {
glog.Exitf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
}
// sirupsen/logrus
{
logrus.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
logrus.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
logrus.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
logrus.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
logrus.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Tracef("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logrus.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
@@ -631,24 +664,32 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
fields := make(logrus.Fields)
entry := logrus.WithFields(fields)
entry.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
entry.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
entry.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
entry.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
entry.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Tracef("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
entry.Warningf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger := entry.Logger
logger.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Debugf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Errorf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
logger.Fatalf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
logger.Infof("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Logf(0, "user %#q logged in.\n", username) // $ hasTaintFlow="username"
if testFlag == " true" {
logger.Panicf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
logger.Printf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Tracef("user %#q logged in.\n", username) // $ hasTaintFlow="username"
logger.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
@@ -677,3 +718,9 @@ func handlerGood4(req *http.Request, ctx *goproxy.ProxyCtx) {
sLogger.Warnf("user %#q logged in.\n", username) // $ hasTaintFlow="username"
}
}
// GOOD: User-provided values formatted using a %T directive, which prints the type of the argument
func handlerGood5(req *http.Request) {
object := req.URL.Query()["username"][0]
log.Printf("found object of type %T.\n", object)
}

View File

@@ -1,35 +1,35 @@
#select
| klog.go:22:15:22:20 | header | klog.go:20:30:20:37 | selection of Header | klog.go:22:15:22:20 | header | $@ flows to a logging call. | klog.go:20:30:20:37 | selection of Header | Sensitive data returned by HTTP request headers |
| klog.go:28:13:28:41 | call to Get | klog.go:28:13:28:20 | selection of Header | klog.go:28:13:28:41 | call to Get | $@ flows to a logging call. | klog.go:28:13:28:20 | selection of Header | Sensitive data returned by HTTP request headers |
| main.go:15:12:15:19 | password | main.go:15:12:15:19 | password | main.go:15:12:15:19 | password | $@ flows to a logging call. | main.go:15:12:15:19 | password | Sensitive data returned by an access to password |
| main.go:16:17:16:24 | password | main.go:16:17:16:24 | password | main.go:16:17:16:24 | password | $@ flows to a logging call. | main.go:16:17:16:24 | password | Sensitive data returned by an access to password |
| main.go:17:13:17:20 | password | main.go:17:13:17:20 | password | main.go:17:13:17:20 | password | $@ flows to a logging call. | main.go:17:13:17:20 | password | Sensitive data returned by an access to password |
| main.go:18:14:18:21 | password | main.go:18:14:18:21 | password | main.go:18:14:18:21 | password | $@ flows to a logging call. | main.go:18:14:18:21 | password | Sensitive data returned by an access to password |
| main.go:19:12:19:19 | password | main.go:19:12:19:19 | password | main.go:19:12:19:19 | password | $@ flows to a logging call. | main.go:19:12:19:19 | password | Sensitive data returned by an access to password |
| main.go:20:17:20:24 | password | main.go:20:17:20:24 | password | main.go:20:17:20:24 | password | $@ flows to a logging call. | main.go:20:17:20:24 | password | Sensitive data returned by an access to password |
| main.go:21:13:21:20 | password | main.go:21:13:21:20 | password | main.go:21:13:21:20 | password | $@ flows to a logging call. | main.go:21:13:21:20 | password | Sensitive data returned by an access to password |
| main.go:22:14:22:21 | password | main.go:22:14:22:21 | password | main.go:22:14:22:21 | password | $@ flows to a logging call. | main.go:22:14:22:21 | password | Sensitive data returned by an access to password |
| main.go:23:12:23:19 | password | main.go:23:12:23:19 | password | main.go:23:12:23:19 | password | $@ flows to a logging call. | main.go:23:12:23:19 | password | Sensitive data returned by an access to password |
| main.go:24:17:24:24 | password | main.go:24:17:24:24 | password | main.go:24:17:24:24 | password | $@ flows to a logging call. | main.go:24:17:24:24 | password | Sensitive data returned by an access to password |
| main.go:25:13:25:20 | password | main.go:25:13:25:20 | password | main.go:25:13:25:20 | password | $@ flows to a logging call. | main.go:25:13:25:20 | password | Sensitive data returned by an access to password |
| main.go:26:14:26:21 | password | main.go:26:14:26:21 | password | main.go:26:14:26:21 | password | $@ flows to a logging call. | main.go:26:14:26:21 | password | Sensitive data returned by an access to password |
| main.go:27:16:27:23 | password | main.go:27:16:27:23 | password | main.go:27:16:27:23 | password | $@ flows to a logging call. | main.go:27:16:27:23 | password | Sensitive data returned by an access to password |
| main.go:30:10:30:17 | password | main.go:30:10:30:17 | password | main.go:30:10:30:17 | password | $@ flows to a logging call. | main.go:30:10:30:17 | password | Sensitive data returned by an access to password |
| main.go:31:15:31:22 | password | main.go:31:15:31:22 | password | main.go:31:15:31:22 | password | $@ flows to a logging call. | main.go:31:15:31:22 | password | Sensitive data returned by an access to password |
| main.go:32:11:32:18 | password | main.go:32:11:32:18 | password | main.go:32:11:32:18 | password | $@ flows to a logging call. | main.go:32:11:32:18 | password | Sensitive data returned by an access to password |
| main.go:33:12:33:19 | password | main.go:33:12:33:19 | password | main.go:33:12:33:19 | password | $@ flows to a logging call. | main.go:33:12:33:19 | password | Sensitive data returned by an access to password |
| main.go:34:10:34:17 | password | main.go:34:10:34:17 | password | main.go:34:10:34:17 | password | $@ flows to a logging call. | main.go:34:10:34:17 | password | Sensitive data returned by an access to password |
| main.go:35:15:35:22 | password | main.go:35:15:35:22 | password | main.go:35:15:35:22 | password | $@ flows to a logging call. | main.go:35:15:35:22 | password | Sensitive data returned by an access to password |
| main.go:36:11:36:18 | password | main.go:36:11:36:18 | password | main.go:36:11:36:18 | password | $@ flows to a logging call. | main.go:36:11:36:18 | password | Sensitive data returned by an access to password |
| main.go:37:12:37:19 | password | main.go:37:12:37:19 | password | main.go:37:12:37:19 | password | $@ flows to a logging call. | main.go:37:12:37:19 | password | Sensitive data returned by an access to password |
| main.go:38:10:38:17 | password | main.go:38:10:38:17 | password | main.go:38:10:38:17 | password | $@ flows to a logging call. | main.go:38:10:38:17 | password | Sensitive data returned by an access to password |
| main.go:39:15:39:22 | password | main.go:39:15:39:22 | password | main.go:39:15:39:22 | password | $@ flows to a logging call. | main.go:39:15:39:22 | password | Sensitive data returned by an access to password |
| main.go:40:11:40:18 | password | main.go:40:11:40:18 | password | main.go:40:11:40:18 | password | $@ flows to a logging call. | main.go:40:11:40:18 | password | Sensitive data returned by an access to password |
| main.go:41:12:41:19 | password | main.go:41:12:41:19 | password | main.go:41:12:41:19 | password | $@ flows to a logging call. | main.go:41:12:41:19 | password | Sensitive data returned by an access to password |
| main.go:42:14:42:21 | password | main.go:42:14:42:21 | password | main.go:42:14:42:21 | password | $@ flows to a logging call. | main.go:42:14:42:21 | password | Sensitive data returned by an access to password |
| main.go:44:12:44:19 | password | main.go:44:12:44:19 | password | main.go:44:12:44:19 | password | $@ flows to a logging call. | main.go:44:12:44:19 | password | Sensitive data returned by an access to password |
| main.go:45:17:45:24 | password | main.go:45:17:45:24 | password | main.go:45:17:45:24 | password | $@ flows to a logging call. | main.go:45:17:45:24 | password | Sensitive data returned by an access to password |
| main.go:52:35:52:42 | password | main.go:52:35:52:42 | password | main.go:52:35:52:42 | password | $@ flows to a logging call. | main.go:52:35:52:42 | password | Sensitive data returned by an access to password |
| klog.go:23:15:23:20 | header | klog.go:21:30:21:37 | selection of Header | klog.go:23:15:23:20 | header | $@ flows to a logging call. | klog.go:21:30:21:37 | selection of Header | Sensitive data returned by HTTP request headers |
| klog.go:29:13:29:41 | call to Get | klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | $@ flows to a logging call. | klog.go:29:13:29:20 | selection of Header | Sensitive data returned by HTTP request headers |
| main.go:16:12:16:19 | password | main.go:16:12:16:19 | password | main.go:16:12:16:19 | password | $@ flows to a logging call. | main.go:16:12:16:19 | password | Sensitive data returned by an access to password |
| main.go:17:19:17:26 | password | main.go:17:19:17:26 | password | main.go:17:19:17:26 | password | $@ flows to a logging call. | main.go:17:19:17:26 | password | Sensitive data returned by an access to password |
| main.go:18:13:18:20 | password | main.go:18:13:18:20 | password | main.go:18:13:18:20 | password | $@ flows to a logging call. | main.go:18:13:18:20 | password | Sensitive data returned by an access to password |
| main.go:19:14:19:21 | password | main.go:19:14:19:21 | password | main.go:19:14:19:21 | password | $@ flows to a logging call. | main.go:19:14:19:21 | password | Sensitive data returned by an access to password |
| main.go:20:12:20:19 | password | main.go:20:12:20:19 | password | main.go:20:12:20:19 | password | $@ flows to a logging call. | main.go:20:12:20:19 | password | Sensitive data returned by an access to password |
| main.go:21:19:21:26 | password | main.go:21:19:21:26 | password | main.go:21:19:21:26 | password | $@ flows to a logging call. | main.go:21:19:21:26 | password | Sensitive data returned by an access to password |
| main.go:22:13:22:20 | password | main.go:22:13:22:20 | password | main.go:22:13:22:20 | password | $@ flows to a logging call. | main.go:22:13:22:20 | password | Sensitive data returned by an access to password |
| main.go:23:14:23:21 | password | main.go:23:14:23:21 | password | main.go:23:14:23:21 | password | $@ flows to a logging call. | main.go:23:14:23:21 | password | Sensitive data returned by an access to password |
| main.go:24:12:24:19 | password | main.go:24:12:24:19 | password | main.go:24:12:24:19 | password | $@ flows to a logging call. | main.go:24:12:24:19 | password | Sensitive data returned by an access to password |
| main.go:25:19:25:26 | password | main.go:25:19:25:26 | password | main.go:25:19:25:26 | password | $@ flows to a logging call. | main.go:25:19:25:26 | password | Sensitive data returned by an access to password |
| main.go:26:13:26:20 | password | main.go:26:13:26:20 | password | main.go:26:13:26:20 | password | $@ flows to a logging call. | main.go:26:13:26:20 | password | Sensitive data returned by an access to password |
| main.go:27:14:27:21 | password | main.go:27:14:27:21 | password | main.go:27:14:27:21 | password | $@ flows to a logging call. | main.go:27:14:27:21 | password | Sensitive data returned by an access to password |
| main.go:28:16:28:23 | password | main.go:28:16:28:23 | password | main.go:28:16:28:23 | password | $@ flows to a logging call. | main.go:28:16:28:23 | password | Sensitive data returned by an access to password |
| main.go:32:10:32:17 | password | main.go:32:10:32:17 | password | main.go:32:10:32:17 | password | $@ flows to a logging call. | main.go:32:10:32:17 | password | Sensitive data returned by an access to password |
| main.go:33:17:33:24 | password | main.go:33:17:33:24 | password | main.go:33:17:33:24 | password | $@ flows to a logging call. | main.go:33:17:33:24 | password | Sensitive data returned by an access to password |
| main.go:34:11:34:18 | password | main.go:34:11:34:18 | password | main.go:34:11:34:18 | password | $@ flows to a logging call. | main.go:34:11:34:18 | password | Sensitive data returned by an access to password |
| main.go:35:12:35:19 | password | main.go:35:12:35:19 | password | main.go:35:12:35:19 | password | $@ flows to a logging call. | main.go:35:12:35:19 | password | Sensitive data returned by an access to password |
| main.go:36:10:36:17 | password | main.go:36:10:36:17 | password | main.go:36:10:36:17 | password | $@ flows to a logging call. | main.go:36:10:36:17 | password | Sensitive data returned by an access to password |
| main.go:37:17:37:24 | password | main.go:37:17:37:24 | password | main.go:37:17:37:24 | password | $@ flows to a logging call. | main.go:37:17:37:24 | password | Sensitive data returned by an access to password |
| main.go:38:11:38:18 | password | main.go:38:11:38:18 | password | main.go:38:11:38:18 | password | $@ flows to a logging call. | main.go:38:11:38:18 | password | Sensitive data returned by an access to password |
| main.go:39:12:39:19 | password | main.go:39:12:39:19 | password | main.go:39:12:39:19 | password | $@ flows to a logging call. | main.go:39:12:39:19 | password | Sensitive data returned by an access to password |
| main.go:40:10:40:17 | password | main.go:40:10:40:17 | password | main.go:40:10:40:17 | password | $@ flows to a logging call. | main.go:40:10:40:17 | password | Sensitive data returned by an access to password |
| main.go:41:17:41:24 | password | main.go:41:17:41:24 | password | main.go:41:17:41:24 | password | $@ flows to a logging call. | main.go:41:17:41:24 | password | Sensitive data returned by an access to password |
| main.go:42:11:42:18 | password | main.go:42:11:42:18 | password | main.go:42:11:42:18 | password | $@ flows to a logging call. | main.go:42:11:42:18 | password | Sensitive data returned by an access to password |
| main.go:43:12:43:19 | password | main.go:43:12:43:19 | password | main.go:43:12:43:19 | password | $@ flows to a logging call. | main.go:43:12:43:19 | password | Sensitive data returned by an access to password |
| main.go:44:14:44:21 | password | main.go:44:14:44:21 | password | main.go:44:14:44:21 | password | $@ flows to a logging call. | main.go:44:14:44:21 | password | Sensitive data returned by an access to password |
| main.go:47:12:47:19 | password | main.go:47:12:47:19 | password | main.go:47:12:47:19 | password | $@ flows to a logging call. | main.go:47:12:47:19 | password | Sensitive data returned by an access to password |
| main.go:48:17:48:24 | password | main.go:48:17:48:24 | password | main.go:48:17:48:24 | password | $@ flows to a logging call. | main.go:48:17:48:24 | password | Sensitive data returned by an access to password |
| main.go:55:35:55:42 | password | main.go:55:35:55:42 | password | main.go:55:35:55:42 | password | $@ flows to a logging call. | main.go:55:35:55:42 | password | Sensitive data returned by an access to password |
| overrides.go:13:14:13:23 | call to String | overrides.go:9:9:9:16 | password | overrides.go:13:14:13:23 | call to String | $@ flows to a logging call. | overrides.go:9:9:9:16 | password | Sensitive data returned by an access to password |
| passwords.go:9:14:9:14 | x | passwords.go:30:8:30:15 | password | passwords.go:9:14:9:14 | x | $@ flows to a logging call. | passwords.go:30:8:30:15 | password | Sensitive data returned by an access to password |
| passwords.go:25:14:25:21 | password | passwords.go:25:14:25:21 | password | passwords.go:25:14:25:21 | password | $@ flows to a logging call. | passwords.go:25:14:25:21 | password | Sensitive data returned by an access to password |
@@ -55,11 +55,11 @@
| passwords.go:127:14:127:21 | selection of y | passwords.go:122:13:122:25 | call to getPassword | passwords.go:127:14:127:21 | selection of y | $@ flows to a logging call. | passwords.go:122:13:122:25 | call to getPassword | Sensitive data returned by a call to getPassword |
| protobuf.go:14:14:14:35 | call to GetDescription | protobuf.go:12:22:12:29 | password | protobuf.go:14:14:14:35 | call to GetDescription | $@ flows to a logging call. | protobuf.go:12:22:12:29 | password | Sensitive data returned by an access to password |
edges
| klog.go:20:3:25:3 | range statement[1] | klog.go:21:27:21:33 | headers | provenance | |
| klog.go:20:30:20:37 | selection of Header | klog.go:20:3:25:3 | range statement[1] | provenance | Src:MaD:1 Config |
| klog.go:21:4:24:4 | range statement[1] | klog.go:22:15:22:20 | header | provenance | |
| klog.go:21:27:21:33 | headers | klog.go:21:4:24:4 | range statement[1] | provenance | Config |
| klog.go:28:13:28:20 | selection of Header | klog.go:28:13:28:41 | call to Get | provenance | Src:MaD:1 Config |
| klog.go:21:3:26:3 | range statement[1] | klog.go:22:27:22:33 | headers | provenance | |
| klog.go:21:30:21:37 | selection of Header | klog.go:21:3:26:3 | range statement[1] | provenance | Src:MaD:1 Config |
| klog.go:22:4:25:4 | range statement[1] | klog.go:23:15:23:20 | header | provenance | |
| klog.go:22:27:22:33 | headers | klog.go:22:4:25:4 | range statement[1] | provenance | Config |
| klog.go:29:13:29:20 | selection of Header | klog.go:29:13:29:41 | call to Get | provenance | Src:MaD:1 Config |
| overrides.go:9:9:9:16 | password | overrides.go:13:14:13:23 | call to String | provenance | |
| passwords.go:8:12:8:12 | definition of x | passwords.go:9:14:9:14 | x | provenance | |
| passwords.go:30:8:30:15 | password | passwords.go:8:12:8:12 | definition of x | provenance | |
@@ -101,42 +101,42 @@ edges
models
| 1 | Source: net/http; Request; true; Header; ; ; ; remote; manual |
nodes
| klog.go:20:3:25:3 | range statement[1] | semmle.label | range statement[1] |
| klog.go:20:30:20:37 | selection of Header | semmle.label | selection of Header |
| klog.go:21:4:24:4 | range statement[1] | semmle.label | range statement[1] |
| klog.go:21:27:21:33 | headers | semmle.label | headers |
| klog.go:22:15:22:20 | header | semmle.label | header |
| klog.go:28:13:28:20 | selection of Header | semmle.label | selection of Header |
| klog.go:28:13:28:41 | call to Get | semmle.label | call to Get |
| main.go:15:12:15:19 | password | semmle.label | password |
| main.go:16:17:16:24 | password | semmle.label | password |
| main.go:17:13:17:20 | password | semmle.label | password |
| main.go:18:14:18:21 | password | semmle.label | password |
| main.go:19:12:19:19 | password | semmle.label | password |
| main.go:20:17:20:24 | password | semmle.label | password |
| main.go:21:13:21:20 | password | semmle.label | password |
| main.go:22:14:22:21 | password | semmle.label | password |
| main.go:23:12:23:19 | password | semmle.label | password |
| main.go:24:17:24:24 | password | semmle.label | password |
| main.go:25:13:25:20 | password | semmle.label | password |
| main.go:26:14:26:21 | password | semmle.label | password |
| main.go:27:16:27:23 | password | semmle.label | password |
| main.go:30:10:30:17 | password | semmle.label | password |
| main.go:31:15:31:22 | password | semmle.label | password |
| main.go:32:11:32:18 | password | semmle.label | password |
| main.go:33:12:33:19 | password | semmle.label | password |
| main.go:34:10:34:17 | password | semmle.label | password |
| main.go:35:15:35:22 | password | semmle.label | password |
| main.go:36:11:36:18 | password | semmle.label | password |
| main.go:37:12:37:19 | password | semmle.label | password |
| main.go:38:10:38:17 | password | semmle.label | password |
| main.go:39:15:39:22 | password | semmle.label | password |
| main.go:40:11:40:18 | password | semmle.label | password |
| main.go:41:12:41:19 | password | semmle.label | password |
| main.go:42:14:42:21 | password | semmle.label | password |
| main.go:44:12:44:19 | password | semmle.label | password |
| main.go:45:17:45:24 | password | semmle.label | password |
| main.go:52:35:52:42 | password | semmle.label | password |
| klog.go:21:3:26:3 | range statement[1] | semmle.label | range statement[1] |
| klog.go:21:30:21:37 | selection of Header | semmle.label | selection of Header |
| klog.go:22:4:25:4 | range statement[1] | semmle.label | range statement[1] |
| klog.go:22:27:22:33 | headers | semmle.label | headers |
| klog.go:23:15:23:20 | header | semmle.label | header |
| klog.go:29:13:29:20 | selection of Header | semmle.label | selection of Header |
| klog.go:29:13:29:41 | call to Get | semmle.label | call to Get |
| main.go:16:12:16:19 | password | semmle.label | password |
| main.go:17:19:17:26 | password | semmle.label | password |
| main.go:18:13:18:20 | password | semmle.label | password |
| main.go:19:14:19:21 | password | semmle.label | password |
| main.go:20:12:20:19 | password | semmle.label | password |
| main.go:21:19:21:26 | password | semmle.label | password |
| main.go:22:13:22:20 | password | semmle.label | password |
| main.go:23:14:23:21 | password | semmle.label | password |
| main.go:24:12:24:19 | password | semmle.label | password |
| main.go:25:19:25:26 | password | semmle.label | password |
| main.go:26:13:26:20 | password | semmle.label | password |
| main.go:27:14:27:21 | password | semmle.label | password |
| main.go:28:16:28:23 | password | semmle.label | password |
| main.go:32:10:32:17 | password | semmle.label | password |
| main.go:33:17:33:24 | password | semmle.label | password |
| main.go:34:11:34:18 | password | semmle.label | password |
| main.go:35:12:35:19 | password | semmle.label | password |
| main.go:36:10:36:17 | password | semmle.label | password |
| main.go:37:17:37:24 | password | semmle.label | password |
| main.go:38:11:38:18 | password | semmle.label | password |
| main.go:39:12:39:19 | password | semmle.label | password |
| main.go:40:10:40:17 | password | semmle.label | password |
| main.go:41:17:41:24 | password | semmle.label | password |
| main.go:42:11:42:18 | password | semmle.label | password |
| main.go:43:12:43:19 | password | semmle.label | password |
| main.go:44:14:44:21 | password | semmle.label | password |
| main.go:47:12:47:19 | password | semmle.label | password |
| main.go:48:17:48:24 | password | semmle.label | password |
| main.go:55:35:55:42 | password | semmle.label | password |
| overrides.go:9:9:9:16 | password | semmle.label | password |
| overrides.go:13:14:13:23 | call to String | semmle.label | call to String |
| passwords.go:8:12:8:12 | definition of x | semmle.label | definition of x |

View File

@@ -1,2 +1,4 @@
query: Security/CWE-312/CleartextLogging.ql
postprocess: utils/test/PrettyPrintModels.ql
postprocess:
- utils/test/PrettyPrintModels.ql
- utils/test/InlineExpectationsTestQuery.ql

View File

@@ -3,9 +3,10 @@ package main
//go:generate depstubber -vendor k8s.io/klog "" Info
import (
"k8s.io/klog"
"net/http"
"strings"
"k8s.io/klog"
)
func mask(key, value string) string {
@@ -17,15 +18,15 @@ func mask(key, value string) string {
func klogTest() {
http.HandleFunc("/klog", func(w http.ResponseWriter, r *http.Request) {
for name, headers := range r.Header {
for name, headers := range r.Header { // $ Source
for _, header := range headers {
klog.Info(header) // NOT OK
klog.Info(header) // $ Alert
klog.Info(mask(name, header)) // OK
}
}
klog.Info(r.Header.Get("Accept")) // OK
klog.Info(r.Header["Content-Type"]) // OK
klog.Info(r.Header.Get("Authorization")) // NOT OK
klog.Info(r.Header.Get("Authorization")) // $ Alert
})
http.ListenAndServe(":80", nil)
}

View File

@@ -4,51 +4,54 @@ package main
//go:generate depstubber -vendor github.com/golang/glog "" Info
import (
"log"
"github.com/golang/glog"
"github.com/sirupsen/logrus"
"log"
)
func main() {
password := "P4ssw0rd"
log.Print(password)
log.Printf("", password)
log.Printf(password, "")
log.Println(password)
log.Fatal(password)
log.Fatalf("", password)
log.Fatalf(password, "")
log.Fatalln(password)
log.Panic(password)
log.Panicf("", password)
log.Panicf(password, "")
log.Panicln(password)
log.Output(0, password)
log.Print(password) // $ Alert
log.Printf("%s", password) // $ Alert
log.Printf(password, "") // $ Alert
log.Println(password) // $ Alert
log.Fatal(password) // $ Alert
log.Fatalf("%s", password) // $ Alert
log.Fatalf(password, "") // $ Alert
log.Fatalln(password) // $ Alert
log.Panic(password) // $ Alert
log.Panicf("%s", password) // $ Alert
log.Panicf(password, "") // $ Alert
log.Panicln(password) // $ Alert
log.Output(0, password) // $ Alert
log.Printf("%T", password)
l := log.Default()
l.Print(password)
l.Printf("", password)
l.Printf(password, "")
l.Println(password)
l.Fatal(password)
l.Fatalf("", password)
l.Fatalf(password, "")
l.Fatalln(password)
l.Panic(password)
l.Panicf("", password)
l.Panicf(password, "")
l.Panicln(password)
l.Output(0, password)
l.Print(password) // $ Alert
l.Printf("%s", password) // $ Alert
l.Printf(password, "") // $ Alert
l.Println(password) // $ Alert
l.Fatal(password) // $ Alert
l.Fatalf("%s", password) // $ Alert
l.Fatalf(password, "") // $ Alert
l.Fatalln(password) // $ Alert
l.Panic(password) // $ Alert
l.Panicf("%s", password) // $ Alert
l.Panicf(password, "") // $ Alert
l.Panicln(password) // $ Alert
l.Output(0, password) // $ Alert
l.Printf("%T", password)
glog.Info(password)
logrus.Warning(password)
glog.Info(password) // $ Alert
logrus.Warning(password) // $ Alert
fields := make(logrus.Fields)
fields["pass"] = password
entry := logrus.WithFields(fields)
entry.Errorf("")
entry = logrus.WithField("pass", password)
entry = logrus.WithField("pass", password) // $ Alert
entry.Panic("")
}

View File

@@ -6,10 +6,10 @@ type s struct{}
func (_ s) String() string {
password := "horsebatterystaplecorrect"
return password
return password // $ Source
}
func overrideTest(x s, y fmt.Stringer) {
fmt.Println(x.String()) // NOT OK
fmt.Println(x.String()) // $ Alert
fmt.Println(y.String()) // OK
}

View File

@@ -6,7 +6,7 @@ import (
)
func myLog(x string) {
log.Println(x) // NOT OK
log.Println(x) // $ Alert
}
func redact(kind, value string) string {
@@ -22,33 +22,33 @@ func test() {
x := "horsebatterystapleincorrect"
var o passStruct
log.Println(password) // NOT OK
log.Println(o.password) // NOT OK
log.Println(getPassword()) // NOT OK
log.Println(o.getPassword()) // NOT OK
log.Println(password) // $ Alert
log.Println(o.password) // $ Alert
log.Println(getPassword()) // $ Alert
log.Println(o.getPassword()) // $ Alert
myLog(password)
myLog(password) // $ Source
log.Panic(password) // NOT OK
log.Panic(password) // $ Alert
log.Println(name + ", " + password) // NOT OK
log.Println(name + ", " + password) // $ Alert
obj1 := passStruct{
password: x,
password: x, // $ Source
}
log.Println(obj1) // NOT OK
log.Println(obj1) // $ Alert
obj2 := xStruct{
x: password,
x: password, // $ Source
}
log.Println(obj2) // NOT OK
log.Println(obj2) // $ Alert
var obj3 xStruct
log.Println(obj3) // caught because of the below line
obj3.x = password // NOT OK
log.Println(obj3) // $ SPURIOUS: Alert // caught because of the below line and def-use flow
obj3.x = password // $ Source
fixed_password := "cowbatterystaplecorrect"
log.Println(fixed_password) // Probably OK, but caught
log.Println(fixed_password) // $ Alert // Probably OK
log.Println(IncorrectPasswordError) // OK
@@ -83,12 +83,12 @@ func test() {
log.Println(password_sha) // OK
utilityObject := passSetStruct{
passwordSet: make(map[string]bool),
passwordSet: make(map[string]bool), // $ Source
}
log.Println(utilityObject) // NOT OK
log.Println(utilityObject) // $ Alert
secret := password
log.Printf("pw: %s", secret) // NOT OK
secret := password // $ Source
log.Printf("pw: %s", secret) // $ Alert
log.Println("Password is: " + redact("password", password))
@@ -98,33 +98,33 @@ func test() {
if t.test(y) {
f()
// ...
log.Println("Password is: " + password) // NOT OK
log.Println("Password is: " + password) // $ Alert
// ...
}
if t.test(y) {
if f() {
log.Println("Password is: " + password) // NOT OK
log.Println("Password is: " + password) // $ Alert
}
}
if os.Getenv("APP_ENV") != "production" {
log.Println("Password is: " + password) // OK, but still flagged
log.Println("Password is: " + password) // $ SPURIOUS: Alert
}
var password1 stringable = stringable{"arstneio"}
log.Println(name + ", " + password1.String()) // NOT OK
log.Println(name + ", " + password1.String()) // $ Alert
config := Config{
password: x,
password: x, // $ Source
hostname: "tarski",
x: password,
y: getPassword(),
x: password, // $ Source
y: getPassword(), // $ Source
}
log.Println(config.hostname) // OK
log.Println(config) // NOT OK
log.Println(config.x) // NOT OK
log.Println(config.y) // NOT OK
log.Println(config) // $ Alert
log.Println(config.x) // $ Alert
log.Println(config.y) // $ Alert
obj4 := xStruct{
x: "aaaaa",

View File

@@ -9,8 +9,8 @@ func testProtobuf() {
password := "P@ssw0rd"
query := &query.Query{}
query.Description = password
query.Description = password // $ Source
log.Println(query.GetDescription()) // NOT OK
log.Println(query.GetDescription()) // $ Alert
log.Println(query.GetId()) // OK
}

View File

@@ -4,7 +4,8 @@ import ssl
httpd = HTTPServer(('localhost', 4443), SimpleHTTPRequestHandler)
sslctx = ssl.SSLContext()
sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
sslctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
sslctx.load_cert_chain(certfile="../cert.pem", keyfile="../key.pem")
httpd.socket = sslctx.wrap_socket (httpd.socket, server_side=True)

View File

@@ -23,5 +23,5 @@ where
sink.getNode().asExpr() = c.getAlgoSpec() and
InsecureCryptoFlow::flowPath(source, sink)
select c, source, sink,
"Cryptographic algorithm $@ may not be secure, consider using a different algorithm.", source,
"Cryptographic algorithm $@ may not be secure. Consider using a different algorithm.", source,
source.getNode().asExpr().(InsecureAlgorithm).getStringValue()

View File

@@ -6,7 +6,7 @@ nodes
| WeakHashing.java:21:56:21:91 | getProperty(...) | semmle.label | getProperty(...) |
subpaths
#select
| Test.java:34:21:34:53 | new SecretKeySpec(...) | Test.java:34:48:34:52 | "foo" | Test.java:34:48:34:52 | "foo" | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | Test.java:34:48:34:52 | "foo" | foo |
| WeakHashing.java:15:29:15:84 | getInstance(...) | WeakHashing.java:15:55:15:83 | getProperty(...) | WeakHashing.java:15:55:15:83 | getProperty(...) | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | WeakHashing.java:15:55:15:83 | getProperty(...) | MD5 |
| WeakHashing.java:18:30:18:96 | getInstance(...) | WeakHashing.java:18:56:18:95 | getProperty(...) | WeakHashing.java:18:56:18:95 | getProperty(...) | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | WeakHashing.java:18:56:18:95 | getProperty(...) | MD5 |
| WeakHashing.java:21:30:21:92 | getInstance(...) | WeakHashing.java:21:56:21:91 | getProperty(...) | WeakHashing.java:21:56:21:91 | getProperty(...) | Cryptographic algorithm $@ may not be secure, consider using a different algorithm. | WeakHashing.java:21:56:21:91 | getProperty(...) | MD5 |
| Test.java:34:21:34:53 | new SecretKeySpec(...) | Test.java:34:48:34:52 | "foo" | Test.java:34:48:34:52 | "foo" | Cryptographic algorithm $@ may not be secure. Consider using a different algorithm. | Test.java:34:48:34:52 | "foo" | foo |
| WeakHashing.java:15:29:15:84 | getInstance(...) | WeakHashing.java:15:55:15:83 | getProperty(...) | WeakHashing.java:15:55:15:83 | getProperty(...) | Cryptographic algorithm $@ may not be secure. Consider using a different algorithm. | WeakHashing.java:15:55:15:83 | getProperty(...) | MD5 |
| WeakHashing.java:18:30:18:96 | getInstance(...) | WeakHashing.java:18:56:18:95 | getProperty(...) | WeakHashing.java:18:56:18:95 | getProperty(...) | Cryptographic algorithm $@ may not be secure. Consider using a different algorithm. | WeakHashing.java:18:56:18:95 | getProperty(...) | MD5 |
| WeakHashing.java:21:30:21:92 | getInstance(...) | WeakHashing.java:21:56:21:91 | getProperty(...) | WeakHashing.java:21:56:21:91 | getProperty(...) | Cryptographic algorithm $@ may not be secure. Consider using a different algorithm. | WeakHashing.java:21:56:21:91 | getProperty(...) | MD5 |

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for the `underscore.string` package.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for the `ApolloServer` class from `@apollo/server` and similar packages. In particular, the incoming data in a GraphQL resolver is now seen as a source of untrusted user input.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved support for `superagent` to handle the case where the package is directly called as a function, or via the `.del()` or `.agent()` method.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Improved support for `got` package with `Options`, `paginate()` and `extend()`

View File

@@ -0,0 +1,15 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: sourceModel
data:
- ["@apollo/server", "Member[ApolloServer,ApolloServerBase].Argument[0].AnyMember.AnyMember.AnyMember.Parameter[1]", "remote"]
- addsTo:
pack: codeql/javascript-all
extensible: typeModel
data:
- ["@apollo/server", "@apollo/server/standalone", ""]
- ["@apollo/server", "apollo-server-express", ""]
- ["@apollo/server", "apollo-server-core", ""]
- ["@apollo/server", "apollo-server", ""]

View File

@@ -0,0 +1,35 @@
extensions:
- addsTo:
pack: codeql/javascript-all
extensible: typeModel
data:
- ["'underscore.string'.Wrapper", "'underscore.string'", "ReturnValue"]
- ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,strip,lstrip,rstrip,camelcase].ReturnValue"]
- ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote,q,rjust,ljust].ReturnValue"]
- ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,concat].ReturnValue"]
- ["'underscore.string'.Wrapper", "'underscore.string'.Wrapper", "Member[tap].ReturnValue"]
- addsTo:
pack: codeql/javascript-all
extensible: summaryModel
data:
- ["'underscore.string'", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,strip,lstrip,rstrip,camelcase]", "Argument[0]", "ReturnValue", "taint"]
- ["'underscore.string'", "Member[chop,chars,words,lines]", "Argument[0]", "ReturnValue.ArrayElement", "taint"]
- ["'underscore.string'", "Member[toSentence,toSentenceSerial]", "Argument[0].ArrayElement", "ReturnValue", "taint"]
- ["'underscore.string'", "Member[insert,replaceAll,splice,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[0,2]", "ReturnValue", "taint"]
- ["'underscore.string'", "Member[splice]", "Argument[0,3]", "ReturnValue", "taint"]
- ["'underscore.string'", "Member[join]", "Argument[0..]", "ReturnValue", "taint"]
- ["'underscore.string'", "Member[surround,quote,q]", "Argument[0,1]", "ReturnValue", "taint"]
- ["'underscore.string'", "", "Argument[0]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[slugify,capitalize,decapitalize,clean,cleanDiacritics,swapCase,escapeHTML,unescapeHTML,wrap,dedent,reverse,pred,succ,titleize,camelize,classify,underscored,dasherize,humanize,trim,ltrim,rtrim,truncate,sprintf,strRight,strRightBack,strLeft,strLeftBack,stripTags,unquote,value,strip,lstrip,rstrip,camelcase]", "Argument[this]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[insert,replaceAll,join,splice,prune,pad,lpad,rpad,repeat,surround,quote,q,rjust,ljust]", "Argument[this]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[insert,replaceAll,prune,pad,lpad,rpad,repeat,rjust,ljust]", "Argument[1]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[surround,quote,q]", "Argument[0]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[splice]", "Argument[2]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[join,concat]", "Argument[0..]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[toUpperCase,toLowerCase,replace,slice,substring,substr,split]", "Argument[this]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[tap]", "Argument[this]", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[tap]", "Argument[0].ReturnValue", "ReturnValue", "taint"]
- ["'underscore.string'.Wrapper", "Member[tap]", "Argument[this]", "Argument[0].Parameter[1]", "taint"]
- ["'underscore.string'", "Member[map]", "Argument[0]", "Argument[1].Parameter[0]", "taint"]
- ["'underscore.string'", "Member[map]", "Argument[1].ReturnValue", "ReturnValue", "taint"]

View File

@@ -143,3 +143,4 @@ import semmle.javascript.linters.ESLint
import semmle.javascript.linters.JSLint
import semmle.javascript.linters.Linting
import semmle.javascript.security.dataflow.RemoteFlowSources
import semmle.javascript.frameworks.UnderscoreDotString

View File

@@ -414,20 +414,74 @@ module ClientRequest {
}
}
/**
* Represents an instance of the `got` HTTP client library.
*/
abstract private class GotInstance extends API::Node {
/**
* Gets the options object associated with this instance of `got`.
*/
API::Node getOptions() { none() }
}
/**
* Represents the root `got` module import.
* For example: `const got = require('got')`.
*/
private class RootGotInstance extends GotInstance {
RootGotInstance() { this = API::moduleImport("got") }
}
/**
* Represents an instance of `got` created by calling the `extend()` method.
* It may also be chained with multiple calls to `extend()`.
*
* For example: `const client = got.extend({ prefixUrl: 'https://example.com' })`.
*/
private class ExtendGotInstance extends GotInstance {
private GotInstance base;
private API::CallNode extendCall;
ExtendGotInstance() {
extendCall = base.getMember("extend").getACall() and
this = extendCall.getReturn()
}
override API::Node getOptions() {
result = extendCall.getParameter(0) or result = base.getOptions()
}
}
/**
* A model of a URL request made using the `got` library.
*/
class GotUrlRequest extends ClientRequest::Range {
GotInstance got;
GotUrlRequest() {
exists(API::Node callee, API::Node got | this = callee.getACall() |
got = [API::moduleImport("got"), API::moduleImport("got").getMember("extend").getReturn()] and
callee = [got, got.getMember(["stream", "get", "post", "put", "patch", "head", "delete"])]
exists(API::Node callee | this = callee.getACall() |
callee =
[
got,
got.getMember(["stream", "get", "post", "put", "patch", "head", "delete", "paginate"])
]
)
}
override DataFlow::Node getUrl() {
result = this.getArgument(0) and
not exists(this.getOptionArgument(1, "baseUrl"))
or
// Handle URL from options passed to extend()
result = got.getOptions().getMember("url").asSink() and
not exists(this.getArgument(0))
or
// Handle URL from options passed as third argument when first arg is undefined/missing
exists(API::InvokeNode optionsCall |
optionsCall = API::moduleImport("got").getMember("Options").getAnInvocation() and
optionsCall.getReturn().getAValueReachableFromSource() = this.getAnArgument() and
result = optionsCall.getParameter(0).getMember("url").asSink()
)
}
override DataFlow::Node getHost() {
@@ -513,6 +567,13 @@ module ClientRequest {
}
}
/**
* Gets the name of a superagent request method.
*/
private string getSuperagentRequestMethodName() {
result = [httpMethodName(), any(Http::RequestMethodName m), "del", "DEL"]
}
/**
* A model of a URL request made using the `superagent` library.
*/
@@ -520,10 +581,22 @@ module ClientRequest {
DataFlow::Node url;
SuperAgentUrlRequest() {
exists(string moduleName, DataFlow::SourceNode callee | this = callee.getACall() |
moduleName = "superagent" and
callee = DataFlow::moduleMember(moduleName, httpMethodName()) and
exists(string moduleName | moduleName = "superagent" |
// Handle method calls like superagent.get(url)
this = API::moduleImport(moduleName).getMember(getSuperagentRequestMethodName()).getACall() and
url = this.getArgument(0)
or
// Handle direct calls like superagent('GET', url)
this = API::moduleImport(moduleName).getACall() and
this.getArgument(0).mayHaveStringValue(getSuperagentRequestMethodName()) and
url = this.getArgument(1)
or
// Handle agent calls like superagent.agent().get(url)
exists(DataFlow::SourceNode agent |
agent = API::moduleImport(moduleName).getMember("agent").getACall() and
this = agent.getAMethodCall(httpMethodName()) and
url = this.getArgument(0)
)
)
}

View File

@@ -0,0 +1,26 @@
/**
* Provides classes for modeling data flow behavior of the Underscore.string library (https://www.npmjs.com/package/underscore.string).
*/
private import javascript
private import semmle.javascript.dataflow.internal.AdditionalFlowInternal
/**
* Models data flow for the Underscore.string library.
*/
private class UnderscoreDotString extends AdditionalFlowInternal {
/**
* Some of the methods in `underscore.string` have the same name as methods from `Array.prototype`.
* This prevents methods like `splice` from propagating into Argument[this].ArrayElement.
*/
override predicate clearsContent(DataFlow::Node node, DataFlow::ContentSet contents) {
exists(DataFlow::CallNode call |
call =
ModelOutput::getATypeNode(["'underscore.string'.Wrapper", "'underscore.string'"])
.getAMember()
.getACall() and
node = call.getReceiver().getPostUpdateNode() and
contents = DataFlow::ContentSet::arrayElement()
)
}
}

View File

@@ -0,0 +1,130 @@
var s = require("underscore.string");
function strToStr() {
sink(s.slugify(source("s1"))); // $ hasTaintFlow=s1
sink(s.capitalize(source("s2"))); // $ hasTaintFlow=s2
sink(s.decapitalize(source("s3"))); // $ hasTaintFlow=s3
sink(s.clean(source("s4"))); // $ hasTaintFlow=s4
sink(s.cleanDiacritics(source("s5"))); // $ hasTaintFlow=s5
sink(s.swapCase(source("s6"))); // $ hasTaintFlow=s6
sink(s.escapeHTML(source("s7"))); // $ hasTaintFlow=s7
sink(s.unescapeHTML(source("s8"))); // $ hasTaintFlow=s8
sink(s.wrap(source("s9"), {})); // $ hasTaintFlow=s9
sink(s.dedent(source("s10"), " ")); // $ hasTaintFlow=s10
sink(s.reverse(source("s11"))); // $ hasTaintFlow=s11
sink(s.pred(source("s12"))); // $ hasTaintFlow=s12
sink(s.succ(source("s13"))); // $ hasTaintFlow=s13
sink(s.titleize(source("s14"))); // $ hasTaintFlow=s14
sink(s.camelize(source("s15"))); // $ hasTaintFlow=s15
sink(s.classify(source("s16"))); // $ hasTaintFlow=s16
sink(s.underscored(source("s17"))); // $ hasTaintFlow=s17
sink(s.dasherize(source("s18"))); // $ hasTaintFlow=s18
sink(s.humanize(source("s19"))); // $ hasTaintFlow=s19
sink(s.trim(source("s20"),"charsToStrim")); // $ hasTaintFlow=s20
sink(s.ltrim(source("s21"),"charsToStrim")); // $ hasTaintFlow=s21
sink(s.rtrim(source("s22"),"charsToStrim")); // $ hasTaintFlow=s22
sink(s.truncate(source("s23"), 10)); // $ hasTaintFlow=s23
sink(s.sprintf(source("s24"), 1.17)); // $ hasTaintFlow=s24
sink(s.strRight(source("s25"), "pattern")); // $ hasTaintFlow=s25
sink(s.strRightBack(source("s26"), "pattern")); // $ hasTaintFlow=s26
sink(s.strLeft(source("s27"), "pattern")); // $ hasTaintFlow=s27
sink(s.strLeftBack(source("s28"), "pattern")); // $ hasTaintFlow=s28
sink(s.stripTags(source("s29"))); // $ hasTaintFlow=s29
sink(s.unquote(source("s30"), "quote")); // $ hasTaintFlow=s30
sink(s.map(source("s31"), (x) => {return x;})); // $ hasTaintFlow=s31
sink(s.strip(source("s32"),"charsToStrim")); // $ hasTaintFlow=s32
sink(s.lstrip(source("s33"),"charsToStrim")); // $ hasTaintFlow=s33
sink(s.rstrip(source("s34"),"charsToStrim")); // $ hasTaintFlow=s34
sink(s.camelcase(source("s35"))); // $ hasTaintFlow=s35
}
function strToArray() {
sink(s.chop(source("s1"), 3)); // $ MISSING: hasTaintFlow=s1
sink(s.chars(source("s2"))[0]); // $ hasTaintFlow=s2
sink(s.words(source("s3"))[0]); // $ hasTaintFlow=s3
sink(s.lines(source("s7"))[0]); // $ hasTaintFlow=s7
sink(s.chop(source("s1"), 3).length);
}
function arrayToStr() {
sink(s.toSentence([source("s1")])); // $ hasTaintFlow=s1
sink(s.toSentenceSerial([source("s2")])); // $ hasTaintFlow=s2
}
function multiSource() {
sink(s.insert("str", 4, source("s1"))); // $ hasTaintFlow=s1
sink(s.insert(source("s2"), 4, "")); // $ hasTaintFlow=s2
sink(s.replaceAll("astr", "a", source("s3"))); // $ hasTaintFlow=s3
sink(s.replaceAll(source("s4"), "a", "")); // $ hasTaintFlow=s4
sink(s.join(",", source("s5"), "str")); // $ hasTaintFlow=s5
sink(s.join(",", "str", source("s6"))); // $ hasTaintFlow=s6
sink(s.splice(source("s7"), 1, 2, "str")); // $ hasTaintFlow=s7
sink(s.splice("str", 1, 2, source("s8"))); // $ hasTaintFlow=s8
sink(s.prune(source("s9"), 1, "additional")); // $ hasTaintFlow=s9
sink(s.prune("base", 1, source("s10"))); // $ hasTaintFlow=s10
sink(s.pad(source("s11"), 10, "charsToPad", "right")); // $ hasTaintFlow=s11
sink(s.pad("base", 10, source("s12"), "right")); // $ hasTaintFlow=s12
sink(s.lpad(source("s13"), 10, "charsToPad")); // $ hasTaintFlow=s13
sink(s.lpad("base", 10, source("s14"))); // $ hasTaintFlow=s14
sink(s.rpad(source("s15"), 10, "charsToPad")); // $ hasTaintFlow=s15
sink(s.rpad("base", 10, source("s16"))); // $ hasTaintFlow=s16
sink(s.repeat(source("s17"), 3, "seperator")); // $ hasTaintFlow=s17
sink(s.repeat("base", 3, source("s18"))); // $ hasTaintFlow=s18
sink(s.surround(source("s19"), "wrap")); // $ hasTaintFlow=s19
sink(s.surround("base", source("s20"))); // $ hasTaintFlow=s20
sink(s.quote(source("s21"), "quote")); // $ hasTaintFlow=s21
sink(s.quote("base", source("s22"))); // $ hasTaintFlow=s22
sink(s.q(source("s23"), "quote")); // $ hasTaintFlow=s23
sink(s.q("base", source("s24"))); // $ hasTaintFlow=s24
sink(s.rjust(source("s25"), 10, "charsToPad")); // $ hasTaintFlow=s25
sink(s.rjust("base", 10, source("s26"))); // $ hasTaintFlow=s26
sink(s.ljust(source("s27"), 10, "charsToPad")); // $ hasTaintFlow=s27
sink(s.ljust("base", 10, source("s28"))); // $ hasTaintFlow=s28
}
function chaining() {
sink(s(source("s1"))
.slugify().capitalize().decapitalize().clean().cleanDiacritics()
.swapCase().escapeHTML().unescapeHTML().wrap().dedent()
.reverse().pred().succ().titleize().camelize().classify()
.underscored().dasherize().humanize().trim().ltrim().rtrim()
.truncate().sprintf().strRight().strRightBack()
.strLeft().strLeftBack().stripTags().unquote().value()); // $ hasTaintFlow=s1
sink(s(source("s2"))
.insert(4, source("s3")).replaceAll("a", source("s4"))
.join(",", source("s5")).splice(1, 2, source("s6"))
.prune(1, source("s7")).pad(10, source("s8"), "right")
.lpad(10, source("s9")).rpad(10, source("s10"))
.repeat(3, source("s11")).surround(source("s12"))
.quote(source("s13")).value()); // $ hasTaintFlow=s2 hasTaintFlow=s3 hasTaintFlow=s4 hasTaintFlow=s5 hasTaintFlow=s6 hasTaintFlow=s7 hasTaintFlow=s8 hasTaintFlow=s9 hasTaintFlow=s10 hasTaintFlow=s11 hasTaintFlow=s12 hasTaintFlow=s13
sink(s(source("s14")).toUpperCase().toLowerCase().replace().slice(1).substring(1).substr(1).concat(source("s15")).split()); // $ hasTaintFlow=s14 hasTaintFlow=s15
sink(s(source("s16"))
.strip().lstrip().rstrip().camelcase()
.q(source("s17")).ljust(10, source("s18"))
.rjust(10, source("s19"))); // $ hasTaintFlow=s16 hasTaintFlow=s17 hasTaintFlow=s18 hasTaintFlow=s19
sink(s(source("s20")).tap(function(value) {
return value + source("s21");
}).value()); // $ hasTaintFlow=s20 hasTaintFlow=s21
}
function mapTests(){
sink(s.map(source("s1"), (x) => {return x + source("s2");})); // $ hasTaintFlow=s1 hasTaintFlow=s2
s.map(source("s1"), (x) => { sink(x); return x;}); // $ hasTaintFlow=s1
}

View File

@@ -10,6 +10,9 @@ test_ClientRequest
| puppeteer.ts:6:11:6:42 | page.go ... e.com') |
| puppeteer.ts:8:5:8:61 | page.ad ... css" }) |
| puppeteer.ts:18:30:18:50 | page.go ... estUrl) |
| superagent.js:4:5:4:26 | superag ... ', url) |
| superagent.js:5:5:5:23 | superagent.del(url) |
| superagent.js:6:5:6:32 | superag ... st(url) |
| tst.js:11:5:11:16 | request(url) |
| tst.js:13:5:13:20 | request.get(url) |
| tst.js:15:5:15:23 | request.delete(url) |
@@ -91,9 +94,19 @@ test_ClientRequest
| tst.js:286:20:286:55 | new Web ... :8080') |
| tst.js:296:5:299:6 | axios({ ... \\n }) |
| tst.js:312:12:312:36 | fetchPo ... o/bar') |
| tst.js:319:5:319:26 | superag ... ', url) |
| tst.js:320:5:320:23 | superagent.del(url) |
| tst.js:321:5:321:32 | superag ... st(url) |
| tst.js:328:5:328:38 | got(und ... ptions) |
| tst.js:329:5:329:49 | got(und ... {url})) |
| tst.js:332:5:332:46 | got.ext ... ).get() |
| tst.js:334:5:334:25 | got.pag ... rl, {}) |
| tst.js:337:5:337:20 | jsonClient.get() |
| tst.js:340:5:340:21 | jsonClient2.get() |
test_getADataNode
| axiosTest.js:12:5:17:6 | axios({ ... \\n }) | axiosTest.js:15:18:15:55 | { 'Cont ... json' } |
| axiosTest.js:12:5:17:6 | axios({ ... \\n }) | axiosTest.js:16:15:16:35 | {x: 'te ... 'test'} |
| superagent.js:6:5:6:32 | superag ... st(url) | superagent.js:6:39:6:42 | data |
| tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data |
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 |
| tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:33:57:37 | data2 |
@@ -132,6 +145,7 @@ test_getADataNode
| tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:247:24:247:68 | request ... o.png') |
| tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:255:25:255:35 | 'new_value' |
| tst.js:286:20:286:55 | new Web ... :8080') | tst.js:288:21:288:35 | 'Hello Server!' |
| tst.js:321:5:321:32 | superag ... st(url) | tst.js:321:39:321:42 | data |
test_getHost
| tst.js:87:5:87:39 | http.ge ... host}) | tst.js:87:34:87:37 | host |
| tst.js:89:5:89:23 | axios({host: host}) | tst.js:89:18:89:21 | host |
@@ -154,6 +168,9 @@ test_getUrl
| puppeteer.ts:6:11:6:42 | page.go ... e.com') | puppeteer.ts:6:21:6:41 | 'https: ... le.com' |
| puppeteer.ts:8:5:8:61 | page.ad ... css" }) | puppeteer.ts:8:29:8:58 | "http:/ ... le.css" |
| puppeteer.ts:18:30:18:50 | page.go ... estUrl) | puppeteer.ts:18:40:18:49 | requestUrl |
| superagent.js:4:5:4:26 | superag ... ', url) | superagent.js:4:23:4:25 | url |
| superagent.js:5:5:5:23 | superagent.del(url) | superagent.js:5:20:5:22 | url |
| superagent.js:6:5:6:32 | superag ... st(url) | superagent.js:6:29:6:31 | url |
| tst.js:11:5:11:16 | request(url) | tst.js:11:13:11:15 | url |
| tst.js:13:5:13:20 | request.get(url) | tst.js:13:17:13:19 | url |
| tst.js:15:5:15:23 | request.delete(url) | tst.js:15:20:15:22 | url |
@@ -240,9 +257,23 @@ test_getUrl
| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:296:11:299:5 | {\\n ... ,\\n } |
| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:298:14:298:44 | "http:/ ... -axios" |
| tst.js:312:12:312:36 | fetchPo ... o/bar') | tst.js:312:26:312:35 | '/foo/bar' |
| tst.js:319:5:319:26 | superag ... ', url) | tst.js:319:23:319:25 | url |
| tst.js:320:5:320:23 | superagent.del(url) | tst.js:320:20:320:22 | url |
| tst.js:321:5:321:32 | superag ... st(url) | tst.js:321:29:321:31 | url |
| tst.js:328:5:328:38 | got(und ... ptions) | tst.js:327:34:327:36 | url |
| tst.js:328:5:328:38 | got(und ... ptions) | tst.js:328:9:328:17 | undefined |
| tst.js:329:5:329:49 | got(und ... {url})) | tst.js:329:9:329:17 | undefined |
| tst.js:329:5:329:49 | got(und ... {url})) | tst.js:329:44:329:46 | url |
| tst.js:334:5:334:25 | got.pag ... rl, {}) | tst.js:334:18:334:20 | url |
| tst.js:337:5:337:20 | jsonClient.get() | tst.js:336:41:336:43 | url |
| tst.js:340:5:340:21 | jsonClient2.get() | tst.js:339:42:339:44 | url |
| tst.js:340:5:340:21 | jsonClient2.get() | tst.js:339:61:339:63 | url |
test_getAResponseDataNode
| axiosTest.js:4:5:7:6 | axios({ ... \\n }) | axiosTest.js:4:5:7:6 | axios({ ... \\n }) | json | true |
| axiosTest.js:12:5:17:6 | axios({ ... \\n }) | axiosTest.js:12:5:17:6 | axios({ ... \\n }) | json | true |
| superagent.js:4:5:4:26 | superag ... ', url) | superagent.js:4:5:4:26 | superag ... ', url) | stream | true |
| superagent.js:5:5:5:23 | superagent.del(url) | superagent.js:5:5:5:23 | superagent.del(url) | stream | true |
| superagent.js:6:5:6:32 | superag ... st(url) | superagent.js:6:5:6:32 | superag ... st(url) | stream | true |
| tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true |
| tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true |
| tst.js:25:5:25:14 | axios(url) | tst.js:25:5:25:14 | axios(url) | | true |
@@ -314,3 +345,12 @@ test_getAResponseDataNode
| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:303:26:303:37 | err.response | json | false |
| tst.js:296:5:299:6 | axios({ ... \\n }) | tst.js:304:27:304:38 | err.response | json | false |
| tst.js:312:12:312:36 | fetchPo ... o/bar') | tst.js:312:12:312:36 | fetchPo ... o/bar') | fetch.response | true |
| tst.js:319:5:319:26 | superag ... ', url) | tst.js:319:5:319:26 | superag ... ', url) | stream | true |
| tst.js:320:5:320:23 | superagent.del(url) | tst.js:320:5:320:23 | superagent.del(url) | stream | true |
| tst.js:321:5:321:32 | superag ... st(url) | tst.js:321:5:321:32 | superag ... st(url) | stream | true |
| tst.js:328:5:328:38 | got(und ... ptions) | tst.js:328:5:328:38 | got(und ... ptions) | text | true |
| tst.js:329:5:329:49 | got(und ... {url})) | tst.js:329:5:329:49 | got(und ... {url})) | text | true |
| tst.js:332:5:332:46 | got.ext ... ).get() | tst.js:332:5:332:46 | got.ext ... ).get() | text | true |
| tst.js:334:5:334:25 | got.pag ... rl, {}) | tst.js:334:5:334:25 | got.pag ... rl, {}) | text | true |
| tst.js:337:5:337:20 | jsonClient.get() | tst.js:337:5:337:20 | jsonClient.get() | text | true |
| tst.js:340:5:340:21 | jsonClient2.get() | tst.js:340:5:340:21 | jsonClient2.get() | text | true |

View File

@@ -0,0 +1,7 @@
import { superagent } from "./superagentWrapper.js";
function test(url) {
superagent('GET', url);
superagent.del(url);
superagent.agent().post(url).send(data);
}

View File

@@ -0,0 +1,2 @@
import superagent from 'superagent';
export { superagent }

View File

@@ -314,3 +314,28 @@ function usePolyfill() {
return response.text()
})
}
function useSuperagent(url){
superagent('GET', url);
superagent.del(url);
superagent.agent().post(url).send(data);
}
import { Options } from 'got';
function gotTests(url){
const options = new Options({url});
got(undefined, undefined, options);
got(undefined, undefined, new Options({url}));
const options2 = new Options({url});
got.extend(options2).extend(options).get();
got.paginate(url, {});
const jsonClient = got.extend({url: url});
jsonClient.get();
const jsonClient2 = got.extend({url: url}).extend({url: url});
jsonClient2.get();
}

View File

@@ -1,4 +1,5 @@
#select
| apollo.serverSide.ts:8:39:8:64 | get(fil ... => {}) | apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:8:43:8:50 | file.url | The $@ of this request depends on a $@. | apollo.serverSide.ts:8:43:8:50 | file.url | URL | apollo.serverSide.ts:7:36:7:44 | { files } | user-provided value |
| serverSide.js:18:5:18:20 | request(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:18:13:18:19 | tainted | The $@ of this request depends on a $@. | serverSide.js:18:13:18:19 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
| serverSide.js:20:5:20:24 | request.get(tainted) | serverSide.js:14:29:14:35 | req.url | serverSide.js:20:17:20:23 | tainted | The $@ of this request depends on a $@. | serverSide.js:20:17:20:23 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
| serverSide.js:24:5:24:20 | request(options) | serverSide.js:14:29:14:35 | req.url | serverSide.js:23:19:23:25 | tainted | The $@ of this request depends on a $@. | serverSide.js:23:19:23:25 | tainted | URL | serverSide.js:14:29:14:35 | req.url | user-provided value |
@@ -24,6 +25,11 @@
| serverSide.js:125:5:128:6 | axios({ ... \\n }) | serverSide.js:123:29:123:35 | req.url | serverSide.js:127:14:127:20 | tainted | The $@ of this request depends on a $@. | serverSide.js:127:14:127:20 | tainted | URL | serverSide.js:123:29:123:35 | req.url | user-provided value |
| serverSide.js:131:5:131:20 | axios.get(myUrl) | serverSide.js:123:29:123:35 | req.url | serverSide.js:131:15:131:19 | myUrl | The $@ of this request depends on a $@. | serverSide.js:131:15:131:19 | myUrl | URL | serverSide.js:123:29:123:35 | req.url | user-provided value |
edges
| apollo.serverSide.ts:7:36:7:44 | files | apollo.serverSide.ts:8:13:8:17 | files | provenance | |
| apollo.serverSide.ts:7:36:7:44 | { files } | apollo.serverSide.ts:7:36:7:44 | files | provenance | |
| apollo.serverSide.ts:8:13:8:17 | files | apollo.serverSide.ts:8:28:8:31 | file | provenance | |
| apollo.serverSide.ts:8:28:8:31 | file | apollo.serverSide.ts:8:43:8:46 | file | provenance | |
| apollo.serverSide.ts:8:43:8:46 | file | apollo.serverSide.ts:8:43:8:50 | file.url | provenance | |
| serverSide.js:14:9:14:52 | tainted | serverSide.js:18:13:18:19 | tainted | provenance | |
| serverSide.js:14:9:14:52 | tainted | serverSide.js:20:17:20:23 | tainted | provenance | |
| serverSide.js:14:9:14:52 | tainted | serverSide.js:23:19:23:25 | tainted | provenance | |
@@ -73,6 +79,12 @@ edges
| serverSide.js:130:9:130:45 | myUrl | serverSide.js:131:15:131:19 | myUrl | provenance | |
| serverSide.js:130:37:130:43 | tainted | serverSide.js:130:9:130:45 | myUrl | provenance | |
nodes
| apollo.serverSide.ts:7:36:7:44 | files | semmle.label | files |
| apollo.serverSide.ts:7:36:7:44 | { files } | semmle.label | { files } |
| apollo.serverSide.ts:8:13:8:17 | files | semmle.label | files |
| apollo.serverSide.ts:8:28:8:31 | file | semmle.label | file |
| apollo.serverSide.ts:8:43:8:46 | file | semmle.label | file |
| apollo.serverSide.ts:8:43:8:50 | file.url | semmle.label | file.url |
| serverSide.js:14:9:14:52 | tainted | semmle.label | tainted |
| serverSide.js:14:19:14:42 | url.par ... , true) | semmle.label | url.par ... , true) |
| serverSide.js:14:29:14:35 | req.url | semmle.label | req.url |

View File

@@ -0,0 +1,27 @@
import { ApolloServer } from '@apollo/server';
import { get } from 'https';
function createApolloServer(typeDefs) {
const resolvers = {
Mutation: {
downloadFiles: async (_, { files }) => { // $ Source[js/request-forgery]
files.forEach((file) => { get(file.url, (res) => {}); }); // $ Alert[js/request-forgery] Sink[js/request-forgery]
return true;
},
},
};
const server = new ApolloServer({typeDefs, resolvers});
const resolvers2 = {
Mutation: {
downloadFiles: async (_, { files }) => { // $ MISSING: Source[js/request-forgery]
files.forEach((file) => { get(file.url, (res) => {}); }); // $ MISSING: Alert[js/request-forgery] Sink[js/request-forgery]
return true;
},
},
};
class CustomApollo extends ApolloServer {}
const srv = new CustomApollo({typeDefs, resolvers: resolvers2});
}

View File

@@ -64,4 +64,15 @@ class QlRefDocument extends YamlDocument {
value = n.lookup("postprocess").(YamlSequence).getElement(_)
)
}
predicate isPrintAst() {
this.getFile().getStem() = "PrintAst"
or
exists(YamlMapping n, YamlScalar value |
n.getDocument() = this and
value.getValue().matches("%PrintAst%")
|
value = n.lookup("query")
)
}
}

View File

@@ -11,5 +11,7 @@ import ql
import codeql_ql.ast.Yaml
from QlRefDocument f
where not f.usesInlineExpectations()
where
not f.usesInlineExpectations() and
not f.isPrintAst()
select f, "Query test does not use inline test expectations."

View File

@@ -0,0 +1 @@
| |

View File

@@ -0,0 +1 @@
dummy/PrintAst.ql

View File

@@ -0,0 +1 @@
| |

View File

@@ -0,0 +1 @@
query: dummy/PrintAst.ql

View File

@@ -0,0 +1 @@
select ""

View File

@@ -1,7 +1,7 @@
use lib::a_module::hello;
use lib::a_module::hello; // $ item=HELLO
mod a_module;
fn main() {
hello();
hello(); // $ item=HELLO
}

View File

@@ -1,3 +1,3 @@
pub fn hello() {
println!("Hello, world!");
}
} // HELLO

View File

@@ -0,0 +1 @@
import utils.test.PathResolutionInlineExpectationsTest

View File

@@ -2,14 +2,23 @@
"sysroot_src": "filled by the rust_project fixture",
"crates": [
{
"display_name": "exe",
"version": "0.1.0",
"root_module": "exe/src/main.rs",
"edition": "2021",
"deps": [{"crate": 1, "name": "lib"}]
"deps": [
{
"crate": 1,
"name": "lib"
}
]
},
{
"display_name": "lib",
"version": "0.1.0",
"root_module": "lib/src/lib.rs",
"edition": "2021",
"deps": []
}
]
}
}

View File

@@ -1,4 +1,4 @@
| Elements extracted | 87 |
| Elements extracted | 90 |
| Elements unextracted | 0 |
| Extraction errors | 0 |
| Extraction warnings | 0 |

View File

@@ -1,4 +1,4 @@
| Elements extracted | 87 |
| Elements extracted | 90 |
| Elements unextracted | 0 |
| Extraction errors | 0 |
| Extraction warnings | 0 |

View File

@@ -13,6 +13,7 @@ private import codeql.rust.elements.internal.generated.Crate
module Impl {
private import rust
private import codeql.rust.elements.internal.NamedCrate
private import codeql.rust.internal.PathResolution
class Crate extends Generated::Crate {
override string toStringImpl() {
@@ -58,6 +59,14 @@ module Impl {
*/
Crate getADependency() { result = this.getDependency(_) }
/** Gets the source file that defines this crate, if any. */
SourceFile getSourceFile() { result.getFile() = this.getModule().getFile() }
/**
* Gets a source file that belongs to this crate, if any.
*/
SourceFile getASourceFile() { result = this.(CrateItemNode).getASourceFile() }
override Location getLocation() { result = this.getModule().getLocation() }
}
}

View File

@@ -23,7 +23,7 @@ module Impl {
*/
class FieldExpr extends Generated::FieldExpr {
/** Gets the record field that this access references, if any. */
StructField getStructField() { result = TypeInference::resolveRecordFieldExpr(this) }
StructField getStructField() { result = TypeInference::resolveStructFieldExpr(this) }
/** Gets the tuple field that this access references, if any. */
TupleField getTupleField() { result = TypeInference::resolveTupleFieldExpr(this) }

View File

@@ -43,6 +43,6 @@ module Impl {
* Empty structs are considered to use record fields.
*/
pragma[nomagic]
predicate isRecord() { not this.isTuple() }
predicate isStruct() { not this.isTuple() }
}
}

View File

@@ -38,12 +38,12 @@ module Impl {
predicate isTuple() { this.getFieldList() instanceof TupleFieldList }
/**
* Holds if this variant uses record fields.
* Holds if this variant uses struct fields.
*
* Empty variants are considered to use record fields.
* Empty variants are considered to use struct fields.
*/
pragma[nomagic]
predicate isRecord() { not this.isTuple() }
predicate isStruct() { not this.isTuple() }
/** Gets the enum that this variant belongs to. */
Enum getEnum() { this = result.getVariantList().getAVariant() }

View File

@@ -73,7 +73,7 @@ final class Namespace extends TNamespace {
* - https://doc.rust-lang.org/reference/visibility-and-privacy.html
* - https://doc.rust-lang.org/reference/names/namespaces.html
*/
abstract class ItemNode extends AstNode {
abstract class ItemNode extends Locatable {
/** Gets the (original) name of this item. */
abstract string getName();
@@ -109,7 +109,11 @@ abstract class ItemNode extends AstNode {
/** Gets the immediately enclosing module (or source file) of this item. */
pragma[nomagic]
ModuleLikeNode getImmediateParentModule() { this = result.getAnItemInScope() }
ModuleLikeNode getImmediateParentModule() {
this = result.getAnItemInScope()
or
result = this.(SourceFileItemNode).getSuper()
}
pragma[nomagic]
private ItemNode getASuccessorRec(string name) {
@@ -122,6 +126,10 @@ abstract class ItemNode extends AstNode {
or
useImportEdge(this, name, result)
or
crateDefEdge(this, name, result)
or
crateDependencyEdge(this, name, result)
or
// items made available through `use` are available to nodes that contain the `use`
exists(UseItemNode use |
use = this.getASuccessorRec(_) and
@@ -168,19 +176,18 @@ abstract class ItemNode extends AstNode {
result = this.getASuccessorRec(name)
or
name = "super" and
if this instanceof Module
if this instanceof Module or this instanceof SourceFile
then result = this.getImmediateParentModule()
else result = this.getImmediateParentModule().getImmediateParentModule()
or
name = "self" and
not this instanceof Module and
result = this.getImmediateParentModule()
if this instanceof Module then result = this else result = this.getImmediateParentModule()
or
name = "Self" and
this = result.(ImplOrTraitItemNode).getAnItemInSelfScope()
or
name = "crate" and
result.(SourceFileItemNode).getFile() = this.getFile()
this = result.(CrateItemNode).getASourceFile()
}
/** Gets the location of this item. */
@@ -203,6 +210,11 @@ abstract private class ModuleLikeNode extends ItemNode {
}
private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
pragma[nomagic]
ModuleLikeNode getSuper() {
result = any(ModuleItemNode mod | fileImport(mod, this)).getASuccessor("super")
}
override string getName() { result = "(source file)" }
override Namespace getNamespace() {
@@ -211,6 +223,55 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
override Visibility getVisibility() { none() }
override predicate isPublic() { any() }
override TypeParam getTypeParam(int i) { none() }
}
class CrateItemNode extends ItemNode instanceof Crate {
/**
* Gets the module node that defines this crate.
*
* This is either a source file, when the crate is defined in source code,
* or a module, when the crate is defined in a dependency.
*/
pragma[nomagic]
ModuleLikeNode getModuleNode() {
result = super.getSourceFile()
or
not exists(super.getSourceFile()) and
result = super.getModule()
}
/**
* Gets a source file that belongs to this crate, if any.
*
* This is calculated as those source files that can be reached from the entry
* file of this crate using zero or more `mod` imports, without going through
* the entry point of some other crate.
*/
pragma[nomagic]
SourceFileItemNode getASourceFile() {
result = super.getSourceFile()
or
exists(SourceFileItemNode mid, Module mod |
mid = this.getASourceFile() and
mod.getFile() = mid.getFile() and
fileImport(mod, result) and
not result = any(Crate other).getSourceFile()
)
}
override string getName() { result = Crate.super.getName() }
override Namespace getNamespace() {
result.isType() // can be referenced with `crate`
}
override Visibility getVisibility() { none() }
override predicate isPublic() { any() }
override TypeParam getTypeParam(int i) { none() }
}
@@ -460,7 +521,7 @@ private class UseItemNode extends ItemNode instanceof Use {
override Namespace getNamespace() { none() }
override Visibility getVisibility() { none() }
override Visibility getVisibility() { result = Use.super.getVisibility() }
override TypeParam getTypeParam(int i) { none() }
}
@@ -586,11 +647,33 @@ private predicate fileImport(Module m, SourceFile f) {
* Holds if `mod` is a `mod name;` item targeting a file resulting in `item` being
* in scope under the name `name`.
*/
pragma[nomagic]
private predicate fileImportEdge(Module mod, string name, ItemNode item) {
item.isPublic() and
exists(SourceFile f |
exists(SourceFileItemNode f |
fileImport(mod, f) and
sourceFileEdge(f, name, item)
item = f.getASuccessor(name)
)
}
/**
* Holds if crate `c` defines the item `i` named `name`.
*/
pragma[nomagic]
private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
i = c.getModuleNode().getASuccessor(name) and
not i instanceof Crate
}
/**
* Holds if `m` depends on crate `dep` named `name`.
*/
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
exists(CrateItemNode c | dep = c.(Crate).getDependency(name) |
// entry module/entry source file
m = c.getModuleNode()
or
// entry/transitive source file
m = c.getASourceFile()
)
}
@@ -745,13 +828,53 @@ private predicate pathUsesNamespace(Path p, Namespace n) {
)
}
/** Gets the item that `path` resolves to, if any. */
cached
ItemNode resolvePath(RelevantPath path) {
pragma[nomagic]
private ItemNode resolvePath1(RelevantPath path) {
exists(Namespace ns | result = resolvePath0(path, ns) |
pathUsesNamespace(path, ns)
or
not pathUsesNamespace(path, _)
not pathUsesNamespace(path, _) and
not path = any(MacroCall mc).getPath()
)
}
pragma[nomagic]
private ItemNode resolvePathPrivate(
RelevantPath path, ModuleLikeNode itemParent, ModuleLikeNode pathParent
) {
result = resolvePath1(path) and
itemParent = result.getImmediateParentModule() and
not result.isPublic() and
(
pathParent.getADescendant() = path
or
pathParent = any(ItemNode mid | path = mid.getADescendant()).getImmediateParentModule()
)
}
/**
* Gets a module that has access to private items defined inside `itemParent`.
*
* According to [The Rust Reference][1] this is either `itemParent` itself or any
* descendant of `itemParent`.
*
* [1]: https://doc.rust-lang.org/reference/visibility-and-privacy.html#r-vis.access
*/
pragma[nomagic]
private ModuleLikeNode getAPrivateVisibleModule(ModuleLikeNode itemParent) {
exists(resolvePathPrivate(_, itemParent, _)) and
result.getImmediateParentModule*() = itemParent
}
/** Gets the item that `path` resolves to, if any. */
cached
ItemNode resolvePath(RelevantPath path) {
result = resolvePath1(path) and
result.isPublic()
or
exists(ModuleLikeNode itemParent, ModuleLikeNode pathParent |
result = resolvePathPrivate(path, itemParent, pathParent) and
pathParent = getAPrivateVisibleModule(itemParent)
)
}
@@ -831,3 +954,44 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
name != "_"
)
}
/** Provides predicates for debugging the path resolution implementation. */
private module Debug {
private Locatable getRelevantLocatable() {
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
filepath.matches("%/main.rs") and
startline = 1
)
}
predicate debugUnqualifiedPathLookup(RelevantPath p, string name, Namespace ns, ItemNode encl) {
p = getRelevantLocatable() and
unqualifiedPathLookup(p, name, ns, encl)
}
ItemNode debugResolvePath(RelevantPath path) {
path = getRelevantLocatable() and
result = resolvePath(path)
}
predicate debugUseImportEdge(Use use, string name, ItemNode item) {
use = getRelevantLocatable() and
useImportEdge(use, name, item)
}
ItemNode debugGetASuccessorRec(ItemNode i, string name) {
i = getRelevantLocatable() and
result = i.getASuccessor(name)
}
predicate debugFileImportEdge(Module mod, string name, ItemNode item) {
mod = getRelevantLocatable() and
fileImportEdge(mod, name, item)
}
predicate debugFileImport(Module m, SourceFile f) {
m = getRelevantLocatable() and
fileImport(m, f)
}
}

View File

@@ -7,6 +7,7 @@ private import PathResolution
/** Holds if `p` may resolve to multiple items including `i`. */
query predicate multiplePathResolutions(Path p, ItemNode i) {
p.fromSource() and
i = resolvePath(p) and
// `use foo::bar` may use both a type `bar` and a value `bar`
not p =

View File

@@ -29,7 +29,7 @@ abstract class Type extends TType {
pragma[nomagic]
abstract Function getMethod(string name);
/** Gets the record field `name` belonging to this type, if any. */
/** Gets the struct field `name` belonging to this type, if any. */
pragma[nomagic]
abstract StructField getStructField(string name);

View File

@@ -248,24 +248,24 @@ private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) {
}
/**
* A matching configuration for resolving types of record expressions
* A matching configuration for resolving types of struct expressions
* like `Foo { bar = baz }`.
*/
private module StructExprMatchingInput implements MatchingInputSig {
private newtype TPos =
TFieldPos(string name) { exists(any(Declaration decl).getField(name)) } or
TRecordPos()
TStructPos()
class DeclarationPosition extends TPos {
string asFieldPos() { this = TFieldPos(result) }
predicate isRecordPos() { this = TRecordPos() }
predicate isStructPos() { this = TStructPos() }
string toString() {
result = this.asFieldPos()
or
this.isRecordPos() and
result = "(record)"
this.isStructPos() and
result = "(struct)"
}
}
@@ -286,15 +286,15 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = tp.resolveTypeAt(path)
)
or
// type parameter of the record itself
dpos.isRecordPos() and
// type parameter of the struct itself
dpos.isStructPos() and
result = this.getTypeParameter(_) and
path = TypePath::singleton(result)
}
}
private class RecordStructDecl extends Declaration, Struct {
RecordStructDecl() { this.isRecord() }
private class StructDecl extends Declaration, Struct {
StructDecl() { this.isStruct() }
override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() }
@@ -304,14 +304,14 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = super.getDeclaredType(dpos, path)
or
// type of the struct itself
dpos.isRecordPos() and
dpos.isStructPos() and
path.isEmpty() and
result = TStruct(this)
}
}
private class RecordVariantDecl extends Declaration, Variant {
RecordVariantDecl() { this.isRecord() }
private class StructVariantDecl extends Declaration, Variant {
StructVariantDecl() { this.isStruct() }
Enum getEnum() { result.getVariantList().getAVariant() = this }
@@ -325,7 +325,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = super.getDeclaredType(dpos, path)
or
// type of the enum itself
dpos.isRecordPos() and
dpos.isStructPos() and
path.isEmpty() and
result = TEnum(this.getEnum())
}
@@ -342,7 +342,7 @@ private module StructExprMatchingInput implements MatchingInputSig {
result = this.getFieldExpr(apos.asFieldPos()).getExpr()
or
result = this and
apos.isRecordPos()
apos.isStructPos()
}
Type getInferredType(AccessPosition apos, TypePath path) {
@@ -360,8 +360,8 @@ private module StructExprMatchingInput implements MatchingInputSig {
private module StructExprMatching = Matching<StructExprMatchingInput>;
/**
* Gets the type of `n` at `path`, where `n` is either a record expression or
* a field expression of a record expression.
* Gets the type of `n` at `path`, where `n` is either a struct expression or
* a field expression of a struct expression.
*/
pragma[nomagic]
private Type inferStructExprType(AstNode n, TypePath path) {
@@ -777,7 +777,7 @@ private module FieldExprMatchingInput implements MatchingInputSig {
Declaration getTarget() {
// mutual recursion; resolving fields requires resolving types and vice versa
result = [resolveRecordFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)]
result = [resolveStructFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)]
}
}
@@ -921,10 +921,10 @@ private module Cached {
}
/**
* Gets the record field that the field expression `fe` resolves to, if any.
* Gets the struct field that the field expression `fe` resolves to, if any.
*/
cached
StructField resolveRecordFieldExpr(FieldExpr fe) {
StructField resolveStructFieldExpr(FieldExpr fe) {
exists(string name | result = getFieldExprLookupType(fe, name).getStructField(name))
}

View File

@@ -0,0 +1,48 @@
/**
* Provides an inline expectations test for path resolution.
*/
private import rust
private import codeql.rust.internal.PathResolution
private import codeql.rust.internal.TypeInference
private import utils.test.InlineExpectationsTest
private module ResolveTest implements TestSig {
string getARelevantTag() { result = "item" }
private predicate itemAt(ItemNode i, string filepath, int line, boolean inMacro) {
i.getLocation().hasLocationInfo(filepath, _, _, line, _) and
if i.(AstNode).isInMacroExpansion() then inMacro = true else inMacro = false
}
private predicate commmentAt(string text, string filepath, int line) {
exists(Comment c |
c.getLocation().hasLocationInfo(filepath, line, _, _, _) and
c.getCommentText() = text
)
}
private predicate item(ItemNode i, string value) {
exists(string filepath, int line, boolean inMacro | itemAt(i, filepath, line, inMacro) |
commmentAt(value, filepath, line) and inMacro = false
or
not (commmentAt(_, filepath, line) and inMacro = false) and
value = i.getName()
)
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(AstNode n |
not n = any(Path parent).getQualifier() and
location = n.getLocation() and
element = n.toString() and
tag = "item"
|
item(resolvePath(n), value)
or
item(n.(MethodCallExpr).getStaticTarget(), value)
)
}
}
import MakeTest<ResolveTest>

View File

@@ -59,6 +59,19 @@ private module Compare<ResolvableSig R, CompareSig<R> RustAnalyzer, CompareSig<R
predicate qlUniqueCount(int c) { c = count(Source s | qlUnique(s)) }
// debug predicates to find missing targets in QL implementation
private module Debug {
predicate qlMissing(Source s, Target t) {
t = RustAnalyzer::resolve(s) and
not t = Ql::resolve(s)
}
predicate qlMissingWithCount(Source s, Target t, int c) {
qlMissing(s, t) and
c = strictcount(Source s0 | qlMissing(s0, t))
}
}
predicate summary(string key, int value) {
key = "rust-analyzer unique" and rustAnalyzerUniqueCount(value)
or

View File

@@ -0,0 +1,3 @@
multipleStaticCallTargets
| regular.rs:29:5:29:9 | s.g(...) | anonymous.rs:15:9:15:22 | fn g |
| regular.rs:29:5:29:9 | s.g(...) | regular.rs:13:5:13:18 | fn g |

Some files were not shown because too many files have changed in this diff Show More