Compare commits
14 Commits
master
...
rule/S1312
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6612bf124d | ||
![]() |
b5cdf8c3e3 | ||
![]() |
704b46ff86 | ||
![]() |
644d73ed16 | ||
![]() |
3afe7c4b77 | ||
![]() |
7a4b34cebc | ||
![]() |
7724aa888d | ||
![]() |
262903cd6d | ||
![]() |
eca917f94f | ||
![]() |
1c7d4f739c | ||
![]() |
44cb8a6434 | ||
![]() |
95e52a6176 | ||
![]() |
3b318d3b25 | ||
![]() |
aed4db2f9a |
@ -1,4 +1,4 @@
|
||||
load("github.com/SonarSource/cirrus-modules@v3", "load_features")
|
||||
load("github.com/SonarSource/cirrus-modules@v2", "load_features")
|
||||
|
||||
def main(ctx):
|
||||
return load_features(ctx)
|
||||
|
41
.cirrus.yml
41
.cirrus.yml
@ -38,7 +38,9 @@ tooling_tests_task:
|
||||
env:
|
||||
PYTHONPATH: .
|
||||
install_dependencies_script:
|
||||
- ci/install_rspec_tools_dependencies.sh
|
||||
- cd rspec-tools
|
||||
- pipenv install --dev
|
||||
- pipenv run pip install pytest pytest-cov
|
||||
tests_script:
|
||||
- bash ci/fetch_branches.sh
|
||||
- cd rspec-tools
|
||||
@ -54,7 +56,7 @@ frontend_tests_task:
|
||||
<<: *CONTAINER_DEFINITION
|
||||
dockerfile: ci/frontend-tests-dockerfile
|
||||
cpu: 1
|
||||
memory: 3G
|
||||
memory: 2G
|
||||
node_modules_cache:
|
||||
folder: frontend/node_modules
|
||||
reupload_on_changes: false # since there is a fingerprint script
|
||||
@ -75,6 +77,15 @@ frontend_tests_task:
|
||||
- cd frontend
|
||||
- sonar-scanner
|
||||
|
||||
validate_metadata_task:
|
||||
eks_container:
|
||||
<<: *CONTAINER_DEFINITION
|
||||
dockerfile: ci/Dockerfile
|
||||
cpu: 1
|
||||
memory: 2G
|
||||
metadata_tests_script:
|
||||
- ./ci/validate_metadata.sh
|
||||
|
||||
validate_ci_tests_task:
|
||||
skip: "!changesInclude('ci_tests/**', 'ci/**')"
|
||||
eks_container:
|
||||
@ -85,22 +96,17 @@ validate_ci_tests_task:
|
||||
ci_tests_script:
|
||||
- ./ci_tests/asciidoc_validation/run_tests.sh
|
||||
|
||||
validate_rules_task:
|
||||
validate_asciidoc_task:
|
||||
eks_container:
|
||||
<<: *CONTAINER_DEFINITION
|
||||
dockerfile: ci/Dockerfile
|
||||
cpu: 1
|
||||
memory: 2G
|
||||
metadata_validation_script:
|
||||
- ./ci/validate_metadata.sh
|
||||
file_extensions_validation_script:
|
||||
- ./ci/validate_file_extensions.sh
|
||||
asciidoc_validation_script:
|
||||
asciidoc_tests_script:
|
||||
- ./ci/validate_asciidoc.sh
|
||||
|
||||
validate_links_task:
|
||||
timeout_in: 120m
|
||||
execution_lock: RSPEC_validate_links
|
||||
eks_container:
|
||||
<<: *CONTAINER_DEFINITION
|
||||
dockerfile: ci/Dockerfile
|
||||
@ -111,20 +117,31 @@ validate_links_task:
|
||||
LINK_CACHE_PATH: /root/link-probing-history.cache
|
||||
cache_download_script:
|
||||
- bash ci/cirrus-cache.sh download ${LINK_CACHE_NAME} ${LINK_CACHE_PATH}
|
||||
- md5sum /root/link-probing-history.cache/link_probes.history || true
|
||||
tests_script:
|
||||
- md5sum /root/link-probing-history.cache/link_probes.history || true
|
||||
- ./ci/validate_links.sh ${LINK_CACHE_PATH}
|
||||
- md5sum /root/link-probing-history.cache/link_probes.history
|
||||
always:
|
||||
cache_upload_script:
|
||||
- md5sum /root/link-probing-history.cache/link_probes.history || true
|
||||
- bash ci/cirrus-cache.sh upload ${LINK_CACHE_NAME} ${LINK_CACHE_PATH}
|
||||
|
||||
validate_file_extensions_task:
|
||||
eks_container:
|
||||
<<: *CONTAINER_DEFINITION
|
||||
dockerfile: ci/Dockerfile
|
||||
cpu: 1
|
||||
memory: 2G
|
||||
file_extension_tests_script:
|
||||
- bash ./ci/validate_file_extensions.sh
|
||||
|
||||
all_required_checks_task:
|
||||
depends_on:
|
||||
- tooling_tests
|
||||
- frontend_tests
|
||||
- validate_rules
|
||||
- validate_metadata
|
||||
- validate_asciidoc
|
||||
- validate_ci_tests
|
||||
- validate_file_extensions
|
||||
eks_container:
|
||||
<<: *CONTAINER_DEFINITION
|
||||
dockerfile: ci/Dockerfile
|
||||
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"build": {
|
||||
"dockerfile": "../ci/Dockerfile"
|
||||
},
|
||||
// https://code.visualstudio.com/docs/devcontainers/create-dev-container#_rebuild
|
||||
"postCreateCommand": ".devcontainer/finalize-container.sh",
|
||||
"waitFor": "postCreateCommand",
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"extensions": [
|
||||
"ms-python.python",
|
||||
"asciidoctor.asciidoctor-vscode"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
TOP_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &> /dev/null && pwd)/..
|
||||
|
||||
$TOP_DIR/ci/install_rspec_tools_dependencies.sh
|
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@ -1 +1 @@
|
||||
.github/CODEOWNERS @sonarsource/quality-cfamily-squad
|
||||
.github/CODEOWNERS @SonarSource/languages-team-cfamily
|
||||
|
9
.github/pull_request_template.md
vendored
9
.github/pull_request_template.md
vendored
@ -1,12 +1,3 @@
|
||||
<!--
|
||||
Jira Automation:
|
||||
|
||||
* Mention existing issue in the PR title to move it around automatically.
|
||||
* Mention existing issue in the PR description and a sub-task will be created for you to track this rspec PR separately.
|
||||
|
||||
No issue is created by default.
|
||||
-->
|
||||
|
||||
## Review
|
||||
|
||||
A dedicated reviewer checked the rule description successfully for:
|
||||
|
28
.github/workflows/PullRequestClosed.yml
vendored
28
.github/workflows/PullRequestClosed.yml
vendored
@ -1,28 +0,0 @@
|
||||
name: Pull Request Closed
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
PullRequestMerged_job:
|
||||
name: Pull Request Merged
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
pull-requests: read
|
||||
# For external PR, ticket should be moved manually
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- id: secrets
|
||||
uses: SonarSource/vault-action-wrapper@v3
|
||||
with:
|
||||
secrets: |
|
||||
development/kv/data/jira user | JIRA_USER;
|
||||
development/kv/data/jira token | JIRA_TOKEN;
|
||||
- uses: sonarsource/gh-action-lt-backlog/PullRequestClosed@v2
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
jira-user: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_USER }}
|
||||
jira-token: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_TOKEN }}
|
28
.github/workflows/PullRequestCreated.yml
vendored
28
.github/workflows/PullRequestCreated.yml
vendored
@ -1,28 +0,0 @@
|
||||
name: Pull Request Created
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: ["opened"]
|
||||
|
||||
jobs:
|
||||
PullRequestCreated_job:
|
||||
name: Pull Request Created
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
# For external PR, ticket should be created manually
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- id: secrets
|
||||
uses: SonarSource/vault-action-wrapper@v3
|
||||
with:
|
||||
secrets: |
|
||||
development/github/token/{REPO_OWNER_NAME_DASH}-jira token | GITHUB_TOKEN;
|
||||
development/kv/data/jira user | JIRA_USER;
|
||||
development/kv/data/jira token | JIRA_TOKEN;
|
||||
- uses: sonarsource/gh-action-lt-backlog/PullRequestCreated@v2
|
||||
with:
|
||||
github-token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}
|
||||
jira-user: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_USER }}
|
||||
jira-token: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_TOKEN }}
|
28
.github/workflows/RequestReview.yml
vendored
28
.github/workflows/RequestReview.yml
vendored
@ -1,28 +0,0 @@
|
||||
name: Request review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: ["review_requested"]
|
||||
|
||||
jobs:
|
||||
RequestReview_job:
|
||||
name: Request review
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
# For external PR, ticket should be moved manually
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
steps:
|
||||
- id: secrets
|
||||
uses: SonarSource/vault-action-wrapper@v3
|
||||
with:
|
||||
secrets: |
|
||||
development/github/token/{REPO_OWNER_NAME_DASH}-jira token | GITHUB_TOKEN;
|
||||
development/kv/data/jira user | JIRA_USER;
|
||||
development/kv/data/jira token | JIRA_TOKEN;
|
||||
- uses: sonarsource/gh-action-lt-backlog/RequestReview@v2
|
||||
with:
|
||||
github-token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}
|
||||
jira-user: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_USER }}
|
||||
jira-token: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_TOKEN }}
|
30
.github/workflows/SubmitReview.yml
vendored
30
.github/workflows/SubmitReview.yml
vendored
@ -1,30 +0,0 @@
|
||||
name: Submit Review
|
||||
|
||||
on:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
SubmitReview_job:
|
||||
name: Submit Review
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write
|
||||
pull-requests: read
|
||||
# For external PR, ticket should be moved manually
|
||||
if: |
|
||||
github.event.pull_request.head.repo.full_name == github.repository
|
||||
&& (github.event.review.state == 'changes_requested'
|
||||
|| github.event.review.state == 'approved')
|
||||
steps:
|
||||
- id: secrets
|
||||
uses: SonarSource/vault-action-wrapper@v3
|
||||
with:
|
||||
secrets: |
|
||||
development/kv/data/jira user | JIRA_USER;
|
||||
development/kv/data/jira token | JIRA_TOKEN;
|
||||
- uses: sonarsource/gh-action-lt-backlog/SubmitReview@v2
|
||||
with:
|
||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||
jira-user: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_USER }}
|
||||
jira-token: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_TOKEN }}
|
3
.github/workflows/add_language.yml
vendored
3
.github/workflows/add_language.yml
vendored
@ -15,9 +15,6 @@ on:
|
||||
jobs:
|
||||
add_language_to_rule:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
3
.github/workflows/create_new_rspec.yml
vendored
3
.github/workflows/create_new_rspec.yml
vendored
@ -12,9 +12,6 @@ on:
|
||||
jobs:
|
||||
create_new_rule:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
20
.github/workflows/ensure_label.yml
vendored
20
.github/workflows/ensure_label.yml
vendored
@ -1,20 +0,0 @@
|
||||
name: PR should have a language label
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, labeled, unlabeled, synchronize]
|
||||
|
||||
jobs:
|
||||
label:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- uses: mheap/github-action-required-labels@v5
|
||||
with:
|
||||
mode: minimum
|
||||
count: 1
|
||||
add_comment: true
|
||||
use_regex: true
|
||||
labels: ".*"
|
||||
message: "Please add a label with the relevant language(s) to be able to merge this PR"
|
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
permissions:
|
||||
pull-requests: read # Get the list and metadata of open new-rule PRs
|
||||
contents: write # Get the contents of open new-rule PRs, the 'master'; write to 'gh-pages' branch
|
||||
|
105
.github/workflows/update_coverage.yml
vendored
105
.github/workflows/update_coverage.yml
vendored
@ -1,35 +1,21 @@
|
||||
name: Update rule coverage
|
||||
on:
|
||||
schedule:
|
||||
- cron: '17 2 * * *'
|
||||
workflow_dispatch: # When manually triggered from a non-default branch, the results will not be pushed
|
||||
- cron: '17 0 * * *'
|
||||
|
||||
jobs:
|
||||
update_coverage:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
id-token: write # required by SonarSource/vault-action-wrapper
|
||||
contents: write
|
||||
actions: write # required by andymckay/cancel-action
|
||||
env:
|
||||
TMP_BRANCH: temporary/coverage_update
|
||||
|
||||
steps:
|
||||
- name: 'get secrets'
|
||||
id: secrets
|
||||
uses: SonarSource/vault-action-wrapper@v3
|
||||
with:
|
||||
secrets: |
|
||||
development/github/token/SonarSource-rspec-coverage token | coverage_github_token;
|
||||
development/kv/data/slack token | slack_token;
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: true
|
||||
fetch-depth: 0
|
||||
ref: master
|
||||
path: 'rspec'
|
||||
token: ${{ fromJSON(steps.secrets.outputs.vault).coverage_github_token }}
|
||||
ref: 'master'
|
||||
token: ${{ secrets.COVERAGE_GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
@ -45,7 +31,7 @@ jobs:
|
||||
|
||||
- name: 'Regenerate coverage information'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).coverage_github_token }}
|
||||
GITHUB_TOKEN: ${{ secrets.COVERAGE_GITHUB_TOKEN }}
|
||||
id: gen-coverage
|
||||
working-directory: 'rspec/rspec-tools'
|
||||
run: |
|
||||
@ -73,69 +59,46 @@ jobs:
|
||||
git commit -m "update coverage information"
|
||||
git push --force-with-lease origin $TMP_BRANCH
|
||||
|
||||
- name: 'Create a PR'
|
||||
id: create-github-pr
|
||||
working-directory: 'rspec'
|
||||
env:
|
||||
GH_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).coverage_github_token }}
|
||||
run: |
|
||||
PR_URL=$(gh pr create --head ${{ env.TMP_BRANCH }} --title "Update coverage information" --body "" --label "rspec system")
|
||||
gh pr merge $PR_URL
|
||||
- name: 'Wait for CI to succeed'
|
||||
if: steps.gen-coverage.outputs.new_coverage == 'true'
|
||||
uses: fountainhead/action-wait-for-check@v1.0.0
|
||||
id: wait-for-build
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
checkName: all_required_checks
|
||||
ref: ${{ env.TMP_BRANCH }}
|
||||
timeoutSeconds: 2400
|
||||
intervalSeconds: 30
|
||||
|
||||
- name: 'Wait until the PR is merged'
|
||||
id: wait-for-pr-to-merge
|
||||
env:
|
||||
GH_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).coverage_github_token }}
|
||||
- name: 'Push the updated coverage to master'
|
||||
if: |
|
||||
steps.gen-coverage.outputs.new_coverage == 'true' &&
|
||||
steps.wait-for-build.outputs.conclusion == 'success'
|
||||
working-directory: 'rspec'
|
||||
run: |
|
||||
set -ueo pipefail
|
||||
git checkout master
|
||||
git merge $TMP_BRANCH
|
||||
git push origin master
|
||||
|
||||
# Implicitly referring to the PR corresponding to current branch
|
||||
- name: 'Delete the temporary branch'
|
||||
if: always() && steps.create-temp-branch.conclusion == 'success'
|
||||
uses: dawidd6/action-delete-branch@v3
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN}}
|
||||
branches: ${{ env.TMP_BRANCH}}
|
||||
|
||||
# Set timeout (20 minutes in seconds)
|
||||
TIMEOUT=1200 # seconds
|
||||
START_TIME=$(date +%s)
|
||||
INTERVAL=20 # seconds
|
||||
|
||||
while true; do
|
||||
# Check if the PR is merged
|
||||
PR_STATE=$(gh pr view --json state,mergedAt -q '.state')
|
||||
MERGED_AT=$(gh pr view --json state,mergedAt -q '.mergedAt')
|
||||
|
||||
if [[ "${PR_STATE}" == "MERGED" ]]; then
|
||||
echo "PR merged at: $MERGED_AT"
|
||||
exit 0
|
||||
fi
|
||||
echo "PR state is ${PR_STATE}"
|
||||
|
||||
# Check for timeout
|
||||
CURRENT_TIME=$(date +%s)
|
||||
ELAPSED_TIME=$((CURRENT_TIME - START_TIME))
|
||||
|
||||
if [[ "${ELAPSED_TIME}" -gt "${TIMEOUT}" ]]; then
|
||||
echo "Timeout waiting for PR to merge."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait for $INTERVAL seconds before checking again
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
|
||||
- name: 'Close PR and delete branch upon failure to merge'
|
||||
if: ${{ failure() }}
|
||||
env:
|
||||
GH_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).coverage_github_token }}
|
||||
working-directory: 'rspec'
|
||||
run: |
|
||||
PR_URL=$(gh pr view --json url --jq '.url')
|
||||
gh pr close "$PR_URL" --delete-branch
|
||||
- name: 'Fail if the change breaks CI'
|
||||
if: |
|
||||
steps.gen-coverage.outputs.new_coverage == 'true' &&
|
||||
steps.wait-for-build.outputs.conclusion != 'success'
|
||||
run: exit 1
|
||||
|
||||
- name: 'Notify on slack about the failure'
|
||||
if: ${{ failure() }}
|
||||
env:
|
||||
SLACK_API_TOKEN: ${{ fromJSON(steps.secrets.outputs.vault).slack_token }}
|
||||
SLACK_API_TOKEN: ${{ secrets.SLACK_API_TOKEN }}
|
||||
working-directory: 'rspec/rspec-tools'
|
||||
run: |
|
||||
pipenv run rspec-tools notify-failure-on-slack \
|
||||
--message "ERROR: failed to update rule coverage. See https://github.com/SonarSource/rspec/actions/runs/$GITHUB_RUN_ID" \
|
||||
--channel team-analysis-rspec
|
||||
--channel team-lang-rspec-v2
|
||||
|
5
.github/workflows/update_quickfix_status.yml
vendored
5
.github/workflows/update_quickfix_status.yml
vendored
@ -25,10 +25,7 @@ on:
|
||||
jobs:
|
||||
update_quickfix_status:
|
||||
name: Update quick fix status
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-20.04
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
steps:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,7 +10,6 @@
|
||||
# generated files
|
||||
/rules/**/*.html
|
||||
/frontend/public/rules
|
||||
rspec-tools/link_probes.history
|
||||
|
||||
# compiled files
|
||||
*.out
|
||||
|
275
LICENSE
275
LICENSE
@ -1,184 +1,165 @@
|
||||
SONAR Source-Available License v1.0
|
||||
Last Updated November 13, 2024
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
1. DEFINITIONS
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
"Agreement" means this Sonar Source-Available License v1.0
|
||||
|
||||
"Competing" means marketing a product or service as a substitute for the
|
||||
functionality or value of SonarQube. A product or service may compete regardless
|
||||
of how it is designed or deployed. For example, a product or service may compete
|
||||
even if it provides its functionality via any kind of interface (including
|
||||
services, libraries, or plug-ins), even if it is ported to a different platform
|
||||
or programming language, and even if it is provided free of charge.
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
"Contribution" means:
|
||||
0. Additional Definitions.
|
||||
|
||||
a) in the case of the initial Contributor, the initial content Distributed under
|
||||
this Agreement, and
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
b) in the case of each subsequent Contributor:
|
||||
i) changes to the Program, and
|
||||
ii) additions to the Program;
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
where such changes and/or additions to the Program originate from and are
|
||||
Distributed by that particular Contributor. A Contribution "originates" from a
|
||||
Contributor if it was added to the Program by such Contributor itself or anyone
|
||||
acting on such Contributor's behalf. Contributions do not include changes or
|
||||
additions to the Program that are not Modified Works.
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
"Contributor" means any person or entity that Distributes the Program.
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source Code or other form,
|
||||
that is based on (or derived from) the Program and for which the editorial
|
||||
revisions, annotations, elaborations, or other modifications represent, as a
|
||||
whole, an original work of authorship.
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
"Distribute" means the acts of a) distributing or b) making available in any
|
||||
manner that enables the transfer of a copy.
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
"Licensed Patents" mean patent claims licensable by a Contributor that are
|
||||
necessarily infringed by the use or sale of its Contribution alone or when
|
||||
combined with the Program.
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
"Modified Works" shall mean any work in Source Code or other form that results
|
||||
from an addition to, deletion from, or modification of the contents of the
|
||||
Program, including, for purposes of clarity, any new file in Source Code form
|
||||
that contains any contents of the Program. Modified Works shall not include
|
||||
works that contain only declarations, interfaces, types, classes, structures, or
|
||||
files of the Program solely in each case in order to link to, bind by name, or
|
||||
subclass the Program or Modified Works thereof.
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
"Non-competitive Purpose" means any purpose except for (a) providing to others
|
||||
any product or service that includes or offers the same or substantially similar
|
||||
functionality as SonarQube, (b) Competing with SonarQube, and/or (c) employing,
|
||||
using, or engaging artificial intelligence technology that is not part of the
|
||||
Program to ingest, interpret, analyze, train on, or interact with the data
|
||||
provided by the Program, or to engage with the Program in any manner.
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
"Notices" means any legal statements or attributions included with the Program,
|
||||
including, without limitation, statements concerning copyright, patent,
|
||||
trademark, disclaimers of warranty, or limitations of liability
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
"Program" means the Contributions Distributed in accordance with this Agreement.
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
"Recipient" means anyone who receives the Program under this Agreement,
|
||||
including Contributors.
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
"SonarQube" means an open-source or commercial edition of software offered by
|
||||
SonarSource that is branded "SonarQube".
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
"SonarSource" means SonarSource SA, a Swiss company registered in Switzerland
|
||||
under UID No. CHE-114.587.664.
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
"Source Code" means the form of a Program preferred for making modifications,
|
||||
including but not limited to software source code, documentation source, and
|
||||
configuration files.
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
2. GRANT OF RIGHTS
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
a) Subject to the terms of this Agreement, each Contributor hereby grants
|
||||
Recipient a non-exclusive, worldwide, royalty-free copyright license, for any
|
||||
Non-competitive Purpose, to reproduce, prepare Derivative Works of, publicly
|
||||
display, publicly perform, Distribute and sublicense the Contribution of such
|
||||
Contributor, if any, and such Derivative Works.
|
||||
4. Combined Works.
|
||||
|
||||
b) Subject to the terms of this Agreement, each Contributor hereby grants
|
||||
Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed
|
||||
Patents, for any Non-competitive Purpose, to make, use, sell, offer to sell,
|
||||
import, and otherwise transfer the Contribution of such Contributor, if any, in
|
||||
Source Code or other form. This patent license shall apply to the combination of
|
||||
the Contribution and the Program if, at the time the Contribution is added by
|
||||
the Contributor, such addition of the Contribution causes such combination to be
|
||||
covered by the Licensed Patents. The patent license shall not apply to any other
|
||||
combinations that include the Contribution.
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
c) Recipient understands that although each Contributor grants the licenses to
|
||||
its Contributions set forth herein, no assurances are provided by any
|
||||
Contributor that the Program does not infringe the patent or other intellectual
|
||||
property rights of any other entity. Each Contributor disclaims any liability to
|
||||
Recipient for claims brought by any other entity based on infringement of
|
||||
intellectual property rights or otherwise. As a condition to exercising the
|
||||
rights and licenses granted hereunder, each Recipient hereby assumes sole
|
||||
responsibility to secure any other intellectual property rights needed, if any.
|
||||
For example, if a third-party patent license is required to allow Recipient to
|
||||
Distribute the Program, it is Recipient's responsibility to acquire that license
|
||||
before distributing the Program.
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
d) Each Contributor represents that to its knowledge it has sufficient copyright
|
||||
rights in its Contribution, if any, to grant the copyright license set forth in
|
||||
this Agreement.
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
3. REQUIREMENTS
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
3.1 If a Contributor Distributes the Program in any form, then the Program must
|
||||
also be made available as Source Code, in accordance with section 3.2, and the
|
||||
Contributor must accompany the Program with a statement that the Source Code for
|
||||
the Program is available under this Agreement, and inform Recipients how to
|
||||
obtain it in a reasonable manner on or through a medium customarily used for
|
||||
software exchange; and
|
||||
d) Do one of the following:
|
||||
|
||||
3.2 When the Program is Distributed as Source Code:
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
a) it must be made available under this Agreement, and
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
b) a copy of this Agreement must be included with each copy of the Program.
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
3.3 Contributors may not remove or alter any Notices contained within the
|
||||
Program from any copy of the Program which they Distribute, provided that
|
||||
Contributors may add their own appropriate Notices.
|
||||
5. Combined Libraries.
|
||||
|
||||
4. NO WARRANTY
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
|
||||
OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
|
||||
LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
|
||||
responsible for determining the appropriateness of using and distributing the
|
||||
Program and assumes all risks associated with its exercise of rights under this
|
||||
Agreement, including but not limited to the risks and costs of program errors,
|
||||
compliance with applicable laws, damage to or loss of data, programs or
|
||||
equipment, and unavailability or interruption of operations.
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
5. DISCLAIMER OF LIABILITY
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
|
||||
THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGES.
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
6. GENERAL
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
If any provision of this Agreement is invalid or unenforceable under applicable
|
||||
law, it shall not affect the validity or enforceability of the remainder of the
|
||||
terms of this Agreement, and without further action by the parties hereto, such
|
||||
provision shall be reformed to the minimum extent necessary to make such
|
||||
provision valid and enforceable.
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If Recipient institutes patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Program itself
|
||||
(excluding combinations of the Program with other software or hardware)
|
||||
infringes such Recipient’s patent(s), then such Recipient’s rights granted under
|
||||
Section 2(b) shall terminate as of the date such litigation is filed.
|
||||
|
||||
All Recipient’s rights under this Agreement shall terminate if it fails to
|
||||
comply with any of the material terms or conditions of this Agreement and does
|
||||
not cure such failure in a reasonable period of time after becoming aware of
|
||||
such noncompliance. If all Recipient’s rights under this Agreement terminate,
|
||||
Recipient agrees to cease use and distribution of the Program as soon as
|
||||
reasonably practicable. However, Recipient’s obligations under this Agreement
|
||||
and any licenses granted by Recipient relating to the Program shall continue and
|
||||
survive.
|
||||
|
||||
Except as expressly stated in Sections 2(a) and 2(b) above, Recipient receives
|
||||
no rights or licenses to the intellectual property of any Contributor under this
|
||||
Agreement, whether expressly, by implication, estoppel, or otherwise. All rights
|
||||
in the Program not expressly granted under this Agreement are reserved. Nothing
|
||||
in this Agreement is intended to be enforceable by any entity that is not a
|
||||
Contributor or Recipient. No third-party beneficiary rights are created under
|
||||
this Agreement.
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
|
@ -8,8 +8,6 @@ This repository contains the specification of every static-analysis rule availab
|
||||
|
||||
It also contains rules which have been dropped and rules which will one day be implemented.
|
||||
|
||||
The content of this repository is covered by the link:LICENSE[SONAR Source-Available License v1.0].
|
||||
|
||||
== Rules directory structure
|
||||
|
||||
* https://github.com/SonarSource/rspec/tree/master/rules[rules] directory: contains every specified rule.
|
||||
|
@ -7,10 +7,10 @@ RUN apt-get update && \
|
||||
ca-certificates gnupg && \
|
||||
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | \
|
||||
gpg --dearmor -o /etc/apt/nodesource-keyring.gpg && \
|
||||
echo "deb [signed-by=/etc/apt/nodesource-keyring.gpg] https://deb.nodesource.com/node_20.x nodistro main" \
|
||||
echo "deb [signed-by=/etc/apt/nodesource-keyring.gpg] https://deb.nodesource.com/node_16.x nodistro main" \
|
||||
> /etc/apt/sources.list.d/nodesource.list && \
|
||||
apt-get update && \
|
||||
apt-get -y install nodejs && \
|
||||
apt-get install nodejs && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
|
@ -6,38 +6,38 @@ ACTION=${1}
|
||||
CACHE_NAME=${2}
|
||||
PATH_TO_CACHE=${3}
|
||||
|
||||
CACHE_URL="http://${CIRRUS_HTTP_CACHE_HOST}/${CACHE_NAME}"
|
||||
CACHE_KEY=${CACHE_NAME}
|
||||
DEFAULT_CACHE_KEY=${CACHE_NAME}
|
||||
|
||||
TMP_PATH="/tmp/tmp-cache.tgz"
|
||||
CACHE_URL=http://${CIRRUS_HTTP_CACHE_HOST}/${CACHE_KEY}
|
||||
|
||||
TMP_PATH=/tmp/tmp-cache.tgz
|
||||
|
||||
case "${ACTION}" in
|
||||
|
||||
download)
|
||||
echo "Download cache with key ${CACHE_NAME} from ${CACHE_URL}"
|
||||
curl --silent --show-error --fail --location --output "${TMP_PATH}" "${CACHE_URL}" || {
|
||||
echo "Cache download failed" >&2
|
||||
exit 0
|
||||
echo "Download cache with key ${CACHE_KEY}"
|
||||
|
||||
echo " -> try ${CACHE_URL}"
|
||||
curl -sfSL -o ${TMP_PATH} ${CACHE_URL} || {
|
||||
echo "Cache download failed";
|
||||
exit 0;
|
||||
}
|
||||
du -hs "${TMP_PATH}"
|
||||
tar -Pxzf "${TMP_PATH}"
|
||||
rm "${TMP_PATH}"
|
||||
du -hs ${TMP_PATH}
|
||||
tar -Pxzf ${TMP_PATH}
|
||||
rm ${TMP_PATH}
|
||||
;;
|
||||
|
||||
upload)
|
||||
echo "Upload cache to ${CACHE_URL}"
|
||||
tar -Pczf "${TMP_PATH}" "${PATH_TO_CACHE}"
|
||||
du -hs "${TMP_PATH}"
|
||||
curl --silent --show-error -X POST --data-binary "@${TMP_PATH}" "${CACHE_URL}" || {
|
||||
echo "Cache upload failed" >&2
|
||||
exit 0
|
||||
}
|
||||
tar -Pczf ${TMP_PATH} ${PATH_TO_CACHE}
|
||||
du -hs ${TMP_PATH}
|
||||
curl -s -X POST --data-binary @${TMP_PATH} ${CACHE_URL}
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unexpected cache ACTION: ${ACTION}" >&2
|
||||
echo "Unexpected cache ACTION: ${ACTION}"
|
||||
exit 1
|
||||
;;
|
||||
|
||||
esac
|
||||
|
||||
echo "Cache ${ACTION}ed succeeded."
|
||||
|
@ -1,3 +1,3 @@
|
||||
FROM public.ecr.aws/docker/library/node:20.9.0
|
||||
FROM public.ecr.aws/docker/library/node:16.20.2
|
||||
|
||||
CMD ["bash"]
|
||||
|
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
cd rspec-tools
|
||||
pipenv install --dev
|
||||
pipenv run pip install pytest pytest-cov
|
0
ci/validate_file_extensions.sh
Executable file → Normal file
0
ci/validate_file_extensions.sh
Executable file → Normal file
@ -13,20 +13,17 @@ else
|
||||
git diff --name-only "${base}" -- rules/ | # Get all the changes in rules
|
||||
sed -Ee 's#(rules/S[0-9]+)/.*#\1#' | # extract the rule directories
|
||||
sort -u | # deduplicate
|
||||
while IFS= read -r rule; do if [[ -d "$rule" ]]; then echo "$rule"; fi done | # filter out deleted rules
|
||||
while IFS= read -r rule; do [[ -d "$rule" ]] && echo "$rule" || true; done | # filter non-deleted rules
|
||||
sed 's#rules/##' | # get rule ids
|
||||
mapfile -t affected_rules # store them in the `affected_rules` array
|
||||
echo "Validating ${affected_rules[*]}"
|
||||
echo "Validating ${affected_rules[@]}"
|
||||
fi
|
||||
|
||||
printf '\n\n\n'
|
||||
|
||||
# Validate metadata
|
||||
if [[ "${#affected_rules[@]}" -gt 0 ]]
|
||||
then
|
||||
cd rspec-tools
|
||||
pipenv install
|
||||
printf '\n\n\n'
|
||||
pipenv run rspec-tools validate-rules-metadata "${affected_rules[@]}"
|
||||
else
|
||||
echo "No rule changed or added"
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
== In the RSPEC
|
||||
|
||||
The rule status (`/status` in the metadata) should be set to `deprecated`, and its tags should be removed. If the rule is in `SonarWay`, it should be removed from this profile.
|
||||
The rule status (`/status` in the metadata) should be set to `deprecated`.
|
||||
|
||||
Optionally, `/extra/replacementRules` can list the rules that replace this rule.
|
||||
|
||||
|
@ -271,24 +271,6 @@ tsql:: use `sql`
|
||||
|
||||
In case no language is appropriate for a code block (for example shared examples between multiple languages), you can use `text` as the language.
|
||||
|
||||
=== Comments within code blocks
|
||||
|
||||
Colon (`:`) should be used as separator between `Noncompliant`/`Compliant` comments and the text explanation that follows, if any.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
int X = 2; // Noncompliant: variable should be in lowercase
|
||||
----
|
||||
|
||||
|
||||
When referencing a name within a comment in a code example, use double quotes to make it clear it refers to an existing element in the code.
|
||||
|
||||
[source,cpp]
|
||||
----
|
||||
int i = 0;
|
||||
cout << noexcept(++i); // Noncompliant: "i" is not incremented
|
||||
----
|
||||
|
||||
=== Diff view
|
||||
|
||||
Additionally, you can also use two attributes to let the products know your code examples should be highlighted with a diff view when possible
|
||||
|
@ -1,15 +1,11 @@
|
||||
// Ansible
|
||||
// C#
|
||||
* ASP.NET
|
||||
* ASP.NET Core
|
||||
* ASP.NET MVC 4.x
|
||||
* Razor
|
||||
* .NET
|
||||
* Entity Framework Core
|
||||
* Dapper
|
||||
* BouncyCastle
|
||||
* Jwt.Net
|
||||
* Blazor
|
||||
// C-Family
|
||||
* Botan
|
||||
* CryptoPP
|
||||
@ -26,49 +22,35 @@
|
||||
* Xerces
|
||||
* libxml2
|
||||
// Java
|
||||
* Android
|
||||
* Android WebView
|
||||
* Apache Commons
|
||||
* Apache Commons
|
||||
* Apache Commons Email
|
||||
* Apache HttpClient
|
||||
* Auth0 JWT
|
||||
* Commons Compiler
|
||||
* Dom4j
|
||||
* FasterXML
|
||||
* Groovy
|
||||
* Gson
|
||||
* Hibernate
|
||||
* Java Cryptography Extension
|
||||
* Java EE
|
||||
* Java JWT
|
||||
* Java SE
|
||||
* Java JDBC API
|
||||
* Java I/O API
|
||||
* Jdom2
|
||||
* JSP
|
||||
* Legacy Mongo Java API
|
||||
* OkHttp
|
||||
* Realm
|
||||
* Apache HttpClient
|
||||
* Couchbase
|
||||
* SAX
|
||||
* Servlet
|
||||
* Spring
|
||||
* Spring Data MongoDB
|
||||
* Spring Data Cassandra
|
||||
* Spring Data Redis
|
||||
* Spring Data Neo4j
|
||||
* SQLCipher
|
||||
* Thymeleaf
|
||||
* Java SE
|
||||
* Java EE
|
||||
* Hibernate
|
||||
* Apache Commons
|
||||
* Commons Compiler
|
||||
* Legacy Mongo Java API
|
||||
* FasterXML
|
||||
* Gson
|
||||
* Android
|
||||
* Dom4j
|
||||
* Jdom2
|
||||
* OkHttp
|
||||
* Java JWT
|
||||
* Auth0 JWT
|
||||
* Apache Commons Email
|
||||
* SQLCipher
|
||||
* Realm
|
||||
* Java Cryptography Extension
|
||||
* Apache HttpClient
|
||||
// JS
|
||||
* Jasmine
|
||||
* Jest
|
||||
* Flow.js
|
||||
* Node.js
|
||||
* Express.js
|
||||
* SSH2
|
||||
* Mocha
|
||||
* MongoDB
|
||||
* Mongoose
|
||||
* Sequelize
|
||||
@ -83,7 +65,6 @@
|
||||
* TypeScript
|
||||
* PropTypes
|
||||
* JSX
|
||||
* Electron
|
||||
// PHP
|
||||
* Core PHP
|
||||
* Guzzle
|
||||
@ -95,10 +76,7 @@
|
||||
// Python
|
||||
* aiohttp
|
||||
* Amazon DynamoDB
|
||||
* Argon2-cffi
|
||||
* Bcrypt
|
||||
* Cryptodome
|
||||
* databases
|
||||
* Django
|
||||
* Django Templates
|
||||
* FastAPI
|
||||
@ -107,7 +85,6 @@
|
||||
* Jinja
|
||||
* lxml
|
||||
* MySQL Connector/Python
|
||||
* Numpy
|
||||
* Paramiko
|
||||
* pyca
|
||||
* PyCrypto
|
||||
@ -119,15 +96,10 @@
|
||||
* python-ldap
|
||||
* Python SQLite
|
||||
* Python Standard Library
|
||||
* PyTorch
|
||||
* PyYAML
|
||||
* Requests
|
||||
* Scrypt
|
||||
* Scikit-Learn
|
||||
* SignXML
|
||||
* SQLAlchemy
|
||||
* ssl
|
||||
* TensorFlow
|
||||
// Docker
|
||||
* Wget
|
||||
// Cloudformation
|
||||
@ -142,8 +114,7 @@
|
||||
// Terraform
|
||||
* AWS API Gateway
|
||||
* AWS OpenSearch
|
||||
* Azure Databases
|
||||
* Azure Storage Accounts
|
||||
* Azure MSSQL
|
||||
* GCP Load Balancers
|
||||
* AWS Identity and Access Management
|
||||
// CDK
|
||||
@ -153,7 +124,7 @@
|
||||
* CryptoSwift
|
||||
* IDZSwiftCommonCrypto
|
||||
// Azure resource manager
|
||||
* JSON templates
|
||||
* ARM templates
|
||||
* Bicep
|
||||
// PL/SQL
|
||||
* DBMS_CRYPTO
|
||||
@ -161,5 +132,3 @@
|
||||
* Go Standard Library
|
||||
// Kubernetes
|
||||
* Helm
|
||||
// Kotlin
|
||||
Jetpack Compose
|
||||
|
@ -45,7 +45,6 @@ When web pages have massively long names like "Java™ Platform, Standard Editio
|
||||
* AWS blog - https://aws.amazon.com/blogs
|
||||
* Azure Documentation - https://learn.microsoft.com/en-us/azure/?product=popular
|
||||
* CERT - https://wiki.sei.cmu.edu/confluence/display/seccode
|
||||
* Clippy Lints - https://rust-lang.github.io/rust-clippy/master/index.html
|
||||
* {cpp} reference - https://en.cppreference.com/w/
|
||||
* {cpp} Core Guidelines - https://github.com/isocpp/CppCoreGuidelines/blob/e49158a/CppCoreGuidelines.md
|
||||
* CVE - https://cve.mitre.org
|
||||
|
@ -40,6 +40,6 @@ You can update the quickfix field using this GitHub Workflow: https://github.com
|
||||
|
||||
The code field is an object that contains information related to the clean code taxonomy. It is an object with two required properties:
|
||||
|
||||
* `impacts`: A nested object that is treated as a mapping from a software quality to a level (`"INFO"`, `"LOW"`, `"MEDIUM"`, `"HIGH"` or `"BLOCKER"`). Note that at least one software quality has to be specified. The current list of allowed software qualities is `"MAINTAINABILITY"`, `"RELIABILITY"` and `"SECURITY"`.
|
||||
* `impacts`: A nested object that is treated as a mapping from a software quality to a level (`"LOW"`, `"MEDIUM"` or `"HIGH"`). Note that at least one software quality has to be specified. The current list of allowed software qualities is `"MAINTAINABILITY"`, `"RELIABILITY"` and `"SECURITY"`.
|
||||
|
||||
* `attribute`: A single clean code attribute that the rule aims to achieve. This has to be one of the following values: `"FORMATTED"`, `"CONVENTIONAL"`, `"IDENTIFIABLE"`, `"CLEAR"`, `"LOGICAL"`, `"COMPLETE"`, `"EFFICIENT"`, `"FOCUSED"`, `"DISTINCT"`, `"MODULAR"`, `"TESTED"`, `"LAWFUL"`, `"TRUSTWORTHY"`, `"RESPECTFUL"`.
|
||||
|
@ -109,17 +109,3 @@ Use it when referencing variable names, file names, tokens, and all kinds of spe
|
||||
Write:: Compiling source file `src/generic_file.py` breaks an `assert` call in pytest framework.
|
||||
Avoid:: Compiling source file "src/generic_file.py" breaks an `assert` call in `pytest` framework.
|
||||
|
||||
== Referencing elements from the code
|
||||
|
||||
When referencing elements from the code within a normal sentence, use the `backticks` (```) to format it. This includes variable names, function names, class names, and so on.
|
||||
|
||||
When referencing the same elements within a comment in a code block, surrpond it with double quotes.
|
||||
[source,cpp]
|
||||
----
|
||||
int i = 0;
|
||||
// Write
|
||||
cout << noexcept(++i); // Noncompliant, "i" is not incremented -> Double quotes
|
||||
// Avoid
|
||||
cout << noexcept(++i); // Noncompliant, i is not incremented -> No quotes
|
||||
cout << noexcept(++i); // Noncompliant, `i` is not incremented -> Backticks
|
||||
----
|
||||
|
@ -1,50 +0,0 @@
|
||||
|
||||
= Search page for the rule repository
|
||||
|
||||
This is a single-page React application that indexes the rule repository and
|
||||
allows you to run flexible search through all of the rules and rule drafts,
|
||||
and render the rule specifications in HTML.
|
||||
The render is not guaranteed to match the rule rendering in the products,
|
||||
but it is a good proxy.
|
||||
|
||||
== Local deployment
|
||||
|
||||
Make sure you have NodeJs and `npm` available. Tested with NPM v10.2.3 and NodeJS v18.19.0.
|
||||
|
||||
Install dependencies
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
npm install
|
||||
----
|
||||
|
||||
If you have some non-js dependencies missing, this might fail.
|
||||
Possibly missing non-js dependencies include OpenSSL, libuv, libssh2, KRB5.
|
||||
|
||||
Once you succeed in installing the dependencies you are ready to predeploy.
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
npm run predeploy
|
||||
----
|
||||
|
||||
This command builds the database of the rule specifications.
|
||||
|
||||
NOTE: If the script fails to clone or fetch due to an SSL certificate failure
|
||||
and your network uses a custom CA certificate you might need to make sure it is installed
|
||||
in the accessible place.
|
||||
As a workaround you can https://github.com/nodegit/nodegit/issues/1742[disable the certificate check].
|
||||
|
||||
NOTE: In the predeploy step (specifically the `prepare-rules` part of it) the script fetches all the open PRs locally.
|
||||
You might want to set `GITHUB_TOKEN` to your personal GitHub token
|
||||
to avoid GitHub throttling your requests during the predeploy stage.
|
||||
|
||||
|
||||
Now you can run it locally:
|
||||
|
||||
[source,shell]
|
||||
----
|
||||
npm start
|
||||
----
|
||||
|
||||
This should open https://localhost:3000/rspec in your default browser with the rule search page.
|
52
frontend/README.md
Normal file
52
frontend/README.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||
|
||||
The page will reload if you make edits.\
|
||||
You will also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run predeploy`
|
||||
|
||||
Custom command to build the search index.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
||||
|
||||
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
||||
|
||||
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
**Note:** To easily use the `npm` commands on Windows, you can use VSCode with a `npm` support extension.
|
18473
frontend/package-lock.json
generated
18473
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@
|
||||
"html-react-parser": "^1.4.14",
|
||||
"lunr": "^2.3.9",
|
||||
"node-html-parser": "^5.4.2",
|
||||
"nodegit": "^0.28.0-alpha.24",
|
||||
"nodegit": "^0.27.0",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-highlight": "^0.14.0",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,6 @@ import Typography from '@material-ui/core/Typography';
|
||||
import Tabs from '@material-ui/core/Tabs';
|
||||
import Tab from '@material-ui/core/Tab';
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Tooltip from '@material-ui/core/Tooltip';
|
||||
import { createTheme, Link, ThemeProvider } from '@material-ui/core';
|
||||
import Highlight from 'react-highlight';
|
||||
import { Link as RouterLink, useHistory } from 'react-router-dom';
|
||||
@ -14,7 +13,6 @@ import { RULE_STATE, useRuleCoverage } from './utils/useRuleCoverage';
|
||||
import { useFetch } from './utils/useFetch';
|
||||
import RuleMetadata, { Version, Coverage } from './types/RuleMetadata';
|
||||
import parse, { attributesToProps, domToReact, DOMNode, Element } from 'html-react-parser';
|
||||
import VisibilityOffOutlinedIcon from '@material-ui/icons/VisibilityOffOutlined';
|
||||
|
||||
import './hljs-humanoid-light.css';
|
||||
|
||||
@ -147,9 +145,8 @@ type UsedStyles = ReturnType<typeof useStyles>;
|
||||
const languageToJiraProject = new Map(Object.entries({
|
||||
'PYTHON': 'SONARPY',
|
||||
'ABAP': 'SONARABAP',
|
||||
'AZURE_RESOURCE_MANAGER': 'SONARIAC',
|
||||
'AZURERESOURCEMANAGER': 'SONARIAC',
|
||||
'CFAMILY': 'CPP',
|
||||
'DART': 'DART',
|
||||
'DOCKER': 'SONARIAC',
|
||||
'JAVA': 'SONARJAVA',
|
||||
'JCL': 'SONARJCL',
|
||||
@ -158,42 +155,38 @@ const languageToJiraProject = new Map(Object.entries({
|
||||
'HTML': 'SONARHTML',
|
||||
'PHP': 'SONARPHP',
|
||||
'PLI': 'SONARPLI',
|
||||
'PLSQL': 'PLSQL',
|
||||
'PLSQL': 'SONARPLSQL',
|
||||
'RPG': 'SONARRPG',
|
||||
'APEX': 'SONARAPEX',
|
||||
'RUBY': 'SONARRUBY',
|
||||
'RUST': 'SKUNK',
|
||||
'APEX': 'SONARSLANG',
|
||||
'RUBY': 'SONARSLANG',
|
||||
'KOTLIN': 'SONARKT',
|
||||
'SCALA': 'SONARSCALA',
|
||||
'GO': 'SONARGO',
|
||||
'SECRETS': 'SONARTEXT',
|
||||
'SCALA': 'SONARSLANG',
|
||||
'GO': 'SONARSLANG',
|
||||
'SECRETS': 'SECRETS',
|
||||
'SWIFT': 'SONARSWIFT',
|
||||
'TSQL': 'TSQL',
|
||||
'VB6': 'VB6',
|
||||
'TSQL': 'SONARTSQL',
|
||||
'VB6': 'SONARVBSIX',
|
||||
'XML': 'SONARXML',
|
||||
'CLOUDFORMATION': 'SONARIAC',
|
||||
'TERRAFORM': 'SONARIAC',
|
||||
'KUBERNETES': 'SONARIAC',
|
||||
'TEXT': 'SONARTEXT',
|
||||
'ANSIBLE': 'SONARIAC',
|
||||
}));
|
||||
|
||||
const languageToGithubProject = new Map(Object.entries({
|
||||
'ABAP': 'sonar-abap',
|
||||
'AZURE_RESOURCE_MANAGER': 'sonar-iac',
|
||||
'AZURERESOURCEMANAGER': 'sonar-iac',
|
||||
'CSHARP': 'sonar-dotnet',
|
||||
'DART': 'sonar-dart',
|
||||
'DOCKER': 'sonar-iac',
|
||||
'VBNET': 'sonar-dotnet',
|
||||
'JAVASCRIPT': 'SonarJS',
|
||||
'TYPESCRIPT': 'SonarJS',
|
||||
'SWIFT': 'sonar-swift',
|
||||
'KOTLIN': 'sonar-kotlin',
|
||||
'GO': 'sonar-go',
|
||||
'SCALA': 'sonar-scala',
|
||||
'RUBY': 'sonar-ruby',
|
||||
'RUST': 'sonar-rust',
|
||||
'APEX': 'sonar-apex',
|
||||
'GO': 'slang-enterprise',
|
||||
'SCALA': 'slang-enterprise',
|
||||
'RUBY': 'slang-enterprise',
|
||||
'APEX': 'slang-enterprise',
|
||||
'HTML': 'sonar-html',
|
||||
'COBOL': 'sonar-cobol',
|
||||
'VB6': 'sonar-vb',
|
||||
@ -212,9 +205,8 @@ const languageToGithubProject = new Map(Object.entries({
|
||||
'CLOUDFORMATION': 'sonar-iac',
|
||||
'TERRAFORM': 'sonar-iac',
|
||||
'KUBERNETES': 'sonar-iac',
|
||||
'SECRETS': 'sonar-text',
|
||||
'SECRETS': 'sonar-secrets',
|
||||
'TEXT': 'sonar-text',
|
||||
'ANSIBLE': 'sonar-iac-enterprise',
|
||||
}));
|
||||
|
||||
function ticketsAndImplementationPRsLinks(ruleNumber: string, title: string, language?: string) {
|
||||
@ -264,7 +256,6 @@ interface PageMetadata {
|
||||
prUrl: string | undefined;
|
||||
branch: string;
|
||||
coverage: Coverage;
|
||||
isInQualityProfile: boolean;
|
||||
jsonString: string | undefined;
|
||||
}
|
||||
|
||||
@ -275,7 +266,6 @@ function usePageMetadata(ruleid: string, language: string, classes: UsedStyles):
|
||||
let coverage: Coverage = 'Loading...';
|
||||
let title = 'Loading...';
|
||||
let avoid = false;
|
||||
let isInQualityProfile = false;
|
||||
let metadataJSONString;
|
||||
let languagesTabs = null;
|
||||
let prUrl: string | undefined = undefined;
|
||||
@ -315,7 +305,6 @@ function usePageMetadata(ruleid: string, language: string, classes: UsedStyles):
|
||||
} else {
|
||||
coverage = allLangsRuleCoverage(metadataJSON.allKeys, coverageMapper);
|
||||
}
|
||||
isInQualityProfile = metadataJSON.defaultQualityProfiles.length > 0;
|
||||
}
|
||||
|
||||
if (coverage !== 'Not Covered') {
|
||||
@ -330,7 +319,6 @@ function usePageMetadata(ruleid: string, language: string, classes: UsedStyles):
|
||||
prUrl,
|
||||
branch,
|
||||
coverage,
|
||||
isInQualityProfile,
|
||||
jsonString: metadataJSONString
|
||||
};
|
||||
}
|
||||
@ -433,10 +421,7 @@ export function RulePage(props: any) {
|
||||
|
||||
<RuleThemeProvider>
|
||||
<Container maxWidth="md">
|
||||
<h1>
|
||||
{metadata.isInQualityProfile ? <></> : <><Tooltip title="Not in any Quality Profile"><VisibilityOffOutlinedIcon /></Tooltip> </>}
|
||||
{metadata.title}
|
||||
</h1>
|
||||
<h1>{metadata.title}</h1>
|
||||
<hr />
|
||||
<Box className={classes.coverage}>
|
||||
<h2>Covered Since</h2>
|
||||
|
@ -2217,18 +2217,7 @@ exports[`renders closed rule S1007 1`] = `
|
||||
class="MuiContainer-root MuiContainer-maxWidthMd"
|
||||
>
|
||||
<h1>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="MuiSvgIcon-root"
|
||||
focusable="false"
|
||||
title="Not in any Quality Profile"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M12 6c3.79 0 7.17 2.13 8.82 5.5-.59 1.22-1.42 2.27-2.41 3.12l1.41 1.41c1.39-1.23 2.49-2.77 3.18-4.53C21.27 7.11 17 4 12 4c-1.27 0-2.49.2-3.64.57l1.65 1.65C10.66 6.09 11.32 6 12 6zm-1.07 1.14L13 9.21c.57.25 1.03.71 1.28 1.28l2.07 2.07c.08-.34.14-.7.14-1.07C16.5 9.01 14.48 7 12 7c-.37 0-.72.05-1.07.14zM2.01 3.87l2.68 2.68C3.06 7.83 1.77 9.53 1 11.5 2.73 15.89 7 19 12 19c1.52 0 2.98-.29 4.32-.82l3.42 3.42 1.41-1.41L3.42 2.45 2.01 3.87zm7.5 7.5l2.61 2.61c-.04.01-.08.02-.12.02-1.38 0-2.5-1.12-2.5-2.5 0-.05.01-.08.01-.13zm-3.4-3.4l1.75 1.75c-.23.55-.36 1.15-.36 1.78 0 2.48 2.02 4.5 4.5 4.5.63 0 1.23-.13 1.77-.36l.98.98c-.88.24-1.8.38-2.75.38-3.79 0-7.17-2.13-8.82-5.5.7-1.43 1.72-2.61 2.93-3.53z"
|
||||
/>
|
||||
</svg>
|
||||
When the absolute positioning of bits representing a bit-field is required, then the behaviour and packing of bit-fields shall be documented
|
||||
When the absolute positioning of bits representing a bit-field is required, then the behaviour and packing of bit-fields shall be documented
|
||||
</h1>
|
||||
<hr />
|
||||
<div
|
||||
|
@ -31,7 +31,7 @@ export async function process_incomplete_rspecs(tmpRepoDir: string,
|
||||
const repo = await (() => {
|
||||
if (!fs.existsSync(path.join(tmpRepoDir, '.git'))) {
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
return Git.Clone.clone(`https://${process.env.GITHUB_TOKEN}@github.com/SonarSource/rspec/`, tmpRepoDir);
|
||||
return Git.Clone.clone('https://' + process.env.GITHUB_TOKEN + '@github.com/SonarSource/rspec/', tmpRepoDir);
|
||||
} else {
|
||||
return Git.Clone.clone('https://github.com/SonarSource/rspec/', tmpRepoDir);
|
||||
}
|
||||
|
@ -16,6 +16,5 @@ export default interface RuleMetadata {
|
||||
languagesSupport: LanguageSupport[],
|
||||
allKeys: string[],
|
||||
branch: string,
|
||||
defaultQualityProfiles: string[],
|
||||
prUrl?: string
|
||||
}
|
||||
|
@ -6,11 +6,10 @@ type RuleCoverage = Record<string, Record<string, Version>>;
|
||||
const languageToSonarpedia = new Map<string, string[]>(Object.entries({
|
||||
'abap': ['ABAP'],
|
||||
'apex': ['APEX'],
|
||||
'azureresourcemanager': ['AZURE_RESOURCE_MANAGER'],
|
||||
'azureresourcemanager': ['AZURERESOURCEMANAGER'],
|
||||
'cfamily': ['CPP', 'C', 'OBJC'],
|
||||
'cobol': ['COBOL'],
|
||||
'csharp': ['CSH'],
|
||||
'dart': ['DART'],
|
||||
'docker': ['DOCKER'],
|
||||
'vbnet': ['VBNET'],
|
||||
'css': ['CSS'],
|
||||
@ -27,7 +26,6 @@ const languageToSonarpedia = new Map<string, string[]>(Object.entries({
|
||||
'plsql': ['PLSQL'],
|
||||
'python': ['PY'],
|
||||
'rpg': ['RPG'],
|
||||
'rust': ['RUST'],
|
||||
'secrets': ['SECRETS'],
|
||||
'swift': ['SWIFT'],
|
||||
'tsql': ['TSQL'],
|
||||
@ -38,8 +36,7 @@ const languageToSonarpedia = new Map<string, string[]>(Object.entries({
|
||||
'cloudformation': ['CLOUDFORMATION'],
|
||||
'terraform': ['TERRAFORM'],
|
||||
'kubernetes': ['KUBERNETES'],
|
||||
'text': ['TEXT'],
|
||||
'ansible': ['ANSIBLE']
|
||||
'text': ['TEXT']
|
||||
}));
|
||||
|
||||
export function useRuleCoverage() {
|
||||
|
@ -17,8 +17,8 @@ slackclient = "*"
|
||||
[dev-packages]
|
||||
pytest = ">=6.2.2"
|
||||
mypy = ">=0.800"
|
||||
pytest-snapshot = "*"
|
||||
rspec-tools = {file = ".", editable = true}
|
||||
pytest-snapshot = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
|
@ -55,5 +55,5 @@ In order to generate an HTML file from the ASCIIdoc, you can use [asciidoctor](h
|
||||
|
||||
[source,sh]
|
||||
----
|
||||
$ asciidoctor rule.adoc
|
||||
$ asciidoctor -e rule.adoc
|
||||
----
|
||||
|
@ -1,56 +0,0 @@
|
||||
{
|
||||
"title": "SECRET_TYPE should not be disclosed",
|
||||
"type": "VULNERABILITY",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"SECURITY": "BLOCKER"
|
||||
},
|
||||
"attribute": "TRUSTWORTHY"
|
||||
},
|
||||
"status": "beta",
|
||||
"remediation": {
|
||||
"func": "Constant\/Issue",
|
||||
"constantCost": "30min"
|
||||
},
|
||||
"tags": [
|
||||
"cwe",
|
||||
"cert"
|
||||
],
|
||||
"defaultSeverity": "Blocker",
|
||||
"ruleSpecification": "RSPEC-${RSPEC_ID}",
|
||||
"sqKey": "S${RSPEC_ID}",
|
||||
"scope": "All",
|
||||
"securityStandards": {
|
||||
"CWE": [
|
||||
798,
|
||||
259
|
||||
],
|
||||
"OWASP": [
|
||||
"A3"
|
||||
],
|
||||
"CERT": [
|
||||
"MSC03-J."
|
||||
],
|
||||
"OWASP Top 10 2021": [
|
||||
"A7"
|
||||
],
|
||||
"PCI DSS 3.2": [
|
||||
"6.5.10"
|
||||
],
|
||||
"PCI DSS 4.0": [
|
||||
"6.2.4"
|
||||
],
|
||||
"ASVS 4.0": [
|
||||
"2.10.4",
|
||||
"3.5.2",
|
||||
"6.4.1"
|
||||
],
|
||||
"STIG ASD_V5R3": [
|
||||
"V-222642"
|
||||
]
|
||||
},
|
||||
"defaultQualityProfiles": [
|
||||
"Sonar way"
|
||||
],
|
||||
"quickfix": "unknown"
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
:example_env: ENV_VAR_NAME
|
||||
:example_name: java-property-name
|
||||
:example_secret: example_secret_value
|
||||
|
||||
// Set value that can be used to refer to the type of secret in, for example:
|
||||
// "An attacker can use this {secret_type} to ..."
|
||||
// Commonly used values: access token, api key, application secret, application key or consumer key, service password, OAuth token, deployment password
|
||||
:secret_type: secret
|
||||
|
||||
include::../../../shared_content/secrets/description.adoc[]
|
||||
|
||||
== Why is this an issue?
|
||||
|
||||
include::../../../shared_content/secrets/rationale.adoc[]
|
||||
|
||||
=== What is the potential impact?
|
||||
|
||||
// Optional: Give a general description of the secret and what it's used for.
|
||||
|
||||
include::../../../shared_content/secrets/impact/generic_impact.adoc[]
|
||||
|
||||
// Uncomment the following line, if specifying detailed impacts from below (also make sure to have new lines around the uncommented includes):
|
||||
// include::../../../shared_content/secrets/impact/specific_impact_intro.adoc[]
|
||||
|
||||
// Secret may allow hosting arbitrary files
|
||||
// include::../../../shared_content/secrets/impact/malware_distribution.adoc[]
|
||||
|
||||
// Secret may allow accessing or compromising sensitive data
|
||||
// include::../../../shared_content/secrets/impact/data_compromise.adoc[]
|
||||
|
||||
// Secret may allow uploading artifacts to services used elsewhere in the supply chain
|
||||
// This is specific for code and artifact repositories
|
||||
// include::../../../shared_content/secrets/impact/supply_chain_attack.adoc[]
|
||||
|
||||
// Secret may be used to trigger workflows
|
||||
// This is webhook-specific
|
||||
// include::../../../shared_content/secrets/impact/codeless_vulnerability_chaining.adoc[]
|
||||
|
||||
// OAuth tokens may allow accessing 3rd party services
|
||||
// include::../../../shared_content/secrets/impact/oauth_token_compromise.adoc[]
|
||||
|
||||
// Mailing service compromise may allow sending spam, which may result in account termination
|
||||
// include::../../../shared_content/secrets/impact/suspicious_activities_termination.adoc[]
|
||||
|
||||
// Sensitive information leak / identity impersonation, e.g., through leaked signing secret
|
||||
// include::../../../shared_content/secrets/impact/security_downgrade.adoc[]
|
||||
|
||||
// Audit trail discrepancies
|
||||
// include::../../../shared_content/secrets/impact/non_repudiation.adoc[]
|
||||
|
||||
// Package repository secrets may allow access to source code etc.
|
||||
// include::../../../shared_content/secrets/impact/source_code_compromise.adoc[]
|
||||
|
||||
// Spamming automated calls may cause large bills and rate limited service access
|
||||
// include::../../../shared_content/secrets/impact/exceed_rate_limits.adoc[]
|
||||
|
||||
// For blockchain specific tokens
|
||||
// include::../../../shared_content/secrets/impact/blockchain_data_exposure.adoc[]
|
||||
|
||||
// Specific for banking / financial transaction tokens, causing financial loss
|
||||
// include::../../../shared_content/secrets/impact/banking_financial_loss.adoc[]
|
||||
|
||||
// Secret can be used to send spam or phish users
|
||||
// include::../../../shared_content/secrets/impact/phishing.adoc[]
|
||||
|
||||
// Secret may allow modifying application data (object stores etc.)
|
||||
// include::../../../shared_content/secrets/impact/data_modification.adoc[]
|
||||
|
||||
// Specific to services that are used to share PII (personal infos, chat logs, ..)
|
||||
// include::../../../shared_content/secrets/impact/personal_data_compromise.adoc[]
|
||||
|
||||
// Secret may allow accessing financial data, like CC information or confidential financial reports
|
||||
// include::../../../shared_content/secrets/impact/disclosure_of_financial_data.adoc[]
|
||||
|
||||
// Secret may allow occurring financial losses through 3rd party API usage
|
||||
// include::../../../shared_content/secrets/impact/financial_loss.adoc[]
|
||||
|
||||
// Secret may be used to modify dashboards to corrupt shown data
|
||||
// Requires setting service_name variable
|
||||
// :service_name: secret service
|
||||
// include::../../../shared_content/secrets/impact/dataviz_takeover.adoc[]
|
||||
|
||||
// Secret is related to IaaS providers and can be used to change DNS, launch VMs, etc.
|
||||
// Requires setting service_name variable
|
||||
// :service_name: secret service
|
||||
// include::../../../shared_content/secrets/impact/infrastructure_takeover.adoc[]
|
||||
|
||||
== How to fix it
|
||||
|
||||
// 1. Revoke leaked secrets
|
||||
|
||||
include::../../../shared_content/secrets/fix/revoke.adoc[]
|
||||
|
||||
// 2. Analyze recent use to identify misuse
|
||||
|
||||
include::../../../shared_content/secrets/fix/recent_use.adoc[]
|
||||
|
||||
// 3. Use a secret vault in the future
|
||||
|
||||
include::../../../shared_content/secrets/fix/vault.adoc[]
|
||||
|
||||
// 4. Never hard-code secrets
|
||||
|
||||
include::../../../shared_content/secrets/fix/default.adoc[]
|
||||
|
||||
// OAuth PKCE is very specific to OAuth 2.0
|
||||
// include::../../../shared_content/secrets/fix/oauth_pkce.adoc[]
|
||||
|
||||
=== Code examples
|
||||
|
||||
include::../../../shared_content/secrets/examples.adoc[]
|
||||
|
||||
//=== How does this work?
|
||||
|
||||
//=== Pitfalls
|
||||
|
||||
//=== Going the extra mile
|
||||
|
||||
== Resources
|
||||
|
||||
include::../../../shared_content/secrets/resources/standards.adoc[]
|
||||
|
||||
//=== Benchmarks
|
@ -1,28 +1,21 @@
|
||||
import datetime
|
||||
import json
|
||||
import pathlib
|
||||
import random
|
||||
import socket
|
||||
|
||||
import os,io
|
||||
import re
|
||||
import requests
|
||||
import json
|
||||
import random
|
||||
import datetime
|
||||
from bs4 import BeautifulSoup
|
||||
from socket import timeout
|
||||
import pathlib
|
||||
|
||||
TOLERABLE_LINK_DOWNTIME = datetime.timedelta(days=7)
|
||||
LINK_PROBES_HISTORY_FILE = './link_probes.history'
|
||||
PROBING_COOLDOWN = datetime.timedelta(days=2)
|
||||
PROBING_SPREAD = 60 * 24 # in minutes, 1 day
|
||||
PROBING_COOLDOWN = datetime.timedelta(days=1)
|
||||
PROBING_SPREAD = 100 # minutes
|
||||
link_probes_history = {}
|
||||
|
||||
# These links consistently fail in CI, but work-on-my-machine
|
||||
EXCEPTION_PREFIXES = [
|
||||
# It seems the server certificate was renewed on 2nd of August 2024.
|
||||
# The server is sending only its certificate, without including the
|
||||
# Intermediate certificate used to issue the server cert. Because of that
|
||||
# some application are not able to verify the complete chain of trust.
|
||||
"https://wiki.sei.cmu.edu/",
|
||||
# The CI reports 403 on drupal.org while it works locally.
|
||||
# Maybe the CI's IP is blocklisted...
|
||||
"https://www.drupal.org/",
|
||||
EXCEPTIONS = [
|
||||
]
|
||||
|
||||
def show_files(filenames):
|
||||
@ -72,7 +65,7 @@ def live_url(url: str, timeout=5):
|
||||
req = requests.Request('GET', url, headers = {'sec-ch-ua': '" Not A;Brand";v="99", "Chromium";v="90"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'Upgrade-Insecure-Requests': '1',
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 GLS/100.10.9939.100',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36',
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
|
||||
'Sec-Fetch-Site':'none',
|
||||
'Sec-Fetch-Mode':'navigate',
|
||||
@ -101,13 +94,13 @@ def live_url(url: str, timeout=5):
|
||||
print(f"ERROR: Too many redirects: {rr}")
|
||||
return False
|
||||
except requests.Timeout as t:
|
||||
print(f"ERROR: Request timeout {t}")
|
||||
print(f"ERROR: timeout ", t)
|
||||
return False
|
||||
except socket.timeout as t:
|
||||
print(f"ERROR: Socket timeout {t}")
|
||||
except timeout as t:
|
||||
print(f"ERROR: timeout ", t)
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"ERROR: {e}")
|
||||
print(f"ERROR: ", e)
|
||||
return False
|
||||
|
||||
def findurl_in_html(filename,urls):
|
||||
@ -152,51 +145,20 @@ def get_all_links_from_htmls(dir):
|
||||
print("All html files crawled")
|
||||
return urls
|
||||
|
||||
def url_is_exception(url: str) -> bool:
|
||||
return any(
|
||||
url.startswith(e) for e in EXCEPTION_PREFIXES
|
||||
)
|
||||
|
||||
def probe_links(urls: dict) -> bool:
|
||||
def probe_links(urls):
|
||||
errors = []
|
||||
link_cache_exception = 0
|
||||
link_cache_hit = 0
|
||||
link_cache_miss = 0
|
||||
print("Testing links")
|
||||
link_count = len(urls)
|
||||
for idx, url in enumerate(urls):
|
||||
print(f"[{idx+1}/{link_count}] {url} in {len(urls[url])} files")
|
||||
if url_is_exception(url):
|
||||
link_cache_exception += 1
|
||||
for url in urls:
|
||||
print(f"{url} in {len(urls[url])} files")
|
||||
if url in EXCEPTIONS:
|
||||
print("skip as an exception")
|
||||
elif url_was_reached_recently(url):
|
||||
link_cache_hit += 1
|
||||
print("skip probing because it was reached recently")
|
||||
elif live_url(url, timeout=5):
|
||||
link_cache_miss += 1
|
||||
rejuvenate_url(url)
|
||||
elif url_is_long_dead(url):
|
||||
link_cache_miss += 1
|
||||
errors.append(url)
|
||||
else:
|
||||
link_cache_miss += 1
|
||||
|
||||
confirmed_errors = confirm_errors(errors, urls)
|
||||
|
||||
print(f"\n\n\n{'=' * 80}\n\n\n")
|
||||
if confirmed_errors:
|
||||
report_errors(confirmed_errors, urls)
|
||||
print(f"{len(confirmed_errors)}/{len(urls)} links are dead, see above ^^ the list and the related files\n\n")
|
||||
print("Cache statistics:")
|
||||
print(f"\t{link_cache_hit=}")
|
||||
print(f"\t{link_cache_miss=}")
|
||||
link_cache_hit_ratio = (link_cache_hit) / (link_cache_hit + link_cache_miss)
|
||||
print(f"\t{link_cache_hit_ratio:03.2%} hits")
|
||||
print(f"\t{link_cache_exception=}")
|
||||
print(f"\n\n\n{'=' * 80}\n\n\n")
|
||||
|
||||
success = len(confirmed_errors) == 0
|
||||
return success
|
||||
return errors
|
||||
|
||||
def confirm_errors(presumed_errors, urls):
|
||||
confirmed_errors = []
|
||||
@ -218,9 +180,16 @@ def report_errors(errors, urls):
|
||||
def check_html_links(dir):
|
||||
load_url_probing_history()
|
||||
urls = get_all_links_from_htmls(dir)
|
||||
success = probe_links(urls)
|
||||
if success:
|
||||
errors = probe_links(urls)
|
||||
exit_code = 0
|
||||
if errors:
|
||||
confirmed_errors = confirm_errors(errors, urls)
|
||||
if confirmed_errors:
|
||||
report_errors(confirmed_errors, urls)
|
||||
print(f"{len(confirmed_errors)}/{len(urls)} links are dead, see above ^^ the list and the related files")
|
||||
exit_code = 1
|
||||
if exit_code == 0:
|
||||
print(f"All {len(urls)} links are good")
|
||||
save_url_probing_history()
|
||||
exit(0 if success else 1)
|
||||
exit(exit_code)
|
||||
|
||||
|
@ -1,43 +1,13 @@
|
||||
import collections
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
from git import Repo
|
||||
from git import Git
|
||||
from pathlib import Path
|
||||
|
||||
from git import Git, Repo
|
||||
from rspec_tools.utils import load_json, pushd
|
||||
from rspec_tools.utils import (load_json, pushd)
|
||||
|
||||
REPOS = [
|
||||
'sonar-abap',
|
||||
'sonar-apex',
|
||||
'sonar-architecture',
|
||||
'sonar-cobol',
|
||||
'sonar-cpp',
|
||||
'sonar-dart',
|
||||
'sonar-dataflow-bug-detection',
|
||||
'sonar-dotnet-enterprise',
|
||||
'sonar-flex',
|
||||
'sonar-go-enterprise',
|
||||
'sonar-html',
|
||||
'sonar-iac-enterprise',
|
||||
'sonar-java',
|
||||
'SonarJS',
|
||||
'sonar-kotlin',
|
||||
'sonar-php',
|
||||
'sonar-pli',
|
||||
'sonar-plsql',
|
||||
'sonar-python-enterprise',
|
||||
'sonar-rpg',
|
||||
'sonar-ruby',
|
||||
'sonar-scala',
|
||||
'sonar-security',
|
||||
'sonar-swift',
|
||||
'sonar-text-enterprise',
|
||||
'sonar-tsql',
|
||||
'sonar-vb',
|
||||
'sonar-xml'
|
||||
]
|
||||
REPOS = ['sonar-abap','sonar-cpp','sonar-cobol','sonar-dotnet','sonar-css','sonar-flex','slang-enterprise','sonar-java','SonarJS','sonar-php','sonar-pli','sonar-plsql','sonar-python','sonar-rpg','sonar-swift','sonar-text','sonar-tsql','sonar-vb','sonar-html','sonar-xml','sonar-kotlin', 'sonar-secrets', 'sonar-security', 'sonar-dataflow-bug-detection', 'sonar-iac']
|
||||
|
||||
CANONICAL_NAMES = {
|
||||
'CLOUD_FORMATION': 'CLOUDFORMATION',
|
||||
@ -46,14 +16,14 @@ CANONICAL_NAMES = {
|
||||
'WEB': 'HTML'
|
||||
}
|
||||
|
||||
|
||||
RULES_FILENAME = 'covered_rules.json'
|
||||
|
||||
|
||||
def get_rule_id(filename):
|
||||
rule_id = filename[:-5]
|
||||
return rule_id.removesuffix('_abap').removesuffix('_java')
|
||||
|
||||
if '_' in rule_id:
|
||||
return rule_id[:rule_id.find('_')]
|
||||
else:
|
||||
return rule_id
|
||||
|
||||
def compatible_languages(rule, languages_from_sonarpedia):
|
||||
'''
|
||||
@ -72,7 +42,7 @@ def get_implemented_rules(path, languages_from_sonarpedia):
|
||||
for lang in languages_from_sonarpedia:
|
||||
implemented_rules[lang] = []
|
||||
for filename in os.listdir(path):
|
||||
if filename.endswith(".json") and 'profile' not in filename:
|
||||
if filename.endswith(".json") and not filename.startswith("Sonar_way"):
|
||||
rule = load_json(os.path.join(path, filename))
|
||||
rule_id = get_rule_id(filename)
|
||||
for language in compatible_languages(rule, languages_from_sonarpedia):
|
||||
@ -163,7 +133,7 @@ class Coverage:
|
||||
self.rule_implemented(rule_id, language, analyzer, version)
|
||||
|
||||
def all_implemented_rules():
|
||||
implemented_rules = collections.defaultdict(list)
|
||||
implemented_rules = {}
|
||||
for sp_file in Path('.').rglob('sonarpedia.json'):
|
||||
print(sp_file)
|
||||
sonarpedia_path=sp_file.parents[0]
|
||||
@ -171,10 +141,7 @@ def all_implemented_rules():
|
||||
sonarpedia = load_json(sp_file)
|
||||
path = str(sonarpedia_path) + '/' + sonarpedia['rules-metadata-path'].replace('\\', '/')
|
||||
languages = sonarpedia['languages']
|
||||
|
||||
implemented_rules_in_path = get_implemented_rules(path, languages)
|
||||
for lang, rules in implemented_rules_in_path.items():
|
||||
implemented_rules[lang] += rules
|
||||
implemented_rules.update(get_implemented_rules(path, languages))
|
||||
except Exception as e:
|
||||
print(f"failed to collect implemented rules for {sp_file}: {e}")
|
||||
continue
|
||||
@ -184,29 +151,17 @@ def checkout_repo(repo):
|
||||
git_url=f"https://github.com/SonarSource/{repo}"
|
||||
token=os.getenv('GITHUB_TOKEN')
|
||||
if token:
|
||||
git_url=f"https://oauth2:{token}@github.com/SonarSource/{repo}"
|
||||
git_url=f"https://{token}@github.com/SonarSource/{repo}"
|
||||
if not os.path.exists(repo):
|
||||
return Repo.clone_from(git_url, repo)
|
||||
else:
|
||||
return Repo(repo)
|
||||
|
||||
|
||||
VERSION_RE = re.compile(r'\d[\d\.]+')
|
||||
def is_version_tag(name):
|
||||
return bool(re.fullmatch(VERSION_RE, name))
|
||||
|
||||
|
||||
def comparable_version(key):
|
||||
if not is_version_tag(key):
|
||||
return [0]
|
||||
return list(map(int, key.split('.')))
|
||||
|
||||
|
||||
def collect_coverage_for_all_versions(repo, coverage):
|
||||
git_repo = checkout_repo(repo)
|
||||
tags = git_repo.tags
|
||||
versions = [tag.name for tag in tags if is_version_tag(tag.name)]
|
||||
versions.sort(key = comparable_version)
|
||||
tags.sort(key = lambda t: t.commit.committed_date)
|
||||
versions = [tag.name for tag in tags if '-' not in tag.name]
|
||||
for version in versions:
|
||||
collect_coverage_for_version(repo, git_repo, version, coverage)
|
||||
collect_coverage_for_version(repo, git_repo, 'master', coverage)
|
||||
|
@ -95,7 +95,7 @@ class RuleCreator:
|
||||
if rule_item.is_file():
|
||||
template_content = rule_item.read_text()
|
||||
lang = LANG_TO_SOURCE[language]
|
||||
final_content = template_content.replace('[source,text', f'[source,{lang}')
|
||||
final_content = template_content.replace('[source,text]', f'[source,{lang}]')
|
||||
rule_item.write_text(final_content)
|
||||
|
||||
def _fill_multi_lang_template_files(self, rule_dir: Path, rule_number: int, languages: Iterable[str]):
|
||||
@ -113,9 +113,7 @@ class RuleCreator:
|
||||
|
||||
def _fill_single_lang_template_files(self, rule_dir: Path, rule_number: int, language: str):
|
||||
common_template = self.TEMPLATE_PATH / 'single_language' / 'common'
|
||||
lang_specific_template = self.TEMPLATE_PATH / 'single_language' / language
|
||||
if not Path(lang_specific_template).exists():
|
||||
lang_specific_template = self.TEMPLATE_PATH / 'single_language' / 'language_specific'
|
||||
lang_specific_template = self.TEMPLATE_PATH / 'single_language' / 'language_specific'
|
||||
copy_directory_content(common_template, rule_dir)
|
||||
|
||||
lang_dir = rule_dir /language
|
||||
|
@ -16,10 +16,9 @@ LANG_TO_LABEL = {'abap': 'abap',
|
||||
'cobol': 'cobol',
|
||||
'csharp': 'dotnet',
|
||||
'css': 'css',
|
||||
'dart': 'dart',
|
||||
'docker': 'iac',
|
||||
'flex': 'flex',
|
||||
'go': 'go',
|
||||
'go': 'slang',
|
||||
'html': 'html',
|
||||
'java': 'java',
|
||||
'javascript': 'jsts',
|
||||
@ -40,7 +39,6 @@ LANG_TO_LABEL = {'abap': 'abap',
|
||||
'tsql': 'tsql',
|
||||
'vb6': 'vb6',
|
||||
'vbnet': 'dotnet',
|
||||
'ansible': 'iac',
|
||||
'cloudformation': 'iac',
|
||||
'terraform': 'iac',
|
||||
'kubernetes': 'iac',
|
||||
@ -54,7 +52,6 @@ LANG_TO_SOURCE = {
|
||||
'cloudformation': 'yaml',
|
||||
'csharp': 'csharp',
|
||||
'css': 'css',
|
||||
'dart': 'dart',
|
||||
'docker': 'docker',
|
||||
'go': 'go',
|
||||
'html': 'html',
|
||||
@ -77,7 +74,6 @@ LANG_TO_SOURCE = {
|
||||
'c': 'c',
|
||||
'objectivec': 'objectivec',
|
||||
'vb': 'vb',
|
||||
'ansible': 'yaml',
|
||||
# these languages are not supported by highlight.js as the moment:
|
||||
'apex': 'apex',
|
||||
'azureresourcemanager': 'bicep',
|
||||
|
@ -1,6 +1,6 @@
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Dict, Final, List, Union
|
||||
from typing import Final, Dict, List
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
from rspec_tools.errors import RuleValidationError
|
||||
@ -78,26 +78,15 @@ def intersection(list1, list2):
|
||||
def difference(list1, list2):
|
||||
return list(set(list1) - set(list2))
|
||||
|
||||
def validate_titles_are_not_misclassified_as_subtitles(rule_language: LanguageSpecificRule, subtitles: list[str], allowed_h2_sections: list[str]):
|
||||
# TODO This does not validate "How to fix it" section for frameworks as the section names are a bit special.
|
||||
misclassified = intersection(subtitles, allowed_h2_sections)
|
||||
if misclassified:
|
||||
misclassified.sort()
|
||||
misclassified_str = ', '.join(misclassified)
|
||||
raise RuleValidationError(f'Rule {rule_language.id} has some sections misclassified. Ensure there are not too many `=` in the asciidoc file for: {misclassified_str}')
|
||||
|
||||
def validate_section_names(rule_language: LanguageSpecificRule):
|
||||
"""Validates all h2-level section names"""
|
||||
def get_titles(level: Union[str, list[str]]) -> list[str]:
|
||||
return list(map(lambda x: x.text.strip(), rule_language.description.find_all(level)))
|
||||
|
||||
h2_titles = get_titles('h2')
|
||||
subtitles = get_titles(['h3', 'h4', 'h5', 'h6'])
|
||||
allowed_h2_sections = list(MANDATORY_SECTIONS) + list(OPTIONAL_SECTIONS.keys())
|
||||
validate_titles_are_not_misclassified_as_subtitles(rule_language, subtitles, allowed_h2_sections)
|
||||
descr = rule_language.description
|
||||
h2_titles = list(map(lambda x: x.text.strip(), descr.find_all('h2')))
|
||||
|
||||
validate_duplications(h2_titles, rule_language)
|
||||
|
||||
education_titles = intersection(h2_titles, allowed_h2_sections)
|
||||
education_titles = intersection(h2_titles, list(MANDATORY_SECTIONS) + list(OPTIONAL_SECTIONS.keys()))
|
||||
if education_titles:
|
||||
# Using the education format.
|
||||
validate_how_to_fix_it_sections_names(rule_language, h2_titles)
|
||||
|
@ -156,15 +156,6 @@
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"OWASP Mobile Top 10 2024": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^M([1-9]|10)$"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"PCI DSS 3.2": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
@ -227,15 +218,6 @@
|
||||
"pattern": "^\\d+\\.\\d+\\.\\d+$"
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"STIG ASD_V5R3": {
|
||||
"type": "array",
|
||||
"minItems": 0,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"pattern": "^V-\\d+$"
|
||||
},
|
||||
"uniqueItems": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -276,15 +258,15 @@
|
||||
"properties": {
|
||||
"MAINTAINABILITY": {
|
||||
"type": "string",
|
||||
"enum": ["INFO", "LOW", "MEDIUM", "HIGH", "BLOCKER"]
|
||||
"enum": ["LOW", "MEDIUM", "HIGH"]
|
||||
},
|
||||
"RELIABILITY": {
|
||||
"type": "string",
|
||||
"enum": ["INFO", "LOW", "MEDIUM", "HIGH", "BLOCKER"]
|
||||
"enum": ["LOW", "MEDIUM", "HIGH"]
|
||||
},
|
||||
"SECURITY": {
|
||||
"type": "string",
|
||||
"enum": ["INFO", "LOW", "MEDIUM", "HIGH", "BLOCKER"]
|
||||
"enum": ["LOW", "MEDIUM", "HIGH"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -4,10 +4,7 @@ Checks are:
|
||||
* "ifdef"/"endif" blocks should be well-formed for RSPEC
|
||||
* Inline code with backquotes is correctly escaped and balanced
|
||||
* Include commands are not appended to other code
|
||||
* "C++" is referred to using the {cpp} attribute
|
||||
* rules.sonarsource.com is not linked directly
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
@ -55,8 +52,6 @@ PASSTHROUGH_MACRO = re.compile(PASSTHROUGH_MACRO_TEXT)
|
||||
|
||||
CPP = re.compile(r"\b[Cc]\+\+")
|
||||
|
||||
RULES_SONARSOURCE = re.compile(r"https?:\/\/rules\.sonarsource\.com\/(.*)\/RSPEC-\d+")
|
||||
|
||||
# There is a regex trick here:
|
||||
# We want to skip passthrough macros, to not find pass:[``whatever``]
|
||||
# We do that by matching
|
||||
@ -204,8 +199,7 @@ class Sanitizer:
|
||||
cpp = CPP.search(line, pos)
|
||||
if cpp:
|
||||
self._on_error(
|
||||
line_number,
|
||||
'To avoid rendering issues, always use the "{cpp}" attribute to refer to the language C++.',
|
||||
line_number, 'To avoid rendering issues, always use the "{cpp}" attribute to refer to the language C++'
|
||||
)
|
||||
return next_pos
|
||||
|
||||
@ -217,7 +211,7 @@ class Sanitizer:
|
||||
line_number - 1,
|
||||
"""An empty line is missing after the include.
|
||||
This may result in broken tags and other display issues.
|
||||
Make sure there are always empty lines before and after each include.""",
|
||||
Make sure there are always empty lines before and after each include""",
|
||||
)
|
||||
if INCLUDE.match(line):
|
||||
self._previous_line_was_include = True
|
||||
@ -226,17 +220,11 @@ Make sure there are always empty lines before and after each include.""",
|
||||
line_number,
|
||||
"""An empty line is missing before the include.
|
||||
This may result in broken tags and other display issues.
|
||||
Make sure there are always empty lines before and after each include.""",
|
||||
Make sure there are always empty lines before and after each include""",
|
||||
)
|
||||
return
|
||||
else:
|
||||
self._previous_line_was_include = False
|
||||
if RULES_SONARSOURCE.search(line) and not self._is_env_open:
|
||||
self._on_error(
|
||||
line_number,
|
||||
"""Do not put direct links to https://rules.sonarsource.com/.
|
||||
Just use the rule ID and let cross-reference substitution do its job.""",
|
||||
)
|
||||
pos = 0
|
||||
res = self._advance_to_next_backquote(line, pos, line_number)
|
||||
# We filter out matches for passthrough. See comment near the BACKQUOTE declaration
|
||||
|
@ -1,16 +0,0 @@
|
||||
== Title
|
||||
|
||||
In this case, there is also an impact on reliability and so it is handled by the rule https://rules.sonarsource.com/java/RSPEC-5810/[S5810].
|
||||
|
||||
=== Documentation
|
||||
|
||||
* https://rules.sonarsource.com/csharp/RSPEC-6420/[S6420 - Client instances should not be recreated on each Azure Function invocation]
|
||||
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
||||
https://rules.sonarsource.com/csharp/RSPEC-6420/[We ignore rspecator view]
|
||||
|
||||
endif::env-github,rspecator-view[]
|
||||
|
||||
http://rules.sonarsource.com/csharp/RSPEC-6420/[We detect http too]
|
@ -1,3 +1,3 @@
|
||||
$PATH/include_stuck_after.adoc:3 An empty line is missing after the include.
|
||||
This may result in broken tags and other display issues.
|
||||
Make sure there are always empty lines before and after each include.
|
||||
Make sure there are always empty lines before and after each include
|
||||
|
@ -1,3 +1,3 @@
|
||||
$PATH/include_stuck_before.adoc:2 An empty line is missing before the include.
|
||||
This may result in broken tags and other display issues.
|
||||
Make sure there are always empty lines before and after each include.
|
||||
Make sure there are always empty lines before and after each include
|
||||
|
@ -1,6 +0,0 @@
|
||||
$PATH/link_rule_sonarsource_com.adoc:3 Do not put direct links to https://rules.sonarsource.com/.
|
||||
Just use the rule ID and let cross-reference substitution do its job.
|
||||
$PATH/link_rule_sonarsource_com.adoc:7 Do not put direct links to https://rules.sonarsource.com/.
|
||||
Just use the rule ID and let cross-reference substitution do its job.
|
||||
$PATH/link_rule_sonarsource_com.adoc:16 Do not put direct links to https://rules.sonarsource.com/.
|
||||
Just use the rule ID and let cross-reference substitution do its job.
|
@ -1,6 +1,6 @@
|
||||
$PATH/two_stuck_includes.adoc:3 An empty line is missing after the include.
|
||||
This may result in broken tags and other display issues.
|
||||
Make sure there are always empty lines before and after each include.
|
||||
Make sure there are always empty lines before and after each include
|
||||
$PATH/two_stuck_includes.adoc:4 An empty line is missing before the include.
|
||||
This may result in broken tags and other display issues.
|
||||
Make sure there are always empty lines before and after each include.
|
||||
Make sure there are always empty lines before and after each include
|
||||
|
@ -1,2 +1,2 @@
|
||||
$PATH/unnamed_language.adoc:1 To avoid rendering issues, always use the "{cpp}" attribute to refer to the language C++.
|
||||
$PATH/unnamed_language.adoc:3 To avoid rendering issues, always use the "{cpp}" attribute to refer to the language C++.
|
||||
$PATH/unnamed_language.adoc:1 To avoid rendering issues, always use the "{cpp}" attribute to refer to the language C++
|
||||
$PATH/unnamed_language.adoc:3 To avoid rendering issues, always use the "{cpp}" attribute to refer to the language C++
|
||||
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"title": "Function names should comply with a naming convention",
|
||||
"defaultQualityProfiles": [
|
||||
|
||||
]
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
== Why is this an issue?
|
||||
|
||||
=== How to fix it
|
||||
|
||||
=== Resources
|
@ -1,457 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="Asciidoctor 1.5.8">
|
||||
<title>Why is this an issue?</title>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
|
||||
<style>
|
||||
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
|
||||
/* Uncomment @import statement below to use as custom stylesheet */
|
||||
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
|
||||
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
|
||||
audio,canvas,video{display:inline-block}
|
||||
audio:not([controls]){display:none;height:0}
|
||||
script{display:none!important}
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
|
||||
a{background:transparent}
|
||||
a:focus{outline:thin dotted}
|
||||
a:active,a:hover{outline:0}
|
||||
h1{font-size:2em;margin:.67em 0}
|
||||
abbr[title]{border-bottom:1px dotted}
|
||||
b,strong{font-weight:bold}
|
||||
dfn{font-style:italic}
|
||||
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
|
||||
mark{background:#ff0;color:#000}
|
||||
code,kbd,pre,samp{font-family:monospace;font-size:1em}
|
||||
pre{white-space:pre-wrap}
|
||||
q{quotes:"\201C" "\201D" "\2018" "\2019"}
|
||||
small{font-size:80%}
|
||||
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||
sup{top:-.5em}
|
||||
sub{bottom:-.25em}
|
||||
img{border:0}
|
||||
svg:not(:root){overflow:hidden}
|
||||
figure{margin:0}
|
||||
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
|
||||
legend{border:0;padding:0}
|
||||
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
|
||||
button,input{line-height:normal}
|
||||
button,select{text-transform:none}
|
||||
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
|
||||
button[disabled],html input[disabled]{cursor:default}
|
||||
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
|
||||
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
|
||||
textarea{overflow:auto;vertical-align:top}
|
||||
table{border-collapse:collapse;border-spacing:0}
|
||||
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
|
||||
html,body{font-size:100%}
|
||||
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
|
||||
a:hover{cursor:pointer}
|
||||
img,object,embed{max-width:100%;height:auto}
|
||||
object,embed{height:100%}
|
||||
img{-ms-interpolation-mode:bicubic}
|
||||
.left{float:left!important}
|
||||
.right{float:right!important}
|
||||
.text-left{text-align:left!important}
|
||||
.text-right{text-align:right!important}
|
||||
.text-center{text-align:center!important}
|
||||
.text-justify{text-align:justify!important}
|
||||
.hide{display:none}
|
||||
img,object,svg{display:inline-block;vertical-align:middle}
|
||||
textarea{height:auto;min-height:50px}
|
||||
select{width:100%}
|
||||
.center{margin-left:auto;margin-right:auto}
|
||||
.stretch{width:100%}
|
||||
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
|
||||
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
|
||||
a{color:#2156a5;text-decoration:underline;line-height:inherit}
|
||||
a:hover,a:focus{color:#1d4b8f}
|
||||
a img{border:none}
|
||||
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
|
||||
p aside{font-size:.875em;line-height:1.35;font-style:italic}
|
||||
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
|
||||
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
|
||||
h1{font-size:2.125em}
|
||||
h2{font-size:1.6875em}
|
||||
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
|
||||
h4,h5{font-size:1.125em}
|
||||
h6{font-size:1em}
|
||||
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
|
||||
em,i{font-style:italic;line-height:inherit}
|
||||
strong,b{font-weight:bold;line-height:inherit}
|
||||
small{font-size:60%;line-height:inherit}
|
||||
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
|
||||
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
|
||||
ul,ol{margin-left:1.5em}
|
||||
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
|
||||
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
|
||||
ul.square{list-style-type:square}
|
||||
ul.circle{list-style-type:circle}
|
||||
ul.disc{list-style-type:disc}
|
||||
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
|
||||
dl dt{margin-bottom:.3125em;font-weight:bold}
|
||||
dl dd{margin-bottom:1.25em}
|
||||
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
|
||||
abbr{text-transform:none}
|
||||
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
|
||||
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
|
||||
blockquote cite::before{content:"\2014 \0020"}
|
||||
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
|
||||
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
|
||||
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
|
||||
h1{font-size:2.75em}
|
||||
h2{font-size:2.3125em}
|
||||
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
|
||||
h4{font-size:1.4375em}}
|
||||
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
|
||||
table thead,table tfoot{background:#f7f8f7}
|
||||
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
|
||||
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
|
||||
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
|
||||
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
|
||||
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
|
||||
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
|
||||
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
|
||||
.clearfix::after,.float-group::after{clear:both}
|
||||
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
|
||||
*:not(pre)>code.nobreak{word-wrap:normal}
|
||||
*:not(pre)>code.nowrap{white-space:nowrap}
|
||||
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
|
||||
em em{font-style:normal}
|
||||
strong strong{font-weight:400}
|
||||
.keyseq{color:rgba(51,51,51,.8)}
|
||||
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
|
||||
.keyseq kbd:first-child{margin-left:0}
|
||||
.keyseq kbd:last-child{margin-right:0}
|
||||
.menuseq,.menuref{color:#000}
|
||||
.menuseq b:not(.caret),.menuref{font-weight:inherit}
|
||||
.menuseq{word-spacing:-.02em}
|
||||
.menuseq b.caret{font-size:1.25em;line-height:.8}
|
||||
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
|
||||
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
|
||||
b.button::before{content:"[";padding:0 3px 0 2px}
|
||||
b.button::after{content:"]";padding:0 2px 0 3px}
|
||||
p a>code:hover{color:rgba(0,0,0,.9)}
|
||||
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
|
||||
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
|
||||
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
|
||||
#content{margin-top:1.25em}
|
||||
#content::before{content:none}
|
||||
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
|
||||
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
|
||||
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
|
||||
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
|
||||
#header .details span:first-child{margin-left:-.125em}
|
||||
#header .details span.email a{color:rgba(0,0,0,.85)}
|
||||
#header .details br{display:none}
|
||||
#header .details br+span::before{content:"\00a0\2013\00a0"}
|
||||
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
|
||||
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
|
||||
#header #revnumber{text-transform:capitalize}
|
||||
#header #revnumber::after{content:"\00a0"}
|
||||
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
|
||||
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
|
||||
#toc>ul{margin-left:.125em}
|
||||
#toc ul.sectlevel0>li>a{font-style:italic}
|
||||
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
|
||||
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
|
||||
#toc li{line-height:1.3334;margin-top:.3334em}
|
||||
#toc a{text-decoration:none}
|
||||
#toc a:active{text-decoration:underline}
|
||||
#toctitle{color:#7a2518;font-size:1.2em}
|
||||
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
|
||||
body.toc2{padding-left:15em;padding-right:0}
|
||||
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
|
||||
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
|
||||
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
|
||||
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
|
||||
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
|
||||
body.toc2.toc-right{padding-left:0;padding-right:15em}
|
||||
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
|
||||
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
|
||||
#toc.toc2{width:20em}
|
||||
#toc.toc2 #toctitle{font-size:1.375em}
|
||||
#toc.toc2>ul{font-size:.95em}
|
||||
#toc.toc2 ul ul{padding-left:1.25em}
|
||||
body.toc2.toc-right{padding-left:0;padding-right:20em}}
|
||||
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
|
||||
#content #toc>:first-child{margin-top:0}
|
||||
#content #toc>:last-child{margin-bottom:0}
|
||||
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
|
||||
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
|
||||
#content{margin-bottom:.625em}
|
||||
.sect1{padding-bottom:.625em}
|
||||
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
|
||||
.sect1{padding-bottom:1.25em}}
|
||||
.sect1:last-child{padding-bottom:0}
|
||||
.sect1+.sect1{border-top:1px solid #e7e7e9}
|
||||
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
|
||||
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
|
||||
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
|
||||
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
|
||||
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
|
||||
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
|
||||
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
|
||||
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
|
||||
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
|
||||
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
|
||||
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
|
||||
.admonitionblock>table td.icon{text-align:center;width:80px}
|
||||
.admonitionblock>table td.icon img{max-width:none}
|
||||
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
|
||||
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
|
||||
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
|
||||
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
|
||||
.exampleblock>.content>:first-child{margin-top:0}
|
||||
.exampleblock>.content>:last-child{margin-bottom:0}
|
||||
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
|
||||
.sidebarblock>:first-child{margin-top:0}
|
||||
.sidebarblock>:last-child{margin-bottom:0}
|
||||
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
|
||||
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
|
||||
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
|
||||
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
|
||||
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
|
||||
@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
|
||||
@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
|
||||
.literalblock pre.nowrap,.literalblock pre.nowrap pre,.listingblock pre.nowrap,.listingblock pre.nowrap pre{white-space:pre;word-wrap:normal}
|
||||
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
|
||||
.listingblock pre.highlightjs{padding:0}
|
||||
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
|
||||
.listingblock pre.prettyprint{border-width:0}
|
||||
.listingblock>.content{position:relative}
|
||||
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
|
||||
.listingblock:hover code[data-lang]::before{display:block}
|
||||
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
|
||||
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
|
||||
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
|
||||
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
|
||||
table.pyhltable td.code{padding-left:.75em;padding-right:0}
|
||||
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dddddf}
|
||||
pre.pygments .lineno{display:inline-block;margin-right:.25em}
|
||||
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
|
||||
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
|
||||
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
|
||||
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
|
||||
.quoteblock blockquote{margin:0;padding:0;border:0}
|
||||
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
|
||||
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
|
||||
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
|
||||
.verseblock{margin:0 1em 1.25em}
|
||||
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
|
||||
.verseblock pre strong{font-weight:400}
|
||||
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
|
||||
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
|
||||
.quoteblock .attribution br,.verseblock .attribution br{display:none}
|
||||
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
|
||||
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
|
||||
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
|
||||
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
|
||||
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
|
||||
.quoteblock.excerpt,.quoteblock .quoteblock{margin:0 0 1.25em;padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
|
||||
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
|
||||
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
|
||||
table.tableblock{max-width:100%;border-collapse:separate}
|
||||
p.tableblock:last-child{margin-bottom:0}
|
||||
td.tableblock>.content{margin-bottom:-1.25em}
|
||||
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
|
||||
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
|
||||
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
|
||||
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
|
||||
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
|
||||
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
|
||||
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
|
||||
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
|
||||
table.frame-all{border-width:1px}
|
||||
table.frame-sides{border-width:0 1px}
|
||||
table.frame-topbot,table.frame-ends{border-width:1px 0}
|
||||
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
|
||||
table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
|
||||
th.halign-left,td.halign-left{text-align:left}
|
||||
th.halign-right,td.halign-right{text-align:right}
|
||||
th.halign-center,td.halign-center{text-align:center}
|
||||
th.valign-top,td.valign-top{vertical-align:top}
|
||||
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
|
||||
th.valign-middle,td.valign-middle{vertical-align:middle}
|
||||
table thead th,table tfoot th{font-weight:bold}
|
||||
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
|
||||
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
|
||||
p.tableblock>code:only-child{background:none;padding:0}
|
||||
p.tableblock{font-size:1em}
|
||||
td>div.verse{white-space:pre}
|
||||
ol{margin-left:1.75em}
|
||||
ul li ol{margin-left:1.5em}
|
||||
dl dd{margin-left:1.125em}
|
||||
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
|
||||
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
|
||||
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
|
||||
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
|
||||
ul.unstyled,ol.unstyled{margin-left:0}
|
||||
ul.checklist{margin-left:.625em}
|
||||
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
|
||||
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
|
||||
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
|
||||
ul.inline>li{margin-left:1.25em}
|
||||
.unstyled dl dt{font-weight:400;font-style:normal}
|
||||
ol.arabic{list-style-type:decimal}
|
||||
ol.decimal{list-style-type:decimal-leading-zero}
|
||||
ol.loweralpha{list-style-type:lower-alpha}
|
||||
ol.upperalpha{list-style-type:upper-alpha}
|
||||
ol.lowerroman{list-style-type:lower-roman}
|
||||
ol.upperroman{list-style-type:upper-roman}
|
||||
ol.lowergreek{list-style-type:lower-greek}
|
||||
.hdlist>table,.colist>table{border:0;background:none}
|
||||
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
|
||||
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
|
||||
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
|
||||
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
|
||||
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
|
||||
.colist td:not([class]):first-child img{max-width:none}
|
||||
.colist td:not([class]):last-child{padding:.25em 0}
|
||||
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
|
||||
.imageblock.left{margin:.25em .625em 1.25em 0}
|
||||
.imageblock.right{margin:.25em 0 1.25em .625em}
|
||||
.imageblock>.title{margin-bottom:0}
|
||||
.imageblock.thumb,.imageblock.th{border-width:6px}
|
||||
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
|
||||
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
|
||||
.image.left{margin-right:.625em}
|
||||
.image.right{margin-left:.625em}
|
||||
a.image{text-decoration:none;display:inline-block}
|
||||
a.image object{pointer-events:none}
|
||||
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
|
||||
sup.footnote a,sup.footnoteref a{text-decoration:none}
|
||||
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
|
||||
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
|
||||
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
|
||||
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
|
||||
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
|
||||
#footnotes .footnote:last-of-type{margin-bottom:0}
|
||||
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
|
||||
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
|
||||
.gist .file-data>table td.line-data{width:99%}
|
||||
div.unbreakable{page-break-inside:avoid}
|
||||
.big{font-size:larger}
|
||||
.small{font-size:smaller}
|
||||
.underline{text-decoration:underline}
|
||||
.overline{text-decoration:overline}
|
||||
.line-through{text-decoration:line-through}
|
||||
.aqua{color:#00bfbf}
|
||||
.aqua-background{background-color:#00fafa}
|
||||
.black{color:#000}
|
||||
.black-background{background-color:#000}
|
||||
.blue{color:#0000bf}
|
||||
.blue-background{background-color:#0000fa}
|
||||
.fuchsia{color:#bf00bf}
|
||||
.fuchsia-background{background-color:#fa00fa}
|
||||
.gray{color:#606060}
|
||||
.gray-background{background-color:#7d7d7d}
|
||||
.green{color:#006000}
|
||||
.green-background{background-color:#007d00}
|
||||
.lime{color:#00bf00}
|
||||
.lime-background{background-color:#00fa00}
|
||||
.maroon{color:#600000}
|
||||
.maroon-background{background-color:#7d0000}
|
||||
.navy{color:#000060}
|
||||
.navy-background{background-color:#00007d}
|
||||
.olive{color:#606000}
|
||||
.olive-background{background-color:#7d7d00}
|
||||
.purple{color:#600060}
|
||||
.purple-background{background-color:#7d007d}
|
||||
.red{color:#bf0000}
|
||||
.red-background{background-color:#fa0000}
|
||||
.silver{color:#909090}
|
||||
.silver-background{background-color:#bcbcbc}
|
||||
.teal{color:#006060}
|
||||
.teal-background{background-color:#007d7d}
|
||||
.white{color:#bfbfbf}
|
||||
.white-background{background-color:#fafafa}
|
||||
.yellow{color:#bfbf00}
|
||||
.yellow-background{background-color:#fafa00}
|
||||
span.icon>.fa{cursor:default}
|
||||
a span.icon>.fa{cursor:inherit}
|
||||
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
|
||||
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
|
||||
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
|
||||
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
|
||||
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
|
||||
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
|
||||
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
|
||||
.conum[data-value] *{color:#fff!important}
|
||||
.conum[data-value]+b{display:none}
|
||||
.conum[data-value]::after{content:attr(data-value)}
|
||||
pre .conum[data-value]{position:relative;top:-.125em}
|
||||
b.conum *{color:inherit!important}
|
||||
.conum:not([data-value]):empty{display:none}
|
||||
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
|
||||
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
|
||||
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
|
||||
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
|
||||
p{margin-bottom:1.25rem}
|
||||
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
|
||||
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
|
||||
.print-only{display:none!important}
|
||||
@page{margin:1.25cm .75cm}
|
||||
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
|
||||
html{font-size:80%}
|
||||
a{color:inherit!important;text-decoration:underline!important}
|
||||
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
|
||||
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
|
||||
abbr[title]::after{content:" (" attr(title) ")"}
|
||||
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
|
||||
thead{display:table-header-group}
|
||||
svg{max-width:100%}
|
||||
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
|
||||
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
|
||||
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
|
||||
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
|
||||
body.book #header{text-align:center}
|
||||
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
|
||||
body.book #header .details{border:0!important;display:block;padding:0!important}
|
||||
body.book #header .details span:first-child{margin-left:0!important}
|
||||
body.book #header .details br{display:block}
|
||||
body.book #header .details br+span::before{content:none!important}
|
||||
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
|
||||
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
|
||||
.listingblock code[data-lang]::before{display:block}
|
||||
#footer{padding:0 .9375em}
|
||||
.hide-on-print{display:none!important}
|
||||
.print-only{display:block!important}
|
||||
.hide-for-print{display:none!important}
|
||||
.show-for-print{display:inherit!important}}
|
||||
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
|
||||
.sect1{padding:0!important}
|
||||
.sect1+.sect1{border:0}
|
||||
#footer{background:none}
|
||||
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
|
||||
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
|
||||
</style>
|
||||
</head>
|
||||
<body class="article">
|
||||
<div id="header">
|
||||
</div>
|
||||
<div id="content">
|
||||
<div class="sect1">
|
||||
<h2 id="_why_is_this_an_issue">Why is this an issue?</h2>
|
||||
<div class="sectionbody">
|
||||
<div class="sect2">
|
||||
<h3 id="_how_to_fix_it">How to fix it</h3>
|
||||
|
||||
</div>
|
||||
<div class="sect2">
|
||||
<h3 id="_resources">Resources</h3>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer">
|
||||
<div id="footer-text">
|
||||
Last updated 2024-10-10 12:53:12 UTC
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -65,17 +65,6 @@ MOCK_REPOS=[{'name':'SonarJS',
|
||||
['sonarpedia.json', '{"rules-metadata-path": "rules", "languages":["XML"]}'],
|
||||
['rules/S103.json', '{}']]}
|
||||
]},
|
||||
{'name':'sonar-java',
|
||||
'versions': [
|
||||
{'name': '1.2.0.123',
|
||||
'date': '2020-01-02 10:00:00',
|
||||
'files': [['module1/rules/Sonar_way_profile.json', '{}'],
|
||||
['module1/sonarpedia.json', '{"rules-metadata-path": "rules", "languages":["JAVA"]}'],
|
||||
['module1/rules/S100.json', '{}'],
|
||||
['module2/rules/Sonar_way_profile.json', '{}'],
|
||||
['module2/sonarpedia.json', '{"rules-metadata-path": "rules", "languages":["JAVA"]}'],
|
||||
['module2/rules/S101.json', '{}']]}
|
||||
]},
|
||||
{'name':'broken',
|
||||
'versions': [
|
||||
{'name': 'v1',
|
||||
@ -170,20 +159,19 @@ def test_update_coverage_for_repo(tmpdir, rules_dir: Path, mock_git_analyzer_rep
|
||||
assert cov['JAVASCRIPT']['S1145'] == {'since': REPO + ' 3.3.0.5702', 'until': REPO + ' 6.7.0.14237'}
|
||||
|
||||
|
||||
@patch('rspec_tools.coverage.REPOS', ['SonarJS', 'sonar-xml', 'sonar-java'])
|
||||
@patch('rspec_tools.coverage.REPOS', ['SonarJS', 'sonar-xml'])
|
||||
def test_update_coverage_for_all_repos(tmpdir, rules_dir: Path, mock_git_analyzer_repos):
|
||||
with pushd(tmpdir), patch('rspec_tools.coverage.Repo', mock_git_analyzer_repos):
|
||||
update_coverage_for_all_repos(rules_dir)
|
||||
coverage = tmpdir.join('covered_rules.json')
|
||||
assert coverage.exists()
|
||||
cov = load_json(coverage)
|
||||
assert {'JAVASCRIPT', 'TYPESCRIPT', 'XML', 'CSS', 'JAVA'} == set(cov.keys())
|
||||
assert {'JAVASCRIPT', 'TYPESCRIPT', 'XML', 'CSS'} == set(cov.keys())
|
||||
assert 'S100' in cov['JAVASCRIPT']
|
||||
assert 'MethodName' not in cov['JAVASCRIPT'] # MethodName is a legacy key for S100
|
||||
assert {'S100'} == set(cov['CSS'].keys())
|
||||
assert {'S103', 'S1000'} == set(cov['XML'].keys())
|
||||
assert cov['XML']['S1000'] == 'SonarJS 7.0.0.14528'
|
||||
assert {'S100', 'S101'} == set(cov['JAVA'].keys())
|
||||
|
||||
def test_update_coverage_no_sonarpedia(tmpdir, rules_dir: Path, mock_git_analyzer_repos, capsys):
|
||||
with pushd(tmpdir), patch('rspec_tools.coverage.Repo', mock_git_analyzer_repos):
|
||||
|
@ -43,13 +43,10 @@ def test_create_new_multi_lang_rule_branch(rule_creator: RuleCreator, mock_git_r
|
||||
for lang_item in lang_root.glob('**/*'):
|
||||
if lang_item.is_file():
|
||||
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
||||
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[os.path.basename(lang)]}')
|
||||
expected_content = expected_content.replace('[source,text]', f'[source,{LANG_TO_SOURCE[os.path.basename(lang)]}]')
|
||||
relative_path = lang_item.relative_to(lang_root)
|
||||
actual_content = rule_dir.joinpath(lang, relative_path).read_text()
|
||||
assert actual_content == expected_content
|
||||
if lang_item.suffix == '.adoc':
|
||||
assert 'source,text' not in actual_content
|
||||
assert LANG_TO_SOURCE[os.path.basename(lang)] in actual_content
|
||||
|
||||
|
||||
def test_create_new_single_lang_rule_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
||||
@ -78,13 +75,10 @@ def test_create_new_single_lang_rule_branch(rule_creator: RuleCreator, mock_git_
|
||||
if lang_item.is_file():
|
||||
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
||||
dir_name = os.path.basename(lang)
|
||||
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[dir_name]}')
|
||||
expected_content = expected_content.replace('[source,text]', f'[source,{LANG_TO_SOURCE[dir_name]}]')
|
||||
relative_path = lang_item.relative_to(lang_root)
|
||||
actual_content = rule_dir.joinpath(lang, relative_path).read_text()
|
||||
assert actual_content == expected_content
|
||||
if lang_item.suffix == '.adoc':
|
||||
assert 'source,text' not in actual_content
|
||||
assert LANG_TO_SOURCE[dir_name] in actual_content
|
||||
|
||||
|
||||
def test_create_new_rule_pull_request(rule_creator: RuleCreator):
|
||||
@ -144,13 +138,10 @@ def test_add_lang_singlelang_nonconventional_rule_create_branch(rule_creator: Ru
|
||||
for lang_item in lang_root.glob('**/*'):
|
||||
if lang_item.is_file():
|
||||
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
||||
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[language]}')
|
||||
expected_content = expected_content.replace('[source,text]', f'[source,{LANG_TO_SOURCE[language]}]')
|
||||
relative_path = lang_item.relative_to(lang_root)
|
||||
actual_content = rule_dir.joinpath(language, relative_path).read_text()
|
||||
assert actual_content == expected_content
|
||||
if lang_item.suffix == '.adoc':
|
||||
assert 'source,text' not in actual_content
|
||||
assert LANG_TO_SOURCE[language] in actual_content
|
||||
|
||||
|
||||
def test_add_lang_singlelang_conventional_rule_create_branch(rule_creator: RuleCreator, mock_git_rspec_repo: Repo):
|
||||
@ -195,13 +186,10 @@ def test_add_lang_multilang_rule_create_branch(rule_creator: RuleCreator, mock_g
|
||||
for lang_item in lang_root.glob('**/*'):
|
||||
if lang_item.is_file():
|
||||
expected_content = lang_item.read_text().replace('${RSPEC_ID}', str(rule_number))
|
||||
expected_content = expected_content.replace('[source,text', f'[source,{LANG_TO_SOURCE[language]}')
|
||||
expected_content = expected_content.replace('[source,text]', f'[source,{LANG_TO_SOURCE[language]}]')
|
||||
relative_path = lang_item.relative_to(lang_root)
|
||||
actual_content = rule_dir.joinpath(language, relative_path).read_text()
|
||||
assert actual_content == expected_content
|
||||
if lang_item.suffix == '.adoc':
|
||||
assert 'source,text' not in actual_content
|
||||
assert LANG_TO_SOURCE[language] in actual_content
|
||||
|
||||
|
||||
@patch('rspec_tools.create_rule.RuleCreator')
|
||||
|
@ -29,7 +29,6 @@ def relative_output(capsys, path: Path):
|
||||
("include_stuck_after", 1),
|
||||
("two_stuck_includes", 2),
|
||||
("unnamed_language", 2),
|
||||
("link_rule_sonarsource_com", 3),
|
||||
],
|
||||
)
|
||||
def test_need_sanitation(
|
||||
|
@ -39,11 +39,6 @@ def test_unexpected_section_fails_validation(invalid_rule):
|
||||
with pytest.raises(RuleValidationError, match=fr'^Rule {rule.id} has an unconventional header "Invalid header"'):
|
||||
validate_section_names(rule)
|
||||
|
||||
def test_sections_with_wrong_level_fails_validation(invalid_rule):
|
||||
rule = invalid_rule('S100', 'php')
|
||||
with pytest.raises(RuleValidationError, match=fr'^Rule {rule.id} has some sections misclassified. Ensure there are not too many `=` in the asciidoc file for: How to fix it, Resources'):
|
||||
validate_section_names(rule)
|
||||
|
||||
def test_valid_section_levels_passes_validation(rule_language):
|
||||
'''Check that description with correct formatting is considered valid.'''
|
||||
validate_section_levels(rule_language('S100', 'cfamily'))
|
||||
|
@ -82,7 +82,7 @@ def test_rule_with_invalid_impacts(invalid_rules: RulesRepository):
|
||||
|
||||
def test_rule_with_invalid_impact_level(invalid_rules: RulesRepository):
|
||||
s506 = invalid_rules.get_rule('S506')
|
||||
with pytest.raises(RuleValidationError, match=re.escape("Rule S506 failed validation for these reasons:\n - Rule scala:S506 has invalid metadata in MAINTAINABILITY: 'INVALID' is not one of ['INFO', 'LOW', 'MEDIUM', 'HIGH', 'BLOCKER']")):
|
||||
with pytest.raises(RuleValidationError, match=re.escape("Rule S506 failed validation for these reasons:\n - Rule scala:S506 has invalid metadata in MAINTAINABILITY: 'INVALID' is not one of ['LOW', 'MEDIUM', 'HIGH']")):
|
||||
validate_rule_metadata(s506)
|
||||
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
{
|
||||
"title": "Method names should comply with a naming convention",
|
||||
"scope": "Main"
|
||||
"title": "Method names should comply with a naming convention"
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
{
|
||||
"title": "Function and method names should comply with a naming convention",
|
||||
"defaultQualityProfiles": [],
|
||||
"scope": "Main",
|
||||
"compatibleLanguages": [
|
||||
"js",
|
||||
"ts"
|
||||
]
|
||||
"scope": "Main"
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
"title": "Procedure names should comply with a naming convention"
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
== Why is this an issue?
|
||||
|
||||
Shared naming conventions allow teams to collaborate efficiently.
|
||||
|
||||
This rule raises an issue when a procedure name does not match a provided regular expression.
|
||||
|
||||
For example, with the default provided regular expression ``++^[A-Z][A-Z0-9]*$++``, the procedure:
|
||||
|
||||
[source,jcl]
|
||||
----
|
||||
//* Noncompliant
|
||||
//$PROC1 PROC
|
||||
----
|
||||
|
||||
should be renamed to
|
||||
|
||||
[source,jcl]
|
||||
----
|
||||
//PROC1 PROC
|
||||
----
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
||||
'''
|
||||
== Implementation Specification
|
||||
(visible only on this page)
|
||||
|
||||
include::../message.adoc[]
|
||||
|
||||
'''
|
||||
== Comments And Links
|
||||
(visible only on this page)
|
||||
|
||||
include::../comments-and-links.adoc[]
|
||||
|
||||
endif::env-github,rspecator-view[]
|
@ -1,4 +1,4 @@
|
||||
=== Message
|
||||
|
||||
Rename [method|function|subroutine|procedure] "XXXX" to match the regular expression ${format}.
|
||||
Rename [method|function|subroutine] "XXXX" to match the regular expression ${format}.
|
||||
|
||||
|
@ -2,7 +2,7 @@ include::../rule.adoc[]
|
||||
|
||||
For example, with the default provided regular expression ``++^[a-z][a-zA-Z0-9]*$++``, the function:
|
||||
|
||||
[source,php,diff-id=1,diff-type=noncompliant]
|
||||
[source,php]
|
||||
----
|
||||
function DoSomething(){ // Noncompliant
|
||||
// ...
|
||||
@ -11,31 +11,13 @@ function DoSomething(){ // Noncompliant
|
||||
|
||||
should be renamed to
|
||||
|
||||
[source,php,diff-id=1,diff-type=compliant]
|
||||
[source,php]
|
||||
----
|
||||
function doSomething(){
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
In case the Drupal framework is detected and the default regex is not replaced, it will follow the PHP coding standards for Drupal.
|
||||
|
||||
[source,php,diff-id=2,diff-type=noncompliant]
|
||||
----
|
||||
function doSomething(){ // Noncompliant
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
should be renamed to
|
||||
|
||||
[source,php,diff-id=2,diff-type=compliant]
|
||||
----
|
||||
function do_something(){
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
=== Exceptions
|
||||
|
||||
Methods with an ``++@inheritdoc++`` annotation, as well as magic methods (``++__construct()++``, ``++__destruct()++``, ``++__call()++``, ``++__callStatic()++``, ``++__get()++``, ``++__set()++``, ``++__isset()++``, ``++__unset()++``, ``++__sleep()++``, ``++__wakeup()++``, ``++__toString()++``, ``++__invoke()++``, ``++__set_state()++``, ``++__clone()++``, ``++__debugInfo()++``) are ignored.
|
||||
@ -52,10 +34,6 @@ function __destruct(){...} // Compliant by exception
|
||||
function myFunc(){...} // Compliant by exception
|
||||
----
|
||||
|
||||
== References
|
||||
|
||||
* https://www.drupal.org/docs/develop/standards/php/php-coding-standards#s-functions-and-variables[Drupal - Naming Conventions - Functions and variables]
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
||||
'''
|
||||
|
@ -1,12 +1,13 @@
|
||||
== Why is this an issue?
|
||||
|
||||
A using-directive (e.g., `using namespace std;`) makes names from another namespace available in the current scope. It should only be used when those names do not create an ambiguity with other names. Otherwise, it is better to fully qualify the names you want to use.
|
||||
A using directive makes names from another namespace available in the current scope. It should only be used when those names do not create an ambiguity with other names, otherwise, it is better to fully qualify the names you want to use.
|
||||
|
||||
The effect of using-directives inside a function body ceases at the end of the current scope. However, when the using-directives are at the global or namespace scope, their effects propagate to the rest of the scope.
|
||||
|
||||
When you write a header file, you don't know from which contexts it will be included. Therefore, if this header contains using-directives at the global or namespace scope, you cannot be sure that they will not create ambiguities in some of the including contexts. Those ambiguities could lead to compilation failures or, worse, to a different function being selected by overload resolution depending on the order of inclusion of headers.
|
||||
When you write a header file, you don't know from which context it will be included. Therefore, if this header contains using directives, you cannot be sure that they will not create ambiguities in that context. Those ambiguities could lead to compilation failures or, worse, to a different function being selected by overload resolution depending on the order of inclusion of headers.
|
||||
|
||||
|
||||
A using declaration behaves in the same way but only for one name. Because of their much narrower scope, this rule does not apply to using declarations.
|
||||
|
||||
This rule will raise an issue on using-directives in header files.
|
||||
|
||||
=== Noncompliant code example
|
||||
|
||||
@ -51,21 +52,12 @@ void m2 ( )
|
||||
|
||||
=== Exceptions
|
||||
|
||||
Using-declarations (e.g., `using std::cout;`) behave in the same way but only for one name. This rule does not apply to them because their scope is much narrower.
|
||||
The issue only happens if the using directive is at global scope or at namespace scope. If is is inside a function body, it will cease to be in effect at the end of the current scope, and will not propagate to the users of the header file.
|
||||
|
||||
Additionally, since it isn't easy to fully qualify the content of the `std::literals` and `std::placeholders` namespaces, this rule doesn't raise violations for using-directives that target these namespaces or their sub-namespaces, such as ``++std::literals::chrono_literals++``.
|
||||
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* {cpp} reference - https://en.cppreference.com/w/cpp/language/namespace#Using-directives[using-directives]
|
||||
|
||||
|
||||
=== External coding guidelines
|
||||
|
||||
* MISRA {cpp}:2008, 7-3-6 - using-directives and using-declarations (excluding class scope or function scope using-declarations) shall not be used in header files.
|
||||
|
||||
* {cpp} Core Guidelines - https://github.com/isocpp/CppCoreGuidelines/blob/e49158a/CppCoreGuidelines.md#sf7-dont-write-using-namespace-at-global-scope-in-a-header-file[SF.7: Don't write `using namespace` at global scope in a header file]
|
||||
|
||||
|
||||
|
@ -1,56 +0,0 @@
|
||||
== Why is this an issue?
|
||||
|
||||
Shared naming conventions allow teams to collaborate efficiently. In Dart, the convention is that all type names should be in camel-case starting with a capital letter (aka Pascal case).
|
||||
|
||||
This rule raises an issue when a class name does not comply with this convention.
|
||||
|
||||
== How to fix it
|
||||
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,dart]
|
||||
----
|
||||
class My_Class { } // Noncompliant: contains a dash
|
||||
class myClass { } // Noncompliant: starts with a lowercase
|
||||
class myclass { } // Noncompliant: all in lowercase
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,dart]
|
||||
----
|
||||
class MyClass { }
|
||||
----
|
||||
|
||||
== Resources
|
||||
|
||||
* Dart Docs - https://dart.dev/tools/linter-rules/camel_case_types[Dart Linter rule - camel_case_types]
|
||||
|
||||
=== Related rules
|
||||
|
||||
* S7046 - Extension identifiers should comply with a naming convention
|
||||
* S7075 - Non-constant names should comply with a naming convention
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
||||
'''
|
||||
== Implementation Specification
|
||||
(visible only on this page)
|
||||
|
||||
=== Message
|
||||
|
||||
* The type name '<typeName>' isn't an UpperCamelCase identifier.
|
||||
|
||||
=== Highlighting
|
||||
|
||||
The type name (without generic parameters, or representation type declaration).
|
||||
|
||||
'''
|
||||
== Comments And Links
|
||||
(visible only on this page)
|
||||
|
||||
include::../comments-and-links.adoc[]
|
||||
|
||||
endif::env-github,rspecator-view[]
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"scope": "Main"
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,5 @@
|
||||
"defaultQualityProfiles": [
|
||||
"Sonar way"
|
||||
],
|
||||
"scope": "Main",
|
||||
"compatibleLanguages": [
|
||||
"js",
|
||||
"ts"
|
||||
]
|
||||
"scope": "Main"
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"scope": "Main"
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,5 @@
|
||||
"scope": "Main",
|
||||
"defaultQualityProfiles": [],
|
||||
"status": "deprecated",
|
||||
"tags": [],
|
||||
"compatibleLanguages": [
|
||||
"js",
|
||||
"ts"
|
||||
]
|
||||
"tags": []
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
{
|
||||
|
||||
"defaultQualityProfiles": [
|
||||
"Sonar way"
|
||||
]
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"type": "CODE_SMELL",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"MAINTAINABILITY": "BLOCKER"
|
||||
"MAINTAINABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "CLEAR"
|
||||
},
|
||||
@ -17,13 +17,19 @@
|
||||
"based-on-misra"
|
||||
],
|
||||
"extra": {
|
||||
"replacementRules": [],
|
||||
"legacyKeys": []
|
||||
"replacementRules": [
|
||||
|
||||
],
|
||||
"legacyKeys": [
|
||||
|
||||
]
|
||||
},
|
||||
"defaultSeverity": "Blocker",
|
||||
"ruleSpecification": "RSPEC-1032",
|
||||
"sqKey": "S1032",
|
||||
"scope": "Main",
|
||||
"defaultQualityProfiles": [],
|
||||
"defaultQualityProfiles": [
|
||||
|
||||
],
|
||||
"quickfix": "unknown"
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"type": "CODE_SMELL",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"MAINTAINABILITY": "BLOCKER"
|
||||
"MAINTAINABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "CLEAR"
|
||||
},
|
||||
@ -19,8 +19,12 @@
|
||||
"pitfall"
|
||||
],
|
||||
"extra": {
|
||||
"replacementRules": [],
|
||||
"legacyKeys": []
|
||||
"replacementRules": [
|
||||
|
||||
],
|
||||
"legacyKeys": [
|
||||
|
||||
]
|
||||
},
|
||||
"defaultSeverity": "Blocker",
|
||||
"ruleSpecification": "RSPEC-1036",
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"scope": "Main"
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,3 @@
|
||||
{
|
||||
"scope": "Main",
|
||||
"compatibleLanguages": [
|
||||
"js",
|
||||
"ts"
|
||||
]
|
||||
"scope": "Main"
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
|
||||
"title": "Files should not have too many lines"
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ ifdef::env-github,rspecator-view[]
|
||||
== Implementation Specification
|
||||
(visible only on this page)
|
||||
|
||||
=== Message
|
||||
|
||||
File "XXXX" has {0} lines of code, which is greater than {1} authorized. Split it into smaller files.
|
||||
include::../message.adoc[]
|
||||
|
||||
include::../parameters.adoc[]
|
||||
|
||||
|
@ -1,6 +1,3 @@
|
||||
{
|
||||
"title": "All \"except\" blocks should be able to catch exceptions",
|
||||
"tags": [
|
||||
"suspicious"
|
||||
]
|
||||
"title": "All \"except\" blocks should be able to catch exceptions"
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
"title": "Finalizers should not throw exceptions",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"RELIABILITY": "BLOCKER"
|
||||
"RELIABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "LOGICAL"
|
||||
},
|
||||
|
@ -2,7 +2,7 @@
|
||||
"title": "Finalize method should not throw exceptions",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"RELIABILITY": "BLOCKER"
|
||||
"RELIABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "LOGICAL"
|
||||
},
|
||||
|
@ -45,6 +45,7 @@ void goo ( ) throw ( Exception, int )
|
||||
|
||||
* MISRA {cpp}:2008, 15-5-2
|
||||
* CWE - https://cwe.mitre.org/data/definitions/391[CWE-391 - Unchecked Error Condition]
|
||||
* https://www.securecoding.cert.org/confluence/x/EADTAQ[CERT, ERR55-CPP.] - Honor exception specifications
|
||||
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
@ -1,3 +1,3 @@
|
||||
{
|
||||
"scope": "Main"
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,5 @@
|
||||
"scope": "Main",
|
||||
"defaultQualityProfiles": [],
|
||||
"status": "deprecated",
|
||||
"tags": [],
|
||||
"compatibleLanguages": [
|
||||
"js",
|
||||
"ts"
|
||||
]
|
||||
"tags": []
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
"type": "BUG",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"RELIABILITY": "BLOCKER"
|
||||
"RELIABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "COMPLETE"
|
||||
},
|
||||
|
@ -3,7 +3,7 @@
|
||||
"type": "BUG",
|
||||
"code": {
|
||||
"impacts": {
|
||||
"RELIABILITY": "BLOCKER"
|
||||
"RELIABILITY": "HIGH"
|
||||
},
|
||||
"attribute": "LOGICAL"
|
||||
},
|
||||
@ -12,9 +12,13 @@
|
||||
"func": "Constant\/Issue",
|
||||
"constantCost": "30min"
|
||||
},
|
||||
"tags": [],
|
||||
"tags": [
|
||||
|
||||
],
|
||||
"extra": {
|
||||
"replacementRules": [],
|
||||
"replacementRules": [
|
||||
|
||||
],
|
||||
"legacyKeys": [
|
||||
"PipelinedFunctionsWithoutPipeRow"
|
||||
]
|
||||
|
@ -1,4 +1,4 @@
|
||||
:language_std_outputs: std::cout, std::cerr, printf, std::print
|
||||
:language_std_outputs: std::cout, std::cerr, printf
|
||||
|
||||
== Why is this an issue?
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"defaultQualityProfiles": [
|
||||
|
||||
]
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
:language_std_outputs: print
|
||||
|
||||
== Why is this an issue?
|
||||
|
||||
include::../description.adoc[]
|
||||
|
||||
If you are using Flutter, you can use `debugPrint` or surround print calls with a check for `kDebugMode`.
|
||||
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,dart]
|
||||
----
|
||||
void doSomething(int x) {
|
||||
// ...
|
||||
print('debug: $x');
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,dart]
|
||||
----
|
||||
void doSomething(int x) {
|
||||
// ...
|
||||
debugPrint('debug: $x');
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
or
|
||||
|
||||
[source,dart]
|
||||
----
|
||||
void doSomething(int x) {
|
||||
// ...
|
||||
if (kDebugMode) {
|
||||
print('debug: $x');
|
||||
}
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
or
|
||||
|
||||
[source,dart]
|
||||
----
|
||||
void doSomething(int x) {
|
||||
// ...
|
||||
log('log: $x');
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
== Resources
|
||||
|
||||
* OWASP - https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/[Top 10 2021 Category A9 - Security Logging and Monitoring Failures]
|
||||
* OWASP - https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure[Top 10 2017 Category A3 - Sensitive Data Exposure]
|
||||
* Dart Docs - https://dart.dev/tools/linter-rules/avoid_print[Dart Linter rule - avoid_print]
|
||||
* Flutter API Docs - https://api.flutter.dev/flutter/foundation/kDebugMode-constant.html[kDebugMode top-level constant]
|
||||
|
||||
ifdef::env-github,rspecator-view[]
|
||||
|
||||
'''
|
||||
== Implementation Specification
|
||||
(visible only on this page)
|
||||
|
||||
=== Message
|
||||
|
||||
* Don't invoke 'print' in production code.
|
||||
|
||||
=== Highlighting
|
||||
|
||||
The identifier of the `print` method, without argument list.
|
||||
|
||||
'''
|
||||
== Comments And Links
|
||||
(visible only on this page)
|
||||
|
||||
include::../comments-and-links.adoc[]
|
||||
|
||||
endif::env-github,rspecator-view[]
|
@ -3,9 +3,7 @@
|
||||
"bad-practice",
|
||||
"user-experience"
|
||||
],
|
||||
"defaultQualityProfiles": [],
|
||||
"compatibleLanguages": [
|
||||
"js",
|
||||
"ts"
|
||||
"defaultQualityProfiles": [
|
||||
|
||||
]
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"defaultQualityProfiles": [],
|
||||
"tags": [
|
||||
"bad-practice",
|
||||
"clippy"
|
||||
]
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
:language_std_outputs: print!, println!
|
||||
|
||||
== Why is this an issue?
|
||||
|
||||
include::../description.adoc[]
|
||||
|
||||
=== Code examples
|
||||
|
||||
==== Noncompliant code example
|
||||
|
||||
[source,rust,diff-id=1,diff-type=noncompliant]
|
||||
----
|
||||
fn do_something() {
|
||||
println!("my message"); // Noncompliant, output directly to stdout without a logger
|
||||
}
|
||||
----
|
||||
|
||||
==== Compliant solution
|
||||
|
||||
[source,rust,diff-id=1,diff-type=compliant]
|
||||
----
|
||||
use log::{info, LevelFilter};
|
||||
use simple_logger::SimpleLogger;
|
||||
|
||||
fn do_something() {
|
||||
SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();
|
||||
// ...
|
||||
info!("my message"); // Compliant, output via logger
|
||||
// ...
|
||||
}
|
||||
----
|
||||
|
||||
== Resources
|
||||
|
||||
=== Documentation
|
||||
|
||||
* Clippy Lints - https://rust-lang.github.io/rust-clippy/master/index.html#print_stdout
|
||||
* OWASP - https://owasp.org/Top10/A09_2021-Security_Logging_and_Monitoring_Failures/[Top 10 2021 Category A9 - Security Logging and Monitoring Failures]
|
||||
* OWASP - https://owasp.org/www-project-top-ten/2017/A3_2017-Sensitive_Data_Exposure[Top 10 2017 Category A3 - Sensitive Data Exposure]
|
@ -1,3 +0,0 @@
|
||||
{
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user