Skip to content

Releases: shsingh/pqscan

pqscan 2026.01

Choose a tag to compare

@github-actions github-actions released this 22 Oct 13:09
2026.01
6edba15

pqscan 2026.01 — the release cut

2026.01 is the first general-availability cut. The rc series (2026.01-rc1,
rc2, rc3) stays the historical record. One release page carries this cut; the
rc pages remain for the record.

What this cut carries

  • The QUIC census grows two rungs (PQ-69, merged through the #182 estate).
    The deep census dials the RFC 9369 (QUIC v2) transport version and completes
    one real HTTP/3 GET through the pinned quic-go stack. The record's
    h3_direct claim = the handshake's ALPN answer; the deep findings carry the
    functional h3 verdict beside it. quic/v2 and quic/h3-exchange ride the
    existing QUIC rung gate (-quic-off and an unhinted target stay QUIC-free).
  • The binary size bound = 10,000,000 bytes (10 MB) on both planes
    (PQ-70, PR #186's ledger cure).
    The measured rows: linux/amd64 7,581,858 B
    (the CI-pinned go1.26.0 chain), 8,085,664 B (the go1.27.2 host),
    darwin/arm64 7,644,994 B — every row measured live on the merge tree
    ba89d23; the gate, the ledger and the site card read one bound.
  • The measured performance: 2,750 h/s aggregate (W=8, loopback fixture,
    the runner's same-day reading at the census tip; the SLO ≥ 2,500/s/core
    stays green with every run). The site card and this README carry the same
    number.
  • The sites live on their own domains: pqscan.kalatopi.sh,
    opensase.kalatopi.sh, ai-sec-lab.kalatopi.sh — HTTPS enforced, per-domain
    certificates, the DNS records live.
  • The writing standard (ASD-STE100) rides every user-facing surface:
    the CLI's help and refusal strings, the -explain prose, the repository
    documents, the site pages. The rendered pages carry no tracking ids.

The install

The release page carries the per-platform binaries, CHECKSUMS-sha256.txt, and
per-asset attestations. The install paths read INSTALL.md; the examples pin
2026.01.

  • Homebrew: the tap formula bumps with this cut.
  • Source: go install github.com/shsingh/pqscan/cmd/pqscan@2026.01

The tag carries a signed annotated object; the publish gate ran the full
strict consistency check at the tagged tree before the dispatch.

pqscan 2026.01-rc3

Choose a tag to compare

@github-actions github-actions released this 20 Oct 11:37
2026.01-rc3
c969064

pqscan 2026.01-rc3

The successor release candidate to 2026.01-rc2. rc3 is the
quality-gate day: the CLI surface went through a three-way parity census
against the reference tools, every documented flag combination is
machine-run on CI, the chain adapters read version-stamped pinned captures,
and error records finally meet the same schema contract success records
have had since schema 1.

The surface census: the documented surface is the real surface

The three-way census over the CLI surface — every spec row against its
USAGE.md row against the implemented state — landed in
docs/surface-census.md
(issue #146, PR
#151):

  • Planned-list cuts: -quic (superseded by the shipped -quic-always /
    -quic-off pair; the bare flag has no independent reading) and -verify
    (owned by no contract row; naabu's -verify is a captured name collision)
    leave the planned surface.
  • The spec's never-needed negative rows are cut: -stream, -ja4,
    -ca-bundle, -no-ptr, -no-color.
  • -jarm earned its documented row (httpx v1.12.0's -jarm is the captured
    convention) and stays a documented-ahead row in the planned surface.
  • -from-nuclei entered the surface and shipped in this same wave (below).

Every parity claim is a captured help line, version-stamped offline
(captures: naabu 2.6.1, httpx v1.12.0, subfinder v2.16.0, nuclei v3.11.1 —
help/version surfaces only, no scanned targets). The verdict rule: a row
earns its place iff a contract row plus a reference-tool or chain contract
needs it; it is cut iff superseded by a shipped sibling or owned by nothing.

The flag matrix

PQ-53 (issue #147, PR
#152): a generated pairwise
covering array over the CLI surface — the domain table
(tests/matrix/domains.json), 20 cases (tests/matrix/cases.jsonl) —
regenerated by scripts/gen_flag_matrix.go behind a self-verifying gate: CI
re-pins the array, regenerates, and compares three-way. The flag-matrix
context joined the required checks: every change is machine-run against the
documented combinations.

The combination batteries

PQ-54 (issue #148, PR
#155): the whole-argv property
battery over the unenumerated input space — two fixed seeds × 200 vectors
per tests/matrix/battery_test.go run (rotatable via PQ54_SEEDS; the
fixed seeds always run) — plus the documented exit-64 refusal classes as
deliberate battery rows whose expected text quotes the binary's own refusal
lines. Pooled and calibrated to the CI runner's wall budget.

The chain matrix and the adapters

PQ-55 (issue #149, PR
#158): -from-nuclei reads
the pinned capture (nuclei -l hosts.txt -silent -j — one JSON finding per
line, the matched-at host:port with the url as the fallback, scheme and path
stripped) into the one composition shared with -u / -l / -- and the
other adapters, deduped by host:port. The adapters' consumer cells joined
the matrix run, and every adapter input dialect is pinned by a
version-stamped capture before its parse contract — the httpx -csv
dialect's real captured shape is the pinned reality the docs quote.

The combination ledger

PQ-56 (issue #150, PR
#160):
tests/matrix/LEDGER.md pins landed truth — one
checkbox per matrix cell in the issue registry, a per-cell PASS/SKIP line
posted per build, green cells ticked with the proven commit, and every fix
or feature landing its own cell in the same change.

The doc-reference scrub

PQ-57 (issue #153, PRs
#161 and
#163): the tool's user-facing
strings carry zero PRD references — no doc-file paths, no internal tokens,
no issue-register mentions anywhere user-facing. The surface audit gained a
zero-reference census (it renders the live surface and greps one inventory:
doc-file paths, .md tokens, PQ-N ids, status words), so a re-introduced
reference fails CI. The sweep is recorded in the spec's test-and-verification
chapter (section 10).

Errors meet the record contract

PQ-60 (issue #157, PR
#162): schema-required blocks
emit unconditionally on BOTH record classes — the handshake zero-halves and
the quic block appear on error-class and skipped runs exactly as on success
records (omitempty is forbidden on the schema's required field list), and
TestErrorRecordSchemaContract pins the uniform contract against the
published docs/schema-v1.json. The error.* goldens
regenerated; the success-class goldens stayed byte-identical — the cure did
not disturb the valid shapes.

The recipes and the docs re-capture

PQ-58 (issue #154, PR
#164): every recipe line on
the site is executed live against the current surface and its Observation
quotes that exact run's output; the external-input examples pin the
reference tools' captured dialects (subfinder v2.16.0, httpx v1.12.0,
nuclei v3.11.1, version-stamped in the fixtures).

The performance and size surfaces move with the cut

From rc3 on, every release build is preceded by the release-prep pass
(issue #156): the throughput
SLO + size + resume suites re-run live on the to-be-cut tree, and README's
SLO cell, the site's performance surfaces and the size ledger
(docs/size-ledger.md) carry the measured numbers — the
release gate then verifies rather than prepares. At this cut the throughput
SLO cell stands at 2,952 h/s (re-run 3,026; the engine's handshake planes
are unchanged since 2026.01-rc2 and the CI runner's same-day readings
bracket the documented cell), while the size ledger moved to the measured
tree: 7,131,298 bytes CI-enforced (go1.26.0), 7,643,296 bytes local at
go1.27.2.


Release notes reference: 2026.01-rc2.md. Attestation: gh attestation verify <asset> --owner shsingh; all assets carry SLSA provenance (ADR-0003).

pqscan 2026.01-rc2

Choose a tag to compare

@github-actions github-actions released this 16 Oct 12:28
2026.01-rc2
5874edb

pqscan 2026.01-rc2

The successor release candidate to 2026.01-rc1. rc2 carries the post-rc1 operator wave: the CLI now speaks for itself, the record's human line tells the same story the machine formats carry, the input grammar works the way the Project Discovery chains actually hand off, and the forced PQ ladder is finally visible.

The CLI speaks for itself

  • -version prints the stamp and nothing else — no status words, no internal document references: pqscan 2026.01-rc2.
  • -h is a real help for the practitioner: what the tool observes on both planes, the readiness verdict and its HNDL consequence in plain language, the whole implemented surface grouped (descriptions read straight off the registration surface — one source), runnable examples, the real exit codes (0/1/64), and the reading-the-output glossary. Every flag also parses under two dashes (--word ≡ -word), and the completions + the man page say so.
  • -explain adds a plain-language block under each target line: the verdict in words (zero-signal scans state that scoring is an error state, not a grade), what the negotiated group means (PQ hybrid / classical / obsolete draft, with the harvest-now-decrypt-later consequence), the certificate layer with the rotation that closes the gap, the QUIC plane, and an error-class hint when nothing negotiated. Deep mode adds the executed plan's reading — counts, the matrix yield rolled up by probe family, and the accepted rows named — and pq mode's ladder carries the same reading for the forced offers.

The record's human line tells the whole truth

The default -text line carries the same facts as the machine formats, suffix-appended (existing fields byte-stable):

  • pq=<label>(<score>) — the readiness verdict on the line
  • deep=<plan>:<N>p/<N>ok/<N>rej — the executed plan (or forced ladder) counts
  • cert=<sigAlg>/<keyAlg> with +pq-sig/+pq-key/+dual markers when true — the certificate layer in every mode
  • ptr= / sni= enrichment when present

Rejections stay observations: a refused probe is a result, never an error.

The input grammar works the way the chains do

  • Implicit piped stdin — subfinder -d example.com | pqscan -- still works, and cat targets.txt | pqscan -jsonl now works with no marker at all: piped input is the default target source when no -u/-l/--/adapters are given.
  • -l - — the universal stdin-file alias.
  • scheme://host[:port] lines parse everywhere the host:port grammar does — the httpx -silent handoff flows through the pipe unstripped.
  • The full documented chain now runs end to end: subfinder -d example.com -silent | httpx -silent -p 443 | pqscan -jsonl.

The forced PQ ladder is visible

-mode pq records what the ladder did: a ladder block in the record (mode: "pq", attempted/ok/rejected + one finding per forced offer — the same shape the deep executor uses) and the counts on the line (deep=pq:…p/…ok/…rej). -mode fast and -mode pq no longer look identical.

Shell completions

pqscan -completion bash|zsh emits deterministic completion scripts covering every implemented flag, the choice values, and file completion where a flag takes a path — install one-liners ride the help, USAGE.md and INSTALL.md.

The audit that guards all of the above

go test ./cmd/pqscan/ -run TestCLISurfaceContract -v re-checks the whole human-facing surface on every change — per-flag help/man-page/completion coverage, the meta paths, the exit-code table, a live scan with -explain, and the gate verdicts — so verifying the CLI never requires cutting a binary.

Labels and hygiene

Repository labels are area:* (the primary axis — every issue files the right area) + bug (a genuine operator-facing defect, kept after closure) + the milestone/effort slices; the board's status stays a project field.


Release notes reference: 2026.01-rc1.md. Attestation: gh attestation verify <asset> --owner shsingh; all assets carry SLSA provenance (ADR-0003).

pqscan 2026.01-rc1

Choose a tag to compare

@github-actions github-actions released this 15 Oct 13:10
2026.01-rc1
e5ef250

pqscan 2026.01-rc1 — TLS/QUIC cipher-configuration and PQC readiness scanner

2026.01-rc1 is the milestone-completion candidate: every register leaf
(PQ-02 through
PQ-37) has landed via
reviewed, GPG-signed watched-RED pairs — grammar, pipeline, encoders/WAL/
resume, the usage-drift gate, the IANA registry, the readiness rubric
(+ the live verdict), certificate PQ analytics, congestion control
(limiter/AIMD/breakers with -rate/-threads), the deep-mode plan and
executor, the h3 discovery, the resolver pool and the PD-dialect input
adapters. Artifacts are verifiable before they run
(ADR-0003); the release
gate (PQ-34) re-verifies the
signed tag, the repo's version sync, the site render and FRESH
performance numbers as part of every publish.

Verify

sha256sum -c <(grep <artifact> CHECKSUMS-sha256.txt)
gh attestation verify <artifact> -R shsingh/pqscan

2026.01-rc1 content:

  • goreleaser consolidation (PQ-27):
    the release matrix is now five targets — linux/amd64+arm64,
    darwin/amd64+arm64, windows/amd64 — built by
    goreleaser (v2) from
    .goreleaser.yaml, with CHECKSUMS-sha256.txt over the bare
    pqscan-<os>-<arch> asset names and a deterministic
    GORELEASER_CURRENT_TAG version stamp.
  • Pre-built windows/amd64 binary (the
    PQ-29 install-story
    promise kept): pqscan-windows-amd64.exe, attested like the rest.
  • Release gate as publish pre-flight: the publish job runs
    scripts/check_release_consistency.sh <tag> before creating the release
    (the runner has no release key, so the tag signature is verified at the
    cut machine and recorded here in
    PQ-27).
  • Sample scan dataset committed: docs/sample-scan.jsonl — one live
    fast-mode record against google.com (the reference
    PQ-36 target),
    captured by this cut's build.

pqscan v0.0.2-alpha

Choose a tag to compare

@github-actions github-actions released this 15 Oct 08:33
v0.0.2-alpha
d0a81c6

pqscan v0.0.2-alpha — TLS/QUIC cipher-configuration and PQC readiness scanner

pqscan is a small, fast, chainable TLS/QUIC cipher-configuration and
post-quantum readiness scanner shipped as a single static binary (the
PD-ecosystem contract in
docs/spec.md#5-feature-set).
v0.0.2-alpha is the first development cut; the 2026.01-rc1 name is
reserved for the release that follows completion of the current
milestone set (M1-M5). It packages the engine state
that closed the M0 gate
together with the tooling needed to verify it. Artifacts are verifiable
before they are run — that is the governance contract of this tool.

What is included

  • Both-plane engine proven live. Forced-group probing negotiates the
    PQC hybrid group X25519MLKEM768 (4588) on both transport planes:
    on the TCP plane (internal/tlsx) — TLS 1.3, TLS_AES_128_GCM_SHA256
    (version 772) — and inside QUIC v1 with ALPN h3
    (internal/quicx). Measured against a live hybrid edge, evidence
    verbatim on issue #8
    (TCP) and issue #9
    (QUIC). Rejections are results, not errors: UDP failures are
    classified (refused / blocked) and recorded; on-the-wire HRR
    observation (RFC 8446 §4.1.3) extracts the group a server demands,
    including the obsolete Kyber draft 25497 still honoured by some
    edges — the finding that seeds the compat-oracle ladder.
  • -debug / -debug-out diagnostics. Every engine decision point
    (ladder step, QUIC handshake, refusal classification) emits a
    diagnostics event: a human stream on stderr under -debug, and a
    schema-1 machine report via -debug-out diag.json
    (USAGE.md,
    issue #29).
  • Single-target fast mode (-u). The binary scans a single target
    (host, host:port, ip:port) in fast mode: both planes probed
    (QUIC skippable via -quic-off), jsonl/text output via -jsonl /
    -o — live on the proven engines (PQ-30,
    PR #55).
  • Measured benchmarks. The M0 gate measured the single-target fast
    path end to end on the loopback fixture: 2,952 handshakes/s at
    W=8
    (re-run 3,026) against the ≥ 2,500 target
    (issue #10). The
    latency decomposition holds on live hosts: connect ≈ 1 RTT
    (18.94 ms), handshake 23.44 ms, total ≈ 2 RTT + server compute
    (42.4 ms, cloudflare seq×20); QUIC per-conn cost 22.5 ms avg
    handshake, goroutine delta 3, heap 665 KB. Full SLO cells in
    docs/m0-report.md.
  • SLSA provenance on every artifact. Every binary in this release
    is built in Actions and attested in the same job that produces it
    (actions/attest-build-provenance, no post-hoc wrapping):
    Sigstore-signed SLSA build provenance bound to the repository/OID
    issuer
    (ADR-0003: SLSA provenance via GitHub Artifact Attestations).

Verify before running

Every artifact carries SLSA build provenance; verify it — the digests
must match the artifacts for this repository. With the gh CLI:

gh attestation verify <artifact> -R shsingh/pqscan

A verified run exits 0; a non-TTY invocation of the CLI may print
nothing on success — for the structured proof (subject digest, signer
identity, Rekor timestamp, build invocation) use:

gh attestation verify <artifact> -R shsingh/pqscan --format json

The Sigstore bundle is also retrievable offline per artifact with
gh attestation download <artifact> -R shsingh/pqscan.

Each release also carries CHECKSUMS-sha256.txt (sha256 over every
binary). From the directory holding the artifacts:

sha256sum --check CHECKSUMS-sha256.txt

Limitations

2026.01-rc1 is an engine-gate release candidate, not the full M1/M2
surface:

  • Multi-target grammar and run pipeline land with M1: target
    grammar and the run pipeline
    (#38), output encoders
    and the WAL (#39).
    Until then the rc1 binary's scan surface is intentionally minimal —
    single targets via the fast mode (-u) on the live-proven engines
    and the diagnostics path fully functional; targets-as-grammar
    (CIDRs, ranges, lists) are rejected until PQ-15 lands.
  • Deep- and pq-mode ladders land with M2: the deep-mode plan
    executor (offer-one matrix, pruned DAG)
    (#43), PQC readiness
    scoring (#42), IANA
    regen tables (#41) and
    the surrounding analytics — the full range is tracked under issues
    #38–#45.
  • M0 deferred SLO cells — aggregate sustained under load, p95
    per-target, RSS at 50k in-flight and deep-mode rate are measured at
    their owning milestones (M3/M4) and are listed explicitly in
    docs/m0-report.md
    so no cell is silently skipped.