Skip to content

Fixes #34390: Recognize identifier variants and validate NRIC/FIN check letters - #34672

Queued
stout-yeoman wants to merge 13 commits into
mainfrom
stout-yeoman/34390-identifier-formats
Queued

stout-yeoman wants to merge 13 commits into
mainfrom
stout-yeoman/34390-identifier-formats

Conversation

@stout-yeoman

@stout-yeoman stout-yeoman commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Describe your changes:

Fixes #34390

Recognize lowercase IBAN, NIF, NIE and UEN values, hyphenated ABN/ACN values, and attached Italian VAT prefixes. Reject incorrect NRIC/FIN check letters for S/T/F/G/M families and unsupported prefixes matched by Presidio's weak pattern.

Valid NRIC/FIN checksums retain the 0.5 pattern score. Lowercase variants and hyphenated ABN/ACN forms retain pattern scores and need matching context to reach the default tagging threshold. Canonical forms retain upstream checksum scoring. Attached VAT, such as IT12345678903, validates at full confidence. Checksums validate representation, not actual issuance.

Type of change:

  • Bug fix

High-level design:

Decorated factories and small subclasses in presidio_utils.py apply format normalization/checksum checks; patterns.py supplies bounded identifier patterns. Presidio retains responsibility for IBAN spans/trailing prose. Existing configured entity names, languages and contexts remain supported, with no schema or migration changes.

Attribution uses the configured recognizer name and stored recognizer ID, following the upstream factory contract. The database test now asserts SgFinRecognizer rather than the implementation subclass name. Negative configured-path tests pair each rejected value with a valid control and inspect actual TagAnalyzer evidence/original spans, so an obsolete or disconnected recognizer cannot make them pass vacuously. Attached VAT is exercised through TagProcessor with both neutral and identifying columns and through the real Italian database fixture.

Tests:

Use cases covered

Valid/invalid checksums, all NRIC/FIN families, canonical and new formats, original spans and punctuation, Unicode lookalikes, larger-token boundaries, configured language/context, context-dependent scores, neutral-column controls, attached VAT at score 1.0, and persisted recognizer identity/pattern evidence.

Unit tests

At 0cf68d9f5130db719ee1e859cd1b239f6bfa8802:

cd ingestion
../env/bin/python -m pytest tests/unit/pii tests/unit/metadata/pii --cov=metadata.pii.algorithms.presidio_utils --cov=metadata.pii.algorithms.patterns --cov-branch --cov-report=term-missing -q

516 passed; 98% utility and 100% pattern coverage including branches. Updated tests/unit/pii/algorithms/test_presidio_utils.py and tests/unit/metadata/pii/test_tag_processor_integration.py; the factory suite also ran. Focused hardening checks: 11 passed (nine paired identifier cases, two attached VAT contexts). A deliberate valid-NRIC negative-oracle probe demonstrates the corrected assertion fails when invalid attribution is introduced. Applicable Ruff/format, pre-commit and whitespace checks passed; source type checks report 0 errors/0 warnings (the final delta is test-only). Independent final review found no actionable issues.

Earlier runs: 442 PII tests on the original implementation, 161 focused utility/factory tests on the attribution correction, and 514 full related tests at a96a9afbcf; the 516-test run above supersedes their counts/coverage.

Backend integration tests

Not applicable: no Java, REST endpoint, schema, migration, seed or pom changes. python3 .github/scripts/plan_local_java_tests.py --check-branch passed; no affected Java tests.

Ingestion integration tests

Updated ingestion/tests/integration/auto_classification/databases/{init.sql,test_tag_processor.py}. Ran the complete affected database file against real PostgreSQL/OpenMetadata at 0cf68d9f5130: 4 passed, covering default classification plus English, Spanish and Italian identifier workflows. Used normal repository fixtures/credentials with only the local endpoint adapted to port 18585. Verified persisted configured recognizer ID/name/score/pattern evidence, typo exclusion and neutral-column controls. The Italian fixture uses attached IT12345678903.

The baseline reproduced the stale subclass-name assertion: 1 failed, 3 deselected; both the attribution correction and final attached-VAT fixture reruns passed. No packaging/model code changes or clean-wheel certification is claimed; the separate model-provisioning check is wheel-gated.

Playwright (UI) tests

Shared validation uses local combined commit d84bd7b9204de848334bce46f7e033ccefb6f804: the production union of exact published card head 512b065669 and identifier head 0cf68d9f51, plus32 local preservation/control tests. UI sources and lockfiles are unchanged by either PR. A matching freshly built backend, production UI bundle, real managed Airflow runner and isolated MySQL/Metabase/Kafka/schema-registry fixtures resolve the earlier missing-team-type/runner prerequisites.

The current combined impact planner selected 37 specs /616 tests. Full original execution against the Vite development UI completed 603 passed,13 failed,0 skipped. Original failures and traces are retained. Ten failures were traced to shared global settings interference/precondition conflicts (domain search, generic entity domain/glossary helpers and the logical test suite); three bulk-edit variants stalled before export in development mode.

Unchanged failed cases were rerun sequentially against the production UI with their normal settings preconditions. All13 original failing test IDs/projects now pass: Entity9/9 (including one extra control), Logical1/1, Domain3/3, Bulk3/3, plus setup2/2. Production bulk success supports the development lifecycle explanation. This is a full original run plus controlled reruns, not a claim that one uninterrupted616-case run was green. No assertion or product source was weakened. All six AutoPilot connectors and the real Incident workflow passed in the original run. A separate local tooling repair isolates global-setting writers and restores settings; it is outside both PII PRs.

Additional shared regression validation

  • 957 combined unit tests pass:925 from the production union plus32 local preservation/control cases. This is local combined coverage, separate from this PR's individual unit count above. PII coverage96%; scoped typecheck/format/lint checks pass.
  • 5 real database integration tests and 62 normal CLI persisted-column checks pass across the two exact individual heads and combined validation. Stored configured recognizer names/IDs/scores/patterns are checked.
  • 48,536 paired executions (12,134 each for baseline/card/identifier/combined) found no serious new combination regression. Reviewed removals are intended malformed/ambiguous candidate rejections or the requested Date-to-Card recovery. Rare pre-existing URL limitations remain deferred.
  • Live reclassification preserves original manual/generated/unrelated labels, adds Sensitive beside unrelated labels and avoids duplicates. Existing mutually exclusive PII labels retain the existing preservation behavior; this change does not automatically delete old applied tags or upgrade a pre-existing NonSensitive label.
  • Card/identifier and multilingual labels were checked in the actual UI, including reload/navigation persistence;18 live URL/IP/independent-email controls pass.
  • Scoped downstream Collate CLI/UI and processor contracts found no serious new regression; retained expectation differences were checked against the recorded baseline. Full current Collate integration remains incomplete because its generated schema overlay lacks TestCaseEvaluationScope; no full current-schema downstream certification is claimed.

Manual testing performed

  1. Started the designated local OpenMetadata/PostgreSQL/search stack, provisioned English/Spanish/Italian models through normal metadata install-classification-models, and confirmed imports/CLI use the isolated changed checkout.
  2. Ingested a disposable PostgreSQL source through normal metadata ingest -c ...; ran metadata classify -c ... with the shipped TagProcessor for English, Spanish and Italian tables.
  3. Queried persisted column labels/evidence: 15 checks passed, including lowercase/context-dependent forms, hyphenated ABN/ACN, NRIC/FIN positive/negative controls, attached VAT and neutral columns. This ran at a96a9afbcf; production code is identical at final 0cf68d9f5130 (only tests/fixture changed).
  4. Removed source and catalog service and verified deletion. Scoped Collate runtime/UI compatibility was subsequently checked as described above; full current-schema integration remains incomplete.

UI screen recording:

Not applicable: backend ingestion bug fixes, with no UI feature or UI source changes. The normal ingestion/classification CLI was exercised as described above.

Checklist:

  • Read the contributing guide.
  • PR title follows Fixes <issue-number>: <short explanation> and the issue is linked above.
  • Comments explain non-obvious validation and scoring behavior.
  • Added unit and ingestion integration tests for the exact regressions; results and limitations are listed above.
  • JSON schema/migrations: not applicable; no schema changes.
  • UI recording: not applicable for these backend ingestion bug fixes.
  • Decision check: no new cross-component contract/default; existing configured attribution and scoring contracts retained, with format/checksum regressions covered in tests.

Merge coordination

Coordinate with #34387 (issue #34347): retain its ACN zero-check-digit correction together with this PR's hyphenated form/context-dependent scoring. That validator correction remains separate.

This PR shares recognizer registration and database fixtures with #34674. Merge sequentially, reconcile/rebase shared files and rerun the combined fixture and configured TagProcessor checks.

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment thread ingestion/src/metadata/pii/algorithms/identifier_recognizers.py Outdated
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Comment thread ingestion/src/metadata/pii/default_identifier_policy.py Outdated
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@stout-yeoman
stout-yeoman marked this pull request as ready for review October 8, 2026 22:41
@stout-yeoman
stout-yeoman requested a review from a team as a code owner October 8, 2026 22:41
@stout-yeoman stout-yeoman added the safe to test Add this label to run secure Github workflows on PRs label Oct 8, 2026
@stout-yeoman
stout-yeoman added this pull request to the merge queue Oct 13, 2026
Any commits made after this event will not be merged.
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚦 Removed from the merge queue — failed_checks (2026-10-13T22:15:40Z)

Blocked the queue: py-tests-status

  • py-tests-postgres — py-tests-status, python / Verify Expected Jobs, python / Integration Tests (shard-2), python / Integration Tests (shard-2), python / Integration Tests (shard-2)
  • py-tests — python / Integration Tests (shard-2), python / Integration Tests (shard-2), python / Integration Tests (shard-2)

@stout-yeoman
stout-yeoman added this pull request to the merge queue Oct 14, 2026
Any commits made after this event will not be merged.
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚦 Removed from the merge queue — failed_checks (2026-10-14T19:33:01Z)

Blocked the queue: py-tests-status, py-tests-status

  • py-tests — py-tests-status, python / Verify Expected Jobs, python / Integration Tests (shard-2), python / Integration Tests (shard-2), python / Integration Tests (shard-2)
  • py-tests-postgres — py-tests-status, python / Verify Expected Jobs, python / Integration Tests (shard-2), python / Integration Tests (shard-2), python / Integration Tests (shard-2)

@TeddyCr
TeddyCr added this pull request to the merge queue Oct 14, 2026
Any commits made after this event will not be merged.
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚦 Removed from the merge queue — failed_checks (2026-10-15T06:32:30Z)

Blocked the queue: py-tests-status, py-tests-status

  • py-tests-postgres — py-tests-status, python / Verify Expected Jobs, python / Integration Tests (shard-2), python / Integration Tests (shard-2), python / Integration Tests (shard-2)
  • Prune dead merge-queue refs — cancel-stale-runs
  • py-tests — py-tests-status, python / Verify Expected Jobs, python / Integration Tests (shard-2), python / Integration Tests (shard-2), python / Integration Tests (shard-2)

@akashverma0786
akashverma0786 added this pull request to the merge queue Oct 15, 2026
Any commits made after this event will not be merged.
@akashverma0786
akashverma0786 removed this pull request from the merge queue due to a manual request Oct 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚦 Removed from the merge queue — manual (2026-10-15T07:34:32Z)

The entry left the queue before it was built, so no checks ran against it.

@gitar-bot

gitar-bot Bot commented Oct 15, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 closed / 2 findings

🔴 High risk · Changing NRIC/FIN and other PII recognition and persisted tags could leave identity-bearing columns unflagged or incorrectly classify ordinary fields.

Adds identifier variant recognition for lowercase IBAN, NIF, NIE and UEN, hyphenated ABN/ACN, and attached Italian VAT prefixes, with NRIC/FIN check letter validation across all families. Legacy ACN/ABN/VAT/UEN stay Sensitive when NonSensitive is not a candidate, and compact IBAN followed by a number in prose is no longer detected. No open issues found.

✅ 2 closed
✅ Bug: Legacy ACN/ABN/VAT/UEN stay Sensitive when NonSensitive is not a candidate

📄 ingestion/src/metadata/pii/default_identifier_policy.py:64-78 📄 ingestion/src/metadata/pii/tag_processor.py:75-77
prepare_default_pii_tags returns the tags unchanged when PII.NonSensitive is missing from the list (line 68). ClassificationManager.get_enabled_tags already drops tags that have autoClassificationEnabled=False or no recognizers, so non_sensitive comes back None in exactly the case the autoClassificationEnabled is not False branch on line 85 is written to handle. On an existing install where a user has disabled NonSensitive or removed all of its recognizers, the stored unchanged AuAcn/AuAbn/ItVat/SgUen defaults stay on PII.Sensitive and keep producing Sensitive tags. That contradicts the PR's goal of retiring ACN and moving these identifiers off Sensitive. The fix is to remove the retired defaults from Sensitive whenever Sensitive is present, and only migrate them when a NonSensitive candidate is also present.

✅ Edge Case: Compact IBAN followed by a number in prose is no longer detected

📄 ingestion/src/metadata/pii/algorithms/identifier_recognizers.py:103-106
In BoundedIbanRecognizer.analyze, re.match(r" *[0-9_-]", text[end:]) drops any end position that is followed by optional spaces and then a digit, _ or -. The check is meant to stop a valid prefix being pulled out of a longer grouped IBAN (e.g. GB82 WEST ... 32 99), but it also applies to compact IBANs that are followed by unrelated numbers. So free-text cells like Paid DE89370400440532013000 100 EUR or DE89370400440532013000 2024-01-01 now return no IBAN result at all, which is a false negative compared with the previous recognizer. None of the tests cover a compact IBAN followed by a separate number.

Fix: only apply the continuation guard when the matched value is itself grouped (contains a space or -). A compact IBAN that ends at a word boundary is already complete, so it can't be a salvaged prefix.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@sonarqubecloud

Copy link
Copy Markdown

@stout-yeoman
stout-yeoman added this pull request to the merge queue Oct 15, 2026
Any commits made after this event will not be merged.

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

safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Identifier recognizers miss valid formats and accept unchecked NRIC/FIN values

3 participants