Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/services/repo-onboarding-pack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@ export function buildRepoOnboardingPackPreviewFromManifest(
}

/**
* Build a sanitized onboarding-pack preview for an accepted (registered) repository.
* Build a sanitized onboarding-pack preview for an installed repository. The preview is derived
* entirely from the repo's own focus manifest/policy compiler (contribution lanes, label policy,
* validation/maintainer expectations) with zero gittensor-subnet economics data, so it is scoped to
* isInstalled like the sibling advisory tools in this same access tier (getMaintainerLane, getLabelAudit,
* getBurdenForecast all use isInstalled-equivalent RBAC with no isRegistered gate) -- not isRegistered.
*/
export async function buildRepoOnboardingPackPreviewForRepo(
env: Env,
repoFullName: string,
options: { refreshManifest?: boolean } = {},
): Promise<RepoOnboardingPackPreviewResponse | { error: string; repoFullName: string }> {
const repo = await getRepository(env, repoFullName);
if (!repo?.isRegistered) {
if (!repo?.isInstalled) {
return {
error: "repo_not_accepted",
repoFullName,
Expand Down
4 changes: 2 additions & 2 deletions test/unit/mcp-output-schemas.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,9 @@ describe("MCP tool calls return schema-valid structured content", () => {
expect(JSON.stringify(data)).not.toMatch(/hotkey|coldkey|wallet|payout|reward/i);
});

it("gittensory_get_repo_onboarding_pack returns a structured preview for a registered repo", async () => {
it("gittensory_get_repo_onboarding_pack returns a structured preview for an installed repo", async () => {
const env = createTestEnv();
await upsertRepositoryFromGitHub(env, { name: "demo", full_name: "octo/demo", private: false, owner: { login: "octo" } });
await upsertRepositoryFromGitHub(env, { name: "demo", full_name: "octo/demo", private: false, owner: { login: "octo" } }, 501);
await env.DB.prepare("UPDATE repositories SET is_registered = 1 WHERE full_name = ?").bind("octo/demo").run();
// Onboarding-pack previews require a maintainer/owner/operator session or a trusted static identity --
// the shared static "mcp" identity (connectTestClient's default) is unconditionally rejected here, unlike
Expand Down
35 changes: 23 additions & 12 deletions test/unit/onboarding-pack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,16 +265,13 @@ describe("buildRepoOnboardingPackPreview", () => {
});

describe("buildRepoOnboardingPackPreviewForRepo", () => {
it("returns preview_only pack for accepted registered repos", async () => {
it("returns preview_only pack for an installed repo", async () => {
const env = createTestEnv();
await upsertRepositoryFromGitHub(
env,
{ name: "gittensory", full_name: "JSONbored/gittensory", private: false, owner: { login: "JSONbored" } },
1,
);
await env.DB.prepare("UPDATE repositories SET is_registered = 1 WHERE full_name = ?")
.bind("JSONbored/gittensory")
.run();
const response = await buildRepoOnboardingPackPreviewForRepo(env, "JSONbored/gittensory");
expect("error" in response).toBe(false);
if ("error" in response) return;
Expand All @@ -284,14 +281,28 @@ describe("buildRepoOnboardingPackPreviewForRepo", () => {
expect(isRepoOnboardingPackPublicSafe(response.preview)).toBe(true);
});

it("rejects onboarding pack preview for unregistered repos", async () => {
it("rejects onboarding pack preview for a repo not installed on this instance", async () => {
const env = createTestEnv();
await upsertRepositoryFromGitHub(
env,
{ name: "unregistered", full_name: "owner/unregistered", private: false, owner: { login: "owner" } },
1,
);
const response = await buildRepoOnboardingPackPreviewForRepo(env, "owner/unregistered");
expect(response).toMatchObject({ error: "repo_not_accepted", repoFullName: "owner/unregistered" });
await upsertRepositoryFromGitHub(env, { name: "not-installed", full_name: "owner/not-installed", private: false, owner: { login: "owner" } });
const response = await buildRepoOnboardingPackPreviewForRepo(env, "owner/not-installed");
expect(response).toMatchObject({ error: "repo_not_accepted", repoFullName: "owner/not-installed" });
});

it("#onboarding-pack-isinstalled: returns a real preview for an installed-but-not-subnet-registered repo", async () => {
// The preview is derived entirely from the repo's own focus manifest/policy compiler (contribution
// lanes, label policy, maintainer expectations) with zero gittensor-subnet economics data, so it must
// not require subnet registration -- it's scoped to isInstalled like the sibling advisory tools.
const env = createTestEnv();
await upsertRepositoryFromGitHub(env, { name: "installed-not-registered", full_name: "acme/installed-not-registered", private: false, owner: { login: "acme" } }, 42);
const response = await buildRepoOnboardingPackPreviewForRepo(env, "acme/installed-not-registered");
expect("error" in response).toBe(false);
});

it("#onboarding-pack-isinstalled: rejects a subnet-registered-but-not-installed repo", async () => {
const env = createTestEnv();
await upsertRepositoryFromGitHub(env, { name: "registered-not-installed", full_name: "acme/registered-not-installed", private: false, owner: { login: "acme" } });
await env.DB.prepare("UPDATE repositories SET is_registered = 1 WHERE full_name = ?").bind("acme/registered-not-installed").run();
const response = await buildRepoOnboardingPackPreviewForRepo(env, "acme/registered-not-installed");
expect(response).toMatchObject({ error: "repo_not_accepted", repoFullName: "acme/registered-not-installed" });
});
});