Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ builds:

archives:
- id: default
format: tar.gz
formats: [tar.gz]
name_template: >-
{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}
format_overrides:
- goos: windows
format: zip
formats: [zip]
files:
- LICENSE
- README.md
Expand Down Expand Up @@ -102,21 +102,20 @@ release:

Verify your download with the checksums.txt file.

brews:
# A cask has no install or test block: its binary stanza installs cryptoscan.
homebrew_casks:
- name: cryptoscan
repository:
owner: csnp
name: homebrew-tap
token: "{{ .Env.HOMEBREW_TAP_TOKEN }}"
skip_upload: true
directory: Formula
directory: Casks
homepage: https://qramm.org
description: Cryptographic discovery tool for the post-quantum era
license: Apache-2.0
install: |
bin.install "cryptoscan"
test: |
system "#{bin}/cryptoscan", "--version"
binaries:
- cryptoscan

nfpms:
- id: packages
Expand Down
114 changes: 114 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,65 @@ All notable changes to CryptoScan are recorded here. This project follows

## [Unreleased]

### Added

- **A scan names the `node_modules` directories it did not enter.** Installed
packages were left out of every scan without a word. The text report of
`scan` now lists each `node_modules` directory the walk passed over,
relative to the scan root, under
`N dependency directories were not scanned, so the packages installed there are not in this report:`,
and says that passing a package's directory to `cryptoscan scan` scans it.
JSON output carries the list as `skippedDependencyDirs`, an empty array when
there is none, and JSON, CSV, SARIF and CBOM output print it on stderr. A
`node_modules` directory inside another one is not reached, so it is not
listed.

### Changed

- **A JSON finding names its severity.** `--format json` wrote each finding's
severity as a number from 0 to 4, as in `"severity": 3`, while
`summary.bySeverity` is keyed by name. Each finding now carries the name, as
in `"severity": "HIGH"`, the form `summary.bySeverity`, the text report, CSV
and `cryptoscan patterns list --format json` use. A reader that compared the
number has to compare the name. A JSON report written by an earlier release,
with numbers, still loads as a `--baseline`.
- **Every JSON finding has `algorithm` and `keySize`.** Both keys were left out
of a finding that had no value for them. They are now on every finding, as
`null` when the pattern names no algorithm or records no key size, and they
are the last two keys of the finding object.
- **CBOM components describe more of what was found.** In `--format cbom` and
`cryptoscan cbom` output, AES-GCM and ChaCha20-Poly1305 have the primitive
`ae`, the CycloneDX value for authenticated encryption, where they had
`other` and `mac`. TLS findings are `protocol` assets with
`protocolProperties` of type `tls` and the TLS version their match names,
one component per version, where they were algorithm assets with primitive
`other`. Findings in the `Configuration`, `Library Import` and
`PQC Library Import` categories that name no algorithm, such as
`Hardcoded Key Size` and `Post-Quantum Crypto Library`, are left out of the
CBOM rather than written as algorithm components with no properties; the
other formats still report them. A finding with a recorded key size is a
component of its own, named with the size, such as `RSA-1024` with
`classicalSecurityLevel` 80. One `RSA` component used to hold every RSA
finding with the level of the first one, which on `crypto-samples` gave 80
to all 15 occurrences; RSA findings with no recorded size now carry no
level. [CBOM fields](docs/cbom-fields.md) lists each field as it is now.
- **The text report.** The footer no longer ends with the CSNP mission
statement. A file with one finding reads `(1 finding)` in the TOP PRIORITY
FILES rows and in the `--group-by file` headers, where it read
`(1 findings)`. The list printed while the scan runs stops after 200
matches with the line
`Matches after the first 200 are not listed while the scan runs; the report lists every finding.`,
and the stream footer says how many matches the scan found; the report
after it still lists every finding.
- **Help text.** `cryptoscan --help` opens with what the tool finds, where it
opened with `A powerful tool for discovering cryptographic algorithms`.
`scan --help` says that the report classes SHA-2 and AES as PARTIAL and that
`--include-quantum-safe` lists the SHA-2 findings, and the AES findings at
INFO severity other than AES-GCM and AES-ECB, that a default scan leaves
out, where it called them quantum-safe; `pqc --help` calls them PARTIAL too. The `--fail-on` help says
that, when neither the flag nor `failOn` in the config file is set, the scan
exits 1 when any finding is CRITICAL.

### Fixed

