@stigmer/server 3.17.0 → 3.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boot/compose.d.ts +12 -0
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +4 -2
- package/dist/boot/compose.js.map +1 -1
- package/dist/domain/iampolicy/constants.d.ts +3 -3
- package/dist/domain/iampolicy/constants.js +3 -3
- package/dist/domain/oauthapp/refresolution/refresolution.js +1 -1
- package/dist/domain/oauthapp/refresolution.js +1 -1
- package/dist/domain/platform/controller.d.ts +8 -1
- package/dist/domain/platform/controller.d.ts.map +1 -1
- package/dist/domain/platform/controller.js +2 -3
- package/dist/domain/platform/controller.js.map +1 -1
- package/dist/domain/plugin/constants.d.ts +7 -1
- package/dist/domain/plugin/constants.d.ts.map +1 -1
- package/dist/domain/plugin/constants.js +7 -1
- package/dist/domain/plugin/constants.js.map +1 -1
- package/dist/domain/plugin/materialize/plan.d.ts.map +1 -1
- package/dist/domain/plugin/materialize/plan.js +16 -1
- package/dist/domain/plugin/materialize/plan.js.map +1 -1
- package/dist/domain/plugin/members.d.ts +46 -0
- package/dist/domain/plugin/members.d.ts.map +1 -1
- package/dist/domain/plugin/members.js +31 -8
- package/dist/domain/plugin/members.js.map +1 -1
- package/dist/domain/plugin/push.d.ts +5 -3
- package/dist/domain/plugin/push.d.ts.map +1 -1
- package/dist/domain/plugin/push.js +58 -14
- package/dist/domain/plugin/push.js.map +1 -1
- package/dist/pipeline/apiresource-labels.d.ts +20 -1
- package/dist/pipeline/apiresource-labels.d.ts.map +1 -1
- package/dist/pipeline/apiresource-labels.js +17 -0
- package/dist/pipeline/apiresource-labels.js.map +1 -1
- package/dist/store/interface.d.ts +6 -2
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/package.json +5 -5
- package/src/boot/compose.ts +16 -2
- package/src/domain/iampolicy/constants.ts +3 -3
- package/src/domain/oauthapp/__tests__/oauthapp.test.ts +2 -2
- package/src/domain/oauthapp/__tests__/refresolution.test.ts +2 -2
- package/src/domain/oauthapp/refresolution/refresolution.ts +1 -1
- package/src/domain/oauthapp/refresolution.ts +1 -1
- package/src/domain/platform/__tests__/platform.test.ts +47 -0
- package/src/domain/platform/controller.ts +10 -4
- package/src/domain/plugin/__tests__/materialize.test.ts +42 -47
- package/src/domain/plugin/__tests__/members.test.ts +149 -0
- package/src/domain/plugin/__tests__/plugin.test.ts +219 -8
- package/src/domain/plugin/constants.ts +7 -1
- package/src/domain/plugin/materialize/plan.ts +20 -1
- package/src/domain/plugin/members.ts +76 -7
- package/src/domain/plugin/push.ts +80 -20
- package/src/pipeline/apiresource-labels.ts +26 -1
- package/src/sandbox/__tests__/local-process.integration.test.ts +20 -6
- package/src/store/interface.ts +6 -2
|
@@ -13,7 +13,11 @@
|
|
|
13
13
|
* authorizer's permissive default ALLOWS reserved-label writes by design
|
|
14
14
|
* (the self-hosted operator owns the store), which is why a restrict-shaped
|
|
15
15
|
* predicate here still pairs the label with server-owned state: the
|
|
16
|
-
* plugin-managed guard refuses only beside an existing plugin row
|
|
16
|
+
* plugin-managed guard refuses only beside an existing plugin row, and a
|
|
17
|
+
* plugin adopts a system-content row only when its own claim to the same
|
|
18
|
+
* label was just charged to `can_write_reserved_labels` by the sanitiser
|
|
19
|
+
* (domain/plugin/members.ts) — the label narrows which rows are eligible,
|
|
20
|
+
* the live authorization is what grants.
|
|
17
21
|
*/
|
|
18
22
|
import type { ApiResourceMetadata } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
19
23
|
|
|
@@ -39,6 +43,20 @@ export const DEFAULT_INSTANCE_LABEL = `${RESERVED_LABEL_PREFIX}default-instance`
|
|
|
39
43
|
*/
|
|
40
44
|
export const SYSTEM_MANAGED_LABEL = `${RESERVED_LABEL_PREFIX}system-managed`;
|
|
41
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Marks system content: a resource the platform itself seeded rather than a
|
|
48
|
+
* user authored — the system organization, the default agent, the
|
|
49
|
+
* platform's own MCP servers. The label predates this module (the retired
|
|
50
|
+
* seedpack wrote it on every row it applied; the official plugins' overlays
|
|
51
|
+
* carry it on the resources they replace) and has one server-side meaning:
|
|
52
|
+
* a plugin push may adopt a system-content row that holds a slug the plugin
|
|
53
|
+
* needs, keeping the row's id and everything bound to it, instead of
|
|
54
|
+
* refusing the slug as taken. It never marks a user's resource, so a user's
|
|
55
|
+
* row is never adopted (domain/plugin/members.ts, judgeSlug). The CLI names
|
|
56
|
+
* the same bytes as SYSTEM_ORG_LABEL for the organization it ensures.
|
|
57
|
+
*/
|
|
58
|
+
export const SYSTEM_LABEL = `${RESERVED_LABEL_PREFIX}system`;
|
|
59
|
+
|
|
42
60
|
/**
|
|
43
61
|
* The only value that activates a reserved marker label; any other value is
|
|
44
62
|
* inert (matching cloud's "true".equals(...)). Stamped by the flows that
|
|
@@ -86,3 +104,10 @@ export function isDefaultInstance(
|
|
|
86
104
|
): boolean {
|
|
87
105
|
return metadata?.labels[DEFAULT_INSTANCE_LABEL] === RESERVED_LABEL_TRUE;
|
|
88
106
|
}
|
|
107
|
+
|
|
108
|
+
/** Whether the metadata carries the SYSTEM_LABEL marker (undefined-safe). */
|
|
109
|
+
export function isSystemContent(
|
|
110
|
+
metadata: ApiResourceMetadata | undefined,
|
|
111
|
+
): boolean {
|
|
112
|
+
return metadata?.labels[SYSTEM_LABEL] === RESERVED_LABEL_TRUE;
|
|
113
|
+
}
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* can read it, so no real runner install is needed.
|
|
7
7
|
*
|
|
8
8
|
* Unix-only like the runner itself; deterministic (poll with timeout,
|
|
9
|
-
* never sleep).
|
|
9
|
+
* never sleep). Every poll gets an explicit budget: vitest's default
|
|
10
|
+
* second is enough on an idle laptop and not under the full suite's
|
|
11
|
+
* load, where a /bin/sh child can take longer than that to start and
|
|
12
|
+
* write its first line. Polling returns the moment the condition holds,
|
|
13
|
+
* so the larger budget costs nothing on a quiet host.
|
|
10
14
|
*/
|
|
11
15
|
import {
|
|
12
16
|
chmodSync,
|
|
@@ -25,6 +29,9 @@ import { createLogger } from "../../boot/logger.js";
|
|
|
25
29
|
import { newLocalProcessSandboxProvisioner } from "../local-process.js";
|
|
26
30
|
import type { SandboxDriverConfig } from "../provisioner.js";
|
|
27
31
|
|
|
32
|
+
/** How long a spawned child is given to start, write, or die under load. */
|
|
33
|
+
const CHILD_SETTLE_TIMEOUT_MS = 10_000;
|
|
34
|
+
|
|
28
35
|
const silentLogger = createLogger({
|
|
29
36
|
level: "error",
|
|
30
37
|
pretty: false,
|
|
@@ -75,7 +82,9 @@ describe.skipIf(process.platform === "win32")(
|
|
|
75
82
|
taskQueue: "session:ses_smoke",
|
|
76
83
|
stigmerToken: "tok-smoke",
|
|
77
84
|
});
|
|
78
|
-
await vi.waitFor(() => expect(spawnCount()).toBe(1)
|
|
85
|
+
await vi.waitFor(() => expect(spawnCount()).toBe(1), {
|
|
86
|
+
timeout: CHILD_SETTLE_TIMEOUT_MS,
|
|
87
|
+
});
|
|
79
88
|
expect(await driver.probe("session", "ses_smoke")).toBe("running");
|
|
80
89
|
|
|
81
90
|
// Fast path: a second ensure must not spawn a second process.
|
|
@@ -104,16 +113,21 @@ describe.skipIf(process.platform === "win32")(
|
|
|
104
113
|
|
|
105
114
|
it("deprovision kills the child; probe reports absent; re-ensure respawns", async () => {
|
|
106
115
|
await driver.deprovisionSessionSandbox("ses_smoke");
|
|
107
|
-
await vi.waitFor(
|
|
108
|
-
|
|
109
|
-
|
|
116
|
+
await vi.waitFor(
|
|
117
|
+
async () => {
|
|
118
|
+
expect(await driver.probe("session", "ses_smoke")).toBe("absent");
|
|
119
|
+
},
|
|
120
|
+
{ timeout: CHILD_SETTLE_TIMEOUT_MS },
|
|
121
|
+
);
|
|
110
122
|
|
|
111
123
|
// The repair arm without stored state: a fresh ensure respawns.
|
|
112
124
|
await driver.ensureSessionSandbox("ses_smoke", {
|
|
113
125
|
taskQueue: "session:ses_smoke",
|
|
114
126
|
stigmerToken: "",
|
|
115
127
|
});
|
|
116
|
-
await vi.waitFor(() => expect(spawnCount()).toBe(2)
|
|
128
|
+
await vi.waitFor(() => expect(spawnCount()).toBe(2), {
|
|
129
|
+
timeout: CHILD_SETTLE_TIMEOUT_MS,
|
|
130
|
+
});
|
|
117
131
|
expect(await driver.probe("session", "ses_smoke")).toBe("running");
|
|
118
132
|
});
|
|
119
133
|
|
package/src/store/interface.ts
CHANGED
|
@@ -217,8 +217,12 @@ export interface SearchIndexQueryResult {
|
|
|
217
217
|
// =============================================================================
|
|
218
218
|
|
|
219
219
|
/**
|
|
220
|
-
* Key-value state for
|
|
221
|
-
*
|
|
220
|
+
* Key-value state for one-shot boot work that must run once per database.
|
|
221
|
+
* The one writer today is the membership rules' reconciliation
|
|
222
|
+
* (`iampolicy/constants.ts` ROLES_RECONCILED_KEY). A database migrated
|
|
223
|
+
* from the Go server carries that server's bootstrap keys too; the
|
|
224
|
+
* migration preserves them (see sqlite/__tests__/migrations.test.ts) and
|
|
225
|
+
* nothing reads them.
|
|
222
226
|
*/
|
|
223
227
|
export interface BootstrapStateStore {
|
|
224
228
|
/** Returns "" (not an error) when the key does not exist — Go's contract. */
|