Skip to content

feat(native) #5544 : experimental GraalVM native-image build of the ArcadeDB server - #5323

Merged
robfrank merged 22 commits into
mainfrom
feat/native-image
Jul 29, 2026
Merged

feat(native) #5544 : experimental GraalVM native-image build of the ArcadeDB server#5323
robfrank merged 22 commits into
mainfrom
feat/native-image

Conversation

@robfrank

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds an experimental GraalVM native-image build of the ArcadeDB server, delivered as an opt-in add-on that never gates or replaces the JVM distribution.

  • New native Maven module, activated only by -Pnative (kept OUT of the default <modules>, so mvn clean install is unchanged).
  • Builds a self-contained native binary of the server: SQL, Cypher, HTTP/Studio, and the Postgres / Redis / MongoDB / Bolt / gRPC wire protocols all work natively. GraalJS scripting is embedded and works. Gremlin and the OpenTelemetry tracing module are excluded from the native build.
  • A reusable smoke-test script (native/src/test/scripts/smoke.sh + exercise.sh) that is the single acceptance gate across local, CI, and container runs.
  • Reachability metadata generated via the GraalVM tracing agent plus the library metadata repository (not hand-maintained).
  • A 5-target CI matrix workflow (.github/workflows/native-image.yml): linux/amd64 + linux/arm64 (required), macos/arm64, macos/amd64, windows/amd64 (best-effort). Native-image cannot cross-compile, so each target builds on its own runner.
  • Split-arch static Linux binaries and Docker images: amd64 = fully-static musl on FROM scratch; arm64 = mostly-static glibc (-H:+StaticExecutableWithDynamicLibC) on gcr.io/distroless/base-debian12 (GraalVM CE ships no aarch64 musl static libs - Missing static JDK libraries compiled against musl oracle/graal#4645). Multi-arch manifest via imagetools, published only on release.
  • docs/native-image.md documenting the build, matrix, containers, and limitations.

Motivation

A native binary gives fast cold start and low memory footprint, which suits edge / Kubernetes / serverless deployments where the JVM's startup and RAM overhead are costly. This revives and completes the abandoned poc/native_image branch (last touched ~2 years ago; GraalVM 23.1.1 / v26.1.1), rebased onto current main and GraalVM CE 25.

Related issues

Supersedes the stale poc/native_image branch. References oracle/graal#4645 (no aarch64 musl static libs in GraalVM CE, which drove the split-arch Docker approach).

Additional Notes

Verification. The native binary was built and smoke-tested locally on macos/arm64 (HTTP/Studio/SQL/Cypher/JS plus Redis PING->PONG, Bolt v5.4 handshake, MongoDB hello, gRPC reflection). The Linux static builds and Docker images are CI-only (not buildable on a macOS dev machine). Recommend one manual workflow_dispatch run before relying on a release: it --loads and smokes both containers locally and publishes nothing (Docker Hub login and --push are gated to the release event, so a branch push / PR cannot publish to arcadedata/arcadedb).

Known limitations / follow-ups (none blocking, all documented in docs/native-image.md):

  • JS security caveat: the Truffle blocklist was relaxed (-H:-TruffleCheckBlockListMethods) to embed GraalJS. Atomics / SharedArrayBuffer / TypedArray.prototype.set are reachable via any authenticated {"language":"js"} command and are unverified under AOT runtime compilation. This is a real residual risk for the experimental add-on; the JVM build already exposes the same JS surface.
  • Binary size ~732 MB from -H:IncludeResources=.* embedding all classpath resources. A size-tightening pass (restrict to Studio/config/Lucene patterns) is the obvious next optimization.
  • macos/amd64 uses the paid macos-15-intel runner (the free macos-13 was retired). This repo already disabled that runner elsewhere, so it is likely a dead leg; it is continue-on-error, so harmless, and can be commented out.
  • distroless base is not digest-pinned (unlike the JVM Dockerfile); a supply-chain follow-up.
  • JVector jdk.incubator.vector may fall back to scalar under native-image (perf only, not correctness).

Design & plan. The full spec and implementation plan are committed on the branch: docs/superpowers/specs/2026-07-18-native-image-design.md and docs/superpowers/plans/2026-07-18-native-image.md.

Checklist

  • I have run the build using mvn clean package command (the default reactor is unaffected; the native image builds via mvn -Pnative -pl native -am -DskipTests package, verified on macos/arm64)
  • My unit tests cover both failure and success scenarios (the acceptance gate for native-image bring-up is the smoke script, which hard-asserts HTTP/Studio/SQL/Cypher/JS and fails loudly; wire protocols are exercised when their client is present, run for real on the Linux CI legs)

🤖 Generated with Claude Code

@mergify

mergify Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 1 high · 3 minor

Alerts:
⚠ 4 issues (≤ 0 issues of at least minor severity)

Results:
4 new issues

Category Results
Documentation 1 minor
ErrorProne 1 high
CodeStyle 2 minor

View in Codacy

🟢 Metrics 7 complexity

Metric Results
Complexity 7

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request introduces an experimental GraalVM native-image build for ArcadeDB, adding a new native Maven module, Dockerfiles for static and mostly-static builds, design/plan documentation, and comprehensive smoke-testing and tracing scripts. The feedback highlights a potential runtime issue in the scratch-based Dockerfile due to a missing /tmp directory, and identifies several instances in the exercise.sh test script where set -e will cause silent exits on command failures, bypassing the intended descriptive error messages.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

COPY config /home/arcadedb/config
COPY --chmod=0755 arcadedb /home/arcadedb/bin/arcadedb

WORKDIR /home/arcadedb

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.

medium

Since this image is built FROM scratch, it does not contain a /tmp directory by default. Many Java libraries (such as Lucene, Netty, or ArcadeDB itself) create temporary files or unpack native libraries into the system's temporary directory (java.io.tmpdir, which defaults to /tmp on Linux). The absence of /tmp can lead to runtime IOException failures when these libraries attempt to write temporary files.\n\nYou can easily create /tmp in a scratch image by using the WORKDIR instruction to target /tmp before setting the final working directory.

WORKDIR /tmp\nWORKDIR /home/arcadedb

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fa6d755. Added WORKDIR /tmp before the app WORKDIR to materialize /tmp (java.io.tmpdir defaults to it). Created root-owned 0755, writable by the default root runtime user; a comment notes a non-root --user run should bind-mount a writable /tmp. Only the scratch/amd64 image is affected - the arm64 distroless base already ships /tmp.

Comment thread native/src/test/scripts/exercise.sh Outdated
req() { curl -fsS -u "$DB_USER:$PASS" -H 'Content-Type: application/json' "$@"; }

echo "[exercise] Studio index"
OUT="$(req "http://$HOST:$HTTP/")"

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.

medium

Because set -e is enabled at the top of the script, any command that returns a non-zero exit status will cause the shell to exit immediately. During the assignment OUT="$(req ...)", if the request fails (e.g., connection refused or HTTP error), the script will exit immediately and silently. This bypasses the subsequent grep check and the custom error message echo "[exercise] FAIL: Studio index".\n\nAppending || true to the assignment allows the script to continue to the grep check, which will then fail and print your descriptive error message.

Suggested change
OUT="$(req "http://$HOST:$HTTP/")"
OUT=\"$(req \"http://$HOST:$HTTP/\")\" || true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fa6d755. Appended || true to the five OUT=$(req ...) / psql assignments so a failed request reaches the custom [exercise] FAIL: ... message instead of a bare set -e exit. Pass/fail is unchanged: an empty OUT still fails the subsequent grep, so the assertion still fails loudly.

Comment thread native/src/test/scripts/exercise.sh Outdated
-d '{"language":"sql","command":"CREATE DOCUMENT TYPE T"}' >/dev/null
req -X POST "http://$HOST:$HTTP/api/v1/command/$DB" \
-d '{"language":"sql","command":"INSERT INTO T SET n = 42"}' >/dev/null
OUT="$(req -X POST "http://$HOST:$HTTP/api/v1/query/$DB" -d '{"language":"sql","command":"SELECT n FROM T"}')"

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.

medium

Similar to the issue on line 78, if the SQL query fails, the script will exit immediately and silently due to set -e, bypassing the custom error message. Appending || true ensures the script proceeds to the grep check and prints the descriptive error message.

Suggested change
OUT="$(req -X POST "http://$HOST:$HTTP/api/v1/query/$DB" -d '{"language":"sql","command":"SELECT n FROM T"}')"
OUT=\"$(req -X POST \"http://$HOST:$HTTP/api/v1/query/$DB\" -d '{\"language\":\"sql\",\"command\":\"SELECT n FROM T\"}')\" || true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fa6d755 (same || true change applied to this assignment).

Comment thread native/src/test/scripts/exercise.sh Outdated
Comment on lines +99 to +100
OUT="$(req -X POST "http://$HOST:$HTTP/api/v1/command/$DB" \
-d '{"language":"cypher","command":"CREATE (a:Person {name:\"Ada\"}) RETURN a.name AS n"}')"

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.

medium

Similar to the issue on line 78, if the Cypher command fails, the script will exit immediately and silently due to set -e, bypassing the custom error message. Appending || true ensures the script proceeds to the grep check and prints the descriptive error message.

