@true-and-useful/janee 0.8.4 → 0.9.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.
- package/README.md +81 -1
- package/SKILL.md +5 -0
- package/dist/cli/commands/add.d.ts +6 -0
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/add.js +216 -6
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/serve-mcp.d.ts.map +1 -1
- package/dist/cli/commands/serve-mcp.js +71 -1
- package/dist/cli/commands/serve-mcp.js.map +1 -1
- package/dist/cli/commands/status.d.ts +4 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +127 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/config-yaml.d.ts +22 -1
- package/dist/cli/config-yaml.d.ts.map +1 -1
- package/dist/cli/config-yaml.js +34 -1
- package/dist/cli/config-yaml.js.map +1 -1
- package/dist/cli/index.js +16 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/core/agent-scope.d.ts +81 -0
- package/dist/core/agent-scope.d.ts.map +1 -0
- package/dist/core/agent-scope.js +146 -0
- package/dist/core/agent-scope.js.map +1 -0
- package/dist/core/directory.d.ts +1 -1
- package/dist/core/directory.d.ts.map +1 -1
- package/dist/core/directory.js +8 -0
- package/dist/core/directory.js.map +1 -1
- package/dist/core/exec.d.ts +86 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +149 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/github-app.d.ts +32 -0
- package/dist/core/github-app.d.ts.map +1 -0
- package/dist/core/github-app.js +105 -0
- package/dist/core/github-app.js.map +1 -0
- package/dist/core/health.d.ts +27 -0
- package/dist/core/health.d.ts.map +1 -0
- package/dist/core/health.js +73 -0
- package/dist/core/health.js.map +1 -0
- package/dist/core/mcp-server.d.ts +17 -1
- package/dist/core/mcp-server.d.ts.map +1 -1
- package/dist/core/mcp-server.js +299 -11
- package/dist/core/mcp-server.js.map +1 -1
- package/dist/core/sessions.d.ts.map +1 -1
- package/dist/core/sessions.js +11 -1
- package/dist/core/sessions.js.map +1 -1
- package/dist/providers/env.d.ts +27 -0
- package/dist/providers/env.d.ts.map +1 -0
- package/dist/providers/env.js +64 -0
- package/dist/providers/env.js.map +1 -0
- package/dist/providers/filesystem.d.ts +34 -0
- package/dist/providers/filesystem.d.ts.map +1 -0
- package/dist/providers/filesystem.js +143 -0
- package/dist/providers/filesystem.js.map +1 -0
- package/dist/providers/index.d.ts +25 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +39 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/registry.d.ts +40 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +113 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +137 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +135 -0
- package/dist/providers/types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent-scoped credential management for Janee
|
|
4
|
+
*
|
|
5
|
+
* When an agent creates a credential via MCP, it is automatically scoped
|
|
6
|
+
* to that agent. Other agents cannot access it unless the owner (or an admin)
|
|
7
|
+
* explicitly grants access.
|
|
8
|
+
*
|
|
9
|
+
* Access policies:
|
|
10
|
+
* - "agent-only": Only the creating agent can access (default for agent-created creds)
|
|
11
|
+
* - "all-agents": Any agent can access (default for CLI-created creds)
|
|
12
|
+
* - "shared": Specific agents listed in `sharedWith` can access
|
|
13
|
+
*
|
|
14
|
+
* ## Trust Model
|
|
15
|
+
*
|
|
16
|
+
* Agent identity is resolved from the MCP transport session rather than
|
|
17
|
+
* client-asserted tool arguments, when available. The resolution order is:
|
|
18
|
+
*
|
|
19
|
+
* 1. **Transport-bound identity** (preferred): The MCP session metadata
|
|
20
|
+
* (e.g., client certificate, OAuth token subject, or HTTP auth header)
|
|
21
|
+
* provides a verified agentId. This cannot be spoofed.
|
|
22
|
+
*
|
|
23
|
+
* 2. **Client-asserted identity** (fallback): If the transport doesn't carry
|
|
24
|
+
* identity, the agent can self-report via the `agentId` tool argument.
|
|
25
|
+
* This is useful for development/testing but should NOT be trusted in
|
|
26
|
+
* production multi-agent environments.
|
|
27
|
+
*
|
|
28
|
+
* The `resolveAgentIdentity()` function implements this resolution order.
|
|
29
|
+
* Callers should always use it instead of reading `args.agentId` directly.
|
|
30
|
+
*/
|
|
31
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
|
+
exports.resolveAgentIdentity = resolveAgentIdentity;
|
|
33
|
+
exports.cliCreatedOwnership = cliCreatedOwnership;
|
|
34
|
+
exports.agentCreatedOwnership = agentCreatedOwnership;
|
|
35
|
+
exports.canAgentAccess = canAgentAccess;
|
|
36
|
+
exports.grantAccess = grantAccess;
|
|
37
|
+
exports.revokeAccess = revokeAccess;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve agent identity from transport session + fallback to client assertion.
|
|
40
|
+
*
|
|
41
|
+
* In production, transport-bound identity (from session metadata) takes precedence
|
|
42
|
+
* over the client-asserted agentId argument. This prevents spoofing.
|
|
43
|
+
*
|
|
44
|
+
* @param session - MCP session object (may contain transport-bound identity)
|
|
45
|
+
* @param assertedAgentId - Client-asserted agentId from tool arguments (untrusted)
|
|
46
|
+
* @returns Resolved agent ID, or undefined if no identity available
|
|
47
|
+
*/
|
|
48
|
+
function resolveAgentIdentity(session, assertedAgentId) {
|
|
49
|
+
// Priority 1: Transport-bound identity from session metadata
|
|
50
|
+
// (set by authenticated MCP transports — OAuth, mTLS, signed tokens)
|
|
51
|
+
if (session?.metadata?.verifiedAgentId) {
|
|
52
|
+
return session.metadata.verifiedAgentId;
|
|
53
|
+
}
|
|
54
|
+
// Priority 2: Session-level agentId (set during session creation)
|
|
55
|
+
if (session?.agentId) {
|
|
56
|
+
return session.agentId;
|
|
57
|
+
}
|
|
58
|
+
// Priority 3 (fallback): Client-asserted identity from tool arguments.
|
|
59
|
+
// WARNING: This is spoofable. Only use in single-agent or dev environments.
|
|
60
|
+
return assertedAgentId;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Default ownership for credentials created via CLI (human admin)
|
|
64
|
+
*/
|
|
65
|
+
function cliCreatedOwnership() {
|
|
66
|
+
return {
|
|
67
|
+
accessPolicy: 'all-agents',
|
|
68
|
+
createdAt: new Date().toISOString()
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Default ownership for credentials created by an agent via MCP
|
|
73
|
+
*/
|
|
74
|
+
function agentCreatedOwnership(agentId) {
|
|
75
|
+
return {
|
|
76
|
+
createdBy: agentId,
|
|
77
|
+
accessPolicy: 'agent-only',
|
|
78
|
+
createdAt: new Date().toISOString()
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Check whether an agent is allowed to access a credential
|
|
83
|
+
*
|
|
84
|
+
* Rules:
|
|
85
|
+
* 1. If no ownership metadata exists, allow access (backward compat)
|
|
86
|
+
* 2. "all-agents" policy: always allow
|
|
87
|
+
* 3. "agent-only" policy: only the creator
|
|
88
|
+
* 4. "shared" policy: creator + listed agents
|
|
89
|
+
*/
|
|
90
|
+
function canAgentAccess(agentId, ownership) {
|
|
91
|
+
// No ownership metadata = legacy credential, allow all
|
|
92
|
+
if (!ownership)
|
|
93
|
+
return true;
|
|
94
|
+
// All-agents policy = unrestricted
|
|
95
|
+
if (ownership.accessPolicy === 'all-agents')
|
|
96
|
+
return true;
|
|
97
|
+
// Agent must identify themselves for restricted policies
|
|
98
|
+
if (!agentId)
|
|
99
|
+
return false;
|
|
100
|
+
// Agent-only: must be the creator
|
|
101
|
+
if (ownership.accessPolicy === 'agent-only') {
|
|
102
|
+
return ownership.createdBy === agentId;
|
|
103
|
+
}
|
|
104
|
+
// Shared: creator or in the shared list
|
|
105
|
+
if (ownership.accessPolicy === 'shared') {
|
|
106
|
+
if (ownership.createdBy === agentId)
|
|
107
|
+
return true;
|
|
108
|
+
return ownership.sharedWith?.includes(agentId) ?? false;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Grant access to another agent (changes policy to "shared" if needed)
|
|
114
|
+
*/
|
|
115
|
+
function grantAccess(ownership, targetAgentId) {
|
|
116
|
+
const updated = { ...ownership };
|
|
117
|
+
if (updated.accessPolicy === 'agent-only') {
|
|
118
|
+
updated.accessPolicy = 'shared';
|
|
119
|
+
updated.sharedWith = [targetAgentId];
|
|
120
|
+
}
|
|
121
|
+
else if (updated.accessPolicy === 'shared') {
|
|
122
|
+
if (!updated.sharedWith)
|
|
123
|
+
updated.sharedWith = [];
|
|
124
|
+
if (!updated.sharedWith.includes(targetAgentId)) {
|
|
125
|
+
updated.sharedWith.push(targetAgentId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// "all-agents" doesn't need grants
|
|
129
|
+
return updated;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Revoke access from an agent
|
|
133
|
+
*/
|
|
134
|
+
function revokeAccess(ownership, targetAgentId) {
|
|
135
|
+
const updated = { ...ownership };
|
|
136
|
+
if (updated.accessPolicy === 'shared' && updated.sharedWith) {
|
|
137
|
+
updated.sharedWith = updated.sharedWith.filter(id => id !== targetAgentId);
|
|
138
|
+
// If no one is shared with, revert to agent-only
|
|
139
|
+
if (updated.sharedWith.length === 0) {
|
|
140
|
+
updated.accessPolicy = 'agent-only';
|
|
141
|
+
delete updated.sharedWith;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return updated;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=agent-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-scope.js","sourceRoot":"","sources":["../../src/core/agent-scope.ts"],"names":[],"mappings":"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"}
|
package/dist/core/directory.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface ServiceTemplate {
|
|
|
8
8
|
description: string;
|
|
9
9
|
baseUrl: string;
|
|
10
10
|
auth: {
|
|
11
|
-
type: 'bearer' | 'basic' | 'hmac-mexc' | 'hmac-bybit' | 'hmac-okx' | 'headers' | 'service-account';
|
|
11
|
+
type: 'bearer' | 'basic' | 'hmac-mexc' | 'hmac-bybit' | 'hmac-okx' | 'headers' | 'service-account' | 'github-app';
|
|
12
12
|
fields: string[];
|
|
13
13
|
};
|
|
14
14
|
docs?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/core/directory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"directory.d.ts","sourceRoot":"","sources":["../../src/core/directory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QACJ,IAAI,EAAE,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,GAAG,UAAU,GAAG,SAAS,GAAG,iBAAiB,GAAG,YAAY,CAAC;QAClH,MAAM,EAAE,MAAM,EAAE,CAAC;KAClB,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAQD;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAgO7C,CAAC;AAEF;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAYhE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAEpE;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,CAY/D"}
|
package/dist/core/directory.js
CHANGED
|
@@ -36,6 +36,14 @@ exports.serviceDirectory = [
|
|
|
36
36
|
docs: 'https://docs.github.com/en/rest',
|
|
37
37
|
tags: ['developer', 'git', 'code']
|
|
38
38
|
},
|
|
39
|
+
{
|
|
40
|
+
name: 'github-app',
|
|
41
|
+
description: 'GitHub App with installation tokens (for autonomous agents)',
|
|
42
|
+
baseUrl: 'https://api.github.com',
|
|
43
|
+
auth: { type: 'github-app', fields: ['appId', 'pemFile', 'installationId'] },
|
|
44
|
+
docs: 'https://docs.github.com/en/apps',
|
|
45
|
+
tags: ['developer', 'git', 'code']
|
|
46
|
+
},
|
|
39
47
|
{
|
|
40
48
|
name: 'linear',
|
|
41
49
|
description: 'Issue tracking for software teams',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/core/directory.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;
|
|
1
|
+
{"version":3,"file":"directory.js","sourceRoot":"","sources":["../../src/core/directory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secure CLI Execution for Janee (RFC 0001)
|
|
3
|
+
*
|
|
4
|
+
* Executes CLI commands with credentials injected via environment variables.
|
|
5
|
+
* The agent specifies the command to run but never sees the actual credential.
|
|
6
|
+
* Janee's core security property is preserved: agent never sees the key.
|
|
7
|
+
*/
|
|
8
|
+
export interface ExecCapability {
|
|
9
|
+
service: string;
|
|
10
|
+
mode: 'exec';
|
|
11
|
+
allowCommands: string[];
|
|
12
|
+
env: Record<string, string>;
|
|
13
|
+
workDir?: string;
|
|
14
|
+
ttl: string;
|
|
15
|
+
autoApprove?: boolean;
|
|
16
|
+
requiresReason?: boolean;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface ExecRequest {
|
|
20
|
+
capability: string;
|
|
21
|
+
command: string[];
|
|
22
|
+
stdin?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ExecResult {
|
|
25
|
+
stdout: string;
|
|
26
|
+
stderr: string;
|
|
27
|
+
exitCode: number;
|
|
28
|
+
executionTimeMs: number;
|
|
29
|
+
}
|
|
30
|
+
export interface ExecAuditEvent {
|
|
31
|
+
id: string;
|
|
32
|
+
timestamp: string;
|
|
33
|
+
type: 'cli_execution';
|
|
34
|
+
service: string;
|
|
35
|
+
capability: string;
|
|
36
|
+
command: string[];
|
|
37
|
+
exitCode: number;
|
|
38
|
+
executionTimeMs: number;
|
|
39
|
+
stdout: string;
|
|
40
|
+
stderr: string;
|
|
41
|
+
denied?: boolean;
|
|
42
|
+
denyReason?: string;
|
|
43
|
+
reason?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Validate that a command is allowed by the capability's whitelist
|
|
47
|
+
*/
|
|
48
|
+
export declare function validateCommand(command: string[], allowCommands: string[]): {
|
|
49
|
+
allowed: boolean;
|
|
50
|
+
reason?: string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Build environment variables for command execution.
|
|
54
|
+
* Replaces {{credential}} placeholders with the actual secret.
|
|
55
|
+
* Replaces {{apiKey}} and {{apiSecret}} for HMAC-style auth.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildExecEnv(envTemplate: Record<string, string>, credential: string, extraCredentials?: {
|
|
58
|
+
apiKey?: string;
|
|
59
|
+
apiSecret?: string;
|
|
60
|
+
passphrase?: string;
|
|
61
|
+
}): Record<string, string>;
|
|
62
|
+
/**
|
|
63
|
+
* Scrub credential values from output strings.
|
|
64
|
+
* Prevents accidental credential leakage in stdout/stderr.
|
|
65
|
+
*/
|
|
66
|
+
export declare function scrubCredentials(output: string, credential: string, extraCredentials?: {
|
|
67
|
+
apiKey?: string;
|
|
68
|
+
apiSecret?: string;
|
|
69
|
+
passphrase?: string;
|
|
70
|
+
}): string;
|
|
71
|
+
/**
|
|
72
|
+
* Execute a CLI command with injected credentials.
|
|
73
|
+
* Returns stdout/stderr/exitCode without exposing the credential.
|
|
74
|
+
*/
|
|
75
|
+
export declare function executeCommand(command: string[], injectedEnv: Record<string, string>, options: {
|
|
76
|
+
workDir?: string;
|
|
77
|
+
timeout?: number;
|
|
78
|
+
stdin?: string;
|
|
79
|
+
credential: string;
|
|
80
|
+
extraCredentials?: {
|
|
81
|
+
apiKey?: string;
|
|
82
|
+
apiSecret?: string;
|
|
83
|
+
passphrase?: string;
|
|
84
|
+
};
|
|
85
|
+
}): Promise<ExecResult>;
|
|
86
|
+
//# sourceMappingURL=exec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EAAE,EACjB,aAAa,EAAE,MAAM,EAAE,GACtB;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA0BvC;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,UAAU,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9E,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBxB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,gBAAgB,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9E,MAAM,CAmBR;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EAAE,EACjB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnC,OAAO,EAAE;IACP,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACjF,GACA,OAAO,CAAC,UAAU,CAAC,CAuErB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Secure CLI Execution for Janee (RFC 0001)
|
|
4
|
+
*
|
|
5
|
+
* Executes CLI commands with credentials injected via environment variables.
|
|
6
|
+
* The agent specifies the command to run but never sees the actual credential.
|
|
7
|
+
* Janee's core security property is preserved: agent never sees the key.
|
|
8
|
+
*/
|
|
9
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
10
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.validateCommand = validateCommand;
|
|
14
|
+
exports.buildExecEnv = buildExecEnv;
|
|
15
|
+
exports.scrubCredentials = scrubCredentials;
|
|
16
|
+
exports.executeCommand = executeCommand;
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
19
|
+
/**
|
|
20
|
+
* Validate that a command is allowed by the capability's whitelist
|
|
21
|
+
*/
|
|
22
|
+
function validateCommand(command, allowCommands) {
|
|
23
|
+
if (!command || command.length === 0) {
|
|
24
|
+
return { allowed: false, reason: 'Empty command' };
|
|
25
|
+
}
|
|
26
|
+
const executable = path_1.default.basename(command[0]);
|
|
27
|
+
if (!allowCommands.includes(executable)) {
|
|
28
|
+
return {
|
|
29
|
+
allowed: false,
|
|
30
|
+
reason: `Command '${executable}' not allowed by capability. Allowed: ${allowCommands.join(', ')}`
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// Check for shell injection patterns in arguments
|
|
34
|
+
const shellMetachars = /[;&|`$(){}\\<>]/;
|
|
35
|
+
for (let i = 1; i < command.length; i++) {
|
|
36
|
+
if (shellMetachars.test(command[i])) {
|
|
37
|
+
return {
|
|
38
|
+
allowed: false,
|
|
39
|
+
reason: `Argument ${i} contains shell metacharacters. Use structured arguments instead of shell syntax.`
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return { allowed: true };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build environment variables for command execution.
|
|
47
|
+
* Replaces {{credential}} placeholders with the actual secret.
|
|
48
|
+
* Replaces {{apiKey}} and {{apiSecret}} for HMAC-style auth.
|
|
49
|
+
*/
|
|
50
|
+
function buildExecEnv(envTemplate, credential, extraCredentials) {
|
|
51
|
+
const env = {};
|
|
52
|
+
for (const [key, value] of Object.entries(envTemplate)) {
|
|
53
|
+
let resolved = value;
|
|
54
|
+
resolved = resolved.replace(/{{credential}}/g, credential);
|
|
55
|
+
if (extraCredentials?.apiKey) {
|
|
56
|
+
resolved = resolved.replace(/{{apiKey}}/g, extraCredentials.apiKey);
|
|
57
|
+
}
|
|
58
|
+
if (extraCredentials?.apiSecret) {
|
|
59
|
+
resolved = resolved.replace(/{{apiSecret}}/g, extraCredentials.apiSecret);
|
|
60
|
+
}
|
|
61
|
+
if (extraCredentials?.passphrase) {
|
|
62
|
+
resolved = resolved.replace(/{{passphrase}}/g, extraCredentials.passphrase);
|
|
63
|
+
}
|
|
64
|
+
env[key] = resolved;
|
|
65
|
+
}
|
|
66
|
+
return env;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Scrub credential values from output strings.
|
|
70
|
+
* Prevents accidental credential leakage in stdout/stderr.
|
|
71
|
+
*/
|
|
72
|
+
function scrubCredentials(output, credential, extraCredentials) {
|
|
73
|
+
let scrubbed = output;
|
|
74
|
+
// Only scrub if credential is long enough to be meaningful
|
|
75
|
+
if (credential && credential.length >= 8) {
|
|
76
|
+
scrubbed = scrubbed.replaceAll(credential, '[REDACTED]');
|
|
77
|
+
}
|
|
78
|
+
if (extraCredentials?.apiKey && extraCredentials.apiKey.length >= 8) {
|
|
79
|
+
scrubbed = scrubbed.replaceAll(extraCredentials.apiKey, '[REDACTED]');
|
|
80
|
+
}
|
|
81
|
+
if (extraCredentials?.apiSecret && extraCredentials.apiSecret.length >= 8) {
|
|
82
|
+
scrubbed = scrubbed.replaceAll(extraCredentials.apiSecret, '[REDACTED]');
|
|
83
|
+
}
|
|
84
|
+
if (extraCredentials?.passphrase && extraCredentials.passphrase.length >= 8) {
|
|
85
|
+
scrubbed = scrubbed.replaceAll(extraCredentials.passphrase, '[REDACTED]');
|
|
86
|
+
}
|
|
87
|
+
return scrubbed;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Execute a CLI command with injected credentials.
|
|
91
|
+
* Returns stdout/stderr/exitCode without exposing the credential.
|
|
92
|
+
*/
|
|
93
|
+
async function executeCommand(command, injectedEnv, options) {
|
|
94
|
+
const timeout = options.timeout || 30000;
|
|
95
|
+
const startTime = Date.now();
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
const proc = (0, child_process_1.spawn)(command[0], command.slice(1), {
|
|
98
|
+
env: {
|
|
99
|
+
...process.env, // Inherit base env
|
|
100
|
+
...injectedEnv, // Override with injected credentials
|
|
101
|
+
// Safety: prevent credential exfil via common env vars
|
|
102
|
+
HISTFILE: '/dev/null',
|
|
103
|
+
LESSHISTFILE: '/dev/null',
|
|
104
|
+
},
|
|
105
|
+
cwd: options.workDir || '/tmp/janee-exec',
|
|
106
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
107
|
+
timeout,
|
|
108
|
+
// Don't use shell — prevents injection
|
|
109
|
+
shell: false,
|
|
110
|
+
});
|
|
111
|
+
let stdout = '';
|
|
112
|
+
let stderr = '';
|
|
113
|
+
proc.stdout.on('data', (data) => {
|
|
114
|
+
stdout += data.toString();
|
|
115
|
+
});
|
|
116
|
+
proc.stderr.on('data', (data) => {
|
|
117
|
+
stderr += data.toString();
|
|
118
|
+
});
|
|
119
|
+
if (options.stdin) {
|
|
120
|
+
proc.stdin.write(options.stdin);
|
|
121
|
+
proc.stdin.end();
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
proc.stdin.end();
|
|
125
|
+
}
|
|
126
|
+
proc.on('close', (code) => {
|
|
127
|
+
const executionTimeMs = Date.now() - startTime;
|
|
128
|
+
// Scrub credentials from output
|
|
129
|
+
const scrubbedStdout = scrubCredentials(stdout, options.credential, options.extraCredentials);
|
|
130
|
+
const scrubbedStderr = scrubCredentials(stderr, options.credential, options.extraCredentials);
|
|
131
|
+
resolve({
|
|
132
|
+
stdout: scrubbedStdout,
|
|
133
|
+
stderr: scrubbedStderr,
|
|
134
|
+
exitCode: code ?? 1,
|
|
135
|
+
executionTimeMs,
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
proc.on('error', (error) => {
|
|
139
|
+
const executionTimeMs = Date.now() - startTime;
|
|
140
|
+
resolve({
|
|
141
|
+
stdout: '',
|
|
142
|
+
stderr: `Failed to execute command: ${error.message}`,
|
|
143
|
+
exitCode: 127,
|
|
144
|
+
executionTimeMs,
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub App Authentication
|
|
3
|
+
*
|
|
4
|
+
* Handles JWT-based authentication for GitHub Apps, minting short-lived
|
|
5
|
+
* installation tokens that are cached and auto-refreshed.
|
|
6
|
+
*/
|
|
7
|
+
export interface GitHubAppCredentials {
|
|
8
|
+
appId: string;
|
|
9
|
+
privateKey: string;
|
|
10
|
+
installationId: string;
|
|
11
|
+
}
|
|
12
|
+
export interface InstallationToken {
|
|
13
|
+
token: string;
|
|
14
|
+
expires_at: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function validateGitHubAppCredentials(credentials: any): GitHubAppCredentials;
|
|
17
|
+
export declare function createGitHubAppJWT(appId: string, privateKey: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Exchange a GitHub App JWT for an installation access token.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mintInstallationToken(appJwt: string, installationId: string): Promise<InstallationToken>;
|
|
22
|
+
/**
|
|
23
|
+
* Get a cached installation token or mint a fresh one.
|
|
24
|
+
* Refreshes when <10 minutes remaining (tokens last 1 hour).
|
|
25
|
+
*/
|
|
26
|
+
export declare function getInstallationToken(serviceName: string, credentials: GitHubAppCredentials): Promise<string>;
|
|
27
|
+
export declare function clearCachedInstallationToken(serviceName: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Validate credentials by signing a JWT and listing installations.
|
|
30
|
+
*/
|
|
31
|
+
export declare function testGitHubAppAuth(credentials: GitHubAppCredentials): Promise<void>;
|
|
32
|
+
//# sourceMappingURL=github-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-app.d.ts","sourceRoot":"","sources":["../../src/core/github-app.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,GAAG,GAAG,oBAAoB,CAkBnF;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAY5E;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,iBAAiB,CAAC,CA4B5B;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,oBAAoB,GAChC,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAEtE;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAexF"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub App Authentication
|
|
4
|
+
*
|
|
5
|
+
* Handles JWT-based authentication for GitHub Apps, minting short-lived
|
|
6
|
+
* installation tokens that are cached and auto-refreshed.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.validateGitHubAppCredentials = validateGitHubAppCredentials;
|
|
13
|
+
exports.createGitHubAppJWT = createGitHubAppJWT;
|
|
14
|
+
exports.mintInstallationToken = mintInstallationToken;
|
|
15
|
+
exports.getInstallationToken = getInstallationToken;
|
|
16
|
+
exports.clearCachedInstallationToken = clearCachedInstallationToken;
|
|
17
|
+
exports.testGitHubAppAuth = testGitHubAppAuth;
|
|
18
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
19
|
+
const tokenCache = new Map();
|
|
20
|
+
function validateGitHubAppCredentials(credentials) {
|
|
21
|
+
if (!credentials || typeof credentials !== 'object') {
|
|
22
|
+
throw new Error('Invalid credentials: must be an object');
|
|
23
|
+
}
|
|
24
|
+
if (!credentials.appId || typeof credentials.appId !== 'string') {
|
|
25
|
+
throw new Error('Invalid credentials: missing or invalid appId');
|
|
26
|
+
}
|
|
27
|
+
if (!credentials.privateKey || typeof credentials.privateKey !== 'string') {
|
|
28
|
+
throw new Error('Invalid credentials: missing or invalid privateKey');
|
|
29
|
+
}
|
|
30
|
+
if (!credentials.installationId || typeof credentials.installationId !== 'string') {
|
|
31
|
+
throw new Error('Invalid credentials: missing or invalid installationId');
|
|
32
|
+
}
|
|
33
|
+
return credentials;
|
|
34
|
+
}
|
|
35
|
+
function createGitHubAppJWT(appId, privateKey) {
|
|
36
|
+
const now = Math.floor(Date.now() / 1000);
|
|
37
|
+
return jsonwebtoken_1.default.sign({
|
|
38
|
+
iat: now - 60,
|
|
39
|
+
exp: now + 10 * 60,
|
|
40
|
+
iss: appId,
|
|
41
|
+
}, privateKey, { algorithm: 'RS256' });
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Exchange a GitHub App JWT for an installation access token.
|
|
45
|
+
*/
|
|
46
|
+
async function mintInstallationToken(appJwt, installationId) {
|
|
47
|
+
const response = await fetch(`https://api.github.com/app/installations/${installationId}/access_tokens`, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Accept': 'application/vnd.github+json',
|
|
51
|
+
'Authorization': `Bearer ${appJwt}`,
|
|
52
|
+
'User-Agent': 'janee',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const errorText = await response.text();
|
|
57
|
+
throw new Error(`GitHub token mint failed: ${response.status} ${errorText}`);
|
|
58
|
+
}
|
|
59
|
+
const data = (await response.json());
|
|
60
|
+
if (!data.token || !data.expires_at) {
|
|
61
|
+
throw new Error('Invalid token response: missing token or expires_at');
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
token: data.token,
|
|
65
|
+
expires_at: Math.floor(new Date(data.expires_at).getTime() / 1000),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get a cached installation token or mint a fresh one.
|
|
70
|
+
* Refreshes when <10 minutes remaining (tokens last 1 hour).
|
|
71
|
+
*/
|
|
72
|
+
async function getInstallationToken(serviceName, credentials) {
|
|
73
|
+
const cached = tokenCache.get(serviceName);
|
|
74
|
+
if (cached) {
|
|
75
|
+
const timeRemaining = cached.expires_at - Math.floor(Date.now() / 1000);
|
|
76
|
+
if (timeRemaining > 600) {
|
|
77
|
+
return cached.token;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const appJwt = createGitHubAppJWT(credentials.appId, credentials.privateKey);
|
|
81
|
+
const token = await mintInstallationToken(appJwt, credentials.installationId);
|
|
82
|
+
tokenCache.set(serviceName, token);
|
|
83
|
+
return token.token;
|
|
84
|
+
}
|
|
85
|
+
function clearCachedInstallationToken(serviceName) {
|
|
86
|
+
tokenCache.delete(serviceName);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validate credentials by signing a JWT and listing installations.
|
|
90
|
+
*/
|
|
91
|
+
async function testGitHubAppAuth(credentials) {
|
|
92
|
+
const appJwt = createGitHubAppJWT(credentials.appId, credentials.privateKey);
|
|
93
|
+
const response = await fetch('https://api.github.com/app', {
|
|
94
|
+
headers: {
|
|
95
|
+
'Accept': 'application/vnd.github+json',
|
|
96
|
+
'Authorization': `Bearer ${appJwt}`,
|
|
97
|
+
'User-Agent': 'janee',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
const errorText = await response.text();
|
|
102
|
+
throw new Error(`GitHub App auth test failed: ${response.status} ${errorText}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=github-app.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-app.js","sourceRoot":"","sources":["../../src/core/github-app.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health check module for Janee services
|
|
3
|
+
* Provides connectivity and latency checks for configured API backends
|
|
4
|
+
*/
|
|
5
|
+
export interface HealthCheckResult {
|
|
6
|
+
service: string;
|
|
7
|
+
healthy: boolean;
|
|
8
|
+
statusCode?: number;
|
|
9
|
+
latencyMs: number;
|
|
10
|
+
error?: string;
|
|
11
|
+
checkedAt: string;
|
|
12
|
+
}
|
|
13
|
+
export interface HealthCheckOptions {
|
|
14
|
+
timeout?: number;
|
|
15
|
+
fetchFn?: typeof fetch;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if a service endpoint is reachable and responding
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkServiceHealth(serviceName: string, baseUrl: string, options?: HealthCheckOptions): Promise<HealthCheckResult>;
|
|
21
|
+
/**
|
|
22
|
+
* Check health of multiple services in parallel
|
|
23
|
+
*/
|
|
24
|
+
export declare function checkAllServicesHealth(services: Map<string, {
|
|
25
|
+
baseUrl: string;
|
|
26
|
+
}>, options?: HealthCheckOptions): Promise<HealthCheckResult[]>;
|
|
27
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/core/health.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CA6D5B;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC1C,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAK9B"}
|