Skip to content

feat: Nexus-bootstrap CLI wrapper + LTA 2026.1 manifest refresh#10

Merged
aksOps merged 2 commits into
mainfrom
feat/cli-wrapper-script
May 26, 2026
Merged

feat: Nexus-bootstrap CLI wrapper + LTA 2026.1 manifest refresh#10
aksOps merged 2 commits into
mainfrom
feat/cli-wrapper-script

Conversation

@aksOps
Copy link
Copy Markdown
Contributor

@aksOps aksOps commented May 26, 2026

Summary

Two related changes that close gaps left after the SonarQube LTA 2026.1
migration in #8:

  1. Refresh the bundled runtime manifest so sonar setup actually
    provisions LTA 2026.1 artifacts. The manifest was stale on engine +
    9 of 10 plugins, and its version field (the cache key for
    ~/.sonar/<version>/) still pointed at the old engine — sonar setup
    would land in the wrong directory and verify against the wrong SHAs.
  2. Add an outer bootstrap wrapper (scripts/sonar-cli.sh +
    scripts/sonar-cli.ps1) that pulls the dist zip from a corporate
    Nexus and provisions a Temurin JDK 21 if the system has none, then
    hands off to the existing bin/sonar. Closes the chicken-and-egg
    problem for users who don't run the Maven build themselves and don't
    have a system JDK 21.

What changed

Bundled manifest refresh (chore(setup) commit):

  • src/main/resources/manifest.json: cache key 10.24.0.81415
    11.3.0.85510; all 11 GAVs bumped to LTA 2026.1; all 11 SHA-256s
    recomputed from the real jars.
  • Manifest.java: javadoc trimmed (no more reference to nonexistent
    daemon/plugins/CHECKSUMS.txt or "all-zeros placeholder").
  • ManifestTest.java: two hardcoded version constants bumped.
  • SetupCommandTest.java: latent test seam fixed — stubRunner paired
    the bundled-version-based layout with the test's own manifest. Both
    happened to be 10.24.0.81415 so it worked by coincidence; this bump
    exposed it. Rewired to build the layout from the test's manifest via
    RuntimeLayout.forVersion, so the test is isolated from future
    bundled-manifest bumps.

Wrapper scripts (feat(scripts) commit):

  • scripts/sonar-cli.sh (POSIX sh, executable) — required
    SONAR_NEXUS_BASE; optional SONAR_PREDICTOR_VERSION (default
    0.3.0-SNAPSHOT), SONAR_PREDICTOR_HOME (default
    ~/.sonar-predictor), SONAR_PREDICTOR_FORCE=1. Idempotent
    bundle/JDK provisioning, exec's bin/sonar so signals propagate.
  • scripts/sonar-cli.ps1 — Windows mirror, same env contract.

Nexus path conventions (one sed if your layout differs):

{base}/sonar-predictor/{version}/sonar-predictor-dist-{version}.zip
{base}/temurin/21/{os}-{arch}.{tar.gz|zip}

Test plan

  • mvn -B test358/358 pass, BUILD SUCCESS
  • sh -n scripts/sonar-cli.sh
  • dash -n scripts/sonar-cli.sh ✓ (POSIX-clean)
  • PowerShell parser on scripts/sonar-cli.ps1
  • Missing SONAR_NEXUS_BASE → exit 2 with clear "required" message
  • Unreachable Nexus (http://127.0.0.1:1) → exit 2 with failing URL
  • Pre-cached bundle → hands off to bin/sonar, picocli help renders, exit 0
  • End-to-end smoke against your real corporate Nexus (needs you — I
    used a placeholder; rename {base}/sonar-predictor/... and
    {base}/temurin/21/... if your layout differs)
  • Wrapper exercised on macOS (only Linux validated locally)
  • Wrapper exercised on Windows (.ps1 parser-validated only)

Known gaps / follow-ups

  • No SHA verification of the dist zip / JDK archive in the wrapper.
    Trust boundary is your corporate Nexus. Add a pin file later if you
    want defence-in-depth.
  • The bundle's bin/sonar and bin/sonar.bat still refuse with exit 2
    when no Java 21+ is found. With the wrapper in front of them, that
    error path is unreachable for normal users — but the inner launchers
    stay unchanged so direct bin/sonar invocation still works.

aksOps added 2 commits May 26, 2026 01:19
The bundled runtime manifest was left at the pre-LTA pins after commit
976a8c4 migrated pom.xml to 2026.1: every artifact except sonar-go-plugin
was on the old version, and the manifest's `version` field (the cache
key for ~/.sonar/<version>/) still pointed at the old engine. `sonar
setup` would land in the wrong directory and verify against stale SHAs.

