Skip to content

fix(hugegraph-dist): gate init-store on a dedicated init_store.enabled option - #3119

Open
bitflicker64 wants to merge 20 commits into
apache:masterfrom
bitflicker64:fix/no-init
Open

fix(hugegraph-dist): gate init-store on a dedicated init_store.enabled option#3119
bitflicker64 wants to merge 20 commits into
apache:masterfrom
bitflicker64:fix/no-init

Conversation

@bitflicker64

@bitflicker64 bitflicker64 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Fixes #3118

Kept in sync with hugegraph#171

Rescoped. This PR previously carried a second, unrelated change: a
ConfigTool CLI, a rewrite of the entrypoint's auth bootstrap, and a
1,022-line shell test suite for it. That made a ~2,900-line diff covering two
ideas at once. It has been split out to #3133 and follows as its own PR.

Problem

InitStore always performs local initialization: it scans conf/graphs,
initializes non-HStore backends, and bootstraps the built-in admin account.
That is correct for standalone and tarball deployments, but a PD/HStore
deployment already owns its metadata, and its Kubernetes pods cannot rely on
the container-local docker/init_complete flag surviving a restart.

Solution

A dedicated init_store.enabled option, defaulting to true, so existing
standalone and tarball configurations keep the current path unchanged.
Distributed deployments set it to false — or HG_SERVER_INIT_STORE_ENABLED=false
in the server container — to skip backend and plugin registration, the graph
initialization scan, and local admin initialization.

#3118 proposed reusing graph.load_from_local_config. A dedicated option was
used instead: that flag governs whether GraphManager loads graphs from
./conf/graphs, which is a different question from whether init-store should
run, and overloading it would have coupled two unrelated decisions.


Scope

In scope

Area Change
ServerOptions New init_store.enabled, Boolean, default true
InitStore Gate before backend/plugin registration; fail-closed check on the disabled path; writes the completion marker when it initializes, and consults it only after the gate
GraphManager initAdminUserIfNeeded propagates every failure except already-exists, judged by re-reading the user
bin/init-store.sh Propagates InitStore's exit status
docker-entrypoint.sh Maps HG_SERVER_INIT_STORE_ENABLED onto the property, validates it, hands the marker path to Java, and runs init-store on every startup
docker/README.md Documents the variable, the auth requirements, and the marker behaviour
Tests InitStoreConfigTest, 15 cases; GraphManagerAdminInitTest, 3 cases

Behaviour, by deployment shape

Shape Before After
Tarball / standalone, option unset Full init Unchanged
Tarball, option explicitly true Full init Full init
Docker, no auth, disabled Full init Skips; no marker written
Docker, built-in auth, disabled, usePD=true + HStore auth graph + explicit auth.admin_pa Full init Skips; server creates the admin from auth.admin_pa on the PD path
Docker, built-in auth, disabled, any of those missing Full init Fails closed
Remote auth or custom authenticator, disabled Full init Skips; exempt, they own their identities

Deliberately out of scope

  • Entrypoint auth bootstrap and ConfigTool — split to [Bug] Docker entrypoint auth bootstrap is unsafe for mounted and upgraded configs #3133. Seven review
    threads on this PR target that code and are answered there.
  • Reading the effective property back in the entrypoint. A shell reader
    cannot implement the Java-properties grammar HugeConfig uses. Solved here
    by having init-store own the marker instead; a general config-reading CLI
    belongs to [Bug] Docker entrypoint auth bootstrap is unsafe for mounted and upgraded configs #3133.
  • Signalling "skipped" through a distinct exit code.
    run-native-runtime-smoke-test.sh, start-server.sh and
    test-start-hugegraph.sh all treat any non-zero status from
    bin/init-store.sh as fatal.
  • Rotating an existing admin password. auth.admin_pa applies only when
    the account is first created.
  • graph.load_from_local_config, GraphManager behaviour, Helm job structure,
    shipped Compose usePD defaults.

Downstream

#3132 (Helm chart) injects HG_SERVER_INIT_STORE_ENABLED=false and must land
after this PR. It also has to write auth.admin_pa, which it does not today —
commented there.


