feat: encrypted account-level secrets (#501)
* feat: add encrypted account-level secrets with UI for adding API keys Adds AccountSecret model with AES-256-GCM encryption, API routes for CRUD, "Add secret" button in model costs section, and injects decrypted secrets into action env (YAML secrets take precedence). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: repo secrets, sidebar icons, lazy learnings history - add repo-level secrets with inheritance from org secrets - add icons to console sidebar sections - fix learnings history modal: lazy fetch with hover prefetch, strip content from list response, load content per-expansion Made-with: Cursor * add input validation bounds for secrets and fix client-side name filter Made-with: Cursor * refactor: migrate all client-side data fetching to TanStack Query Replace manual useState/useEffect/fetch patterns and the custom usePolling hook with useQuery, useInfiniteQuery, and useMutation across the entire frontend for consistent caching, background refetching, and reactive invalidation. - ActiveWorkflowRunsSection: useQuery + refetchInterval - WorkflowRunHistory: useInfiniteQuery + polling query - LearningsSection: useQuery per revision (lazy) - FlagsSettings: self-contained useQuery + useMutation - SecretsCard: useMutation for delete - AddWorkflowButton, VerifyWorkflowButton: useMutation - EmailSignupForm, email-waitlist: useMutation - providers.tsx: enable refetchOnWindowFocus - Delete usePolling.ts (no remaining consumers) Made-with: Cursor * address PR review: squash migrations, rename accountSecrets → dbSecrets Squash the two separate secrets migrations into a single migration. Rename the wire format field from accountSecrets to dbSecrets since it now carries merged account + repo secrets. Made-with: Cursor * fix: update proxyKeys.ts imports after cache.ts -> yes package migration Made-with: Cursor --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
pullfrog[bot]
parent
0055aef618
commit
ba1966f17c
@@ -107721,7 +107721,7 @@ var providers = {
|
||||
}),
|
||||
google: provider({
|
||||
displayName: "Google",
|
||||
envVars: ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"],
|
||||
envVars: ["GEMINI_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
||||
models: {
|
||||
"gemini-pro": {
|
||||
displayName: "Gemini Pro",
|
||||
@@ -151108,7 +151108,8 @@ async function fetchRunContext(params) {
|
||||
},
|
||||
apiToken: data.apiToken,
|
||||
oss: data.oss ?? false,
|
||||
proxyModel: data.proxyModel
|
||||
proxyModel: data.proxyModel,
|
||||
dbSecrets: data.dbSecrets
|
||||
};
|
||||
} catch {
|
||||
clearTimeout(timeoutId);
|
||||
@@ -151133,7 +151134,8 @@ async function resolveRunContextData(params) {
|
||||
repoSettings: runContext.settings,
|
||||
apiToken: runContext.apiToken,
|
||||
oss: runContext.oss,
|
||||
proxyModel: runContext.proxyModel
|
||||
proxyModel: runContext.proxyModel,
|
||||
dbSecrets: runContext.dbSecrets
|
||||
};
|
||||
}
|
||||
|
||||
@@ -151457,6 +151459,16 @@ async function main() {
|
||||
const initialOctokit = createOctokit(jobToken);
|
||||
const runContext = await resolveRunContextData({ octokit: initialOctokit, token: jobToken });
|
||||
timer.checkpoint("runContextData");
|
||||
if (runContext.dbSecrets) {
|
||||
for (const [key, value2] of Object.entries(runContext.dbSecrets)) {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = value2;
|
||||
core5.setSecret(value2);
|
||||
}
|
||||
}
|
||||
const count = Object.keys(runContext.dbSecrets).length;
|
||||
if (count > 0) log.info(`\xBB ${count} db secret(s) loaded`);
|
||||
}
|
||||
const payload = resolvePayload(resolvedPromptInput, runContext.repoSettings);
|
||||
toolState.model = payload.model;
|
||||
if (payload.event.trigger === "pull_request_synchronize") {
|
||||
|
||||
@@ -169,6 +169,18 @@ export async function main(): Promise<MainResult> {
|
||||
const runContext = await resolveRunContextData({ octokit: initialOctokit, token: jobToken });
|
||||
timer.checkpoint("runContextData");
|
||||
|
||||
// inject account-level secrets into process.env (YAML secrets take precedence)
|
||||
if (runContext.dbSecrets) {
|
||||
for (const [key, value] of Object.entries(runContext.dbSecrets)) {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = value;
|
||||
core.setSecret(value);
|
||||
}
|
||||
}
|
||||
const count = Object.keys(runContext.dbSecrets).length;
|
||||
if (count > 0) log.info(`» ${count} db secret(s) loaded`);
|
||||
}
|
||||
|
||||
// resolve payload to determine shell permission
|
||||
const payload = resolvePayload(resolvedPromptInput, runContext.repoSettings);
|
||||
toolState.model = payload.model;
|
||||
|
||||
@@ -93,7 +93,7 @@ export const providers = {
|
||||
}),
|
||||
google: provider({
|
||||
displayName: "Google",
|
||||
envVars: ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"],
|
||||
envVars: ["GEMINI_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
||||
models: {
|
||||
"gemini-pro": {
|
||||
displayName: "Gemini Pro",
|
||||
|
||||
@@ -37559,7 +37559,7 @@ var providers = {
|
||||
}),
|
||||
google: provider({
|
||||
displayName: "Google",
|
||||
envVars: ["GOOGLE_GENERATIVE_AI_API_KEY", "GEMINI_API_KEY"],
|
||||
envVars: ["GEMINI_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
||||
models: {
|
||||
"gemini-pro": {
|
||||
displayName: "Gemini Pro",
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface RunContext {
|
||||
apiToken: string;
|
||||
oss: boolean;
|
||||
proxyModel?: string | undefined;
|
||||
dbSecrets?: Record<string, string> | undefined;
|
||||
}
|
||||
|
||||
const defaultSettings: RepoSettings = {
|
||||
@@ -82,6 +83,7 @@ export async function fetchRunContext(params: {
|
||||
apiToken: string;
|
||||
oss?: boolean;
|
||||
proxyModel?: string;
|
||||
dbSecrets?: Record<string, string>;
|
||||
} | null;
|
||||
|
||||
if (data === null) {
|
||||
@@ -100,6 +102,7 @@ export async function fetchRunContext(params: {
|
||||
apiToken: data.apiToken,
|
||||
oss: data.oss ?? false,
|
||||
proxyModel: data.proxyModel,
|
||||
dbSecrets: data.dbSecrets,
|
||||
};
|
||||
} catch {
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface RunContextData {
|
||||
apiToken: string;
|
||||
oss: boolean;
|
||||
proxyModel?: string | undefined;
|
||||
dbSecrets?: Record<string, string> | undefined;
|
||||
}
|
||||
|
||||
interface ResolveRunContextDataParams {
|
||||
@@ -46,5 +47,6 @@ export async function resolveRunContextData(
|
||||
apiToken: runContext.apiToken,
|
||||
oss: runContext.oss,
|
||||
proxyModel: runContext.proxyModel,
|
||||
dbSecrets: runContext.dbSecrets,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user