package com.xfestudio.xfeservermanager.core.policy;
import com.xfestudio.xfeservermanager.api.command.InvocationAst;
import com.xfestudio.xfeservermanager.api.policy.ActorContext;
import com.xfestudio.xfeservermanager.api.policy.DecisionEffect;
import com.xfestudio.xfeservermanager.api.policy.PolicyDecision;
import com.xfestudio.xfeservermanager.api.policy.PolicyEvaluationContext;
import com.xfestudio.xfeservermanager.api.policy.PolicyRule;
import com.xfestudio.xfeservermanager.api.policy.PolicySnapshot;
import com.xfestudio.xfeservermanager.api.policy.PolicyViolation;
import com.xfestudio.xfeservermanager.api.policy.RuleTier;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
/** Deterministic, immutable-snapshot command policy evaluator. */
public final class CommandPolicyEngine {
private static final Comparator<MatchedRule> PRECEDENCE = Comparator
.comparingInt((MatchedRule match) -> match.rule().tier().priority())
.thenComparingInt(MatchedRule::roleWeight)
.thenComparingInt(match -> match.rule().specificity());
private final PolicySnapshotProvider snapshots;
private final ConstraintEvaluator constraints;
public CommandPolicyEngine(PolicySnapshotProvider snapshots) {
this(snapshots, new ConstraintEvaluator());
}
public CommandPolicyEngine(PolicySnapshotProvider snapshots, ConstraintEvaluator constraints) {
this.snapshots = Objects.requireNonNull(snapshots, "snapshots");
this.constraints = Objects.requireNonNull(constraints, "constraints");
}
public PolicyDecision evaluate(PolicyEvaluationContext context) {
Objects.requireNonNull(context, "context");
return evaluate(snapshots.activeSnapshot(), context.actor(), context.invocation(), 0);
}
private PolicyDecision evaluate(
PolicySnapshot snapshot,
ActorContext actor,
InvocationAst invocation,
int depth
) {
if (depth > 32) {
return denied(snapshot.version(), List.of(),
new PolicyViolation("nested_command_depth", "", "Nested command depth exceeds 32"),
"Nested command analysis limit exceeded");
}
List<MatchedRule> matches = snapshot.rules().stream()
.filter(PolicyRule::effectiveEnabled)
.filter(rule -> rule.subject().matches(actor))
.filter(rule -> rule.command().matches(invocation))
.map(rule -> new MatchedRule(rule,
rule.tier() == RuleTier.ROLE ? rule.subject().matchingRoleWeight(actor) : 0))
.toList();
List<MatchedRule> hardRules = matches.stream()
.filter(match -> match.rule().tier() == RuleTier.HARD_SAFETY)
.toList();
List<String> matchedIds = new ArrayList<>();
hardRules.forEach(match -> matchedIds.add(match.rule().id()));
PolicyDecision hardFailure = evaluateLayer(snapshot.version(), hardRules, invocation, matchedIds, true);
if (hardFailure != null) {
return hardFailure;
}
List<MatchedRule> subjectMatches = matches.stream()
.filter(match -> match.rule().tier() != RuleTier.HARD_SAFETY)
.toList();
List<MatchedRule> selected = mostSpecific(subjectMatches);
selected.forEach(match -> matchedIds.add(match.rule().id()));
PolicyDecision layerFailure = evaluateLayer(snapshot.version(), selected, invocation, matchedIds, false);
if (layerFailure != null) {
return layerFailure;
}
DecisionEffect effect = selectEffect(selected, hardRules);
if (effect == DecisionEffect.GRANT && !invocation.semanticsKnown()) {
return denied(snapshot.version(), matchedIds,
new PolicyViolation("unknown_command_elevation", "",
"Commands without known argument semantics cannot receive elevated permission"),
"Unsafe permission elevation was blocked");
}
for (InvocationAst nested : invocation.nestedInvocations()) {
PolicyDecision nestedDecision = evaluate(snapshot, actor, nested, depth + 1);
if (nestedDecision.isDenied()) {
List<PolicyViolation> nestedViolations = new ArrayList<>(nestedDecision.violations());
nestedViolations.add(new PolicyViolation(
"nested_command_denied", "", "Nested command " + nested.commandId() + " was denied"));
List<String> combinedIds = combineIds(matchedIds, nestedDecision.matchedRuleIds());
return new PolicyDecision(DecisionEffect.DENY, snapshot.version(), combinedIds,
nestedViolations, "Nested command policy denied execution");
}
if (effect == DecisionEffect.GRANT && !nestedDecision.grantsPermission()) {
return denied(snapshot.version(), combineIds(matchedIds, nestedDecision.matchedRuleIds()),
new PolicyViolation("nested_command_not_granted", "",
"Every nested command requires an explicit grant when its parent is elevated"),
"Nested command did not receive explicit permission");
}
}
String explanation = switch (effect) {
case PASS_THROUGH -> "No authorizing policy matched; use the platform permission result";
case GRANT -> "An explicit policy grant matched";
case CONSTRAIN -> "Policy constraints passed; use the platform permission result";
case DENY -> throw new IllegalStateException("Denied effects return before this point");
};
return new PolicyDecision(effect, snapshot.version(), matchedIds, List.of(), explanation);
}
/** Returns a denial or null when a layer permits evaluation to continue. */
private PolicyDecision evaluateLayer(
long version,
List<MatchedRule> layer,
InvocationAst invocation,
List<String> allMatchedIds,
boolean hardLayer
) {
if (layer.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.DENY)) {
String explanation = hardLayer ? "A hard safety rule denied the command" : "A policy rule denied the command";
return denied(version, allMatchedIds,
new PolicyViolation("rule_denied", "", explanation), explanation);
}
List<PolicyViolation> violations = layer.stream()
.filter(match -> match.rule().effect() == DecisionEffect.CONSTRAIN
|| match.rule().effect() == DecisionEffect.GRANT)
.flatMap(match -> constraints.evaluate(match.rule().constraints(), invocation).stream())
.distinct()
.toList();
if (!violations.isEmpty()) {
return new PolicyDecision(DecisionEffect.DENY, version, allMatchedIds, violations,
hardLayer ? "A hard safety constraint was violated" : "A command constraint was violated");
}
return null;
}
private static List<MatchedRule> mostSpecific(List<MatchedRule> matches) {
MatchedRule best = matches.stream().max(PRECEDENCE).orElse(null);
if (best == null) {
return List.of();
}
return matches.stream().filter(candidate -> PRECEDENCE.compare(candidate, best) == 0).toList();
}
private static DecisionEffect selectEffect(List<MatchedRule> selected, List<MatchedRule> hardRules) {
if (selected.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.GRANT)) {
return DecisionEffect.GRANT;
}
if (selected.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.CONSTRAIN)
|| hardRules.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.CONSTRAIN)) {
return DecisionEffect.CONSTRAIN;
}
return DecisionEffect.PASS_THROUGH;
}
private static PolicyDecision denied(
long version, List<String> ruleIds, PolicyViolation violation, String explanation) {
return new PolicyDecision(DecisionEffect.DENY, version, ruleIds, List.of(violation), explanation);
}
private static List<String> combineIds(List<String> first, List<String> second) {
List<String> result = new ArrayList<>(first);
second.stream().filter(id -> !result.contains(id)).forEach(result::add);
return result;
}
private record MatchedRule(PolicyRule rule, int roleWeight) {
}
}
package com.xfestudio.xfeservermanager.core.policy;
import com.xfestudio.xfeservermanager.api.command.InvocationAst;
import com.xfestudio.xfeservermanager.api.policy.ActorContext;
import com.xfestudio.xfeservermanager.api.policy.DecisionEffect;
import com.xfestudio.xfeservermanager.api.policy.PolicyDecision;
import com.xfestudio.xfeservermanager.api.policy.PolicyEvaluationContext;
import com.xfestudio.xfeservermanager.api.policy.PolicyRule;
import com.xfestudio.xfeservermanager.api.policy.PolicySnapshot;
import com.xfestudio.xfeservermanager.api.policy.PolicyViolation;
import com.xfestudio.xfeservermanager.api.policy.RuleTier;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
/** Deterministic, immutable-snapshot command policy evaluator. */
public final class CommandPolicyEngine {
private static final Comparator<MatchedRule> PRECEDENCE = Comparator
.comparingInt((MatchedRule match) -> match.rule().tier().priority())
.thenComparingInt(MatchedRule::roleWeight)
.thenComparingInt(match -> match.rule().specificity());
private final PolicySnapshotProvider snapshots;
private final ConstraintEvaluator constraints;
public CommandPolicyEngine(PolicySnapshotProvider snapshots) {
this(snapshots, new ConstraintEvaluator());
}
public CommandPolicyEngine(PolicySnapshotProvider snapshots, ConstraintEvaluator constraints) {
this.snapshots = Objects.requireNonNull(snapshots, "snapshots");
this.constraints = Objects.requireNonNull(constraints, "constraints");
}
public PolicyDecision evaluate(PolicyEvaluationContext context) {
Objects.requireNonNull(context, "context");
return evaluate(snapshots.activeSnapshot(), context.actor(), context.invocation(), 0);
}
private PolicyDecision evaluate(
PolicySnapshot snapshot,
ActorContext actor,
InvocationAst invocation,
int depth
) {
if (depth > 32) {
return denied(snapshot.version(), List.of(),
new PolicyViolation("nested_command_depth", "", "Nested command depth exceeds 32"),
"Nested command analysis limit exceeded");
}
List<MatchedRule> matches = snapshot.rules().stream()
.filter(PolicyRule::effectiveEnabled)
.filter(rule -> rule.subject().matches(actor))
.filter(rule -> rule.command().matches(invocation))
.map(rule -> new MatchedRule(rule,
rule.tier() == RuleTier.ROLE ? rule.subject().matchingRoleWeight(actor) : 0))
.toList();
List<MatchedRule> hardRules = matches.stream()
.filter(match -> match.rule().tier() == RuleTier.HARD_SAFETY)
.toList();
List<String> matchedIds = new ArrayList<>();
hardRules.forEach(match -> matchedIds.add(match.rule().id()));
PolicyDecision hardFailure = evaluateLayer(snapshot.version(), hardRules, invocation, matchedIds, true);
if (hardFailure != null) {
return hardFailure;
}
List<MatchedRule> subjectMatches = matches.stream()
.filter(match -> match.rule().tier() != RuleTier.HARD_SAFETY)
.toList();
List<MatchedRule> selected = mostSpecific(subjectMatches);
selected.forEach(match -> matchedIds.add(match.rule().id()));
PolicyDecision layerFailure = evaluateLayer(snapshot.version(), selected, invocation, matchedIds, false);
if (layerFailure != null) {
return layerFailure;
}
DecisionEffect effect = selectEffect(selected, hardRules);
if (effect == DecisionEffect.GRANT && !invocation.semanticsKnown()) {
return denied(snapshot.version(), matchedIds,
new PolicyViolation("unknown_command_elevation", "",
"Commands without known argument semantics cannot receive elevated permission"),
"Unsafe permission elevation was blocked");
}
for (InvocationAst nested : invocation.nestedInvocations()) {
PolicyDecision nestedDecision = evaluate(snapshot, actor, nested, depth + 1);
if (nestedDecision.isDenied()) {
List<PolicyViolation> nestedViolations = new ArrayList<>(nestedDecision.violations());
nestedViolations.add(new PolicyViolation(
"nested_command_denied", "", "Nested command " + nested.commandId() + " was denied"));
List<String> combinedIds = combineIds(matchedIds, nestedDecision.matchedRuleIds());
return new PolicyDecision(DecisionEffect.DENY, snapshot.version(), combinedIds,
nestedViolations, "Nested command policy denied execution");
}
if (effect == DecisionEffect.GRANT && !nestedDecision.grantsPermission()) {
return denied(snapshot.version(), combineIds(matchedIds, nestedDecision.matchedRuleIds()),
new PolicyViolation("nested_command_not_granted", "",
"Every nested command requires an explicit grant when its parent is elevated"),
"Nested command did not receive explicit permission");
}
}
String explanation = switch (effect) {
case PASS_THROUGH -> "No authorizing policy matched; use the platform permission result";
case GRANT -> "An explicit policy grant matched";
case CONSTRAIN -> "Policy constraints passed; use the platform permission result";
case DENY -> throw new IllegalStateException("Denied effects return before this point");
};
return new PolicyDecision(effect, snapshot.version(), matchedIds, List.of(), explanation);
}
/** Returns a denial or null when a layer permits evaluation to continue. */
private PolicyDecision evaluateLayer(
long version,
List<MatchedRule> layer,
InvocationAst invocation,
List<String> allMatchedIds,
boolean hardLayer
) {
if (layer.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.DENY)) {
String explanation = hardLayer ? "A hard safety rule denied the command" : "A policy rule denied the command";
return denied(version, allMatchedIds,
new PolicyViolation("rule_denied", "", explanation), explanation);
}
List<PolicyViolation> violations = layer.stream()
.filter(match -> match.rule().effect() == DecisionEffect.CONSTRAIN
|| match.rule().effect() == DecisionEffect.GRANT)
.flatMap(match -> constraints.evaluate(match.rule().constraints(), invocation).stream())
.distinct()
.toList();
if (!violations.isEmpty()) {
return new PolicyDecision(DecisionEffect.DENY, version, allMatchedIds, violations,
hardLayer ? "A hard safety constraint was violated" : "A command constraint was violated");
}
return null;
}
private static List<MatchedRule> mostSpecific(List<MatchedRule> matches) {
MatchedRule best = matches.stream().max(PRECEDENCE).orElse(null);
if (best == null) {
return List.of();
}
return matches.stream().filter(candidate -> PRECEDENCE.compare(candidate, best) == 0).toList();
}
private static DecisionEffect selectEffect(List<MatchedRule> selected, List<MatchedRule> hardRules) {
if (selected.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.GRANT)) {
return DecisionEffect.GRANT;
}
if (selected.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.CONSTRAIN)
|| hardRules.stream().anyMatch(match -> match.rule().effect() == DecisionEffect.CONSTRAIN)) {
return DecisionEffect.CONSTRAIN;
}
return DecisionEffect.PASS_THROUGH;
}
private static PolicyDecision denied(
long version, List<String> ruleIds, PolicyViolation violation, String explanation) {
return new PolicyDecision(DecisionEffect.DENY, version, ruleIds, List.of(violation), explanation);
}
private static List<String> combineIds(List<String> first, List<String> second) {
List<String> result = new ArrayList<>(first);
second.stream().filter(id -> !result.contains(id)).forEach(result::add);
return result;
}
private record MatchedRule(PolicyRule rule, int roleWeight) {
}
}