Fail-closed check

With the gate off and the built-in authenticator selected, the admin is created
on the PD startup path by GraphManager.initAdminUserIfNeeded(conf.get(ADMIN_PA)).
Creation failures there now abort startup; only the already-exists case is
ignored, judged by re-reading the user.
Only an HStore auth graph reads that account back, and ADMIN_PA defaults to
the public value pa. Docker PASSWORD never reaches this path — init-store
reads it from stdin and the disabled path returns first.

So the disabled path refuses unless usePD=true, the auth graph uses HStore,
and auth.admin_pa is explicitly set and non-empty. Remote auth and custom
authenticators are exempt. Refusing is what keeps a deployment from coming up
with a publicly known administrator credential.

bin/init-store.sh propagates the exit status for this to mean anything: its
trailing echo "Initialization finished." previously made the script exit 0
regardless, so a refusal was swallowed and the entrypoint started the server
anyway.

Completion marker

init-store writes docker/init_complete itself, and only after it has
initialized. The entrypoint supplies the path and no longer decides. Deciding
in shell meant reading the environment variable, which says nothing about a
config mounted with init_store.enabled=false already set — that was recorded
as initialized, and setting it back to true later skipped initialization
permanently. Nothing is written when no caller supplies a path, so the tarball
path is unaffected. init-store also reads the marker — after the disabled
gate — so an existing one skips re-initialization but never the fail-closed
check, and the entrypoint runs init-store on every startup to make that hold.

Validation

JDK 11:

  • Full unit suite: Tests run: 610, Failures: 0, Errors: 0, Skipped: 1 (the
    skip is pre-existing). Checkstyle clean in all modules.
  • bash -n on both changed scripts.
  • Exit-status propagation checked through echo "$PASSWORD" | ./bin/init-store.sh
    under set -euo pipefail.
  • Env-var validation exercised across false/FALSE/" false"/No/OFF/true/t/YES,
    unset, and the rejected 0/1/disabled. The accepted set is exactly what
    commons-lang 2.x BooleanUtils takes, reached through commons-configuration
    1.x PropertyConverter — note that is not commons-lang3, which would also
    accept 0 and 1.

Not covered: a successful enabled run writing the marker needs a live backend.
No end-to-end container build was run — entrypoint changes are verified by
extracted-script simulation and code reading. shellcheck was not available.

…g is false

Honor the existing ServerOptions flag in InitStore so distributed/HStore
can opt out of local backend and admin init. Unset keeps full init for
standalone. Docker maps HG_SERVER_LOAD_FROM_LOCAL_CONFIG to
rest-server.properties.

Fixes apache#3118
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. tests Add or improve test cases labels Jul 26, 2026

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: Disabling local graph loading also bypasses the Docker password-based admin bootstrap, so the requested credential is never installed. Evidence: exact-head static trace through docker-entrypoint.sh, InitStore.java, and GraphManager.java; 3/3 focused tests passed; visible checks are green.

…d option

Replace the graph.load_from_local_config gate with a dedicated
init_store.enabled option defaulting to true. That property already means
whether GraphManager loads graph definitions from the local directory, and
existing configs may materialize its declared false default, so reusing it
made an explicit false skip backend and admin initialization for standalone
RocksDB/HBase installs.

The early return also skipped StandardAuthenticator.initAdminUserIfNeeded,
so a Docker PASSWORD was piped into init-store.sh and discarded without
creating the admin, leaving the server on the auth.admin_pa default. In skip
mode the entrypoint now writes PASSWORD to auth.admin_pa instead, and does
not create docker/init_complete since nothing was initialized. The gate is
read back from rest-server.properties so a config mounted without the env
var behaves the same way.

Cover the lifecycle with a main-level test whose graphs directory would fail
if the early exit were missed, and entrypoint smoke tests for default init,
PASSWORD, skip, skip with PASSWORD, mounted property, and false to true
restart. Run those in Docker CI and extend its path filter to the dist
docker directory.
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jul 26, 2026
@bitflicker64 bitflicker64 changed the title fix(hugegraph-dist): skip init-store when graph.load_from_local_config is false fix(hugegraph-dist): gate init-store on a dedicated init_store.enabled option Jul 26, 2026
@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 76 lines in your changes missing coverage. Please review.
✅ Project coverage is 1.70%. Comparing base (f8e7abf) to head (edf07d0).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
.../main/java/org/apache/hugegraph/cmd/InitStore.java 0.00% 61 Missing ⚠️
...n/java/org/apache/hugegraph/core/GraphManager.java 0.00% 12 Missing ⚠️
...ava/org/apache/hugegraph/config/ServerOptions.java 0.00% 3 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (f8e7abf) and HEAD (edf07d0). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (f8e7abf) HEAD (edf07d0)
3 2
Additional details and impacted files
@@             Coverage Diff              @@
##             master   #3119       +/-   ##
============================================
- Coverage     39.13%   1.70%   -37.43%     
+ Complexity      264      56      -208     
============================================
  Files           770     748       -22     
  Lines         65772   63335     -2437     
  Branches       8725    8291      -434     
============================================
- Hits          25741    1081    -24660     
- Misses        37272   62162    +24890     
+ Partials       2759      92     -2667     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The skip path still fails admin bootstrap for the shipped HStore configuration and has inconsistent option/password handling; backend and plugin registration also occurs before the gate. Evidence: six independent review lanes, exact-head static traces, an uppercase FALSE regression test failing four assertions, and all visible latest-head checks passing.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
… is true

With init_store.enabled=false the built-in admin account is not created by
init-store, and the only other component that creates it is
GraphManager.initAdminUserIfNeeded(), reached from loadMetaFromPD() and so
gated on usePD. That option defaults to false and the shipped HStore compose
files do not set it, so enabling auth in skip mode would start a server that
enforces authentication with no account to authenticate against.

The entrypoint now refuses that combination and exits with an explanation,
and InitStore logs the same condition for non-Docker installs. Skipping
without auth is unaffected. usePD=true is already the documented pairing for
distributed deployments in the cluster-test rest-server.properties template.

Also align the shell with the server's boolean parsing, which is
case-insensitive, so HG_SERVER_INIT_STORE_ENABLED=FALSE no longer means skip
to Java and run to the entrypoint; read the property through the separators a
properties file allows; escape the password for properties serialization so a
backslash survives; and register backends and plugins only on the enabled
path, since plugin registration runs every plugin's register() and propagates
its failures.

Add entrypoint coverage for these plus a test that disabled mode leaves
backend options unregistered. Note a pre-existing arthas config key mismatch
found while checking the option table.
@bitflicker64

bitflicker64 commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Unrelated to this change, but noticed while checking the ServerOptions table, so I left a TODO on it rather than silently fixing it here.

The arthas options are declared camelCase (arthas.telnetPort, arthas.httpPort, arthas.disabledCommands) while conf/rest-server.properties ships them snake_case (arthas.telnet_port, arthas.http_port, arthas.disabled_commands). Nothing normalizes between the two, so those keys never match and config.get() returns the declared default. Only arthas.ip works.

It is invisible today because each shipped value equals its default. It bites on any change, e.g. arthas.disabled_commands=jad,exec is dropped and exec stays enabled.

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The mounted-properties override path can create duplicate scalar keys and make init-store or server startup fail. Evidence: six independent review lanes, exact-head static tracing through docker-entrypoint.sh and HugeConfig.java, and all visible latest-head checks passing.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
get_prop was widened to read the `=`, `:` and whitespace separators a
properties file allows, but set_prop still matched only `key=value`. A mounted
`init_store.enabled:false` overridden by HG_SERVER_INIT_STORE_ENABLED therefore
gained a second definition instead of being replaced, and a key defined twice
collects both values into a list that fails the scalar type check while the
config is still loading. Both init-store and server startup would fail. The
same applied to a colon-form auth.admin_pa overridden by PASSWORD.

set_prop now matches the same separators and collapses every existing
definition into one canonical `key=value` line, leaving comments alone. It is
written in awk, so the key and value are matched and emitted literally and no
regex escaping is involved.

Cover colon-form and whitespace-form overrides asserting a single remaining
definition, a colon-form auth.admin_pa override, and that commented defaults
are not treated as definitions. Add a test loading a duplicated key through
HugeConfig to pin why the collapse is required.
@bitflicker64
bitflicker64 requested a review from imbajin July 27, 2026 15:19

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The disabled init path can still report success for an unusable auth configuration, and two Docker config rewrite paths can fail or corrupt mounted/protected configs. Evidence: six independent exact-head review lanes; entrypoint smoke tests passed 57 assertions with 2 macOS-only skips; git diff --check passed; codecov/patch and codecov/project are failing.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/test/test-docker-entrypoint.sh Outdated
…onf in place

Four fixes to the skip path.

InitStore returned zero for a configuration it had just reported as unusable:
init_store.enabled=false with an authenticator set and usePD false means no
component creates the built-in admin. Tarball and init-job callers see only the
exit status, so they continued into an auth-enabled server nobody could reach.
It now fails. Remote auth is exempt, since the auth manager is then an RPC
client and StandardAuthenticator only bootstraps a local one; the entrypoint
guard gains the same exemption, which it was missing.

set_prop replaced the config by rename. A single-file bind mount cannot be
replaced that way, so startup aborted under set -e, and the rename also
discarded the original mode, which matters where auth.admin_pa is written. It
now truncates and rewrites in place, and creates its scratch file under umask
077.

On the skip path enable-auth.sh ran unconditionally, and it appends its keys
without checking, so a mounted config that already enabled auth ended up with
auth.authenticator and auth.graph_store defined twice, which the config parser
rejects. It now runs only when auth is not configured yet, and both keys are
collapsed to single definitions afterwards.

The test guard that skipped two cases without GNU sed was stale once set_prop
moved to awk. Removed, so those cases run everywhere.

Cover the exit status and the remote-auth exemption in the CLI test, and add
entrypoint cases for a mounted auth config, the remote-auth exemption, inode
and mode preservation, and scratch file cleanup.

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The skip path can leave Gremlin authentication incomplete and rejects supported custom authenticators. Evidence: six independent exact-head review lanes, static traces through enable-auth.sh and HugeAuthenticator.loadAuthenticator(), 74/74 entrypoint assertions passing, git diff --check passing, and all visible latest-head workflows passing.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jul 28, 2026
…n check

enable-auth.sh also adds the authentication block to gremlin-server.yaml and
switches hugegraph.properties to the auth proxy. Skipping it whenever
auth.authenticator already existed left both undone, so a mounted config that
set only that key could start with REST auth on and Gremlin open. Apply each of
the three changes only where it is missing instead, and point the Gremlin block
at whichever authenticator the REST config names.

The admin-account requirement now applies only to the built-in authenticator
and its subclasses. auth.authenticator takes any implementation class, and a
custom LDAP/OIDC/plugin one manages identities elsewhere, so requiring usePD
for it rejected a deployment that works.

get_prop no longer deletes whitespace inside a value, only around it, as the
properties parser does.
- get_prop uses `sed -E` rather than `-r`, which only GNU sed documents
- the appended gremlin-server.yaml block no longer glues itself onto a last
  line that has no trailing newline
- the option description, the InitStore comment and docker/README no longer
  claim every authenticator needs the built-in admin account, which stopped
  being true when the check was narrowed
- InitStoreConfigTest is imported in suite order in UnitTestSuite
- a test asserts the entrypoint's inlined auth block still names everything
  bin/enable-auth.sh does, so the two cannot drift unnoticed
@bitflicker64

Copy link
Copy Markdown
Contributor Author

Did a self-review pass over the whole diff and pushed 090763a with the follow-ups, no behaviour change beyond the two fixes below:

  • get_prop now uses sed -E rather than -r, which only GNU sed documents.
  • The gremlin-server.yaml block is no longer appended onto a last line that has no trailing newline.

The rest is text and hygiene: the option description, the InitStore comment and docker/README.md still said every auth.authenticator needs the built-in admin account, which stopped being true when the check was narrowed; InitStoreConfigTest is now imported in suite order.

Since the entrypoint reapplies what bin/enable-auth.sh does when it cannot run the script itself, there is now a test asserting the entrypoint still names every class and key that script does, so the two cannot drift silently. Happy to move that logic into enable-auth.sh instead if you would rather have one source of truth there, it just reaches outside the docker path.

Local run: 106 assertions across 30 entrypoint cases, unit suite 626 tests green on JDK 11, rat and editorconfig clean.

# Conflicts:
#	hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The skip path still has inconsistent admin-bootstrap decisions across Docker and Java, and several auth configurations can start unusable or incompletely protected. Evidence: six independent exact-head review lanes, static traces through docker-entrypoint.sh, InitStore, GraphManager, and StandardHugeGraph; 106/106 entrypoint assertions and the focused Java test passed; git diff --check passed; visible Actions passed but Codecov statuses failed.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread .github/workflows/docker-build-ci.yml Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/test/test-docker-entrypoint.sh Outdated
Comment thread PR_DESCRIPTION.md Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (1)

hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/auth/StandardAuthenticator.java:240

  • StandardAuthenticator.initAdminUserIfNeeded() only checks whether auth.authenticator is empty, but it doesn't verify that the configured authenticator is actually StandardAuthenticator (or a subclass). If this helper is invoked with a config that sets a custom/local authenticator, it can still open the auth graph and potentially create HugeGraph's built-in admin account even though that authenticator doesn't use it. Add a defensive check so the method no-ops unless auth.authenticator resolves to StandardAuthenticator (or subclass).
        HugeConfig config = new HugeConfig(confFile);
        String authClass = config.get(ServerOptions.AUTHENTICATOR);
        if (authClass.isEmpty()) {
            return;
        }
        config.addProperty(INITING_STORE, true);
        auth.initAdminUser(config, password, fromConfig);

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The current head still has upgrade and authentication-consistency regressions, plus configuration durability and deployment-hardening gaps. Evidence: six independent exact-head review lanes; static traces through docker-entrypoint.sh, ConfigTool, and init-store.sh; 217/217 entrypoint assertions passed; Actions passed while codecov/patch and codecov/project failed.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
Comment thread hugegraph-server/hugegraph-dist/docker/test/test-docker-entrypoint.sh Outdated
- migrate verified legacy auth volumes without old secrets
- fail closed on REST and Gremlin auth mismatches
- protect config rewrites and reject include flattening
- read administrator passwords from standard input
- verify read-only mounts in Docker CI

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The latest head still treats aligned authentication configuration as proof that a legacy administrator exists, so a no-auth volume later configured for authentication can skip bootstrap without a usable admin. Evidence: six independent exact-head lanes; test-docker-entrypoint.sh:419-428 creates only init_complete plus enable-auth.sh configuration and asserts init-store is not run; existing discussion_r3687911099 covers the blocker.

…asks for

The Docker auth bootstrap and the ConfigTool it depends on grew into a
second change sharing this branch, which made the diff hard to review as
one idea. They move to a follow-up, leaving the option, the gate, the env
mapping and the init-flag guard here.

Review fixes carried over:

- init-store.sh propagates InitStore's exit status. The trailing
  "Initialization finished." echo made the script exit 0 no matter what,
  so a refused configuration let the entrypoint start a server nobody
  could log in to.
- The entrypoint normalizes HG_SERVER_INIT_STORE_ENABLED and rejects
  values HugeConfig would refuse, instead of recording an initialization
  that never happened.
- The admin bootstrap check no longer requires auth.admin_pa, which
  nothing in the container writes. usePD and the hstore auth graph stay.
- PASSWORD is documented as having no effect once init-store is skipped,
  and the entrypoint warns when both are set.
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Aug 1, 2026
@bitflicker64

Copy link
Copy Markdown
Contributor Author

Rescoped this PR.

It had grown to ~2,900 lines doing two unrelated things: the init-store gate #3118 asked for, and a rewrite of the Docker auth bootstrap built on a new ConfigTool. Reviewing those as one diff was not reasonable, so the second half is now #3133 and follows as its own PR.

What is left here is 496 lines across 7 files — the option, the gate, the env mapping, and the init-flag guard.

Your 7 open threads are all on code that moved out. I have replied on each pointing at #3133 instead of resolving them, so they stay findable there.

Two things worth flagging from re-reading it:

  • bin/init-store.sh always exited 0, because of the trailing echo "Initialization finished.". So the fail-closed check this PR adds was never observable — the entrypoint started the server regardless. Fixed here, which is what makes the check mean anything.
  • PASSWORD does nothing when init-store is skipped. init-store reads it from stdin and the disabled path returns before that, so the admin is created from auth.admin_pa, whose default pa is public. Documented in docker/README.md and warned at runtime; the real fix needs [Bug] Docker entrypoint auth bootstrap is unsafe for mounted and upgraded configs #3133.

The admin-bootstrap check no longer requires auth.admin_pa — nothing in the container writes it, so that clause could never be satisfied and would have broken the distributed path once the exit status started propagating. usePD and the HStore auth-graph checks stay, which is what your original comment was about.

604 tests, 0 failures on JDK 11, checkstyle clean. Description updated to match. Not run: shellcheck (unavailable locally) and no end-to-end container build — the entrypoint changes are verified by extracted-script simulation, not a running container.

Mirrored to hugegraph#171.

- Name the actual boolean converter in the entrypoint comment. "BooleanUtils"
  alone is ambiguous: commons-lang3 accepts 0 and 1, the commons-lang 2.x one
  reached through commons-configuration 1.x PropertyConverter does not, and
  the accepted spellings follow the latter.
- Say that the init_complete guard applies to the environment variable, not to
  the property set directly in a mounted rest-server.properties.
- Move InitStoreConfigTest into its own cmd group in UnitTestSuite instead of
  the core one.
- Trim test comments closer to the density of the surrounding suite.
@bitflicker64

Copy link
Copy Markdown
Contributor Author

Follow-up push (5268091) after another review pass. No behaviour change — 604 tests, 0 failures, checkstyle clean.

  • The entrypoint comment said the accepted spellings are "the ones HugeConfig accepts (BooleanUtils)". That is ambiguous, and it misled a bot reviewer into reporting the 0/1 test as a false green. Conversion actually runs through commons-configuration 1.x PropertyConverter → commons-lang 2.6 BooleanUtils, which rejects 0 and 1; commons-lang3 would accept them. The comment now names the path.
  • docker/README.md said "With false, the entrypoint deliberately never writes docker/init_complete". True for the environment variable, not for the property set directly in a mounted config. Reworded, with the limitation stated.
  • InitStoreConfigTest moved out of the /* core */ group in UnitTestSuite into its own /* cmd */ group, and its comments trimmed toward the density of the surrounding suite.

Two things I would rather raise myself than have you find them:

checkAdminBootstrapReachable may be in the wrong class. StandardAuthenticator.setup() already does the same resolution — scanGraphsDir(GRAPHS), look up auth.graph_store, fail naming both options — and StandardAuthenticator.initAdminUserIfNeeded(String) is the existing static config-path entry point that InitStore already calls. So the check arguably belongs beside that code rather than in InitStore, which as written reaches into auth internals and repeats the auth-graph lookup. I kept it in InitStore because that is where the skip decision is made and where the exit status has to be produced, but I will move it if you would rather.

One branch is effectively unreachable and untested. ConfigUtil.scanGraphsDir throws when the graphs directory is absent, so for usePD=true + built-in auth + no local conf/graphs, the failure surfaces as scanGraphsDir's generic message rather than "auth graph 'x' has no local configuration". The path == null branch only fires when the directory exists but lacks the named graph. I can add a test for that case, or fold the two messages together.

Also for ordering: #3132 (the Helm chart) injects HG_SERVER_INIT_STORE_ENABLED=false and depends on this PR's env mapping, so it should land after this one.

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: The disabled-init path can expose a predictable administrator credential and can persist an incorrect initialization marker for mounted configurations. Evidence: exact-head static traces through InitStore, GraphManager, and docker-entrypoint.sh; 12/12 focused tests passed; all visible latest-head workflows passed.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
…cord init by result

Two findings from review of the disabled init-store path.

The check now also requires an explicit non-empty auth.admin_pa. Without it a
fresh built-in-auth deployment reaches GraphManager.initAdminUserIfNeeded() on
the PD startup path, which creates the admin from that option's public 'pa'
default while Docker PASSWORD is discarded on this path. The accepted-HStore
test had no admin_pa, so it pinned exactly that case.

The docker init marker is now written by init-store itself, and only when it
initialized. The entrypoint could only decide from its own environment
variable, so a config mounted with init_store.enabled=false was still recorded
as initialized, and setting it back to true later skipped initialization for
good. The marker path is passed in, so callers that do not want one are
unaffected.
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Aug 2, 2026
@bitflicker64
bitflicker64 requested a review from Copilot August 2, 2026 05:17

Copilot AI 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.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated no new comments.

Suppressed comments (2)

docker/README.md:178

  • The README still says the entrypoint writes docker/init_complete only when HG_SERVER_INIT_STORE_ENABLED=false is set, but the entrypoint no longer writes the marker at all; InitStore writes it only after a successful enabled run. As written, this incorrectly implies that disabling via a mounted rest-server.properties behaves differently from disabling via the env var.
> With the variable set to `false`, the entrypoint deliberately never writes
> `docker/init_complete`, so a later re-enable is still able to initialize.
> Setting the property directly in a mounted `rest-server.properties` does not
> get that guard.

hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh:74

  • HG_SERVER_INIT_STORE_ENABLED is mapped into rest-server.properties via set_prop, but set_prop only detects existing key= definitions. If a mounted rest-server.properties uses : as the separator (valid for Java properties), this will append a second logical definition, and HugeConfig will load it as a list and fail (as the unit test documents). Consider teaching set_prop to match both = and : separators (and ideally whitespace separators) when deciding whether to replace vs append.
INIT_STORE_ENABLED=$(printf '%s' "${HG_SERVER_INIT_STORE_ENABLED:-}" |
                     tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
case "${INIT_STORE_ENABLED}" in
    "" | y | t | yes | on | true | n | f | no | off | false) ;;
    *) log "ERROR: invalid HG_SERVER_INIT_STORE_ENABLED" \
           "'${HG_SERVER_INIT_STORE_ENABLED}'"
       exit 1 ;;
esac
[[ -n "${INIT_STORE_ENABLED}" ]] && \
    set_prop "init_store.enabled" "${INIT_STORE_ENABLED}" "${REST_SERVER_CONF}"

…moved

init-store writes the marker now, so a run disabled by a mounted property
records nothing just as one disabled by the environment variable does. The
text still described the entrypoint owning it, and still claimed the mounted
case was unguarded, which the change removed.
@bitflicker64

Copy link
Copy Markdown
Contributor Author

Both Copilot points, one taken and one deferred.

README (taken, ff1325a). Correct catch, and it was my own stale text. After the marker moved into init-store, the paragraph still described the entrypoint owning it and still claimed the mounted-property case was unguarded — which is exactly what that change removed. It now says the marker is written by init-store only after it has initialized, so a skipped run records nothing whichever way it was disabled.

