Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5928f1d
feat(compat): centralize legacy server capabilities
imbajin Aug 15, 2026
97891c1
feat(hubble-auth): centralize anonymous mode boundary
imbajin Aug 15, 2026
f77d730
refactor(client): use centralized server capabilities
imbajin Aug 15, 2026
a8305e9
feat(hubble): unify auth and permission modes
imbajin Aug 15, 2026
77bbbaa
fix(hubble): harden compatibility presets
imbajin Aug 16, 2026
f770c5b
fix(hubble): preserve member manager access
imbajin Aug 16, 2026
d579541
fix(hubble): align ci and compatibility checks
imbajin Aug 16, 2026
fc4db04
chore: reflow pr-added lines to 120
imbajin Aug 16, 2026
bbc3fe5
chore(format): merge long wrapped lines
imbajin Aug 16, 2026
2f01b03
fix(hubble): refine account and node surfaces
imbajin Aug 16, 2026
f31977a
chore(hubble): add frontend development proxy
imbajin Aug 16, 2026
664f1ba
fix(hubble): restore operations and account UX
imbajin Aug 16, 2026
6ca7cb6
fix(hubble): propagate deployment auth mode
imbajin Aug 16, 2026
b0a1fa9
fix(hubble): stabilize operations discovery
imbajin Aug 17, 2026
0fd3596
fix(hubble): preserve account permission semantics
imbajin Aug 17, 2026
d369224
fix(hubble): enforce permission boundaries
imbajin Aug 17, 2026
95351af
fix(hubble): align non-PD operations entry
imbajin Aug 17, 2026
92d01bb
fix(hubble): preserve legacy analyst access
imbajin Aug 17, 2026
2be170c
fix(hubble): preserve admin preset selection
imbajin Aug 17, 2026
2cdc5f6
fix(hubble): explain standalone overview
imbajin Aug 17, 2026
bf52253
fix(hubble): clarify account permissions
imbajin Aug 17, 2026
e97c0af
fix(hubble): restore scoped graph access
imbajin Aug 17, 2026
e5669cf
fix(hubble): enforce permission preset boundaries
imbajin Aug 17, 2026
1668bcf
fix(hubble): align graph write controls
imbajin Aug 17, 2026
e2b12b8
fix(hubble): clarify read-only template state
imbajin Aug 17, 2026
cc346cb
fix(hubble): keep graph list requests unscoped
imbajin Aug 17, 2026
480a570
fix(ci): upload coverage to current repository
imbajin Aug 17, 2026
2111378
test(hubble): cover permission update paths
imbajin Aug 18, 2026
4a13835
fix(hubble): hide unavailable member capability
imbajin Aug 18, 2026
49573c6
fix(hubble): restore graphspace preset state
imbajin Aug 18, 2026
431de79
fix(hubble): normalize PD cluster states
imbajin Aug 18, 2026
981a8ae
refactor(style): set line width to 120
imbajin Aug 18, 2026
45eaa82
fix(hubble): enforce template ownership
imbajin Aug 18, 2026
2d07ea4
fix(hubble): paginate GraphSpace enrichment
imbajin Aug 18, 2026
1a45c63
fix(hubble): satisfy pagination lint
imbajin Aug 18, 2026
fa62c7a
fix(hubble): reset stale account context
imbajin Aug 18, 2026
7d1ffd3
fix(hubble): harden account boundaries
imbajin Aug 18, 2026
257dd48
fix(hubble): normalize missing graphspaces
imbajin Aug 18, 2026
bc3dd75
fix(hubble): require scoped graphspaces
imbajin Aug 18, 2026
3d5eedd
fix(hubble): support legacy auth profiles
imbajin Aug 18, 2026
9119970
fix(hubble): harden auth boundary handling
imbajin Aug 18, 2026
2eba150
fix(hubble): rollback permission updates
imbajin Aug 18, 2026
b5471dc
fix(hubble): separate account identities
imbajin Aug 18, 2026
a3b5cd8
refactor(hubble): align code with 120 columns
imbajin Aug 18, 2026
cc3bddf
fix(hubble): hide backend URL from bootstrap
imbajin Aug 18, 2026
72adfde
fix(hubble): explain unavailable legacy metrics
imbajin Aug 18, 2026
0368295
docs(hubble): add non-auth PR screenshots
imbajin Aug 18, 2026
b46f15d
fix(hubble): enforce GraphSpace visibility
imbajin Aug 18, 2026
f7166cf
fix(hubble): guard scoped requests
imbajin Aug 18, 2026
fb41744
fix(hubble): secure indirect GraphSpace scopes
imbajin Aug 18, 2026
e1234fa
fix(hubble): scope local query records
imbajin Aug 18, 2026
eec5800
fix(hubble): enforce scoped write boundaries
imbajin Aug 18, 2026
fd1a939
fix(hubble): separate account security updates
imbajin Aug 18, 2026
8fac0e8
fix(hubble): reject legacy permission writes
imbajin Aug 18, 2026
02cbe0e
fix(hubble): clear inaccessible graph context
imbajin Aug 18, 2026
0c940ad
fix(hubble): hide empty operations menu
imbajin Aug 18, 2026
30ac490
fix(hubble): support legacy gremlin auth
imbajin Aug 18, 2026
83c2147
fix(hubble): scope legacy gremlin auth
imbajin Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ root = true
charset = utf-8
end_of_line = lf
insert_final_newline = true
max_line_length = 100
max_line_length = 120
ij_wrap_on_typing = true
ij_visual_guides = 100
ij_visual_guides = 120


