@stigmer/server 3.22.1 → 3.23.1-dev.20260923075205
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/artifactstorage/artifact-storage.d.ts +29 -31
- package/dist/artifactstorage/artifact-storage.d.ts.map +1 -1
- package/dist/artifactstorage/artifact-storage.js +5 -7
- package/dist/artifactstorage/artifact-storage.js.map +1 -1
- package/dist/artifactstorage/r2-storage.d.ts +12 -7
- package/dist/artifactstorage/r2-storage.d.ts.map +1 -1
- package/dist/artifactstorage/r2-storage.js +6 -14
- package/dist/artifactstorage/r2-storage.js.map +1 -1
- package/dist/authorization/authorizer.d.ts +4 -8
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +5 -9
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/derived-tuples.d.ts.map +1 -1
- package/dist/authorization/derived-tuples.js +10 -25
- package/dist/authorization/derived-tuples.js.map +1 -1
- package/dist/authorization/evaluator.d.ts +7 -8
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js +4 -20
- package/dist/authorization/evaluator.js.map +1 -1
- package/dist/authorization/list-read-scope.d.ts.map +1 -1
- package/dist/authorization/list-read-scope.js +5 -9
- package/dist/authorization/list-read-scope.js.map +1 -1
- package/dist/authorization/model/agent.d.ts.map +1 -1
- package/dist/authorization/model/agent.js +4 -5
- package/dist/authorization/model/agent.js.map +1 -1
- package/dist/authorization/model/agent_instance.d.ts.map +1 -1
- package/dist/authorization/model/agent_instance.js +2 -2
- package/dist/authorization/model/agent_instance.js.map +1 -1
- package/dist/authorization/model/mcp_server.d.ts.map +1 -1
- package/dist/authorization/model/mcp_server.js +2 -2
- package/dist/authorization/model/mcp_server.js.map +1 -1
- package/dist/authorization/model/plugin.d.ts.map +1 -1
- package/dist/authorization/model/plugin.js +3 -4
- package/dist/authorization/model/plugin.js.map +1 -1
- package/dist/authorization/model/rewrite.d.ts +8 -10
- package/dist/authorization/model/rewrite.d.ts.map +1 -1
- package/dist/authorization/model/rewrite.js +0 -3
- package/dist/authorization/model/rewrite.js.map +1 -1
- package/dist/authorization/model/skill.d.ts.map +1 -1
- package/dist/authorization/model/skill.js +2 -2
- package/dist/authorization/model/skill.js.map +1 -1
- package/dist/authorization/model/workflow.d.ts.map +1 -1
- package/dist/authorization/model/workflow.js +2 -2
- package/dist/authorization/model/workflow.js.map +1 -1
- package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
- package/dist/authorization/model/workflow_instance.js +2 -2
- package/dist/authorization/model/workflow_instance.js.map +1 -1
- package/dist/authorization/organization-directory.d.ts.map +1 -1
- package/dist/authorization/organization-directory.js +2 -3
- package/dist/authorization/organization-directory.js.map +1 -1
- package/dist/authorization/store-test-kit.d.ts +0 -6
- package/dist/authorization/store-test-kit.d.ts.map +1 -1
- package/dist/authorization/store-test-kit.js +16 -62
- package/dist/authorization/store-test-kit.js.map +1 -1
- package/dist/authorization/tuples.d.ts +13 -32
- package/dist/authorization/tuples.d.ts.map +1 -1
- package/dist/authorization/tuples.js +3 -11
- package/dist/authorization/tuples.js.map +1 -1
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +49 -24
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/config.d.ts +4 -3
- package/dist/boot/config.d.ts.map +1 -1
- package/dist/boot/config.js.map +1 -1
- package/dist/boot/skill-transfer-origin.d.ts +52 -0
- package/dist/boot/skill-transfer-origin.d.ts.map +1 -0
- package/dist/boot/skill-transfer-origin.js +54 -0
- package/dist/boot/skill-transfer-origin.js.map +1 -0
- package/dist/domain/agent/controller.d.ts.map +1 -1
- package/dist/domain/agent/controller.js +4 -4
- package/dist/domain/agent/controller.js.map +1 -1
- package/dist/domain/agentchannel/controller.d.ts.map +1 -1
- package/dist/domain/agentchannel/controller.js +3 -1
- package/dist/domain/agentchannel/controller.js.map +1 -1
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +3 -1
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentinstance/controller.d.ts.map +1 -1
- package/dist/domain/agentinstance/controller.js +3 -4
- package/dist/domain/agentinstance/controller.js.map +1 -1
- package/dist/domain/agentshare/constants.d.ts +6 -11
- package/dist/domain/agentshare/constants.d.ts.map +1 -1
- package/dist/domain/agentshare/constants.js +8 -16
- package/dist/domain/agentshare/constants.js.map +1 -1
- package/dist/domain/agentshare/controller.d.ts.map +1 -1
- package/dist/domain/agentshare/controller.js +3 -1
- package/dist/domain/agentshare/controller.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +18 -25
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +41 -142
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/environment/controller.d.ts.map +1 -1
- package/dist/domain/environment/controller.js +2 -3
- package/dist/domain/environment/controller.js.map +1 -1
- package/dist/domain/executioncontext/controller.d.ts.map +1 -1
- package/dist/domain/executioncontext/controller.js +2 -1
- package/dist/domain/executioncontext/controller.js.map +1 -1
- package/dist/domain/mcpserver/controller.d.ts.map +1 -1
- package/dist/domain/mcpserver/controller.js +3 -4
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/plugin/controller.d.ts +3 -7
- package/dist/domain/plugin/controller.d.ts.map +1 -1
- package/dist/domain/plugin/controller.js +9 -11
- package/dist/domain/plugin/controller.js.map +1 -1
- package/dist/domain/plugin/push.d.ts +7 -5
- package/dist/domain/plugin/push.d.ts.map +1 -1
- package/dist/domain/plugin/push.js +8 -14
- package/dist/domain/plugin/push.js.map +1 -1
- package/dist/domain/schedule/controller.d.ts.map +1 -1
- package/dist/domain/schedule/controller.js +3 -1
- package/dist/domain/schedule/controller.js.map +1 -1
- package/dist/domain/session/controller.d.ts.map +1 -1
- package/dist/domain/session/controller.js +3 -2
- package/dist/domain/session/controller.js.map +1 -1
- package/dist/domain/skill/constants.d.ts +26 -3
- package/dist/domain/skill/constants.d.ts.map +1 -1
- package/dist/domain/skill/constants.js +26 -3
- package/dist/domain/skill/constants.js.map +1 -1
- package/dist/domain/skill/controller.d.ts +6 -11
- package/dist/domain/skill/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +33 -24
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/skill/push.d.ts +2 -2
- package/dist/domain/skill/push.d.ts.map +1 -1
- package/dist/domain/skill/push.js +2 -2
- package/dist/domain/skill/push.js.map +1 -1
- package/dist/domain/skill/transfer/handler.d.ts +17 -9
- package/dist/domain/skill/transfer/handler.d.ts.map +1 -1
- package/dist/domain/skill/transfer/handler.js +19 -8
- package/dist/domain/skill/transfer/handler.js.map +1 -1
- package/dist/domain/skill/transfer/slots.d.ts +26 -41
- package/dist/domain/skill/transfer/slots.d.ts.map +1 -1
- package/dist/domain/skill/transfer/slots.js +80 -87
- package/dist/domain/skill/transfer/slots.js.map +1 -1
- package/dist/domain/skill/transfer/staging.d.ts +48 -0
- package/dist/domain/skill/transfer/staging.d.ts.map +1 -0
- package/dist/domain/skill/transfer/staging.js +127 -0
- package/dist/domain/skill/transfer/staging.js.map +1 -0
- package/dist/domain/workflow/agent-call-references.d.ts +54 -0
- package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
- package/dist/domain/workflow/agent-call-references.js +97 -0
- package/dist/domain/workflow/agent-call-references.js.map +1 -0
- package/dist/domain/workflow/controller.d.ts.map +1 -1
- package/dist/domain/workflow/controller.js +14 -6
- package/dist/domain/workflow/controller.js.map +1 -1
- package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.d.ts +10 -1
- package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
- package/dist/domain/workflow/validation/task-config-constraints.js +3 -2
- package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
- package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
- package/dist/domain/workflowexecution/controller.js +4 -2
- package/dist/domain/workflowexecution/controller.js.map +1 -1
- package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
- package/dist/domain/workflowinstance/controller.js +3 -4
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/extensions/authorization-queries.d.ts +6 -5
- package/dist/extensions/authorization-queries.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +1 -1
- package/dist/extensions/resource-authorization.d.ts +3 -2
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/pipeline/apiresource-meta.d.ts +12 -3
- package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
- package/dist/pipeline/apiresource-meta.js +21 -10
- package/dist/pipeline/apiresource-meta.js.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.d.ts +9 -3
- package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.js +9 -11
- package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
- package/dist/pipeline/steps/references.d.ts +178 -20
- package/dist/pipeline/steps/references.d.ts.map +1 -1
- package/dist/pipeline/steps/references.js +344 -43
- package/dist/pipeline/steps/references.js.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.d.ts +11 -8
- package/dist/pipeline/steps/resolve-artifact-source.d.ts.map +1 -1
- package/dist/pipeline/steps/resolve-artifact-source.js +8 -4
- package/dist/pipeline/steps/resolve-artifact-source.js.map +1 -1
- package/dist/query/search/controller.js +0 -1
- package/dist/query/search/controller.js.map +1 -1
- package/dist/query/search/criteria.d.ts +1 -5
- package/dist/query/search/criteria.d.ts.map +1 -1
- package/dist/query/search/criteria.js +3 -13
- package/dist/query/search/criteria.js.map +1 -1
- package/dist/query/search/handler.d.ts +5 -4
- package/dist/query/search/handler.d.ts.map +1 -1
- package/dist/query/search/handler.js +7 -6
- package/dist/query/search/handler.js.map +1 -1
- package/dist/query/search/query-store.d.ts.map +1 -1
- package/dist/query/search/query-store.js +0 -2
- package/dist/query/search/query-store.js.map +1 -1
- package/dist/store/interface.d.ts +3 -6
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/dist/store/postgres/migrations.d.ts +3 -1
- package/dist/store/postgres/migrations.d.ts.map +1 -1
- package/dist/store/postgres/migrations.js +35 -1
- package/dist/store/postgres/migrations.js.map +1 -1
- package/dist/store/postgres/store.d.ts.map +1 -1
- package/dist/store/postgres/store.js +4 -9
- package/dist/store/postgres/store.js.map +1 -1
- package/dist/store/public-visibility-retired.d.ts +67 -0
- package/dist/store/public-visibility-retired.d.ts.map +1 -0
- package/dist/store/public-visibility-retired.js +55 -0
- package/dist/store/public-visibility-retired.js.map +1 -0
- package/dist/store/sqlite/migrations.d.ts +3 -1
- package/dist/store/sqlite/migrations.d.ts.map +1 -1
- package/dist/store/sqlite/migrations.js +36 -1
- package/dist/store/sqlite/migrations.js.map +1 -1
- package/dist/store/sqlite/store.d.ts.map +1 -1
- package/dist/store/sqlite/store.js +4 -8
- package/dist/store/sqlite/store.js.map +1 -1
- package/package.json +6 -6
- package/src/artifactstorage/__tests__/artifact-storage.test.ts +36 -33
- package/src/artifactstorage/__tests__/r2-storage.test.ts +11 -13
- package/src/artifactstorage/artifact-storage.ts +37 -33
- package/src/artifactstorage/r2-storage.ts +6 -15
- package/src/authorization/README.md +24 -26
- package/src/authorization/__tests__/authorizer.test.ts +10 -9
- package/src/authorization/__tests__/derived-tuples.test.ts +4 -11
- package/src/authorization/__tests__/evaluator.test.ts +14 -73
- package/src/authorization/__tests__/facts.test.ts +2 -2
- package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +19 -27
- package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +6 -98
- package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +4 -61
- package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +1 -15
- package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +1 -21
- package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +1 -25
- package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +1 -3
- package/src/authorization/__tests__/list-read-scope.test.ts +18 -17
- package/src/authorization/__tests__/store-tests.test.ts +2 -6
- package/src/authorization/__tests__/tuples.test.ts +12 -11
- package/src/authorization/authorizer.ts +4 -9
- package/src/authorization/derived-tuples.ts +14 -31
- package/src/authorization/evaluator.ts +8 -44
- package/src/authorization/list-read-scope.ts +5 -11
- package/src/authorization/model/agent.ts +2 -5
- package/src/authorization/model/agent_instance.ts +0 -2
- package/src/authorization/model/mcp_server.ts +0 -2
- package/src/authorization/model/plugin.ts +1 -4
- package/src/authorization/model/rewrite.ts +8 -13
- package/src/authorization/model/skill.ts +0 -2
- package/src/authorization/model/workflow.ts +0 -2
- package/src/authorization/model/workflow_instance.ts +0 -2
- package/src/authorization/organization-directory.ts +1 -3
- package/src/authorization/store-test-kit.ts +16 -75
- package/src/authorization/tuples.ts +16 -39
- package/src/boot/__tests__/skill-transfer-origin.test.ts +72 -0
- package/src/boot/compose.ts +62 -25
- package/src/boot/config.ts +4 -3
- package/src/boot/skill-transfer-origin.ts +76 -0
- package/src/domain/agent/__tests__/agent.test.ts +11 -4
- package/src/domain/agent/controller.ts +7 -7
- package/src/domain/agentchannel/__tests__/agentchannel.test.ts +223 -48
- package/src/domain/agentchannel/controller.ts +6 -1
- package/src/domain/agentexecution/controller.ts +6 -1
- package/src/domain/agentinstance/controller.ts +6 -12
- package/src/domain/agentshare/__tests__/agentshare.test.ts +196 -172
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +16 -31
- package/src/domain/agentshare/constants.ts +14 -26
- package/src/domain/agentshare/controller.ts +6 -1
- package/src/domain/agentshare/steps.ts +41 -194
- package/src/domain/environment/controller.ts +5 -8
- package/src/domain/executioncontext/controller.ts +5 -1
- package/src/domain/mcpserver/__tests__/mcpserver.test.ts +115 -28
- package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +53 -18
- package/src/domain/mcpserver/controller.ts +6 -12
- package/src/domain/plugin/controller.ts +16 -25
- package/src/domain/plugin/push.ts +8 -16
- package/src/domain/schedule/controller.ts +6 -1
- package/src/domain/session/controller.ts +12 -4
- package/src/domain/skill/__tests__/skill.test.ts +5 -3
- package/src/domain/skill/__tests__/slots.test.ts +113 -60
- package/src/domain/skill/__tests__/staging.test.ts +304 -0
- package/src/domain/skill/constants.ts +28 -3
- package/src/domain/skill/controller.ts +44 -42
- package/src/domain/skill/push.ts +3 -3
- package/src/domain/skill/transfer/handler.ts +33 -15
- package/src/domain/skill/transfer/slots.ts +89 -100
- package/src/domain/skill/transfer/staging.ts +191 -0
- package/src/domain/workflow/__tests__/agent-call-references.test.ts +222 -0
- package/src/domain/workflow/agent-call-references.ts +157 -0
- package/src/domain/workflow/controller.ts +28 -10
- package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
- package/src/domain/workflow/validation/task-config-constraints.ts +7 -3
- package/src/domain/workflowexecution/controller.ts +7 -2
- package/src/domain/workflowinstance/controller.ts +6 -12
- package/src/extensions/__tests__/built-in-authorization-composed.test.ts +32 -19
- package/src/extensions/__tests__/extension-composition.test.ts +4 -4
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +9 -6
- package/src/extensions/authorization-queries.ts +6 -5
- package/src/extensions/list-read-scope.ts +1 -1
- package/src/extensions/resource-authorization.ts +3 -5
- package/src/index.ts +0 -1
- package/src/pipeline/__tests__/supports-visibility.test.ts +112 -0
- package/src/pipeline/apiresource-meta.ts +21 -10
- package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +18 -31
- package/src/pipeline/steps/__tests__/references.test.ts +703 -0
- package/src/pipeline/steps/authorization-tuples.ts +9 -11
- package/src/pipeline/steps/references.ts +578 -70
- package/src/pipeline/steps/resolve-artifact-source.ts +20 -13
- package/src/query/search/__tests__/criteria.test.ts +0 -4
- package/src/query/search/__tests__/query-store.test.ts +11 -40
- package/src/query/search/controller.ts +0 -1
- package/src/query/search/criteria.ts +0 -14
- package/src/query/search/handler.ts +6 -7
- package/src/query/search/query-store.ts +0 -2
- package/src/store/__tests__/public-visibility-retired.test.ts +127 -0
- package/src/store/__tests__/store-contract.ts +6 -51
- package/src/store/interface.ts +3 -6
- package/src/store/postgres/__tests__/migrations.test.ts +187 -6
- package/src/store/postgres/__tests__/store-contract.test.ts +0 -2
- package/src/store/postgres/migrations.ts +48 -1
- package/src/store/postgres/store.ts +4 -11
- package/src/store/public-visibility-retired.ts +119 -0
- package/src/store/sqlite/__tests__/migrations.test.ts +191 -5
- package/src/store/sqlite/migrations.ts +45 -1
- package/src/store/sqlite/store.ts +4 -10
- package/src/transport/registry/__tests__/lanes.test.ts +1 -1
- package/dist/pipeline/steps/visibility-gates.d.ts +0 -27
- package/dist/pipeline/steps/visibility-gates.d.ts.map +0 -1
- package/dist/pipeline/steps/visibility-gates.js +0 -139
- package/dist/pipeline/steps/visibility-gates.js.map +0 -1
- package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +0 -98
- package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +0 -52
- package/src/pipeline/steps/__tests__/visibility-gates.test.ts +0 -187
- package/src/pipeline/steps/visibility-gates.ts +0 -174
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
* predates Go's idempotent ALTERs gains its columns; a legacy pre-v2
|
|
7
7
|
* database gets its prefix-based audit rows migrated. Rollback safety
|
|
8
8
|
* (DD-006): a v7 database re-opened by Go-shaped version checks
|
|
9
|
-
* (< 6) runs nothing.
|
|
9
|
+
* (< 6) runs nothing. v10, the chain's first row-decoding step, moves
|
|
10
|
+
* every row of the seven kinds that held the retired public level to org
|
|
11
|
+
* and leaves every other row's bytes as they were; a row it cannot decode
|
|
12
|
+
* fails the step and leaves the database at v9.
|
|
10
13
|
*/
|
|
11
14
|
import { mkdtempSync, rmSync } from "node:fs";
|
|
12
15
|
import { tmpdir } from "node:os";
|
|
@@ -15,12 +18,20 @@ import { DatabaseSync } from "node:sqlite";
|
|
|
15
18
|
|
|
16
19
|
import { afterEach, describe, expect, it } from "vitest";
|
|
17
20
|
|
|
21
|
+
import { create, fromBinary, fromJson, toBinary } from "@bufbuild/protobuf";
|
|
22
|
+
import type { DescMessage } from "@bufbuild/protobuf";
|
|
23
|
+
|
|
24
|
+
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
25
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
26
|
+
|
|
18
27
|
import { SqliteStore } from "../store.js";
|
|
19
28
|
import {
|
|
20
29
|
CURRENT_SCHEMA_VERSION,
|
|
30
|
+
SCHEMA_VERSION_10,
|
|
21
31
|
getSchemaVersion,
|
|
22
32
|
runMigrations,
|
|
23
33
|
} from "../migrations.js";
|
|
34
|
+
import { PUBLIC_ROW_KINDS_AT_RETIREMENT } from "../../public-visibility-retired.js";
|
|
24
35
|
import { materializeGoFixture } from "./support.js";
|
|
25
36
|
|
|
26
37
|
const cleanups: Array<() => void | Promise<void>> = [];
|
|
@@ -81,7 +92,9 @@ describe("fresh database", () => {
|
|
|
81
92
|
const rows = db
|
|
82
93
|
.prepare(`SELECT version FROM schema_version ORDER BY version`)
|
|
83
94
|
.all() as Array<{ version: number }>;
|
|
84
|
-
expect(rows.map((row) => row.version)).toEqual([
|
|
95
|
+
expect(rows.map((row) => row.version)).toEqual([
|
|
96
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
|
97
|
+
]);
|
|
85
98
|
});
|
|
86
99
|
|
|
87
100
|
it("re-opening an already-migrated database is a no-op", async () => {
|
|
@@ -138,7 +151,9 @@ describe("Go-created v6 database adoption (DD-002 fixture)", () => {
|
|
|
138
151
|
expect(org.id).toBe("acme");
|
|
139
152
|
|
|
140
153
|
const audit = db
|
|
141
|
-
.prepare(
|
|
154
|
+
.prepare(
|
|
155
|
+
`SELECT version_hash, tag FROM resource_audit WHERE kind = 'organization'`,
|
|
156
|
+
)
|
|
142
157
|
.get() as { version_hash: string; tag: string };
|
|
143
158
|
expect(audit).toEqual({ version_hash: "hash-v1", tag: "stable" });
|
|
144
159
|
|
|
@@ -283,8 +298,10 @@ describe("legacy pre-v2 database", () => {
|
|
|
283
298
|
CREATE TABLE schema_version (version INTEGER PRIMARY KEY, applied_at TEXT NOT NULL DEFAULT (datetime('now')));
|
|
284
299
|
INSERT INTO schema_version (version) VALUES (1);
|
|
285
300
|
CREATE TABLE resources (kind TEXT NOT NULL, id TEXT NOT NULL, data BLOB NOT NULL, updated_at TEXT NOT NULL DEFAULT (datetime('now')), PRIMARY KEY (kind, id)) WITHOUT ROWID;
|
|
286
|
-
|
|
287
|
-
|
|
301
|
+
-- Field 1 (api_version) holding one ASCII byte: bytes v10 can decode
|
|
302
|
+
-- as a Skill, since it walks every live row of that kind.
|
|
303
|
+
INSERT INTO resources (kind, id, data) VALUES ('skill', 'skl_1', X'0a0176');
|
|
304
|
+
INSERT INTO resources (kind, id, data) VALUES ('skill', 'skill_audit/skl_1/1706123456789', X'0a0177');
|
|
288
305
|
`);
|
|
289
306
|
setup.close();
|
|
290
307
|
|
|
@@ -330,3 +347,172 @@ describe("rollback safety (DD-006)", () => {
|
|
|
330
347
|
expect(version.v).toBeGreaterThanOrEqual(6);
|
|
331
348
|
});
|
|
332
349
|
});
|
|
350
|
+
|
|
351
|
+
describe("v10: the retired public level leaves every row", () => {
|
|
352
|
+
/** A v9 database: the chain replayed, then v10's version row removed. */
|
|
353
|
+
function v9Database(): { dbPath: string; db: DatabaseSync } {
|
|
354
|
+
const dbPath = tempDbPath();
|
|
355
|
+
const setup = new DatabaseSync(dbPath);
|
|
356
|
+
runMigrations(setup);
|
|
357
|
+
setup
|
|
358
|
+
.prepare(`DELETE FROM schema_version WHERE version = ?`)
|
|
359
|
+
.run(SCHEMA_VERSION_10);
|
|
360
|
+
expect(getSchemaVersion(setup)).toBe(SCHEMA_VERSION_10 - 1);
|
|
361
|
+
return { dbPath, db: setup };
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function agentBytes(
|
|
365
|
+
id: string,
|
|
366
|
+
visibility: ApiResourceVisibility,
|
|
367
|
+
): Uint8Array {
|
|
368
|
+
return toBinary(
|
|
369
|
+
AgentSchema,
|
|
370
|
+
create(AgentSchema, {
|
|
371
|
+
apiVersion: "agentic.stigmer.ai/v1",
|
|
372
|
+
kind: "Agent",
|
|
373
|
+
metadata: { id, name: id, slug: id, org: "acme", visibility },
|
|
374
|
+
spec: { instructions: "a conformant instruction body" },
|
|
375
|
+
}),
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** A row of `schema` carrying only the envelope every kind shares, at `visibility`. */
|
|
380
|
+
function envelopeBytes(
|
|
381
|
+
schema: DescMessage,
|
|
382
|
+
id: string,
|
|
383
|
+
visibility: ApiResourceVisibility,
|
|
384
|
+
): Uint8Array {
|
|
385
|
+
return toBinary(
|
|
386
|
+
schema,
|
|
387
|
+
fromJson(schema, {
|
|
388
|
+
metadata: {
|
|
389
|
+
id,
|
|
390
|
+
name: id,
|
|
391
|
+
slug: id,
|
|
392
|
+
org: "acme",
|
|
393
|
+
visibility: ApiResourceVisibility[visibility],
|
|
394
|
+
},
|
|
395
|
+
}),
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function insert(
|
|
400
|
+
db: DatabaseSync,
|
|
401
|
+
kind: string,
|
|
402
|
+
id: string,
|
|
403
|
+
data: Uint8Array,
|
|
404
|
+
): void {
|
|
405
|
+
db.prepare(
|
|
406
|
+
`INSERT INTO resources (kind, id, data, updated_at) VALUES (?, ?, ?, '2026-09-01 00:00:00')`,
|
|
407
|
+
).run(kind, id, data);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function row(
|
|
411
|
+
db: DatabaseSync,
|
|
412
|
+
kind: string,
|
|
413
|
+
id: string,
|
|
414
|
+
): { data: Uint8Array; updated_at: string } {
|
|
415
|
+
return db
|
|
416
|
+
.prepare(
|
|
417
|
+
`SELECT data, updated_at FROM resources WHERE kind = ? AND id = ?`,
|
|
418
|
+
)
|
|
419
|
+
.get(kind, id) as { data: Uint8Array; updated_at: string };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
it("moves a public row of every kind in the frozen table to org, and leaves an org row and a private row byte-for-byte", () => {
|
|
423
|
+
const { dbPath, db: setup } = v9Database();
|
|
424
|
+
// One public row per kind the level could live under, each encoded
|
|
425
|
+
// through its own schema.
|
|
426
|
+
for (const entry of PUBLIC_ROW_KINDS_AT_RETIREMENT) {
|
|
427
|
+
insert(
|
|
428
|
+
setup,
|
|
429
|
+
entry.kind,
|
|
430
|
+
`${entry.kind}_public`,
|
|
431
|
+
envelopeBytes(
|
|
432
|
+
entry.schema,
|
|
433
|
+
`${entry.kind}_public`,
|
|
434
|
+
ApiResourceVisibility.visibility_public,
|
|
435
|
+
),
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
const orgBytes = agentBytes(
|
|
439
|
+
"agt_org",
|
|
440
|
+
ApiResourceVisibility.visibility_org,
|
|
441
|
+
);
|
|
442
|
+
const privateBytes = agentBytes(
|
|
443
|
+
"agt_private",
|
|
444
|
+
ApiResourceVisibility.visibility_private,
|
|
445
|
+
);
|
|
446
|
+
insert(setup, "agent", "agt_org", orgBytes);
|
|
447
|
+
insert(setup, "agent", "agt_private", privateBytes);
|
|
448
|
+
setup.close();
|
|
449
|
+
|
|
450
|
+
const store = SqliteStore.open(dbPath);
|
|
451
|
+
cleanups.push(() => store.close());
|
|
452
|
+
const db = new DatabaseSync(dbPath);
|
|
453
|
+
cleanups.push(() => db.close());
|
|
454
|
+
|
|
455
|
+
expect(getSchemaVersion(db)).toBe(CURRENT_SCHEMA_VERSION);
|
|
456
|
+
for (const entry of PUBLIC_ROW_KINDS_AT_RETIREMENT) {
|
|
457
|
+
const moved = row(db, entry.kind, `${entry.kind}_public`);
|
|
458
|
+
expect(moved.data, entry.kind).toEqual(
|
|
459
|
+
envelopeBytes(
|
|
460
|
+
entry.schema,
|
|
461
|
+
`${entry.kind}_public`,
|
|
462
|
+
ApiResourceVisibility.visibility_org,
|
|
463
|
+
),
|
|
464
|
+
);
|
|
465
|
+
expect(moved.updated_at, `${entry.kind} updated_at bumped`).not.toBe(
|
|
466
|
+
"2026-09-01 00:00:00",
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
expect(row(db, "agent", "agt_org")).toEqual({
|
|
470
|
+
data: orgBytes,
|
|
471
|
+
updated_at: "2026-09-01 00:00:00",
|
|
472
|
+
});
|
|
473
|
+
expect(row(db, "agent", "agt_private")).toEqual({
|
|
474
|
+
data: privateBytes,
|
|
475
|
+
updated_at: "2026-09-01 00:00:00",
|
|
476
|
+
});
|
|
477
|
+
const publicLeft = db
|
|
478
|
+
.prepare(`SELECT count(*) AS n FROM resources WHERE kind = 'agent'`)
|
|
479
|
+
.get() as { n: number };
|
|
480
|
+
expect(publicLeft.n).toBe(3);
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
it("a row of a kind outside the frozen table is never decoded", () => {
|
|
484
|
+
const { dbPath, db: setup } = v9Database();
|
|
485
|
+
// Bytes no schema decodes, under a kind the level never applied to.
|
|
486
|
+
insert(setup, "session", "ses_opaque", new Uint8Array([0xff, 0xff]));
|
|
487
|
+
setup.close();
|
|
488
|
+
|
|
489
|
+
const store = SqliteStore.open(dbPath);
|
|
490
|
+
cleanups.push(() => store.close());
|
|
491
|
+
const db = new DatabaseSync(dbPath);
|
|
492
|
+
cleanups.push(() => db.close());
|
|
493
|
+
expect(getSchemaVersion(db)).toBe(CURRENT_SCHEMA_VERSION);
|
|
494
|
+
expect(row(db, "session", "ses_opaque").data).toEqual(
|
|
495
|
+
new Uint8Array([0xff, 0xff]),
|
|
496
|
+
);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
it("a row of a table kind that does not decode fails the step, names the row, and leaves the database at v9 with every row untouched", () => {
|
|
500
|
+
const { dbPath, db: setup } = v9Database();
|
|
501
|
+
const publicBytes = agentBytes(
|
|
502
|
+
"agt_public",
|
|
503
|
+
ApiResourceVisibility.visibility_public,
|
|
504
|
+
);
|
|
505
|
+
insert(setup, "agent", "agt_public", publicBytes);
|
|
506
|
+
insert(setup, "agent", "agt_broken", new Uint8Array([0xff, 0xff, 0xff]));
|
|
507
|
+
setup.close();
|
|
508
|
+
|
|
509
|
+
expect(() => SqliteStore.open(dbPath)).toThrow(
|
|
510
|
+
/migrate to v10: .*agent 'agt_broken' cannot be moved off the retired public level/,
|
|
511
|
+
);
|
|
512
|
+
|
|
513
|
+
const db = new DatabaseSync(dbPath);
|
|
514
|
+
cleanups.push(() => db.close());
|
|
515
|
+
expect(getSchemaVersion(db)).toBe(SCHEMA_VERSION_10 - 1);
|
|
516
|
+
expect(row(db, "agent", "agt_public").data).toEqual(publicBytes);
|
|
517
|
+
});
|
|
518
|
+
});
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
*/
|
|
33
33
|
import type { DatabaseSync } from "node:sqlite";
|
|
34
34
|
|
|
35
|
+
import {
|
|
36
|
+
PUBLIC_ROW_KINDS_AT_RETIREMENT,
|
|
37
|
+
movePublicRowToOrg,
|
|
38
|
+
} from "../public-visibility-retired.js";
|
|
39
|
+
|
|
35
40
|
export const SCHEMA_VERSION_1 = 1;
|
|
36
41
|
export const SCHEMA_VERSION_2 = 2;
|
|
37
42
|
export const SCHEMA_VERSION_3 = 3;
|
|
@@ -44,9 +49,11 @@ export const SCHEMA_VERSION_7 = 7;
|
|
|
44
49
|
export const SCHEMA_VERSION_8 = 8;
|
|
45
50
|
/** v9: the rows of the removed Project kind deleted. */
|
|
46
51
|
export const SCHEMA_VERSION_9 = 9;
|
|
52
|
+
/** v10: every row holding the retired public visibility level moved to org. */
|
|
53
|
+
export const SCHEMA_VERSION_10 = 10;
|
|
47
54
|
|
|
48
55
|
/** Target version for new databases. */
|
|
49
|
-
export const CURRENT_SCHEMA_VERSION =
|
|
56
|
+
export const CURRENT_SCHEMA_VERSION = SCHEMA_VERSION_10;
|
|
50
57
|
|
|
51
58
|
/** Applies all pending migrations in order. */
|
|
52
59
|
export function runMigrations(db: DatabaseSync): void {
|
|
@@ -69,6 +76,7 @@ export function runMigrations(db: DatabaseSync): void {
|
|
|
69
76
|
[SCHEMA_VERSION_7, migrateToV7],
|
|
70
77
|
[SCHEMA_VERSION_8, migrateToV8],
|
|
71
78
|
[SCHEMA_VERSION_9, migrateToV9],
|
|
79
|
+
[SCHEMA_VERSION_10, migrateToV10],
|
|
72
80
|
];
|
|
73
81
|
|
|
74
82
|
for (const [version, migrate] of chain) {
|
|
@@ -379,3 +387,39 @@ function migrateToV9(db: DatabaseSync): void {
|
|
|
379
387
|
DELETE FROM resource_audit WHERE kind = 'project';
|
|
380
388
|
`);
|
|
381
389
|
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* v10: the public visibility level is retired, so every row that still
|
|
393
|
+
* holds it is moved to org visibility — the chain's first migration that
|
|
394
|
+
* decodes a row (public-visibility-retired.ts says why a migration, why
|
|
395
|
+
* the kind table is frozen there, and why an undecodable row fails the
|
|
396
|
+
* step). This step owns the SQL: one read per kind in the frozen table,
|
|
397
|
+
* one UPDATE per moved row with `updated_at` bumped the way saveResource
|
|
398
|
+
* bumps it, rows that hold any other level left byte-for-byte as they
|
|
399
|
+
* are. Runs inside applyInTransaction's BEGIN, so a throw from the mover
|
|
400
|
+
* rolls the whole step back and the boot stops on the row it names.
|
|
401
|
+
*/
|
|
402
|
+
function migrateToV10(db: DatabaseSync): void {
|
|
403
|
+
const update = db.prepare(
|
|
404
|
+
`UPDATE resources SET data = ?, updated_at = datetime('now') WHERE kind = ? AND id = ?`,
|
|
405
|
+
);
|
|
406
|
+
for (const entry of PUBLIC_ROW_KINDS_AT_RETIREMENT) {
|
|
407
|
+
const rows = db
|
|
408
|
+
.prepare(`SELECT id, data FROM resources WHERE kind = ?`)
|
|
409
|
+
.all(entry.kind) as Array<{ id: string; data: Uint8Array }>;
|
|
410
|
+
for (const row of rows) {
|
|
411
|
+
let moved: Uint8Array | undefined;
|
|
412
|
+
try {
|
|
413
|
+
moved = movePublicRowToOrg(entry, row.data);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
throw new Error(
|
|
416
|
+
`${entry.kind} '${row.id}' cannot be moved off the retired public level: ${String(error)}`,
|
|
417
|
+
{ cause: error },
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
if (moved !== undefined) {
|
|
421
|
+
update.run(moved, entry.kind, row.id);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
@@ -820,21 +820,15 @@ export class SqliteStore implements Store {
|
|
|
820
820
|
const kindPlaceholders = query.kinds.map(() => "?").join(",");
|
|
821
821
|
const kindArgs = [...query.kinds];
|
|
822
822
|
|
|
823
|
-
// The scope-filter fragments,
|
|
824
|
-
// org
|
|
823
|
+
// The scope-filter fragments: the org filter, strict (a row is in the
|
|
824
|
+
// requested org or it is not; visibility never widens or narrows the
|
|
825
|
+
// scope), then the authorized-id allowlist.
|
|
825
826
|
const scopeClauses: string[] = [];
|
|
826
827
|
const scopeArgs: string[] = [];
|
|
827
828
|
if (query.orgFilter !== "") {
|
|
828
|
-
scopeClauses.push(
|
|
829
|
-
query.crossOrgPublic
|
|
830
|
-
? `AND (org = ? OR visibility = 'visibility_public')`
|
|
831
|
-
: `AND org = ?`,
|
|
832
|
-
);
|
|
829
|
+
scopeClauses.push(`AND org = ?`);
|
|
833
830
|
scopeArgs.push(query.orgFilter);
|
|
834
831
|
}
|
|
835
|
-
if (query.excludePublic) {
|
|
836
|
-
scopeClauses.push(`AND visibility != 'visibility_public'`);
|
|
837
|
-
}
|
|
838
832
|
if (query.authorizedIdsByKind !== undefined) {
|
|
839
833
|
// The 20260830.01 scoping arm: per-kind resource_id allowlists.
|
|
840
834
|
// An empty set contributes NO clause — that kind matches nothing —
|
|
@@ -38,7 +38,7 @@ beforeAll(async () => {
|
|
|
38
38
|
// test previously composed against the DEFAULT paths, which meant
|
|
39
39
|
// opening the developer's real ~/.stigmer/stigmer.db — and with the
|
|
40
40
|
// skill domain's boot-time staging wipe (#8) it would now also clear
|
|
41
|
-
// ~/.stigmer/storage/skills
|
|
41
|
+
// ~/.stigmer/storage/skills/staging. Tests never touch the home dir.
|
|
42
42
|
testDir = mkdtempSync(path.join(tmpdir(), "registry-lanes-test-"));
|
|
43
43
|
const config = loadConfig({
|
|
44
44
|
STIGMER_MODEL_REGISTRY_REFRESH: "off",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { DescMessage } from "@bufbuild/protobuf";
|
|
2
|
-
import type { Authorizer } from "../../extensions/authorizer.js";
|
|
3
|
-
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
4
|
-
import type { PipelineStep } from "../pipeline.js";
|
|
5
|
-
/**
|
|
6
|
-
* The denial callers see at both doors (the Java policy copy verbatim).
|
|
7
|
-
* Deliberately not byte-pinned by the OSS conformance suite; the cloud
|
|
8
|
-
* gate itself is recorded via the clientPublicVisibilityWrites flag.
|
|
9
|
-
*/
|
|
10
|
-
export declare const PUBLIC_VISIBILITY_DENY_MESSAGE: string;
|
|
11
|
-
/** The CREATE door: a new state declaring PUBLIC needs the operator grant. */
|
|
12
|
-
export declare function newGuardPublicVisibilityStep<Desc extends DescMessage>(authorizer: Authorizer): PipelineStep<Desc>;
|
|
13
|
-
/**
|
|
14
|
-
* The UPDATE door: escalation to PUBLIC (the stored level is anything
|
|
15
|
-
* else) needs the operator grant. Reads the loaded target from the
|
|
16
|
-
* chain's own context key (every updateVisibility chain stores it —
|
|
17
|
-
* the RecordVisibilityBeforeUpdate pattern).
|
|
18
|
-
*/
|
|
19
|
-
export declare function newAuthorizeVisibilityTransitionStep<Desc extends DescMessage>(targetKey: string, authorizer: Authorizer): PipelineStep<Desc>;
|
|
20
|
-
/**
|
|
21
|
-
* The single owner of "may this caller set public?" — both doors call it,
|
|
22
|
-
* and so does the plugin push chain, whose requested level rides the
|
|
23
|
-
* request (the level then flows to every member through the members' own
|
|
24
|
-
* create and updateVisibility doors, which run this check again).
|
|
25
|
-
*/
|
|
26
|
-
export declare function requireOperatorMaySetPublic(authorizer: Authorizer, caller: CallerIdentity): Promise<void>;
|
|
27
|
-
//# sourceMappingURL=visibility-gates.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visibility-gates.d.ts","sourceRoot":"","sources":["../../../src/pipeline/steps/visibility-gates.ts"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAOtD,OAAO,KAAK,EAAE,UAAU,EAAiB,MAAM,gCAAgC,CAAC;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAInD;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,QAEU,CAAC;AAEtD,8EAA8E;AAC9E,wBAAgB,4BAA4B,CAAC,IAAI,SAAS,WAAW,EACnE,UAAU,EAAE,UAAU,GACrB,YAAY,CAAC,IAAI,CAAC,CAgBpB;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAAC,IAAI,SAAS,WAAW,EAC3E,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,UAAU,GACrB,YAAY,CAAC,IAAI,CAAC,CA+BpB;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The PUBLIC-visibility operator gates — the two write doors a resource
|
|
3
|
-
* can become public through, both consulting the ONE composed Authorizer
|
|
4
|
-
* with the same platform-scoped check (the Java
|
|
5
|
-
* PublicVisibilityEscalationPolicy port; C2 Stage 3, 20260827.10).
|
|
6
|
-
*
|
|
7
|
-
* PUBLIC is the only level that crosses every org boundary (one flip
|
|
8
|
-
* lists a resource in every tenant's cross-org catalog), so entering it
|
|
9
|
-
* is a curation decision: the owner requests, the platform team grants.
|
|
10
|
-
* The answer is `can_set_public_visibility` on `platform:stigmer` — a
|
|
11
|
-
* named operator capability, never a bare operator lookup.
|
|
12
|
-
*
|
|
13
|
-
* - GuardPublicVisibility: the CREATE door, in the create chains of
|
|
14
|
-
* the kinds whose VisibilityConfig supports PUBLIC (agent, workflow,
|
|
15
|
-
* mcp_server, agent_instance, workflow_instance). After
|
|
16
|
-
* BuildNewState — it inspects the state that will persist — which
|
|
17
|
-
* keeps the pinned INVALID_ARGUMENT level-support rejections (the
|
|
18
|
-
* earlier ValidateVisibility) their precedence over this
|
|
19
|
-
* PERMISSION_DENIED.
|
|
20
|
-
* - AuthorizeVisibilityTransition: the UPDATE door, in every
|
|
21
|
-
* updateVisibility chain after ValidateVisibilityUpdate (the pinned
|
|
22
|
-
* FAILED_PRECONDITION default-instance rejection keeps precedence,
|
|
23
|
-
* the Java ordering the conformance suite depends on). Gates only
|
|
24
|
-
* the ESCALATION to public (stored level is anything else).
|
|
25
|
-
*
|
|
26
|
-
* Both run LAZILY — only requests that actually involve the PUBLIC level
|
|
27
|
-
* reach the Authorizer — and both pass for internal callers (server-side
|
|
28
|
-
* flows publish platform resources by design). The OSS permissive
|
|
29
|
-
* default allows, so the local posture keeps today's behavior
|
|
30
|
-
* byte-identically; the cloud's FGA Authorizer supplies the gate.
|
|
31
|
-
*
|
|
32
|
-
* DELIBERATE partial port, recorded owner-visibly (Stage-3 execution
|
|
33
|
-
* record): Java's transition step additionally lets operators WITHOUT
|
|
34
|
-
* resource can_edit publish and take down (its updateVisibility chains
|
|
35
|
-
* authorize post-load, transition-aware); this edition's position-1
|
|
36
|
-
* Authorize enforces can_edit on updateVisibility before any step here
|
|
37
|
-
* runs, so those operator-without-edit lanes require can_edit until the
|
|
38
|
-
* Stage-4 chain disposition addresses them. No conformance lane pins
|
|
39
|
-
* them.
|
|
40
|
-
*/
|
|
41
|
-
import { Code, ConnectError } from "@connectrpc/connect";
|
|
42
|
-
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
43
|
-
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
44
|
-
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
45
|
-
import { internalError } from "../errors.js";
|
|
46
|
-
import { metadataOf } from "./shapes.js";
|
|
47
|
-
/**
|
|
48
|
-
* The denial callers see at both doors (the Java policy copy verbatim).
|
|
49
|
-
* Deliberately not byte-pinned by the OSS conformance suite; the cloud
|
|
50
|
-
* gate itself is recorded via the clientPublicVisibilityWrites flag.
|
|
51
|
-
*/
|
|
52
|
-
export const PUBLIC_VISIBILITY_DENY_MESSAGE = "Public visibility is granted by the platform team. " +
|
|
53
|
-
"Ask a platform operator to publish this resource.";
|
|
54
|
-
/** The CREATE door: a new state declaring PUBLIC needs the operator grant. */
|
|
55
|
-
export function newGuardPublicVisibilityStep(authorizer) {
|
|
56
|
-
return {
|
|
57
|
-
name: "GuardPublicVisibility",
|
|
58
|
-
async execute(ctx) {
|
|
59
|
-
if (ctx.callerIdentity.callerClass === "internal") {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (metadataOf(ctx.newState)?.visibility !==
|
|
63
|
-
ApiResourceVisibility.visibility_public) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* The UPDATE door: escalation to PUBLIC (the stored level is anything
|
|
72
|
-
* else) needs the operator grant. Reads the loaded target from the
|
|
73
|
-
* chain's own context key (every updateVisibility chain stores it —
|
|
74
|
-
* the RecordVisibilityBeforeUpdate pattern).
|
|
75
|
-
*/
|
|
76
|
-
export function newAuthorizeVisibilityTransitionStep(targetKey, authorizer) {
|
|
77
|
-
return {
|
|
78
|
-
name: "AuthorizeVisibilityTransition",
|
|
79
|
-
async execute(ctx) {
|
|
80
|
-
if (ctx.callerIdentity.callerClass === "internal") {
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const requested = ctx.input
|
|
84
|
-
.visibility;
|
|
85
|
-
if (requested !== ApiResourceVisibility.visibility_public) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const target = ctx.get(targetKey);
|
|
89
|
-
if (target === undefined) {
|
|
90
|
-
// Wiring error, not a user error: without the loaded target there
|
|
91
|
-
// is no stored level, and a gate that silently passes un-guards
|
|
92
|
-
// the boundary it exists to protect.
|
|
93
|
-
throw internalError(new Error("AuthorizeVisibilityTransition ran without a loaded target — step must be placed after the load step"), "visibility authorization requires the loaded resource");
|
|
94
|
-
}
|
|
95
|
-
const stored = metadataOf(target)?.visibility;
|
|
96
|
-
if (stored === ApiResourceVisibility.visibility_public) {
|
|
97
|
-
return; // Re-asserting a stored PUBLIC is not an escalation.
|
|
98
|
-
}
|
|
99
|
-
await requireOperatorMaySetPublic(authorizer, ctx.callerIdentity);
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* The single owner of "may this caller set public?" — both doors call it,
|
|
105
|
-
* and so does the plugin push chain, whose requested level rides the
|
|
106
|
-
* request (the level then flows to every member through the members' own
|
|
107
|
-
* create and updateVisibility doors, which run this check again).
|
|
108
|
-
*/
|
|
109
|
-
export async function requireOperatorMaySetPublic(authorizer, caller) {
|
|
110
|
-
let decision;
|
|
111
|
-
try {
|
|
112
|
-
decision = await authorizer.authorize(caller, {
|
|
113
|
-
permission: IamPermission.can_set_public_visibility,
|
|
114
|
-
resourceKind: ApiResourceKind.platform,
|
|
115
|
-
resourceId: "stigmer",
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
throw publicVisibilityCheckFailure(error);
|
|
120
|
-
}
|
|
121
|
-
switch (decision.kind) {
|
|
122
|
-
case "allow":
|
|
123
|
-
return;
|
|
124
|
-
case "deny":
|
|
125
|
-
case "not-found":
|
|
126
|
-
throw new ConnectError(PUBLIC_VISIBILITY_DENY_MESSAGE, Code.PermissionDenied);
|
|
127
|
-
case "unavailable":
|
|
128
|
-
throw publicVisibilityCheckFailure(decision.cause);
|
|
129
|
-
default: {
|
|
130
|
-
const exhaustive = decision;
|
|
131
|
-
throw publicVisibilityCheckFailure(new Error(`unknown decision ${JSON.stringify(exhaustive)}`));
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/** Authorization infrastructure failure: fail closed, sanitized (#478). */
|
|
136
|
-
function publicVisibilityCheckFailure(error) {
|
|
137
|
-
return internalError(error instanceof Error ? error : new Error(String(error)), "public-visibility authorization could not be completed");
|
|
138
|
-
}
|
|
139
|
-
//# sourceMappingURL=visibility-gates.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"visibility-gates.js","sourceRoot":"","sources":["../../../src/pipeline/steps/visibility-gates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGzD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wDAAwD,CAAC;AAC/F,OAAO,EAAE,eAAe,EAAE,MAAM,qFAAqF,CAAC;AAEtH,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAI1E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;GAIG;AACH,MAAM,CAAC,MAAM,8BAA8B,GACzC,qDAAqD;IACrD,mDAAmD,CAAC;AAEtD,8EAA8E;AAC9E,MAAM,UAAU,4BAA4B,CAC1C,UAAsB;IAEtB,OAAO;QACL,IAAI,EAAE,uBAAuB;QAC7B,KAAK,CAAC,OAAO,CAAC,GAAyB;YACrC,IAAI,GAAG,CAAC,cAAc,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;gBAClD,OAAO;YACT,CAAC;YACD,IACE,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,UAAU;gBACpC,qBAAqB,CAAC,iBAAiB,EACvC,CAAC;gBACD,OAAO;YACT,CAAC;YACD,MAAM,2BAA2B,CAAC,UAAU,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oCAAoC,CAClD,SAAiB,EACjB,UAAsB;IAEtB,OAAO;QACL,IAAI,EAAE,+BAA+B;QACrC,KAAK,CAAC,OAAO,CAAC,GAAyB;YACrC,IAAI,GAAG,CAAC,cAAc,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;gBAClD,OAAO;YACT,CAAC;YACD,MAAM,SAAS,GAAI,GAAG,CAAC,KAA0C;iBAC9D,UAAU,CAAC;YACd,IAAI,SAAS,KAAK,qBAAqB,CAAC,iBAAiB,EAAE,CAAC;gBAC1D,OAAO;YACT,CAAC;YACD,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAClC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,kEAAkE;gBAClE,gEAAgE;gBAChE,qCAAqC;gBACrC,MAAM,aAAa,CACjB,IAAI,KAAK,CACP,qGAAqG,CACtG,EACD,uDAAuD,CACxD,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,UAAU,CAAC,MAA6B,CAAC,EAAE,UAAU,CAAC;YACrE,IAAI,MAAM,KAAK,qBAAqB,CAAC,iBAAiB,EAAE,CAAC;gBACvD,OAAO,CAAC,qDAAqD;YAC/D,CAAC;YACD,MAAM,2BAA2B,CAAC,UAAU,EAAE,GAAG,CAAC,cAAc,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,UAAsB,EACtB,MAAsB;IAEtB,IAAI,QAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,MAAM,EAAE;YAC5C,UAAU,EAAE,aAAa,CAAC,yBAAyB;YACnD,YAAY,EAAE,eAAe,CAAC,QAAQ;YACtC,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,4BAA4B,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,QAAQ,QAAQ,CAAC,IAAI,EAAE,CAAC;QACtB,KAAK,OAAO;YACV,OAAO;QACT,KAAK,MAAM,CAAC;QACZ,KAAK,WAAW;YACd,MAAM,IAAI,YAAY,CACpB,8BAA8B,EAC9B,IAAI,CAAC,gBAAgB,CACtB,CAAC;QACJ,KAAK,aAAa;YAChB,MAAM,4BAA4B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACrD,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,UAAU,GAAU,QAAQ,CAAC;YACnC,MAAM,4BAA4B,CAChC,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC,CAC5D,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,SAAS,4BAA4B,CAAC,KAAc;IAClD,OAAO,aAAa,CAClB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EACzD,wDAAwD,CACzD,CAAC;AACJ,CAAC"}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/cross-org-share-creation.fga.yaml
|
|
2
|
-
# at commit 2ec420161 (the OpenFGA store test the cloud runs against its live model).
|
|
3
|
-
# The body below is byte-identical to the source; the cloud re-runs the LIVE
|
|
4
|
-
# file against this evaluator at the re-pin, so a stale copy is caught there.
|
|
5
|
-
# Cross-org share creation, the FGA half of the decision 013 D2 consent
|
|
6
|
-
# bar. Creating a share of ANOTHER org's marketplace-public agent requires:
|
|
7
|
-
#
|
|
8
|
-
# 1. can_execute on the agent — granted to every authenticated account by
|
|
9
|
-
# the allow_public wildcard when the agent is public (checked here),
|
|
10
|
-
# and to nobody cross-org when it is not.
|
|
11
|
-
# 2. can_create_agent_share on the SHARE's own org — admin-level: a
|
|
12
|
-
# public share spends the org's credits on the open internet. The
|
|
13
|
-
# per-kind can_create_* pattern, one more row.
|
|
14
|
-
#
|
|
15
|
-
# The same-org bar (agent can_edit) is untouched and pinned by
|
|
16
|
-
# agent-share-owner.fga.yaml; the app-level halves of the contract
|
|
17
|
-
# (visibility check, audience rule, dependency sweep, agent-id pin) are
|
|
18
|
-
# handler logic outside FGA, pinned by the Java and Go unit tests.
|
|
19
|
-
|
|
20
|
-
name: cross-org-share-creation
|
|
21
|
-
model_file: ../model/fga.mod
|
|
22
|
-
|
|
23
|
-
tuples:
|
|
24
|
-
# provider-org publishes a marketplace-public agent (the conditional
|
|
25
|
-
# wildcard viewer tuple visibility_public writes).
|
|
26
|
-
- user: organization:provider-org
|
|
27
|
-
relation: organization
|
|
28
|
-
object: agent:public-helper
|
|
29
|
-
- user: identity_account:paula
|
|
30
|
-
relation: owner
|
|
31
|
-
object: agent:public-helper
|
|
32
|
-
- user: identity_account:*
|
|
33
|
-
relation: viewer
|
|
34
|
-
object: agent:public-helper
|
|
35
|
-
condition:
|
|
36
|
-
name: allow_public
|
|
37
|
-
context: {}
|
|
38
|
-
|
|
39
|
-
# A private agent in the same provider org — the wildcard is absent.
|
|
40
|
-
- user: organization:provider-org
|
|
41
|
-
relation: organization
|
|
42
|
-
object: agent:private-helper
|
|
43
|
-
- user: identity_account:paula
|
|
44
|
-
relation: owner
|
|
45
|
-
object: agent:private-helper
|
|
46
|
-
|
|
47
|
-
# consumer-org: an admin and a plain member.
|
|
48
|
-
- user: identity_account:adam
|
|
49
|
-
relation: admin
|
|
50
|
-
object: organization:consumer-org
|
|
51
|
-
- user: identity_account:mia
|
|
52
|
-
relation: member
|
|
53
|
-
object: organization:consumer-org
|
|
54
|
-
|
|
55
|
-
tests:
|
|
56
|
-
- name: consumer-org admin holds both halves of the cross-org bar
|
|
57
|
-
check:
|
|
58
|
-
- user: identity_account:adam
|
|
59
|
-
object: agent:public-helper
|
|
60
|
-
context:
|
|
61
|
-
allow: true
|
|
62
|
-
assertions:
|
|
63
|
-
can_execute: true
|
|
64
|
-
can_edit: false
|
|
65
|
-
- user: identity_account:adam
|
|
66
|
-
object: organization:consumer-org
|
|
67
|
-
assertions:
|
|
68
|
-
can_create_agent_share: true
|
|
69
|
-
|
|
70
|
-
- name: plain member lacks the org-side bar (spending is admin-level)
|
|
71
|
-
check:
|
|
72
|
-
- user: identity_account:mia
|
|
73
|
-
object: agent:public-helper
|
|
74
|
-
context:
|
|
75
|
-
allow: true
|
|
76
|
-
assertions:
|
|
77
|
-
can_execute: true
|
|
78
|
-
- user: identity_account:mia
|
|
79
|
-
object: organization:consumer-org
|
|
80
|
-
assertions:
|
|
81
|
-
can_create_agent_share: false
|
|
82
|
-
|
|
83
|
-
- name: nobody cross-org can execute a private agent
|
|
84
|
-
check:
|
|
85
|
-
- user: identity_account:adam
|
|
86
|
-
object: agent:private-helper
|
|
87
|
-
context:
|
|
88
|
-
allow: true
|
|
89
|
-
assertions:
|
|
90
|
-
can_execute: false
|
|
91
|
-
can_view: false
|
|
92
|
-
|
|
93
|
-
- name: the org-side bar does not leak across orgs
|
|
94
|
-
check:
|
|
95
|
-
- user: identity_account:paula
|
|
96
|
-
object: organization:consumer-org
|
|
97
|
-
assertions:
|
|
98
|
-
can_create_agent_share: false
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/public-visibility-setter.fga.yaml
|
|
2
|
-
# at commit b87dd1170 (the OpenFGA store test the cloud runs against its live model).
|
|
3
|
-
# The body below is byte-identical to the source; the cloud re-runs the LIVE
|
|
4
|
-
# file against this evaluator at the re-pin, so a stale copy is caught there.
|
|
5
|
-
# Store tests for the public-visibility permission (marketplace curation).
|
|
6
|
-
#
|
|
7
|
-
# can_set_public_visibility gates who may set a resource's visibility to
|
|
8
|
-
# PUBLIC — the only level that crosses every org boundary. It derives
|
|
9
|
-
# from the platform operator role: operators (human curators and the
|
|
10
|
-
# seeding machine account) hold it; ordinary tenants — even org owners,
|
|
11
|
-
# who can otherwise fully manage their resources — never do. Enforced by
|
|
12
|
-
# PublicVisibilityEscalationPolicy at both write doors (updateVisibility
|
|
13
|
-
# escalation and create-with-public).
|
|
14
|
-
#
|
|
15
|
-
# Run with:
|
|
16
|
-
# fga model test --tests public-visibility-setter.fga.yaml
|
|
17
|
-
name: public-visibility-setter
|
|
18
|
-
model_file: ../model/fga.mod
|
|
19
|
-
|
|
20
|
-
tuples:
|
|
21
|
-
# The bootstrap machine account is the platform operator
|
|
22
|
-
# (BootstrapIdentitySeeder re-asserts this tuple on every boot).
|
|
23
|
-
- user: identity_account:machine
|
|
24
|
-
relation: operator
|
|
25
|
-
object: platform:stigmer
|
|
26
|
-
|
|
27
|
-
# A human operator granted the same platform role.
|
|
28
|
-
- user: identity_account:opal
|
|
29
|
-
relation: operator
|
|
30
|
-
object: platform:stigmer
|
|
31
|
-
|
|
32
|
-
# A tenant org owner — owns everything in their org, nothing on the
|
|
33
|
-
# platform.
|
|
34
|
-
- user: identity_account:mallory
|
|
35
|
-
relation: owner
|
|
36
|
-
object: organization:acme
|
|
37
|
-
|
|
38
|
-
tests:
|
|
39
|
-
- name: operators may set public visibility, tenants may not
|
|
40
|
-
check:
|
|
41
|
-
- user: identity_account:machine
|
|
42
|
-
object: platform:stigmer
|
|
43
|
-
assertions:
|
|
44
|
-
can_set_public_visibility: true
|
|
45
|
-
- user: identity_account:opal
|
|
46
|
-
object: platform:stigmer
|
|
47
|
-
assertions:
|
|
48
|
-
can_set_public_visibility: true
|
|
49
|
-
- user: identity_account:mallory
|
|
50
|
-
object: platform:stigmer
|
|
51
|
-
assertions:
|
|
52
|
-
can_set_public_visibility: false
|