Skip to main content

juneau-sc-server

Maven
<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-sc-server</artifactId>
<version>${juneau.version}</version>
</dependency>
Jarjuneau-sc-server-10.0.0.jar
LinksMaven Central · Javadocs · Source

Contents/Features​

juneau-sc-server is the server component of the juneau-sc configuration server. It is a standalone Juneau microservice built on juneau-microservice-jetty that:

  • Clones or pulls a remote Git repository containing .cfg files.
  • Exposes those files over a REST API at GET /configs/{project}/{branch}.
  • Returns a JSON map containing up to two configuration layers: a shared APPLICATION default and a PROJECT-specific override.

The server depends on JGit for Git operations and on juneau-rest-server / juneau-microservice-jetty for the REST layer.

Package overview​

The juneau-sc-server module consists of the following classes:

org.apache.juneau.server.config - PackageApp - Executable entry-point that boots the microservice with the Jetty and application configurations.org.apache.juneau.server.config.rest - PackageLoadConfigResource - @Rest(path="/configs/*") servlet exposing GET /{project}/{branch}.org.apache.juneau.server.config.repository - PackageGetConfiguration - Command that clones/pulls the repo and loads the APPLICATION and PROJECT config files.GitControl - JGit wrapper for clone / pull / checkout / commit / push operations.ConfigItem - JSON-serializable holder for a single config file's raw text.Command - Interface for an executable repository command.GetValue - Callback interface returning a value after execution.

Running the Server​

The server is launched as a standard executable jar:

public class App {

public static void main(String[] args) throws Exception {
Microservice
.create()
.args(args)
.configurations(JettyConfiguration.class, AppConfig.class)
.build()
.start()
.startConsole()
.join();
}

@Configuration
public static class AppConfig {

@Bean
public Servlet loadConfigResource() {
return new LoadConfigResource();
}
}
}

The LoadConfigResource servlet is automatically mounted by Jetty at the path declared by its @Rest(path="/configs/*") annotation.

Server Configuration File​

The server reads its own settings from a juneau-server-config.cfg file located in the working directory. The most important section is [GitServer]:

[Jetty]
# Port(s) to listen on — first available wins; 0 = random
port = 10000,0,0,0

[GitServer]
# Local filesystem path where the repo will be cloned
pathLocal = /var/lib/juneau-sc/config-repo

# Remote Git repository URI
gitRemote = https://github.com/my-org/my-config-repo.git

On each request the server:

  1. Checks whether pathLocal exists.
    • If not, it runs a git clone of gitRemote into that directory.
    • If yes, it runs a git pull.
  2. Checks out the requested branch (git checkout origin/{branch}).
  3. Reads application.cfg (shared defaults) and {project}.cfg (project override) from the local clone.

REST Endpoint​

GET /configs/{project}/{branch}
SegmentDescription
{project}Name of the project; the server looks for {project}.cfg in the repo root.
{branch}Git branch to check out before reading files.

Success response — 200 OK, Content-Type: application/json:

{
"APPLICATION": {
"value": "<raw text of application.cfg>"
},
"PROJECT": {
"value": "<raw text of {project}.cfg>"
}
}

If application.cfg is absent, the APPLICATION key is omitted.
If {project}.cfg is absent, the PROJECT key is omitted.

Example:

curl http://localhost:10000/configs/my-service/main

Security Considerations​

The current implementation does not perform authentication or authorisation on the /configs endpoint. Before exposing it outside a trusted network, consider:

  • Adding HTTP Basic Auth or OAuth via a Juneau RestGuard (wired through @Rest(guards=...)) or a servlet filter.
  • Restricting access at the network layer (firewall rules, service mesh policy).
  • Storing Git credentials outside the config file (environment variables or a secrets manager) rather than hard-coding them.

GitControl itself does not hardcode credentials — its 5-argument constructor (GitControl(localPath, remotePath, username, password, forcePush)) takes them as caller-supplied parameters, and the 2-argument constructor defaults to anonymous transport with force-push disabled. The residual risk is entirely at the call site: anything that wires up GitControl (e.g. an AppConfig/App.java bean method) can still reintroduce the original problem by passing literal credential strings:

// Unsafe — literal credentials checked into source control.
new GitControl(pathLocal, gitRemote, "svc-account", "hardcoded-token", false);

// Safe — credentials sourced from the environment (or a secrets manager) at startup, never committed.
new GitControl(pathLocal, gitRemote, System.getenv("GIT_USERNAME"), System.getenv("GIT_TOKEN"), false);

For the strongest option, GitControl also has a constructor that resolves the password/token from a pluggable SecretStore: the secret is looked up by key from the store resolved off a BeanStore (defaulting to an in-memory store), held as a char[] rather than a String, and zeroed when the GitControl is closed. Contribute an EnvVarSecretStore, an OS-keychain-backed store, or your own secrets-manager adapter to keep the token out of both source and the checked-in juneau-server-config.cfg:

// Safest — the token never appears as a literal or a String; it comes from the contributed SecretStore.
BeanStore beanStore = new BasicBeanStore().addBean(SecretStore.class, new EnvVarSecretStore());
new GitControl(pathLocal, gitRemote, "svc-account", "GIT_TOKEN", beanStore, false);

Never hardcode the username/password arguments in application code or in the checked-in juneau-server-config.cfg.

See Also​