[*.{java,xml,py}]
Expand Down
1 change: 1 addition & 0 deletions .github/actions/upload-coverage/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ runs:
uses: codecov/codecov-action@v7
with:
token: ${{ inputs.token }}
slug: ${{ github.repository }}
files: ${{ inputs.file }}
2 changes: 1 addition & 1 deletion .github/workflows/client-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,4 @@ jobs:
uses: ./.github/actions/upload-coverage
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: target/jacoco.xml
file: hugegraph-client/target/jacoco.xml
17 changes: 14 additions & 3 deletions .github/workflows/hubble-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ on:

env:
TRAVIS_DIR: hugegraph-hubble/hubble-dist/assembly/travis
HUGEGRAPH_SERVER_COMMIT: 99936be5f41fccd193f120e01206e3cf3c73a050
HUGEGRAPH_SERVER_FETCH_REF: refs/heads/master
# Server PR #3159 declares the GraphSpace default-role contract as API 0.72.
HUGEGRAPH_SERVER_COMMIT: 52035dad9ee8d6b666329ca0d03950c773d3e1eb
HUGEGRAPH_SERVER_FETCH_REF: refs/pull/3159/head

jobs:
hubble-ci:
Expand Down Expand Up @@ -138,6 +139,16 @@ jobs:
cd ../../../
pwd
$TRAVIS_DIR/install-hugegraph.sh $COMMIT_ID $COMMIT_REF
API_VERSION="$(curl --fail --silent http://127.0.0.1:8080/versions |
python -c 'import json,sys; print(json.load(sys.stdin)["versions"]["api"])')"
python - "$API_VERSION" <<'PY'
import sys
parts = tuple(int(value) for value in sys.argv[1].split(".")[:2])
if parts < (0, 72):
raise SystemExit(
f"Expected HugeGraph REST API >= 0.72, got {sys.argv[1]}"
)
PY

