Conversation
…ntials The Teradata connector (source and destination) now logs on with exactly one of three credential sets, selected by which fields are present: username and password (unchanged), a pasted JWT, or a JWT the connector mints with an OAuth 2.0 client credentials grant. JWT logon is the driver's logmech=JWT with logdata=token=<JWT> and no user or password. The connector opens a connection per query, so the token is read at every logon: a malformed or expired pasted token is refused before it is sent, and a client-credentials token is renewed before it expires. JWT logon errors become fixed-text errors, with a distinct one for an expired token, and each run logs the method it authenticated with, never the credential. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 8 files
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
- The client-credentials token source refuses an http token URL itself, not only through the connection config, so direct construction cannot send the client secret in cleartext. - An auth verdict raised while the destination precheck probes CREATE TABLE (a JWT that expired or was refused since the first logon) now fails the precheck instead of reading as an inconclusive probe. - CHANGELOG: `from None` suppresses the driver text in tracebacks rather than removing it, and the audit line is once per outcome per connection config. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 5 files (changes from recent commits).
Shadow auto-approve: would not auto-approve because issues were found.
Re-trigger cubic
|
Automated review, forwarded by @paulkarayan. Findings are code-verified where they name a file and line; the strong-review gpt-pro leg and cubic did not run. NO-GO -- 1 blocker(s), 0 concern(s), 3 note(s), 1 nit(s). (verdict: BLOCK) JWT and client-credential Teradata configs cannot be pickled, so the default 2-process ingest pipeline crashes; the fix is ~4 lines plus a pickle test. Blockers (1)
Notes (3)
Nits (1)
Full review |
What & why
Problem: The Teradata connector (source and destination) authenticates with a database username and password only. A site whose Teradata database trusts JWTs from its identity provider cannot use that identity for the connector. Adding a field to the connector's config here is also what lets the Unstructured platform accept one: its connector-config validation reads these models, and it drops any key they do not declare. Today it drops
tokenand demandspassword.Change: The connector takes exactly one of three credential sets, selected by which fields are present:
teradatasql.connectgetsuser,access_config.passwordhost, user, password, dbs_port, database, the same keys in the same orderaccess_config.tokenhost, logmech="JWT", logdata="token=<JWT>", dbs_port, database, with nouserorpasswordtoken_url,client_id,access_config.client_secret, optionalscopeaccess_confignext to the password. The non-secret OAuth fields sit on the connection config besidehost, so a platform that encrypts every string inaccess_configdoes not hide them.exp, is refused before the database is contacted; with 20.0.0.66 the driver does not checklogdatafor JWT before connecting. A client-credentials token is renewed two minutes before it expires, or halfway through a shorter life. If the identity provider is unreachable, the held token keeps working until it expires. If the provider refuses the client, the run stops.JWT Token expiredbecomesTokenExpiredError(401).UserAuthError(401).ProviderErrorfor a connection failure, any other TLS failure, 408, 429 or 5xx. Only a registered RFC 6749 error code is ever echoed.Teradata authentication: auth.method=<password|jwt|jwt_client_credentials> outcome=<authenticated|ErrorType> job_id=<JOB_ID> dag_node_id=<DAG_NODE_ID>.Driver facts this relies on (teradatasql README,
logmechtable, JWT row): "logdatamust containtoken=followed by the JSON Web Token. The database user must have the "logon with null password" permission." The database takes the user from the token'ssubclaim by default.useris not sent on the JWT path; teradataml'screate_contextbuilds a JWT logon the same way.Impact
TeradataAccessConfig.passwordandTeradataConnectionConfig.userbecome optional, and the model validator requires them together. New optional fields:access_config.token,access_config.client_secret,token_url,client_id,scope.requestsjoins theteradataextra.from None, so the driver's text no longer rides along as the exception's__context__. The message and type are unchanged.token_url.Risk / rollback
test_password_logon_is_unchanged, which also asserts parameter order.JWT Token expired, the word JWT, database 8017). The exact wrapper Teradata puts around a server-side JWT error has not been observed live; an unrecognised one falls through to the existing connection-error summary.How it was verified
make test-unit(the full target,-n auto): 1991 passed. The Teradata modules are 169 existing, 82 new intest_teradata_auth.pyand 45 new intest_teradata_jwt.py.make check(ruff check .): all checks passed.ruff formatis clean on the new files.teradata.pywas already format-dirty atHEAD: the formatter asks for exactly the same changes onmainand on this branch, so I did not reformat it.make check-versionwas not run locally (it needs GNU sed). CHANGELOG's top heading and__version__.pyboth read 1.11.21.main'steradata.pygive 43 failed, 2 passed. The two that pass are the password-path guards, which must pass onmain.flatten_dict/extract_config/validate_dataclass, copied verbatim) against this model:main: a JWT config losestokenand fails withaccess_config.password: Field is requiredanduser: Field is required.token/client_secretare kept insideaccess_config, andtoken_url/client_id/scopeat top level, with no errors.logmech=JWT,logdata=token=..., with nouserorpassword.Proof
Not in this PR
logmech=SECRET/CRED/BEARER) are not exposed. They depend on the database advertising its identity provider, which could not be tested here.🤖 Generated with Claude Code