feat(device-core): add authorized project read model

This commit is contained in:
Codex
2026-08-10 20:10:29 +03:00
parent 43dc9b1f45
commit f5d7916338
7 changed files with 629 additions and 3 deletions
@@ -237,6 +237,77 @@ test("management API exposes a repository idempotency conflict without retrying"
}
});
test("project query is service-authenticated and forwards only the trusted actor", async () => {
let queriedActor;
const runtime = await startTestServer({
managementApiEnabled: true,
managementToken,
repository: {
health: async () => "ready",
executeManagementCommand: async () => ({ replayed: false, result: {} }),
listAccessibleProjects: async (actor) => {
queriedActor = actor;
return [{ projectRef: "project:11111111-1111-4111-8111-111111111111" }];
},
},
});
try {
const unauthorized = await fetch(
`${runtime.baseUrl}/internal/v1/query/projects`,
);
assert.equal(unauthorized.status, 401);
const response = await fetch(
`${runtime.baseUrl}/internal/v1/query/projects`,
{ headers: managementHeaders() },
);
assert.equal(response.status, 200);
assert.equal((await response.json()).projects.length, 1);
assert.deepEqual(queriedActor, {
userRef: "user:engineer",
hubRole: "admin",
groupRefs: ["group:engineers", "group:operators"],
ownerScopes: [{ scopeKind: "company", ownerRef: "client:example" }],
});
} finally {
await runtime.close();
}
});
test("project workspace query accepts only a canonical project path", async () => {
const projectId = "11111111-1111-4111-8111-111111111111";
let queried;
const runtime = await startTestServer({
managementApiEnabled: true,
managementToken,
repository: {
health: async () => "ready",
executeManagementCommand: async () => ({ replayed: false, result: {} }),
getProjectWorkspace: async (actor, id) => {
queried = { actor, id };
return { project: { projectRef: `project:${id}` }, devices: [] };
},
},
});
try {
const response = await fetch(
`${runtime.baseUrl}/internal/v1/query/projects/${projectId}/workspace`,
{ headers: managementHeaders() },
);
assert.equal(response.status, 200);
assert.equal((await response.json()).workspace.devices.length, 0);
assert.equal(queried.id, projectId);
const invalid = await fetch(
`${runtime.baseUrl}/internal/v1/query/projects/not-a-project/workspace`,
{ headers: managementHeaders() },
);
assert.equal(invalid.status, 404);
} finally {
await runtime.close();
}
});
test("discovery ingest is closed by default", async () => {
const runtime = await startTestServer({
repository: {
@@ -0,0 +1,192 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import {
getDeviceProjectWorkspace,
listAccessibleDeviceProjects,
} from "../src/project-query-repository.mjs";
import { normalizeManagementActor } from "../src/project-management.mjs";
const projectId = "11111111-1111-4111-8111-111111111111";
const actor = normalizeManagementActor({
userRef: "user:device-admin",
hubRole: "admin",
groupRefs: ["group:engineers"],
ownerScopes: [],
});
const timestamp = "2026-08-10T00:00:00.000Z";
test("project list applies direct-grant precedence and returns bounded summaries", async () => {
const client = {
async query(sql) {
assert.match(sql, /from device_projects p/);
return {
rows: [
projectGrantRow({
grant_id: "22222222-2222-4222-8222-222222222222",
principal_kind: "group",
principal_ref: "group:engineers",
project_role: "engineer",
}),
projectGrantRow({
grant_id: "33333333-3333-4333-8333-333333333333",
principal_kind: "user",
principal_ref: "user:device-admin",
project_role: "viewer",
}),
],
};
},
};
const projects = await listAccessibleDeviceProjects(client, actor);
assert.equal(projects.length, 1);
assert.equal(projects[0].access.projectRole, "viewer");
assert.equal(projects[0].access.capabilities.includes("collection.manage"), false);
assert.deepEqual(projects[0].counts, {
devices: 3,
collections: 2,
discoveries: 1,
});
});
test("project workspace returns only masked identity projections", async () => {
const client = workspaceClient();
const workspace = await getDeviceProjectWorkspace(client, actor, projectId);
assert.equal(workspace.project.projectRef, `project:${projectId}`);
assert.equal(workspace.devices[0].identifier.masked, "***********0001");
assert.equal(workspace.discoveries[0].identifier.masked, "***********0001");
assert.equal(workspace.enrollments[0].expectedIdentifier.masked, "***********0001");
const serialized = JSON.stringify(workspace);
assert.equal(serialized.includes("hmac-sha256"), false);
assert.equal(serialized.includes("ndc-credref"), false);
});
test("project read source never selects identifier digests or credential refs", async () => {
const source = await readFile(
new URL("../src/project-query-repository.mjs", import.meta.url),
"utf8",
);
assert.doesNotMatch(
source,
/\b(?:identifier_digest|expected_identifier_digest|credential_ref)\b/,
);
});
function workspaceClient() {
let grantReads = 0;
return {
async query(sql) {
if (/from device_projects p/.test(sql)) {
return { rows: [projectGrantRow()] };
}
if (/from device_project_grants/.test(sql)) {
grantReads += 1;
return { rows: [storedGrantRow()] };
}
if (/from device_instances di/.test(sql)) {
return { rows: [{
id: "44444444-4444-4444-8444-444444444444",
device_key: "pilot-device",
display_name: "Pilot device",
model_profile_ref: "vendor.model.v1",
lifecycle_state: "online",
identifier_kind: "imei",
identifier_masked: "***********0001",
session_state: "online",
last_seen_at: timestamp,
created_at: timestamp,
updated_at: timestamp,
}] };
}
if (/from device_collections dc/.test(sql)) {
return { rows: [{
id: "55555555-5555-4555-8555-555555555555",
collection_key: "pilot-fleet",
name: "Pilot fleet",
description: null,
lifecycle_state: "active",
member_count: "1",
created_at: timestamp,
updated_at: timestamp,
}] };
}
if (/from device_discoveries dd/.test(sql)) {
return { rows: [{
id: "66666666-6666-4666-8666-666666666666",
identifier_kind: "imei",
identifier_masked: "***********0001",
model_profile_ref: "vendor.model.v1",
protocol: "INTERNAL",
lifecycle_state: "quarantine",
first_observed_at: timestamp,
last_observed_at: timestamp,
enrollment_intent_id: "77777777-7777-4777-8777-777777777777",
claimed_device_id: null,
}] };
}
if (/from device_enrollment_intents dei/.test(sql)) {
return { rows: [{
id: "77777777-7777-4777-8777-777777777777",
enrollment_key: "pilot-enrollment",
display_name: "Pilot device",
model_profile_ref: "vendor.model.v1",
expected_identifier_kind: "imei",
expected_identifier_masked: "***********0001",
lifecycle_state: "observed",
observed_discovery_id: "66666666-6666-4666-8666-666666666666",
claimed_device_id: null,
expires_at: null,
created_at: timestamp,
updated_at: timestamp,
}] };
}
throw new Error(`unexpected_query:${sql}`);
},
get grantReads() {
return grantReads;
},
};
}
function projectGrantRow(overrides = {}) {
return {
id: projectId,
project_key: "pilot-project",
name: "Pilot project",
description: null,
lifecycle_state: "active",
owner_scope_id: "88888888-8888-4888-8888-888888888888",
scope_kind: "company",
owner_ref: "client:dctouch",
owner_display_name: "DCTOUCH",
owner_lifecycle_state: "active",
grant_id: "33333333-3333-4333-8333-333333333333",
principal_kind: "user",
principal_ref: "user:device-admin",
project_role: "viewer",
capability_allow: [],
capability_deny: [],
grant_lifecycle_state: "active",
device_count: "3",
collection_count: "2",
discovery_count: "1",
created_at: timestamp,
updated_at: timestamp,
...overrides,
};
}
function storedGrantRow() {
return {
id: "33333333-3333-4333-8333-333333333333",
principal_kind: "user",
principal_ref: "user:device-admin",
project_role: "admin",
capability_allow: [],
capability_deny: [],
lifecycle_state: "active",
};
}