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
4 changes: 2 additions & 2 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ services:
image: redis:7.0.0
restart: always
ports:
- 6379:6379
- 6381:6379
networks:
- synmetrix_default

Expand All @@ -36,7 +36,7 @@ services:
- ./services/actions/src:/app/src
- ./services/actions/index.js:/app/index.js
ports:
- 3000:3000
- 3001:3000
env_file:
- .env
- .dev.env
Expand Down
73 changes: 72 additions & 1 deletion services/cubejs/src/routes/__tests__/discover.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { describe, it } from "node:test";
import assert from "node:assert/strict";

import { extractCubes, buildDiscoverResponse } from "../discover.js";
import {
extractCubes,
buildDiscoverResponse,
resolvePartitionTeamIds,
} from "../discover.js";

// --- Helpers ---

Expand Down Expand Up @@ -236,4 +240,71 @@ describe("buildDiscoverResponse", () => {
assert.equal(result[0].version_id, null);
assert.deepEqual(result[0].cubes, []);
});

it("filters datasources by partition team IDs", () => {
const dataSources = [
makeDatasource("ds-a", "match", [yamlSchema("a.yml", [{ name: "A" }])], {
team_id: "team-1",
}),
makeDatasource("ds-b", "other", [yamlSchema("b.yml", [{ name: "B" }])], {
team_id: "team-2",
}),
];
const partitionTeamIds = new Set(["team-1"]);
const result = buildDiscoverResponse(dataSources, partitionTeamIds);
assert.equal(result.length, 1);
assert.equal(result[0].id, "ds-a");
});

it("returns all datasources when no partitionTeamIds provided", () => {
const dataSources = [
makeDatasource("ds-a", "a", [], { team_id: "team-1" }),
makeDatasource("ds-b", "b", [], { team_id: "team-2" }),
];
const result = buildDiscoverResponse(dataSources, null);
assert.equal(result.length, 2);
});
});

// --- resolvePartitionTeamIds ---

describe("resolvePartitionTeamIds", () => {
it("returns team IDs matching the partition", () => {
const members = [
{ team_id: "t1", team: { settings: { partition: "blue.is" } } },
{ team_id: "t2", team: { settings: { partition: "other.co" } } },
{ team_id: "t3", team: { settings: { partition: "blue.is" } } },
];
const ids = resolvePartitionTeamIds(members, "blue.is");
assert.equal(ids.size, 2);
assert.ok(ids.has("t1"));
assert.ok(ids.has("t3"));
assert.ok(!ids.has("t2"));
});

it("returns null when no partition in token", () => {
const members = [
{ team_id: "t1", team: { settings: { partition: "blue.is" } } },
];
assert.equal(resolvePartitionTeamIds(members, undefined), null);
assert.equal(resolvePartitionTeamIds(members, null), null);
});

it("returns empty set when no teams match", () => {
const members = [
{ team_id: "t1", team: { settings: { partition: "other.co" } } },
];
const ids = resolvePartitionTeamIds(members, "blue.is");
assert.equal(ids.size, 0);
});

it("handles teams with no settings", () => {
const members = [
{ team_id: "t1", team: { settings: null } },
{ team_id: "t2", team: {} },
{ team_id: "t3" },
];
const ids = resolvePartitionTeamIds(members, "blue.is");
assert.equal(ids.size, 0);
});
});
32 changes: 29 additions & 3 deletions services/cubejs/src/routes/discover.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,29 @@ export function extractCubes(schema) {
}));
}

/**
* Build a set of team IDs whose partition matches the JWT partition claim.
*/
export function resolvePartitionTeamIds(members, partition) {
if (!partition) return null; // no filtering if no partition in token
const ids = new Set();
for (const member of members) {
if (member.team?.settings?.partition === partition) {
ids.add(member.team_id);
}
}
return ids;
}

/**
* Build the datasources response from findUser result.
* When partitionTeamIds is provided, only include datasources from those teams.
*/
export function buildDiscoverResponse(dataSources) {
return dataSources.map((ds) => {
export function buildDiscoverResponse(dataSources, partitionTeamIds) {
const filtered = partitionTeamIds
? dataSources.filter((ds) => partitionTeamIds.has(ds.team_id))
: dataSources;
return filtered.map((ds) => {
const activeBranch =
ds.branches?.find((b) => b.status === "active") || ds.branches?.[0];
const latestVersion = activeBranch?.versions?.[0] || null;
Expand Down Expand Up @@ -103,7 +121,15 @@ export default async function discover(req, res) {
return res.json({ datasources: [] });
}

res.json({ datasources: buildDiscoverResponse(user.dataSources) });
// Only return datasources from the team matching the JWT partition claim
const partitionTeamIds = resolvePartitionTeamIds(
user.members,
payload.partition
);

res.json({
datasources: buildDiscoverResponse(user.dataSources, partitionTeamIds),
});
} catch (err) {
const status = err.status || 500;
if (status >= 500) {
Expand Down
Loading