refactor(license): extract cameleer-license-api module from server-core
Splits the pure license contract types (LicenseInfo, LicenseValidator, LicenseState, LicenseStateMachine, LicenseLimits, DefaultTierLimits) into a new cameleer-license-api module under package com.cameleer.license. Why: cameleer-license-minter previously depended on cameleer-server-core for these types, dragging cameleer-server-core + cameleer-common onto the classpath of every minter consumer (notably cameleer-saas). The SaaS management plane has no business carrying server-runtime types — it only needs the license contract to mint and verify tokens. After: cameleer-license-minter -> cameleer-license-api (no server internals) cameleer-server-core -> cameleer-license-api cameleer-saas -> cameleer-license-minter -> cameleer-license-api Verified: mvn -pl cameleer-license-minter dependency:tree shows the minter no longer pulls cameleer-server-core or cameleer-common. Full reactor verify (-DskipITs) green: 371 tests pass. LicenseGate stays in server-core (server-runtime state holder, not contract). Closes cameleer/cameleer-server#156 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,14 +47,19 @@ paths:
|
||||
|
||||
## license/ — License domain (signed-token tier system)
|
||||
|
||||
The pure license **contract types** live in the separate `cameleer-license-api` module under package `com.cameleer.license` (no Spring, no server-runtime deps) so consumers like `cameleer-license-minter` and `cameleer-saas` can use them without inheriting server internals. Server-core only contains the runtime state holder (`LicenseGate`).
|
||||
|
||||
Contract types in `cameleer-license-api` (package `com.cameleer.license`):
|
||||
- `LicenseInfo` — record: `(UUID licenseId, String tenantId, String label, Map<String,Integer> limits, Instant issuedAt, Instant expiresAt, int gracePeriodDays)`. `isExpired()` true once `now > expiresAt + gracePeriodDays`; `isAfterRawExpiry()` true once `now > expiresAt`. Constructed via `LicenseValidator`; canonical ctor null-checks all required fields and rejects blank tenantId / negative grace.
|
||||
- `LicenseLimits` — typed limits container backed by `Map<String,Integer>`. `defaultsOnly()` returns the `DefaultTierLimits.DEFAULTS` view; `mergeOverDefaults(overrides)` produces the license-overrides UNION default tier. `get(String key)` returns the cap; throws `IllegalArgumentException` for unknown keys (programmer error). `isDefaultSourced(key, license)` reports whether a key fell through to the default tier.
|
||||
- `DefaultTierLimits` — immutable `LinkedHashMap` of constants for the no-license fallback tier: `max_environments=1, max_apps=3, max_agents=5, max_users=3, max_outbound_connections=1, max_alert_rules=2, max_total_cpu_millis=2000, max_total_memory_mb=2048, max_total_replicas=5, max_execution_retention_days=1, max_log_retention_days=1, max_metric_retention_days=1, max_jar_retention_count=3`.
|
||||
- `LicenseValidator` — verifies signed token. Constructor `(String publicKeyBase64, String expectedTenantId)` decodes an X.509 Ed25519 public key. `validate(String token)` splits `payload.signature`, verifies the Ed25519 signature, parses the JSON payload, enforces `tenantId == expectedTenantId`, and returns `LicenseInfo`. Throws `SecurityException` on signature mismatch / `IllegalArgumentException` on parse failure / expired payload.
|
||||
- `LicenseGate` — runtime state holder (thread-safe via `AtomicReference<Snapshot>`). `getCurrent()` returns the current `LicenseInfo` (null when ABSENT/INVALID); `getState()` delegates to `LicenseStateMachine.classify(...)`; `getEffectiveLimits()` returns license-overrides UNION defaults in `ACTIVE`/`GRACE`, defaults-only otherwise. `getInvalidReason()`, `load(LicenseInfo)`, `markInvalid(String reason)`, `clear()` are the mutators. `getLimit(key, defaultValue)` shorthand swallows unknown-key errors.
|
||||
- `LicenseStateMachine` — pure classifier. `classify(LicenseInfo, String invalidReason)` returns `INVALID` if a reason is set, `ABSENT` if no license, `ACTIVE` if `now <= expiresAt`, `GRACE` if expired but within grace window, `EXPIRED` otherwise.
|
||||
- `LicenseState` — enum: `ABSENT, ACTIVE, GRACE, EXPIRED, INVALID`.
|
||||
|
||||
Runtime state holder in server-core (package `com.cameleer.server.core.license`):
|
||||
- `LicenseGate` — runtime state holder (thread-safe via `AtomicReference<Snapshot>`). `getCurrent()` returns the current `LicenseInfo` (null when ABSENT/INVALID); `getState()` delegates to `LicenseStateMachine.classify(...)`; `getEffectiveLimits()` returns license-overrides UNION defaults in `ACTIVE`/`GRACE`, defaults-only otherwise. `getInvalidReason()`, `load(LicenseInfo)`, `markInvalid(String reason)`, `clear()` are the mutators. `getLimit(key, defaultValue)` shorthand swallows unknown-key errors.
|
||||
|
||||
## search/ — Execution search and stats
|
||||
|
||||
- `SearchService` — search, count, stats, statsForApp, statsForRoute, timeseries, timeseriesForApp, timeseriesForRoute, timeseriesGroupedByApp, timeseriesGroupedByRoute, slaCompliance, slaCountsByApp, slaCountsByRoute, topErrors, activeErrorTypes, punchcard, distinctAttributeKeys. `statsForRoute`/`timeseriesForRoute` take `(routeId, applicationId)` — app filter is applied to `stats_1m_route`.
|
||||
|
||||
@@ -14,8 +14,10 @@ Cameleer Server — observability server that receives, stores, and serves Camel
|
||||
|
||||
## Modules
|
||||
|
||||
- `cameleer-license-api` — pure license contract types (`LicenseInfo`, `LicenseValidator`, `LicenseState`, `LicenseStateMachine`, `LicenseLimits`, `DefaultTierLimits`) under package `com.cameleer.license`. No Spring or server-runtime deps; consumed by `cameleer-server-core` (validation/runtime gate) and `cameleer-license-minter` (vendor signing) — and transitively by `cameleer-saas` via the minter — without inheriting server internals.
|
||||
- `cameleer-server-core` — domain logic, storage interfaces, services (no Spring dependencies)
|
||||
- `cameleer-server-app` — Spring Boot web app, REST controllers, SSE, persistence, Docker orchestration
|
||||
- `cameleer-license-minter` — vendor-only Ed25519 license signing library + CLI. Depends only on `cameleer-license-api` so consumers don't pull in `cameleer-server-core`.
|
||||
|
||||
## Build Commands
|
||||
|
||||
|
||||
54
cameleer-license-api/pom.xml
Normal file
54
cameleer-license-api/pom.xml
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.cameleer</groupId>
|
||||
<artifactId>cameleer-server-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>cameleer-license-api</artifactId>
|
||||
<name>Cameleer License API</name>
|
||||
<description>Pure license contract types — LicenseInfo, LicenseValidator, LicenseState, LicenseStateMachine, LicenseLimits, DefaultTierLimits. Shared by server-core (validation/runtime gate) and cameleer-license-minter (vendor-side signing). Has no Spring or server-runtime dependencies so consumers like cameleer-saas can depend on the minter without inheriting server internals.</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<!-- Plain library JAR — no repackage. -->
|
||||
<execution>
|
||||
<id>repackage</id>
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
public enum LicenseState {
|
||||
ABSENT,
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
public final class LicenseStateMachine {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.cameleer.server.core.license;
|
||||
package com.cameleer.license;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -58,7 +58,7 @@ Two JARs land in `cameleer-license-minter/target/`:
|
||||
|
||||
```java
|
||||
import com.cameleer.license.minter.LicenseMinter;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
|
||||
LicenseInfo info = new LicenseInfo(
|
||||
java.util.UUID.randomUUID(),
|
||||
@@ -136,11 +136,11 @@ base64(canonicalJson) + "." + base64(ed25519Signature)
|
||||
- The signature is computed with `Signature.getInstance("Ed25519")` over the canonical payload bytes (not over the base64-encoded form).
|
||||
- Encoding is `Base64.getEncoder()` (RFC 4648 §4 — *not* base64url). The validator decodes with the matching `Base64.getDecoder()`.
|
||||
|
||||
`LicenseValidator.validate(...)` (`cameleer-server-core/src/main/java/com/cameleer/server/core/license/LicenseValidator.java:42`) splits on the first `.`, decodes both halves, verifies the signature, then deserializes the payload.
|
||||
`LicenseValidator.validate(...)` (`cameleer-license-api/src/main/java/com/cameleer/license/LicenseValidator.java:42`) splits on the first `.`, decodes both halves, verifies the signature, then deserializes the payload.
|
||||
|
||||
## LicenseInfo schema
|
||||
|
||||
Source: `cameleer-server-core/src/main/java/com/cameleer/server/core/license/LicenseInfo.java`. Field-by-field:
|
||||
Source: `cameleer-license-api/src/main/java/com/cameleer/license/LicenseInfo.java`. Field-by-field:
|
||||
|
||||
| Field | Type | Required | Semantics |
|
||||
|---|---|---|---|
|
||||
@@ -154,7 +154,7 @@ Source: `cameleer-server-core/src/main/java/com/cameleer/server/core/license/Lic
|
||||
|
||||
## Limits dictionary
|
||||
|
||||
Canonical key set: `cameleer-server-core/src/main/java/com/cameleer/server/core/license/DefaultTierLimits.java`. Any key not listed here is silently ignored by the server's `LicenseGate.getEffectiveLimits()`.
|
||||
Canonical key set: `cameleer-license-api/src/main/java/com/cameleer/license/DefaultTierLimits.java`. Any key not listed here is silently ignored by the server's `LicenseGate.getEffectiveLimits()`.
|
||||
|
||||
| CLI flag | Key | Default | What the server enforces |
|
||||
|---|---|---|---|
|
||||
@@ -284,4 +284,4 @@ mvn -pl cameleer-server-app dependency:tree | grep license-minter
|
||||
# expected: empty output (or, in development branches, a single line scoped 'test')
|
||||
```
|
||||
|
||||
`cameleer-license-minter/pom.xml` depends on `cameleer-server-core` for `LicenseInfo` and the validator round-trip used by `--verify`. The server app intentionally does not depend on the minter — vendors mint outside the customer-deployed runtime, and a compromised customer cannot leverage server code to forge tokens.
|
||||
`cameleer-license-minter/pom.xml` depends on `cameleer-license-api` for the pure license contract types (`LicenseInfo`, `LicenseValidator`) used by mint + `--verify`. It deliberately does **not** depend on `cameleer-server-core`, so consumers of the minter (e.g. `cameleer-saas`) do not inherit server-runtime types onto their classpath. The server app intentionally does not depend on the minter — vendors mint outside the customer-deployed runtime, and a compromised customer cannot leverage server code to forge tokens.
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.cameleer</groupId>
|
||||
<artifactId>cameleer-server-core</artifactId>
|
||||
<artifactId>cameleer-license-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.cameleer.license.minter;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.license.minter.cli;
|
||||
|
||||
import com.cameleer.license.minter.LicenseMinter;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
@@ -107,7 +107,7 @@ public final class LicenseMinterCli {
|
||||
}
|
||||
try {
|
||||
String pubB64 = Files.readString(Path.of(pubPath)).trim();
|
||||
new com.cameleer.server.core.license.LicenseValidator(pubB64, tenant).validate(token);
|
||||
new com.cameleer.license.LicenseValidator(pubB64, tenant).validate(token);
|
||||
out.println("verified ok");
|
||||
} catch (Exception ve) {
|
||||
err.println("VERIFY FAILED: " + ve.getMessage());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.license.minter;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseValidator;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseValidator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.security.KeyPair;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package com.cameleer.license.minter.cli;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseValidator;
|
||||
import com.cameleer.license.LicenseValidator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.cameleer.server.app.license.LicenseRepository;
|
||||
import com.cameleer.server.app.license.LicenseService;
|
||||
import com.cameleer.server.core.admin.AuditService;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseValidator;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseValidator;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.cameleer.server.app.controller;
|
||||
import com.cameleer.server.app.license.LicenseRepository;
|
||||
import com.cameleer.server.app.license.LicenseService;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package com.cameleer.server.app.license;
|
||||
import com.cameleer.server.core.admin.AuditCategory;
|
||||
import com.cameleer.server.core.admin.AuditResult;
|
||||
import com.cameleer.server.core.admin.AuditService;
|
||||
import com.cameleer.license.LicenseLimits;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseLimits;
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import io.micrometer.core.instrument.Gauge;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
@@ -3,9 +3,9 @@ package com.cameleer.server.app.license;
|
||||
import com.cameleer.server.core.admin.AuditCategory;
|
||||
import com.cameleer.server.core.admin.AuditResult;
|
||||
import com.cameleer.server.core.admin.AuditService;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseValidator;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseLimits;
|
||||
import com.cameleer.license.LicenseLimits;
|
||||
import com.cameleer.server.core.runtime.Environment;
|
||||
import com.cameleer.server.core.runtime.EnvironmentRepository;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
@@ -2,7 +2,7 @@ package com.cameleer.server.app;
|
||||
|
||||
import com.cameleer.server.core.agent.AgentRegistryService;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.server.core.security.JwtService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
|
||||
@@ -22,7 +22,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Verifies that the {@code max_alert_rules} cap from the default tier is enforced at
|
||||
* {@code POST /api/v1/environments/{envSlug}/alerts/rules}. Default tier
|
||||
* {@code max_alert_rules = 2}; with no license installed the gate is in
|
||||
* {@link com.cameleer.server.core.license.LicenseState#ABSENT} and the defaults are
|
||||
* {@link com.cameleer.license.LicenseState#ABSENT} and the defaults are
|
||||
* authoritative. The first two creates succeed; the third must be rejected with the
|
||||
* structured 403 envelope produced by {@link LicenseExceptionAdvice}.
|
||||
*/
|
||||
|
||||
@@ -19,7 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
/**
|
||||
* Verifies that the {@code max_apps} cap from the default tier is enforced at
|
||||
* {@code POST /api/v1/environments/{envSlug}/apps}. Default tier {@code max_apps = 3}; with no
|
||||
* license installed the gate is in {@link com.cameleer.server.core.license.LicenseState#ABSENT}
|
||||
* license installed the gate is in {@link com.cameleer.license.LicenseState#ABSENT}
|
||||
* and the defaults are authoritative. The fourth create attempt must be rejected with the
|
||||
* structured 403 envelope produced by {@link LicenseExceptionAdvice}.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.cameleer.license.minter.LicenseMinter;
|
||||
import com.cameleer.server.app.AbstractPostgresIT;
|
||||
import com.cameleer.server.app.TestSecurityHelper;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import com.cameleer.server.core.admin.AuditCategory;
|
||||
import com.cameleer.server.core.admin.AuditResult;
|
||||
import com.cameleer.server.core.admin.AuditService;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.server.core.license.LicenseValidator;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import com.cameleer.license.LicenseValidator;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
|
||||
@@ -20,7 +20,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* Verifies that the {@code max_outbound_connections} cap from the default tier is enforced at
|
||||
* {@code POST /api/v1/admin/outbound-connections}. Default tier
|
||||
* {@code max_outbound_connections = 1}; with no license installed the gate is in
|
||||
* {@link com.cameleer.server.core.license.LicenseState#ABSENT} and the defaults are
|
||||
* {@link com.cameleer.license.LicenseState#ABSENT} and the defaults are
|
||||
* authoritative. The first create succeeds; the second must be rejected with the structured
|
||||
* 403 envelope produced by {@link LicenseExceptionAdvice}.
|
||||
*/
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.cameleer.server.app.license;
|
||||
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseInfo;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import com.cameleer.server.core.runtime.Environment;
|
||||
import com.cameleer.server.core.runtime.EnvironmentRepository;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.cameleer.server.app.license;
|
||||
import com.cameleer.server.app.AbstractPostgresIT;
|
||||
import com.cameleer.server.app.TestSecurityHelper;
|
||||
import com.cameleer.server.core.license.LicenseGate;
|
||||
import com.cameleer.server.core.license.LicenseState;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
<description>Domain logic, storage, and agent registry</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.cameleer</groupId>
|
||||
<artifactId>cameleer-license-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cameleer</groupId>
|
||||
<artifactId>cameleer-common</artifactId>
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.cameleer.server.core.license;
|
||||
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseLimits;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import com.cameleer.license.LicenseStateMachine;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.cameleer.server.core.license;
|
||||
|
||||
import com.cameleer.license.DefaultTierLimits;
|
||||
import com.cameleer.license.LicenseInfo;
|
||||
import com.cameleer.license.LicenseState;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.Instant;
|
||||
6
pom.xml
6
pom.xml
@@ -20,6 +20,7 @@
|
||||
<description>Observability server for Cameleer agents</description>
|
||||
|
||||
<modules>
|
||||
<module>cameleer-license-api</module>
|
||||
<module>cameleer-server-core</module>
|
||||
<module>cameleer-server-app</module>
|
||||
<module>cameleer-license-minter</module>
|
||||
@@ -40,6 +41,11 @@
|
||||
<artifactId>cameleer-common</artifactId>
|
||||
<version>${cameleer-common.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cameleer</groupId>
|
||||
<artifactId>cameleer-license-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.cameleer</groupId>
|
||||
<artifactId>cameleer-server-core</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user