Suggested change
OUT="$(req -X POST "http://$HOST:$HTTP/api/v1/command/$DB" \
-d '{"language":"cypher","command":"CREATE (a:Person {name:\"Ada\"}) RETURN a.name AS n"}')"
OUT=\"$(req -X POST \"http://$HOST:$HTTP/api/v1/command/$DB\" \n -d '{\"language\":\"cypher\",\"command\":\"CREATE (a:Person {name:\"Ada\"}) RETURN a.name AS n\"}')\" || true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fa6d755 (same || true change applied to this assignment).

Comment thread native/src/test/scripts/exercise.sh Outdated
Comment on lines +110 to +111
OUT="$(req -X POST "http://$HOST:$HTTP/api/v1/command/$DB" \
-d '{"language":"js","command":"40 + 2"}')"

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.

medium

Similar to the issue on line 78, if the JS command fails, the script will exit immediately and silently due to set -e, bypassing the custom error message. Appending || true ensures the script proceeds to the grep check and prints the descriptive error message.

Suggested change
OUT="$(req -X POST "http://$HOST:$HTTP/api/v1/command/$DB" \
-d '{"language":"js","command":"40 + 2"}')"
OUT=\"$(req -X POST \"http://$HOST:$HTTP/api/v1/command/$DB\" \n -d '{\"language\":\"js\",\"command\":\"40 + 2\"}')\" || true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fa6d755 (same || true change applied to this assignment).

Comment thread native/src/test/scripts/exercise.sh Outdated

echo "[exercise] Postgres-wire round-trip"
if command -v psql >/dev/null 2>&1; then
OUT="$(PGPASSWORD="$PASS" psql -h "$HOST" -p "$PG" -U "$DB_USER" -d "$DB" -tAc 'SELECT 1')"

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.

medium

Similar to the issue on line 78, if psql fails to connect or execute, the script will exit immediately and silently due to set -e, bypassing the custom error message. Appending || true ensures the script proceeds to the grep check and prints the descriptive error message.

Suggested change
OUT="$(PGPASSWORD="$PASS" psql -h "$HOST" -p "$PG" -U "$DB_USER" -d "$DB" -tAc 'SELECT 1')"
OUT=\"$(PGPASSWORD=\"$PASS\" psql -h \"$HOST\" -p \"$PG\" -U \"$DB_USER\" -d \"$DB\" -tAc 'SELECT 1')\" || true

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed in fa6d755 (same || true change applied to this assignment).

@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review: experimental GraalVM native-image build

