Skip to content

[DT-4274][risk=low] Add the showcase catalog projection query and eligibility filter (3/3) - #3184

Merged
otchet-broad merged 21 commits into
otchet-dt-4274-utilsfrom
otchet-dt-4274-projection
Oct 27, 2026
Merged

otchet-broad merged 21 commits into
otchet-dt-4274-utilsfrom
otchet-dt-4274-projection

Conversation

@otchet-broad

@otchet-broad otchet-broad commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Addresses

https://broadworkbench.atlassian.net/browse/DT-4274

Security risk: low — adds a read-only query for a future public endpoint (S2.2). No endpoint or caller is added here.

Summary

Part 3 of 3 of the DT-4274 showcase catalog projection. At reviewer request, the original PR was split: the helpers are in #3189 and the field contract is in #3190. This PR now holds only the query and its mapper. It is stacked on #3190; merge order: #3189, #3190, then this PR. The review threads below are kept. The TranslationUtil and ShowcaseScopeKey threads now apply to #3189 and #3190.

  • Projection: DatasetDAO.findShowcaseSummaries is one fixed SQL block. It reads named columns, plus dataset_property and study_property rows filtered by separate bound allowlists from ShowcasePublicField. ShowcaseDatasetSummaryMapper builds the ShowcaseDatasetSummary record. Property names match ignoring case and blank values are skipped. Provider links must be absolute http(s) with a valid host, a valid port and no user info; non-ASCII hosts are published in punycode. Participant counts that are not non-negative integers become null. Consent codes come from TranslationUtil.summaryCodes ([DT-4274][risk=low] Add consent-code summaries and a null-serializing Gson (1/3) #3189), which leaves out free text.
  • Eligibility, in the same WHERE: the study must be public, and the dataset must be open/external or approved by a DAC that is not soft-deleted. Access classification follows Dataset.getAccessManagement() (current key before legacy consentGroup.accessManagement, case-insensitive, trimmed). The admin, creator, custodian and no-study exceptions of DatasetService do not apply.
  • Semgrep: IDN.toASCII in the mapper carries a nosemgrep for gitlab.find_sec_bugs.IMPROPER_UNICODE-1. validHostName checks the ASCII result, and that result is what the URL publishes, so the check runs after the transformation.

The field table that data stewards and AppSec need to approve is now in #3190.

Testing

DatasetShowcaseSummaryDAOTest (64 tests, Testcontainers Postgres, synthetic records) covers open/controlled/external, controlled without DAC approval, private and missing studies, null visibility (rejected by the schema), a hard-deleted dataset, legacy access and URL keys, case-insensitive property names, blank rows, deleted or missing DACs, unknown values, unapproved properties, type conversion, unsafe URLs and ordering. A Claude + Codex cross-review found no high or medium issues; its three low findings are fixed or recorded in the contracts doc. The fixes for the review threads below were cross-reviewed again before pushing.


Have you read CONTRIBUTING.md lately? If not, do that first.

  • Label PR with a Jira ticket number and include a link to the ticket
  • Label PR with a security risk modifier [no, low, medium, high]
  • PR describes scope of changes
  • Get a minimum of one thumbs worth of review, preferably two if enough team members are available
  • Get PO sign-off for all non-trivial UI or workflow changes
  • Verify all tests go green
  • Test this change deployed correctly and works on dev environment after deployment

🤖 Generated with Claude Code

otchet-broad and others added 9 commits October 26, 2026 18:07
…ope vocabulary

Add ShowcasePublicField, ShowcaseScopeKey and the flat ShowcaseDatasetSummary record, a
key-set test that ties the record to the allowlist, and TranslationUtil.summaryCodes for
consent codes without free text. Record the field, eligibility and scope decisions in the
S1.1 contracts doc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…irements

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gibility tests

Add DatasetDAO.findShowcaseSummaries: one fixed query that reads named columns and
allowlisted dataset/study properties through bound lists, and applies public visibility and
the open/external-or-DAC-approved rule in its WHERE clause. Map rows with
ShowcaseDatasetSummaryMapper. DAO tests cover access classification with legacy keys, private
and missing studies, hard deletes, unapproved properties, type conversion and unsafe URLs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ring.trim

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the JVM time zone

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rializing Gson

#3174 removed GsonUtil.buildGsonNullSerializer(). Add getNullSerializingInstance(), which keeps
null fields without the registration enum adapter, and point the summary key-set test and the
S2.2 requirements at it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…pe, use assertNull

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…species and date caveats

Older registrations stored the provider link as consentGroup.url, as they did for access
management. Read it after url. Drop the unsupported UTC claim for availableDate, and record
species as a free-text field that needs a steward decision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@otchet-broad
otchet-broad requested a review from a team as a code owner October 26, 2026 18:50
@otchet-broad
otchet-broad requested review from fboulnois and rushtong and a balanced review from Copilot and removed request for a team October 26, 2026 18:50

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The public-field contract still requires data-steward and AppSec sign-off, particularly on exposing unrestricted species text.

No open issues 🎉

What changed in this PR

Implements the S2.1 Data Showcase catalog projection for a future public endpoint. This PR adds the data-access foundation and contract; it introduces no endpoint or caller.

Changes:

  • Defines the public-field allowlist, summary record and DAC scope vocabulary.
  • Adds an eligibility-filtered query and mapper, codes-only consent summaries and null-preserving serialization.
  • Adds regression tests and documents the contract, approval gates and S2.2 integration requirements.
File Description
src/​test/​java/​org/​broadinstitute/​consent/​http/​util/​gson/​GsonUtilTest.java Tests preservation of null fields.
src/​test/​java/​org/​broadinstitute/​consent/​http/​models/​ShowcaseDatasetSummaryTest.java Checks summary fields and serialization against the allowlist.
src/​test/​java/​org/​broadinstitute/​consent/​http/​matching/​TranslationUtilTest.java Tests consent-code ordering and null input.
src/​test/​java/​org/​broadinstitute/​consent/​http/​db/​DatasetShowcaseSummaryDAOTest.java Covers eligibility, projection, conversions and ordering.
src/​main/​java/​org/​broadinstitute/​consent/​http/​util/​gson/​GsonUtil.java Adds a null-serializing Gson instance.
src/​main/​java/​org/​broadinstitute/​consent/​http/​models/​ShowcaseDatasetSummary.java Defines the flat public summary record.
src/​main/​java/​org/​broadinstitute/​consent/​http/​matching/​TranslationUtil.java Extracts consent codes without free-text values.
src/​main/​java/​org/​broadinstitute/​consent/​http/​enumeration/​ShowcaseScopeKey.java Defines exact DAC-name scope matching.
src/​main/​java/​org/​broadinstitute/​consent/​http/​enumeration/​ShowcasePublicField.java Defines field metadata and property allowlists.
src/​main/​java/​org/​broadinstitute/​consent/​http/​db/​mapper/​ShowcaseDatasetSummaryMapper.java Maps summaries and validates counts and provider URLs.
src/​main/​java/​org/​broadinstitute/​consent/​http/​db/​DatasetDAO.java Adds the public-study and access-eligibility projection query.
docs/​plans/​data-showcase-delivery-plan.md Updates contract references and the summary example.
docs/​plans/​data-showcase-contracts.md Documents fields, eligibility, scope and remaining approval gates.

Review effort: Balanced

@rushtong rushtong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review notes from a Claude Code pass (high effort). The first two comments are the most important: they affect which data becomes public. The last two are minor cleanup.

Comment thread src/main/java/org/broadinstitute/consent/http/db/DatasetDAO.java Outdated
Comment thread src/main/java/org/broadinstitute/consent/http/db/DatasetDAO.java Outdated
Comment thread src/main/java/org/broadinstitute/consent/http/db/DatasetDAO.java Outdated
Comment thread src/main/java/org/broadinstitute/consent/http/db/DatasetDAO.java Outdated
Comment thread src/main/java/org/broadinstitute/consent/http/matching/TranslationUtil.java Outdated
Comment thread src/main/java/org/broadinstitute/consent/http/db/DatasetDAO.java Outdated
Comment thread src/main/java/org/broadinstitute/consent/http/enumeration/ShowcaseScopeKey.java Outdated
otchet-broad and others added 3 commits October 26, 2026 21:27
…sitive and non-blank properties

- Approval counts only with a DAC that exists and is not soft-deleted; dacName ignores
  soft-deleted DACs.
- Allowlisted property names match ignoring case, and blank values are skipped, so an empty
  older row no longer hides a newer value or the legacy url.
- Provider links are checked by authority, so hosts with an underscore or a non-ASCII
  character are kept; an "@" in the authority is still rejected.
- Compute the access value once; state how summaryCodes differs from translateSummary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sh non-ASCII hosts as punycode

The authority check accepted any non-blank authority, so links with no host, a bad port, or
bidi and homograph characters were published. Keep URI's checks when it parses a host;
otherwise parse the host and port, convert the host with IDN.toASCII and require valid labels
and a port from 1 to 65535. Lower-case the allowlists with Locale.ROOT.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…IDNA deviation characters

A whole-host regex overflowed the stack on a very long host. Check each label instead, with
the 63 and 253 character limits, on both URI branches. Reject the characters that
java.net.IDN (IDNA2003) and browsers (UTS 46) map to different hosts, such as "ß", and
accept leading zeros in a port.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@rushtong rushtong left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the updates and responses, they all look good. Pending the semgrep fix, 👍🏽

@fboulnois fboulnois left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split this into smaller PRs?

otchet-broad and others added 2 commits October 27, 2026 17:15
…the provider-link host

validHostName checks the ASCII result of IDN.toASCII, and that result is
what the URL publishes, so the check runs after the transformation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and scope vocabulary

ShowcasePublicField lists each public field with its source, type and
nullability; ShowcaseDatasetSummary is the flat record whose components
must equal that list; ShowcaseScopeKey fixes the scope vocabulary. The
contracts doc records the fields, eligibility and approval gates. Split
from #3184 at reviewer request; the query that fills the record stays
in #3184.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@otchet-broad
otchet-broad changed the base branch from develop to otchet-dt-4274-contract October 27, 2026 17:41
@otchet-broad otchet-broad changed the title [DT-4274][risk=low] Add the showcase catalog projection, field allowlist and eligibility query [DT-4274][risk=low] Add the showcase catalog projection query and eligibility filter (3/3) Oct 27, 2026
@otchet-broad

Copy link
Copy Markdown
Contributor Author

@fboulnois Split into three stacked PRs:

  1. [DT-4274][risk=low] Add consent-code summaries and a null-serializing Gson (1/3) #3189: TranslationUtil.summaryCodes and GsonUtil.getNullSerializingInstance (4 files)
  2. [DT-4274][risk=low] Define the showcase public fields and summary record (2/3) #3190: the field contract: ShowcasePublicField, ShowcaseDatasetSummary, ShowcaseScopeKey and the contracts doc (6 files, stacked on [DT-4274][risk=low] Add consent-code summaries and a null-serializing Gson (1/3) #3189)
  3. This PR: the projection query, its mapper and the DAO tests (3 files, stacked on [DT-4274][risk=low] Define the showcase public fields and summary record (2/3) #3190)

The merge order is #3189, #3190, then #3184. The code is unchanged. I merged the new branches into this branch instead of rewriting it, so the earlier review threads are kept.

@sonarqubecloud

Copy link
Copy Markdown

otchet-broad and others added 6 commits October 27, 2026 18:24
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eld types against the record

Address review on #3190: a PropertyTable per field drives the allowlists,
so relabeling a Source cannot change which rows the projection reads.
IDENTIFIER and ACCESS_URL are DERIVED. Tests check each field's type
against its record component, compare serialized keys as a set and
check that property sources read their table. Drop the unused units
metadata, and mark the contracts doc's query rules as pending #3184.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… required summary fields

Sonar S3776: safeUrl's handling of hosts that java.net.URI does not
parse moves to asciiHostUrl, with no change in behavior. Every DAO test
result is now checked against ShowcasePublicField.isNullable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Address review on #3190: nothing calls the enum yet, and its SQL column
text belongs in the DAO query. The contracts doc keeps the agreed scope
vocabulary; S2.2 adds the code with the query that uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from otchet-dt-4274-contract to otchet-dt-4274-utils October 27, 2026 22:03

@kevinmarete kevinmarete left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍🏾

@otchet-broad
otchet-broad merged commit 62ab030 into otchet-dt-4274-utils Oct 27, 2026
4 checks passed
@otchet-broad
otchet-broad deleted the otchet-dt-4274-projection branch October 27, 2026 23:03
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.

5 participants