Skip to content

fix(ci): fail a personal-data scan that scanned nothing - #401

Open
geiresx wants to merge 90 commits into
GeiserX:mainfrom
geiresx:pgp/rust-z2d
Open

geiresx wants to merge 90 commits into
GeiserX:mainfrom
geiresx:pgp/rust-z2d

Conversation

@geiresx

@geiresx geiresx commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

A personal-data check could pass after scanning no text file. The Rust port also missed some Python matches and printed detected values into public logs. The latest fix restores ordinary Cyrillic text without admitting Unicode case differences.

The five shell checks now call og dev. Their Python implementations are removed. Shell options and exception lists stay in place.

Caller Rust command
check-personal-data.sh og dev scan personal-data
check-images.sh og dev scan images, og dev versions coupled
gen-containers-config.sh --check-versions og dev versions check-run
check-links.sh og dev versions expand
check-pgs-labels.sh og dev pgs trait, label-match, metric-match

Deliberate fixes:

  • A scan that reads no text file fails. Roots reached through symbolic links keep their exception lists.
  • Findings contain only kind, escaped filename and line number. Invalid patterns and matcher errors produce redacted diagnostics. This changes the removed Python scanner's log output.
  • Built-in and custom patterns share a Python-subset compiler and a backtracking search through fancy-regex. Assertions participate in match selection. Necessary-literal checks skip impossible built-in rules.
  • Python word, digit, whitespace and case behavior is preserved on admitted text. Combining marks and join controls remain non-word characters. Dotted and dotless I are supported. Genotype matches can backtrack to a shorter valid span. A nonempty match can follow an empty alternative at the same position. Captures do not narrow ALLOW checks.
  • Pattern files use universal newlines. Exception tables use Python's line separators. Scanned blobs retain replacement decoding and LF splitting.
  • Unsupported custom syntax, nullable quantified operands, exhausted matchers and invalid UTF-8 paths stop with redacted exit 2. The scanner documentation defines the supported subset and resource limits.
  • The Unicode property guard covers UCD 13, 15, 16 and 17 differences and scalars unassigned in UCD 17. Every astral cased scalar also stops the scan, including case-mapping targets. These guards apply to text, filenames, patterns and exception rows. Newer plain symbols, emoji and uncased astral text can scan. Guarded file contents need an ASCII SKIP glob. ALLOW cannot exempt them.
  • BMP regex case differences refuse patterns that name a member of a differing fold class under active global or scoped i. Literals, escaped members, positive and negative classes, and range interiors are checked. Case-sensitive Cyrillic names and ordinary Russian, Ukrainian and Serbian text work. Dot and category escapes remain supported. Such a refusal names the pattern file and line, says the cause, and says what to change: turn the i flag off for that part and list the exact spellings. It never quotes the pattern.
  • The property generator uses twelve official files with pinned SHA-256 hashes. The regeneration check requires identical bytes. A separate embedded BMP table comes from real Python regex calls. Text validation uses one binary search per non-ASCII character. Pattern compilation also checks a small fold-class set, initialized once from embedded relations and the engine's fold table. There is no per-file index or runtime subprocess.
  • Selected filenames are validated before exclusions and Git requests. Working-copy symlinks validate every hop with a 40-hop bound. Cached scans validate the indexed target blob even if the working copy changed. Target names, including directory components, get the same UTF-8 and Unicode validation before SKIP. Staged paths use NUL-delimited batch requests. Selected gitlinks and unreadable index objects stop the scan unless SKIP excludes them.
  • Both interpreter verifiers fail when any explicitly supplied interpreter path is missing or cannot run. PATH discovery remains optional. CI requires Python 3.9, 3.12 and 3.15, installed with pinned uv tooling.
  • Stale image exemptions fail. Version pins reject malformed or duplicate assignments. JSON booleans cannot count as numeric PGS effects.

Pipeline output filenames and formats do not change. FIFO behavior and the versions, images, PGS and links implementations are unchanged by this fix round.

