Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .local.env
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
SENTRIUS_VERSION=1.1.178
SENTRIUS_SSH_VERSION=1.1.33
SENTRIUS_KEYCLOAK_VERSION=1.1.46
SENTRIUS_AGENT_VERSION=1.1.33
SENTRIUS_AI_AGENT_VERSION=1.1.60
LLMPROXY_VERSION=1.0.43
LAUNCHER_VERSION=1.0.50
AGENTPROXY_VERSION=1.0.63
SENTRIUS_VERSION=1.1.193
SENTRIUS_SSH_VERSION=1.1.35
SENTRIUS_KEYCLOAK_VERSION=1.1.47
SENTRIUS_AGENT_VERSION=1.1.34
SENTRIUS_AI_AGENT_VERSION=1.1.64
LLMPROXY_VERSION=1.0.46
LAUNCHER_VERSION=1.0.51
AGENTPROXY_VERSION=1.0.66
16 changes: 8 additions & 8 deletions .local.env.bak
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
SENTRIUS_VERSION=1.1.178
SENTRIUS_SSH_VERSION=1.1.33
SENTRIUS_KEYCLOAK_VERSION=1.1.46
SENTRIUS_AGENT_VERSION=1.1.33
SENTRIUS_AI_AGENT_VERSION=1.1.60
LLMPROXY_VERSION=1.0.43
LAUNCHER_VERSION=1.0.50
AGENTPROXY_VERSION=1.0.63
SENTRIUS_VERSION=1.1.193
SENTRIUS_SSH_VERSION=1.1.35
SENTRIUS_KEYCLOAK_VERSION=1.1.47
SENTRIUS_AGENT_VERSION=1.1.34
SENTRIUS_AI_AGENT_VERSION=1.1.64
LLMPROXY_VERSION=1.0.46
LAUNCHER_VERSION=1.0.51
AGENTPROXY_VERSION=1.0.66
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package io.sentrius.agent.analysis.agents.agents;

