Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
zvigrinberg
left a comment
There was a problem hiding this comment.
@TamarW0 LGTM Approved.
Don't forget tests in a follow up PR.
Code Review — 8 findingsCritical / High (must fix before merge)1. Missing wildcard case in The match handles Fix: Add explicit case "disabled" | None:
return None
case _:
logger.error(
"Unrecognized auth_type '%s'. Valid values: basic, bearer, keycloak, cognito, disabled",
http_config.auth_type,
)
return None2. When Cognito token fetch fails, Fix: Log a warning at call sites when auth was configured but returned None: auth_header = get_auth_header(http_output_config)
if auth_header is None and http_output_config.auth_type not in ("disabled", None):
logger.warning(
"Auth type is '%s' but get_auth_header returned None — "
"credential backend calls will fall back to SA token",
http_output_config.auth_type,
)3. The field description says Fix: Either prepend domain = http_config.cognito_domain.rstrip("/")
if not domain.startswith("https://"):
domain = f"https://{domain}"
token_url = f"{domain}/oauth2/token"Or update the field description to require the scheme. 4. The type signature accepts Fix: def get_auth_header(http_config: CVEHttpOutputConfig | None) -> str | None:
if http_config is None:
return None
match http_config.auth_type:
...High (should fix)5. No warning when configured auth fails — When Fix: Add an else branch logging a warning when 6. Broad Catches Medium (recommended)7. Token fetched 4× per pipeline run — Each pipeline node independently calls 8. Zero test coverage for new code paths
|
--------- Signed-off-by: Zvi Grinberg <zgrinber@redhat.com> Co-authored-by: Tamar Weisskopf <tweissko@redhat.com> Co-authored-by: Zvi Grinberg <zgrinber@redhat.com>
Comprehensive tests for OAuth2 client_credentials flow, token fetching, and configuration validation. 21 tests pass covering success/error paths and edge cases. Relates to: TC-5942 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
700b0a2 to
7402e3a
Compare
Fixes based on Theodor's review: 1. Add wildcard case to get_auth_header - logs error for unrecognized auth_type values (e.g. typos like 'Cognito') 2. Handle None config in get_auth_header to prevent AttributeError when config key is missing 3. Auto-prepend https:// to cognito_domain if missing, update field description to accept both formats 4. Replace broad Exception with specific exception handling: - requests.RequestException for network/HTTP errors - KeyError/ValueError for invalid JSON responses Tests updated to cover all new behaviors (27 tests pass). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Specify auth_type='disabled' in test to clarify Cognito fields are optional when NOT using Cognito auth - Add test verifying required field validation when auth_type='cognito' 28 tests now pass.
Removed test_cognito_fields_accept_and_store_values - testing that Pydantic stores values is the framework's responsibility, not ours. 27 focused tests remain.
Remove comment explaining https:// prepending as the code is self-explanatory.
Rename test to reflect that fields default to None (not specific to when auth_type is disabled). The same pattern applies to all auth types - fields are optional until that specific auth_type is used.
|
/test vulnerability-analysis-on-pr |
tmihalac
left a comment
There was a problem hiding this comment.
PR Review — AWS Cognito OIDC Provider (APPENG-5865)
Solid work on the Cognito flow itself — get_auth_header is nicely hardened (explicit None-config guard, a disabled | None case, and a case _ catch-all that logs unrecognized auth_type, with a test for the "Cognito" typo). _fetch_cognito_token has clean error handling: specific exception catches, no credential leakage in logs, a 30s timeout, correct Basic-auth client_credentials flow, and https/trailing-slash normalization. Test coverage for the Cognito path is thorough and behavior-focused. A few things worth addressing below.
Important
-
The
cve_http_outputauth header is now reused to authenticate to the credential backend — please confirm this is intended. Previouslyfetch_and_decrypt_credentialalways authenticated to{backend_url}/api/v1/credentials/{id}via_resolve_jwt_token(K8s SA token /CLIENT_JWT_TOKEN). Nowclone_and_deps,generate_vdbs, andcve_segmentationresolve the header from thecve_http_outputconfig (the config for sending reports) and inject it viahttp_auth_header_context, overriding the SA-token path. These are almost certainly different services with different token audiences/IdPs — reusing the output token against the credential backend works only if both trust the same issuer/audience. Withauth_type: basicthe backend would get aBasic ...header and reject it (401/403).auth_type: disabled(default) yieldsNone→ falls back to the SA token, so default/local setups are unaffected, but any deployment with real auth configured silently changes behavior. See inline comment. -
builder.get_function_config(HTTP_OUTPUT_AGENT_CONFIG)can raise and break three core stages.clone_and_deps,generate_vdbs, andcve_segmentationnow hard-depend on acve_http_outputfunction being registered. If it isn't,get_function_configtypically raises — breaking stages that previously had no such dependency.get_auth_headeralready toleratesNone, so guard the lookup (try/except or a get-or-None variant) so a missing output config degrades gracefully instead of crashing the pipeline. See inline comment.
Suggestion
- Cognito token is fetched fresh on every stage, with no caching. Each of the three stages independently calls
get_auth_header, so acognitodeployment makes 3 separateoauth2/tokenround-trips per scan. Consider resolving once and threading it through, or caching with expiry. Also note a long-running stage could outlive the token's expiry (default ~1h) since the header is captured at stage entry. Not blocking.
|
|
||
| url = f"{backend_url.rstrip('/')}/api/v1/credentials/{credential_id}" | ||
| headers = {"Authorization": f"Bearer {resolved_token}"} | ||
| headers = {"Authorization": auth_header} |
There was a problem hiding this comment.
This override means the credential backend is now authenticated with whatever get_auth_header(cve_http_output_config) returns, instead of the K8s SA token / CLIENT_JWT_TOKEN from _resolve_jwt_token. The credential backend and the HTTP report-output endpoint are almost certainly different services with different token audiences — this only works if both trust the same issuer/audience. With auth_type: basic the backend would receive a Basic ... header and reject it (raises AuthenticationError on 401/403). Please confirm the credential backend actually accepts the cve_http_output token before merging. (disabled/default is unaffected — it falls back to the SA token here.)
There was a problem hiding this comment.
Regarding the comment about reusing the cve_http_output token for the credential backend:
This pattern was introduced in commit 06d6368 ("fix: add generic idp authentication for credentials endpoint") for keycloak — the Cognito PR follows the same existing design. The credential backend is configured to accept the same IdP tokens as the HTTP output endpoint.
| ) | ||
|
|
||
| with credential_context(message.credential_id): | ||
| http_output_config = builder.get_function_config(HTTP_OUTPUT_AGENT_CONFIG) |
There was a problem hiding this comment.
get_function_config typically raises if cve_http_output isn't registered, which would break this stage entirely — it previously had no dependency on the output config. Since get_auth_header already tolerates None, consider guarding this lookup (try/except or a get-or-None variant) so a missing output config degrades gracefully rather than crashing clone/VDB/segmentation. Same pattern applies in cve_generate_vdbs.py and cve_segmentation.py.
Add try/except guards around builder.get_function_config(HTTP_OUTPUT_AGENT_CONFIG) in clone_and_deps, generate_vdbs, and cve_segmentation stages. When cve_http_output is not registered or config is missing, falls back to default SA token authentication instead of crashing. This prevents the three core pipeline stages from breaking when HTTP output config is absent. Addresses review feedback from tmihalac on PR #331.
- Replace bare 'except Exception' with specific exceptions (KeyError, ValueError, AttributeError) - Add logging when falling back to SA token authentication - Provides visibility into when fallback occurs in production
tmihalac
left a comment
There was a problem hiding this comment.
Automated review of the Cognito auth changes. The core OAuth2 client_credentials logic is correct, secure (no secret leakage), and well unit-tested. Flagging 5 findings inline — 2 Critical (silent auth downgrade + untested integration path) and 3 Important (duplication, over-broad except, redundant token fetch). Details on the relevant lines.
| logger.error("Cognito auth requires cognito_domain, cognito_client_id, and cognito_client_secret") | ||
| return None | ||
| token = _fetch_cognito_token(http_config) | ||
| return f"Bearer {token}" if token else None |
There was a problem hiding this comment.
🔴 Critical — Cognito failure silently downgrades to unauthenticated, and the lost report is reported as success.
On any Cognito failure (bad secret, network error, non-200, missing access_token), _fetch_cognito_token returns None, so this branch returns None — indistinguishable from auth_type: disabled. Downstream in output_to_http._arun, the Authorization header is attached only if auth_header is not None, so the POST goes out unauthenticated. The backend 401s, request_with_retry raises after retries, and the pre-existing broad except Exception swallows it — _arun then returns message as success while the report was never delivered.
The three states "auth disabled", "auth required but failed", and "auth code bug" all collapse into one None.
Fix: when a non-disabled auth_type fails to produce a token, raise (or return a distinct sentinel) so the sender refuses to send unauthenticated; and don't let a delivery failure return success.
| Unexpected HTTP status or network error. | ||
| """ | ||
| resolved_token = _resolve_jwt_token(jwt_token) | ||
| auth_header = _http_auth_header_ctx.get() |
There was a problem hiding this comment.
🔴 Critical — the entire integration half of this feature is untested.
This new context-var branch (and the http_auth_header_context manager above it) has no test. test_credential_client.py wasn't touched, and there are no tests for the try/except wiring added to cve_clone_and_deps.py / cve_generate_vdbs.py / cve_segmentation.py. The unit tests cover _fetch_cognito_token/get_auth_header well, but not the load-bearing wiring.
Please add (extend the untouched test_credential_client.py):
- uses the context header when set, and
_resolve_jwt_tokenis not called; - falls back to
Bearer <jwt>when the context value isNone; - the ContextVar is reset after the
withexits (concurrency-critical — this codebase runs parallel async tasks); - per pipeline site: config present → header propagated; missing config raises →
auth_header=Nonefallback.
Also verify the real exception type builder.get_function_config raises when the function isn't registered is actually within (KeyError, ValueError, AttributeError) — if not, the step crashes instead of falling back.
| ) | ||
|
|
||
| with credential_context(message.credential_id): | ||
| try: |
There was a problem hiding this comment.
🟠 Important — this ~10-line auth-resolution block is copy-pasted into three files.
The identical block appears here, in cve_generate_vdbs.py, and in cve_segmentation.py. Extract a single helper (e.g. resolve_http_auth_header(builder) -> str | None in cve_http_output.py) so the fallback policy lives in one place — and can be unit-tested once rather than three times (see the coverage note on the credential client).
| try: | ||
| http_output_config = builder.get_function_config(HTTP_OUTPUT_AGENT_CONFIG) | ||
| auth_header = get_auth_header(http_output_config) | ||
| except (KeyError, ValueError, AttributeError) as e: |
There was a problem hiding this comment.
🟠 Important — this except is too broad, mislabels the cause, and logs too quietly.
- Catching
AttributeErrorswallows genuine programming bugs (attr typo, config-shape refactor, a bug inget_auth_header) and silently downgrades to SA-token auth. - The
exceptwraps bothget_function_configandget_auth_header; the latter already handles its own errors and returnsNone, so if it ever raises, the log "HTTP output config unavailable" is false (the config was available). - Switching from an operator-configured Cognito/Keycloak identity to the SA token is a trust-boundary downgrade, but it's logged at INFO — routinely filtered in prod, so the degradation is invisible.
Fix: wrap only builder.get_function_config in a narrow except KeyError; call get_auth_header outside the try (it returns None on all internal failures); and log at WARNING/ERROR when a configured auth_type yields a None header.
| return None | ||
|
|
||
|
|
||
| def _fetch_cognito_token(http_config: CVEHttpOutputConfig) -> str | None: |
There was a problem hiding this comment.
🟠 Important — redundant token fetch per pipeline node + mid-operation expiry risk.
With auth_type: cognito, each of the three nodes (clone_and_deps, generate_vdbs, segmentation) independently calls this → a fresh requests.post (30s timeout) to /oauth2/token on every scan, and the token is discarded after that node's credential fetch. That's 3+ token round-trips per scan.
Also: the header is resolved once at the start of a minutes-long _arun and held in the ContextVar for the whole operation — a Cognito token (typical expires_in 3600s) can expire mid-operation with no refresh (observable via 401, but fragile).
Consider: caching the token respecting expires_in, or resolving it once per scan and threading it through.
Address review feedback from tmihalac: 1. Extract resolve_http_auth_header() helper to eliminate code duplication across three pipeline stages (clone_and_deps, generate_vdbs, segmentation) 2. Narrow exception handling to KeyError only (not ValueError/AttributeError) to avoid swallowing programming bugs 3. Separate get_function_config error handling from get_auth_header call to ensure accurate error messages 4. Add warning when configured auth type fails to produce token (e.g. Cognito failure), distinguishing it from intentionally disabled auth 5. Use logger.warning (not info) for auth downgrade from configured identity to SA token - this is a trust-boundary change that needs visibility Addresses review comments: - Important: Code duplication (discussion_r4024823753) - Important: Exception too broad and logs too quietly (discussion_r4024823757)
Address review feedback (discussion_r4024823747): Tests for http_auth_header_context manager: - Uses context header when set (SA token not called) - Falls back to SA token when context is None - ContextVar resets properly after context exit (concurrency-safe) - Nested contexts use innermost value and restore correctly - Supports both Bearer and Basic auth header formats Tests for resolve_http_auth_header helper: - Returns None when config missing (KeyError handled) - Returns None when auth disabled (no warnings) - Returns Bearer token on Cognito success - Logs WARNING when configured auth fails (not INFO) - Handles basic/keycloak auth types Coverage: - http_auth_header_context: 6 tests (context behavior, reset, nesting) - resolve_http_auth_header: 9 tests (config missing, auth types, warnings) Addresses: Critical review item about untested integration
Replace silent None returns in get_auth_header() with AuthHeaderError exceptions to prevent configured auth failures from silently downgrading to unauthenticated requests. Callers (output_to_http, resolve_http_auth_header) catch the exception and handle appropriately: abort sending or fall back to SA token with a warning. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Auth failure in the delivery stage should fail the pipeline visibly, not silently return the message as if delivery succeeded. Pipeline stages (clone, vdb, segmentation) still catch and fall back to SA token via resolve_http_auth_header — that graceful degradation is correct for credential fetching, but not for the final report delivery. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Token caching is out of scope for this PR. Created a follow-up ticket to address both the redundant token fetches and the mid-operation expiry risk TC-6316 |
|
/test vulnerability-analysis-on-pr |
|
The HTTP request is still inside try/except Exception, logs the error, then the else is skipped and _arun() still returns message regardless. |
Re-raise after logging in the outer except block so the pipeline sees the failure instead of silently returning message as success. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
/test vulnerability-analysis-on-pr |
No description provided.