The widened scope includes caller registrations and workflow wiring in rust/og/src/main.rs, rust/crates/og-dev/{Cargo.toml,src/*}, rust/Cargo.lock, and .github/workflows/{personal-data,guard,freshness,nextflow}.yml. The matcher adds pinned dependencies and lockfile entries. The containers parity fixture wraps its selector in process { ... }, as Nextflow requires. Parity adapters extract the removed Python from pinned Git sources. No Python source file is added.

How it was checked

All inputs are public or synthetic. Finding tests run the removed scanner and compare sorted metadata, including duplicate findings. Redaction checks inspect stdout and stderr. Span tests compare match order and offsets with real Python interpreters.

The round-seven red-test commit fails all four controls: ordinary Cyrillic, pattern flag scope, indexed target validation before SKIP, and required interpreter failures. Guard replays it with cargo test --no-fail-fast and requires every named failure.

The converse verifier checks every differing BMP pair. Property-guarded endpoints must stop in all four entry modes. Admitted endpoints are tested with patterns that name no fold-class member under i: dot, categories and their negations, unrelated classes, ranges, alternations, scoped flags and quantifiers. Case-sensitive Cyrillic patterns are compared too. Third case partners are discovered from real singleton relations on every interpreter. Differing named-class shapes must be refused. A span difference on admitted text under an accepted pattern fails verification. This is a bounded check, not a proof for unbounded patterns.

U+1C89/U+1C8A are property-guarded. The test verifies that they stop before matching. Ordinary Cyrillic sentences scan clean in explicit/tracked and working-copy/index modes. A planted built-in finding inside Russian text remains exit 1. Case-sensitive custom names work. Case-insensitive names and ranges that name guarded fold classes return redacted exit 2.

Earlier red controls remain linked and replayed by Guard:

Guard also removes the BMP table and plants an incorrect word class and a swallowed matcher error. Each mutation must fail its named tests. The fixed source is restored after every control.

Earlier model evidence: 14,534 patterns, 9,314 accepted, 5,220 refused, 259 texts and 2,412,326 accepted pattern/text pairs. CI keeps the complete two-node/two-character slice: 598 patterns, 500 accepted, 98 refused, 43 texts and 21,500 pairs. Two span-fuzz seeds compare 298,627 and 292,152 pairs on Python 3.14. Unicode verification also runs Python 3.9/3.11/3.12/3.13/3.14/3.15 locally. Ordinary span iteration follows Python 3.15, including empty-text \B. All 614 astral case sources and targets in the pinned UCD files remain guarded. The property table contains 830,004 scalars. The BMP table contains 32 differing pairs and now guards patterns separately.

Time and memory on the same Mac, /usr/bin/time -l, using a synthetic 20,000-line file with one finding per line:

Scanner Wall time Peak RSS
Removed Python 0.11 s 16,990,208 bytes
Rust 1.93 release build 0.08 s 16,351,232 bytes

Both report 20,000 findings. The Rust output contains no planted value. These earlier measurements support no general speed claim.

Round-seven head: 65ba929fb967b785fc892628b799b60fbbd62a39. Local Rust 1.93 passes 136 unit tests and 11 repository tests, with one large model ignored by default. Clippy and rustdoc pass with warnings denied. Rustfmt passes. The corrected child-output assertion passes for both verifiers with missing and failing explicit interpreter paths.

Six interpreters verify 1,243 candidate BMP pairs and the 32 checked-in differing pairs. The admitted-text converse compares 266,544 span rows. It covers 25 admitted endpoints and 26 property-stopped endpoints. All 150 differing named-class shapes are refused, including 108 third-partner shapes. The round-seven pre-fix replay reconfirms all four expected failures on this code, then restores the fixed sources.

The local oracle passes all 30 items in 10 cases. Its 15 self-tests and the comparator's 44 controls pass. Linux shadow controls remain CI checks. Personal-data, image and PGS shell self-tests and the links test pass. The single containers-software-versions case passes all four assertions for 128 synthetic processes. No real pipeline run is claimed. The public scan is clean for 2,439 text files: 6.21 s and 18,661,376 bytes peak RSS on this run.

All upstream fast checks are green on that head: Guard with ci-ok, Rust, Lint, both Nextflow legs, Docs, Container Test and Personal data.

Guard's Rust job passes 862 workspace tests, all seven pinned scanner-control rounds, the missing-table control and both matcher mutations. It installs and requires Python 3.9, 3.12 and 3.15. Local replays also pass rounds one through seven and the missing-table control. The local incorrect-word-class mutation fails its named tests.

A final local control deliberately bypasses the property guard for U+1C89/U+1C8A. The revised converse then fails with an accepted-pattern span mismatch. Restoring the guard leaves the production source unchanged. Both verifiers also reject a deliberately unavailable required Python version.

READY 65ba929fb967b785fc892628b799b60fbbd62a39. Fork E2E scheduling and landing remain with the orchestrator. The PR stays open.

CodeRabbit has no completed review or review threads. The earlier request was rate limited. The round-seven request followed the push after the shared queue cleared. It also answered rate limited. No repeat request was sent.

Beads

pgp-bs9u.37

The Zenodo archive never changes, so the deflated bytes of each member sit
at a fixed offset. Pin them, fetch one range per member, and let gzip check
the CRC-32 and size the archive stores; the sha256 pin stays.

Bead: pgp-bs9u.39
og dev fixture comphet writes the compound-het fixture byte for byte
(CPython's Mersenne Twister for the seeded contig); og dev fixture
trim-pharmcat trims a PharmCAT report; og dev evidence clashes and
hg002-gvcf replace the public-evidence workflow's inline Python, streaming,
with the covered positions kept as merged spans. Parity cases against the
Python, and a golden for the site past a contig's end.

Bead: pgp-bs9u.39
The personal-data scan, the image scan, the coupled-version check, the
run-versions check, the URL expander of check-links.sh and the PGS Catalog
answer readers, ported from the Python inside five scripts/ci scripts.

Bead: pgp-bs9u.37
The 210-line checker the workflow wrote into a file is now an og dev verb;
its pins table is data in scripts/ci/renovate-pins.tsv, where a missing file
or a glob that matches nothing is an error. On the last saved log of main
it prints the same lines as the Python, clean and with planted pins.

Bead: pgp-bs9u.39
… their Python

public-evidence.yml runs og dev evidence clashes and hg002-gvcf; the
comphet e2e case builds its fixture with og dev fixture comphet. The
comphet generator and the PharmCAT trimmer are deleted.

Bead: pgp-bs9u.39
Every field the trimmer keeps or drops, a non-object diplotype, a null
allele, the recommendationDiplotypes fallback, non-ASCII text, and counts
of 2, 0 and -1.

Bead: pgp-bs9u.39
…next)

Comphet seeded with 32, the trimmer drops activityScore, clashes needs
three records, and renovate-check no longer flags an @ in a package name.
Guard rust and parity must go red on this commit.

Bead: pgp-bs9u.39
check-personal-data.sh, check-images.sh, gen-containers-config.sh
--check-versions, check-links.sh and check-pgs-labels.sh call the og dev
verbs instead of their Python heredocs, and each workflow job that runs
them has og. New self-test controls: a scan of no text file, a stale image
exemption, a versions.env line that is not NAME="value", and a JSON true
read as an effect of 1.

Bead: pgp-bs9u.37
Each self-test control and cargo test of the fixes must go red on this
commit; the next commit reverts it.

Bead: pgp-bs9u.37
@geiresx
geiresx requested a review from GeiserX as a code owner November 13, 2026 10:33
@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 110 files, which is 10 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

Check out review usage here.

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 5aa373f and e93d564.

Files ignored due to path filters: 35

  • rust/Cargo.lock is excluded by !**/*.lock
  • scripts/ci/e2e-case-paths.tsv is excluded by !**/*.tsv
  • scripts/ci/e2e-case-times.tsv is excluded by !**/*.tsv
  • scripts/ci/nf-trace-requests.tsv is excluded by !**/*.tsv
  • scripts/ci/renovate-pins.tsv is excluded by !**/*.tsv
  • tests/parity/cases.tsv is excluded by !**/*.tsv
  • tests/parity/gen/ci-pharmcat.sh is excluded by !**/gen/**
  • tests/parity/gen/ci-smoke.sh is excluded by !**/gen/**
  • tests/parity/gen/dev-scanners-clean-dev-scan-images.sh is excluded by !**/gen/**
  • tests/parity/gen/dev-scanners-matching-dev-pgs-metric.sh is excluded by !**/gen/**
  • tests/parity/gen/dev-scanners-matching-dev-pgs-trait.sh is excluded by !**/gen/**
  • tests/parity/gen/dev-scanners-urls-dev-versions-expand.sh is excluded by !**/gen/**
  • tests/parity/gen/dev-scanners.sh is excluded by !**/gen/**
  • tests/parity/gen/personal-unicode-generate.sh is excluded by !**/gen/**
  • tests/parity/gen/personal-unicode-generator.rs is excluded by !**/gen/**
  • tests/parity/gen/personal-unicode-sources.tsv is excluded by !**/*.tsv, !**/gen/**
  • tests/parity/gen/traits.sh is excluded by !**/gen/**
  • tests/parity/inputs/ci-readers/attempts.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/ci-readers/cells.csv is excluded by !**/*.csv
  • tests/parity/inputs/ci-readers/o.msp.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/ci-readers/requests-frac.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/ci-readers/requests.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/ci-readers/smn.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/ci-readers/want.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/dev-evidence-clashes/chrA.tsv.gz is excluded by !**/*.gz
  • tests/parity/inputs/dev-evidence-clashes/chrB.tsv.gz is excluded by !**/*.gz
  • tests/parity/inputs/dev-evidence-clashes/chrZ.tsv.gz is excluded by !**/*.gz
  • tests/parity/inputs/dev-evidence-clashes/notes.tsv.gz is excluded by !**/*.gz
  • tests/parity/inputs/dev-evidence-clashes/raw.vcf.gz is excluded by !**/*.gz
  • tests/parity/inputs/dev-evidence-clashes/split.vcf.gz is excluded by !**/*.gz
  • tests/parity/inputs/dev-evidence-hg002-gvcf/sites-past-end.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/dev-evidence-hg002-gvcf/sites.tsv is excluded by !**/*.tsv
  • tests/parity/inputs/dev-evidence-hg002-gvcf/truth.vcf.gz is excluded by !**/*.gz
  • tests/parity/remnants.tsv is excluded by !**/*.tsv
  • tests/smoke/commands.tsv is excluded by !**/*.tsv
Files selected for processing: 110

  • .github/workflows/e2e.yml
  • .github/workflows/freshness.yml
  • .github/workflows/guard.yml
  • .github/workflows/nextflow.yml
  • .github/workflows/personal-data.yml
  • .github/workflows/public-evidence.yml
  • .github/workflows/renovate-dry-run.yml
  • CHANGELOG.md
  • bin/copy_number.py
  • bin/traits_report.py
  • docs/42-traits.md
  • docs/cn-loci.md
  • docs/rust.md
  • modules/local/traits/main.nf
  • rust/README.md
  • rust/crates/og-dev/Cargo.toml
  • rust/crates/og-dev/src/evidence.rs
  • rust/crates/og-dev/src/fixture.rs
  • rust/crates/og-dev/src/images.rs
  • rust/crates/og-dev/src/lib.rs
  • rust/crates/og-dev/src/lookaround.rs
  • rust/crates/og-dev/src/nf_trace.rs
  • rust/crates/og-dev/src/personal_data.rs
  • rust/crates/og-dev/src/pgs.rs
  • rust/crates/og-dev/src/pharmcat.rs
  • rust/crates/og-dev/src/renovate.rs
  • rust/crates/og-dev/src/smoke.rs
  • rust/crates/og-dev/src/versions.rs
  • rust/crates/og-dev/src/versions_env.rs
  • rust/crates/og-dev/tests/ci_readers.rs
  • rust/crates/og-io/src/lib.rs
  • rust/crates/og-steps/src/lib.rs
  • rust/crates/og-steps/src/traits.rs
  • rust/og/src/main.rs
  • scripts/42-traits.sh
  • scripts/ci/check-images.sh
  • scripts/ci/check-links.sh
  • scripts/ci/check-personal-data.sh
  • scripts/ci/check-pgs-labels.sh
  • scripts/ci/e2e-scope.sh
  • scripts/ci/gen-containers-config.sh
  • scripts/ci/image-smoke.sh
  • scripts/ci/parity-diff.sh
  • scripts/ci/settle-doubts.sh
  • tests/demo/make_demo_sample.py
  • tests/e2e/31-pharmcat-07.sh
  • tests/e2e/60-nextflow.sh
  • tests/e2e/comphet-phasing-1-reads.sh
  • tests/e2e/genotype-rules-2-g2.sh
  • tests/e2e/lib.sh
  • tests/e2e/nextflow-from-fastq-2-nextflow.sh
  • tests/e2e/pgx-6-gvcf-column.sh
  • tests/e2e/report-followups-1-sections.sh
  • tests/e2e/rust-c2b-traits.sh
  • tests/e2e/rust-z2e-readers.sh
  • tests/e2e/vendor-vcf-intake-5-docs.sh
  • tests/e2e/vntyper-1.sh
  • tests/fixtures/comphet/README.md
  • tests/fixtures/comphet/make_fixture.py
  • tests/fixtures/pharmcat/README.md
  • tests/fixtures/pharmcat/trim_report.py
  • tests/parity/README.md
  • tests/parity/evidence/rust-c2b-controls.txt
  • tests/parity/golden/dev-evidence-hg002-gvcf/past-the-end/out.vcf
  • tests/parity/golden/dev-evidence-hg002-gvcf/past-the-end/stdout
  • tests/parity/golden/dev-pharmcat-called/truncated/exit
  • tests/parity/golden/dev-pharmcat-called/truncated/stderr
  • tests/parity/golden/dev-scan-personal/odd-filename/stdout
  • tests/parity/golden/dev-scan-personal/unicode-fixed-seed/stdout
  • tests/parity/golden/dev-smoke-check/eigen/stdout
  • tests/parity/golden/dev-smoke-check/hap-ibd/stdout
  • tests/parity/golden/dev-smoke-check/ibdmix/stdout
  • tests/parity/golden/dev-smoke-check/parascopy/stdout
  • tests/parity/golden/dev-smoke-check/rfmix/stdout
  • tests/parity/golden/dev-smoke-mini/fixture/mini.fa
  • tests/parity/inputs/ci-readers/empty.json
  • tests/parity/inputs/ci-readers/flat.json
  • tests/parity/inputs/ci-readers/nested.json
  • tests/parity/inputs/ci-readers/o.ibd
  • tests/parity/inputs/ci-readers/o.txt
  • tests/parity/inputs/ci-readers/oracle.sh
  • tests/parity/inputs/ci-readers/t.evec
  • tests/parity/inputs/ci-readers/truncated.json
  • tests/parity/inputs/dev-evidence-hg002-gvcf/ref.fasta
  • tests/parity/inputs/dev-evidence-hg002-gvcf/ref.fasta.fai
  • tests/parity/inputs/dev-evidence-hg002-gvcf/truth-past-end.bed
  • tests/parity/inputs/dev-evidence-hg002-gvcf/truth.bed
  • tests/parity/inputs/dev-fixture-trim-pharmcat/edge.json
  • tests/parity/inputs/dev-scanners/clean.md
  • tests/parity/inputs/dev-scanners/containers.config
  • tests/parity/inputs/dev-scanners/image.md
  • tests/parity/inputs/dev-scanners/metric.json
  • tests/parity/inputs/dev-scanners/oracle.sh
  • tests/parity/inputs/dev-scanners/software_versions.yml
  • tests/parity/inputs/dev-scanners/trait.json
  • tests/parity/inputs/dev-scanners/urls
  • tests/parity/inputs/dev-scanners/versions.env
  • tests/parity/oracle.ref
  • tests/smoke/vntyper.sh
  • tests/smoke/vntyper_testdata.py
  • tests/smoke/vntyper_testdata.sh
  • tests/test_ci_readers.sh
  • tests/test_collect_summary.py
  • tests/test_copy_number.py
  • tests/test_genotype_rules_indels.py
  • tests/test_hba_copy_number.py
  • tests/test_lpa_kiv2.py
  • tests/test_render_report.py
  • tests/test_traits_report.py
  • tests/test_traits_table.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Reverts 8153ee5, which planted the five pre-fix readings to show each
control red.

Bead: pgp-bs9u.37
…lanted fault

The first red control stopped at clippy, so cargo test never ran and the
PGS self-test step never started. This one plants the same five readings
in a form clippy accepts; the next commit takes them back out.

Bead: pgp-bs9u.37
The dev-evidence-hg002-gvcf parity cases read ref.fasta and its .fai,
which the *.fasta ignore rule kept out of the tree, so CI parity stopped
with 'input not in tests/parity/inputs'.

Bead: pgp-bs9u.39
The first red control stopped at clippy, so cargo test never ran. This one
plants the same five pre-fix readings in a form clippy accepts, on top of
the main merge; the next commit takes them back out.

Bead: pgp-bs9u.37
The *.vcf ignore rule kept the golden out.vcf of
dev-evidence-hg002-gvcf/past-the-end out of the tree, so CI compared og
with the oracle and reported the deliberate fix as a difference.

Bead: pgp-bs9u.39
Select comphet-phasing-1-reads when its Rust generator changes. Keep the push paths and scope list aligned. Check HG002 truth records and the last valid reference block directly against the committed golden.

Bead: pgp-bs9u.39
Guard must reject 1/1 reference blocks in evidence::tests::hg002_gvcf_keeps_truth_and_adds_only_valid_reference_blocks. Revert this planted fault after recording its red CI job.

Bead: pgp-bs9u.39
…-c2b

# Conflicts:
#	CHANGELOG.md
#	bin/copy_number.py
#	docs/rust.md
#	scripts/ci/e2e-case-paths.tsv
#	tests/parity/oracle.ref
…-z2e

# Conflicts:
#	.github/workflows/guard.yml
#	CHANGELOG.md
#	docs/rust.md
#	rust/README.md
#	rust/crates/og-dev/src/lib.rs
#	scripts/ci/e2e-case-paths.tsv
#	scripts/ci/e2e-case-times.tsv
#	tests/parity/README.md
#	tests/parity/cases.tsv
#	tests/parity/oracle.ref
@geiresx

geiresx commented Nov 13, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…-z2f

# Conflicts:
#	CHANGELOG.md
#	docs/rust.md
#	rust/crates/og-dev/src/lib.rs
#	rust/og/src/main.rs
#	tests/parity/cases.tsv
#	tests/parity/oracle.ref
…-z2d

# Conflicts:
#	.github/workflows/guard.yml
#	CHANGELOG.md
#	rust/crates/og-dev/src/lib.rs
#	rust/og/src/main.rs
#	tests/parity/cases.tsv
#	tests/parity/oracle.ref

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants