diff --git a/src/services/repo-onboarding-pack.ts b/src/services/repo-onboarding-pack.ts index ae956ba0a6..e7f103437e 100644 --- a/src/services/repo-onboarding-pack.ts +++ b/src/services/repo-onboarding-pack.ts @@ -25,7 +25,11 @@ 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, @@ -33,7 +37,7 @@ export async function buildRepoOnboardingPackPreviewForRepo( options: { refreshManifest?: boolean } = {}, ): Promise { const repo = await getRepository(env, repoFullName); - if (!repo?.isRegistered) { + if (!repo?.isInstalled) { return { error: "repo_not_accepted", repoFullName, diff --git a/test/unit/mcp-output-schemas.test.ts b/test/unit/mcp-output-schemas.test.ts index a859d632f3..0b80cc3c32 100644 --- a/test/unit/mcp-output-schemas.test.ts +++ b/test/unit/mcp-output-schemas.test.ts @@ -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 diff --git a/test/unit/onboarding-pack.test.ts b/test/unit/onboarding-pack.test.ts index 9d582d3197..a5da81f255 100644 --- a/test/unit/onboarding-pack.test.ts +++ b/test/unit/onboarding-pack.test.ts @@ -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; @@ -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" }); }); });