set_prop separators (deferred to #3133). The behaviour is real: set_prop detects only key=, so a mounted rest-server.properties using : gets a second logical definition appended and HugeConfig then rejects the file as a list — testDuplicateDefinitionFailsToLoad pins that symptom.

Leaving it here for three reasons. It is pre-existing and not specific to this option: the same set_prop already maps backend and pd.peers, so any fix should cover all three at once. It fails closed and loudly rather than silently, now that init-store propagates its exit status — the container stops instead of starting misconfigured. And teaching shell to match =, : and whitespace separators is the start of a properties parser in sed, which was rejected on this PR earlier for not matching the grammar HugeConfig actually uses.

That is the same reasoning behind moving ConfigTool out, and #3133 covers replacing grep/sed property access with the Commons Configuration path. I have added the separator case there explicitly.

@imbajin imbajin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: yes. Summary: Existing initialization markers can bypass the new disabled-path safety checks, and PD administrator creation failures are still swallowed. Evidence: six independent exact-head review lanes, static traces through docker-entrypoint.sh, InitStore, and GraphManager; InitStoreConfigTest passed 13/13; git diff --check passed; visible exact-head checks are green.

Comment thread hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh Outdated
An existing docker/init_complete marker skipped bin/init-store.sh
entirely, so the disabled path's fail-closed check never ran after an
upgrade or a configuration change: built-in auth could start without
usePD, an HStore auth graph, or an explicit auth.admin_pa. The
entrypoint now runs init-store on every startup and hands it the marker
path — absolute, so the in-Java check agrees with the shell guard —
and init-store consults the marker only after the gate check, so a
marker left by an earlier release or an earlier enabled run skips
re-initialization and nothing else. An enabled run with the marker
present returns before backend registration and stdin, keeping the
restart branch free of wait-storage and PASSWORD.

GraphManager.initAdminUserIfNeeded() swallowed every failure from
metaManager.createUser() and initDefaultGraphSpace(), so a PD write,
permission or validation failure still started a server with no usable
administrator — the exact outcome the gate check refuses. Only the
already-exists case is benign now, judged by re-reading the user
rather than by matching the message (the probe failure is attached as
suppressed if the re-read itself fails); everything else aborts
startup. Writing the completion marker also tolerates a concurrent
container having recorded it first.

Regressions: an existing marker with an invalid built-in-auth disabled
configuration still fails closed; an existing marker with the gate
enabled returns before the graph scan; the admin is created when
absent, kept without failing when already present, and a non-duplicate
creation failure propagates with its cause.

Copilot AI 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.

Pull request overview

Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.

Suppressed comments (3)

hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java:175

  • recordInitComplete() treats FileAlreadyExistsException as success unconditionally. If the marker path already exists but is a directory (or other non-regular file), this will silently “record” completion even though future runs (with the tightened check) won’t consider it a valid marker. It’s safer to accept the already-exists case only when the existing entry is a regular file.
        try {
            Files.createFile(path);
        } catch (FileAlreadyExistsException e) {
            // A concurrent container finishing its own successful init has
            // already recorded it, which is the same outcome
        }

hugegraph-server/hugegraph-dist/docker/docker-entrypoint.sh:74

  • The HG_SERVER_INIT_STORE_ENABLED mapping relies on set_prop, which only replaces existing definitions written as key=.... Java .properties also allow key:... and whitespace separators; with a mounted rest-server.properties that uses init_store.enabled: false, this will append a second logical definition instead of replacing, and HugeConfig will then load the key as a list and fail the boolean type check. Consider deleting any existing init_store.enabled line (regardless of separator) before appending the normalized value.
[[ -n "${INIT_STORE_ENABLED}" ]] && \
    set_prop "init_store.enabled" "${INIT_STORE_ENABLED}" "${REST_SERVER_CONF}"

hugegraph-server/hugegraph-dist/src/main/java/org/apache/hugegraph/cmd/InitStore.java:151

  • presentInitCompleteMarker() treats any existing filesystem entry as a completion marker (Files.exists). If the configured path exists but is a directory (or other non-regular file), init-store will incorrectly skip initialization. Consider requiring a regular file via Files.isRegularFile(...) so the marker can’t be accidentally satisfied by a directory.

This issue also appears on line 170 of the same file.

    private static String presentInitCompleteMarker() {
        String marker = configuredInitCompleteMarker();
        if (marker != null && Files.exists(Paths.get(marker))) {
            return marker;
        }
        return null;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files. tests Add or improve test cases

Projects

None yet

Development

Successfully merging this pull request may close these issues.

InitStore should be able to skip local init in PD/HStore deployments

3 participants