Skip to content

Commit

Permalink
2.3.0 (#139)
Browse files Browse the repository at this point in the history
* Requirements

* Docker image

* Tests config

* CI/CD

* Requirements

* Tests config

* Static code analysis

* Update README

* Update release notes

* Requirements

* Requirements

* Old semgrep compatibility

* Drop old Python

* Drop old Python

* No AST on Windows

* Update README

* Update release notes
  • Loading branch information
adeptex authored Jun 15, 2024
1 parent 8f17f77 commit e6694d7
Show file tree
Hide file tree
Showing 59 changed files with 1,062 additions and 549 deletions.
10 changes: 7 additions & 3 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
.git
.gitignore
.dockerignore
.github

whispers.png

# Created by https://www.gitignore.io/api/linux,macos,python,visualstudiocode
# Edit at https://www.gitignore.io/?templates=linux,macos,python,visualstudiocode
Expand Down Expand Up @@ -61,7 +64,7 @@ __pycache__/
.Python
build/
develop-eggs/
# dist/
dist/
downloads/
eggs/
.eggs/
Expand All @@ -76,8 +79,8 @@ share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
dev
dev/
tests/

# PyInstaller
# Usually these files are written by a python script from a template
Expand All @@ -98,6 +101,7 @@ htmlcov/
.cache
nosetests.xml
coverage.xml
coverage.svg
*.cover
.hypothesis/
.pytest_cache/
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ jobs:
matrix:
env-version:
- os: "ubuntu-20.04"
python: 3.6
python: 3.8.18
- os: "ubuntu-latest"
python: 3.11.1
python: 3.12.3
- os: "windows-latest"
python: 3.11.1
python: 3.12.3
- os: "macos-latest"
python: 3.11.1
python: 3.12.3

runs-on: ${{ matrix.env-version.os }}

Expand Down Expand Up @@ -61,12 +61,13 @@ jobs:
if: matrix.env-version.os == 'windows-latest'
run: |
pyinstaller --clean --noconfirm --strip --noupx --console --onefile --add-data 'whispers/config.yml;whispers' --add-data 'whispers/rules/*.yml;whispers/rules' --name whispers.exe whispers/main.py
dist/whispers.exe tests/fixtures
dist/whispers.exe --init
dist/whispers.exe --ast -F None tests/fixtures
- name: compile .bin
if: matrix.env-version.os != 'windows-latest'
run: |
pyinstaller --clean --noconfirm --strip --noupx --console --onefile --add-data 'whispers/config.yml:whispers' --add-data 'whispers/rules/*.yml:whispers/rules' --name whispers.bin whispers/main.py
dist/whispers.bin --help
dist/whispers.bin --init
dist/whispers.bin tests/fixtures
dist/whispers.bin --ast -F None tests/fixtures
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
matrix:
env-version:
- os: "ubuntu-latest"
python: 3.11.1
python: 3.12.3

runs-on: ${{ matrix.env-version.os }}

Expand Down
13 changes: 5 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
FROM python:3.9-slim
FROM python:3.11-slim

RUN apt update \
&& apt install -y make python3-lxml python3-yaml \
&& apt clean
WORKDIR /opt/whispers

WORKDIR /src
ADD . .

COPY dist/*.tar.gz .
RUN pip3 install -e .

RUN pip3 install *.tar.gz \
&& rm -rf *.tar.gz
RUN whispers --help

ENTRYPOINT [ "whispers" ]
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
recursive-include whispers *.yml
include requirements.txt requirements-dev.txt
26 changes: 12 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,36 @@ install-dev:
pip3 install -r requirements.txt -e ".[dev]"

flake8-lint:
flake8 whispers/ tests/
flake8 whispers/ tests/unit/ setup.py

isort-lint:
isort --check-only whispers/ tests/
isort --check-only whispers/ tests/unit/ setup.py

black-lint:
black --check whispers/ tests/
black --check whispers/ tests/unit/ setup.py

lint: isort-lint black-lint flake8-lint

format:
autoflake --in-place --recursive --remove-all-unused-imports whispers/ tests/
autopep8 --in-place --recursive --aggressive --aggressive whispers/ tests/
isort whispers/ tests/
black whispers/ tests/
autoflake --in-place --recursive --remove-all-unused-imports whispers/ tests/unit/ setup.py
autopep8 --in-place --recursive --aggressive --aggressive whispers/ tests/unit/ setup.py
isort whispers/ tests/unit/ setup.py
black whispers/ tests/unit/ setup.py

unit:
pytest --show-capture=all -v tests/
pytest --show-capture=all -vv tests/unit/

coverage:
coverage run --source=whispers/ --branch -m pytest tests/ --junitxml=build/test.xml -v
coverage run --source=whispers/ --branch -m pytest tests/unit/ --junitxml=build/test.xml -vv
coverage xml -i -o build/coverage.xml
coverage report
coverage-badge -f -o coverage.svg

test:
make lint coverage

build-image:
python3 -m build
docker build -t=whispers --rm=true .
# docker rmi -f $$(docker images --filter "dangling=true" -q --no-trunc)
image:
docker build -t=whispers .

freeze:
CUSTOM_COMPILE_COMMAND="make freeze" \
Expand Down Expand Up @@ -66,4 +64,4 @@ publish:
test-pip:
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps whispers

.PHONY: install install-dev isort-lint black-lint flake8-lint format lint unit coverage test publish build-image
.PHONY: install install-dev isort-lint black-lint flake8-lint format lint unit coverage test publish image
27 changes: 19 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
[![](https://github.com/adeptex/whispers/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/adeptex/whispers/actions/workflows/build.yml)
[![](https://github.com/adeptex/whispers/blob/master/coverage.svg)](https://github.com/adeptex/whispers/blob/master/coverage.svg)
[![](https://img.shields.io/pypi/dm/whispers)](https://snyk.io/advisor/python/whispers)
![](https://img.shields.io/badge/python-3.6+-blue)
![](https://img.shields.io/badge/python-3.8+-blue)
![](https://img.shields.io/badge/system-linux%20|%20osx%20|%20windows-blue)

> "My little birds are everywhere, even in the North, they whisper to me the strangest stories." - _Varys_
Whispers is a **static structured text** analysis tool designed for parsing various common software config formats in search of hardcoded secrets. Whispers can be used as a [standalone executable](https://github.com/adeptex/whispers#download), or as a [Python library](https://github.com/adeptex/whispers#install), which is meant to facilitate its integration into automated processes and pipelines.
Whispers is an information security analysis tool designed for identifying <u>*hardcoded secrets in structured text and static code*</u> ([CWE-798](https://cwe.mitre.org/data/definitions/798.html)). Whispers can be used as a [standalone binary](https://github.com/adeptex/whispers#download), or as a [Python module](https://github.com/adeptex/whispers#install), which is meant to facilitate its usage individually and as part of automated processes and pipelines at scale.

* :clipboard: [Release notes](https://github.com/adeptex/whispers/blob/master/RELEASE_NOTES.md)
* :gear: [Request a feature](https://github.com/adeptex/whispers/issues/new?assignees=&labels=&template=feature_request.md&title=)
Expand All @@ -32,7 +32,8 @@ pip3 install whispers

## Supported formats

* :clipboard: Complete coverage for JSON, YAML, XML, and [many other formats](https://github.com/adeptex/whispers/blob/master/tests/fixtures).
* :clipboard: **Structured text** coverage for JSON, YAML, XML, and [many other formats](https://github.com/adeptex/whispers/blob/master/tests/fixtures)
* :clipboard: **Static code** coverage for Python, PHP, Java/Scala/Kotlin, JavaScript/TypeScript, Go, and [many other languages](https://semgrep.dev/docs/supported-languages)
* :hammer_and_wrench: [Contribute](https://github.com/adeptex/whispers/issues/new/choose) by submitting format samples!


Expand All @@ -46,8 +47,8 @@ pip3 install whispers
* Authentication tokens
* Webhooks
* Sensitive files
* Python functions
* [See all rules](https://github.com/adeptex/whispers/blob/master/whispers/rules)
* [See all fixtures](https://github.com/adeptex/whispers/blob/master/tests/fixtures)


## Usage
Expand All @@ -67,9 +68,12 @@ whispers --version
```

```bash
# Simplest usage
# Check structured text
whispers dir/or/file

# Check structured text and static code
whispers -a dir/or/file

# Write JSON results to a file instead of the screen
whispers dir/or/file -o /tmp/secrets.json

Expand Down Expand Up @@ -141,13 +145,18 @@ for secret in whispers.secrets(args):

## Docker

```bash
docker build -t=whispers .
```sh
make build-image

# Test
docker run -v $(pwd)/tests/fixtures:/src whispers -F None /src
docker run -v $(pwd)/tests/fixtures:/src whispers --ast -F None /src

# Test with custom config
docker run \
--volume $(pwd)/tests/fixtures:/src \
--volume $(pwd)/tests/configs/integration.yml:/config.yml \
whispers --config /config.yml .
whispers -c /config.yml /src
```


Expand Down Expand Up @@ -194,6 +203,8 @@ See [whispers/models/appconfig.py](https://github.com/adeptex/whispers/blob/mast
```yaml
ast: false

include:
files:
- "**/*.yml" # glob
Expand Down
92 changes: 59 additions & 33 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,81 @@
# Whispers 2.2.0 release notes
# Whispers 2.3.0 release notes

* License change
* Compatibility improvements
* Standardize severity levels
* Minor code refactor
* Detection improvements
* Add XML cases
* Add `apikey-maybe` rule
* **New Feature:** 💫 <u>Static Code Analysis</u> 💫 is now supported!
* The present release complements classic Whispers' structured text analysis with [Semgrep](https://semgrep.dev)'s AST generator for [common programming languages](https://semgrep.dev/docs/supported-languages) like Python, PHP, Java/Scala/Kotlin, JavaScript/TypeScript, Go, etc etc.
* New argument `--ast` for enabling this feature via the CLI (it is disabled by default)
* New setting `ast: true` for enabling this feature via a custom config file (set to `ast: false` by default)
* Replaced [`astroid`](https://github.com/adeptex/whispers/blob/8f17f77e2199c55458ff125e3fb477a2a9349593/whispers/plugins/python.py) Python AST generator with [`semgrep`](https://github.com/adeptex/whispers/blob/master/whispers/plugins/semgrep.py)

* [Detection rule](https://github.com/adeptex/whispers/blob/master/whispers/rules) improvements
* Known API keys
* AWS account ID
* Passwords
* Creditcards

* Drop end-of-life Python support
* Versions 3.6 and 3.7 are no longer supported. Oldest supported version is Python 3.8.
* Last release that supports Python 3.6 and 3.7 is [Whispers 2.2.1](https://github.com/adeptex/whispers/releases/tag/2.2.1)

## 💫 Licensing changes (again) 💫
* Dependency tracking improvements
* New [`requirements-dev.txt`](https://github.com/adeptex/whispers/blob/master/requirements-dev.txt) file allows Dependabot updates for dev dependencies
* Modified [`setup.py`](https://github.com/adeptex/whispers/blob/master/setup.py) to read from `requirements.txt` and `requirements-dev.txt`
* Updated build CI to use Python 3.12.3

Version 2.1 was released under [GNU General Public License v3.0](https://github.com/adeptex/whispers/blob/3f5282ea3855d658ea37ec96dfc693598c16d7a7/LICENSE), which is `intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users.`
* Debugging and troubleshooting
* Modified [`config.yml`](https://github.com/adeptex/whispers/blob/master/whispers/config.yml) to exclude known false positives
* Fixed [`Dockerfile`](https://github.com/adeptex/whispers/blob/master/Dockerfile) to work with `docker build -t whispers .` or the same `make image`
* New arg `--dump` for generating an AST of a file: `whispers --dump src/example.ts`

Version 2.2 is released under [BSD 3-Clause License](https://github.com/adeptex/whispers/blob/master/LICENSE), which is a permissive license that `prohibits others from using the name of the copyright holder or its contributors to promote derived products without written consent.`

This change removes source code disclosure requirement 🕵️
## 💫 New Feature: Static Code Analysis 💫

With the release of Whispers 2.3, it is now possible to accurately apply Whispers' secret detection techniques for structured text to static code. Before this release, Whispers only supported structured text formats, such as JSON or XML. [Semgrep](https://semgrep.dev) is an open source SAST tool, which has a built-in feature for generating Abstract Structure Trees (ASTs) for [many common programming languages](https://semgrep.dev/docs/supported-languages). Generating an AST for static code yields an accurate structured text representation, which can be checked for secrets with Whispers' rules and plugins. As such, generating ASTs requires an additional "format conversion" step, which naturally affects runtime speed. When AST is enabled it will take longer to scan the same scope if any source code files are present. The increased amount of runtime time would be however long it takes to run the following command on all static code files in scope:

## ❌ Breaking changes ❌
```sh
semgrep scan --metrics=off --quiet --dump-ast --json --lang $LANG $SRCFILE
```

Consider the following benchmarks:

```sh
time whispers -F " " tests/fixtures
# 313 detected secrets
# 0,51s user 0,03s system 99% cpu 0,540 total
# 0,60s user 0,04s system 99% cpu 0,642 total

### ❌ Severity levels ❌
time whispers -a -F " " tests/fixtures
# 421 detected secrets
# 2,20s user 0,40s system 100% cpu 2,589 total
# 2,32s user 0,46s system 100% cpu 2,772 total
```

Severity level names have been adapted to a more common format. For example, `BLOCKER` is replaced by `Critical` and so on. The full list is as follows:
AST conversion is **disabled by default** - `semgrep` will **not** execute at all unless explicitly enabled. Custom config files that are missing `ast: false` or `ast: true` will default to `false`.

| Version 2.1 (before) | Version 2.2 (now) |
|---|---|
| `BLOCKER` | `Critical` |
| `CRITICAL` | `High` |
| `MAJOR` | `Medium` |
| `MINOR` | `Low` |
| `INFO` | `Info` |
```yaml
ast: true # enable AST in config.yml
```
⚠️ **Please update your custom rules and CLI args to reflect these changes** ⚠️
```sh
whispers --ast target/dir/or/file # enable AST in CLI
```

Instead of

> `whispers -s BLOCKER dir/or/file`
## ❌ Breaking changes ❌

### ❌ Replaced `astroid` with `semgrep`

use
Before Whispers 2.3, only Python AST scanning was natively supported by `astroid`, and integrated via [`plugins/python.py`](https://github.com/adeptex/whispers/blob/8f17f77e2199c55458ff125e3fb477a2a9349593/whispers/plugins/python.py). With the release of Whispers 2.3, this functionality is superseded by `semgrep`, and integrated via [`plugins/semgrep.py`](https://github.com/adeptex/whispers/blob/master/whispers/plugins/semgrep.py). As a base line, the new `semgrep` plugin detects the same findings as the `astroid` plugin, but supports more programming languages.

> `whispers -s Critical dir/or/file`
Unfortunately `semgrep` has telemetry enabled by default, but can be turned off via [`--metrics=off`](https://github.com/adeptex/whispers/blob/master/whispers/plugins/semgrep.py#L57). In any case, `semgrep` will not execute unless explicitly enabled via args or config.

See [README](https://github.com/adeptex/whispers#readme) for details and examples.
⚠️ **NOTE:** At the time of writing, `semgrep` [does not support Windows OS natively](https://github.com/semgrep/semgrep/issues/1330), and can only be installed through WSL. As such, compiled Whispers PE32+ executable comes without Static Code Analysis support. Installing Whispers on Windows via WSL with `pip3 install whispers` *does* have Static Code Analysis support.


# Changelog

|Version|Release notes|
|---|---|
|2.0.0|https://github.com/adeptex/whispers/releases/tag/2.0.0|
|2.1.0|https://github.com/adeptex/whispers/releases/tag/2.1.0|
|2.2.0|https://github.com/adeptex/whispers/releases/tag/2.2.0|
|Date|Version|Release notes|
|---|---|---|
|2021-12-07|2.0.0|https://github.com/adeptex/whispers/releases/tag/2.0.0|
|2022-07-29|2.1.0|https://github.com/adeptex/whispers/releases/tag/2.1.0|
|2023-10-23|2.2.0|https://github.com/adeptex/whispers/releases/tag/2.2.0|
|2024-06-15|2.3.0|https://github.com/adeptex/whispers/releases/tag/2.3.0|
14 changes: 14 additions & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
autoflake~=1.4
autopep8~=1.7
black==22.8; python_version <= '3.6'
black~=24.3; python_version > '3.6'
build~=0.8
coverage~=4.5
coverage-badge~=1.0
flake8~=5.0
isort~=5.9
pytest~=7.0
pytest-mock~=3.6
pip-tools~=6.2
wheel~=0.37
twine~=3.4
Loading

0 comments on commit e6694d7

Please sign in to comment.