@ory/argus 1.2.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +25 -0
  2. package/assets/skills/ory-build-agent/SKILL.md +1 -1
  3. package/assets/skills/ory-deploy-agent/SKILL.md +315 -0
  4. package/assets/skills/ory-deploy-openai-e2b/SKILL.md +289 -0
  5. package/assets/skills/ory-e2b-sandbox/SKILL.md +10 -6
  6. package/assets/skills/ory-temporal-worker/SKILL.md +4 -4
  7. package/dist/adapters.d.ts +11 -3
  8. package/dist/adapters.js +55 -13
  9. package/dist/agent-auth.d.ts +18 -7
  10. package/dist/agent-auth.js +120 -10
  11. package/dist/auth-store.d.ts +3 -3
  12. package/dist/auth-store.js +56 -12
  13. package/dist/auth.d.ts +1 -1
  14. package/dist/auth.js +1 -1
  15. package/dist/build-info.json +4 -4
  16. package/dist/cli.js +5 -0
  17. package/dist/client.d.ts +15 -0
  18. package/dist/client.js +24 -7
  19. package/dist/config.d.ts +23 -3
  20. package/dist/config.js +202 -18
  21. package/dist/contract-suite.d.ts +0 -8
  22. package/dist/contract-suite.js +0 -1
  23. package/dist/event-reporter.d.ts +1 -0
  24. package/dist/event-reporter.js +19 -2
  25. package/dist/hook-timeout.d.ts +2 -2
  26. package/dist/hook-timeout.js +2 -2
  27. package/dist/index.d.ts +4 -4
  28. package/dist/index.js +13 -6
  29. package/dist/lifecycle.js +2 -1
  30. package/dist/local/configs.d.ts +2 -4
  31. package/dist/local/configs.js +2 -4
  32. package/dist/local/manager.js +4 -4
  33. package/dist/local/seed.d.ts +4 -4
  34. package/dist/local/seed.js +8 -10
  35. package/dist/runtime-credential.d.ts +35 -0
  36. package/dist/runtime-credential.js +252 -1
  37. package/dist/runtime.d.ts +19 -12
  38. package/dist/runtime.js +69 -21
  39. package/dist/setup.js +3 -3
  40. package/dist/skills.d.ts +3 -5
  41. package/dist/skills.js +14 -5
  42. package/dist/subject.d.ts +2 -3
  43. package/dist/subject.js +10 -11
  44. package/dist/testing.d.ts +17 -0
  45. package/dist/testing.js +53 -0
  46. package/dist/tool-catalog.d.ts +12 -12
  47. package/dist/tool-catalog.js +206 -50
  48. package/dist/user-login.js +1 -1
  49. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wantsHelp = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.LOOPBACK_PORTS = exports.buildAuthorizeUrl = exports.sha256Base64Url = exports.generateCodeVerifier = exports.detectHeadless = exports.refreshAccessToken = exports.pkceLogin = exports.resetPermissionModeCache = exports.warmPermissionModeCache = exports.resolvePermissionMode = exports.SESSIONLESS_KEY = exports.UNKNOWN_HARNESS_KEY = exports.unregisterInstalledHarness = exports.registerInstalledHarness = exports.listInstalledHarnesses = exports.getHarnessDataDir = exports.getDataDir = exports.getConfigPath = exports.mutateConfig = exports.describeSecurityGap = exports.isSecurityConnected = exports.resolveConfig = exports.saveConfig = exports.loadConfig = exports.clearSessionContext = exports.setSessionContext = exports.withSessionContext = exports.currentSessionContext = exports.projectActivityEntry = exports.SERVER_ACTIVITY_EVENTS = exports.AgentSecurityEventReporter = exports.withQuietStderr = exports.formatLogEntry = exports.redactLogData = exports.ActiveActivity = exports.DebugLogger = exports.talosRuntimeCredential = exports.runCredentialStoreCommand = exports.resolveRuntimeCredential = exports.enrollTalosRuntimeCredential = exports.enrollTalosChildRuntimeCredential = exports.createOsTalosCredentialStore = exports.configureSystemCaTrustForDefaultFetch = exports.credentialAccount = exports.canonicalProjectUrl = exports.canonicalCredentialIdentity = exports.authenticatedRuntimeRequest = exports.OryAgentClient = void 0;
4
- exports.clearRetiredCredentials = exports.loadRetiredCredentials = exports.saveDelegationNodeId = exports.loadDelegationNodeId = exports.claimSubAgentDynamicCredentials = exports.clearSubAgentDynamicCredentialsForHarness = exports.clearSubAgentDynamicCredentials = exports.saveSubAgentDynamicCredentials = exports.loadSubAgentDynamicCredentialsByHarness = exports.loadAllSubAgentDynamicCredentials = exports.loadSubAgentDynamicCredentials = exports.claimAgentDynamicCredentials = exports.countAgentSessions = exports.latestSubAgentSession = exports.latestAgentRegistration = exports.clearAgentDynamicCredentials = exports.saveAgentDynamicCredentials = exports.loadAgentDynamicCredentialsByHarness = exports.loadAgentDynamicCredentials = exports.registerAgentClient = exports.fetchClientCredentialsToken = exports.ensureSubAgentIdentity = exports.ensureAgentIdentity = exports.resolveRuntimeAgentCredentials = exports.resolveAgentCredentials = exports.ensureAuthenticated = exports.ensureUserAuthenticated = exports.TOKEN_EXPIRY_SKEW_SEC = exports.waitForPeerTokensSync = exports.waitForPeerTokens = exports.clearPkceFlightLock = exports.tryAcquirePkceFlightLock = exports.refreshAndSave = exports.isExpired = exports.clearTokens = exports.saveTokens = exports.loadTokens = exports.toolHookTimeout = exports.sessionStartHookTimeout = exports.HOOK_TIMEOUT_MAX_MS = exports.TOOL_HOOK_WINDOW_MS = exports.SESSION_START_HOOK_WINDOW_MS = exports.describeDanglingRegistration = exports.findDanglingRegistration = exports.deregisterExternalRegistrations = exports.clearAllExternalRegistrations = exports.clearExternalRegistration = exports.recordExternalRegistration = exports.loadExternalRegistrations = exports.shouldPrintHelp = void 0;
5
- exports.mergeMcpServer = exports.mcpServerEntry = exports.emitDeferredNextSteps = exports.beginDeferNextSteps = exports.nextStepsSink = exports.printNextSteps = exports.printSetupHelp = exports.removeFlatHooks = exports.mergeFlatHooks = exports.flatHookEntry = exports.removeMatcherHooks = exports.mergeMatcherHooks = exports.matcherHookEntry = exports.isOryHookCommand = exports.writeJsonFile = exports.readJsonFile = exports.parseSetupArgs = exports.resolveBuildInfo = exports.collectVersionInfo = exports.runVersionCommand = exports.probePermissionsCoverage = exports.collectStatusReport = exports.printPermissionsSection = exports.printAgentIdentitySection = exports.printUserIdentitySection = exports.runStatusCommand = exports.runPostInstall = exports.runWatchCommand = exports.runPermissionsCommand = exports.oryNpx = exports.interactiveConfigPrompt = exports.promptForProjectUrl = exports.promptOnTty = exports.isTtyAvailable = exports.printEnvHelp = exports.printLogTail = exports.printEnvironment = exports.printOryConfig = exports.runAgentCommand = exports.runConfigureCommand = exports.resolveInstalledHarnesses = exports.clearCredentialsForUninstall = exports.READ_CREDENTIAL_RETRY_MS = exports.resetReadCredentialBackoff = exports.ensureReadCredential = exports.DEFAULT_SESSION_RETENTION = exports.AGENT_TOKEN_EXPIRY_SKEW_SEC = exports.revokeAgentDynamicClient = exports.sessionRetention = exports.retireAgentSessions = void 0;
6
- exports.decomposeAndCheck = exports.gateToolCall = exports.applyPermissionMode = exports.checkAndDecide = exports.REGISTRY_URL = exports.runRegistryCommand = exports.runLocalCommand = exports.ORY_COMMAND_SLUGS = exports.ORY_COMMAND_SKILL_NAMES = exports.ORY_SKILL_NAMES = exports.removeSkillDirs = exports.writeSkillTree = exports.toSkillMarkdown = exports.commandToPlainMarkdown = exports.commandToFrontmatterMarkdown = exports.commandToToml = exports.commandToSkill = exports.renderOryCommands = exports.renderOrySkills = exports.renderMirrorBootstrap = exports.MCP_SERVER_PACKAGE = exports.defaultNpmInstaller = exports.describeRuntimeHealth = exports.checkRuntimeHealth = exports.pruneRuntimeStores = exports.removeRuntimeWiring = exports.getRuntimeWiring = exports.recordRuntimeWiring = exports.readRuntimeManifest = exports.getMcpShimPath = exports.getHookShimPath = exports.getShimDir = exports.getRuntimeStoreDir = exports.getRuntimeRoot = exports.moduleSpecifier = exports.requireHookCommand = exports.isOryRuntimeCommand = exports.mcpCommand = exports.hookCommand = exports.writeMcpShim = exports.writeHookShim = exports.resolveMcpRuntimeEntry = exports.resolveRuntimeEntry = exports.linkedRuntime = exports.materializeRuntime = exports.resolveRuntimeForInstall = exports.wireRuntime = exports.unregisterPlugin = exports.registerPlugin = exports.removeMcpServer = void 0;
7
- exports.isUserFacingPhase = exports.classifyLifecycle = exports.extractShellCommand = exports.resolveShellCommandNamespace = exports.getShellCommandCatalog = exports.SHELL_COMMAND_CATALOG = exports.isShellTool = exports.getShellToolCatalog = exports.SHELL_TOOL_CATALOG = exports.isInteractiveTool = exports.getInteractiveToolCatalog = exports.INTERACTIVE_TOOL_CATALOG = exports.getToolCatalog = exports.ALL_TOOLS = exports.KNOWN_HARNESSES = exports.HARNESS_TOOL_CATALOG = exports.DEFAULT_SHELL_NAMESPACE = exports.DEFAULT_NAMESPACE = exports.PERMIT_USE = exports.ENROLLMENT_NAMESPACE = exports.AGENT_ROLE_NAMESPACE = exports.DELEGATION_NAMESPACE = exports.PERMISSION_MODE_NAMESPACE = exports.PROJECT_POSTURE_OBJECT = exports.AUTO_ENROLL_OBJECT = exports.PERMISSION_MODE_OBJECT = exports.RELATION_OPTED_OUT_SUBJECTS = exports.RELATION_MEMBERS = exports.RELATION_ENFORCED_SUBJECTS = exports.RELATION_CREDENTIALS = exports.RELATION_DELEGATES = exports.RELATION_BLOCKED_SUBJECTS = exports.RELATION_USERS = exports.SUBAGENT_NODE_NAMESPACE = exports.AGENT_NODE_NAMESPACE = exports.NODE_REFERENCE_NAMESPACES = exports.PRINCIPAL_NAMESPACES = exports.OPL_IMPORT_SYMBOLS = exports.OPL_IMPORT_MODULE = exports.renderOplImport = exports.renderPrincipalClass = exports.renderEnrollmentNamespaceClass = exports.renderAgentRoleNamespaceClass = exports.renderPermissionModeNamespaceClass = exports.renderDelegationNamespaceClass = exports.renderToolNamespaceClass = exports.buildAgentSecurityOpl = exports.extractBashCommandWords = exports.extractShellCommands = exports.resolveCheckRelation = void 0;
8
- exports.collectSystemServices = exports.wrapTool = exports.writeAgentDelegatesSubagent = exports.writeUserDelegatesAgent = exports.registerSubagent = exports.fail = exports.complete = exports.gate = exports.decideTool = exports.withHookContext = exports.createSessionStarter = exports.sessionStart = exports.resolveNamespace = exports.summarizeToolOutput = exports.summarizeToolInput = exports.OryDenialError = exports.shellDenialFields = exports.alertAttributes = exports.formatAlertSummary = exports.formatAlertMessage = exports.formatDenialSummary = exports.formatDenialMessage = exports.DEFAULT_USER_SUBJECT_NAMESPACE = exports.SESSION_NAMESPACE = exports.SUBAGENT_NAMESPACE = exports.AGENT_NAMESPACE = exports.resolveSubAgentSpawnSubject = exports.resolveSubAgentSubject = exports.resolveAgentSessionSubject = exports.resolveAgentSubject = exports.subjectLabel = exports.runWithUserSubject = exports.resolveUserSubject = exports.checkMcpPermission = exports.parseMcpToolGeneric = exports.parseGeminiMcpTool = exports.parseClaudeCodeMcpTool = exports.TOOL_EXECUTION_PHASES = exports.USER_FACING_PHASES = exports.HARNESS_LIFECYCLE_MAP = exports.isToolExecutionPhase = void 0;
3
+ exports.generateCodeVerifier = exports.detectHeadless = exports.refreshAccessToken = exports.pkceLogin = exports.resetPermissionModeCache = exports.warmPermissionModeCache = exports.resolvePermissionMode = exports.SESSIONLESS_KEY = exports.UNKNOWN_HARNESS_KEY = exports.unregisterInstalledHarness = exports.registerInstalledHarness = exports.listInstalledHarnesses = exports.getHarnessDataDir = exports.getDataDir = exports.getConfigPath = exports.mutateConfigAsync = exports.mutateConfig = exports.AGENT_ROOT_DELEGATION_ENV_VAR = exports.validateAgentRootDelegation = exports.readAgentRootDelegation = exports.describeSecurityGap = exports.isSecurityConnected = exports.resolveConfig = exports.saveConfig = exports.loadConfig = exports.clearSessionContext = exports.setSessionContext = exports.withSessionContext = exports.currentSessionContext = exports.projectActivityEntry = exports.SERVER_ACTIVITY_EVENTS = exports.AgentSecurityEventReporter = exports.withQuietStderr = exports.formatLogEntry = exports.redactLogData = exports.ActiveActivity = exports.DebugLogger = exports.talosRuntimeCredential = exports.runCredentialStoreCommand = exports.resolveRuntimeCredential = exports.enrollTalosRuntimeCredential = exports.enrollTalosChildRuntimeCredential = exports.createOsTalosCredentialStore = exports.createSpiffeFileRequestAuthenticator = exports.configureSystemCaTrustForDefaultFetch = exports.credentialAccount = exports.canonicalProjectUrl = exports.canonicalCredentialIdentity = exports.authenticatedRuntimeRequest = exports.OryAgentClient = void 0;
4
+ exports.clearSubAgentDynamicCredentials = exports.saveSubAgentDynamicCredentials = exports.loadSubAgentDynamicCredentialsByHarness = exports.loadAllSubAgentDynamicCredentials = exports.loadSubAgentDynamicCredentials = exports.claimAgentDynamicCredentials = exports.countAgentSessions = exports.latestSubAgentSession = exports.latestAgentRegistration = exports.clearAgentDynamicCredentials = exports.saveAgentDynamicCredentials = exports.loadAgentDynamicCredentialsByHarness = exports.loadAgentDynamicCredentials = exports.registerAgentClient = exports.fetchClientCredentialsToken = exports.ensureSubAgentIdentity = exports.ensureAgentIdentity = exports.resolveRuntimeAgentCredentials = exports.resolvePreprovisionedRuntimeContext = exports.resolveAgentCredentials = exports.ensureAuthenticated = exports.ensureUserAuthenticated = exports.TOKEN_EXPIRY_SKEW_SEC = exports.waitForPeerTokensSync = exports.waitForPeerTokens = exports.clearPkceFlightLock = exports.tryAcquirePkceFlightLock = exports.refreshAndSave = exports.isExpired = exports.clearTokens = exports.saveTokens = exports.loadTokens = exports.toolHookTimeout = exports.sessionStartHookTimeout = exports.HOOK_TIMEOUT_MAX_MS = exports.TOOL_HOOK_WINDOW_MS = exports.SESSION_START_HOOK_WINDOW_MS = exports.describeDanglingRegistration = exports.findDanglingRegistration = exports.deregisterExternalRegistrations = exports.clearAllExternalRegistrations = exports.clearExternalRegistration = exports.recordExternalRegistration = exports.loadExternalRegistrations = exports.shouldPrintHelp = exports.wantsHelp = exports.DEFAULT_LOGIN_TIMEOUT_MS = exports.LOOPBACK_PORTS = exports.buildAuthorizeUrl = exports.sha256Base64Url = void 0;
5
+ exports.removeFlatHooks = exports.mergeFlatHooks = exports.flatHookEntry = exports.removeMatcherHooks = exports.mergeMatcherHooks = exports.matcherHookEntry = exports.isOryHookCommand = exports.writeJsonFile = exports.readJsonFile = exports.parseSetupArgs = exports.resolveBuildInfo = exports.collectVersionInfo = exports.runVersionCommand = exports.probePermissionsCoverage = exports.collectStatusReport = exports.printPermissionsSection = exports.printAgentIdentitySection = exports.printUserIdentitySection = exports.runStatusCommand = exports.runPostInstall = exports.runWatchCommand = exports.runPermissionsCommand = exports.oryNpx = exports.interactiveConfigPrompt = exports.promptForProjectUrl = exports.promptOnTty = exports.isTtyAvailable = exports.printEnvHelp = exports.printLogTail = exports.printEnvironment = exports.printOryConfig = exports.runAgentCommand = exports.runConfigureCommand = exports.resolveInstalledHarnesses = exports.clearCredentialsForUninstall = exports.READ_CREDENTIAL_RETRY_MS = exports.resetReadCredentialBackoff = exports.ensureReadCredential = exports.DEFAULT_SESSION_RETENTION = exports.AGENT_TOKEN_EXPIRY_SKEW_SEC = exports.revokeAgentDynamicClient = exports.sessionRetention = exports.retireAgentSessions = exports.clearRetiredCredentials = exports.loadRetiredCredentials = exports.saveDelegationNodeId = exports.resolvePreprovisionedRootDelegation = exports.loadDelegationNodeId = exports.claimSubAgentDynamicCredentials = exports.clearSubAgentDynamicCredentialsForHarness = void 0;
6
+ exports.ORY_COMMAND_SLUGS = exports.ORY_COMMAND_SKILL_NAMES = exports.ORY_SKILL_NAMES = exports.removeSkillDirs = exports.writeSkillTree = exports.toSkillMarkdown = exports.commandToPlainMarkdown = exports.commandToFrontmatterMarkdown = exports.commandToToml = exports.commandToSkill = exports.renderOryCommands = exports.renderOrySkills = exports.renderMirrorBootstrap = exports.MCP_SERVER_PACKAGE = exports.defaultNpmInstaller = exports.describeRuntimeHealth = exports.checkRuntimeHealth = exports.pruneRuntimeStores = exports.removeRuntimeWiring = exports.getRuntimeWiring = exports.recordRuntimeWiring = exports.readRuntimeManifest = exports.getMcpShimPath = exports.getHookShimPath = exports.getShimDir = exports.getRuntimeStoreDir = exports.getRuntimeRoot = exports.moduleSpecifier = exports.requireHookCommand = exports.isOryRuntimeCommand = exports.mcpCommand = exports.hookCommand = exports.writeMcpShim = exports.writeHookShim = exports.resolveMcpRuntimeEntry = exports.resolveRuntimeEntry = exports.linkedRuntime = exports.materializeRuntime = exports.resolveRuntimeForInstall = exports.wireRuntime = exports.unregisterPlugin = exports.registerPlugin = exports.removeMcpServer = exports.mergeMcpServer = exports.mcpServerEntry = exports.emitDeferredNextSteps = exports.beginDeferNextSteps = exports.nextStepsSink = exports.printNextSteps = exports.printSetupHelp = void 0;
7
+ exports.getShellToolCatalog = exports.SHELL_TOOL_CATALOG = exports.isInteractiveTool = exports.getInteractiveToolCatalog = exports.INTERACTIVE_TOOL_CATALOG = exports.getToolCatalog = exports.ALL_TOOLS = exports.KNOWN_HARNESSES = exports.HARNESS_TOOL_CATALOG = exports.DEFAULT_SHELL_NAMESPACE = exports.DEFAULT_NAMESPACE = exports.PERMIT_USE = exports.ENROLLMENT_NAMESPACE = exports.AGENT_ROLE_NAMESPACE = exports.DELEGATION_NAMESPACE = exports.PERMISSION_MODE_NAMESPACE = exports.PROJECT_POSTURE_OBJECT = exports.AUTO_ENROLL_OBJECT = exports.PERMISSION_MODE_OBJECT = exports.RELATION_OPTED_OUT_SUBJECTS = exports.RELATION_MEMBERS = exports.RELATION_ENFORCED_SUBJECTS = exports.RELATION_CREDENTIALS = exports.RELATION_DELEGATES = exports.RELATION_BLOCKED_SUBJECTS = exports.RELATION_USERS = exports.SUBAGENT_NODE_NAMESPACE = exports.AGENT_NODE_NAMESPACE = exports.NODE_REFERENCE_NAMESPACES = exports.PRINCIPAL_NAMESPACES = exports.OPL_IMPORT_SYMBOLS = exports.OPL_IMPORT_MODULE = exports.renderOplImport = exports.renderPrincipalClass = exports.renderEnrollmentNamespaceClass = exports.renderAgentRoleNamespaceClass = exports.renderPermissionModeNamespaceClass = exports.renderDelegationNamespaceClass = exports.renderToolNamespaceClass = exports.buildAgentSecurityOpl = exports.extractBashCommandWords = exports.extractShellCommands = exports.resolveCheckRelation = exports.decomposeAndCheck = exports.gateToolCall = exports.applyPermissionMode = exports.checkAndDecide = exports.REGISTRY_URL = exports.runRegistryCommand = exports.runLocalCommand = void 0;
8
+ exports.collectSystemServices = exports.wrapTool = exports.writeAgentDelegatesSubagent = exports.writeUserDelegatesAgent = exports.registerSubagent = exports.fail = exports.complete = exports.gate = exports.decideTool = exports.withHookContext = exports.createSessionStarter = exports.sessionStart = exports.resolveNamespace = exports.summarizeToolOutput = exports.summarizeToolInput = exports.OryDenialError = exports.shellDenialFields = exports.alertAttributes = exports.formatAlertSummary = exports.formatAlertMessage = exports.formatDenialSummary = exports.formatDenialMessage = exports.DEFAULT_USER_SUBJECT_NAMESPACE = exports.SESSION_NAMESPACE = exports.SUBAGENT_NAMESPACE = exports.AGENT_NAMESPACE = exports.resolveSubAgentSpawnSubject = exports.resolveSubAgentSubject = exports.resolveAgentSessionSubject = exports.resolveAgentSubject = exports.subjectLabel = exports.runWithUserSubject = exports.resolveUserSubject = exports.checkMcpPermission = exports.parseMcpToolGeneric = exports.parseGeminiMcpTool = exports.parseClaudeCodeMcpTool = exports.TOOL_EXECUTION_PHASES = exports.USER_FACING_PHASES = exports.HARNESS_LIFECYCLE_MAP = exports.isToolExecutionPhase = exports.isUserFacingPhase = exports.classifyLifecycle = exports.extractShellCommand = exports.resolveShellCommandNamespace = exports.getShellCommandCatalog = exports.SHELL_COMMAND_CATALOG = exports.isShellTool = void 0;
9
9
  var client_js_1 = require("./client.js");
10
10
  Object.defineProperty(exports, "OryAgentClient", { enumerable: true, get: function () { return client_js_1.OryAgentClient; } });
11
11
  var runtime_credential_js_1 = require("./runtime-credential.js");
@@ -14,6 +14,7 @@ Object.defineProperty(exports, "canonicalCredentialIdentity", { enumerable: true
14
14
  Object.defineProperty(exports, "canonicalProjectUrl", { enumerable: true, get: function () { return runtime_credential_js_1.canonicalProjectUrl; } });
15
15
  Object.defineProperty(exports, "credentialAccount", { enumerable: true, get: function () { return runtime_credential_js_1.credentialAccount; } });
16
16
  Object.defineProperty(exports, "configureSystemCaTrustForDefaultFetch", { enumerable: true, get: function () { return runtime_credential_js_1.configureSystemCaTrustForDefaultFetch; } });
17
+ Object.defineProperty(exports, "createSpiffeFileRequestAuthenticator", { enumerable: true, get: function () { return runtime_credential_js_1.createSpiffeFileRequestAuthenticator; } });
17
18
  Object.defineProperty(exports, "createOsTalosCredentialStore", { enumerable: true, get: function () { return runtime_credential_js_1.createOsTalosCredentialStore; } });
18
19
  Object.defineProperty(exports, "enrollTalosChildRuntimeCredential", { enumerable: true, get: function () { return runtime_credential_js_1.enrollTalosChildRuntimeCredential; } });
19
20
  Object.defineProperty(exports, "enrollTalosRuntimeCredential", { enumerable: true, get: function () { return runtime_credential_js_1.enrollTalosRuntimeCredential; } });
@@ -41,7 +42,11 @@ Object.defineProperty(exports, "saveConfig", { enumerable: true, get: function (
41
42
  Object.defineProperty(exports, "resolveConfig", { enumerable: true, get: function () { return config_js_1.resolveConfig; } });
42
43
  Object.defineProperty(exports, "isSecurityConnected", { enumerable: true, get: function () { return config_js_1.isSecurityConnected; } });
43
44
  Object.defineProperty(exports, "describeSecurityGap", { enumerable: true, get: function () { return config_js_1.describeSecurityGap; } });
45
+ Object.defineProperty(exports, "readAgentRootDelegation", { enumerable: true, get: function () { return config_js_1.readAgentRootDelegation; } });
46
+ Object.defineProperty(exports, "validateAgentRootDelegation", { enumerable: true, get: function () { return config_js_1.validateAgentRootDelegation; } });
47
+ Object.defineProperty(exports, "AGENT_ROOT_DELEGATION_ENV_VAR", { enumerable: true, get: function () { return config_js_1.AGENT_ROOT_DELEGATION_ENV_VAR; } });
44
48
  Object.defineProperty(exports, "mutateConfig", { enumerable: true, get: function () { return config_js_1.mutateConfig; } });
49
+ Object.defineProperty(exports, "mutateConfigAsync", { enumerable: true, get: function () { return config_js_1.mutateConfigAsync; } });
45
50
  Object.defineProperty(exports, "getConfigPath", { enumerable: true, get: function () { return config_js_1.getConfigPath; } });
46
51
  Object.defineProperty(exports, "getDataDir", { enumerable: true, get: function () { return config_js_1.getDataDir; } });
47
52
  Object.defineProperty(exports, "getHarnessDataDir", { enumerable: true, get: function () { return config_js_1.getHarnessDataDir; } });
@@ -96,6 +101,7 @@ Object.defineProperty(exports, "ensureUserAuthenticated", { enumerable: true, ge
96
101
  Object.defineProperty(exports, "ensureAuthenticated", { enumerable: true, get: function () { return user_login_js_1.ensureAuthenticated; } });
97
102
  var agent_auth_js_1 = require("./agent-auth.js");
98
103
  Object.defineProperty(exports, "resolveAgentCredentials", { enumerable: true, get: function () { return agent_auth_js_1.resolveAgentCredentials; } });
104
+ Object.defineProperty(exports, "resolvePreprovisionedRuntimeContext", { enumerable: true, get: function () { return agent_auth_js_1.resolvePreprovisionedRuntimeContext; } });
99
105
  Object.defineProperty(exports, "resolveRuntimeAgentCredentials", { enumerable: true, get: function () { return agent_auth_js_1.resolveRuntimeAgentCredentials; } });
100
106
  Object.defineProperty(exports, "ensureAgentIdentity", { enumerable: true, get: function () { return agent_auth_js_1.ensureAgentIdentity; } });
101
107
  Object.defineProperty(exports, "ensureSubAgentIdentity", { enumerable: true, get: function () { return agent_auth_js_1.ensureSubAgentIdentity; } });
@@ -117,6 +123,7 @@ Object.defineProperty(exports, "clearSubAgentDynamicCredentials", { enumerable:
117
123
  Object.defineProperty(exports, "clearSubAgentDynamicCredentialsForHarness", { enumerable: true, get: function () { return agent_auth_js_1.clearSubAgentDynamicCredentialsForHarness; } });
118
124
  Object.defineProperty(exports, "claimSubAgentDynamicCredentials", { enumerable: true, get: function () { return agent_auth_js_1.claimSubAgentDynamicCredentials; } });
119
125
  Object.defineProperty(exports, "loadDelegationNodeId", { enumerable: true, get: function () { return agent_auth_js_1.loadDelegationNodeId; } });
126
+ Object.defineProperty(exports, "resolvePreprovisionedRootDelegation", { enumerable: true, get: function () { return agent_auth_js_1.resolvePreprovisionedRootDelegation; } });
120
127
  Object.defineProperty(exports, "saveDelegationNodeId", { enumerable: true, get: function () { return agent_auth_js_1.saveDelegationNodeId; } });
121
128
  Object.defineProperty(exports, "loadRetiredCredentials", { enumerable: true, get: function () { return agent_auth_js_1.loadRetiredCredentials; } });
122
129
  Object.defineProperty(exports, "clearRetiredCredentials", { enumerable: true, get: function () { return agent_auth_js_1.clearRetiredCredentials; } });
package/dist/lifecycle.js CHANGED
@@ -160,7 +160,8 @@ exports.HARNESS_LIFECYCLE_MAP = {
160
160
  },
161
161
  // Cursor (editor + CLI). Subprocess hooks read from `.cursor/hooks.json`.
162
162
  // `preToolUse` is the single permission gate — it already fires for every
163
- // tool category (Shell, Read, Write, MCP, Task). The more specific
163
+ // documented tool category (Shell, Read, Write, Grep, Delete, Task) and
164
+ // dynamic MCP calls. The more specific
164
165
  // `beforeShellExecution` / `beforeMCPExecution` / `beforeReadFile` hooks and
165
166
  // their `after*` counterparts surface activity to the user and are
166
167
  // activity-only (`user.interaction`), so shell/MCP/file access isn't gated
@@ -76,10 +76,8 @@ export interface OathkeeperConfig {
76
76
  * contract: an Oathkeeper service configured like the hosted
77
77
  * `ory-corp:cloud:keto:read:user-token` rule — `oauth2_introspection`
78
78
  * authenticator against Hydra, `allow` authorizer, `noop` mutator, `strip_path:/user`
79
- * upstream to keto-read — so a valid plugin OAuth2 access token is *required* to
80
- * read permissions locally, exactly as it is on a hosted Ory project. (The
81
- * plugin's agent DCR / user PKCE tokens are populated before any permission read
82
- * runs, so this is transparent in the normal flow.)
79
+ * upstream to keto-read — so a valid OAuth2 access token is *required* to use
80
+ * this direct local read path, exactly as it is on a hosted Ory project.
83
81
  *
84
82
  * Set `ORY_LOCAL_OATHKEEPER=0` (also `false`/`no`/`off`) to opt out and fall back
85
83
  * to a transparent nginx passthrough that strips `/user` and forwards straight to
@@ -201,10 +201,8 @@ function getConsoleConfig(projectRoot) {
201
201
  * contract: an Oathkeeper service configured like the hosted
202
202
  * `ory-corp:cloud:keto:read:user-token` rule — `oauth2_introspection`
203
203
  * authenticator against Hydra, `allow` authorizer, `noop` mutator, `strip_path:/user`
204
- * upstream to keto-read — so a valid plugin OAuth2 access token is *required* to
205
- * read permissions locally, exactly as it is on a hosted Ory project. (The
206
- * plugin's agent DCR / user PKCE tokens are populated before any permission read
207
- * runs, so this is transparent in the normal flow.)
204
+ * upstream to keto-read — so a valid OAuth2 access token is *required* to use
205
+ * this direct local read path, exactly as it is on a hosted Ory project.
208
206
  *
209
207
  * Set `ORY_LOCAL_OATHKEEPER=0` (also `false`/`no`/`off`) to opt out and fall back
210
208
  * to a transparent nginx passthrough that strips `/user` and forwards straight to
@@ -843,7 +843,7 @@ function printSeedResult(result) {
843
843
  console.log("Seed complete!");
844
844
  console.log("==============");
845
845
  console.log("");
846
- console.log(` Agent identity: self-registers on first run via DCR (nothing seeded)`);
846
+ console.log(` Agent identity: Talos enrollment runs at session start (nothing seeded)`);
847
847
  console.log("");
848
848
  console.log(` User identity: ${result.user.identity.email} (${result.user.identity.id})`);
849
849
  console.log(` User password: ${result.user.password}`);
@@ -860,9 +860,9 @@ function printSeedResult(result) {
860
860
  console.log(` export ORY_USER_SUBJECT_ID=${result.user.identity.id}`);
861
861
  console.log("");
862
862
  console.log("The user gate runs PKCE in the browser — sign in with the email and");
863
- console.log("password printed above. The agent OAuth2 client is registered");
864
- console.log("automatically via Dynamic Client Registration (RFC 7591) on first");
865
- console.log("session using the user's bearer as the initial access token.");
863
+ console.log("password printed above. At first session start, the authenticated user");
864
+ console.log("enrolls an actor-bound Talos credential. It is stored in the native OS");
865
+ console.log("credential store; tool hooks only load the existing credential.");
866
866
  console.log("");
867
867
  console.log("Or save the project URL to the shared config (persists across sessions):");
868
868
  console.log("");
@@ -7,10 +7,10 @@
7
7
  * redirect URIs. The launcher always runs the real PKCE browser flow; the
8
8
  * user types these credentials into the login UI to complete the flow.
9
9
  *
10
- * No agent principal is seeded: the harness self-registers a DCR OAuth2
11
- * client for the agent on first session start (using the user's bearer as
12
- * the initial access token), and permission checks are made against the
13
- * user subject — so a pre-seeded agent Kratos identity would be unused.
10
+ * No agent principal is seeded: Agent Security enrolls a Talos runtime
11
+ * credential at session start using the authenticated user's bearer, and
12
+ * permission checks are made against the user subject. A pre-seeded agent
13
+ * Kratos identity would be unused.
14
14
  *
15
15
  * Permission tuples are written as SubjectSet `User:<identity.id>` so
16
16
  * the Console's *Add relationship* dialog (which always emits SubjectSet
@@ -8,10 +8,10 @@
8
8
  * redirect URIs. The launcher always runs the real PKCE browser flow; the
9
9
  * user types these credentials into the login UI to complete the flow.
10
10
  *
11
- * No agent principal is seeded: the harness self-registers a DCR OAuth2
12
- * client for the agent on first session start (using the user's bearer as
13
- * the initial access token), and permission checks are made against the
14
- * user subject — so a pre-seeded agent Kratos identity would be unused.
11
+ * No agent principal is seeded: Agent Security enrolls a Talos runtime
12
+ * credential at session start using the authenticated user's bearer, and
13
+ * permission checks are made against the user subject. A pre-seeded agent
14
+ * Kratos identity would be unused.
15
15
  *
16
16
  * Permission tuples are written as SubjectSet `User:<identity.id>` so
17
17
  * the Console's *Add relationship* dialog (which always emits SubjectSet
@@ -157,9 +157,8 @@ async function seedLocalEnvironment(namespace = "AgentTool") {
157
157
  throw new Error(`backend services not ready before seed: ${readiness.pending.join(", ")} ` +
158
158
  `did not report ready within the timeout. The stack may still be starting — retry in a moment.`);
159
159
  }
160
- // 1. User identity. No agent identity is seeded — the harness
161
- // self-registers a DCR OAuth2 client for the agent on first session
162
- // start, and permission checks target the user subject.
160
+ // 1. User identity. No agent identity is seeded; Talos enrollment is owned
161
+ // by Agent Security at session start, and checks target the user subject.
163
162
  process.stderr.write(" Creating user identity...\n");
164
163
  const userIdentity = await seedIdentity(USER_EMAIL, USER_PASSWORD, "Local User");
165
164
  process.stderr.write(` User: ${userIdentity.id} (${userIdentity.email})\n`);
@@ -168,9 +167,8 @@ async function seedLocalEnvironment(namespace = "AgentTool") {
168
167
  const subjectLabel = `${exports.USER_SUBJECT_NAMESPACE}:${userIdentity.id}`;
169
168
  process.stderr.write(" Native tools: allowed unless explicitly blocked (no baseline grants)\n");
170
169
  // 3. User OAuth2 client (PKCE) — pre-registered so the user gate's
171
- // PKCE flow has somewhere to authenticate against. The agent's
172
- // OAuth2 client is intentionally NOT pre-registered; the harness
173
- // will self-register via DCR on first session start.
170
+ // PKCE flow has somewhere to authenticate against. Agent identity uses
171
+ // Talos runtime enrollment, so no agent OAuth2 client is seeded.
174
172
  process.stderr.write(" Registering user OAuth2 client (PKCE)...\n");
175
173
  let userClient = { clientId: exports.USER_CLIENT_ID };
176
174
  try {
@@ -1,3 +1,5 @@
1
+ import { readFile, realpath } from "node:fs/promises";
2
+ import * as nodeHttps from "node:https";
1
3
  /** The broker header a runtime credential must occupy for a request. */
2
4
  export type RuntimeAuthorizationHeader = "authorization" | "x-ory-agent-authorization";
3
5
  export interface RuntimeAuthenticatedRequest {
@@ -15,10 +17,37 @@ export interface RuntimeAuthenticatedRequest {
15
17
  * the request over mTLS without exposing key material to Argus.
16
18
  */
17
19
  export type RuntimeRequestAuthenticator = (request: RuntimeAuthenticatedRequest) => Promise<Response>;
20
+ export interface SpiffeFileRequestAuthenticatorOptions {
21
+ /** Atomically switched directory or symlink containing one material generation. */
22
+ generationPath?: string;
23
+ certificatePath?: string;
24
+ privateKeyPath?: string;
25
+ trustBundlePath?: string;
26
+ certificateFile?: string;
27
+ privateKeyFile?: string;
28
+ trustBundleFile?: string;
29
+ /** Optional marker read before and after the PEM files to reject mixed generations. */
30
+ generationFile?: string;
31
+ /** Exact URI SAN required on the peer leaf certificate. */
32
+ expectedServerSpiffeId?: string;
33
+ /** Exact and sole URI SAN required on the loaded client leaf certificate. */
34
+ expectedClientSpiffeId?: string;
35
+ /** Explicitly use ordinary HTTPS hostname verification instead of SPIFFE identity. */
36
+ verifyHostname?: boolean;
37
+ privateKeyPassphrase?: string;
38
+ /** @internal Injectable seam for focused transport tests. */
39
+ readFile?: typeof readFile;
40
+ /** @internal Injectable seam for focused generation-path tests. */
41
+ realpath?: typeof realpath;
42
+ /** @internal Injectable seam for focused transport tests. */
43
+ request?: typeof nodeHttps.request;
44
+ }
18
45
  export type RuntimeCredentialKind = "talos" | "injected";
19
46
  export interface RuntimeCredential {
20
47
  kind: RuntimeCredentialKind;
21
48
  subject?: string;
49
+ /** @internal Non-secret binding used to recognize the same Talos key after re-resolution. */
50
+ apiKeyFingerprint?: string;
22
51
  authenticate: RuntimeRequestAuthenticator;
23
52
  }
24
53
  export interface ResolveRuntimeCredentialOptions {
@@ -115,6 +144,12 @@ export declare function talosRuntimeCredential(apiKey: string, options?: {
115
144
  /** @internal Injectable seam for testing default-fetch TLS setup. */
116
145
  configureSystemCaTrust?: () => void;
117
146
  }): RuntimeCredential;
147
+ /**
148
+ * Build an mTLS authenticator from operator-managed SPIFFE files. The files are
149
+ * re-read for every request so atomic SVID and trust-bundle rotations are used
150
+ * without restarting the process.
151
+ */
152
+ export declare function createSpiffeFileRequestAuthenticator(options: SpiffeFileRequestAuthenticatorOptions): RuntimeRequestAuthenticator;
118
153
  /** Resolve only noninteractive runtime credentials. No persisted state is read. */
119
154
  export declare function resolveRuntimeCredential(options?: ResolveRuntimeCredentialOptions): RuntimeCredential | undefined;
120
155
  /** Explicitly enroll a Talos credential and optionally persist it in an OS store. */
@@ -40,13 +40,18 @@ exports.canonicalCredentialIdentity = canonicalCredentialIdentity;
40
40
  exports.credentialAccount = credentialAccount;
41
41
  exports.createOsTalosCredentialStore = createOsTalosCredentialStore;
42
42
  exports.talosRuntimeCredential = talosRuntimeCredential;
43
+ exports.createSpiffeFileRequestAuthenticator = createSpiffeFileRequestAuthenticator;
43
44
  exports.resolveRuntimeCredential = resolveRuntimeCredential;
44
45
  exports.enrollTalosRuntimeCredential = enrollTalosRuntimeCredential;
45
46
  exports.enrollTalosChildRuntimeCredential = enrollTalosChildRuntimeCredential;
46
47
  exports.authenticatedRuntimeRequest = authenticatedRuntimeRequest;
47
48
  const node_child_process_1 = require("node:child_process");
48
49
  const node_crypto_1 = require("node:crypto");
50
+ const promises_1 = require("node:fs/promises");
51
+ const nodeHttps = __importStar(require("node:https"));
52
+ const node_path_1 = require("node:path");
49
53
  const nodeTls = __importStar(require("node:tls"));
54
+ const SPIFFE_CREDENTIAL_METHOD = "spiffe_x509_svid";
50
55
  const CREDENTIAL_SERVICE = "com.ory.agent-security.runtime-credential";
51
56
  const MACOS_CREDENTIAL_SCRIPT = String.raw `
52
57
  ObjC.import('Foundation');
@@ -407,6 +412,7 @@ function talosRuntimeCredential(apiKey, options = {}) {
407
412
  return {
408
413
  kind: "talos",
409
414
  ...(options.subject ? { subject: options.subject } : {}),
415
+ apiKeyFingerprint: (0, node_crypto_1.createHash)("sha256").update(key).digest("hex"),
410
416
  authenticate: async ({ url, init, authorizationHeader, fetch: requestFetch, usesDefaultFetch, }) => {
411
417
  const headerName = authorizationHeader === "authorization"
412
418
  ? "authorization"
@@ -430,6 +436,205 @@ function talosRuntimeCredential(apiKey, options = {}) {
430
436
  },
431
437
  };
432
438
  }
439
+ /**
440
+ * Build an mTLS authenticator from operator-managed SPIFFE files. The files are
441
+ * re-read for every request so atomic SVID and trust-bundle rotations are used
442
+ * without restarting the process.
443
+ */
444
+ function createSpiffeFileRequestAuthenticator(options) {
445
+ const read = options.readFile ?? promises_1.readFile;
446
+ const resolveRealpath = options.realpath ?? promises_1.realpath;
447
+ const requestHttps = options.request ?? nodeHttps.request;
448
+ const expectedServerSpiffeId = options.expectedServerSpiffeId
449
+ ? canonicalSpiffeId(options.expectedServerSpiffeId)
450
+ : undefined;
451
+ const expectedClientSpiffeId = options.expectedClientSpiffeId
452
+ ? canonicalSpiffeId(options.expectedClientSpiffeId, "expectedClientSpiffeId")
453
+ : undefined;
454
+ if (Boolean(expectedServerSpiffeId) === Boolean(options.verifyHostname)) {
455
+ throw new Error("SPIFFE file authentication requires exactly one of expectedServerSpiffeId or verifyHostname");
456
+ }
457
+ const materialPaths = async () => {
458
+ if (options.generationPath) {
459
+ const generation = await resolveRealpath(options.generationPath);
460
+ const files = [
461
+ options.certificateFile ?? "svid.pem",
462
+ options.privateKeyFile ?? "svid-key.pem",
463
+ options.trustBundleFile ?? "bundle.pem",
464
+ options.generationFile,
465
+ ];
466
+ const paths = files.map((file) => {
467
+ if (file === undefined)
468
+ return undefined;
469
+ if ((0, node_path_1.isAbsolute)(file)) {
470
+ throw new Error("SPIFFE generation file names must be relative paths");
471
+ }
472
+ const path = (0, node_path_1.resolve)(generation, file);
473
+ const fromGeneration = (0, node_path_1.relative)(generation, path);
474
+ if (fromGeneration === ".." || fromGeneration.startsWith(`..${node_path_1.sep}`)) {
475
+ throw new Error("SPIFFE generation file names must remain within the generation path");
476
+ }
477
+ return path;
478
+ });
479
+ return paths;
480
+ }
481
+ if (options.generationFile) {
482
+ throw new Error("SPIFFE generationFile requires generationPath");
483
+ }
484
+ if (!options.certificatePath || !options.privateKeyPath || !options.trustBundlePath) {
485
+ throw new Error("SPIFFE file authentication requires generationPath or all three material paths");
486
+ }
487
+ return [options.certificatePath, options.privateKeyPath, options.trustBundlePath];
488
+ };
489
+ const isKeyMismatch = (error) => {
490
+ if (!(error instanceof Error))
491
+ return false;
492
+ const code = error.code;
493
+ return code === "ERR_OSSL_X509_KEY_VALUES_MISMATCH"
494
+ || /key values mismatch/i.test(error.message);
495
+ };
496
+ return async ({ url, init }) => {
497
+ const target = new URL(url);
498
+ if (target.protocol !== "https:") {
499
+ throw new Error("SPIFFE file authentication requires an HTTPS URL");
500
+ }
501
+ if (target.username || target.password) {
502
+ throw new Error("SPIFFE file authentication does not accept URL credentials");
503
+ }
504
+ const normalized = new Request(target, init);
505
+ const body = normalized.body === null
506
+ ? undefined
507
+ : Buffer.from(await normalized.arrayBuffer());
508
+ const send = async () => {
509
+ let snapshot;
510
+ for (let attempt = 0; attempt < 2; attempt += 1) {
511
+ const [certificatePath, privateKeyPath, trustBundlePath, generationFile] = await materialPaths();
512
+ const generationBefore = generationFile ? await read(generationFile) : undefined;
513
+ const [cert, key, ca] = await Promise.all([
514
+ read(certificatePath),
515
+ read(privateKeyPath),
516
+ read(trustBundlePath),
517
+ ]);
518
+ const generationAfter = generationFile ? await read(generationFile) : undefined;
519
+ if (!generationBefore || (generationAfter && generationBefore.equals(generationAfter))) {
520
+ if (expectedClientSpiffeId) {
521
+ validateClientCertificate(cert, expectedClientSpiffeId);
522
+ }
523
+ snapshot = [cert, key, ca];
524
+ break;
525
+ }
526
+ }
527
+ if (!snapshot)
528
+ throw new Error("SPIFFE material generation changed while loading files");
529
+ const [cert, key, ca] = snapshot;
530
+ return await new Promise((resolveResponse, reject) => {
531
+ const outgoing = requestHttps(target, {
532
+ method: normalized.method,
533
+ headers: Object.fromEntries(normalized.headers),
534
+ cert,
535
+ key,
536
+ ...(expectedServerSpiffeId ? { ca } : {}),
537
+ ...(options.privateKeyPassphrase ? { passphrase: options.privateKeyPassphrase } : {}),
538
+ minVersion: "TLSv1.3",
539
+ rejectUnauthorized: true,
540
+ ...(expectedServerSpiffeId ? {
541
+ // Never reuse a connection authenticated under another expected workload ID.
542
+ agent: false,
543
+ checkServerIdentity: (_hostname, certificate) => {
544
+ if (!peerHasExactUriSan(certificate.subjectaltname, expectedServerSpiffeId)) {
545
+ return new Error(`Peer certificate does not contain expected SPIFFE URI SAN ${expectedServerSpiffeId}`);
546
+ }
547
+ return undefined;
548
+ },
549
+ } : {}),
550
+ signal: init.signal ?? undefined,
551
+ }, (incoming) => {
552
+ const chunks = [];
553
+ incoming.on("data", (chunk) => {
554
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
555
+ });
556
+ incoming.on("end", () => {
557
+ const headers = new Headers();
558
+ for (let index = 0; index < incoming.rawHeaders.length; index += 2) {
559
+ headers.append(incoming.rawHeaders[index], incoming.rawHeaders[index + 1]);
560
+ }
561
+ resolveResponse(new Response(Buffer.concat(chunks), {
562
+ status: incoming.statusCode ?? 500,
563
+ statusText: incoming.statusMessage,
564
+ headers,
565
+ }));
566
+ });
567
+ incoming.on("error", reject);
568
+ });
569
+ outgoing.on("error", reject);
570
+ if (body)
571
+ outgoing.write(body);
572
+ outgoing.end();
573
+ });
574
+ };
575
+ try {
576
+ return await send();
577
+ }
578
+ catch (error) {
579
+ if (!isKeyMismatch(error))
580
+ throw error;
581
+ return await send();
582
+ }
583
+ };
584
+ }
585
+ function canonicalSpiffeId(value, name = "expectedServerSpiffeId") {
586
+ const parsed = new URL(value);
587
+ if (parsed.protocol !== "spiffe:"
588
+ || !parsed.hostname
589
+ || parsed.username
590
+ || parsed.password
591
+ || parsed.port
592
+ || parsed.search
593
+ || parsed.hash) {
594
+ throw new Error(`${name} must be a valid SPIFFE ID`);
595
+ }
596
+ return value;
597
+ }
598
+ function validateClientCertificate(certificate, expectedSpiffeId) {
599
+ let leaf;
600
+ try {
601
+ leaf = new node_crypto_1.X509Certificate(certificate);
602
+ }
603
+ catch {
604
+ throw new Error("SPIFFE client certificate is not a valid X.509 certificate");
605
+ }
606
+ const uriSans = uriSansFromSubjectAltName(leaf.subjectAltName);
607
+ if (uriSans.length !== 1 || uriSans[0] !== expectedSpiffeId) {
608
+ throw new Error(`Client certificate must contain only the expected SPIFFE URI SAN ${expectedSpiffeId}`);
609
+ }
610
+ const now = Date.now();
611
+ if (now < Date.parse(leaf.validFrom) || now > Date.parse(leaf.validTo)) {
612
+ throw new Error("SPIFFE client certificate is not currently valid");
613
+ }
614
+ }
615
+ function uriSansFromSubjectAltName(subjectAltName) {
616
+ if (!subjectAltName)
617
+ return [];
618
+ const result = [];
619
+ for (const entry of subjectAltName.match(/(?:^|, )URI:(?:"(?:\\.|[^"\\])*"|.*?)(?=, [A-Za-z0-9.]+:|$)/g) ?? []) {
620
+ const encoded = entry.replace(/^, /, "").slice(4);
621
+ if (!encoded.startsWith('"')) {
622
+ result.push(encoded);
623
+ continue;
624
+ }
625
+ try {
626
+ result.push(JSON.parse(encoded));
627
+ }
628
+ catch {
629
+ // Malformed SANs cannot satisfy an exact SPIFFE identity match.
630
+ }
631
+ }
632
+ return result;
633
+ }
634
+ function peerHasExactUriSan(subjectAltName, expected) {
635
+ const uriSans = uriSansFromSubjectAltName(subjectAltName);
636
+ return uriSans.length === 1 && uriSans[0] === expected;
637
+ }
433
638
  /** Resolve only noninteractive runtime credentials. No persisted state is read. */
434
639
  function resolveRuntimeCredential(options = {}) {
435
640
  if (options.requestAuthenticator) {
@@ -439,11 +644,57 @@ function resolveRuntimeCredential(options = {}) {
439
644
  authenticate: options.requestAuthenticator,
440
645
  };
441
646
  }
442
- const apiKey = (options.env ?? process.env).ORY_AGENT_API_KEY?.trim();
647
+ const env = options.env ?? process.env;
648
+ if (env.ORY_AGENT_CREDENTIAL_METHOD?.trim() === SPIFFE_CREDENTIAL_METHOD) {
649
+ const expectedClientSpiffeId = requiredEnv(env, "ORY_AGENT_SPIFFE_ID");
650
+ const generationPath = env.ORY_AGENT_SPIFFE_GENERATION_PATH?.trim();
651
+ const certificatePath = env.ORY_AGENT_SPIFFE_SVID_PATH?.trim();
652
+ const privateKeyPath = env.ORY_AGENT_SPIFFE_KEY_PATH?.trim();
653
+ const trustBundlePath = env.ORY_AGENT_SPIFFE_TRUST_BUNDLE_PATH?.trim();
654
+ const generationFile = env.ORY_SPIFFE_GENERATION_FILE?.trim();
655
+ const directPaths = [certificatePath, privateKeyPath, trustBundlePath];
656
+ if (generationPath && directPaths.some(Boolean)) {
657
+ throw new Error("SPIFFE configuration must use either ORY_AGENT_SPIFFE_GENERATION_PATH or direct material paths");
658
+ }
659
+ if (!generationPath && !directPaths.every(Boolean)) {
660
+ throw new Error("SPIFFE configuration requires ORY_AGENT_SPIFFE_GENERATION_PATH or all three direct material paths");
661
+ }
662
+ if (!generationPath && generationFile) {
663
+ throw new Error("ORY_SPIFFE_GENERATION_FILE requires ORY_AGENT_SPIFFE_GENERATION_PATH");
664
+ }
665
+ const expectedServerSpiffeId = env.ORY_AGENT_SPIFFE_SERVER_ID?.trim();
666
+ return {
667
+ kind: "injected",
668
+ ...(options.subject ? { subject: options.subject } : {}),
669
+ authenticate: createSpiffeFileRequestAuthenticator({
670
+ ...(generationPath ? {
671
+ generationPath,
672
+ ...(generationFile
673
+ ? { generationFile }
674
+ : {}),
675
+ } : {
676
+ certificatePath: certificatePath,
677
+ privateKeyPath: privateKeyPath,
678
+ trustBundlePath: trustBundlePath,
679
+ }),
680
+ expectedClientSpiffeId,
681
+ ...(expectedServerSpiffeId
682
+ ? { expectedServerSpiffeId }
683
+ : { verifyHostname: true }),
684
+ }),
685
+ };
686
+ }
687
+ const apiKey = env.ORY_AGENT_API_KEY?.trim();
443
688
  if (!apiKey)
444
689
  return undefined;
445
690
  return talosRuntimeCredential(apiKey, { subject: options.subject, fetch: options.fetch });
446
691
  }
692
+ function requiredEnv(env, name) {
693
+ const value = env[name]?.trim();
694
+ if (!value)
695
+ throw new Error(`SPIFFE configuration requires ${name}`);
696
+ return value;
697
+ }
447
698
  /** Explicitly enroll a Talos credential and optionally persist it in an OS store. */
448
699
  async function enrollTalosRuntimeCredential(options) {
449
700
  let response;
package/dist/runtime.d.ts CHANGED
@@ -26,10 +26,10 @@
26
26
  * wired where, so `status` can report the runtime a harness will actually
27
27
  * load, upgrades can rewire, and unreferenced stores can be pruned.
28
28
  *
29
- * A **linked** runtime (`linkedRuntime`) points the shim straight at a
30
- * workspace build instead of a materialized store. That is the development
31
- * loop: `pnpm build` + relaunch, with no publish, no version bump, and no
32
- * registry involved.
29
+ * A **linked** runtime (`linkedRuntime`) points the shim straight at an
30
+ * explicit prebuilt package directory instead of a materialized store. This
31
+ * supports both administrator-managed runtimes and the workspace development
32
+ * loop (`pnpm build` + relaunch), with no registry involved.
33
33
  *
34
34
  * ## The shim must fail open
35
35
  *
@@ -137,8 +137,8 @@ export declare function materializeRuntime(opts: {
137
137
  installer?: NpmInstaller;
138
138
  }): RuntimeTarget;
139
139
  /**
140
- * Use an already-built package directory as the runtime — the development
141
- * path (`install --link <dir>`), where the workspace build *is* the artifact.
140
+ * Use an explicit prebuilt package directory as the runtime, including a
141
+ * managed installation or workspace build.
142
142
  *
143
143
  * Validates that the directory looks like a built package so a typo surfaces
144
144
  * at install time instead of as hooks that silently never run.
@@ -206,13 +206,19 @@ export declare function writeMcpShim(opts: {
206
206
  target: RuntimeTarget;
207
207
  installCommand: string;
208
208
  }): string | undefined;
209
+ /**
210
+ * Resolve the Node executable persisted in subprocess hook and MCP config.
211
+ * Managed installations can pin an administrator-approved absolute path;
212
+ * ordinary installations retain the portable `node` command lookup.
213
+ */
214
+ export declare function resolvePluginNodePath(env?: NodeJS.ProcessEnv): string;
209
215
  /**
210
216
  * The hook command a harness config should carry: `node "<shim>"`.
211
217
  *
212
- * Quoted because a data dir can contain spaces, and several harnesses run the
213
- * command through a shell.
218
+ * Paths are shell-quoted because managed executables and data dirs can contain
219
+ * spaces or shell metacharacters, and several harnesses run this as a string.
214
220
  */
215
- export declare function hookCommand(shimPath: string): string;
221
+ export declare function hookCommand(shimPath: string, nodePath?: string): string;
216
222
  /**
217
223
  * True when a command in a harness config is one of ours.
218
224
  *
@@ -225,7 +231,7 @@ export declare function hookCommand(shimPath: string): string;
225
231
  */
226
232
  export declare function isOryRuntimeCommand(command: string | undefined): boolean;
227
233
  /** The MCP server registration a harness config should carry. */
228
- export declare function mcpCommand(shimPath: string): {
234
+ export declare function mcpCommand(shimPath: string, nodePath?: string): {
229
235
  command: string;
230
236
  args: string[];
231
237
  };
@@ -296,8 +302,9 @@ export declare function pruneRuntimeStores(): string[];
296
302
  * `ORY_PLUGIN_RUNTIME_DIR` → link that directory
297
303
  * otherwise → materialize the CLI's own version
298
304
  *
299
- * The flag and the env var support explicit source installs that point at an
300
- * already-built workspace package instead of materializing from a registry.
305
+ * The flag and the env var support explicit prebuilt runtime installs,
306
+ * including administrator-managed package directories and workspace builds,
307
+ * instead of materializing from a registry.
301
308
  *
302
309
  * The flag deliberately requires an explicit directory. A bare "link whatever
303
310
  * package I am running from" would resolve to npx's ephemeral cache dir under