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
9 changes: 6 additions & 3 deletions src/review/gittensor-wire.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,13 @@ export function shouldEnableGittensorForRepo(

/**
* The set of repos (lowercased full names) this self-host instance has opted into the gittensor plugin for --
* every locally-known repo (listRepositories, deliberately NOT filtered by isRegistered: isRegistered is
* every locally installed repo (listRepositories, deliberately NOT filtered by isRegistered: isRegistered is
* itself DOWNSTREAM of this decision on self-host, see registry/sync.ts's persistRegistrySnapshot, so filtering
* on it here would be circular -- a repo could never earn its first isRegistered=true) whose manifest sets
* `experimental.gittensor: true` AND the global env kill-switch is on. A per-repo manifest-load error is
* skipped (treated as not-opted-in), never aborts the pass -- mirrors selftune-wire.ts's selfTuneRepos.
* `experimental.gittensor: true` AND the global env kill-switch is on. Registry-only rows from historical
* snapshots are ignored: an external repo's cached manifest must not activate outbound subnet work for this
* instance. A per-repo manifest-load error is skipped (treated as not-opted-in), never aborts the pass -- mirrors
* selftune-wire.ts's selfTuneRepos.
* Flag-OFF (default) short-circuits before listing repos or loading a single manifest, so a plain self-host
* instance makes zero local reads for this and zero outbound gittensor-registry requests (see index.ts).
*/
Expand All @@ -48,6 +50,7 @@ export async function gittensorEnabledRepoFullNames(env: Env & { GITTENSORY_EXPE
const repos = await listRepositories(env);
const enabled = new Set<string>();
for (const repo of repos) {
if (!repo.isInstalled) continue;
try {
const manifest = await loadRepoFocusManifest(env, repo.fullName);
if (shouldEnableGittensorForRepo(env, manifest.experimental.gittensor)) enabled.add(repo.fullName.toLowerCase());
Expand Down
15 changes: 15 additions & 0 deletions test/unit/gittensor-wire.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ async function seedRegisteredRepo(env: Env, fullName: string): Promise<void> {
.run();
}

async function seedRegistryOnlyRepo(env: Env, fullName: string): Promise<void> {
const [owner, name] = fullName.split("/");
await (env.DB as unknown as { prepare: (s: string) => { bind: (...v: unknown[]) => { run: () => Promise<unknown> } } })
.prepare("INSERT INTO repositories (full_name, owner, name, is_installed, is_registered) VALUES (?, ?, ?, 0, 1)")
.bind(fullName, owner, name)
.run();
}

// Wrap env.DB.prepare so any SQL matching `pattern` throws, exercising a fail-safe catch; every other query
// delegates to the real test DB unchanged. Mirrors selftune-wiring.test.ts's poisonDbPrepare.
function poisonDbPrepare(env: Env, pattern: RegExp): void {
Expand Down Expand Up @@ -97,6 +105,13 @@ describe("gittensorEnabledRepoFullNames", () => {
await expect(gittensorEnabledRepoFullNames(env)).resolves.toEqual(new Set(["owner/notyetregistered"]));
});

it("excludes registry-only repos whose cached manifests opt in (regression for the unscoped registry activation bypass)", async () => {
const env = createTestEnv({ GITTENSORY_EXPERIMENTAL_GITTENSOR: "true" });
await seedRegistryOnlyRepo(env, "attacker/external");
await upsertRepoFocusManifest(env, "attacker/external", { experimental: { gittensor: true } });
await expect(gittensorEnabledRepoFullNames(env)).resolves.toEqual(new Set());
});

it("fails safe per-repo: a manifest-load error is swallowed and the pass still resolves", async () => {
const env = createTestEnv({ GITTENSORY_EXPERIMENTAL_GITTENSOR: "true" });
await seedRegisteredRepo(env, "owner/blip");
Expand Down