mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-18 21:00:49 +00:00
Improve Foundry auth and task flows (#240)
This commit is contained in:
parent
d75e8c31d1
commit
dbc2ff0682
26 changed files with 621 additions and 137 deletions
|
|
@ -34,6 +34,7 @@ import { getActorRuntimeContext } from "../context.js";
|
|||
import { getTask, getOrCreateHistory, getOrCreateProject, selfWorkspace } from "../handles.js";
|
||||
import { logActorWarning, resolveErrorMessage } from "../logging.js";
|
||||
import { normalizeRemoteUrl, repoIdFromRemote } from "../../services/repo.js";
|
||||
import { resolveWorkspaceGithubAuth } from "../../services/github-auth.js";
|
||||
import { taskLookup, repos, providerProfiles } from "./db/schema.js";
|
||||
import { agentTypeForModel } from "../task/workbench.js";
|
||||
import { expectQueueResponse } from "../../services/queue.js";
|
||||
|
|
@ -213,7 +214,8 @@ async function addRepoMutation(c: any, input: AddRepoInput): Promise<RepoRecord>
|
|||
}
|
||||
|
||||
const { driver } = getActorRuntimeContext();
|
||||
await driver.git.validateRemote(remoteUrl);
|
||||
const auth = await resolveWorkspaceGithubAuth(c, c.state.workspaceId);
|
||||
await driver.git.validateRemote(remoteUrl, { githubToken: auth?.githubToken ?? null });
|
||||
|
||||
const repoId = repoIdFromRemote(remoteUrl);
|
||||
const now = Date.now();
|
||||
|
|
@ -439,7 +441,7 @@ export const workspaceActions = {
|
|||
c.broadcast("workbenchUpdated", { at: Date.now() });
|
||||
},
|
||||
|
||||
async createWorkbenchTask(c: any, input: TaskWorkbenchCreateTaskInput): Promise<{ taskId: string }> {
|
||||
async createWorkbenchTask(c: any, input: TaskWorkbenchCreateTaskInput): Promise<{ taskId: string; tabId?: string }> {
|
||||
const created = await workspaceActions.createTask(c, {
|
||||
workspaceId: c.state.workspaceId,
|
||||
repoId: input.repoId,
|
||||
|
|
@ -448,7 +450,12 @@ export const workspaceActions = {
|
|||
...(input.branch ? { explicitBranchName: input.branch } : {}),
|
||||
...(input.model ? { agentType: agentTypeForModel(input.model) } : {}),
|
||||
});
|
||||
return { taskId: created.taskId };
|
||||
const task = await requireWorkbenchTask(c, created.taskId);
|
||||
const snapshot = await task.getWorkbench({});
|
||||
return {
|
||||
taskId: created.taskId,
|
||||
tabId: snapshot.tabs[0]?.id,
|
||||
};
|
||||
},
|
||||
|
||||
async markWorkbenchUnread(c: any, input: TaskWorkbenchSelectInput): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ function splitScopes(value: string): string[] {
|
|||
.filter((entry) => entry.length > 0);
|
||||
}
|
||||
|
||||
function hasRepoScope(scopes: string[]): boolean {
|
||||
return scopes.some((scope) => scope === "repo" || scope.startsWith("repo:"));
|
||||
}
|
||||
|
||||
function parseEligibleOrganizationIds(value: string): string[] {
|
||||
try {
|
||||
const parsed = JSON.parse(value);
|
||||
|
|
@ -568,6 +572,32 @@ export const workspaceAppActions = {
|
|||
return await buildAppSnapshot(c, input.sessionId);
|
||||
},
|
||||
|
||||
async resolveAppGithubToken(
|
||||
c: any,
|
||||
input: { organizationId: string; requireRepoScope?: boolean },
|
||||
): Promise<{ accessToken: string; scopes: string[] } | null> {
|
||||
assertAppWorkspace(c);
|
||||
const rows = await c.db.select().from(appSessions).orderBy(desc(appSessions.updatedAt)).all();
|
||||
|
||||
for (const row of rows) {
|
||||
if (row.activeOrganizationId !== input.organizationId || !row.githubAccessToken) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const scopes = splitScopes(row.githubScope);
|
||||
if (input.requireRepoScope !== false && !hasRepoScope(scopes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return {
|
||||
accessToken: row.githubAccessToken,
|
||||
scopes,
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
async startAppGithubAuth(c: any, input: { sessionId: string }): Promise<{ url: string }> {
|
||||
assertAppWorkspace(c);
|
||||
const { appShell } = getActorRuntimeContext();
|
||||
|
|
@ -702,18 +732,34 @@ export const workspaceAppActions = {
|
|||
});
|
||||
|
||||
try {
|
||||
const repositories =
|
||||
organization.snapshot.kind === "personal"
|
||||
? await appShell.github.listUserRepositories(session.githubAccessToken)
|
||||
: organization.githubInstallationId
|
||||
? await appShell.github.listInstallationRepositories(organization.githubInstallationId)
|
||||
: (() => {
|
||||
throw new GitHubAppError("GitHub App installation required before importing repositories", 400);
|
||||
})();
|
||||
let repositories;
|
||||
let installationStatus = organization.snapshot.github.installationStatus;
|
||||
|
||||
if (organization.snapshot.kind === "personal") {
|
||||
repositories = await appShell.github.listUserRepositories(session.githubAccessToken);
|
||||
installationStatus = "connected";
|
||||
} else if (organization.githubInstallationId) {
|
||||
try {
|
||||
repositories = await appShell.github.listInstallationRepositories(organization.githubInstallationId);
|
||||
} catch (error) {
|
||||
if (!(error instanceof GitHubAppError) || (error.status !== 403 && error.status !== 404)) {
|
||||
throw error;
|
||||
}
|
||||
repositories = (await appShell.github.listUserRepositories(session.githubAccessToken)).filter((repository) =>
|
||||
repository.fullName.startsWith(`${organization.githubLogin}/`),
|
||||
);
|
||||
installationStatus = "reconnect_required";
|
||||
}
|
||||
} else {
|
||||
repositories = (await appShell.github.listUserRepositories(session.githubAccessToken)).filter((repository) =>
|
||||
repository.fullName.startsWith(`${organization.githubLogin}/`),
|
||||
);
|
||||
installationStatus = "reconnect_required";
|
||||
}
|
||||
|
||||
await workspace.applyOrganizationSyncCompleted({
|
||||
repositories,
|
||||
installationStatus: organization.snapshot.kind === "personal" ? "connected" : organization.snapshot.github.installationStatus,
|
||||
installationStatus,
|
||||
lastSyncLabel: repositories.length > 0 ? "Synced just now" : "No repositories available",
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -181,9 +181,7 @@ SET \`github_sync_status\` = CASE
|
|||
ELSE 'pending'
|
||||
END;
|
||||
`,
|
||||
m0010: `ALTER TABLE \`app_sessions\` ADD COLUMN \`starter_repo_status\` text NOT NULL DEFAULT 'pending';
|
||||
ALTER TABLE \`app_sessions\` ADD COLUMN \`starter_repo_starred_at\` integer;
|
||||
ALTER TABLE \`app_sessions\` ADD COLUMN \`starter_repo_skipped_at\` integer;
|
||||
m0010: `-- no-op: starter_repo_* columns are already present in m0007 app_sessions
|
||||
`,
|
||||
} as const,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue