Skip to content

feat(AF-623): automated sensitive-data discovery & classification scans - #657

Merged
babltiga merged 1 commit into
mainfrom
feature/AF-623-sensitive-data-discovery
Jul 27, 2026
Merged

feat(AF-623): automated sensitive-data discovery & classification scans#657
babltiga merged 1 commit into
mainfrom
feature/AF-623-sensitive-data-discovery

Conversation

@babltiga

@babltiga babltiga commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Closes #623

What

A new discovery Spring Modulith module that closes the AF-447 loop: instead of admins hand-tagging hundreds of columns, an opt-in scanner finds the sensitive columns and proposes the classification tags.

  • Scan pipelineDiscoveryScanService enumerates tables via introspectSchemaForSystem, reads a bounded raw sample per table through the existing AF-443 QueryExecutor.sampleTable path (works for JDBC + all 10 engine plugins), and runs local regex + checksum detectors: email→PII, credit-card PAN with Luhn→PCI, US SSN→PII, IBAN with mod-97→FINANCIAL, phone→PII. First-match-wins ordering, ≥5 samples and ≥30% match ratio required. Raw values live only on the scan stack — findings persist a redacted sample only.
  • Optional AI pass (per-datasource opt-in, fail-safe like the UBA anomaly summary) — new ai.api.DataDiscoveryAiService classifies remaining columns via the org's bound ai_config; the provider only ever sees column names, types, and format-preserving-redacted samples.
  • Worklist — findings land as PENDING rows (discovery_finding, unique per column×classification×detector); rescans refresh PENDING rows and never resurrect CONFIRMED/DISMISSED ones. Confirming applies the tag through DataClassificationAdminService (auto-deriving masking); dismissing suppresses permanently. Bulk decisions are per-row independent (attestation pattern) with TAG_CONFLICT handling.
  • SchedulingDiscoveryScanJob (@SchedulerLock discoveryScanJob, poll default PT15M) drains enabled discovery_scan_config rows past their per-datasource scan_interval_hours; plus an on-demand POST /datasources/{id}/discovery/scan (202/409) so the feature is demoable and e2e-testable.
  • Frontend — a "Discovery" tab on DatasourceSettingsPage: settings card (enable, sample size 10–1000, interval 1–720 h, AI toggle, Scan now, last-scan status) + paginated findings worklist with sticky bulk Confirm/Dismiss bar and partial-success row feedback; tab badge shows the PENDING count. i18n across all 7 locales.
  • AuditDISCOVERY_SCAN_COMPLETED, DISCOVERY_FINDING_CONFIRMED, DISCOVERY_FINDING_DISMISSED (+ resource discovery_finding). No new NotificationEventType (issue asks for audit only).
  • Endpoints (all PERM_DATA_CLASSIFICATION_MANAGE, documented in the API spec first): GET/PUT /datasources/{id}/discovery/config, GET /datasources/{id}/discovery/findings, POST …/findings/bulk-decision, POST …/scan.

Docs & website updated

  • docs/03-data-model.md (new tables + enums + audit actions), docs/04-api-spec.md (5 endpoints), docs/05-backend.md (module section + job table row), docs/06-frontend.md (Discovery tab), docs/09-deployment.md + CLAUDE.md (ACCESSFLOW_DISCOVERY_* env vars + module tree), docs/12-roadmap.md (v2.2 item)
  • README.md feature list; website/index.html (feature blurb + roadmap item), website/docs/index.html (Automated discovery section + env vars), website/README.md content-source map

Testing

  • Backend: full mvn verify -Pcoverage green — 5 detector unit suites, DiscoveryScanServiceTest (caps/deadline/upsert/suppression/AI fail-safe), config/finding/trigger/job/audit-writer/web-model tests, DefaultDataDiscoveryAiServiceTest (strict-JSON lenient parse), and DiscoveryControllerIntegrationTest (Testcontainers; bulk confirm creates the real tag and the derived masking policy). ApplicationModulesTest + ApiPackageDependencyTest pass.
  • Frontend: lint 0 errors, typecheck, test:coverage (91.8% stmts / 83.6% branches), build — all green. New DiscoveryTab.test.tsx (7 tests incl. partial-success bulk path).
  • E2E: new e2e/tests/discovery.spec.ts runs the whole loop against the real stack (seed a table with emails via the query workflow → enable + Scan now → finding appears → bulk confirm → tag on Classification tab + policy on Masking tab). Ran locally along with the six adjacent datasource-settings specs — 19/19 passed.

Known limitations (v1)

A new discovery module samples column data through the existing engine
sampling path (AF-443), detects sensitive values with local regex +
checksum detectors (email, PAN+Luhn, SSN, IBAN, phone) and an optional
fail-safe AI pass (redacted samples only), and proposes classification
tags an admin confirms (AF-447 derivation applies masking) or dismisses
(permanent suppression). Includes the scheduled DiscoveryScanJob, an
on-demand scan endpoint, a Discovery tab with bulk confirm/dismiss on
DatasourceSettingsPage, audit rows, docs, website, and e2e coverage.

Closes #623
@github-actions

Copy link
Copy Markdown
Contributor

Frontend Test Results

1 303 tests   1 303 ✅  3m 53s ⏱️
  170 suites      0 💤
    1 files        0 ❌

Results for commit 9f585bf.

@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for Frontend Coverage (frontend)

Status Category Percentage Covered / Total
🟢 Lines 93.83% (🎯 90%) 2085 / 2222
🟢 Statements 91.81% (🎯 90%) 2323 / 2530
🟢 Functions 90.98% (🎯 90%) 636 / 699
🟢 Branches 83.59% (🎯 80%) 1310 / 1567
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
frontend/src/utils/enumLabels.ts 96.66% 100% 90.9% 96.64% 194, 202, 323, 448, 506
Generated in workflow #828 for commit 9f585bf by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

Backend Test Results

5 567 tests  +139   5 567 ✅ +139   17m 46s ⏱️ +21s
  692 suites + 16       0 💤 ±  0 
  692 files   + 16       0 ❌ ±  0 

Results for commit 9f585bf. ± Comparison against base commit db28877.

@github-actions

Copy link
Copy Markdown
Contributor

Backend Code Coverage

Overall Project 93.14% -0.11% 🍏
Files changed 95.15% 🍏

File Coverage
DiscoveryFindingEntity.java 100% 🍏
DiscoveryAuditWriter.java 100% 🍏
UpdateDiscoveryConfigRequest.java 100% 🍏
BulkDiscoveryDecisionResponse.java 100% 🍏
DiscoveryConfigResponse.java 100% 🍏
DiscoveryFindingResponse.java 100% 🍏
BulkDiscoveryDecisionRequest.java 100% 🍏
DiscoveryFindingPageResponse.java 100% 🍏
DiscoveryFindingStateService.java 100% 🍏
DiscoveryViewMapper.java 100% 🍏
DefaultDiscoveryFindingService.java 100% 🍏
DefaultDiscoveryConfigService.java 100% 🍏
DiscoveryFindingStatus.java 100% 🍏
DiscoveryFindingView.java 100% 🍏
DiscoveryDetector.java 100% 🍏
DiscoveryDecision.java 100% 🍏
UpsertDiscoveryConfigCommand.java 100% 🍏
DiscoveryException.java 100% 🍏
DiscoveryScanConfigView.java 100% 🍏
DiscoveryRowStatus.java 100% 🍏
DiscoveryConfiguration.java 100% 🍏
DiscoveryProperties.java 100% 🍏
AuditAction.java 100% 🍏
AuditResourceType.java 100% 🍏
CreditCardDetector.java 100% 🍏
SsnDetector.java 100% 🍏
EmailDetector.java 100% 🍏
PhoneDetector.java 100% 🍏
ValueDetector.java 100% 🍏
IbanDetector.java 100% 🍏
DiscoveryScanJob.java 100% 🍏
DefaultDataDiscoveryAiService.java 98.28% -1.72% 🍏
DiscoveryController.java 96.98% -3.02% 🍏
DiscoveryScanService.java 94.92% -5.08% 🍏
DiscoveryFindingService.java 92.86% -7.14% 🍏
DataDiscoveryAiService.java 92% -8% 🍏
DefaultDiscoveryScanTriggerService.java 88% -12% 🍏
AiAnalyzerStrategyHolder.java 77.16% -3.44% 🍏
DiscoveryScanAlreadyRunningException.java 75% -25% 🍏
DiscoveryPageAdapter.java 54.55% -45.45% 🍏
SpringPageableAdapter.java 52.5% -47.5% 🍏
DiscoveryScanConfigEntity.java 0% 🍏
DiscoveryExceptionHandler.java 0% 🍏

@babltiga
babltiga merged commit fd17ee3 into main Jul 27, 2026
34 checks passed
@babltiga
babltiga deleted the feature/AF-623-sensitive-data-discovery branch July 27, 2026 14:51
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.

discovery: automated sensitive-data discovery & classification scanning (regex + AI column sampling, admin-confirmed tags)

1 participant