Skip to content

[HWORKS-3370] Provided credentials for data sources (oracle) - #687

Merged
jimdowling merged 11 commits into
logicalclocks:mainfrom
jimdowling:provided-datasource-credentials
Oct 13, 2026
Merged

jimdowling merged 11 commits into
logicalclocks:mainfrom
jimdowling:provided-datasource-credentials

Conversation

@jimdowling

@jimdowling jimdowling commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

JIRA: https://hopsworks.atlassian.net/browse/HWORKS-3370

Related PRs: logicalclocks/hopsworks-ee#3434, logicalclocks/hopsworks-api#1244, logicalclocks/hopsworks-front#2147, logicalclocks/loadtest#1115, #687

Merge order: logicalclocks/hopsworks-api#1244 must merge before this PR. The test-docs-build job builds against hopsworks-api main, which does not yet have ExternalFeatureGroup.data_source_access and ExternalFeatureGroup.test_data_source_access, so the strict build fails on those autorefs until #1244 lands. Rerun CI after #1244 merges and before merging this PR.

Documents PROVIDED credentials for Oracle data sources:

  • user_guides/fs/data_source/creation/sql.md gets a new section, #data-source-provided-credentials, covering:
    • the credentials mode;
    • setting and validating member credentials from the UI, the SDK and the CLI;
    • the HOPS_DS_* variables;
    • which runtimes receive those variables.
  • user_guides/fs/feature_group/create_external.md gets #external-feature-group-data-source, which explains the per-member access status.

markdownlint is clean. The strict build passes with the matching hopsworks-api branch installed, which plain-texts one docstring link to the non-public SqlConnector.

Update

  • Trino catalogs on PROVIDED sources: a new section, #data-source-provided-credentials-trino, with a table of which clients send extra credentials.

  • Replacing a wallet: a new section, #data-source-provided-credentials-wallet.

  • Runtime variables: covers HOPS_DS_<NAME>_CONNECTOR_ID, the Spark wallet fallback, and why deployments do not get the variables.

  • Default username: the new name.

  • Trino catalogs page: projects/trino/catalogs.md now notes PROVIDED catalogs.

  • Review round (51ca5f2): stored-credential steps scoped to Stored with the data source; Yours: incomplete; access checks settle within a few minutes, with member join and the 10-minute reconcile in the trigger list; removing credentials, member removal and data source deletion delete the default-named account entries; the Trino catalog's wallet follows the creator's credentials; shared feature store credentials are added in the owning project; the API box lists the SqlConnector credential methods, linked to the page section since SqlConnector has no API reference entry.

  • Private catalogs (7a4cf2c, 26e2d96): a Trino catalog on a provided data source is always a private catalog of its creator; each member (Data Owner or Data Scientist) creates their own, a project-scope request is refused with CREDENTIALS_MODE_NOT_SUPPORTED (270337), and such a catalog cannot be shared. The wallet lives in a mountable secret of the creator's account and follows their credentials. The text on project copies, shared-project copies, unshare cleanup and the wallet hash pin is removed. projects/trino/catalogs.md says the same. Strict build and markdownlint pass.

  • Screenshots: not updated yet. sql_creation.png predates the Credentials selector, and there are no images of the My credentials dialog, the Data Source submenu or greyed-out cards.

Loadtests