Nice, well-scoped, and genuinely impressive engineering. The design is right: the module is kept out of the default reactor (-Pnative only), the JVM distribution is never gated, action SHAs are pinned, and the split-arch Docker rationale (musl-static amd64 on scratch vs mostly-static glibc arm64 on distroless, oracle/graal#4645) is documented in painful, admirable detail. The PR description is also honest about the residual risks. Comments below are mostly hardening/follow-up, not blockers for an experimental add-on.

Correctness / potential issues

  1. Truffle/GraalVM version skew is fragile (native/pom.xml:66-134). The dependencyManagement block force-downgrades the engine's transitively-pulled graal artifacts from 25.1.3 (engine/pom.xml:41) to 25.0.2 for the native module. That means arcadedb-engine bytecode compiled against the 25.1.3 API runs against 25.0.2 classes in the image, which can surface as NoSuchMethodError/NoSuchFieldError at runtime for anything added in 25.1.x. The js round-trip in exercise.sh covers the happy path, but this pin now has to move in lockstep across three places (engine's graalvm.version, native.graalvm.version, and the workflow's java-version: 25.0.2). Worth a prominent "bump all three together" note (the workflow has one; the engine pom does not).

  2. Locate native binary denylist is brittle (native-image.yml:150-163). The find excludes only *.jar, *.txt, *.o. GraalVM with native-image-job-reports: true / -H:+ReportExceptionStackTraces can emit report/arg files; any stray arcadedb-* file that isn't one of those three extensions trips the -ne 1 guard and fails the job. Matching the executable by permission (-perm -u+x on Linux/macOS, or an explicit per-OS name) would be more robust than an extension denylist.

  3. Container writable-dir ownership (Dockerfile.native.distroless:44-53, Dockerfile.native.scratch:50-67). Only config and bin are COPY --chowned; databases/, backups/, replication/, log/ are declared as VOLUMEs but never created with ownership for the runtime UID (nonroot 65532 on distroless, or an overridden --user on scratch). The CI container smoke only asserts /api/v1/ready, so it won't catch this, but a real docker run without a pre-owned bind mount may fail to persist. Worth creating those dirs with the right owner in the image (or documenting the exact --user/mount requirement more loudly).

Security

  1. -H:-TruffleCheckBlockListMethods (native/pom.xml:235-236). You already flagged this clearly, which is the right call. Given the add-on is experimental and Atomics/SharedArrayBuffer/TypedArray.prototype.set are reachable and unverified under AOT runtime compilation, consider whether JS should be opt-in (excluded by default, enabled by a build flag) rather than embedded by default, so the relaxed blocklist isn't the shipped default. At minimum keep the loud doc note.

  2. distroless base not digest-pinned (Dockerfile.native.distroless:36). The JVM package/src/main/docker/Dockerfile pins by digest; this one uses the floating :nonroot tag. You noted this as a supply-chain follow-up - agreed, worth doing before this leaves "experimental".

Performance

  1. -H:IncludeResources=.* -> ~732 MB (native/pom.xml:225). Already acknowledged. Beyond size, .* also embeds things like the committed reachability-metadata.json and every classpath resource. Tightening to Studio/config/Lucene patterns is the obvious next step before promoting this.

Test coverage

  1. Wire-protocol checks never fail CI, even where the plugin is enabled (exercise.sh:153-215). Redis/Bolt/Mongo/gRPC are all best-effort WARN-skip - including on the two Linux legs that deliberately enable every plugin (native-image.yml:174-183). So a native regression that breaks, say, the Bolt handshake would print a WARN and the build would stay green, even though "wire protocols work natively" is a headline claim of this PR. Consider promoting these to hard assertions on the Linux legs (where the plugins and client tools are guaranteed present), keeping the WARN-skip only for macOS/Windows/local runs where clients may be missing. Right now only Postgres is effectively asserted (and only on amd64, where postgresql-client is installed).

  2. Otherwise the smoke/exercise split is a sensible acceptance gate for a build artifact with no natural JUnit surface, and reusing the exact same exercise.sh under the tracing agent (trace.sh) to keep recorded reachability aligned with what's asserted is a nice touch.

Minor / style

  • Substitutions.java is clean and the Javadoc explaining the jdk.graal.compiler.* rename shadow is excellent.
  • New GraalVM artifacts are version-pinned only (already project deps via engine), so no ATTRIBUTIONS change is strictly required - worth a quick double-check that no genuinely new coordinate slipped in.

Overall: solid, honest, and appropriately fenced off from the default build. My only "please consider before merge" item is #7 (make the Linux wire-protocol checks assert rather than warn) so CI actually defends the claim; the rest are good documented follow-ups.

Reviewed against the repo's CLAUDE.md conventions.

robfrank added a commit that referenced this pull request Jul 18, 2026
…se.sh FAIL diagnostics under set -e

Addresses gemini-code-assist review on PR #5323:
- Dockerfile.native.scratch: scratch has no /tmp; java.io.tmpdir defaults to
  /tmp and Lucene/Netty may write there. Create it via the WORKDIR trick.
- exercise.sh: append '|| true' to the five OUT=$(req/psql ...) assignments so
  a failed request reaches the custom [exercise] FAIL message instead of a bare
  set -e exit. Pass/fail semantics unchanged (empty OUT still fails the grep).
@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 426 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.5.38 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.5.38 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown

Code Review: experimental GraalVM native-image build (PR #5323)

Overall this is a genuinely impressive, well-isolated addition. The native module is opt-in (-Pnative only, kept out of the default <modules>), maven.deploy.skip=true protects the deploy path, and the default reactor is untouched. The documentation and the inline rationale comments are exceptional - the combine.children="append" explanation, the musl/aarch64 split, the Truffle blocklist caveat, and the CA-trust nuance are all documented honestly, including the residual risks. Nicely done.

A few things worth addressing before merge:

🔴 Likely bug: release asset upload will fail on the required Linux legs

In .github/workflows/native-image.yml, the Attach to release step:

gh release upload "${{ github.event.release.tag_name }}" \
  native/target/arcadedb-*.tar.gz native/target/arcadedb-*.zip native/target/*.sha256 \
  --clobber

On the Linux and macOS legs there is no .zip (only Windows produces one). GitHub Actions runs bash steps with set -e and does not enable nullglob, so the unmatched native/target/arcadedb-*.zip glob is passed to gh as a literal filename, gh release upload errors on the missing file, and the step fails. Because linux/amd64 and linux/arm64 are the required legs, every real release would fail to attach the two Linux binaries. The mac legs are continue-on-error, but the Linux ones are not.

Suggest globbing defensively, e.g. collect existing files first:

shopt -s nullglob
assets=(native/target/arcadedb-*.tar.gz native/target/arcadedb-*.zip native/target/*.sha256)
gh release upload "${{ github.event.release.tag_name }}" "${assets[@]}" --clobber

Note the release-upload path only runs on a real release event, so a workflow_dispatch dry run will not exercise it - worth a careful read rather than relying on CI to catch it.

🟡 ATTRIBUTIONS.md not updated for the new dependencies

CLAUDE.md requires: "When adding a dependency, you MUST update ATTRIBUTIONS.md". This PR pulls in several new artifacts (org.graalvm.js:js-language, org.graalvm.truffle:*, org.graalvm.polyglot, org.graalvm.sdk:*, os-maven-plugin, native-maven-plugin). They appear to be UPL-1.0 / build-time and thus license-compatible, but ATTRIBUTIONS.md was not touched. Please confirm the license of each GraalVM artifact (particularly truffle-compiler, historically GPLv2+CE) and update ATTRIBUTIONS.md / NOTICE accordingly, even if they are native-build-only and never shipped in the JVM distribution.

🟡 Security caveat is real (already disclosed, flagging for visibility)

-H:-TruffleCheckBlockListMethods / -H:-TruffleCheckBlackListedMethods relaxes Truffle's AOT soundness check so Atomics.* / SharedArrayBuffer / TypedArray.prototype.set become reachable via any authenticated {"language":"js"} command, unverified under runtime compilation. This is thoroughly documented as an accepted, non-blocking risk for an experimental add-on, and the JVM build already exposes the same JS surface, so I am not blocking on it. Just keep the "experimental" framing prominent wherever this image is advertised, and consider filing a tracking issue to revisit once GraalJS ships those builtins as blocklist-clean.

🟢 Minor / nits

  • Internal planning docs committed: docs/superpowers/plans/2026-07-18-native-image.md (870 lines) and docs/superpowers/specs/... (166 lines) are agent working docs. Consider whether they belong permanently in the repo tree, or whether docs/native-image.md alone is the intended durable documentation.
  • Leaked task references in shipped source: native/pom.xml and trace.sh reference "Task 4"/"Task 5" from the implementation plan. These are meaningless to future readers of the source; consider rephrasing.
  • Stale header in smoke.sh: the usage comment says "Requires ARCADEDB_HOME to point at the distribution root (config/, lib/, bin/)", but the native binary is self-contained and the script roots everything under $WORK. That line looks inaccurate for the native case.
  • Substitutions.java shadowing relies on classpath ordering ("arcadedb-native jar precedes wildfly-common"). Documented and low-risk, but inherently fragile if module/classpath ordering ever changes. Fine as-is; just noting.
  • native as an additional assembly point: per CLAUDE.md, protocol modules are normally aggregated only by the package module. native legitimately acts as a second assembly module here, which is reasonable given its purpose, but worth a mention in the wire-protocol dependency notes so future reviewers do not flag it.

Test coverage

The smoke/exercise scripts are a solid acceptance gate and hard-assert HTTP/Studio/SQL/Cypher/JS while best-effort-exercising every wire protocol. The read_fd_with_deadline / cat-vs-head -c reasoning and the hand-rolled BSON hello are careful work. Since the native module has no JUnit tests (no Java sources of its own beyond the substitution shim), the shell gate is the right approach, but it only runs in the dedicated workflow - a regression in the reachability metadata or build args will not be caught by the normal mvn verify reactor. That is an acceptable trade-off for an opt-in experimental add-on.

Nice work overall - the headline item to fix is the release-upload glob.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 426 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.5.38 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.5.38 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

robfrank added a commit that referenced this pull request Jul 18, 2026
Addresses 5 review items on the native-image work:

- exercise.sh: add WIRE_STRICT=1 opt-in mode that turns the Postgres/
  Redis/Bolt/Mongo/gRPC best-effort WARN-skips into hard FAILs on a
  missing client tool, unreachable port, or wrong response. Wired into
  native-image.yml's two Linux CI legs (which enable every wire plugin),
  so a native regression that breaks a wire protocol now fails the
  build instead of staying green. Installs postgresql-client and
  grpcurl on both Linux legs (previously postgresql-client was amd64-
  only and grpcurl wasn't installed at all).
- native-image.yml: make the "Locate native binary" step select by
  executable bit (.exe suffix on Windows) instead of excluding a fixed
  extension list, which could be tripped by future native-image report
  artifacts.
- Dockerfile.native.scratch / Dockerfile.native.distroless: add a tiny
  busybox builder stage that pre-creates the databases/backups/
  replication/log VOLUME dirs owned by the runtime UID (0 for scratch,
  65532 for distroless), so a non-root `docker run` can actually
  persist to them.
- Dockerfile.native.distroless: pin the distroless base image by
  digest, matching the JVM Dockerfile's supply-chain posture.
- engine/pom.xml: document that graalvm.version must move in lockstep
  with native/pom.xml's native.graalvm.version and native-image.yml's
  setup-graalvm java-version.
@robfrank

Copy link
Copy Markdown
Collaborator Author

Addressed in 2afd8bad2 (gemini's inline items are in fa6d7552e).

Correctness

  1. Version skew - added a lockstep comment on engine/pom.xml's graalvm.version noting that native/pom.xml's native.graalvm.version and the workflow's java-version must move together (the workflow already pins 25.0.2). The js round-trip covers the happy path; the note makes the three-place coupling explicit.
  2. Binary locate - now selects the executable by permission bit (find -maxdepth 1 -type f -name 'arcadedb-*' -perm -u+x, .exe on Windows) instead of the *.jar/*.txt/*.o denylist, so stray GraalVM report files no longer trip the -ne 1 guard.
  3. Volume dir ownership - both Dockerfiles now pre-create databases//backups//replication//log/ owned by the runtime UID (65532 distroless, 0 scratch) via a digest-pinned busybox builder stage, so a real docker run as the intended user can persist without a pre-owned bind mount.

Security
4. -H:-TruffleCheckBlockListMethods / JS opt-in - JS-included-by-default was a deliberate scope decision for this experimental add-on, documented loudly in docs/native-image.md. Making JS opt-in behind a build flag (so the relaxed blocklist isn't the shipped default) is a sound hardening; I've left flipping the default as a maintainer design call rather than changing it unilaterally here, and kept the prominent doc note.
5. distroless digest - pinned to gcr.io/distroless/base-debian12:nonroot@sha256:6c806311d3..., matching the JVM Dockerfile's supply-chain posture.

Performance
6. -H:IncludeResources=.* / ~732 MB - accepted follow-up; tightening to Studio/config/Lucene patterns (and dropping the committed metadata) is the planned next step before promoting out of experimental.

Test coverage
7. Wire checks now hard-assert on the Linux legs - exercise.sh gained a WIRE_STRICT=1 mode (single wire_fail() decision point). Both Linux CI legs install postgresql-client + grpcurl and run the smoke with WIRE_STRICT=1, so Redis/Bolt/Mongo/gRPC/Postgres now fail the build on a native regression there. macOS/Windows/local keep the WARN-skip default (client tools not guaranteed). Verified locally that strict mode hard-fails an absent-tool/unreachable-port case and passes when the protocols actually respond (Redis PONG, Bolt 00000405, Mongo hello, gRPC reflection).
8. Acknowledged - no change needed.

Minor - confirmed no genuinely new dependency coordinate slipped in: the graal artifacts are transitive via arcadedb-engine (only version-pinned in the native module), so no ATTRIBUTIONS.md change is required.

@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 426 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.5.38 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.5.38 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review: experimental GraalVM native-image build

Overall this is a high-quality, well-scoped, and exceptionally well-documented PR. The core design decision is right: the native module is kept out of the default <modules> and only activates under -Pnative, so mvn clean install and the whole existing reactor are genuinely untouched. The inline comments in native/pom.xml, native-image.yml, and the Dockerfiles are some of the clearest build-infra documentation I've reviewed - the combine.children="append" rationale, the split-arch musl/glibc explanation, and the Truffle version-pinning note all pre-empt exactly the questions a reviewer would ask. Supply-chain hygiene (digest-pinned bases, non-root distroless, gated Docker Hub push, WIRE_STRICT CI hardening) is solid.

Feedback below, ordered by importance. None are blocking for an experimental, opt-in add-on, but a few should be tracked before this is ever promoted toward production use.

Security

  • Relaxed Truffle blocklist (-H:-TruffleCheckBlockListMethods / -H:-TruffleCheckBlackListedMethods). You've documented this honestly, and the JVM build already exposes the same JS surface, so I agree it's an accepted residual risk here. Two suggestions: (1) make docs/native-image.md state unambiguously that the native image is not production-hardened for multi-tenant/untrusted JS; (2) consider whether GraalJS should be an opt-in piece of the native build rather than always embedded, so an operator who doesn't need {"language":"js"} isn't carrying the unverified Atomics/SharedArrayBuffer/TypedArray.prototype.set AOT paths at all. That also shrinks the binary.
  • -H:IncludeResources=.* embeds every classpath resource. Beyond the 732 MB size (already flagged as a follow-up), the wider concern is unintended inclusion: anything that lands on the native module's runtime classpath (stray configs, sample keystores, test fixtures pulled transitively) gets baked into a shippable binary. Tightening to explicit Studio/config/Lucene patterns addresses both size and this exposure, and is worth doing before any non-experimental promotion.

Potential gaps

  • Container smoke test is shallow. In native-image.yml, the docker job's "Smoke the container" step only polls /api/v1/ready. The full SQL/Cypher/JS/wire assertions in exercise.sh run against the raw binary in the build job, but not against the packaged image. That means image-packaging regressions (missing /tmp, a bad config copy, a volume-permission issue) that don't stop the process from becoming "ready" would slip through. Consider running exercise.sh against the running container (at least the HTTP/SQL/Cypher/JS hard-asserts) so the Dockerfile is validated end-to-end, not just to first readiness.

Minor

  • macos-15-intel (paid larger runner). As you note, this repo already treats that runner as a dead leg. It's continue-on-error, so harmless, but a permanently red/never-scheduling matrix leg is confusing noise. I'd lean toward commenting it out with a pointer to the entitlement question rather than shipping a leg you expect to fail.
  • Committing docs/superpowers/specs/* and docs/superpowers/plans/*. These read as internal planning/agent artifacts. Worth deciding deliberately whether they belong in the main tree or should be excluded - they'll show up in every future git log/grep over docs/.
  • Version lockstep enforced only by comments. native.graalvm.version (25.0.2) vs engine graalvm.version (25.1.3) vs the setup-graalvm java-version are coupled purely by prose. A drift only surfaces as a native build failure in CI (NoSuchMethodError: getLoopNodeFactory). Given the native workflow runs on workflow_dispatch/release only, a mismatch could sit undetected on main between releases. Low risk, but a tiny CI assertion (or an enforcer rule) that the three values agree would make it self-checking.
  • native/src/main/java/org/wildfly/common/Substitutions.java shadow depends on the arcadedb-native jar preceding wildfly-common on the native-image classpath. It's clever and fails loudly at build time if ordering breaks, so it's acceptable, but it is inherently fragile to reactor/dependency reordering - the load-bearing comment is doing the right thing here.
  • exercise.sh Mongo probe opens fd 5 purely to test reachability, closes it, then lets mongo_hello.py reconnect. Slightly redundant and technically races (port could close between probe and reconnect), but not a real defect - the python client has its own timeout and the check fails cleanly either way.

Test coverage

Reasonable for build infrastructure: the smoke/exercise scripts are the acceptance gate, they hard-assert HTTP/Studio/SQL/Cypher/JS, and WIRE_STRICT=1 on the two required Linux legs correctly upgrades the wire-protocol WARN-skips to hard failures. There's no new Java logic to unit-test (the only Java file is a behaviorally-inert shadow class), so the absence of JUnit tests is fine here.

Nice work reviving and completing this. The honesty about limitations in both the PR description and docs/native-image.md is exactly right for an experimental feature.

🤖 Generated with Claude Code

robfrank added a commit that referenced this pull request Jul 18, 2026
… JS multi-tenant caveat

Addresses claude[bot] re-review on PR #5323:
- docker job smoke now runs exercise.sh (HTTP/Studio/SQL/Cypher/JS hard-asserts)
  against the running container, not just /api/v1/ready, so image-packaging
  regressions (missing /tmp, bad config copy, volume perms) are caught.
- docs/native-image.md: state explicitly the native image is not production-
  hardened for multi-tenant/untrusted JS, with opt-in/version-pin hardening
  options for future promotion.
@robfrank

Copy link
Copy Markdown
Collaborator Author

Re-review addressed in 3295e6ec2.

Container smoke depth (potential gaps) - Fixed. The docker job's smoke step now runs exercise.sh against the running container (HTTP/Studio/SQL/Cypher/JS hard-asserts), not just /api/v1/ready, so image-packaging regressions - missing /tmp, a bad config copy, a volume-permission issue - fail the job instead of slipping through. Wire protocols warn-skip there (their ports aren't published and the default entrypoint enables no wire plugin); the build-job smoke already asserts them with WIRE_STRICT=1 on the two Linux legs.

JS not production-hardened (security) - Added an explicit statement in docs/native-image.md that the native image is NOT production-hardened for multi-tenant/untrusted JS, with the hardening options you suggested (opt-in GraalJS behind a build flag; pin the builder to a Truffle version that keeps the blocklist enforced) called out for a future non-experimental promotion. Flipping JS to opt-in is a maintainer design call for the add-on's default, so I've documented it rather than changing the default here.

Minor items

  • macos-15-intel - left in per the maintainer's explicit choice of the full 5-target matrix; it's continue-on-error so a never-scheduling leg can't red the run, and it's a one-line comment-out if the entitlement question is settled the other way. Flagged prominently in the workflow comment and PR description.
  • Committing docs/superpowers/specs|plans/* - deliberate: this project's convention is to keep the design spec and implementation plan in the feature PR alongside the code. Noted your point that they read as internal artifacts.
  • Version lockstep enforced only by comments - agree a tiny self-checking guard (assert native.graalvm.version == the workflow's setup-graalvm java-version) beats prose. Tracking it as a follow-up; the native workflow runs only on dispatch/release, so I'd want the assertion somewhere that runs per-PR to actually catch drift on main.
  • Substitutions.java shadow fragility and the Mongo reachability-probe race - acknowledged; both are load-bearing-comment / no-real-defect as you noted, no change.

CI note (not this PR): the failing "Meterian client scan" is unrelated - its log shows Unable to generate lockfile in folder /github/workspace/bindings/python; python dependencies generation failed, i.e. a Meterian infra issue scanning the Python bindings, which this branch does not touch (the separate "Meterian" check passes). Codacy's 1-high ErrorProne appears to be on the intentionally-empty org.wildfly.common.Substitutions shadow classes (their whole purpose is to be empty), which I read as a false positive - I can't see the exact rule without the Codacy dashboard, so flagging it for triage there.

@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 426 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.5.38 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.5.38 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review: experimental GraalVM native-image build

Excellent work. This is a carefully scoped, well-documented, opt-in add-on that keeps the JVM reactor entirely untouched (native stays out of the default <modules>, only activated by -Pnative). The inline comments are exceptional - the reasoning behind musl-vs-mostly-static, the Truffle version pin, the combine.children="append" merge semantics, and the push-gating are all explained where a future maintainer will look. Nothing here is blocking; below are a few findings and suggestions.

Potential issue: scratch image /tmp is not writable for the documented non-root run

Dockerfile.native.scratch materializes /tmp via the WORKDIR /tmp trick, which creates it root-owned 0755. The Dockerfile comment itself notes "a non-root --user run should bind-mount a writable /tmp", but the docker run example in docs/native-image.md uses --user 1000:1000 without a /tmp bind mount. Since java.io.tmpdir defaults to /tmp and the comment already anticipates Lucene/Netty writing there, following the documented command against the amd64/scratch image can fail at runtime for UID 1000. The CI container smoke test doesn't catch this because it runs as the default UID 0.

Suggestion: give /tmp standard sticky-world-writable perms in the dirs builder stage (mkdir -m 1777 /skel/tmp and COPY it in, instead of the WORKDIR trick), so any --user value works out of the box - or, at minimum, add the -v /tmp guidance to the docs example so the two don't contradict each other.

CI coverage gap: the native build has no automated trigger

native-image.yml triggers only on workflow_dispatch and release: [published] - there is no push or pull_request trigger. That means a change that breaks the native build (or the Dockerfiles/scripts) can merge to main with zero automated verification; it will only surface at release time, or when someone remembers to manually dispatch. The PR description acknowledges this and recommends a manual run, which is reasonable for landing, but consider a path-filtered pull_request trigger on native/** / the workflow file running at least the required linux/amd64 build + smoke, so regressions are caught before release rather than during it.

Minor

  • smoke.sh:30 - the header comment "Requires ARCADEDB_HOME to point at the distribution root (config/, lib/, bin/)" is stale: the script never reads ARCADEDB_HOME, and the native binary is self-contained. Worth removing/updating so it doesn't mislead.
  • Substitutions.java - the shadow-by-classpath-order trick relies on arcadedb-native preceding wildfly-common on the image classpath. This is deterministic per Maven resolution today but is inherently fragile; if a future dependency reorder flips it, the build breaks with the "Substitution target ... is not loaded" error. The javadoc mitigates the surprise, but a more robust alternative (e.g. explicitly removing the offending substitution via a native-image Feature) would be worth a follow-up.
  • reachability-metadata.json was captured on macOS (it contains apple.security.AppleProvider). With --no-fallback, any Linux-only reflective path not covered by the trace or the metadata repo fails at runtime, not build time. The Linux CI smoke tests exercise the core surface so this is covered for what's tested, but it's a reason to keep the smoke assertions broad; regenerating on Linux (or merging both) would harden the metadata beyond the smoke surface.
  • Workflow permissions - permissions: contents: write is declared at the workflow level but only the build job's "Attach to release" step needs it; the docker/manifest jobs authenticate to Docker Hub via secrets. Scoping contents: write to the build job would tighten least-privilege.

Security note (already well-handled)

The -H:-TruffleCheckBlockListMethods relaxation to embed GraalJS is a genuine, reachable security-relevant change, and it is documented thoroughly and honestly in both native/pom.xml and docs/native-image.md, with the "not production-hardened for untrusted/multi-tenant JS" warning and concrete hardening options for a future non-experimental promotion. For an opt-in experimental add-on where the JVM build already exposes the same JS surface, this is an acceptable, clearly-flagged tradeoff.

Tests

The smoke/exercise script design is a good fit here: one acceptance gate reused across local, CI matrix, and container runs, with WIRE_STRICT=1 correctly turning best-effort WARN-skips into hard assertions on the two Linux legs that install the client tools. JS is a hard assertion; wire protocols degrade gracefully off-CI. This is a sensible testing strategy for build/packaging infra that has no natural JUnit surface.

Overall: solid, self-contained, and appropriately labeled experimental. The /tmp non-root inconsistency and the missing PR/push CI trigger are the two items I'd most want addressed (or explicitly deferred) before a release relies on this.

🤖 Generated with Claude Code

robfrank added a commit that referenced this pull request Jul 18, 2026
…, drop stale comment

Addresses claude[bot] re-review on PR #5323:
- Dockerfile.native.scratch: create /tmp as sticky world-writable (1777) from
  the builder stage instead of the WORKDIR trick (root-owned 0755), so the
  documented 'docker run --user 1000:1000' works without a /tmp bind mount.
- native-image.yml: default permissions to contents:read; scope contents:write
  to the build job (only 'Attach to release' needs it).
- smoke.sh: drop the stale ARCADEDB_HOME header comment (the script never reads it).
@robfrank

Copy link
Copy Markdown
Collaborator Author

Addressed in ad86867c6.

/tmp not writable for the documented non-root run - Fixed properly. /tmp is now created sticky world-writable (1777) from the builder stage (COPY --chmod=1777 /skeltmp /tmp) instead of the WORKDIR trick, so the documented docker run --user 1000:1000 works without a /tmp bind mount for any UID. The two no longer contradict.

No automated native-build CI trigger - This one I'm deliberately leaving as-is and flagging for the maintainer rather than changing unilaterally: the add-on was explicitly scoped during design as experimental and not PR-gating, precisely to avoid slow native builds on every PR. Your narrower suggestion - a path-filtered pull_request trigger on native/** + the workflow file, running only the required linux/amd64 build + smoke - is a good middle ground that keeps the cost near zero for unrelated PRs while closing the "breaks on main undetected" gap. Recorded as a recommended follow-up for the maintainer to opt into; it reverses a stated scope decision, so it's their call.

Minor

  • smoke.sh stale header - Fixed; dropped the ARCADEDB_HOME line (the script never reads it) and replaced it with an accurate note that the executable is self-contained.
  • Workflow permissions - Fixed; defaulted the workflow to contents: read and scoped contents: write to the build job (only its "Attach to release" step needs it). The docker/manifest jobs authenticate to Docker Hub via secrets and keep read.
  • reachability-metadata.json captured on macOS - Correct, and a good follow-up: with --no-fallback, a Linux-only reflective path not covered by the trace or the metadata repo would fail at runtime. The Linux CI smoke exercises the core surface (now including exercise.sh against the packaged container and WIRE_STRICT wire assertions), so what's tested is covered; regenerating the metadata on Linux (or merging both platforms' traces) to harden beyond the smoke surface is tracked as a follow-up. It's also a reason I kept the smoke assertions broad.
  • Substitutions.java classpath-order fragility - Acknowledged; replacing the shadow with a native-image Feature that removes the offending substitution explicitly is the more robust long-term form, noted as a follow-up. It fails loudly at build time today, so the risk is a broken build, not a silent runtime issue.

The contents: read default plus per-job scoping and the 1777 /tmp are in ad86867c6; yaml/actionlint/hadolint/shellcheck all clean.

@codacy-production

codacy-production Bot commented Jul 18, 2026

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 1 high · 3 minor

Alerts:
⚠ 4 issues (≤ 0 issues of at least minor severity)

Results:
4 new issues

Category Results
Documentation 1 minor
ErrorProne 1 high
CodeStyle 2 minor

View in Codacy

🟢 Metrics 7 complexity

Metric Results
Complexity 7

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@claude

claude Bot commented Jul 18, 2026

Copy link
Copy Markdown

Review: experimental GraalVM native-image build (PR #5323)

Overall this is a high-quality, well-isolated addition. The native module stays out of the default reactor (-Pnative only), so mvn clean install is genuinely unaffected; the workflow pins action SHAs, uses least-privilege permissions, digest-pins base images, and gates all registry pushes behind the release event. The smoke/exercise script split (reused verbatim across local, CI, and container runs) is a nice acceptance-gate design, and the inline comments explaining the why (musl vs. mostly-static, Truffle version skew, combine.children="append", os-maven-plugin naming) are excellent. I verified the five wire-protocol plugin class names and the /api/v1/ready endpoint referenced by the scripts all exist and match.

A few things worth addressing or at least discussing:

Security

  • -H:-TruffleCheckBlockListMethods (highest-risk item). Relaxing the Truffle blocklist makes Atomics / SharedArrayBuffer / TypedArray.prototype.set reachable and unverified under AOT for any authenticated {"language":"js"} command. You already document this and note the JVM build exposes the same JS surface, which is fair. Given it's experimental, consider making GraalJS opt-in for the native build (or gating it behind a config flag) until those paths are verified, rather than embedding it by default. At minimum keep the "experimental" label prominent wherever the native image is advertised.
  • Dockerfile.native.scratch runs as UID 0 by default. The JVM image uses USER arcadedb and the arm64 distroless image runs nonroot (65532), but the amd64 scratch image defaults to root unless the operator remembers --user. You can set a numeric USER 1000 in a scratch image even without /etc/passwd; doing so would make amd64/arm64 consistent and safer by default, while still allowing an override. Right now the safer default is only on one of the two published arches.

Repo hygiene

  • Committed internal planning docs. docs/superpowers/plans/2026-07-18-native-image.md (870 lines) and docs/superpowers/specs/... (166 lines) reference agentic "superpowers" sub-skills and checkbox task tracking. These read as internal AI-workflow scaffolding rather than end-user documentation. Consider whether they belong in the public repo, or fold the useful parts into docs/native-image.md and drop the rest.
  • ATTRIBUTIONS.md / NOTICE. The native binary embeds GraalVM polyglot + GraalJS (UPL 1.0, allowed) and the build adds the os-maven-plugin extension. CLAUDE.md asks that new dependencies update ATTRIBUTIONS.md (and NOTICE if applicable). Since these ship inside the produced artifact, please confirm whether an attributions update is needed.

Robustness / minor

  • Binary size ~732 MB from -H:IncludeResources=.*. Acknowledged as a follow-up, but it's large enough to partially undercut the "low footprint" motivation, so I'd prioritize the tightening pass before any real release.
  • mapfile (bash 4+) in the "Locate native binary" step runs on the macOS legs too, where /bin/bash is 3.2. GitHub's shell: bash usually resolves a newer bash on PATH, so this likely works, but a find ... | head -1 read loop would be more portable. Non-blocking since the macOS legs are continue-on-error.
  • Reachability metadata was generated on macos/arm64 only. Linux-specific reflection could be missed; mitigated by metadataRepository + the Linux CI smoke with WIRE_STRICT=1, so this is fine as-is, just worth keeping in mind when the metadata drifts.
  • Container "Smoke the container" step doesn't pass SRV_PID/SERVER_LOG to exercise.sh, so a crashed container waits the full ~120s readiness loop before failing instead of failing fast. Cosmetic.

Testing

The shell smoke gate is a reasonable choice here (a native binary can't be exercised from the normal JUnit reactor), and it hard-asserts HTTP/Studio/SQL/Cypher/JS with wire protocols under WIRE_STRICT=1 on the Linux legs. The only new Java, Substitutions.java, is a build-time classpath shadow that isn't unit-testable; note that it relies on the arcadedb-native module's own classes preceding wildfly-common on the image classpath, which holds because a module's target/classes sorts ahead of dependency jars, but it's an implicit assumption worth a one-line comment.

Nice work overall. The security defaults (JS blocklist relaxation, root-by-default scratch image) are the two items I'd most want resolved or explicitly signed off before this is used for anything beyond experimentation.

Reviewed by Claude Code.

@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 426 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.5.38 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.5.38 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

@robfrank

Copy link
Copy Markdown
Collaborator Author

Thanks for the thorough pass. Status on each:

Security (the two "resolve or sign off" items) - both are deliberate security-default choices that belong to the maintainer, so flagging for explicit sign-off rather than flipping them here:

  • GraalJS opt-in vs embedded-by-default. Documented as an accepted, clearly-flagged residual risk; the JVM build exposes the same JS surface; the "experimental" label is on the PR title, docs/native-image.md, and the module. Making JS a build-flag opt-in for the native image is a good hardening for a non-experimental promotion - recommended follow-up, maintainer's call on the default.
  • scratch defaults to UID 0. Valid consistency gap vs the arm64 distroless nonroot (65532). It's a two-part change (chown the builder /skel volume dirs to 65532:65532 + add USER 65532:65532 to Dockerfile.native.scratch; /tmp is already 1777 so it works for any uid). Since it changes volume-dir ownership and I can only validate the container path in CI, I've left the documented root-default + --user override in place and am flagging the exact change for sign-off, so it lands with a green CI container smoke rather than a blind default flip.

Repo hygiene

  • ATTRIBUTIONS/NOTICE - checked: no update needed. GraalVM polyglot/Truffle is already in ATTRIBUTIONS.md (8 references) and NOTICE (3) because the JVM distribution already ships it via arcadedb-engine; the native binary embeds the same artifacts, no new coordinate. os-maven-plugin is a build-time <extension>, not shipped in the produced binary, so it needs no attribution.
  • Committed planning docs - deliberate per this project's convention (design spec + implementation plan travel in the feature PR). Noted your point that the "superpowers" scaffolding reads as internal; the end-user content lives in docs/native-image.md.

Robustness / minor

  • ~732 MB size - agreed it partly undercuts the low-footprint motivation; the -H:IncludeResources=.* tightening pass is the top follow-up before any real release.
  • mapfile on macOS legs - works on GitHub's macOS runners (shell: bash resolves Homebrew bash 5); those legs are continue-on-error regardless. A portable find ... | while read loop is a trivial follow-up.
  • Container smoke fast-fail - SRV_PID/SERVER_LOG are local-process concepts that don't map to a containerized server, so fast-fail there needs a docker inspect/healthcheck rather than the env vars; the ~120s worst case on a crashed container is cosmetic. Noted.
  • Metadata generated on macos/arm64 - mitigated by metadataRepository + the Linux CI smoke (now including exercise.sh against the container and WIRE_STRICT=1); regenerating on Linux is a tracked follow-up.
  • Substitutions.java classpath ordering - the module's target/classes sorting ahead of dependency jars is exactly why the shadow works; will add that one-liner to the javadoc.

Net: the two security defaults are yours to sign off (recommend the scratch USER 65532 change land with a CI run to verify volume ownership); everything else is either fixed across fa6d7552e/2afd8bad2/3295e6ec2/ad86867c6 or a documented follow-up.

robfrank added a commit that referenced this pull request Jul 18, 2026
…se.sh FAIL diagnostics under set -e

Addresses gemini-code-assist review on PR #5323:
- Dockerfile.native.scratch: scratch has no /tmp; java.io.tmpdir defaults to
  /tmp and Lucene/Netty may write there. Create it via the WORKDIR trick.
- exercise.sh: append '|| true' to the five OUT=$(req/psql ...) assignments so
  a failed request reaches the custom [exercise] FAIL message instead of a bare
  set -e exit. Pass/fail semantics unchanged (empty OUT still fails the grep).
robfrank added a commit that referenced this pull request Jul 18, 2026
Addresses 5 review items on the native-image work:

- exercise.sh: add WIRE_STRICT=1 opt-in mode that turns the Postgres/
  Redis/Bolt/Mongo/gRPC best-effort WARN-skips into hard FAILs on a
  missing client tool, unreachable port, or wrong response. Wired into
  native-image.yml's two Linux CI legs (which enable every wire plugin),
  so a native regression that breaks a wire protocol now fails the
  build instead of staying green. Installs postgresql-client and
  grpcurl on both Linux legs (previously postgresql-client was amd64-
  only and grpcurl wasn't installed at all).
- native-image.yml: make the "Locate native binary" step select by
  executable bit (.exe suffix on Windows) instead of excluding a fixed
  extension list, which could be tripped by future native-image report
  artifacts.
- Dockerfile.native.scratch / Dockerfile.native.distroless: add a tiny
  busybox builder stage that pre-creates the databases/backups/
  replication/log VOLUME dirs owned by the runtime UID (0 for scratch,
  65532 for distroless), so a non-root `docker run` can actually
  persist to them.
- Dockerfile.native.distroless: pin the distroless base image by
  digest, matching the JVM Dockerfile's supply-chain posture.
- engine/pom.xml: document that graalvm.version must move in lockstep
  with native/pom.xml's native.graalvm.version and native-image.yml's
  setup-graalvm java-version.
robfrank added a commit that referenced this pull request Jul 18, 2026
… JS multi-tenant caveat

Addresses claude[bot] re-review on PR #5323:
- docker job smoke now runs exercise.sh (HTTP/Studio/SQL/Cypher/JS hard-asserts)
  against the running container, not just /api/v1/ready, so image-packaging
  regressions (missing /tmp, bad config copy, volume perms) are caught.
- docs/native-image.md: state explicitly the native image is not production-
  hardened for multi-tenant/untrusted JS, with opt-in/version-pin hardening
  options for future promotion.
@robfrank
robfrank force-pushed the feat/native-image branch from ad86867 to 0846f82 Compare July 18, 2026 20:41
robfrank added a commit that referenced this pull request Jul 18, 2026
…, drop stale comment

Addresses claude[bot] re-review on PR #5323:
- Dockerfile.native.scratch: create /tmp as sticky world-writable (1777) from
  the builder stage instead of the WORKDIR trick (root-owned 0755), so the
  documented 'docker run --user 1000:1000' works without a /tmp bind mount.
- native-image.yml: default permissions to contents:read; scope contents:write
  to the build job (only 'Attach to release' needs it).
- smoke.sh: drop the stale ARCADEDB_HOME header comment (the script never reads it).
@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 426 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.5.38 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.5.38 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

robfrank added 19 commits July 29, 2026 17:53
…adata repo

Enables the GraalVM reachability-metadata repository in native-maven-plugin so
Task 4's native build gets well-known library configs (Netty, Lucene,
gRPC/protobuf, graphql-java) from the repo instead of hand-written config, and
adds trace.sh, which launches the assembled JVM distribution under
-agentlib:native-image-agent with every wire plugin enabled
(Postgres/Redis/MongoDB/Bolt/gRPC) and records what the server actually
touches at runtime.

Refactors the HTTP/SQL/Cypher/Postgres assertions out of smoke.sh into
exercise.sh so the exact same checks run against both smoke.sh's own server
and trace.sh's instrumented one; exercise.sh also opportunistically drives a
Redis PING, a Bolt handshake, a hand-rolled Mongo OP_MSG hello (via
mongo_hello.py, no bson/pymongo dependency available), and a grpcurl
reflection list, each skipped with a WARN if its port never opens.
Native-image build of the ArcadeDB server (GraalVM CE 25, macos/arm64) now
compiles and boots. smoke.sh passes: HTTP/Studio, SQL and Cypher round-trips,
and all wire protocols served natively (Redis PING->PONG, Bolt v5.4 handshake,
MongoDB hello, gRPC reflection). Postgres plugin loads (wire assertion needs
psql, verified in CI). GraalJS is embedded (Truffle runtime active).

Blockers resolved:
- wildfly-common Substitutions shadow: GraalVM 25 renamed the substitution
  target org.graalvm.compiler.* -> jdk.graal.compiler.*, breaking wildfly's
  bundled @TargetClass GraalDirectives/Branch hints; a stripped shadow class
  ahead on the classpath removes them (pure branch-probability hints, no
  behavioral effect).
- Undertow/XNIO HostName -> --initialize-at-run-time.
- slf4j API/helpers/spi/event/jul -> --initialize-at-build-time.
- Netty -> --initialize-at-run-time=io.netty.
- JLine -> dumb terminal at runtime.
- JVector -> --add-modules=jdk.incubator.vector.
- GraalJS Truffle blocklist relaxed (-H:-TruffleCheckBlockListMethods) so six
  Atomics/TypedArray.set builtins reaching MethodHandle.linkToStatic do not
  abort the build; those runtime-compiled JS paths are unverified (Task 5).

Known follow-up: binary is 732MB due to -H:IncludeResources=.* embedding all
classpath resources; tighten to specific patterns to shrink.
…chability risk

Task 4 already embeds and runs GraalJS in the native binary. This makes that
permanent: exercise.sh gains a hard JS assertion (same style as the SQL/Cypher
checks, not a WARN-skip) verified against both the native binary and the JVM
server.sh build. docs/native-image.md documents the outcome plus the
investigation into the reviewer's Atomics/SharedArrayBuffer/TypedArray.set
forward-flag: those builtins are reachable through ArcadeDB's polyglot Context
sandboxing (which restricts host/IO/thread/process access, not the JS language
surface itself), confirmed by direct functional tests against the running
native binary, so the Truffle blocklist relaxation's residual risk is real and
stays documented as an accepted, non-blocking risk.
Builds the GraalVM CE 25 native image on each OS/arch runner (native-image
cannot cross-compile): linux/amd64 + linux/arm64 (required), macos + windows
(best-effort via continue-on-error). Smoke-tests each binary, publishes
compressed artifacts + SHA256, attaches to releases. Plumbs a native.static
flag + musl-tools install for the Linux static build (made functional in the
static profile in the next task).

macos-13 was retired by GitHub; macos/amd64 uses macos-15-intel (a paid larger
runner - entitlement to be confirmed by maintainer) and macos/arm64 macos-15.
…solver

Fills in Task 6's native-static no-op profile: --static --libc=musl appended
to the native-maven-plugin buildArgs via combine.children="append" (Maven's
default profile/base plugin merge for repeated <buildArg> elements is
positional, not a union, so an unmarked <buildArgs> would silently overwrite
two base flags instead of adding two new ones).

native-image.yml's musl-tools install step becomes a full musl+zlib toolchain
setup: musl-dev (not just musl-tools) supplies the arch-prefixed compiler
native-image's toolchain probe looks for by name, and a musl-linked static
zlib is built from source with --includedir/--libdir pointed at the musl
triplet's own include/lib dirs - musl-gcc's specs file passes -nostdinc/
-nostdlib and does not fall back to generic /usr/include or /usr/lib.

Confirmed (via the actual graalvm-community-jdk-25.0.2 release tarballs) that
linux-aarch64 ships lib/static/linux-aarch64/glibc but not the musl variant,
so the arm64 static leg will fail at the native-image link stage until Oracle
ships aarch64 musl static JDK libs (oracle/graal#4645) - documented in
docs/native-image.md and inline in the workflow rather than silently masked.

Also documents that ArcadeDB's native image never touches Netty's async DNS
resolver (io.netty.resolver is absent from the whole dependency graph wired
into native/pom.xml, and no real preferJdkResolver-style Netty system
property exists to "force" a JDK resolver anyway), so no runtime DNS flag is
needed for Task 8's Docker ENTRYPOINT.
…glibc arm64) + multi-arch manifest

GraalVM CE cannot build a fully-static musl binary for linux/arm64 (no aarch64
musl JDK libs - oracle/graal#4645), so the two Linux native-image targets now
use different build modes: linux/amd64 stays fully-static musl (FROM scratch),
linux/arm64 switches to mostly-static glibc via a new native-mostly-static
Maven profile (-H:+StaticExecutableWithDynamicLibC, FROM distroless/base
glibc). Adds native-image.yml's docker and manifest jobs to build, smoke-test
and publish per-arch images and stitch them into an arcadedata/arcadedb:<ver>
-native manifest, gated so only a published release pushes to Docker Hub.
CI resolved the newest CE 25.x builder (java-version: "25"), which will
skew against native/pom.xml's exact native.graalvm.version=25.0.2 Truffle
pin as soon as a newer CE 25.x patch ships, breaking the native build at
release time (NoSuchMethodError: OptimizedTruffleRuntime.getLoopNodeFactory()).
Pin the builder to the same exact patch so it stays coupled with the pom.
…se.sh FAIL diagnostics under set -e

Addresses gemini-code-assist review on PR #5323:
- Dockerfile.native.scratch: scratch has no /tmp; java.io.tmpdir defaults to
  /tmp and Lucene/Netty may write there. Create it via the WORKDIR trick.
- exercise.sh: append '|| true' to the five OUT=$(req/psql ...) assignments so
  a failed request reaches the custom [exercise] FAIL message instead of a bare
  set -e exit. Pass/fail semantics unchanged (empty OUT still fails the grep).
Addresses 5 review items on the native-image work:

- exercise.sh: add WIRE_STRICT=1 opt-in mode that turns the Postgres/
  Redis/Bolt/Mongo/gRPC best-effort WARN-skips into hard FAILs on a
  missing client tool, unreachable port, or wrong response. Wired into
  native-image.yml's two Linux CI legs (which enable every wire plugin),
  so a native regression that breaks a wire protocol now fails the
  build instead of staying green. Installs postgresql-client and
  grpcurl on both Linux legs (previously postgresql-client was amd64-
  only and grpcurl wasn't installed at all).
- native-image.yml: make the "Locate native binary" step select by
  executable bit (.exe suffix on Windows) instead of excluding a fixed
  extension list, which could be tripped by future native-image report
  artifacts.
- Dockerfile.native.scratch / Dockerfile.native.distroless: add a tiny
  busybox builder stage that pre-creates the databases/backups/
  replication/log VOLUME dirs owned by the runtime UID (0 for scratch,
  65532 for distroless), so a non-root `docker run` can actually
  persist to them.
- Dockerfile.native.distroless: pin the distroless base image by
  digest, matching the JVM Dockerfile's supply-chain posture.
- engine/pom.xml: document that graalvm.version must move in lockstep
  with native/pom.xml's native.graalvm.version and native-image.yml's
  setup-graalvm java-version.
… JS multi-tenant caveat

Addresses claude[bot] re-review on PR #5323:
- docker job smoke now runs exercise.sh (HTTP/Studio/SQL/Cypher/JS hard-asserts)
  against the running container, not just /api/v1/ready, so image-packaging
  regressions (missing /tmp, bad config copy, volume perms) are caught.
- docs/native-image.md: state explicitly the native image is not production-
  hardened for multi-tenant/untrusted JS, with opt-in/version-pin hardening
  options for future promotion.
…, drop stale comment

Addresses claude[bot] re-review on PR #5323:
- Dockerfile.native.scratch: create /tmp as sticky world-writable (1777) from
  the builder stage instead of the WORKDIR trick (root-owned 0755), so the
  documented 'docker run --user 1000:1000' works without a /tmp bind mount.
- native-image.yml: default permissions to contents:read; scope contents:write
  to the build job (only 'Attach to release' needs it).
- smoke.sh: drop the stale ARCADEDB_HOME header comment (the script never reads it).
macos-15-intel is a paid Larger Runner not enabled here; it fails at job setup,
so the macos/amd64 native-image leg was a permanently-red dead leg. Remove it -
the matrix is now 4 targets (linux amd64+arm64 required; macos/arm64 + windows
best-effort). Docs updated to match.
…native-image)

The free macos-15 (Apple Silicon, ~7GB RAM) cannot build this native image
without thrashing swap for 40+ min - native-image wants ~80% of RAM and the
build image heap is ~630MB. Matrix is now linux/amd64 + linux/arm64 (required)
+ windows/amd64 (best-effort). macOS arm64 is a fast local build (mvn -Pnative);
documented in docs/native-image.md. Also unblocks the docker jobs, which no
longer wait on a slow best-effort macOS leg.
The container ENTRYPOINT sets -Djava.util.logging.config.file=arcadedb-log.properties,
which names its handlers/formatters by string (java.util.logging.FileHandler +
ConsoleHandler, com.arcadedb.log.LogFormatter, com.arcadedb.utility.AnsiLogFormatter).
JUL loads them reflectively, but native-image's static analysis can't see a class
referenced only as a config string, so FileHandler was absent from the image and
threw ClassNotFoundException at startup (non-fatal - logging fell back to console).
smoke.sh never set the JUL config file, so it wasn't caught until the container run.
Register the four classes for reflection (no-arg constructor). Verified: the CNFE is
gone and arcadedb.log is written to the logs directory.
exercise.sh can pass through a non-fatal boot error (e.g. a reflectively-loaded
JUL log handler missing from the native image logs a ClassNotFoundException but
only degrades logging). Scan the container startup log and fail on
ClassNotFoundException / log-handler load failures so a missing-metadata
regression cannot hide behind a green functional smoke.
… tuning

Re-add macos/arm64 (best-effort) to test whether the free ~7GB macos-15 runner
can build the image with memory constraints: new native-lowmem pom profile
(-Dnative.lowmem=true) caps the builder heap (-J-Xmx5g), lowers compiler-thread
parallelism to 2, and uses quick-build mode (-Ob); a macOS-only pre-build step
runs 'mdutil -i off' + 'purge' to reclaim RAM. required:false so a memory
failure never reddens the run.
Build the macOS arm64 native binary on macos-15-xlarge (a paid Apple-Silicon
Larger Runner with the RAM headroom the free macos-15 lacks - the free runner
OOM-thrashes this GraalJS-embedded image). The matrix is now computed in a
setup job so the paid leg is added only on a published release or a manual
dispatch that ticks the new include_macos input; an ordinary dispatch never
allocates the paid runner. The leg is best-effort (continue-on-error), uploads
a release artifact only, and never feeds the Docker images.

Also make the 'Locate native binary' step's array population portable
(while-read instead of mapfile), since GitHub's macOS runners can resolve
'shell: bash' to the system bash 3.2, which lacks mapfile.
@robfrank
robfrank force-pushed the feat/native-image branch from 9f6f610 to 0229ec8 Compare July 29, 2026 15:56
@github-actions

Copy link
Copy Markdown
Contributor

📜 License Compliance Check

✅ License check passed. See artifacts for full report.

License Summary (first 50 lines)

Lists of 425 third-party dependencies.
     (Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)
     (Apache License 2.0) LZ4 Java Compression (at.yawk.lz4:lz4-java:1.11.1 - https://github.com/yawkat/lz4-java)
     (EPL-2.0) (LGPL-2.1-only) Logback Classic Module (ch.qos.logback:logback-classic:1.6.1 - http://logback.qos.ch/logback-classic)
     (EPL-2.0) (LGPL-2.1-only) Logback Core Module (ch.qos.logback:logback-core:1.6.1 - http://logback.qos.ch/logback-core)
     (Apache 2) ArcadeDB BOLT Protocol (com.arcadedb:arcadedb-bolt:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-bolt/)
     (Apache 2) ArcadeDB Console (com.arcadedb:arcadedb-console:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-console/)
     (Apache 2) ArcadeDB Engine (com.arcadedb:arcadedb-engine:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-engine/)
     (Apache 2) ArcadeDB GraphQL (com.arcadedb:arcadedb-graphql:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-graphql/)
     (Apache 2) ArcadeDB Gremlin (com.arcadedb:arcadedb-gremlin:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-gremlin/)
     (Apache 2) ArcadeDB gRPC Stubs (com.arcadedb:arcadedb-grpc:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc/)
     (Apache 2) ArcadeDB gRPC Client (com.arcadedb:arcadedb-grpc-client:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpc-client/)
     (Apache 2) ArcadeDB gRpcW (com.arcadedb:arcadedb-grpcw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-grpcw/)
     (Apache 2) ArcadeDB HA Raft (com.arcadedb:arcadedb-ha-raft:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-ha-raft/)
     (Apache 2) ArcadeDB Integration (com.arcadedb:arcadedb-integration:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-integration/)
     (Apache 2) ArcadeDB load tests (com.arcadedb:arcadedb-load-tests:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-load-tests/)
     (Apache 2) ArcadeDB Metrics (com.arcadedb:arcadedb-metrics:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-metrics/)
     (Apache 2) ArcadeDB MongoDB Wire Protocol (com.arcadedb:arcadedb-mongodbw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-mongodbw/)
     (Apache 2) ArcadeDB Network (com.arcadedb:arcadedb-network:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-network/)
     (Apache 2) ArcadeDB PostgresW (com.arcadedb:arcadedb-postgresw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-postgresw/)
     (Apache 2) ArcadeDB RedisW (com.arcadedb:arcadedb-redisw:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-redisw/)
     (Apache 2) ArcadeDB Server (com.arcadedb:arcadedb-server:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-server/)
     (Apache 2) ArcadeDB Studio (com.arcadedb:arcadedb-studio:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-studio/)
     (Apache 2) ArcadeDB Tracing (com.arcadedb:arcadedb-tracing:26.8.1-SNAPSHOT - https://arcadedata.com/arcadedb-tracing/)
     (The Apache Software License, Version 2.0) HPPC Collections (com.carrotsearch:hppc:0.7.1 - http://labs.carrotsearch.com/hppc.html/hppc)
     (Apache License 2.0) Metrics Core (com.codahale.metrics:metrics-core:3.0.2 - http://metrics.codahale.com/metrics-core/)
     (The Apache License, Version 2.0) com.conversantmedia:disruptor (com.conversantmedia:disruptor:1.2.21 - https://github.com/conversant/disruptor)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.20 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.21 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-annotations (com.fasterxml.jackson.core:jackson-annotations:2.22 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.21.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) Jackson-core (com.fasterxml.jackson.core:jackson-core:2.22.1 - https://github.com/FasterXML/jackson-core)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.21.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) jackson-databind (com.fasterxml.jackson.core:jackson-databind:2.22.1 - https://github.com/FasterXML/jackson)
     (The Apache Software License, Version 2.0) Jackson-dataformat-YAML (com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.22.0 - https://github.com/FasterXML/jackson-dataformats-text)
     (The Apache Software License, Version 2.0) Jackson datatype: JSR310 (com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.22.0 - https://github.com/FasterXML/jackson-modules-java8/jackson-datatype-jsr310)
     (The Apache Software License, Version 2.0) Caffeine cache (com.github.ben-manes.caffeine:caffeine:2.3.1 - https://github.com/ben-manes/caffeine)
     (The Apache Software License, Version 2.0) docker-java-api (com.github.docker-java:docker-java-api:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport (com.github.docker-java:docker-java-transport:3.7.1 - https://github.com/docker-java/docker-java)
     (The Apache Software License, Version 2.0) docker-java-transport-zerodep (com.github.docker-java:docker-java-transport-zerodep:3.7.1 - https://github.com/docker-java/docker-java)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) btf (com.github.java-json-tools:btf:1.3 - https://github.com/java-json-tools/btf)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils (com.github.java-json-tools:jackson-coreutils:2.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) jackson-coreutils-equivalence (com.github.java-json-tools:jackson-coreutils-equivalence:1.0 - https://github.com/java-json-tools/jackson-coreutils)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-patch (com.github.java-json-tools:json-patch:1.13 - https://github.com/java-json-tools/json-patch)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-core (com.github.java-json-tools:json-schema-core:1.2.14 - https://github.com/java-json-tools/json-schema-core)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) json-schema-validator (com.github.java-json-tools:json-schema-validator:2.2.14 - https://github.com/java-json-tools/json-schema-validator)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) msg-simple (com.github.java-json-tools:msg-simple:1.2 - https://github.com/java-json-tools/msg-simple)
     (Apache Software License, version 2.0) (Lesser General Public License, version 3 or greater) uri-template (com.github.java-json-tools:uri-template:0.10 - https://github.com/java-json-tools/uri-template)
     (Apache License 2.0) (GNU Lesser General Public License) javaparser-core (com.github.javaparser:javaparser-core:3.26.3 - https://github.com/javaparser/javaparser-core)

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review: experimental GraalVM native-image build

Thanks for this - the engineering quality here is high and the inline documentation is genuinely excellent. The opt-in isolation (out of the default reactor, -Pnative only), the single smoke/exercise script reused across local/CI/container, digest-pinned base images, least-privilege permissions, and the layered push-gating (no push: trigger, --load on dispatch, --push only on release) are all well thought out. Comments below are mostly maintainability/consistency, plus a couple of things worth deciding explicitly before a release.

1. GraalVM version references are divergent and partly stale (maintainability)

There are now several different GraalVM versions in play:

  • engine/pom.xml -> graalvm.version = 25.2.4
  • native/pom.xml -> native.graalvm.version = 25.0.2
  • .github/workflows/native-image.yml -> java-version: "25.0.2"
  • native/pom.xml comment still refers to "the one the engine pulls transitively (25.1.3)"
  • ATTRIBUTIONS.md lists the GraalVM artifacts at 25.0.2

The new comment in engine/pom.xml says these "must move in lockstep", but engine (25.2.4) and the native builder/CI (25.0.2) are already intentionally different, and the native/pom.xml comment references a third value (25.1.3) that no longer matches engine. This will confuse the next person doing a version bump. Suggest: fix the stale 25.1.3 reference, and reword "lockstep" to explain the native module is deliberately pinned to the builder patch release while engine tracks its own. Also worth calling out the real fragility: if engine ever pulls a new org.graalvm.* artifact transitively that is not in native/pom.xml's <dependencyManagement> list, the engine version leaks into the image and reproduces the getLoopNodeFactory() skew failure.

2. amd64 and arm64 images default to different users (security consistency)

Dockerfile.native.scratch (amd64) runs as UID 0 by default (no /etc/passwd, documented), while Dockerfile.native.distroless (arm64, :nonroot) runs as 65532. A user pulling the single multi-arch arcadedb:<v>-native manifest therefore gets root on amd64 and non-root on arm64 for the same tag. A numeric USER 1000 works on scratch without an /etc/passwd entry, so both arches could default to non-root and match the JVM image posture. At minimum worth an explicit decision rather than an arch-dependent default.

3. PR description vs. actual workflow (stale description)

  • The body describes a "5-target CI matrix" including macos/amd64, but the workflow implements 4 legs (linux/amd64, linux/arm64, windows/amd64, optional macos/arm64). There is no macos/amd64 leg.
  • The body lists "distroless base is not digest-pinned" as a follow-up, but Dockerfile.native.distroless does pin it by @sha256.

Not code issues, but worth aligning so a release manager reading the PR is not misled.

4. JS blocklist relaxation (accepted risk - flag for release notes)

-H:-TruffleCheckBlockListMethods / -H:-TruffleCheckBlackListedMethods make Atomics/SharedArrayBuffer/TypedArray.prototype.set reachable and unverified under AOT for any authenticated {"language":"js"} command. You already document this clearly, and since the build is opt-in/experimental and the JVM build exposes the same JS surface, it is a reasonable trade-off - but it deserves a prominent line in the release notes for anyone exposing the native binary.

5. IncludeResources=.* -> ~732MB binary (documented follow-up)

Already flagged. Beyond size, the blanket .* pulls in resources from every module on the classpath; the tightening pass to Studio/config/Lucene patterns is worth doing before this graduates from experimental, and is a good moment to confirm nothing unintended (test fixtures, other-module resources) ends up embedded.

Minor / nits

  • exercise.sh Mongo check: tcp_connect 5 opens then immediately closes fd 5 before mongo_hello.py opens its own socket - the probe is effectively just a reachability test. Harmless, slightly redundant.
  • No Java unit test, but the only Java source (Substitutions.java) is a logic-free build-time shadow and the smoke/exercise script is the real acceptance gate, so that is consistent with the plan and fine.

Overall a solid, well-isolated experimental add-on that cannot regress the default build. The version-reference cleanup (#1) and the amd64 root-by-default decision (#2) are the two I would most want resolved before a release relies on it. Nice work.

@robfrank robfrank linked an issue Jul 29, 2026 that may be closed by this pull request
4 tasks
@robfrank robfrank changed the title feat(native): experimental GraalVM native-image build of the ArcadeDB server feat(native) #5544 : experimental GraalVM native-image build of the ArcadeDB server Jul 29, 2026
@robfrank
robfrank merged commit f70bcb8 into main Jul 29, 2026
68 of 73 checks passed
@codacy-production

Copy link
Copy Markdown

Not up to standards ⛔

🔴 Issues 1 high · 3 minor

Alerts:
⚠ 4 issues (≤ 0 issues of at least minor severity)

Results:
4 new issues

Category Results
Documentation 1 minor
ErrorProne 1 high
CodeStyle 2 minor

View in Codacy

🟢 Metrics 7 complexity

Metric Results
Complexity 7

View in Codacy

🟢 Coverage ∅ diff coverage · -7.04% coverage variation

Metric Results
Coverage variation -7.04% coverage variation
Diff coverage diff coverage

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (89e69f0) 146725 109537 74.65%
Head commit (0229ec8) 178717 (+31992) 120846 (+11309) 67.62% (-7.04%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#5323) 0 0 ∅ (not applicable)

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

robfrank added a commit that referenced this pull request Aug 14, 2026
robfrank added a commit that referenced this pull request Aug 14, 2026
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.

Experimental: GraalVM native-image build of the ArcadeDB server

1 participant