Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
175ae74
test(ner_org): bring ner_org.rs to 100% line and function coverage
p4gs May 11, 2026
5531daf
test(subprocessor): add 45 targeted tests for uncovered paths (GRC-31…
p4gs May 11, 2026
392db13
test(subprocessor): add 22 more targeted tests — 99.58% lines (nightl…
p4gs May 11, 2026
bb1d8a1
test(subfinder): achieve 100% coverage — eliminate short-circuit regi…
p4gs May 11, 2026
b5eca09
test(whois): partial coverage pass — GRC-317 max_turns checkpoint
p4gs May 11, 2026
d811c96
fix(whois): fix WHOIS client JSON format + add 42 tests for coverage
p4gs May 11, 2026
60fa08b
test(web_traffic): achieve 99.57% line coverage — extract filter_netw…
p4gs May 11, 2026
b4f812f
feat(GRC-314): coverage(off) annotations + domain_utils refactor — ch…
p4gs May 12, 2026
133e7f6
test(GRC-314): final 2-line gap fixes checkpoint — dns, rate_limit, d…
p4gs May 12, 2026
fc74f83
test(GRC-314): subprocessor+whois+web_traffic coverage(off) annotatio…
p4gs May 12, 2026
fcbba14
test(GRC-149): final coverage fixes from sub-issue work
p4gs May 12, 2026
4648d3a
test(GRC-149): exclude network integration tests from coverage builds
p4gs May 12, 2026
25ad219
test(GRC-149): coverage(off) for subfinder system-dependent functions
p4gs May 12, 2026
f7d6645
fix: conditional import for coverage_nightly gated tests
p4gs May 12, 2026
573137f
test(GRC-149): coverage(off) annotations for untestable functions acr…
p4gs May 12, 2026
8ed576e
ci(coverage): raise gate to 100% lines and functions (GRC-144)
p4gs May 12, 2026
0358126
style: cargo fmt
p4gs May 12, 2026
d401928
fix: resolve clippy warnings (single_match, unnecessary_map_or)
p4gs May 12, 2026
85faf1c
ci(coverage): add --lib flag to match verified 100% scope
p4gs May 12, 2026
9d17a0b
ci(coverage): use nightly toolchain for coverage(off) annotations (GR…
p4gs May 13, 2026
487df0e
ci(coverage): pin nightly to 2026-04-29 for stable coverage instrumen…
p4gs May 13, 2026
bce9703
ci: split coverage into summary + lcov to diagnose gate failure
p4gs May 14, 2026
06bdf0a
fix(security): validate interactive output path against traversal (CW…
p4gs May 14, 2026
7b0386c
security(SSCS): coverage 100->95, kill stale audit suppression, add S…
May 17, 2026
7927d7f
fix(result-sink): stop concurrent runs deleting each other's in-fligh…
May 17, 2026
6f77dc0
docs(isa): finalize LEARN — TF-3 verification, changelog C/R/L, defer…
May 17, 2026
c4906e7
chore(paperclip): stage 11-issue delegation backlog + parameterized l…
May 18, 2026
9abeca6
fix(config): fall back to embedded defaults when config file missing …
p4gs May 18, 2026
5f04113
fix: track DNS failures, exit non-zero, show WARNING banner
p4gs May 18, 2026
36bd85a
fix(dep_check): graceful-degrade ONNX/NER instead of exit 1
p4gs May 18, 2026
6335032
fix(timeout): use exit code 142 and warn at scan start
p4gs May 18, 2026
e322f03
fix(result-sink): clippy needless_return + fmt in is_process_running …
May 18, 2026
bb7b062
fix(dns): eliminate live DNS from unit tests (GRC-395)
p4gs May 18, 2026
a6565a8
ci: fix combine-digests working-directory + clean up dead code
p4gs May 18, 2026
994b2ef
docs(go-no-go): record TF-5 NO-GO findings and GRC-395 regression (GR…
p4gs May 18, 2026
0982429
fix(trust-center): gate browser-launching coverage-stub test with #[c…
p4gs May 21, 2026
fb2ead7
Merge branch 'fix/GRC-364-zero-config-fallback' into feat/GRC-149-100…
p4gs May 21, 2026
6f90053
Merge branch 'fix/GRC-365-onnx-graceful-degrade' into feat/GRC-149-10…
p4gs May 21, 2026
02dbeba
style(dep_check): apply cargo fmt to GRC-365 test code
p4gs May 21, 2026
0c961ba
fix(dns): eliminate concurrency false-negatives (GRC-367) + bump hick…
May 30, 2026
50e7ef2
fix(dns): remediate self-audit findings — close CNAME + subdomain thr…
May 30, 2026
bcf5e8a
fix(dns): systematic throttle-counting at the DoH choke-point (GRC-36…
May 30, 2026
602e4b0
docs(changelog): add [1.0.1] entry (GRC-367 DNS throttle fix + GRC-36…
May 30, 2026
a1ef0b5
ci+test: fix pre-existing CI red gates blocking the v1.0.1 merge
May 30, 2026
c0f1654
ci(security): repair 3 broken scanner jobs so they actually run (veri…
May 31, 2026
77bc76d
ci(security): allowlist 5 confirmed gitleaks false positives (documen…
May 31, 2026
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
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: 2
updates:
# GitHub Actions — keep every SHA-pinned action current (defends the
# tj-actions CVE-2025-30066 retroactive-tag-rewrite class: Dependabot
# bumps the pinned digest, the pin stays a 40-char SHA).
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
groups:
actions:
patterns: ["*"]
commit-message:
prefix: "ci(deps)"

# Cargo — the crate lives in /nthpartyfinder.
- package-ecosystem: "cargo"
directory: "/nthpartyfinder"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
commit-message:
prefix: "deps"
29 changes: 25 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ jobs:
timeout-minutes: 10

coverage:
name: Code Coverage
name: Coverage (95% gate)
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # nightly
with:
toolchain: nightly-2026-04-29
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@4c6ee9b0c14666cb5ccda351bcaf3b49e9bd74f4 # cargo-llvm-cov
Expand All @@ -111,8 +112,28 @@ jobs:
- name: Download NER model
if: steps.cache-ner.outputs.cache-hit != 'true'
run: bash scripts/download-model.sh
- name: Generate coverage
run: cargo llvm-cov --locked --all-features --workspace --fail-under-lines 70 --lcov --output-path lcov.info
- name: Run coverage and print summary
env:
RUSTFLAGS: ""
# Coverage floor = 95% line + 95% function (NOT 100%). 100% is explicitly
# not a goal: the last few % is genuinely-unreachable defensive code
# (impossible-error `?` continuations, poison-mutex fallbacks, dead match
# arms); chasing it incentivises deleting graceful error handling.
# --ignore-filename-regex scopes out structurally-untestable infra that
# no meaningful unit test can exercise:
# browser_pool.rs — live headless-Chrome session provider
# memory_monitor.rs — live OS memory-pressure sampler (sysinfo)
# interactive.rs — blocking interactive TUI input loop
# (main.rs is a [[bin]], already excluded by --lib). Keep this regex
# MINIMAL — never widen it to make a change pass; write a real test.
# Mirror of nthpartyfinder/scripts/coverage.sh (keep in sync).
run: cargo +nightly-2026-04-29 llvm-cov --locked --all-features --workspace --lib --ignore-filename-regex '(browser_pool|memory_monitor|interactive)\.rs$' --fail-under-lines 95 --fail-under-functions 95
- name: Generate LCOV report
env:
RUSTFLAGS: ""
# `report` re-emits from data collected by the gate step above; build/feature-selection
# flags (--all-features/--workspace/--lib/--locked) are invalid for the `report` subcommand.
run: cargo +nightly-2026-04-29 llvm-cov report --ignore-filename-regex '(browser_pool|memory_monitor|interactive)\.rs$' --lcov --output-path lcov.info
- name: Upload to Codecov
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ jobs:
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
languages: rust
build-mode: none
# config-file excludes rust/path-injection which produces 28+ false positives;
# inline // lgtm suppression is not supported by the Rust CodeQL pack.
build-mode: none # only supported mode for Rust (CodeQL Rust GA, Oct-2025)
# NOTE: codeql-config.yml carries NO query exclusions. The earlier
# rust/path-injection findings were REMEDIATED IN CODE (commit b9d8609:
# "remediate CodeQL rust/path-injection, rust/non-https-url,
# actions/missing-workflow-permissions"), not suppressed. The config
# file is retained for future query-suite scoping only. CodeQL Rust
# does NOT cover OWASP A06 (vulnerable deps) — SCA stays on cargo-deny.
config-file: ./.github/codeql/codeql-config.yml

- name: Perform CodeQL Analysis
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,55 @@
files: |
nthpartyfinder/target/${{ matrix.target }}/release/nthpartyfinder-${{ matrix.target }}.tgz
nthpartyfinder/target/${{ matrix.target }}/release/nthpartyfinder-${{ matrix.target }}.tgz.sha256

# Per-target digest for SLSA provenance aggregation (B5).
- name: Export artifact digest
id: digest
shell: bash
working-directory: nthpartyfinder/target/${{ matrix.target }}/release
run: |
if command -v sha256sum &>/dev/null; then HASH=$(sha256sum nthpartyfinder-${{ matrix.target }}.tgz);
else HASH=$(shasum -a 256 nthpartyfinder-${{ matrix.target }}.tgz); fi
echo "value=$(echo -n "$HASH" | base64 | tr -d '\n')" >> "$GITHUB_OUTPUT"
- name: Upload digest artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: digest-${{ matrix.target }}
path: nthpartyfinder/target/${{ matrix.target }}/release/nthpartyfinder-${{ matrix.target }}.tgz.sha256
retention-days: 1

# ── SLSA provenance (B5 — SLSA v1.2 Build L3 via slsa-github-generator) ────
# Aggregate every matrix artifact digest, then emit signed provenance.
combine-digests:
name: Combine digests
needs: build-release
runs-on: ubuntu-latest
defaults:
run:
working-directory: .
outputs:
digests: ${{ steps.combine.outputs.digests }}
steps:
- uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: digest-*
path: digests
- id: combine
run: |
cat digests/*/*.sha256 > all-digests.txt
echo "digests=$(base64 -w0 < all-digests.txt)" >> "$GITHUB_OUTPUT"

provenance:

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines +104 to +122
needs: combine-digests
permissions:
actions: read # read workflow metadata
id-token: write # keyless cosign / Fulcio OIDC
contents: write # attach provenance to the release
# NOTE: slsa-github-generator MUST be referenced by semantic tag, not SHA —
# its TUF/slsa-verifier trust model binds builder identity to the tag. This
# is the one sanctioned non-SHA pin (OpenSSF Scorecard documents this
# Pinned-Dependencies exception for slsa-github-generator).
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with:
base64-subjects: ${{ needs.combine-digests.outputs.digests }}
upload-assets: true
45 changes: 45 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: OpenSSF Scorecard

on:
branch_protection_rule:
schedule:
- cron: '24 5 * * 1' # weekly
push:
branches: ["master", "main"]

permissions: read-all

jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
security-events: write # upload SARIF to code scanning
id-token: write # publish results to the public Scorecard API
contents: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
publish_results: true # feeds the public Scorecard badge / API

- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: SARIF file
path: results.sarif
retention-days: 5

- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
sarif_file: results.sarif
category: scorecard
151 changes: 119 additions & 32 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,18 @@ defaults:
working-directory: nthpartyfinder

jobs:
dependency-audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Run cargo audit
run: |
cargo audit \
--ignore RUSTSEC-2026-0097 \
--ignore RUSTSEC-2024-0421 \
--ignore RUSTSEC-2025-0057 \
--ignore RUSTSEC-2025-0119 \
--ignore RUSTSEC-2024-0436 \
--ignore RUSTSEC-2025-0134 \
--ignore RUSTSEC-2026-0118 \
--ignore RUSTSEC-2026-0119 \
--deny warnings

# ── SCA GATE (blocking) ──────────────────────────────────────────────────
# cargo-deny is the single SCA gate (2026 posture: cargo-audit's maintainer
# stepped back Mar-2025; cargo-deny + RustSec DB is the recommended Rust
# advisory/license/source gate). Documented risk-acceptances live in
# deny.toml [advisories] as structured { id, reason } entries with full
# rationale; `unused-ignored-advisory = "warn"` auto-flags stale ignores.
# The previous standalone `cargo audit --ignore <8 IDs>` step was REMOVED:
# it duplicated deny.toml's suppression AND re-silenced 3 advisories deny.toml
# already marks RESOLVED (dead ignore entries — the exact stale-suppression
# anti-pattern the zero-suppression rule targets).
cargo-deny:
name: Cargo Deny
name: Cargo Deny (SCA gate)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
Expand All @@ -48,17 +37,115 @@ jobs:
manifest-path: nthpartyfinder/Cargo.toml
arguments: --all-features

sast-scan:
name: SAST Scan
# ── SCA BREADTH (OSV, report-only) ───────────────────────────────────────
# Second independent engine over the OSV DB (no arbitrary-code-exec path).
# Report-only by design: cargo-deny above is the gate; this widens coverage
# and surfaces SARIF without a second blocking flip mid-campaign.
osv-scanner:
name: OSV Scanner (report-only)
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install Semgrep
run: pip install semgrep
- name: Run Semgrep
run: semgrep scan --config "p/rust" --config "p/security-audit" . --json > sast-results.json || true
- name: Upload SAST results
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
- name: Run osv-scanner
continue-on-error: true
# The repo-root action.yml is a stub with NO `runs:` section ("Top level
# 'runs:' section is required"). The real Docker action lives at the
# `osv-scanner-action/` subpath; same pinned commit, which IS tag v2.3.8.
# NB: this is a Docker `uses:` action — it runs at GITHUB_WORKSPACE (repo
# root), NOT under `defaults.run.working-directory`. Paths below are
# therefore repo-root-relative, and --output writes where the upload
# step reads it (nthpartyfinder/osv.sarif).
uses: google/osv-scanner-action/osv-scanner-action@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8
with:
name: sast-results
path: nthpartyfinder/sast-results.json
scan-args: |-
--lockfile=nthpartyfinder/Cargo.lock
--format=sarif
--output=nthpartyfinder/osv.sarif
- name: Upload OSV SARIF
if: always()
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
sarif_file: nthpartyfinder/osv.sarif
category: osv-scanner

# ── SAST (Opengrep, report-only — gate flip is the scheduled follow-up) ───
# Replaces the prior `semgrep scan ... || true` (non-gating theater that
# discarded its JSON to an artifact). Opengrep is the OSS SAST engine of
# record. Pinned + signature-verified install (never unpinned curl|bash).
# IMPORTANT (advisor): a green Opengrep run is NOT proof of correctness —
# an empty/zero-rule load also exits 0. We therefore (a) assert rule files
# exist and (b) print the loaded-rule count. Report-only NOW; the
# `--error --severity ERROR` gate flip is the documented follow-up AFTER a
# clean report-only baseline on master (never flip gating before baseline,
# else branch protection blocks the campaign's own bugfix merges).
sast-opengrep:
name: SAST — Opengrep (report-only)
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
# cosign must be on PATH BEFORE the Opengrep installer runs — its
# `--verify-signatures` flag shells out to cosign and otherwise fails with
# "cosign is required for --verify-signatures but is not installed."
- name: Install cosign (for Opengrep signature verification)
uses: sigstore/cosign-installer@7e8b541eb2e61bf99390e1afd4be13a184e9ebc5 # v3.10.1
- name: Install Opengrep (pinned + signature-verified)
run: |
curl -fsSL https://raw.githubusercontent.com/opengrep/opengrep/v1.21.0/install.sh \
-o install-opengrep.sh
bash install-opengrep.sh -v v1.21.0 --verify-signatures
echo "$HOME/.opengrep/cli/latest" >> "$GITHUB_PATH"
- name: Assert local ruleset present (anti empty-ruleset trap)
run: test -s .opengrep/rules.yml && grep -c ' - id:' .opengrep/rules.yml
- name: Run Opengrep (report-only, SARIF)
run: |
opengrep scan --config .opengrep/rules.yml \
--sarif-output=opengrep.sarif --verbose . || true
- name: Upload Opengrep SARIF
if: always()
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
with:
sarif_file: nthpartyfinder/opengrep.sarif
category: opengrep

# ── SECRET SCANNING (blocking — secrets must never merge) ─────────────────
secret-scan:
name: Secret Scan (gitleaks)
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0 # full history so a leaked-then-deleted secret is caught
# gitleaks-ACTION requires a paid GITLEAKS_LICENSE for orgs and silently
# no-ops without it. We use the FREE gitleaks CLI instead: download a
# pinned release tarball, verify its SHA256 against the published
# checksum, then run `detect` with `--exit-code 1` so the job FAILS
# (blocks the merge) when any secret is found, and passes otherwise.
- name: Download + verify + run gitleaks (BLOCKING)
env:
GITLEAKS_VERSION: "8.30.1"
# sha256 of gitleaks_8.30.1_linux_x64.tar.gz, from the release's
# published gitleaks_8.30.1_checksums.txt.
GITLEAKS_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb"
run: |
set -euo pipefail
tarball="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
url="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${tarball}"
curl -fsSL "$url" -o "$tarball"
echo "${GITLEAKS_SHA256} ${tarball}" | sha256sum -c -
tar -xzf "$tarball" gitleaks
chmod +x gitleaks
# `working-directory: nthpartyfinder` (workflow defaults) makes this
# step's CWD the subdir, so scan the whole repo via `--source ..`.
# `--config ../.gitleaks.toml` is the repo-root config: it extends the
# full default ruleset and allowlists ONLY documented false positives
# (public model checksums + DNS test fixtures); see that file. Every
# real secret rule stays active + BLOCKING via `--exit-code 1`.
./gitleaks detect --source .. --config ../.gitleaks.toml --no-banner --redact --exit-code 1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,6 @@ venv/
env/
ENV/
.venv/

# scan-run cache artifacts (GRC-367 audit)
cache/
Loading
Loading