Skip to content

fix(dev-ui): guard extraction session load on tenant readiness#788

Merged
aredenba-rh merged 1 commit into
mainfrom
fix/graph-management-tenant-header-race
Jul 6, 2026
Merged

fix(dev-ui): guard extraction session load on tenant readiness#788
aredenba-rh merged 1 commit into
mainfrom
fix/graph-management-tenant-header-race

Conversation

@aredenba-rh

Copy link
Copy Markdown
Collaborator

Problem

On a hard refresh of /knowledge-graphs/{id}/manage?step=graph-management,
the Graph Management Assistant fails to load with:

Failed to load extraction conversation
X-Tenant-ID header is required

Root cause

loadExtractionSession() in manage.vue was the only data loader on this
page missing the hasTenant.value guard that every sibling loader already
has (loadKgIdentity, loadWorkspaceStatus, loadOverviewMetrics,
loadArchivedWriteCount, loadGraphManagementDataSources,
refreshDesignArtifacts).

The page has an immediate: true watcher on activeStep that calls
loadExtractionSession() synchronously on mount. On a hard refresh, all
Nuxt useState resets, so this fires before the default layout's async
fetchTenants() has resolved and populated currentTenantId. The request
goes out with no X-Tenant-ID header, and the API correctly rejects it
with 400 — surfaced to the user as a generic error toast.

On a normal client-side navigation (not a hard refresh) this race doesn't
manifest, since tenant state is already warm in memory — matching what was
observed.

Fix

Add the missing !hasTenant.value guard, matching the established
convention for every other loader on this page. The existing
tenantVersion watcher already re-triggers the extraction session load
once the tenant resolves (via the loadWorkspaceStatus
statusProjection.workspace_mode watch chain), so no additional retry
logic is needed.

Testing

Added graph-management-session-tenant-guard.test.ts (structural
source-reading test, matching this page's existing test conventions):

  • Fails against the old code (confirmed locally before the fix)
  • Passes after adding the guard
  • Documents the hasTenant.value convention across the page's other loaders as a regression baseline

Test plan

  • New unit test fails before the fix, passes after
  • Full dev-ui unit test suite run — no new failures (pre-existing unrelated failures in 9 other files, confirmed present on main before this change too)

Made with Cursor

loadExtractionSession() was the only data loader on the graph
management page missing the hasTenant.value guard that every sibling
loader (loadKgIdentity, loadWorkspaceStatus, loadOverviewMetrics,
loadArchivedWriteCount, loadGraphManagementDataSources,
refreshDesignArtifacts) already has. On a hard refresh of
/knowledge-graphs/{id}/manage?step=graph-management, the page's
immediate watcher on activeStep fires loadExtractionSession()
synchronously on mount, racing ahead of the default layout's async
tenant fetch — so the request went out with no X-Tenant-ID header and
the API correctly rejected it with 400, surfaced to the user as
"Failed to load extraction conversation". The existing tenantVersion
watcher already retriggers the load once the tenant resolves (via the
loadWorkspaceStatus -> statusProjection.workspace_mode chain), so
adding the guard is sufficient to fix the race.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: e97ed9f6-b940-429b-b8f7-eea2d231a65b

📥 Commits

Reviewing files that changed from the base of the PR and between 102fd40 and 0a946c8.

📒 Files selected for processing (2)
  • src/dev-ui/app/pages/knowledge-graphs/[kgId]/manage.vue
  • src/dev-ui/app/tests/graph-management-session-tenant-guard.test.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Prevented an extra data load on hard refresh by waiting for tenant context before loading the graph management session.
    • Reduced the chance of unauthenticated or premature requests when opening the knowledge graph management page.
  • Tests
    • Added coverage to verify tenant-context checks are applied consistently in page-loading behavior.

Walkthrough

CWE-862 (Missing Authorization) mitigation: loadExtractionSession() in manage.vue now requires hasTenant.value truthy alongside existing kgId.value and activeStep checks before executing, blocking premature unauthenticated API calls on hard refresh. A companion Vitest test performs static string inspection of the built source to assert the guard exists in the correct early-return line and audits other loader functions for the same convention. No exported/public API signatures changed.

Estimated code review effort: 2 (Simple) | ~10 minutes

Changes

Area Change
manage.vue Added !hasTenant.value to loadExtractionSession() early-return guard
graph-management-session-tenant-guard.test.ts New test asserting guard presence and cross-loader convention consistency

Related issues: None referenced in provided diff/summary.

Related PRs: None referenced in provided diff/summary.

Suggested labels: security, authorization-fix, tenant-isolation

Suggested reviewers: Assign someone with authority over tenant-context lifecycle in the Vue frontend and someone who owns test conventions for this repo.

Notes:

  • Test is a static string/regex inspection of source text, not a behavioral/unit test of actual reactive state (hasTenant, kgId, activeStep are not mocked or exercised) — this validates code pattern presence, not runtime enforcement. If loadExtractionSession() is refactored (e.g., renamed variable, reordered guard clause), the test could false-pass or false-fail without catching real regressions.
  • No CVE/CWE-mapped fix confirmation beyond CWE-862 pattern; verify server-side enforcement exists too — a client-side guard alone does not prevent a forged/replayed request bypassing the UI (defense-in-depth requirement, not satisfied by this diff alone).
  • Scope confined to Go-irrelevant frontend (Vue/TS); no API/Sentinel/Adapter/Broker Go code touched — outside primary security perimeter of this platform, but frontend tenant leakage still a valid attack surface if it triggers backend calls before tenant scoping resolves.
🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed Matches the change: adding a tenant-readiness guard before extraction-session load (CWE-862).
Description check ✅ Passed Describes the same tenant-header race and fix on hard refresh (CWE-862).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sec-02: Secrets In Log Output ✅ Passed No logger/print calls in PR files or source log statements contained token/password/credential/secret; CWE-532 not triggered.
No Hardcoded Secrets ✅ Passed PASS: The only new code is a tenant guard and a source-reading test; no hardcoded credentials, secret literals, embedded creds, or long base64 strings found (CWE-798/CWE-259).
No Weak Cryptography ✅ Passed PASS: Touched files only add a tenant guard and source-reading test; no MD5/DES/RC4/SHA1-for-security, ECB, custom crypto, or secret comparison code (CWE-327/CWE-208).
No Injection Vectors ✅ Passed No CWE-89/78/79/502 injection pattern appears in the modified code; the only logic change is a tenant guard, and the new file is a test.
No Privileged Containers ✅ Passed Only Vue/test files changed; no Kubernetes/OpenShift manifests, Helm templates, or Dockerfiles, and no privileged flags in the touched files.
No Pii Or Sensitive Data In Logs ✅ Passed PASS: No slog/logr/zap/fmt.Print/console logging was added in the touched files; the diff only adds a tenant guard and a structural test. CWE-532 not implicated.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/graph-management-tenant-header-race
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/graph-management-tenant-header-race

Comment @coderabbitai help to get the list of available commands.

@aredenba-rh aredenba-rh merged commit 69fa29d into main Jul 6, 2026
10 checks passed
@aredenba-rh aredenba-rh deleted the fix/graph-management-tenant-header-race branch July 6, 2026 22:07
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.

1 participant