- **A scan that read no files no longer reports a clean result.** A scan of an
Expand All @@ -22,6 +81,61 @@ All notable changes to CryptoScan are recorded here. This project follows
check mark line now appears only when at least one file was scanned. JSON
output is unchanged and already records `filesScanned` as 0.

- **Reports CryptoScan wrote into the scanned tree are listed as not
scanned, instead of being read as source.** The
README and `docs/ci.md` write reports into the tree they scan, for example
with `cryptoscan scan . --format sarif --output results.sarif`, and the next
scan read them as source. Run twice in a copy of `crypto-samples`, that
command wrote 110 results and then 903. A directory holding only the pretty
JSON report of `crypto-samples` gave 1313 findings, its SARIF report 793 and
its CBOM 184, and each of those scans exited 1. A scan now leaves out a file
that starts like a CryptoScan report: JSON from `scan`, `gate` or `pqc`
(`tool.name` is `CryptoScan`), SARIF (`runs[].tool.driver.name`), a
CycloneDX CBOM (`metadata.tools[].name`), a CSV report (its header row), or
a text report (its title box, or the `Scanning...` line of streamed
output). It also leaves out the file `--output` names, whatever that file
holds. Each such file is named as not scanned, with a reason such as
`CryptoScan report: SARIF` or
`CryptoScan report: the --output file of this scan`, in the text summary,
on stderr for the other formats, and under `skippedFiles` in JSON. A report
saved as documentation, such as `report.txt` or a file under `docs/`, was
already left out of the scan and is still not listed. The text summary adds
`To leave CryptoScan reports off this list, write them outside the scanned folder or pass their names to --exclude.`
The same command now writes 110 results on both runs, and each of the
three report directories gives 0 findings and exits 0. The CSV report and
the single-line JSON report of `crypto-samples` were already left out, as
minified; they are now named as CryptoScan reports.

- **Dependency findings for libraries without post-quantum algorithms name a
change.** Eleven of the libraries the scanner recognizes in dependency
manifests, among them `node-forge`, `tweetnacl`, `jose` and `pycryptodome`,
printed `Fix: Plan migration to a PQC-capable library or enable hybrid mode when available.`,
which names no change to make. Each library without post-quantum
algorithms now names what to move and what to move it to and, for
public-key algorithms in a Python, JavaScript, Go, Java or Rust library,
the post-quantum library the remediation engine names for that language,
for example
`Add liboqs-node and move RSA from node-forge to ML-KEM-768 for encryption and key exchange and ML-DSA-65 for signatures`.
The `cryptography` entry, which said
`Add liboqs-python for PQC support alongside cryptography`, now names what
to move as well. The text is the `Fix:` line of the text report and the
`fix` and `remediation` fields of JSON findings; SARIF writes it as the
`help.text` of the finding's rule, and CSV in its Remediation column.

### Changed

- **The release configuration uses the current GoReleaser keys.**
`goreleaser check` (GoReleaser 2.17.1) reported `archives.format`,
`archives.format_overrides.format` and `brews` as deprecated and exited 2.
The archives now set `formats`, and the Homebrew definition is a cask
(`homebrew_casks`), written to `dist/homebrew/Casks/cryptoscan.rb` in place
of the formula in `dist/homebrew/Formula/cryptoscan.rb`. It is still not
uploaded to the tap (`skip_upload: true`). A cask has no `install` or `test`
block, so the formula's `bin.install` and `--version` test are gone; the
cask's `binary "cryptoscan"` stanza installs the binary. `goreleaser check`
now exits 0, and a snapshot build writes the same six archives as before:
tar.gz for Linux and macOS, zip for Windows.

## [1.5.0] - 2026-10-18

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ CryptoScan goes beyond simple pattern matching:
- **Confidence scoring**: Findings in comments, logs, or docs are marked low confidence
- **File type awareness**: Different severity for code vs. test vs. documentation
- **Language detection**: 15+ programming languages recognized
- **Noise reduction**: Automatically filters minified files, lock files, and build artifacts. The scan summary counts the minified files it left out and names up to ten; JSON output lists them under `skippedFiles`
- **Noise reduction**: Automatically filters minified files, lock files, build artifacts, and the reports CryptoScan writes (JSON, SARIF, CBOM, CSV and text), so a report saved in the project is not scanned as source. The scan summary counts the minified files and reports it left out and names up to ten; JSON output lists them under `skippedFiles`

Algorithm names that appear only in prose, logs or comments are held back from the default report, and the scan summary says how many. [How CryptoScan works](docs/how-it-works.md) explains the rule.

Expand Down
Loading
Loading