Skip to content

Commit 8cdc6b1

Browse files
authored
Version 2.1.0 (#46)
# Whispers 2.1.0 release notes ## ❌ Breaking changes ❌ ### ❌ Arguments ❌ Several arguments have been modified and/or adapted to improve usability. - Human readable output is shown in logs (2.1), `-H` and `--human` (2.0) are removed. - Version can be shown with `--version` (2.1), `-v` (2.0) is removed. - Extended help can be shown with `--info` (2.1), `-i` (2.0) is removed. - Debug mode can be enabled with `--debug` (2.1), `-d` (2.0) is removed. - Logs can be redirected to a file with `--log log.txt` (2.1), constant `/tmp/whispers.log` (2.0) is removed. - Configuration template can be created with `--init` (2.1), `--print_config` (2.0) is removed. ### ❌ Logging ❌ **Version 2.0:** Opt-in logging for tracing execution flow, useful only for debugging. Results printed to `stdout` using `print()` as a JSON dict, one result per line. Enabling logging required adding the `--log` argument. **Version 2.1:** Logging is used to alert identified secrets during execution with `WARNING` level. Results are written to `stdout` as a JSON list at the end. This improves results parseability as a JSON list, while maintaining live results display that was previously achieved by printing secrets as JSON one per line. ## ✅ New features ✅ ### ✅ Results as JSON list ✅ To improve integration and downstream processing, Whispers now outputs results as a JSON list of dictionaries with all detected secrets together (2.1), instead of one JSON dictionary per line (2.0). This list is directly loadable and parsable as JSON.
1 parent cb168c2 commit 8cdc6b1

25 files changed

+153
-434
lines changed

.dockerignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ __pycache__/
6161
.Python
6262
build/
6363
develop-eggs/
64-
dist/
64+
# dist/
6565
downloads/
6666
eggs/
6767
.eggs/

.github/workflows/build.yml

+3
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,6 @@ jobs:
4949

5050
- name: coverage
5151
run: make coverage
52+
53+
- name: package
54+
run: python3 -m build

Dockerfile

+10-13
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
FROM python:3.8.1-slim-buster
1+
FROM python:3.9-slim
22

3-
USER root
4-
ENV HOME="/opt/whispers"
5-
RUN useradd --home-dir $HOME --shell /bin/false user
6-
7-
WORKDIR $HOME
8-
COPY . $HOME/
93
RUN apt update \
10-
&& apt install -y build-essential python3-lxml python3-yaml \
11-
&& apt clean \
12-
&& make install \
13-
&& chown -R user:user $HOME \
14-
&& whispers -v
4+
&& apt install -y make python3-lxml python3-yaml \
5+
&& apt clean
6+
7+
WORKDIR /src
8+
9+
COPY dist/*.tar.gz .
10+
11+
RUN pip3 install *.tar.gz \
12+
&& rm -rf *.tar.gz
1513

16-
USER user
1714
ENTRYPOINT [ "whispers" ]

Makefile

+4-3
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ coverage:
3333
test:
3434
make lint coverage
3535

36-
docker:
36+
build-image:
37+
python3 -m build
3738
docker build -t=whispers --rm=true .
38-
docker rmi -f $$(docker images --filter "dangling=true" -q --no-trunc)
39+
# docker rmi -f $$(docker images --filter "dangling=true" -q --no-trunc)
3940

4041
freeze:
4142
CUSTOM_COMPILE_COMMAND="make freeze" \
@@ -65,4 +66,4 @@ publish:
6566
test-pip:
6667
python3 -m pip install --index-url https://test.pypi.org/simple/ --no-deps whispers
6768

68-
.PHONY: install install-dev isort-lint black-lint flake8-lint format lint unit coverage test publish
69+
.PHONY: install install-dev isort-lint black-lint flake8-lint format lint unit coverage test publish build-image

README.md

+23-10
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,22 @@ whispers
5454

5555
# More information about Whispers
5656
whispers --info
57+
58+
# Show installed version
59+
whispers --version
5760
```
5861

5962
```bash
60-
# Simplest usage with JSON output
63+
# Simplest usage
6164
whispers dir/or/file
6265

63-
# Simplest usage with human-readable output
64-
whispers -H dir/or/file
66+
# Write JSON results to a file instead of the screen
67+
whispers dir/or/file -o /tmp/secrets.json
6568

66-
# Write results to a file instead of the screen
67-
whispers -o /tmp/secrets.json dir/or/file
69+
# Pipe JSON results downstream
70+
whispers dir/or/file | jq '.[].value'
6871

69-
# Advanced usage:
72+
# Custom usage:
7073
# - only check 'keys' rule group
7174
# - with BLOCKER or CRITICAL severity
7275
# - everywhere in target/dir except for .log & .raw files (regex)
@@ -75,12 +78,12 @@ whispers -g keys -s BLOCKER,CRITICAL -F '.*\.(log|raw)' target/dir
7578

7679
```bash
7780
# Configuration file template
78-
whispers --print_config > config.yml
81+
whispers --init > config.yml
7982

8083
# Provide custom configuration file
8184
whispers --config config.yml dir/or/file
8285

83-
# Return this system code on success
86+
# Return custom system code on success
8487
whispers --exitcode 7 dir/or/file
8588
```
8689

@@ -129,6 +132,16 @@ for secret in whispers.secrets(args):
129132
```
130133

131134

135+
## Docker
136+
137+
```bash
138+
docker run \
139+
--volume $(pwd)/tests/fixtures:/src \
140+
--volume $(pwd)/tests/configs/integration.yml:/config.yml \
141+
ghcr.io/adeptex/whispers --config /config.yml .
142+
```
143+
144+
132145
## Config
133146

134147
There are several configuration options available in Whispers. It’s possible to include and exclude results based on file path, keys, values, individual or grouped rules, and severity levels. There is a [default configuration file](https://github.com/adeptex/whispers/blob/master/whispers/config.yml) that will be used if you don't specify a custom one.
@@ -204,7 +217,7 @@ exclude:
204217
The fastest way to tweak detection in a repeatable way (ie: remove false positives and unwanted results) is to copy the default [config.yml](https://github.com/adeptex/whispers/blob/master/whispers/config.yml) into a new file, adapt it, and pass it as an argument to Whispers, for example:
205218

206219
```sh
207-
whispers --print_config > custom.yml
220+
whispers --init > custom.yml
208221
# edit custom.yml as needed
209222
whispers -c custom.yml target
210223
```
@@ -293,7 +306,7 @@ class PluginName:
293306

294307
## Development
295308

296-
```
309+
```bash
297310
git clone https://github.com/adeptex/whispers
298311
cd whispers
299312
make install-dev

RELEASE_NOTES.md

+14-183
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,33 @@
1-
# Whispers 2.0.0 release notes
2-
3-
## :dizzy: Licensing changes :dizzy:
4-
5-
Version 1 was developed and open sourced by [Artёm Tsvetkov](https://github.com/adeptex) at [Skyscanner](https://github.com/Skyscanner/whispers) under [Apache License 2.0](https://github.com/Skyscanner/whispers/blob/master/LICENSE), which states that `licensed works, modifications, and larger works may be distributed under different terms and without source code.`
6-
7-
Version 2 is an independent continuation of my work, which is now released under [GNU General Public License v3.0](https://github.com/adeptex/whispers/blob/master/LICENSE) that 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.`
8-
1+
# Whispers 2.1.0 release notes
92

103
## :x: Breaking changes :x:
114

12-
### :x: Integration :x:
13-
In version 1, Python integration required multiple imports and a correctly-formatted list of values ([ref](https://github.com/Skyscanner/whispers#python)).
14-
15-
In version 2, the integration is simplified to a single import and a string of CLI arguments. The following example illustrates current Python integration:
16-
17-
```py
18-
import whispers
19-
20-
args = (
21-
"-c whispers/config.yml "
22-
"-r apikey,aws-secret,password "
23-
"-s BLOCKER,CRITICAL,MAJOR "
24-
"tests/fixtures"
25-
)
26-
27-
for secret in whispers.secrets(args):
28-
print(f"[{secret.file}:{secret.line}] {secret.key} = {secret.value}")
29-
```
30-
31-
### :x: File exclusion globs are now regex :x:
32-
In version 1, the configuration file expected file exclusion specification to be a list of globs. Whispers would then resolve included globs, resolve excluded globs, and finally subtract the two lists to get applicable scope. The entire target directory tree would be traversed twice to compute applicable files (highly resource-intensive operation!)
33-
34-
In version 2, file exclusions are specified as regex. Instead of resolving globs, Whispers now uses the generator directly. Every file path received from the glob generator is now checked against the file exclusion regex to determine whether the file should be excluded on-the-fly.
35-
36-
This highly improves performance for cases where the target directory contains a large number of files. In version 2 the tree is traversed file by file, individually checking if the file path matches a pre-compiled exclusion regex. This decreases CPU, RAM and time needed to scan directories of potentially unlimited trees and depths.
37-
38-
39-
### :x: Rule names and severity levels :x:
40-
Rule names and severity levels were adapted to make usage more intuitive, and results more useful. The following is the exhaustive list of default rules included in version 2:
41-
42-
| Group | Rule ID | Severity |
43-
|----------------------|----------------------|---------------------|
44-
| files | file-known | MINOR |
45-
| infra | dockercfg | CRITICAL |
46-
| infra | htpasswd | MAJOR |
47-
| infra | npmrc | CRITICAL |
48-
| infra | pip | CRITICAL |
49-
| infra | pypirc | CRITICAL |
50-
| keys | apikey | MAJOR |
51-
| keys | apikey-known | CRITICAL |
52-
| keys | aws-id | BLOCKER |
53-
| keys | aws-secret | BLOCKER |
54-
| keys | aws-token | BLOCKER |
55-
| keys | privatekey | CRITICAL |
56-
| misc | comment | INFO |
57-
| misc | creditcard | MINOR |
58-
| misc | secret | MINOR |
59-
| misc | webhook | MINOR |
60-
| passwords | password | CRITICAL |
61-
| passwords | uri | CRITICAL |
62-
| python | cors | MINOR |
63-
| python | system | MINOR |
64-
65-
Make sure to review and adapt your integration accordingly.
66-
67-
68-
### :x: Rule specification format changes :x:
69-
In version 1 the rules were defined as a dictionary with rule ID as the key and rule config as the value. This created awkward parsing practices and unintuitive code. For example:
70-
```yaml
71-
npmrc:
72-
description: Hardcoded .npmrc authToken
73-
message: .npmrc authToken
74-
severity: CRITICAL
75-
key:
76-
regex: ^npm authToken$
77-
ignorecase: False
78-
```
79-
80-
In version 2 the rules are defined as a list of dictionaries. The rule ID now has its own `id` key inside the rule config definition. For example:
81-
```yaml
82-
- id: npmrc
83-
group: infra
84-
description: Hardcoded .npmrc authToken
85-
message: .npmrc authToken
86-
severity: CRITICAL
87-
key:
88-
regex: ^npm authToken$
89-
ignorecase: False
90-
```
91-
92-
If you have any custom rule definitions, you will have to adjust them for migrating to version 2.
93-
94-
There is an additional new `groups` parameter that can be used to group rules.
95-
96-
97-
### :x: Rule naming :x:
5+
### :x: Arguments :x:
986

99-
Some rules IDs were changed to gain a consitent naming format, please [refer to rules](whispers/rules).
7+
Several arguments have been modified and/or adapted to improve usability.
1008

9+
- Human readable output is shown in logs (2.1), `-H` and `--human` (2.0) are removed.
10110

102-
### :x: Output file format :x:
103-
In version 1 the output file was written in YAML with awkward indexing, which made results unusable.
11+
- Version can be shown with `--version` (2.1), `-v` (2.0) is removed.
10412

105-
In version 2 the same JSON output as `stdout` is written to the output file, making it easier to parse.
13+
- Extended help can be shown with `--info` (2.1), `-i` (2.0) is removed.
10614

15+
- Debug mode can be enabled with `--debug` (2.1), `-d` (2.0) is removed.
10716

108-
### :x: Log file :x:
109-
In version 1, `whispers.log` is always created in the same directory from which Whispers was executed. The log file remains after execution.
17+
- Logs can be redirected to a file with `--log log.txt` (2.1), constant `/tmp/whispers.log` (2.0) is removed.
11018

111-
In version 2, the log file will not be created by default, unless explicitly enabled with an argument: `whispers --log src`. The log is only useful for reviewing exceptions and bugs, not for common usage. In addition, the log will now be written to `/tmp/whispers.log` (Posix) or `%TEMP%\whispers.log` (Windows) so that it does not interfere with analysis or permissions.
19+
- Configuration template can be created with `--init` (2.1), `--print_config` (2.0) is removed.
11220

113-
Together, `--log` and `--debug` can be used to investigate exceptions and bugs. Please [submit a bug report](issues/new) if you find something unexpected!
11421

22+
### :x: Logging :x:
11523

116-
### :x: Removed support for dynamic languages :x:
117-
In version 1 the following language files were parsed as text and checked for common variable declaration and assignment patterns:
118-
* JavaScript
119-
* Java
120-
* Go
121-
* PHP
24+
**Version 2.0:** Opt-in logging for tracing execution flow, useful only for debugging. Results printed to `stdout` using `print()` as a JSON dict, one result per line. Enabling logging required adding the `--log` argument.
12225

123-
It is not possible to parse these languages as Abstract Syntax Trees (ASTs) in Python. The initial attempt was to detect "low hanging fruit" by parsing the files as text instead. This lead to poor functional coverage, as well as a potentially false sense of security.
124-
125-
In version 2 the support for these dynamic languages is dropped. This allowed bringing unit test coverage up to 100%, and in this way ensuring result reliability and true security coverage. It is recommended to rely on AST-based parsing for dynamic languages for getting reliable results. Check out [Semgrep](https://github.com/returntocorp/semgrep)!
126-
127-
Python3 remains fully supported in Whispers 2.
128-
129-
130-
### :x: Replace Levenshtein with Jaro-Winkler :x:
131-
In version 1, [python-Levenshtein](https://github.com/ztane/python-Levenshtein) was used for key-value similarity comparisons (`similar` config parameter). This library is written in Cython and requires additional dependencies for installing. This made it not easily compatible with Windows systems, because additional Visual Studio dependencies needed to be present before installing Whispers.
132-
133-
In version 2, [Jaro-Winkler](https://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance) algorithm is used for similarity comparisons, using the [jellyfish](https://github.com/jamesturk/jellyfish) library, for improved approximate and phonetic string matching. As an additional effect, this change allows installing Whispers on Windows through `pip` without Visual Studio dependencies.
134-
135-
This change should have no effect and behave in a consistent manner. If you have rules that specifically rely on `similar` for key-value comparisons, these may need to be manually tuned.
136-
137-
138-
## :hammer_and_wrench: Improvements :hammer_and_wrench:
139-
140-
### :hammer_and_wrench: Improved support for Windows and MacOS :hammer_and_wrench:
141-
142-
Whispers now runs on Linux, MacOS, and Windows. Install it from PyPI like so: `pip3 install whispers`.
143-
144-
### :hammer_and_wrench: Secrets detection :hammer_and_wrench:
145-
146-
- Added support for Gradle and Maven credentials
147-
- Improved private key detection
148-
- Added known API key formats ([GitGuardian](https://docs.gitguardian.com/secrets-detection/detectors/))
149-
- Added knwon file extensions ([tell_me_your_secrets](https://github.com/valayDave/tell-me-your-secrets/blob/master/tell_me_your_secrets/config.yml))
150-
151-
152-
### :hammer_and_wrench: Include and Exclude by Rule and Severity :hammer_and_wrench:
153-
Individual and grouped rules and severity levels to be included or excluded can now be directly specified with CLI args:
154-
155-
Exclude known files from results: `whispers -R known-file`
156-
Exclude miscellaneous results: `whispers -G misc`
157-
Exclude MAJOR and MINOR severity level results: `whispers -S MAJOR,MINOR`
158-
159-
It is also possible to specify included and excluded rules and severity levels via config.yml. Custom rules can be added directly to the list using the following format:
160-
```yaml
161-
exclude:
162-
files:
163-
- \.npmrc
164-
- .*coded.*
165-
- \.git/.*
166-
keys:
167-
- SECRET_VALUE_KEY
168-
values:
169-
- SECRET_VALUE_PLACEHOLDER
170-
rules:
171-
- password
172-
- uri
173-
- id: starks
174-
message: Whispers from the North
175-
severity: CRITICAL
176-
value:
177-
regex: (Aria|Ned) Stark
178-
ignorecase: True
179-
groups:
180-
- misc
181-
182-
exclude:
183-
severity:
184-
- MINOR
185-
186-
```
187-
188-
If you don't specify any rules, all built-in rules will be used be default. If you do, only those that you specify will be applicable. For a full list of available rules check `whispers --info`.
189-
190-
If you don't specify any severity, all built-in severity levels will be used be default - BLOCKER, CRITICAL, MAJOR, MINOR, INFO.
191-
If you do, only those that you specify will be applicable.
26+
**Version 2.1:** Logging is used to alert identified secrets during execution with `WARNING` level. Results are written to `stdout` as a JSON list at the end. This improves results parseability as a JSON list, while maintaining live results display that was previously achieved by printing secrets as JSON one per line.
19227

19328

19429
## :white_check_mark: New features :white_check_mark:
19530

196-
**No new features** were introduced in this release. Whispers 2 still does the same thing as 1, only better and faster.
197-
198-
The primary objective of the present release was to optimize version 1 logic in order to make it easier to read, understand, and work with in general. This refactoring, along with the aforementioned breaking changes, have shown to increase scanning speed up to 7-10 times (depending on conditions). In addition, it allowed achieving 100% unit test coverage.
199-
200-
Other focus areas of version 2 were improving usability, like being able to easily filter results in and out from CLI; not writing a log file by default; dropping support for untestable dynamic code scanning; and making code more Pythonic by using built-in features and dataclass models.
31+
### :white_check_mark: Results as JSON list :white_check_mark:
20132

202-
Complete list of arguments, rules, and severity levels can be found in `whispers --info`, along with documentation in [README.md](https://github.com/adeptex/whispers/blob/master/README.md).
33+
To improve integration and downstream processing, Whispers now outputs results as a JSON list of dictionaries with all detected secrets together (2.1), instead of one JSON dictionary per line (2.0). This list is directly loadable and parsable as JSON.

setup.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"autoflake~=1.4",
1515
"autopep8~=1.5",
1616
"black~=19.10b0",
17+
"build~=0.8",
1718
"coverage~=4.5",
1819
"coverage-badge~=1.0",
1920
"flake8~=3.9",
@@ -50,5 +51,5 @@ def get_readme():
5051
setup_requires=["pytest-runner"],
5152
tests_require=dev_requires,
5253
extras_require={"dev": dev_requires},
53-
entry_points={"console_scripts": ["whispers=whispers.main:cli"]},
54+
entry_points={"console_scripts": ["whispers=whispers.main:main"]},
5455
)

0 commit comments

Comments
 (0)