- manifest.json: bump engine 10.24.0.81415 -> 11.3.0.85510 plus all 10
  analyzer pins to match pom.xml's LTA 2026.1 properties. All 11 SHA-256s
  recomputed from the Maven artifacts.
- Manifest.java javadoc: drop the stale reference to
  daemon/plugins/CHECKSUMS.txt (the file does not exist in the
  single-module layout) and the "all-zeros placeholder" note (the engine
  SHA has been real for some time).
- SetupCommandTest.stubRunner: fix a latent test seam. Production code
  keys the layout off Manifest.bundled().version(), but the stub paired
  that bundled-based layout with the test's injected manifest. Both
  happened to be "10.24.0.81415" so it worked by coincidence; the bump
  exposed the inconsistency. Build the layout from the test's manifest
  via RuntimeLayout.forVersion so the test is isolated from future
  bundled-manifest bumps.
- ManifestTest: bump the two hardcoded version constants the bundled
  manifest is asserted against.
The dist zip already ships bin/sonar (POSIX) and bin/sonar.bat (Windows)
that auto-discover a Java 21+ runtime, but they refuse with exit 2 if
none is found and they assume the user has the bundle on disk already.
For corporate / air-gapped deployments where users do not run the Maven
build themselves and do not have a system JDK 21, neither assumption
holds.

This adds an outer bootstrap wrapper that:

  1. Fetches the dist zip from a corporate Nexus raw repo into
     ~/.sonar-predictor/dist/<version>/sonar-predictor/ (idempotent;
     skipped if the bundle marker bin/sonar already exists).
  2. Reuses the same Java 21+ discovery as bin/sonar (JAVA_HOME, PATH,
     common install paths) so users with a system JDK pay zero JDK
     download cost.
  3. Otherwise fetches a Temurin JDK 21 archive from the same Nexus into
     ~/.sonar-predictor/jdk/21/<os>-<arch>/ and exports JAVA_HOME so the
     bundle's own launcher picks it up unchanged.
  4. exec's the bundle's bin/sonar (POSIX) or bin/sonar.bat (Windows) so
     signals propagate cleanly. The daemon launches as a child of bin/sonar
     via DaemonLauncher, so a single entrypoint covers both CLI and
     daemon use cases.

Env contract:
  SONAR_NEXUS_BASE          (required) Nexus raw repo base URL, no trailing slash
  SONAR_PREDICTOR_VERSION   (default 0.3.0-SNAPSHOT)
  SONAR_PREDICTOR_HOME      (default $HOME/.sonar-predictor)
  SONAR_PREDICTOR_FORCE=1   re-download even if cached

Nexus path conventions (one sed if your layout differs):
  {base}/sonar-predictor/{version}/sonar-predictor-dist-{version}.zip
  {base}/temurin/21/{os}-{arch}.{tar.gz|zip}

POSIX sh: tested with sh and dash syntax checks. PowerShell: tested via
the language parser. Smoke tests:
  - missing SONAR_NEXUS_BASE -> exit 2 with a clear "required" message
  - unreachable Nexus -> exit 2 with the failing URL surfaced
  - pre-cached bundle -> hands off to bin/sonar (picocli help renders)

Known gap: no checksum verification of the dist zip or JDK archive. The
corporate Nexus is the trust boundary; a SHA pin file can be added later
for defence-in-depth.
@sonarqubecloud
Copy link
Copy Markdown

@aksOps aksOps merged commit 400cf9d into main May 26, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant