fix: remove legacy device pod grants authority (#906)

Co-authored-by: Codex Agent <codex@hwlab.local>
This commit is contained in:
Lyon
2026-06-05 12:02:51 +08:00
committed by GitHub
parent 69385290d6
commit fc411b00f8
6 changed files with 22 additions and 36 deletions
+17 -10
View File
@@ -73,6 +73,23 @@ test("Postgres workspace update query preserves parameter numbering", async () =
assert.equal(update.params[17], "user");
});
test("Postgres access schema removes legacy device_pod_grants authority", async () => {
const calls = [];
const accessController = createAccessController({
runtimeStore: {
query: async (sql, params = []) => {
calls.push({ sql, params });
return { rows: [] };
}
}
});
await accessController.store.countUsers();
assert.ok(calls.some((call) => call.sql === "DROP TABLE IF EXISTS device_pod_grants"));
assert.equal(calls.some((call) => /CREATE TABLE IF NOT EXISTS device_pod_grants\b/u.test(call.sql)), false);
});
test("cloud api /auth/oidc/login returns 302 to Keycloak when issuer and client are configured", async () => {
const server = createCloudApiServer({
env: { HWLAB_ACCESS_CONTROL_REQUIRED: "1", HWLAB_KEYCLOAK_ISSUER: OIDC_ISSUER, HWLAB_KEYCLOAK_CLIENT_ID: OIDC_CLIENT_ID, HWLAB_PUBLIC_ENDPOINT },
@@ -1088,11 +1105,6 @@ test("cloud api access control grants visible device pods and requires device-po
assert.equal(emptyList.status, 200);
assert.deepEqual(emptyList.body.devicePods, []);
const legacyGrant = await postJson(port, "/v1/admin/device-pod-grants", {
devicePodId: "device-pod-71-freq",
userId: userCreate.body.user.id
}, adminCookie);
assert.equal(legacyGrant.status, 404);
await grantDevicePodAccess(port, adminCookie, userCreate.body.user.id, "device-pod-71-freq", ["viewer", "operator", "job_submitter"]);
await grantDevicePodAccess(port, adminCookie, bobCreate.body.user.id, "device-pod-71-freq", ["viewer", "operator", "job_submitter"]);
@@ -1190,11 +1202,6 @@ test("cloud api access control grants visible device pods and requires device-po
assert.equal(unsupported.status, 400);
assert.equal(unsupported.body.error.code, "unsupported_device_job_intent");
const legacyRevoke = await fetch(`http://127.0.0.1:${port}/v1/admin/device-pod-grants/device-pod-71-freq/${bobCreate.body.user.id}`, {
method: "DELETE",
headers: { cookie: adminCookie }
});
assert.equal(legacyRevoke.status, 404);
await revokeDevicePodAccess(port, adminCookie, bobCreate.body.user.id, "device-pod-71-freq", ["viewer", "operator", "job_submitter"]);
const afterRevoke = await getJson(port, "/v1/device-pods", bobLogin.cookie);
+2 -1
View File
@@ -194,7 +194,8 @@ const ACCESS_SCHEMA_STATEMENTS = Object.freeze([
PRIMARY KEY (user_id, relation, object)
)`,
`CREATE INDEX IF NOT EXISTS idx_access_tuples_user ON access_tuples(user_id, object)`,
`CREATE INDEX IF NOT EXISTS idx_access_tuples_object ON access_tuples(object, relation)`
`CREATE INDEX IF NOT EXISTS idx_access_tuples_object ON access_tuples(object, relation)`,
`DROP TABLE IF EXISTS device_pod_grants`
]);
const MUTATING_INTENTS = new Set([
@@ -184,13 +184,7 @@ CREATE TABLE IF NOT EXISTS device_pods (
updated_at TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS device_pod_grants (
device_pod_id TEXT NOT NULL REFERENCES device_pods(id) ON DELETE CASCADE,
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_by_admin_id TEXT NOT NULL REFERENCES users(id),
created_at TEXT NOT NULL,
PRIMARY KEY (device_pod_id, user_id)
);
DROP TABLE IF EXISTS device_pod_grants;
CREATE TABLE IF NOT EXISTS device_leases (
device_pod_id TEXT PRIMARY KEY REFERENCES device_pods(id) ON DELETE CASCADE,
+2
View File
@@ -39,6 +39,8 @@ test("initial migration skeleton declares every frozen table", async () => {
assert.match(sql, /\btarget\b/);
assert.match(sql, /\bresult\b/);
assert.match(sql, /\btimestamp\b/);
assert.doesNotMatch(sql, /CREATE TABLE IF NOT EXISTS device_pod_grants\b/u);
assert.match(sql, /DROP TABLE IF EXISTS device_pod_grants\b/u);
});
test("initial migration exposes columns required by the durable runtime adapter", async () => {
@@ -106,12 +106,6 @@ test("cloud web proxies authenticated Admin Access write routes without legacy g
publicRoute: false,
routeKey: "DELETE /v1/admin/access/users/usr_alice/tools/hwpod/can-use"
});
assert.deepEqual(cloudWebProxyRoutePolicy("POST", "/v1/admin/device-pod-grants"), {
proxy: false,
authRequired: false,
publicRoute: false,
routeKey: "POST /v1/admin/device-pod-grants"
});
});
test("cloud web proxies only supported authenticated device-pod write routes", () => {
@@ -104,18 +104,6 @@ test("cloud web proxies Admin Access write routes and leaves legacy grants local
});
assert.equal(grantResponse.status, 200);
const legacyResponse = await fetch(`${serverUrl(cloudWeb)}/v1/admin/device-pod-grants`, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ userId: "usr_alice", devicePodId: "D601-71-FREQ" })
});
assert.equal(legacyResponse.status, 404);
assert.deepEqual(await legacyResponse.json(), {
error: "not_found",
serviceId: "hwlab-cloud-web",
path: "/v1/admin/device-pod-grants"
});
assert.equal(upstreamRequests.length, 2);
assert.deepEqual(upstreamRequests[0], {
method: "POST",