ManagerRuntimeBridge.java
package com.cloudforge.core.manager;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
/**
* Framework-neutral bridge that materializes Manager settings into system properties
* when the process environment does not already define them.
*
* <p>Spring Boot, tests, and local launchers supply values through {@code lookup};
* deploy-time container env still wins when present.</p>
*/
public final class ManagerRuntimeBridge {
private ManagerRuntimeBridge() {
}
/**
* Apply resolved settings. {@code lookup} is typically Spring Environment or a Map.
*/
public static void apply(Function<String, String> lookup) {
Objects.requireNonNull(lookup, "lookup");
String target = first(lookup, ManagerEnvKeys.PROP_TARGET, ManagerEnvKeys.TARGET);
setIfAbsent(ManagerEnvKeys.TARGET, target);
setIfAbsent(ManagerEnvKeys.AUTH_MODE, first(lookup, ManagerEnvKeys.PROP_AUTH_MODE, ManagerEnvKeys.AUTH_MODE));
setIfAbsent(ManagerEnvKeys.PUBLIC_URL, first(lookup, ManagerEnvKeys.PROP_PUBLIC_URL, ManagerEnvKeys.PUBLIC_URL));
setIfAbsent(ManagerEnvKeys.BIND, first(lookup, ManagerEnvKeys.PROP_BIND, "server.address", ManagerEnvKeys.BIND));
setIfAbsent(ManagerEnvKeys.PORT, first(lookup, "server.port", ManagerEnvKeys.PORT));
setIfAbsent(ManagerEnvKeys.DB_MODE, first(lookup, ManagerEnvKeys.PROP_DB_MODE, ManagerEnvKeys.DB_MODE));
String awsEndpoint = first(lookup, ManagerEnvKeys.PROP_AWS_ENDPOINT_URL, ManagerEnvKeys.AWS_ENDPOINT_URL);
String localstack = first(lookup, ManagerEnvKeys.PROP_LOCALSTACK_ENDPOINT, ManagerEnvKeys.LOCALSTACK_ENDPOINT);
if (localstack == null) {
localstack = awsEndpoint;
}
String ministack = first(lookup, ManagerEnvKeys.PROP_MINISTACK_ENDPOINT, ManagerEnvKeys.MINISTACK_ENDPOINT);
if (ministack == null) {
ministack = awsEndpoint != null ? awsEndpoint : localstack;
}
// ManagerProperties.Localstack#endpoint defaults to "http://localhost:4566" unconditionally
// (a Java field default, there for LocalStack-target convenience) — that default is not
// the same thing as an explicit "run against a local emulator" instruction, but folding it
// into `localstack` above (via the `if (localstack == null)` fallback, itself only reached
// when nothing else set it either) made it look like one by the time it got here. Both
// LOCALSTACK_ENDPOINT and AWS_ENDPOINT_URL (the AWS SDK's own globally-recognized endpoint
// override — every AWS client built anywhere in this process, Cognito's included, see
// ApplicationOidcAuthenticator, honors the latter) have to be gated on actually targeting a
// local emulator (target=localstack/ministack), not just AWS_ENDPOINT_URL alone —
// ApplicationOidcAuthenticator#resolveLocalEmulatorEndpoint checks LOCALSTACK_ENDPOINT
// FIRST, so gating only AWS_ENDPOINT_URL left that check-order unprotected: Cognito sign-in
// kept silently trying to reach localhost:4566 in a production ECS task with no LocalStack
// anywhere in sight, because LOCALSTACK_ENDPOINT itself was still being bridged
// unconditionally here.
boolean targetingLocalEmulator = "localstack".equalsIgnoreCase(target) || "ministack".equalsIgnoreCase(target);
if (targetingLocalEmulator) {
setIfAbsent(ManagerEnvKeys.LOCALSTACK_ENDPOINT, localstack);
setIfAbsent(ManagerEnvKeys.AWS_ENDPOINT_URL, firstNonBlank(awsEndpoint, localstack));
} else {
// awsEndpoint only (never `localstack`, which may carry the inert convenience default)
// — a genuine, explicitly-set AWS_ENDPOINT_URL/its PROP_ counterpart still bridges
// normally outside a local-emulator target (e.g. a real custom VPC endpoint override).
setIfAbsent(ManagerEnvKeys.LOCALSTACK_ENDPOINT, awsEndpoint);
setIfAbsent(ManagerEnvKeys.AWS_ENDPOINT_URL, awsEndpoint);
}
setIfAbsent(ManagerEnvKeys.AWS_DEFAULT_REGION,
first(lookup, ManagerEnvKeys.PROP_AWS_REGION, ManagerEnvKeys.AWS_DEFAULT_REGION));
if (System.getProperty(ManagerEnvKeys.AWS_DEFAULT_REGION) == null
&& (System.getenv(ManagerEnvKeys.AWS_DEFAULT_REGION) == null
|| System.getenv(ManagerEnvKeys.AWS_DEFAULT_REGION).isBlank())) {
System.setProperty(ManagerEnvKeys.AWS_DEFAULT_REGION, "us-east-1");
}
setIfAbsent(ManagerEnvKeys.MINISTACK_ENDPOINT, ministack);
for (String oidcKey : oidcKeys()) {
setIfAbsent(oidcKey, first(lookup, oidcKey));
}
setIfAbsent(ManagerEnvKeys.OIDC_REDIRECT_URL,
first(lookup, ManagerEnvKeys.PROP_OIDC_REDIRECT_URL, ManagerEnvKeys.OIDC_REDIRECT_URL));
}
/** Snapshot of OIDC-related keys for tests and docs. */
public static Map<String, String> oidcKeyCatalog() {
Map<String, String> map = new LinkedHashMap<>();
for (String key : oidcKeys()) {
map.put(key, key);
}
return map;
}
private static String[] oidcKeys() {
return new String[] {
ManagerEnvKeys.OIDC_ISSUER,
ManagerEnvKeys.OIDC_AUTHORIZATION_ENDPOINT,
ManagerEnvKeys.OIDC_TOKEN_ENDPOINT,
ManagerEnvKeys.OIDC_USERINFO_ENDPOINT,
ManagerEnvKeys.OIDC_JWKS_URI,
ManagerEnvKeys.OIDC_CLIENT_ID,
ManagerEnvKeys.OIDC_CLIENT_SECRET,
ManagerEnvKeys.OIDC_REDIRECT_URL,
ManagerEnvKeys.OIDC_SCOPES,
ManagerEnvKeys.OIDC_USERNAME_CLAIM,
ManagerEnvKeys.OIDC_EMAIL_CLAIM,
ManagerEnvKeys.OIDC_GROUPS_CLAIM,
ManagerEnvKeys.OIDC_ADMIN_GROUP,
ManagerEnvKeys.OIDC_MANAGER_GROUP
};
}
private static String first(Function<String, String> lookup, String... keys) {
for (String key : keys) {
String value = lookup.apply(key);
if (value != null && !value.isBlank()) {
return value.trim();
}
String env = System.getenv(key);
if (env != null && !env.isBlank()) {
return env.trim();
}
String prop = System.getProperty(key);
if (prop != null && !prop.isBlank()) {
return prop.trim();
}
}
return null;
}
private static String firstNonBlank(String... values) {
if (values == null) {
return null;
}
for (String value : values) {
if (value != null && !value.isBlank()) {
return value.trim();
}
}
return null;
}
private static void setIfAbsent(String key, String value) {
if (value == null || value.isBlank()) {
return;
}
String env = System.getenv(key);
if (env != null && !env.isBlank()) {
return;
}
System.setProperty(key, value.trim());
}
}