Skip to content

Commit

Permalink
Merge branch 'main' into issue-318
Browse files Browse the repository at this point in the history
  • Loading branch information
bersbersbers committed Jan 25, 2024
2 parents e95006a + c3a07e5 commit a61ef56
Show file tree
Hide file tree
Showing 22 changed files with 169 additions and 20 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
@@ -1,2 +1,3 @@
custom: ["https://psfmember.org/civicrm/contribute/transact/?reset=1&id=42"]
github: [ericwb]
tidelift: pypi/bandit
67 changes: 67 additions & 0 deletions .github/workflows/build-publish-image.yml
@@ -0,0 +1,67 @@
name: Build and Publish Bandit Images

on:
release:
types: [created]
schedule:
- cron: '0 0 * * 0' # Every Sunday at midnight
workflow_dispatch:

jobs:
build-and-publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write

steps:

- name: Get latest release tag
if: github.event_name != 'release'
id: get-latest-tag
run: |
TAG=$(curl -s https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r .tag_name)
echo "Latest tag is $TAG"
echo "RELEASE_TAG=$TAG" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
with:
ref: ${{ github.event_name == 'release' && github.ref || env.RELEASE_TAG }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Install Cosign
uses: sigstore/cosign-installer@9614fae9e5c5eddabb09f90a270fcb487c9f7149 # v3.3.0
with:
cosign-release: 'v2.2.2'

- name: Downcase github.repository value
run: |
echo "IMAGE_NAME=`echo ${{github.repository}} | tr '[:upper:]' '[:lower:]'`" >>${GITHUB_ENV}
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5
with:
context: .
file: ./docker/Dockerfile
push: true
tags: ghcr.io/${{ env.IMAGE_NAME }}/bandit:latest
platforms: linux/amd64, linux/arm64, linux/arm/v7, linux/arm/v8

- name: Sign the image
env:
TAGS: ghcr.io/${{ env.IMAGE_NAME }}/bandit:latest
DIGEST: ${{ steps.build-and-push.outputs.digest }}
run: |
echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
2 changes: 1 addition & 1 deletion .github/workflows/dependency-review.yml
Expand Up @@ -11,4 +11,4 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v3
uses: actions/dependency-review-action@v4
34 changes: 34 additions & 0 deletions README.rst
Expand Up @@ -83,3 +83,37 @@ https://greentreesnakes.readthedocs.org/en/latest/
Documentation of the various types of AST nodes that Bandit currently covers
or could be extended to cover:
https://greentreesnakes.readthedocs.org/en/latest/nodes.html

Container Images
----------------

Bandit is available as a container image, built within the bandit repository
using GitHub Actions. The image is available on ghcr.io:

.. code-block:: console
docker pull ghcr.io/pycqa/bandit/bandit
The image is built for the following architectures:

* amd64
* arm64
* armv7
* armv8

To pull a specific architecture, use the following format:

.. code-block:: console
docker pull --platform=<architecture> ghcr.io/pycqa/bandit/bandit:latest
Every image is signed with sigstore cosign and it is possible to verify the
source of origin using the following cosign command:

.. code-block:: console
cosign verify ghcr.io/pycqa/bandit/bandit:latest \
--certificate-identity https://github.com/pycqa/bandit/.github/workflows/build-publish-image.yml@refs/tags/<version> \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
Where `<version>` is the release version of Bandit.
9 changes: 9 additions & 0 deletions SECURITY.md
@@ -0,0 +1,9 @@
# Security Policy

Bandit is a tool designed to find security issues, so every effort is made that Bandit itself is also
free of those issues. However, if you believe you have found a security vulnerability in this repository
please open it privately via the [Report a security vulnerability](https://github.com/PyCQA/bandit/security/advisories/new) link in the Issues tab.

**Please do not report security vulnerabilities through public issues, discussions, or pull requests.**

Please also inform the [Tidelift security](https://tidelift.com/security). Tidelift will help coordinate the fix and disclosure.
2 changes: 2 additions & 0 deletions bandit/blacklists/calls.py
Expand Up @@ -198,6 +198,7 @@
| | | - random.choices | |
| | | - random.uniform | |
| | | - random.triangular | |
| | | - random.randbytes | |
+------+---------------------+------------------------------------+-----------+
B312: telnetlib
Expand Down Expand Up @@ -523,6 +524,7 @@ def gen_blacklist():
"random.choices",
"random.uniform",
"random.triangular",
"random.randbytes",
],
"Standard pseudo-random generators are not suitable for "
"security/cryptographic purposes.",
Expand Down
6 changes: 3 additions & 3 deletions bandit/blacklists/imports.py
Expand Up @@ -146,8 +146,8 @@
----------------------
XMLRPC is particularly dangerous as it is also concerned with communicating
data over a network. Use defused.xmlrpc.monkey_patch() function to monkey-patch
xmlrpclib and mitigate remote XML attacks.
data over a network. Use defusedxml.xmlrpc.monkey_patch() function to
monkey-patch xmlrpclib and mitigate remote XML attacks.
+------+---------------------+------------------------------------+-----------+
| ID | Name | Imports | Severity |
Expand Down Expand Up @@ -376,7 +376,7 @@ def gen_blacklist():
issue.Cwe.IMPROPER_INPUT_VALIDATION,
["xmlrpc"],
"Using {name} to parse untrusted XML data is known to be "
"vulnerable to XML attacks. Use defused.xmlrpc.monkey_patch() "
"vulnerable to XML attacks. Use defusedxml.xmlrpc.monkey_patch() "
"function to monkey-patch xmlrpclib and mitigate XML "
"vulnerabilities.",
"HIGH",
Expand Down
14 changes: 11 additions & 3 deletions bandit/cli/baseline.py
Expand Up @@ -15,11 +15,14 @@
import logging
import os
import shutil
import subprocess
import subprocess # nosec: B404
import sys
import tempfile

import git
try:
import git
except ImportError:
git = None

bandit_args = sys.argv[1:]
baseline_tmp_file = "_bandit_baseline_run.json_"
Expand Down Expand Up @@ -101,7 +104,7 @@ def main():
bandit_command = ["bandit"] + step["args"]

try:
output = subprocess.check_output(bandit_command)
output = subprocess.check_output(bandit_command) # nosec: B603
except subprocess.CalledProcessError as e:
output = e.output
return_code = e.returncode
Expand Down Expand Up @@ -198,6 +201,11 @@ def initialize():
report_fname = f"{report_basename}.{output_format}"

# #################### Check Requirements #################################
if git is None:
LOG.error("Git not available, reinstall with baseline extra")
valid = False
return (None, None, None)

try:
repo = git.Repo(os.getcwd())

Expand Down
2 changes: 2 additions & 0 deletions bandit/core/manager.py
Expand Up @@ -249,6 +249,8 @@ def discover_files(self, targets, recursive=False, excluded_paths=""):
excluded_path_globs,
enforce_glob=False,
):
if fname != "-":
fname = os.path.join(".", fname)
files_list.add(fname)
else:
excluded_files.add(fname)
Expand Down
3 changes: 1 addition & 2 deletions bandit/core/utils.py
Expand Up @@ -62,7 +62,6 @@ def get_func_name(node):


def get_qual_attr(node, aliases):
prefix = ""
if isinstance(node, ast.Attribute):
try:
val = deepgetattr(node, "value.id")
Expand All @@ -73,7 +72,7 @@ def get_qual_attr(node, aliases):
except Exception:
# NOTE(tkelsey): degrade gracefully when we can't get the fully
# qualified name for an attr, just return its base name.
pass
prefix = ""

return f"{prefix}.{node.attr}"
else:
Expand Down
2 changes: 1 addition & 1 deletion bandit/formatters/xml.py
Expand Up @@ -35,7 +35,7 @@
"""
import logging
import sys
from xml.etree import ElementTree as ET
from xml.etree import ElementTree as ET # nosec: B405

from bandit.core import docs_utils

Expand Down
2 changes: 1 addition & 1 deletion bandit/plugins/general_bind_all_interfaces.py
Expand Up @@ -43,7 +43,7 @@
@test.checks("Str")
@test.test_id("B104")
def hardcoded_bind_all_interfaces(context):
if context.string_val == "0.0.0.0":
if context.string_val == "0.0.0.0": # nosec: B104
return bandit.Issue(
severity=bandit.MEDIUM,
confidence=bandit.MEDIUM,
Expand Down
4 changes: 2 additions & 2 deletions bandit/plugins/general_hardcoded_tmp.py
Expand Up @@ -59,7 +59,7 @@

def gen_config(name):
if name == "hardcoded_tmp_directory":
return {"tmp_dirs": ["/tmp", "/var/tmp", "/dev/shm"]}
return {"tmp_dirs": ["/tmp", "/var/tmp", "/dev/shm"]} # nosec: B108


@test.takes_config
Expand All @@ -69,7 +69,7 @@ def hardcoded_tmp_directory(context, config):
if config is not None and "tmp_dirs" in config:
tmp_dirs = config["tmp_dirs"]
else:
tmp_dirs = ["/tmp", "/var/tmp", "/dev/shm"]
tmp_dirs = ["/tmp", "/var/tmp", "/dev/shm"] # nosec: B108

if any(context.string_val.startswith(s) for s in tmp_dirs):
return bandit.Issue(
Expand Down
7 changes: 7 additions & 0 deletions doc/source/start.rst
Expand Up @@ -31,6 +31,13 @@ If you want to include TOML support, install it with the `toml` extras:
pip install bandit[toml]
If you want to use the bandit-baseline CLI, install it with the `baseline`
extras:

.. code-block:: console
pip install bandit[baseline]
Run Bandit:

.. code-block:: console
Expand Down
16 changes: 16 additions & 0 deletions docker/Dockerfile
@@ -0,0 +1,16 @@
FROM python:3.12-alpine

# Install Git (required for pbr versioning)
RUN apk add --no-cache git

# Copy the source code into the container
COPY . /bandit

# Set the working directory
WORKDIR /bandit

# Install Bandit from the source code using pip
RUN pip install .

# Define entrypoint and default command
ENTRYPOINT ["bandit"]
1 change: 1 addition & 0 deletions examples/random_module.py
Expand Up @@ -10,6 +10,7 @@
bad = random.choices()
bad = random.uniform()
bad = random.triangular()
bad = random.randbytes()

good = os.urandom()
good = random.SystemRandom()
Expand Down
1 change: 0 additions & 1 deletion requirements.txt
@@ -1,7 +1,6 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
GitPython>=3.1.30 # BSD License (3 clause)
PyYAML>=5.3.1 # MIT
stevedore>=1.20.0 # Apache-2.0
colorama>=0.3.9;platform_system=="Windows" # BSD License (3 clause)
Expand Down
2 changes: 2 additions & 0 deletions setup.cfg
Expand Up @@ -35,6 +35,8 @@ yaml =
PyYAML
toml =
tomli>=1.1.0; python_version < "3.11"
baseline =
GitPython>=3.1.30

[entry_points]
console_scripts =
Expand Down
1 change: 0 additions & 1 deletion test-requirements.txt
Expand Up @@ -7,6 +7,5 @@ flake8>=4.0.0 # Apache-2.0
stestr>=2.5.0 # Apache-2.0
testscenarios>=0.5.0 # Apache-2.0/BSD
testtools>=2.3.0 # MIT
tomli>=1.1.0;python_version<"3.11" # MIT
beautifulsoup4>=4.8.0 # MIT
pylint==1.9.4 # GPLv2
4 changes: 2 additions & 2 deletions tests/functional/test_functional.py
Expand Up @@ -396,8 +396,8 @@ def test_popen_wrappers(self):
def test_random_module(self):
"""Test for the `random` module."""
expect = {
"SEVERITY": {"UNDEFINED": 0, "LOW": 8, "MEDIUM": 0, "HIGH": 0},
"CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 8},
"SEVERITY": {"UNDEFINED": 0, "LOW": 9, "MEDIUM": 0, "HIGH": 0},
"CONFIDENCE": {"UNDEFINED": 0, "LOW": 0, "MEDIUM": 0, "HIGH": 9},
}
self.check_example("random_module.py", expect)

Expand Down
4 changes: 2 additions & 2 deletions tests/unit/core/test_manager.py
Expand Up @@ -289,7 +289,7 @@ def test_discover_files_exclude_glob(self, isdir):
self.manager.discover_files(
["a.py", "test_a.py", "test.py"], True, excluded_paths="test_*.py"
)
self.assertEqual(["a.py", "test.py"], self.manager.files_list)
self.assertEqual(["./a.py", "./test.py"], self.manager.files_list)
self.assertEqual(["test_a.py"], self.manager.excluded_files)

@mock.patch("os.path.isdir")
Expand All @@ -298,7 +298,7 @@ def test_discover_files_include(self, isdir):
with mock.patch.object(manager, "_is_file_included") as m:
m.return_value = True
self.manager.discover_files(["thing"], True)
self.assertEqual(["thing"], self.manager.files_list)
self.assertEqual(["./thing"], self.manager.files_list)
self.assertEqual([], self.manager.excluded_files)

def test_run_tests_keyboardinterrupt(self):
Expand Down
5 changes: 4 additions & 1 deletion tox.ini
Expand Up @@ -10,6 +10,10 @@ setenv =
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
extras =
yaml
toml
baseline
commands =
find bandit -type f -name "*.pyc" -delete
stestr run {posargs}
Expand All @@ -34,7 +38,6 @@ commands = flake8 {posargs} bandit
bandit-baseline -r bandit -ll -ii

[testenv:pep8]
skip_install = true
ignore_errors = true
deps = {[testenv]deps}
.
Expand Down

0 comments on commit a61ef56

Please sign in to comment.