- name: Release package audit
env:
Expand Down Expand Up @@ -197,4 +208,4 @@ jobs:
uses: ./.github/actions/upload-coverage
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: target/site/jacoco/*.xml
file: hugegraph-hubble/hubble-be/target/jacoco.xml
2 changes: 1 addition & 1 deletion .github/workflows/loader-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,4 @@ jobs:
uses: ./.github/actions/upload-coverage
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: target/jacoco.xml
file: hugegraph-loader/target/jacoco.xml
6 changes: 0 additions & 6 deletions .github/workflows/tools-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,3 @@ jobs:
- name: Run test
run: |
mvn test -Dtest=FuncTestSuite -pl hugegraph-tools -ntp

- name: Upload coverage to Codecov
uses: ./.github/actions/upload-coverage
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: target/jacoco.xml
2 changes: 1 addition & 1 deletion .serena/memories/README_INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ git --no-pager diff HEAD~1
4. ❌ **DON'T** use `System.out.println` (use logger instead)
5. ❌ **DON'T** forget Apache 2.0 license headers
6. ❌ **DON'T** use tabs (use 4 spaces for Java, 2 for frontend)
7. ❌ **DON'T** exceed 100 character line length
7. ❌ **DON'T** exceed 120 character line length
8. ❌ **DON'T** commit code that fails CI checks

## Getting Help
Expand Down
2 changes: 1 addition & 1 deletion .serena/memories/code_style_and_conventions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
### Basic Formatting
- **Indentation**: 4 spaces (NO TABS)
- **Continuation Indent**: 8 spaces
- **Line Length**: Maximum 100 characters
- **Line Length**: Maximum 120 characters
- **Line Wrapping**: Enabled for long lines
- **Blank Lines**:
- Keep max 1 blank line in declarations
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ mvn test -Dtest=FuncTestSuite -pl hugegraph-tools -ntp
## Code Style

Checkstyle enforced via `tools/checkstyle.xml`:
- Max line length: 100 characters
- Max line length: 120 characters
- 4-space indentation (no tabs)
- No star imports
- No `System.out.println`
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@

A comprehensive suite of client SDKs, data tools, and management utilities for [Apache HugeGraph](https://github.com/apache/hugegraph) graph database. Build applications, load data, and manage graphs with production-ready tools.

Hubble's primary authentication and connection design targets HugeGraph
`1.8/master`: PD discovery supplies the server address, anonymous mode uses a
real unauthenticated client, and account/GraphSpace permissions are reduced to
four readable presets. A thin adapter keeps 1.7 usable and limits 1.5 to its
standalone core graph workflow; version checks are centralized rather than
spread across UI pages.

**Quick Navigation**: [Architecture](#architecture-overview) | [Quick Start](#quick-start) | [Modules](#module-overview) | [Build](#build--development) | [Docker](#docker) | [Related Projects](#related-projects)

## Related Projects
Expand Down Expand Up @@ -57,7 +64,7 @@ graph TB
CLIENT --> HUBBLE
CLIENT --> TOOLS
CLIENT --> SPARK
HUBBLE -.->|WIP: pd-client| PD
HUBBLE -.->|PD discovery UI| PD

LOADER -.->|Sources| SRC["CSV | JSON | HDFS<br/>MySQL | Kafka"]
SPARK -.->|I/O| SPK["Spark DataFrames"]
Expand Down Expand Up @@ -381,7 +388,7 @@ mvn clean install -DskipTests -Dmaven.javadoc.skip=true -ntp
### Code Style

Checkstyle is enforced via `tools/checkstyle.xml`:
- Max line length: 100 characters
- Max line length: 120 characters
- 4-space indentation (no tabs)
- No star imports
- No `System.out.println`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,11 @@ public boolean isSpaceAdmin(String graphSpace) {
.checkPermission(HugePermission.SPACE, graphSpace);
}

public boolean isSpaceMember(String graphSpace) {
return this.managerAPI(graphSpace)
.checkPermission(HugePermission.SPACE_MEMBER, graphSpace);
}

public boolean checkDefaultRole(String graphSpace, String role) {
return this.managerAPI(graphSpace)
.checkDefaultRole(graphSpace, role, "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@
import lombok.Getter;

import org.apache.hugegraph.client.RestClient;
import org.apache.hugegraph.exception.ServerException;
import org.apache.hugegraph.rest.ClientException;
import org.apache.hugegraph.rest.RestClientConfig;
import org.apache.hugegraph.structure.auth.TokenPayload;
import org.apache.hugegraph.structure.auth.User;
import org.apache.hugegraph.util.E;
import org.apache.hugegraph.util.VersionUtil;
import org.apache.hugegraph.version.ClientVersion;
import org.slf4j.Logger;
Expand Down Expand Up @@ -57,6 +61,8 @@ public class HugeClient implements Closeable {
*/
private volatile boolean apiVersionChecked;
private final Object apiVersionLock = new Object();
private ServerCompatibility.Profile compatibility =
ServerCompatibility.Profile.LEGACY;
private VersionManager version;
private GraphsManager graphs;
private SchemaManager schema;
Expand Down Expand Up @@ -209,8 +215,9 @@ private void checkServerApiVersion() {
// 0.81 equals to the {latest_api_version} +10
VersionUtil.check(apiVersion, "0.38", "0.81", "hugegraph-api in server");
this.client.apiVersion(apiVersion);
boolean supportGs = VersionUtil.gte(this.version.getCoreVersion(), "1.7.0");
this.client.setSupportGs(supportGs);
this.compatibility = ServerCompatibility.profile(
this.version.getCoreVersion(), apiVersion.get());
this.client.setSupportGs(this.compatibility.supportsGraphSpace());
}

public GraphsManager graphs() {
Expand Down Expand Up @@ -257,6 +264,50 @@ public AuthManager auth() {
return this.auth;
}

public boolean supportsDefaultRole() {
return this.compatibility.supportsDefaultRole();
}

public boolean supportsPersonalProfileUpdate() {
return this.compatibility.supportsPersonalProfileUpdate();
}

public User findUserByName(String name) {
if (this.supportsDefaultRole()) {
return this.auth.getUserByName(name);
}
return this.auth.listUsers().stream()
.filter(user -> name.equals(user.name()))
.findFirst()
.orElse(null);
}

public User findCurrentUser(String expectedUsername) {
TokenPayload payload = this.auth.verifyToken();
E.checkState(payload != null &&
!Strings.isNullOrEmpty(payload.userId()) &&
!Strings.isNullOrEmpty(payload.username()),
"Invalid current-user identity");
E.checkState(payload.username().equals(expectedUsername),
"Authenticated user does not match the expected user");

User user;
try {
user = this.auth.getUser(payload.userId());
} catch (ServerException e) {
if (e.status() != 403 ||
this.supportsPersonalProfileUpdate()) {
throw e;
}
user = new User();
user.setId(payload.userId());
user.name(payload.username());
}
E.checkState(user != null && expectedUsername.equals(user.name()),
"Current-user record does not match the token identity");
return user;
}

public MetricsManager metrics() {
return this.metrics;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hugegraph.driver;

import org.apache.hugegraph.util.VersionUtil;

/**
* Small compatibility boundary shared by Hubble and clients.
*
* <p>Version checks belong here so callers can express capabilities instead
* of branching on server versions in controllers or pages. Unknown versions
* deliberately use the conservative legacy profile.</p>
*/
public final class ServerCompatibility {

private static final String GRAPHSPACE_MIN_VERSION = "1.7.0";
private static final String DEFAULT_ROLE_MIN_API_VERSION = "0.72";

private ServerCompatibility() {
}

public static Profile profile(String coreVersion) {
return profile(coreVersion, null);
}

public static Profile profile(String coreVersion, String apiVersion) {
if (supportsDefaultRoleApi(apiVersion)) {
return Profile.MODERN;
}
if (coreVersion == null || coreVersion.trim().isEmpty()) {
return Profile.LEGACY;
}
try {
String normalized = coreVersion.trim();
return VersionUtil.gte(normalized, GRAPHSPACE_MIN_VERSION) ? Profile.GRAPHSPACE : Profile.LEGACY;
} catch (RuntimeException ignored) {
return Profile.LEGACY;
}
}

private static boolean supportsDefaultRoleApi(String apiVersion) {
if (apiVersion == null || apiVersion.trim().isEmpty()) {
return false;
}
try {
return VersionUtil.gte(apiVersion.trim(),
DEFAULT_ROLE_MIN_API_VERSION);
} catch (RuntimeException ignored) {
return false;
}
}

public static boolean supportsGraphSpace(String coreVersion) {
return profile(coreVersion).supportsGraphSpace();
}

public static boolean supportsDefaultRole(String coreVersion,
String apiVersion) {
return profile(coreVersion, apiVersion).supportsDefaultRole();
}

public static boolean supportsPersonalProfileUpdate(
String coreVersion, String apiVersion) {
return profile(coreVersion, apiVersion)
.supportsPersonalProfileUpdate();
}

public enum Profile {
LEGACY(false, false, false),
GRAPHSPACE(true, false, false),
MODERN(true, true, true);

private final boolean graphSpace;
private final boolean defaultRole;
private final boolean personalProfileUpdate;

Profile(boolean graphSpace, boolean defaultRole,
boolean personalProfileUpdate) {
this.graphSpace = graphSpace;
this.defaultRole = defaultRole;
this.personalProfileUpdate = personalProfileUpdate;
}

public boolean supportsGraphSpace() {
return this.graphSpace;
}

public boolean supportsDefaultRole() {
return this.defaultRole;
}

public boolean supportsPersonalProfileUpdate() {
return this.personalProfileUpdate;
}
}
}
Loading
Loading