mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 14:15:24 +00:00
fix(host-metrics): exclude image and firmware filesystems (#1469)
* fix(host-metrics): exclude image and firmware filesystems * fix(ci): build plugin SDK before dependent checks * fix(mysql): keep plugin settings scope indexes within limits * test(mysql): refresh reviewed plugin upgrade SQL
This commit is contained in:
1 parent
c38c2e84b8
commit
710f545e34
14 files changed
+4938
-16
No files matched your search
@@ -0,0 +1,117 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { TestSqliteDatabase, testDialect } from "./test-support.js";
|
||||
import { PluginSettingsRepository } from "../../../database/repositories/plugin-settings-repository.js";
|
||||
|
||||
describe("PluginSettingsRepository", () => {
|
||||
let adapter: TestSqliteDatabase;
|
||||
let repo: PluginSettingsRepository;
|
||||
const pluginId = "p".repeat(255);
|
||||
|
||||
beforeEach(async () => {
|
||||
adapter = new TestSqliteDatabase();
|
||||
repo = new PluginSettingsRepository(await adapter.connect());
|
||||
await adapter.run(sql`
|
||||
INSERT INTO plugins (id, name, version, manifest_json)
|
||||
VALUES (${pluginId}, 'Settings test', '1.0.0', '{}')
|
||||
`);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await adapter.close();
|
||||
});
|
||||
|
||||
it("round-trips every supported scope and updates admin settings", async () => {
|
||||
for (const scope of ["admin", "user", "host", "secret"] as const) {
|
||||
const scopeId = scope === "admin" ? null : "42";
|
||||
await repo.set(pluginId, scope, scopeId, "shared-key", scope);
|
||||
expect(
|
||||
await repo.get(pluginId, scope, scopeId, "shared-key"),
|
||||
).toMatchObject({
|
||||
scope,
|
||||
value: scope,
|
||||
});
|
||||
}
|
||||
await repo.set(pluginId, "admin", null, "shared-key", "updated");
|
||||
expect(await repo.getAll(pluginId, "admin", null)).toHaveLength(1);
|
||||
expect(await repo.get(pluginId, "admin", null, "shared-key")).toMatchObject(
|
||||
{
|
||||
value: "updated",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("preserves full-length Unicode identifiers and distinct key suffixes", async () => {
|
||||
const scopeId = "\u{1f511}".repeat(255);
|
||||
const prefix = "\u{1f511}".repeat(254);
|
||||
await repo.set(pluginId, "user", scopeId, `${prefix}a`, "first");
|
||||
await repo.set(pluginId, "user", scopeId, `${prefix}b`, "second");
|
||||
expect(await repo.getAll(pluginId, "user", scopeId)).toHaveLength(2);
|
||||
expect(
|
||||
await repo.get(pluginId, "user", scopeId, `${prefix}a`),
|
||||
).toMatchObject({
|
||||
value: "first",
|
||||
});
|
||||
expect(
|
||||
await repo.get(pluginId, "user", scopeId, `${prefix}b`),
|
||||
).toMatchObject({
|
||||
value: "second",
|
||||
});
|
||||
});
|
||||
|
||||
it("still rejects duplicate non-null scope keys at the database boundary", async () => {
|
||||
await repo.set(pluginId, "host", "42", "setting", "original");
|
||||
await expect(
|
||||
adapter.run(sql`
|
||||
INSERT INTO plugin_settings (plugin_id, scope, scope_id, ${sql.identifier("key")}, value)
|
||||
VALUES (${pluginId}, 'host', '42', 'setting', 'duplicate')
|
||||
`),
|
||||
).rejects.toThrow();
|
||||
expect(await repo.get(pluginId, "host", "42", "setting")).toMatchObject({
|
||||
value: "original",
|
||||
});
|
||||
});
|
||||
|
||||
it.runIf(testDialect() === "mysql")(
|
||||
"preserves existing settings through the enum upgrade",
|
||||
async () => {
|
||||
const migrationDir = new URL(
|
||||
"../../../../../drizzle/mysql/",
|
||||
import.meta.url,
|
||||
);
|
||||
const create = readFileSync(
|
||||
new URL("0029_open_captain_america.sql", migrationDir),
|
||||
"utf8",
|
||||
)
|
||||
.split("--> statement-breakpoint")[0]
|
||||
.replace("`plugin_settings`", "`plugin_settings_upgrade_test`")
|
||||
.replace("enum('admin','user','host','secret')", "varchar(255)")
|
||||
.replace(/\);\s*$/, ") DEFAULT CHARSET=utf8mb3;");
|
||||
const upgrade = readFileSync(
|
||||
new URL("0061_plugin_settings_scope_enum.sql", migrationDir),
|
||||
"utf8",
|
||||
).replace("`plugin_settings`", "`plugin_settings_upgrade_test`");
|
||||
await adapter.run(sql.raw(create));
|
||||
try {
|
||||
for (const scope of ["admin", "user", "host", "secret"]) {
|
||||
await adapter.run(sql`
|
||||
INSERT INTO plugin_settings_upgrade_test (plugin_id, scope, scope_id, ${sql.identifier("key")}, value, encrypted)
|
||||
VALUES (${pluginId}, ${scope}, ${scope === "admin" ? null : "42"}, 'setting', ${scope}, true)
|
||||
`);
|
||||
}
|
||||
const before = await adapter.query(
|
||||
sql`SELECT * FROM plugin_settings_upgrade_test ORDER BY id`,
|
||||
);
|
||||
await adapter.run(sql.raw(upgrade));
|
||||
expect(
|
||||
await adapter.query(
|
||||
sql`SELECT * FROM plugin_settings_upgrade_test ORDER BY id`,
|
||||
),
|
||||
).toEqual(before);
|
||||
} finally {
|
||||
await adapter.run(sql`DROP TABLE plugin_settings_upgrade_test`);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
+4
-1
@@ -59,7 +59,7 @@ CREATE TABLE `rbac_known_permissions` (
|
||||
CREATE TABLE `plugin_settings` (
|
||||
`id` int AUTO_INCREMENT NOT NULL,
|
||||
`plugin_id` varchar(255) NOT NULL,
|
||||
`scope` varchar(255) NOT NULL,
|
||||
`scope` enum('admin','user','host','secret') NOT NULL,
|
||||
`scope_id` varchar(255),
|
||||
`key` varchar(255) NOT NULL,
|
||||
`value` text,
|
||||
@@ -409,6 +409,9 @@ CREATE INDEX `idx_sync_records_user_seq` ON `sync_records` (`user_id`,`seq`);
|
||||
-- ==== core 0060_mean_gorgon ====
|
||||
DROP TABLE `sync_tombstones`;
|
||||
|
||||
-- ==== core 0061_plugin_settings_scope_enum ====
|
||||
ALTER TABLE `plugin_settings` MODIFY COLUMN `scope` enum('admin','user','host','secret') NOT NULL;
|
||||
|
||||
-- ==== plugin workspaces 0001_adopt_user_workspaces.sql ====
|
||||
-- workspaces 0001: adopt_user_workspaces
|
||||
-- Generated by termix-plugin migrations. Review before committing.
|
||||
|
||||
Reference in new issue
Block a user