import java.lang.reflect.Method;
import java.util.List;
import io.sentrius.sso.core.dto.capabilities.ParameterDescriptor;
import io.sentrius.sso.core.model.verbs.DefaultInterpreter;
import io.sentrius.sso.core.model.verbs.InputInterpreterIfc;
import io.sentrius.sso.core.model.verbs.OutputInterpreterIfc;
Expand All @@ -13,6 +15,8 @@ public class AgentVerb {
private String name;
private String description;
private Method method;
private List<ParameterDescriptor> paramDescriptions;
private boolean isAiCallable = true;
@Builder.Default
private boolean requiresTokenManagement = false;
@Builder.Default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {

verbRegistry.scanClasspath();


var keyPair = agentKeyService.getKeyPair();

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import com.fasterxml.jackson.databind.node.ArrayNode;
import io.sentrius.agent.analysis.agents.verbs.AgentVerbs;
import io.sentrius.agent.analysis.api.AgentKeyService;
import io.sentrius.agent.config.AgentConfigOptions;
import io.sentrius.sso.core.dto.ztat.AgentExecution;
import io.sentrius.sso.core.dto.ztat.ZtatRequestDTO;
import io.sentrius.sso.core.exceptions.ZtatException;
Expand All @@ -14,6 +17,7 @@
import io.sentrius.sso.core.services.agents.AgentExecutionService;
import io.sentrius.sso.core.services.agents.ZeroTrustClientService;
import io.sentrius.sso.core.dto.UserDTO;
import io.sentrius.sso.core.services.security.KeycloakService;
import io.sentrius.sso.core.utils.JsonUtil;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
Expand All @@ -35,6 +39,9 @@ public class RegisteredAgent implements ApplicationListener<ApplicationReadyEven
final VerbRegistry verbRegistry;
final AgentVerbs agentVerbs;
final AgentExecutionService agentExecutionService;
final AgentConfigOptions agentConfigOptions;
final AgentKeyService agentKeyService;
private final KeycloakService keycloakService;

private volatile boolean running = true;
private Thread workerThread;
Expand Down Expand Up @@ -70,10 +77,12 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {

verbRegistry.scanClasspath();

final UserDTO user = UserDTO.builder()
UserDTO user = UserDTO.builder()
.username(zeroTrustClientService.getUsername())
.build();
var execution = agentExecutionService.getAgentExecution(user);

var keyPair = agentKeyService.getKeyPair();
try {
agentClientService.heartbeat(execution, execution.getUser().getUsername());
} catch (ZtatException e) {
Expand Down Expand Up @@ -101,15 +110,16 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
}
}

UserDTO finalUser = user;
workerThread = new Thread(() -> {
try {

log.info("Username: {}", user.getUsername());
log.info("Username: {}", finalUser.getUsername());
log.info("Registering v1.0.2 agent...");



var agentExecution = agentExecutionService.getAgentExecution(user);
var agentExecution = agentExecutionService.getAgentExecution(finalUser);
var response = promptAgent(agentExecution);
while (running) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@

import io.github.classgraph.ClassGraph;
import io.github.classgraph.ScanResult;
import io.sentrius.sso.core.dto.capabilities.EndpointDescriptor;
import io.sentrius.agent.discovery.AgentEndpointDiscoveryService;
import io.sentrius.sso.core.dto.ztat.AgentExecution;
import io.sentrius.sso.core.dto.ztat.ZtatRequestDTO;
import io.sentrius.sso.core.exceptions.ZtatException;
import io.sentrius.sso.core.model.verbs.OutputInterpreterIfc;
import io.sentrius.sso.core.model.verbs.Verb;
import io.sentrius.sso.core.model.verbs.VerbResponse;
import io.sentrius.sso.core.services.agents.ZeroTrustClientService;
import io.sentrius.sso.core.services.capabilities.EndpointScanningService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
Expand All @@ -18,8 +21,10 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
Expand All @@ -29,10 +34,14 @@ public class VerbRegistry {
private final ApplicationContext applicationContext;

private final ZeroTrustClientService zeroTrustClientService;

private final EndpointScanningService endpointScanningService;

private final Map<String, AgentVerb> verbs = new HashMap<>();
private final Map<String, Object> instances = new HashMap<>();

private final AgentEndpointDiscoveryService agentEndpointDiscoveryService;

public void scanClasspath() {
// Scan the classpath for classes with the @Verb annotation
synchronized (this) {
Expand Down Expand Up @@ -167,4 +176,30 @@ public VerbResponse execute(AgentExecution agentExecution, VerbResponse priorRes
public Map<String, AgentVerb> getVerbs() {
return new HashMap<>(verbs);
}

/**
* Gets endpoint descriptors for all registered verbs.
* This provides integration with the centralized endpoint scanning system.
*/
public List<EndpointDescriptor> getVerbDescriptors() {
return endpointScanningService.getAllEndpoints()
.stream()
.filter(endpoint -> "VERB".equals(endpoint.getType()))
.filter(endpoint -> verbs.containsKey(endpoint.getName()))
.collect(Collectors.toList());
}

/**
* Gets all available AI-callable verb descriptors.
* This can be used by agents to understand what capabilities are available.
*/
public List<EndpointDescriptor> getAiCallableVerbDescriptors() {
return getVerbDescriptors()
.stream()
.filter(endpoint -> {
Boolean isAiCallable = (Boolean) endpoint.getMetadata().get("isAiCallable");
return isAiCallable != null && isAiCallable;
})
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentrius.agent.config;

import java.util.List;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -14,4 +15,5 @@ public class AgentConfigOptions {

private String namePrefix;
private String type;
private List<String> endpoints;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.sentrius.agent.discovery;

import io.sentrius.agent.analysis.agents.agents.AgentVerb;
import io.sentrius.agent.config.AgentConfigOptions;
import io.sentrius.sso.core.dto.capabilities.EndpointDescriptor;
import io.sentrius.sso.core.dto.ztat.AgentExecution;
import io.sentrius.sso.core.exceptions.ZtatException;
import io.sentrius.sso.core.model.verbs.DefaultInterpreter;
import io.sentrius.sso.core.services.agents.ZeroTrustClientService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class AgentEndpointDiscoveryService {

private final AgentConfigOptions agentConfigOptions;
private final RestTemplate restTemplate = new RestTemplate();
private final ZeroTrustClientService zeroTrustClientService;

// Simulated verb registry for example
private final Map<String, AgentVerb> verbs = new HashMap<>();

public Map<String, AgentVerb> discoverEndpoints(AgentExecution agentExecution) {
String discoveryUrl = agentConfigOptions.getEndpoints() + "?type=VERB";

log.info("Querying discovery endpoint: {}", discoveryUrl);

try {

List<EndpointDescriptor> descriptors = zeroTrustClientService.callGetOnApi(agentExecution, discoveryUrl);
if (descriptors == null || descriptors.isEmpty()) {
log.info("No endpoints discovered from capabilities API");
return verbs;
}

List<EndpointDescriptor> verbEndpoints = descriptors.stream()
.filter(d -> "VERB".equalsIgnoreCase(d.getType()))
.toList();

log.info("Discovered {} VERB endpoints", verbEndpoints.size());

for (EndpointDescriptor endpoint : verbEndpoints) {
if (!verbs.containsKey(endpoint.getName())) {
log.warn("Discovered verb '{}' not registered in agent", endpoint.getName());
// You could also register it here dynamically if desired
verbs.put(endpoint.getName(), convertToVerbDefinition(endpoint));
}
}

} catch (Exception e) {
log.error("Failed to discover endpoints: {}", e.getMessage(), e);
} catch (ZtatException e) {
throw new RuntimeException(e);
}
return verbs;
}

private AgentVerb convertToVerbDefinition(EndpointDescriptor descriptor) {
return AgentVerb.builder()
.name(descriptor.getName())
.description(descriptor.getDescription())
.returnType(descriptor.getReturnType() != null ? descriptor.getReturnType() : String.class)
.requiresTokenManagement(descriptor.isRequiresTokenManagement())
.outputInterpreter(DefaultInterpreter.class) // You can enhance this later if `metadata` has interpreter info
.inputInterpreter(DefaultInterpreter.class)
.paramDescriptions(descriptor.getParameters())
.isAiCallable(true) // Assume everything from the API is callable
.build();
}
}
9 changes: 9 additions & 0 deletions api/src/main/java/io/sentrius/sso/config/AppConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@ public class AppConfig {
// Your configuration beans
@Value("${agentproxy.externalUrl:}") // Defaults to empty string if not set
private String agentProxyExternalUrl;

@Value("${sentrius.agent.register.bootstrap.allow:false}")
private boolean allowRegistration;

@Value("${sentrius.agent.bootstrap.policy:default-policy.yaml}")
private String defaultPolicyFile;

@Value("${sentrius.agent.launcher.service:http://sentrius-launcherservice:8080/}")
private String sentriusLauncherService;
}
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public ResponseEntity<?> requestRegistration(
@RequestHeader("Authorization") String token,
HttpServletRequest request, HttpServletResponse response) throws SQLException, GeneralSecurityException {

String compactJwt = token.startsWith("Bearer ") ? token.substring(7) : token;
String compactJwt = token.startsWith("Beaer ") ? token.substring(7) : token;


if (!keycloakService.validateJwt(compactJwt)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.sentrius.sso.config.ApiPaths;
import io.sentrius.sso.config.AppConfig;
import io.sentrius.sso.core.annotations.LimitAccess;
import io.sentrius.sso.core.config.SystemOptions;
import io.sentrius.sso.core.controllers.BaseController;
Expand Down Expand Up @@ -56,15 +57,8 @@ public class AgentBootstrapController extends BaseController {
final AgentService agentService;
private final ZeroTrustClientService zeroTrustClientService;
private final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
final AppConfig appConfig;

@Value("${sentrius.agent.register.bootstrap.allow:false}")
private boolean allowRegistration;

@Value("${sentrius.agent.bootstrap.policy:default-policy.yaml}")
private String defaultPolicyFile;

@Value("${sentrius.agent.launcher.service:http://sentrius-launcherservice:8080/}")
private String sentriusLauncherService;

public AgentBootstrapController(
UserService userService,
Expand All @@ -74,8 +68,8 @@ public AgentBootstrapController(
CryptoService cryptoService, SessionTrackingService sessionTrackingService, KeycloakService keycloakService,
ATPLPolicyService atplPolicyService,
ZeroTrustAccessTokenService ztatService, ZeroTrustRequestService ztrService, AgentService agentService,
ZeroTrustClientService zeroTrustClientService
) {
ZeroTrustClientService zeroTrustClientService, AppConfig appConfig
) {
super(userService, systemOptions, errorOutputService);
this.auditService = auditService;
this.cryptoService = cryptoService;
Expand All @@ -86,6 +80,7 @@ public AgentBootstrapController(
this.ztrService = ztrService;
this.agentService = agentService;
this.zeroTrustClientService = zeroTrustClientService;
this.appConfig = appConfig;
}


Expand All @@ -110,7 +105,7 @@ public ResponseEntity<AgentRegistrationDTO> bootstrap(
.clientId(unencryptedRegistration.getClientId())
.build();

if (allowRegistration) {
if (appConfig.isAllowRegistration()) {
log.info("Registering {}", registrationDTO.getAgentName());
User user = userService.getUserByUsername(newDTO.getAgentName());
if (user == null) {
Expand All @@ -131,9 +126,9 @@ public ResponseEntity<AgentRegistrationDTO> bootstrap(
log.info("Creating new user: {}", user);
user = userService.save(user);

try(InputStream terminalHelperStream = getClass().getClassLoader().getResourceAsStream(defaultPolicyFile)) {
try(InputStream terminalHelperStream = getClass().getClassLoader().getResourceAsStream(appConfig.getDefaultPolicyFile())) {
if (terminalHelperStream == null) {
throw new RuntimeException(defaultPolicyFile + "not found on classpath");
throw new RuntimeException(appConfig.getDefaultPolicyFile() + "not found on classpath");

}

Expand All @@ -147,7 +142,7 @@ public ResponseEntity<AgentRegistrationDTO> bootstrap(
else {
atplPolicyService.assignPolicyToUser(user, latest.get());
}
log.info("Default policy file: {}", defaultPolicyFile);
log.info("Default policy file: {}", appConfig.getDefaultPolicyFile());

}

Expand All @@ -171,7 +166,7 @@ public ResponseEntity<String> launchPod(


var operatingUser = getOperatingUser(request, response );
zeroTrustClientService.callAuthenticatedPostOnApi(sentriusLauncherService, "agent/launcher/create",
zeroTrustClientService.callAuthenticatedPostOnApi(appConfig.getSentriusLauncherService(), "agent/launcher/create",
registrationDTO);
// bootstrap with a default policy
return ResponseEntity.ok("{\"status\": \"success\"}");
Expand Down
Loading