@inkeep/agents-api 0.43.0 → 0.45.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/dist/.well-known/workflow/v1/manifest.debug.json +1 -1
- package/dist/.well-known/workflow/v1/step.cjs +211602 -195751
- package/dist/createApp.js +11 -9
- package/dist/domains/evals/routes/datasetTriggers.d.ts +2 -2
- package/dist/domains/evals/routes/index.d.ts +2 -2
- package/dist/domains/evals/workflow/routes.d.ts +2 -2
- package/dist/domains/manage/index.js +8 -0
- package/dist/domains/manage/routes/availableAgents.d.ts +7 -0
- package/dist/domains/manage/routes/availableAgents.js +94 -0
- package/dist/domains/manage/routes/branches.js +9 -0
- package/dist/domains/manage/routes/conversations.d.ts +2 -2
- package/dist/domains/manage/routes/evals/datasetItems.js +13 -0
- package/dist/domains/manage/routes/evals/datasets.js +9 -0
- package/dist/domains/manage/routes/evals/evaluationJobConfigEvaluatorRelations.js +5 -0
- package/dist/domains/manage/routes/evals/evaluationJobConfigs.js +9 -0
- package/dist/domains/manage/routes/evals/evaluationResults.d.ts +4 -2
- package/dist/domains/manage/routes/evals/evaluationResults.js +9 -0
- package/dist/domains/manage/routes/evals/evaluationRunConfigs.js +9 -0
- package/dist/domains/manage/routes/evals/evaluationSuiteConfigEvaluatorRelations.js +5 -0
- package/dist/domains/manage/routes/evals/evaluationSuiteConfigs.js +9 -0
- package/dist/domains/manage/routes/evals/evaluators.js +9 -0
- package/dist/domains/manage/routes/github.d.ts +16 -0
- package/dist/domains/manage/routes/github.js +511 -0
- package/dist/domains/manage/routes/index.d.ts +2 -2
- package/dist/domains/manage/routes/invitations.d.ts +4 -3
- package/dist/domains/manage/routes/invitations.js +16 -28
- package/dist/domains/manage/routes/mcp.d.ts +2 -2
- package/dist/domains/manage/routes/mcpToolGithubAccess.d.ts +9 -0
- package/dist/domains/manage/routes/mcpToolGithubAccess.js +205 -0
- package/dist/domains/manage/routes/playgroundToken.js +3 -2
- package/dist/domains/manage/routes/projectGithubAccess.d.ts +9 -0
- package/dist/domains/manage/routes/projectGithubAccess.js +167 -0
- package/dist/domains/manage/routes/projectMembers.js +1 -14
- package/dist/domains/manage/routes/projectPermissions.js +2 -9
- package/dist/domains/manage/routes/projects.js +14 -16
- package/dist/domains/manage/routes/signoz.d.ts +2 -2
- package/dist/domains/manage/routes/signoz.js +22 -16
- package/dist/domains/manage/routes/tools.js +4 -2
- package/dist/domains/manage/routes/userOrganizations.d.ts +4 -3
- package/dist/domains/manage/routes/userOrganizations.js +16 -45
- package/dist/domains/manage/routes/userProjectMemberships.js +1 -2
- package/dist/domains/run/agents/Agent.js +29 -2
- package/dist/domains/run/agents/relationTools.js +2 -1
- package/dist/domains/run/constants/execution-limits/defaults.d.ts +1 -1
- package/dist/domains/run/constants/execution-limits/defaults.js +1 -1
- package/dist/domains/run/constants/execution-limits/index.d.ts +1 -1
- package/dist/domains/run/context/ContextResolver.js +1 -1
- package/dist/domains/run/context/validation.d.ts +1 -1
- package/dist/domains/run/services/AgentSession.js +5 -1
- package/dist/domains/run/services/BaseCompressor.js +1 -1
- package/dist/domains/run/services/TriggerService.d.ts +1 -1
- package/dist/domains/run/services/TriggerService.js +15 -13
- package/dist/domains/run/tools/sandbox-utils.js +1 -1
- package/dist/domains/run/types/executionContext.js +3 -1
- package/dist/env.d.ts +12 -2
- package/dist/env.js +37 -32
- package/dist/factory.d.ts +7 -7
- package/dist/factory.js +4 -10
- package/dist/index.d.ts +6 -5
- package/dist/index.js +3 -5
- package/dist/middleware/branchScopedDb.d.ts +1 -1
- package/dist/middleware/evalsAuth.d.ts +1 -1
- package/dist/middleware/manageAuth.d.ts +1 -1
- package/dist/middleware/projectAccess.d.ts +2 -11
- package/dist/middleware/projectAccess.js +7 -33
- package/dist/middleware/projectConfig.d.ts +3 -3
- package/dist/middleware/ref.d.ts +1 -1
- package/dist/middleware/requirePermission.d.ts +2 -2
- package/dist/middleware/requirePermission.js +1 -2
- package/dist/middleware/runAuth.d.ts +4 -4
- package/dist/middleware/runAuth.js +39 -4
- package/dist/middleware/sessionAuth.d.ts +3 -3
- package/dist/middleware/sessionAuth.js +1 -2
- package/dist/middleware/tracing.d.ts +3 -3
- package/dist/openapi.d.ts +1 -2
- package/dist/openapi.js +1 -2
- package/dist/types/runExecutionContext.js +3 -1
- package/package.json +5 -4
- package/dist/domains/github/config.d.ts +0 -14
- package/dist/domains/github/config.js +0 -47
- package/dist/domains/github/index.d.ts +0 -12
- package/dist/domains/github/index.js +0 -18
- package/dist/domains/github/installation.d.ts +0 -34
- package/dist/domains/github/installation.js +0 -172
- package/dist/domains/github/jwks.d.ts +0 -20
- package/dist/domains/github/jwks.js +0 -85
- package/dist/domains/github/oidcToken.d.ts +0 -22
- package/dist/domains/github/oidcToken.js +0 -140
- package/dist/domains/github/routes/tokenExchange.d.ts +0 -7
- package/dist/domains/github/routes/tokenExchange.js +0 -130
- package/dist/initialization.d.ts +0 -6
- package/dist/initialization.js +0 -72
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "../../logger.js";
|
|
2
|
-
import { getGitHubAppConfig } from "./config.js";
|
|
3
|
-
import { createPrivateKey } from "node:crypto";
|
|
4
|
-
import { SignJWT } from "jose";
|
|
5
|
-
|
|
6
|
-
//#region src/domains/github/installation.ts
|
|
7
|
-
const logger = getLogger("github-installation");
|
|
8
|
-
const GITHUB_API_BASE = "https://api.github.com";
|
|
9
|
-
async function createAppJwt() {
|
|
10
|
-
const config = getGitHubAppConfig();
|
|
11
|
-
const privateKey = createPrivateKey({
|
|
12
|
-
key: config.privateKey,
|
|
13
|
-
format: "pem"
|
|
14
|
-
});
|
|
15
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
16
|
-
return await new SignJWT({}).setProtectedHeader({ alg: "RS256" }).setIssuedAt(now - 60).setExpirationTime(now + 600).setIssuer(config.appId).sign(privateKey);
|
|
17
|
-
}
|
|
18
|
-
async function lookupInstallationForRepo(repositoryOwner, repositoryName) {
|
|
19
|
-
let appJwt;
|
|
20
|
-
try {
|
|
21
|
-
appJwt = await createAppJwt();
|
|
22
|
-
} catch (error) {
|
|
23
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
24
|
-
logger.error({ error: message }, "Failed to create GitHub App JWT");
|
|
25
|
-
return {
|
|
26
|
-
success: false,
|
|
27
|
-
errorType: "jwt_error",
|
|
28
|
-
message: `Failed to create GitHub App authentication: ${message}`
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
const url = `${GITHUB_API_BASE}/repos/${repositoryOwner}/${repositoryName}/installation`;
|
|
32
|
-
try {
|
|
33
|
-
const response = await fetch(url, {
|
|
34
|
-
method: "GET",
|
|
35
|
-
headers: {
|
|
36
|
-
Authorization: `Bearer ${appJwt}`,
|
|
37
|
-
Accept: "application/vnd.github+json",
|
|
38
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
39
|
-
"User-Agent": "inkeep-agents-api"
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
if (response.status === 404) return {
|
|
43
|
-
success: false,
|
|
44
|
-
errorType: "not_installed",
|
|
45
|
-
message: `GitHub App is not installed on repository ${repositoryOwner}/${repositoryName}. Please install the Inkeep Agents GitHub App on the repository to enable token exchange.`
|
|
46
|
-
};
|
|
47
|
-
if (!response.ok) {
|
|
48
|
-
const errorText = await response.text();
|
|
49
|
-
logger.error({
|
|
50
|
-
status: response.status,
|
|
51
|
-
error: errorText,
|
|
52
|
-
repositoryOwner,
|
|
53
|
-
repositoryName
|
|
54
|
-
}, "GitHub API error looking up installation");
|
|
55
|
-
return {
|
|
56
|
-
success: false,
|
|
57
|
-
errorType: "api_error",
|
|
58
|
-
message: `GitHub API error (${response.status}): Failed to look up installation for repository`
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
const data = await response.json();
|
|
62
|
-
const installationId = data.id;
|
|
63
|
-
const accountLogin = data.account?.login;
|
|
64
|
-
const accountType = data.account?.type;
|
|
65
|
-
if (typeof installationId !== "number" || typeof accountLogin !== "string") {
|
|
66
|
-
logger.error({ data }, "Unexpected response format from GitHub API");
|
|
67
|
-
return {
|
|
68
|
-
success: false,
|
|
69
|
-
errorType: "api_error",
|
|
70
|
-
message: "Unexpected response format from GitHub API"
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
logger.info({
|
|
74
|
-
installationId,
|
|
75
|
-
accountLogin,
|
|
76
|
-
accountType,
|
|
77
|
-
repositoryOwner,
|
|
78
|
-
repositoryName
|
|
79
|
-
}, "Found GitHub App installation for repository");
|
|
80
|
-
return {
|
|
81
|
-
success: true,
|
|
82
|
-
installation: {
|
|
83
|
-
installationId,
|
|
84
|
-
accountLogin,
|
|
85
|
-
accountType: accountType === "Organization" ? "Organization" : "User"
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
} catch (error) {
|
|
89
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
90
|
-
logger.error({
|
|
91
|
-
error: message,
|
|
92
|
-
repositoryOwner,
|
|
93
|
-
repositoryName
|
|
94
|
-
}, "Error calling GitHub API to look up installation");
|
|
95
|
-
return {
|
|
96
|
-
success: false,
|
|
97
|
-
errorType: "api_error",
|
|
98
|
-
message: `Failed to connect to GitHub API: ${message}`
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
async function generateInstallationAccessToken(installationId) {
|
|
103
|
-
let appJwt;
|
|
104
|
-
try {
|
|
105
|
-
appJwt = await createAppJwt();
|
|
106
|
-
} catch (error) {
|
|
107
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
108
|
-
logger.error({ error: message }, "Failed to create GitHub App JWT for token generation");
|
|
109
|
-
return {
|
|
110
|
-
success: false,
|
|
111
|
-
errorType: "jwt_error",
|
|
112
|
-
message: `Failed to create GitHub App authentication: ${message}`
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
const url = `${GITHUB_API_BASE}/app/installations/${installationId}/access_tokens`;
|
|
116
|
-
try {
|
|
117
|
-
const response = await fetch(url, {
|
|
118
|
-
method: "POST",
|
|
119
|
-
headers: {
|
|
120
|
-
Authorization: `Bearer ${appJwt}`,
|
|
121
|
-
Accept: "application/vnd.github+json",
|
|
122
|
-
"X-GitHub-Api-Version": "2022-11-28",
|
|
123
|
-
"User-Agent": "inkeep-agents-api"
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
if (!response.ok) {
|
|
127
|
-
const errorText = await response.text();
|
|
128
|
-
logger.error({
|
|
129
|
-
status: response.status,
|
|
130
|
-
error: errorText,
|
|
131
|
-
installationId
|
|
132
|
-
}, "GitHub API error generating installation access token");
|
|
133
|
-
return {
|
|
134
|
-
success: false,
|
|
135
|
-
errorType: "api_error",
|
|
136
|
-
message: `GitHub API error (${response.status}): Failed to generate installation access token`
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
const data = await response.json();
|
|
140
|
-
const token = data.token;
|
|
141
|
-
const expiresAt = data.expires_at;
|
|
142
|
-
if (typeof token !== "string" || typeof expiresAt !== "string") {
|
|
143
|
-
logger.error({ data }, "Unexpected response format from GitHub API for token generation");
|
|
144
|
-
return {
|
|
145
|
-
success: false,
|
|
146
|
-
errorType: "api_error",
|
|
147
|
-
message: "Unexpected response format from GitHub API"
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
return {
|
|
151
|
-
success: true,
|
|
152
|
-
accessToken: {
|
|
153
|
-
token,
|
|
154
|
-
expiresAt
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
} catch (error) {
|
|
158
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
159
|
-
logger.error({
|
|
160
|
-
error: message,
|
|
161
|
-
installationId
|
|
162
|
-
}, "Error calling GitHub API to generate installation access token");
|
|
163
|
-
return {
|
|
164
|
-
success: false,
|
|
165
|
-
errorType: "api_error",
|
|
166
|
-
message: `Failed to connect to GitHub API: ${message}`
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
//#endregion
|
|
172
|
-
export { generateInstallationAccessToken, lookupInstallationForRepo };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { CryptoKey, JWSHeaderParameters } from "jose";
|
|
2
|
-
|
|
3
|
-
//#region src/domains/github/jwks.d.ts
|
|
4
|
-
interface JwksResult {
|
|
5
|
-
success: true;
|
|
6
|
-
key: CryptoKey;
|
|
7
|
-
}
|
|
8
|
-
interface JwksError {
|
|
9
|
-
success: false;
|
|
10
|
-
error: string;
|
|
11
|
-
}
|
|
12
|
-
type GetJwkResult = JwksResult | JwksError;
|
|
13
|
-
declare function getJwkForToken(header: JWSHeaderParameters): Promise<GetJwkResult>;
|
|
14
|
-
declare function clearJwksCache(): void;
|
|
15
|
-
declare function getJwksCacheStatus(): {
|
|
16
|
-
cached: boolean;
|
|
17
|
-
expiresIn?: number;
|
|
18
|
-
};
|
|
19
|
-
//#endregion
|
|
20
|
-
export { GetJwkResult, JwksError, JwksResult, clearJwksCache, getJwkForToken, getJwksCacheStatus };
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "../../logger.js";
|
|
2
|
-
import { createRemoteJWKSet } from "jose";
|
|
3
|
-
|
|
4
|
-
//#region src/domains/github/jwks.ts
|
|
5
|
-
const logger = getLogger("github-jwks");
|
|
6
|
-
const GITHUB_OIDC_JWKS_URL = "https://token.actions.githubusercontent.com/.well-known/jwks";
|
|
7
|
-
const CACHE_TTL_MS = 3600 * 1e3;
|
|
8
|
-
let jwksCache = null;
|
|
9
|
-
function createJwksWithLogging() {
|
|
10
|
-
logger.info({}, "Creating new JWKS fetch function for GitHub OIDC");
|
|
11
|
-
return createRemoteJWKSet(new URL(GITHUB_OIDC_JWKS_URL), { cacheMaxAge: CACHE_TTL_MS });
|
|
12
|
-
}
|
|
13
|
-
function isCacheExpired() {
|
|
14
|
-
if (!jwksCache) return true;
|
|
15
|
-
return Date.now() - jwksCache.fetchedAt > CACHE_TTL_MS;
|
|
16
|
-
}
|
|
17
|
-
function getOrCreateJwksFunction() {
|
|
18
|
-
if (!jwksCache || isCacheExpired()) jwksCache = {
|
|
19
|
-
jwks: createJwksWithLogging(),
|
|
20
|
-
fetchedAt: Date.now()
|
|
21
|
-
};
|
|
22
|
-
return jwksCache.jwks;
|
|
23
|
-
}
|
|
24
|
-
async function getJwkForToken(header) {
|
|
25
|
-
const kid = header.kid;
|
|
26
|
-
if (!kid) return {
|
|
27
|
-
success: false,
|
|
28
|
-
error: "Token is missing key ID (kid) in header"
|
|
29
|
-
};
|
|
30
|
-
try {
|
|
31
|
-
const key = await getOrCreateJwksFunction()(header);
|
|
32
|
-
logger.debug({ kid }, "Successfully retrieved JWK for token");
|
|
33
|
-
return {
|
|
34
|
-
success: true,
|
|
35
|
-
key
|
|
36
|
-
};
|
|
37
|
-
} catch (error) {
|
|
38
|
-
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
39
|
-
if (errorMessage.includes("no applicable key found")) {
|
|
40
|
-
logger.warn({ kid }, "Key ID not found in JWKS, refreshing cache");
|
|
41
|
-
jwksCache = null;
|
|
42
|
-
try {
|
|
43
|
-
const key = await getOrCreateJwksFunction()(header);
|
|
44
|
-
logger.info({ kid }, "Successfully retrieved JWK after cache refresh");
|
|
45
|
-
return {
|
|
46
|
-
success: true,
|
|
47
|
-
key
|
|
48
|
-
};
|
|
49
|
-
} catch (retryError) {
|
|
50
|
-
const retryErrorMessage = retryError instanceof Error ? retryError.message : "Unknown error";
|
|
51
|
-
logger.error({
|
|
52
|
-
kid,
|
|
53
|
-
error: retryErrorMessage
|
|
54
|
-
}, "Failed to retrieve JWK after cache refresh");
|
|
55
|
-
return {
|
|
56
|
-
success: false,
|
|
57
|
-
error: `Key ID '${kid}' not found in GitHub OIDC JWKS`
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
logger.error({
|
|
62
|
-
kid,
|
|
63
|
-
error: errorMessage
|
|
64
|
-
}, "Failed to fetch JWKS from GitHub");
|
|
65
|
-
return {
|
|
66
|
-
success: false,
|
|
67
|
-
error: `Failed to fetch GitHub OIDC JWKS: ${errorMessage}`
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
function clearJwksCache() {
|
|
72
|
-
jwksCache = null;
|
|
73
|
-
logger.debug({}, "JWKS cache cleared");
|
|
74
|
-
}
|
|
75
|
-
function getJwksCacheStatus() {
|
|
76
|
-
if (!jwksCache) return { cached: false };
|
|
77
|
-
const expiresIn = CACHE_TTL_MS - (Date.now() - jwksCache.fetchedAt);
|
|
78
|
-
return {
|
|
79
|
-
cached: true,
|
|
80
|
-
expiresIn: Math.max(0, expiresIn)
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
//#endregion
|
|
85
|
-
export { clearJwksCache, getJwkForToken, getJwksCacheStatus };
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//#region src/domains/github/oidcToken.d.ts
|
|
2
|
-
interface GitHubOidcClaims {
|
|
3
|
-
repository: string;
|
|
4
|
-
repository_owner: string;
|
|
5
|
-
repository_id: string;
|
|
6
|
-
workflow: string;
|
|
7
|
-
actor: string;
|
|
8
|
-
ref: string;
|
|
9
|
-
}
|
|
10
|
-
interface ValidateTokenResult {
|
|
11
|
-
success: true;
|
|
12
|
-
claims: GitHubOidcClaims;
|
|
13
|
-
}
|
|
14
|
-
interface ValidateTokenError {
|
|
15
|
-
success: false;
|
|
16
|
-
errorType: 'invalid_signature' | 'expired' | 'wrong_issuer' | 'wrong_audience' | 'malformed' | 'jwks_error';
|
|
17
|
-
message: string;
|
|
18
|
-
}
|
|
19
|
-
type ValidateOidcTokenResult = ValidateTokenResult | ValidateTokenError;
|
|
20
|
-
declare function validateOidcToken(token: string): Promise<ValidateOidcTokenResult>;
|
|
21
|
-
//#endregion
|
|
22
|
-
export { GitHubOidcClaims, ValidateOidcTokenResult, ValidateTokenError, ValidateTokenResult, validateOidcToken };
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "../../logger.js";
|
|
2
|
-
import { getJwkForToken } from "./jwks.js";
|
|
3
|
-
import { decodeProtectedHeader, errors, jwtVerify } from "jose";
|
|
4
|
-
|
|
5
|
-
//#region src/domains/github/oidcToken.ts
|
|
6
|
-
const logger = getLogger("github-oidc-token");
|
|
7
|
-
const GITHUB_OIDC_ISSUER = "https://token.actions.githubusercontent.com";
|
|
8
|
-
const EXPECTED_AUDIENCE = "inkeep-agents-action";
|
|
9
|
-
async function validateOidcToken(token) {
|
|
10
|
-
let header;
|
|
11
|
-
try {
|
|
12
|
-
header = decodeProtectedHeader(token);
|
|
13
|
-
} catch (error) {
|
|
14
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
15
|
-
logger.warn({ error: message }, "Failed to decode JWT header");
|
|
16
|
-
return {
|
|
17
|
-
success: false,
|
|
18
|
-
errorType: "malformed",
|
|
19
|
-
message: "Invalid JWT format: unable to decode token header"
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
if (header.alg !== "RS256") {
|
|
23
|
-
logger.warn({ algorithm: header.alg }, "Unexpected JWT algorithm");
|
|
24
|
-
return {
|
|
25
|
-
success: false,
|
|
26
|
-
errorType: "malformed",
|
|
27
|
-
message: `Invalid JWT algorithm: expected RS256, got ${header.alg}`
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
const jwkResult = await getJwkForToken(header);
|
|
31
|
-
if (!jwkResult.success) {
|
|
32
|
-
logger.error({ error: jwkResult.error }, "Failed to get JWK for token");
|
|
33
|
-
return {
|
|
34
|
-
success: false,
|
|
35
|
-
errorType: "jwks_error",
|
|
36
|
-
message: jwkResult.error
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
const { payload } = await jwtVerify(token, jwkResult.key, {
|
|
41
|
-
issuer: GITHUB_OIDC_ISSUER,
|
|
42
|
-
audience: EXPECTED_AUDIENCE
|
|
43
|
-
});
|
|
44
|
-
const repository = payload.repository;
|
|
45
|
-
const repositoryOwner = payload.repository_owner;
|
|
46
|
-
const repositoryId = payload.repository_id;
|
|
47
|
-
const workflow = payload.workflow;
|
|
48
|
-
const actor = payload.actor;
|
|
49
|
-
const ref = payload.ref;
|
|
50
|
-
if (typeof repository !== "string" || typeof repositoryOwner !== "string" || typeof repositoryId !== "string" || typeof workflow !== "string" || typeof actor !== "string" || typeof ref !== "string") {
|
|
51
|
-
logger.warn({ payload }, "OIDC token missing required claims");
|
|
52
|
-
return {
|
|
53
|
-
success: false,
|
|
54
|
-
errorType: "malformed",
|
|
55
|
-
message: "OIDC token missing required claims: repository, repository_owner, repository_id, workflow, actor, or ref"
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
logger.info({
|
|
59
|
-
repository,
|
|
60
|
-
actor
|
|
61
|
-
}, "Successfully validated OIDC token");
|
|
62
|
-
return {
|
|
63
|
-
success: true,
|
|
64
|
-
claims: {
|
|
65
|
-
repository,
|
|
66
|
-
repository_owner: repositoryOwner,
|
|
67
|
-
repository_id: repositoryId,
|
|
68
|
-
workflow,
|
|
69
|
-
actor,
|
|
70
|
-
ref
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
} catch (error) {
|
|
74
|
-
if (error instanceof errors.JWTExpired) {
|
|
75
|
-
logger.warn({}, "OIDC token has expired");
|
|
76
|
-
return {
|
|
77
|
-
success: false,
|
|
78
|
-
errorType: "expired",
|
|
79
|
-
message: "OIDC token has expired"
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
if (error instanceof errors.JWTClaimValidationFailed) {
|
|
83
|
-
const claimError = error;
|
|
84
|
-
if (claimError.claim === "iss") {
|
|
85
|
-
logger.warn({ issuer: claimError.reason }, "Invalid OIDC token issuer");
|
|
86
|
-
return {
|
|
87
|
-
success: false,
|
|
88
|
-
errorType: "wrong_issuer",
|
|
89
|
-
message: `Invalid token issuer: expected ${GITHUB_OIDC_ISSUER}`
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
if (claimError.claim === "aud") {
|
|
93
|
-
logger.warn({ audience: claimError.reason }, "Invalid OIDC token audience");
|
|
94
|
-
return {
|
|
95
|
-
success: false,
|
|
96
|
-
errorType: "wrong_audience",
|
|
97
|
-
message: `Invalid token audience: expected ${EXPECTED_AUDIENCE}`
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
logger.warn({
|
|
101
|
-
claim: claimError.claim,
|
|
102
|
-
reason: claimError.reason
|
|
103
|
-
}, "JWT claim validation failed");
|
|
104
|
-
return {
|
|
105
|
-
success: false,
|
|
106
|
-
errorType: "malformed",
|
|
107
|
-
message: `JWT claim validation failed: ${claimError.claim} ${claimError.reason}`
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
if (error instanceof errors.JWSSignatureVerificationFailed) {
|
|
111
|
-
logger.warn({}, "Invalid OIDC token signature");
|
|
112
|
-
return {
|
|
113
|
-
success: false,
|
|
114
|
-
errorType: "invalid_signature",
|
|
115
|
-
message: "Invalid token signature"
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
if (error instanceof errors.JOSEError) {
|
|
119
|
-
logger.error({
|
|
120
|
-
error: error.message,
|
|
121
|
-
code: error.code
|
|
122
|
-
}, "JOSE error during token validation");
|
|
123
|
-
return {
|
|
124
|
-
success: false,
|
|
125
|
-
errorType: "malformed",
|
|
126
|
-
message: `Token validation error: ${error.message}`
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
130
|
-
logger.error({ error: message }, "Unexpected error during token validation");
|
|
131
|
-
return {
|
|
132
|
-
success: false,
|
|
133
|
-
errorType: "malformed",
|
|
134
|
-
message: `Token validation error: ${message}`
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
//#endregion
|
|
140
|
-
export { validateOidcToken };
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import { getLogger } from "../../../logger.js";
|
|
2
|
-
import { isGitHubAppConfigured } from "../config.js";
|
|
3
|
-
import { generateInstallationAccessToken, lookupInstallationForRepo } from "../installation.js";
|
|
4
|
-
import { validateOidcToken } from "../oidcToken.js";
|
|
5
|
-
import { Hono } from "hono";
|
|
6
|
-
import { z } from "zod";
|
|
7
|
-
|
|
8
|
-
//#region src/domains/github/routes/tokenExchange.ts
|
|
9
|
-
const logger = getLogger("github-token-exchange");
|
|
10
|
-
const TokenExchangeRequestSchema = z.object({ oidc_token: z.string() });
|
|
11
|
-
const app = new Hono();
|
|
12
|
-
/**
|
|
13
|
-
* Exchange GitHub OIDC token for installation token.
|
|
14
|
-
*
|
|
15
|
-
* This is an internal infrastructure endpoint called by the CLI from GitHub Actions.
|
|
16
|
-
* It exchanges a GitHub Actions OIDC token for a GitHub App installation access token.
|
|
17
|
-
* Not included in the public OpenAPI spec.
|
|
18
|
-
*/
|
|
19
|
-
app.post("/", async (c) => {
|
|
20
|
-
const rawBody = await c.req.json().catch(() => null);
|
|
21
|
-
const parseResult = TokenExchangeRequestSchema.safeParse(rawBody);
|
|
22
|
-
if (!parseResult.success) {
|
|
23
|
-
const errorMessage = parseResult.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
|
|
24
|
-
c.header("Content-Type", "application/problem+json");
|
|
25
|
-
return c.json({
|
|
26
|
-
title: "Bad Request",
|
|
27
|
-
status: 400,
|
|
28
|
-
detail: errorMessage,
|
|
29
|
-
error: errorMessage
|
|
30
|
-
}, 400);
|
|
31
|
-
}
|
|
32
|
-
const body = parseResult.data;
|
|
33
|
-
logger.info({}, "Processing token exchange request");
|
|
34
|
-
if (!isGitHubAppConfigured()) {
|
|
35
|
-
logger.error({}, "GitHub App credentials not configured");
|
|
36
|
-
const errorMessage = "GitHub App credentials are not configured. Please contact the administrator to set up GITHUB_APP_ID and GITHUB_APP_PRIVATE_KEY.";
|
|
37
|
-
c.header("Content-Type", "application/problem+json");
|
|
38
|
-
return c.json({
|
|
39
|
-
title: "GitHub App Not Configured",
|
|
40
|
-
status: 500,
|
|
41
|
-
detail: errorMessage,
|
|
42
|
-
error: errorMessage
|
|
43
|
-
}, 500);
|
|
44
|
-
}
|
|
45
|
-
const validationResult = await validateOidcToken(body.oidc_token);
|
|
46
|
-
if (!validationResult.success) {
|
|
47
|
-
const errorType = validationResult.errorType;
|
|
48
|
-
logger.warn({
|
|
49
|
-
errorType,
|
|
50
|
-
message: validationResult.message
|
|
51
|
-
}, "OIDC token validation failed");
|
|
52
|
-
c.header("Content-Type", "application/problem+json");
|
|
53
|
-
if (errorType === "malformed") return c.json({
|
|
54
|
-
title: "Bad Request",
|
|
55
|
-
status: 400,
|
|
56
|
-
detail: validationResult.message,
|
|
57
|
-
error: validationResult.message
|
|
58
|
-
}, 400);
|
|
59
|
-
return c.json({
|
|
60
|
-
title: "Token Validation Failed",
|
|
61
|
-
status: 401,
|
|
62
|
-
detail: validationResult.message,
|
|
63
|
-
error: validationResult.message
|
|
64
|
-
}, 401);
|
|
65
|
-
}
|
|
66
|
-
const { claims } = validationResult;
|
|
67
|
-
const installationResult = await lookupInstallationForRepo(claims.repository_owner, claims.repository.split("/")[1]);
|
|
68
|
-
if (!installationResult.success) {
|
|
69
|
-
const { errorType, message } = installationResult;
|
|
70
|
-
if (errorType === "not_installed") {
|
|
71
|
-
c.header("Content-Type", "application/problem+json");
|
|
72
|
-
return c.json({
|
|
73
|
-
title: "GitHub App Not Installed",
|
|
74
|
-
status: 403,
|
|
75
|
-
detail: message,
|
|
76
|
-
error: message
|
|
77
|
-
}, 403);
|
|
78
|
-
}
|
|
79
|
-
logger.error({
|
|
80
|
-
errorType,
|
|
81
|
-
message,
|
|
82
|
-
repository: claims.repository
|
|
83
|
-
}, "Failed to look up GitHub App installation");
|
|
84
|
-
c.header("Content-Type", "application/problem+json");
|
|
85
|
-
return c.json({
|
|
86
|
-
title: "Installation Lookup Failed",
|
|
87
|
-
status: 500,
|
|
88
|
-
detail: message,
|
|
89
|
-
error: message
|
|
90
|
-
}, 500);
|
|
91
|
-
}
|
|
92
|
-
const { installation } = installationResult;
|
|
93
|
-
logger.info({
|
|
94
|
-
installationId: installation.installationId,
|
|
95
|
-
repository: claims.repository
|
|
96
|
-
}, "Found GitHub App installation");
|
|
97
|
-
const tokenResult = await generateInstallationAccessToken(installation.installationId);
|
|
98
|
-
if (!tokenResult.success) {
|
|
99
|
-
const { errorType, message } = tokenResult;
|
|
100
|
-
logger.error({
|
|
101
|
-
errorType,
|
|
102
|
-
message,
|
|
103
|
-
installationId: installation.installationId,
|
|
104
|
-
repository: claims.repository
|
|
105
|
-
}, "Failed to generate installation access token");
|
|
106
|
-
c.header("Content-Type", "application/problem+json");
|
|
107
|
-
return c.json({
|
|
108
|
-
title: "Token Generation Failed",
|
|
109
|
-
status: 500,
|
|
110
|
-
detail: message,
|
|
111
|
-
error: message
|
|
112
|
-
}, 500);
|
|
113
|
-
}
|
|
114
|
-
const { accessToken } = tokenResult;
|
|
115
|
-
logger.info({
|
|
116
|
-
installationId: installation.installationId,
|
|
117
|
-
repository: claims.repository,
|
|
118
|
-
expiresAt: accessToken.expiresAt
|
|
119
|
-
}, "Token exchange completed successfully");
|
|
120
|
-
return c.json({
|
|
121
|
-
token: accessToken.token,
|
|
122
|
-
expires_at: accessToken.expiresAt,
|
|
123
|
-
repository: claims.repository,
|
|
124
|
-
installation_id: installation.installationId
|
|
125
|
-
}, 200);
|
|
126
|
-
});
|
|
127
|
-
var tokenExchange_default = app;
|
|
128
|
-
|
|
129
|
-
//#endregion
|
|
130
|
-
export { tokenExchange_default as default };
|
package/dist/initialization.d.ts
DELETED
package/dist/initialization.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { getLogger as getLogger$1 } from "./logger.js";
|
|
2
|
-
import { env } from "./env.js";
|
|
3
|
-
import runDbClient_default from "./data/db/runDbClient.js";
|
|
4
|
-
import { OrgRoles, addUserToOrganization, getUserByEmail, syncOrgMemberToSpiceDb, upsertOrganization } from "@inkeep/agents-core";
|
|
5
|
-
|
|
6
|
-
//#region src/initialization.ts
|
|
7
|
-
const logger = getLogger$1("initialization");
|
|
8
|
-
async function initializeDefaultUser(authInstance) {
|
|
9
|
-
const { INKEEP_AGENTS_MANAGE_UI_USERNAME, INKEEP_AGENTS_MANAGE_UI_PASSWORD, DISABLE_AUTH } = env;
|
|
10
|
-
const hasCredentials = INKEEP_AGENTS_MANAGE_UI_USERNAME && INKEEP_AGENTS_MANAGE_UI_PASSWORD;
|
|
11
|
-
const orgId = env.TENANT_ID;
|
|
12
|
-
const { created } = await upsertOrganization(runDbClient_default)({
|
|
13
|
-
organizationId: orgId,
|
|
14
|
-
name: env.TENANT_ID,
|
|
15
|
-
slug: env.TENANT_ID,
|
|
16
|
-
logo: null,
|
|
17
|
-
metadata: null
|
|
18
|
-
});
|
|
19
|
-
if (created) logger.info({ organizationId: orgId }, "Created default organization");
|
|
20
|
-
else logger.info({ organizationId: orgId }, "Organization already exists");
|
|
21
|
-
if (!hasCredentials || DISABLE_AUTH || !authInstance) {
|
|
22
|
-
logger.info({ hasCredentials: false }, "Skipping default user creation");
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
try {
|
|
26
|
-
let user = await getUserByEmail(runDbClient_default)(INKEEP_AGENTS_MANAGE_UI_USERNAME);
|
|
27
|
-
if (user) logger.info({
|
|
28
|
-
email: INKEEP_AGENTS_MANAGE_UI_USERNAME,
|
|
29
|
-
userId: user.id
|
|
30
|
-
}, "Default user already exists");
|
|
31
|
-
else {
|
|
32
|
-
logger.info({ email: INKEEP_AGENTS_MANAGE_UI_USERNAME }, "Creating default user with Better Auth...");
|
|
33
|
-
if (!(await authInstance.api.signUpEmail({ body: {
|
|
34
|
-
email: INKEEP_AGENTS_MANAGE_UI_USERNAME,
|
|
35
|
-
password: INKEEP_AGENTS_MANAGE_UI_PASSWORD,
|
|
36
|
-
name: INKEEP_AGENTS_MANAGE_UI_USERNAME.split("@")[0]
|
|
37
|
-
} })).user) throw new Error("signUpEmail returned no user");
|
|
38
|
-
user = await getUserByEmail(runDbClient_default)(INKEEP_AGENTS_MANAGE_UI_USERNAME);
|
|
39
|
-
if (!user) throw new Error("User was created but could not be retrieved from database");
|
|
40
|
-
logger.info({
|
|
41
|
-
email: user.email,
|
|
42
|
-
id: user.id
|
|
43
|
-
}, "Default user created from INKEEP_AGENTS_MANAGE_UI_USERNAME/INKEEP_AGENTS_MANAGE_UI_PASSWORD");
|
|
44
|
-
}
|
|
45
|
-
await addUserToOrganization(runDbClient_default)({
|
|
46
|
-
userId: user.id,
|
|
47
|
-
organizationId: orgId,
|
|
48
|
-
role: OrgRoles.ADMIN
|
|
49
|
-
});
|
|
50
|
-
await syncOrgMemberToSpiceDb({
|
|
51
|
-
tenantId: orgId,
|
|
52
|
-
userId: user.id,
|
|
53
|
-
role: OrgRoles.ADMIN,
|
|
54
|
-
action: "add"
|
|
55
|
-
});
|
|
56
|
-
console.log(`🔐 SpiceDB: Synced member ${user.email} as ${OrgRoles.ADMIN} to org ${orgId}`);
|
|
57
|
-
logger.info({
|
|
58
|
-
organizationId: orgId,
|
|
59
|
-
organizationSlug: env.TENANT_ID,
|
|
60
|
-
userId: user.id,
|
|
61
|
-
email: INKEEP_AGENTS_MANAGE_UI_USERNAME
|
|
62
|
-
}, "Initialization complete - login with these credentials");
|
|
63
|
-
} catch (error) {
|
|
64
|
-
logger.error({
|
|
65
|
-
error,
|
|
66
|
-
email: INKEEP_AGENTS_MANAGE_UI_USERNAME
|
|
67
|
-
}, "Failed to create default user");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
//#endregion
|
|
72
|
-
export { initializeDefaultUser };
|