Loadtests on the final SHAs: 12/12 passed. Run 776b2463 on jim-private-ds, 2026-10-12, test_data_sources_provided_credentials.py (test_01 to test_12) with LOADTEST_TRINO_RESTART=1, laptop runner, 1 worker, 6m18s. It ran on hopsworks-ee 2d961c9ec2 (V118 applied), hopsworks-api 369d7effcc (the same wheel is overlaid on the cluster's Spark and Python job images, so jobs read with this SDK), hopsworks-front 3456cb2df and loadtest bb2573a, against the Oracle Autonomous Database in eu-stockholm-1 over mTLS. That covers the round-1 and round-2 security fixes and the private catalogs for PROVIDED data sources (test_09 creates its catalog as a Data Scientist). The connector uses the wallet's TNS alias with no host. With a host set, flyingduck dials host:port/service over plain TCP and the mTLS listener resets it (DPY-4011). Since then, hopsworks-ee has merged upstream master (502449de93: HWORKS-3384 and HWORKS-3388 proxy tokens, no migrations or REST codes). It compiles but has not been rerun. Not covered by any run: the validate/save rate limit (270343), the cleanup on data source, feature store and project delete, scheduled runs, and a browser pass over the UI. An earlier run, 3af3d0c8 (12/12, 20m39s), was on the round-1 code.

CI: the three references to ExternalFeatureGroup.data_source_access and test_data_source_access link to the section of create_external.md that documents them, so test-docs-build passes strict against hopsworks-api main without waiting for logicalclocks/hopsworks-api#1244.

🤖 Generated with Claude Code

https://hopsworks.atlassian.net/browse/HWORKS-3370

A data source today carries one set of credentials that every project
member reads through, so the database cannot tell members apart and
cannot enforce its own grants per person. Add a credentials mode to
data sources: SHARED keeps today's behaviour, PROVIDED means each
member supplies their own username, password and wallet, stored as
their own private secrets and environment variables. Oracle is the
first and only type that accepts PROVIDED; the mode is fixed at
creation.

Every read path (Arrow Flight, data source browsing, dlt ingestion)
resolves the caller's own credentials and refuses with a clear error
when they are missing. Jobs, Jupyter, terminals, apps and Ray get the
member's HOPS_DS_<NAME>_* variables, tagged with the connector id so a
same-named data source of another feature store never picks them up;
model deployments do not, since a deployment is shared by the whole
project. Trino catalogs built from a PROVIDED data source store no
login: each query authenticates with the querying member's credentials
sent as Trino extra credentials. External feature groups on a PROVIDED
source record, per member, whether that member can read the backing
table, re-checked in the background when credentials change or members
join.

Saves are all-or-nothing from the member's point of view: a failed
validation or save leaves the existing binding, password and wallet as
they were.

The docs describe the PROVIDED mode on the SQL data source page
(names, runtime variables, wallet replacement, Spark, deployments and
Trino catalogs) and how a member's access is shown for external
feature groups.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimdowling
jimdowling force-pushed the provided-datasource-credentials branch from 81259cd to 68a3f96 Compare October 7, 2026 20:40
jimdowling and others added 2 commits October 9, 2026 12:29
https://hopsworks.atlassian.net/browse/HWORKS-3370

Fix the wallet example, which read two secrets from stdin and so always
failed: the CLI takes one per call.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimdowling
jimdowling requested a review from ErmiasG October 12, 2026 11:28
@jimdowling
jimdowling marked this pull request as ready for review October 12, 2026 11:31

@ErmiasG ErmiasG 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 against the HWORKS-3370 description. The Oracle provided-credentials section and the Data Source submenu docs are accurate against hopsworks-api#1244, hopsworks-ee#3434 and hopsworks-front#2147 (method names, CLI flags, error codes, UI labels).

Other findings, not anchored to a diff line:

  1. [Should Fix] test-docs-build fails in strict mode on three unresolved autorefs: ExternalFeatureGroup.test_data_source_access (sql.md:321 and create_external.md) and ExternalFeatureGroup.data_source_access (create_external.md). CI builds against hopsworks-api main, which doesn't have these members yet. State in the body that hopsworks-api#1244 must merge first, and rerun CI before merging.

  2. [Nitpick] sql_creation.png is unchanged, so it presumably lacks the new Credentials selector. There are no images of the My credentials dialog, the Data Source submenu or the greyed-out cards.

Comment thread docs/user_guides/fs/data_source/creation/sql.md Outdated
Comment thread docs/user_guides/fs/data_source/creation/sql.md Outdated
Comment thread docs/user_guides/fs/data_source/creation/sql.md Outdated
Comment thread docs/user_guides/fs/data_source/creation/sql.md
https://hopsworks.atlassian.net/browse/HWORKS-3370

Address review on the provided credentials docs and record the contract
changes made alongside it.

The SQL data source guide now limits the username, password and wallet
steps to stored credentials, lists Yours: incomplete in the Credentials
column, says an access check usually settles within a few minutes and
adds a member joining the project and the 10-minute reconcile to the
check triggers. Removing your credentials, a member leaving the project
and deleting the data source now delete the account entries saved under
their default names, while entries under custom names stay. A Trino
catalog on a provided Oracle data source keeps a copy of the creator's
wallet, deleted when the creator removes their credentials or leaves
and rebuilt when they save a new wallet. SqlConnector is not in the
Python API reference, so the API box lists its credential methods and
links them to the section that shows them. The external feature group
guide explains that credentials for a feature group from a shared
feature store are added in the project that owns the data source.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimdowling

Copy link
Copy Markdown
Contributor Author

Body findings from the review, addressed in 51ca5f2:

  1. Strict build autorefs (ExternalFeatureGroup.test_data_source_access, ExternalFeatureGroup.data_source_access): the PR body now states that [HWORKS-3370] Provided credentials for data sources (oracle) hopsworks-api#1244 must merge first and that CI must be rerun before this PR merges. Locally, uv run hopsworks-docs check passes with the hopsworks-api branch of #1244 installed, and markdownlint and snakeoil pass.

  2. Screenshots: not done. The Oracle database on the test cluster is down and no browser automation was available in this session, so sql_creation.png still lacks the Credentials selector and there are no images of the My credentials dialog, the Data Source submenu or the greyed-out cards. Left open; noted in the PR body.

The same commit also documents contract changes made alongside the review: removing your credentials, removing a member and deleting the data source now delete the default-named env var and secrets (custom-named entries stay); a Trino catalog on a provided data source keeps a copy of the creator's wallet, deleted when the creator removes their credentials or leaves and rebuilt when they save a new wallet; credentials for a feature group read through a shared feature store are added in the project that owns the data source.

jimdowling and others added 2 commits October 12, 2026 17:06
https://hopsworks.atlassian.net/browse/HWORKS-3370

Documents the decisions from round 2 of the security review of
provided credentials for Oracle data sources.

The SQL data source guide now states that only Data owners and Data
scientists can add credentials, and that validate and save are rate
limited per user and data source with HTTP 429 over the limit. Fetching
or listing a provided data source returns the binding status and the
names of the member's env var and secrets, never the username or
password, and the Python client reads the values from the member's own
account entries. Job runs receive the HOPS_DS_* variables through a
per-run Kubernetes Secret instead of plain values in the pod spec, under
the same names. A warning explains that a scheduled run starts as the
job's creator with the creator's provided credentials, so anyone who can
edit the job can run code with that login, and recommends keeping such
jobs editable only by their owner. The Trino catalog section adds that
Hopsworks pins a hash of the wallet copy and refuses to load the catalog
after an outside change until the creator saves credentials again, and
lists the further deletions that remove the copy.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimdowling

Copy link
Copy Markdown
Contributor Author

Round 2 docs at 2bafbcb043: scheduled runs use the creator's credentials (warning), job credentials arrive through a per-run Kubernetes Secret, GET/list no longer return credential values, validate/save are rate limited (HTTP 429), the Trino wallet copy is hash-pinned and removed on catalog, data source, feature store or project delete and on unshare, and only Data owners and Data scientists can add credentials.

uv run hopsworks-docs check (strict) passes with the api#1244 branch installed; markdownlint 0 errors across 282 files; snakeoil leaves the tree clean. The rate-limit error code number will be added once ee#3434's round-2 commit lands.

jimdowling and others added 4 commits October 12, 2026 21:37
https://hopsworks.atlassian.net/browse/HWORKS-3370

Name the rate limit on validate and save: 5 calls per minute per user
and data source, refused with DATA_SOURCE_CREDENTIALS_RATE_LIMITED
(270343).

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
https://hopsworks.atlassian.net/browse/HWORKS-3370

A Trino catalog on a data source with provided credentials is now
always a private catalog of the member who creates it.

The Trino section of the SQL data source guide says so: each member,
Data Owner or Data Scientist, creates their own catalog, a request for
a project catalog is refused with CREDENTIALS_MODE_NOT_SUPPORTED, and
such a catalog cannot be shared. The wallet is built into a mountable
secret of the creator's account and follows their credentials. The
text about project copies of the wallet, copies in shared projects,
cleanup on unshare and the wallet hash pin is removed, since none of
them exist any more.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
https://hopsworks.atlassian.net/browse/HWORKS-3370

The Trino catalogs page now says the same as the SQL data source
guide: a catalog on a data source with provided credentials is always
a private catalog of its creator, each member creates their own, and
it cannot be shared, so it reads as its owner's own database user.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimdowling

Copy link
Copy Markdown
Contributor Author

Round 2 cluster verification: test_data_sources_provided_credentials.py passed 12/12.

Run 776b2463 on jim-private-ds, 2026-10-12, laptop runner, 1 worker, LOADTEST_TRINO_RESTART=1, 6m18s, against the Oracle Autonomous Database in eu-stockholm-1 over mTLS.

Repo Commit
hopsworks-ee 2d961c9ec2 (deployed; V118 schema plus upstream V116/V117 applied)
hopsworks-api 369d7effcc (laptop runner and, as a wheel, in the cluster's spark-feature-pipeline and python-feature-pipeline images)
hopsworks-front 3456cb2df (deployed)
loadtest bb2573a

What the run covers from round 2:

  • Job credentials reach Python and Spark jobs through the per-run <runtime>-dscred Secret (test_05, test_08).
  • GET and list of the PROVIDED connector carry no user, password or walletPassword, and the SDK reads the owner's values from the owner's own account entries (test_02).
  • Catalogs on the PROVIDED data source are private: owner and reader each create their own and read as themselves; a PROJECT-scope request is refused with 270337 and a share with 403 (test_09); after the reader removes their credentials, reads through their own catalog are refused (test_11).

Defects the cluster runs found and fixed on the way:

  • ee be04bf095b: adopt() looked up the runtime with the apiVersion/kind form of genericKubernetesResources, which returned nothing for a live SparkApplication, and then deleted the credentials Secret, so the driver sat in CreateContainerConfigError. It now uses an explicit resource context and keeps the Secret on a miss.
  • ee 2d961c9ec2: a Data Scientist could create their private catalog but not fetch its template (403 on catalog/template); the template now applies the create rule.
  • loadtest bb2573a: a failing assert printed the module's shared state, which holds the Oracle config, passwords and API keys. The state's repr names no values now, and the credential asserts report field names only.

Not covered: the rate limit on validate/save, the project/feature store delete cleanup, scheduled runs, and a browser pass over the front.

@ErmiasG ErmiasG 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.

Approved. test-docs-build is expected to stay red until hopsworks-api#1244 is merged.

https://hopsworks.atlassian.net/browse/HWORKS-3370

test-docs-build builds against hopsworks-api main, which does not have
ExternalFeatureGroup.data_source_access or test_data_source_access
until hopsworks-api#1244 merges, so strict mode failed on three
cross-references to them. They now link to the "From the API and the
CLI" section of create_external.md, which documents both, through a new
external-feature-group-data-source-access heading id, the same way the
SqlConnector credential methods are linked. The build passes strict
against hopsworks-api main.

Signed-off-by: Jim Dowling <jim@logicalclocks.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jimdowling
jimdowling merged commit ee0f8c5 into logicalclocks:main Oct 13, 2026
1 check passed
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