@stigmer/server 3.23.0 → 3.24.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/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/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.map +1 -1
- package/dist/domain/plugin/controller.js +1 -3
- 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/controller.d.ts.map +1 -1
- package/dist/domain/skill/controller.js +0 -2
- package/dist/domain/skill/controller.js.map +1 -1
- package/dist/domain/workflow/agent-call-references.d.ts +81 -0
- package/dist/domain/workflow/agent-call-references.d.ts.map +1 -0
- package/dist/domain/workflow/agent-call-references.js +117 -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 +3 -3
- 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-labels.d.ts +10 -9
- package/dist/pipeline/apiresource-labels.d.ts.map +1 -1
- package/dist/pipeline/apiresource-labels.js +10 -9
- package/dist/pipeline/apiresource-labels.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 +204 -20
- package/dist/pipeline/steps/references.d.ts.map +1 -1
- package/dist/pipeline/steps/references.js +356 -43
- package/dist/pipeline/steps/references.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/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/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 +1 -8
- 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/controller.ts +0 -7
- package/src/domain/workflow/__tests__/agent-call-references.test.ts +373 -0
- package/src/domain/workflow/agent-call-references.ts +204 -0
- package/src/domain/workflow/controller.ts +28 -10
- package/src/domain/workflow/registry/data/task-kind-registry.json +3 -3
- 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-labels.ts +10 -9
- 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 +737 -0
- package/src/pipeline/steps/authorization-tuples.ts +9 -11
- package/src/pipeline/steps/references.ts +622 -70
- 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/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
|
@@ -1362,7 +1362,7 @@
|
|
|
1362
1362
|
{
|
|
1363
1363
|
"name": "agent",
|
|
1364
1364
|
"displayName": "Agent",
|
|
1365
|
-
"description": "Agent
|
|
1365
|
+
"description": "Agent to invoke, as \"slug\", \"org/slug\", or a value holding a runtime expression. - \"slug\": an agent of the organization the workflow runs in; checked when the workflow is saved, against the workflow's own organization - \"org/slug\": that organization's agent; checked when the workflow is saved, and another organization's agent must be shared at platform visibility - a value holding \"${ ... }\", \"${.env_vars.KEY}\" or \"${.secrets.KEY}\": resolved to \"slug\" or \"org/slug\" when the task runs, and read as the person who ran the workflow Examples: \"code-reviewer\", \"acme/data-analyst\", \"${.env_vars.TEAM_ORG}/assistant\" Required field.",
|
|
1366
1366
|
"type": "string",
|
|
1367
1367
|
"required": true,
|
|
1368
1368
|
"groupId": "core",
|
|
@@ -1470,7 +1470,7 @@
|
|
|
1470
1470
|
"additionalProperties": false,
|
|
1471
1471
|
"properties": {
|
|
1472
1472
|
"agent": {
|
|
1473
|
-
"description": "Agent
|
|
1473
|
+
"description": "Agent to invoke, as \"slug\", \"org/slug\", or a value holding a runtime expression. - \"slug\": an agent of the organization the workflow runs in; checked when the workflow is saved, against the workflow's own organization - \"org/slug\": that organization's agent; checked when the workflow is saved, and another organization's agent must be shared at platform visibility - a value holding \"${ ... }\", \"${.env_vars.KEY}\" or \"${.secrets.KEY}\": resolved to \"slug\" or \"org/slug\" when the task runs, and read as the person who ran the workflow Examples: \"code-reviewer\", \"acme/data-analyst\", \"${.env_vars.TEAM_ORG}/assistant\" Required field.",
|
|
1474
1474
|
"maxLength": 127,
|
|
1475
1475
|
"minLength": 1,
|
|
1476
1476
|
"type": "string"
|
|
@@ -1525,7 +1525,7 @@
|
|
|
1525
1525
|
"type": "string"
|
|
1526
1526
|
},
|
|
1527
1527
|
"org": {
|
|
1528
|
-
"description": "Organization that owns the referenced resource. When non-empty: must be a valid org slug (lowercase alphanumeric with hyphens, starts with a letter, 1-63 characters). Example: \"stigmer\", \"acme-corp\". When empty: the reference is relative — the server resolves it to the parent resource's organization at write time. All stored and returned references always have org populated (absolute form). Use empty org for same-org references (the common case).
|
|
1528
|
+
"description": "Organization that owns the referenced resource. When non-empty: must be a valid org slug (lowercase alphanumeric with hyphens, starts with a letter, 1-63 characters). Example: \"stigmer\", \"acme-corp\". When empty: the reference is relative — the server resolves it to the parent resource's organization at write time. All stored and returned references always have org populated (absolute form). Use empty org for same-org references (the common case). An explicit other org is accepted only when that organization is a platform that shares the resource with yours (visibility_platform).",
|
|
1529
1529
|
"maxLength": 63,
|
|
1530
1530
|
"pattern": "^$|^[a-z][a-z0-9-]*[a-z0-9]$",
|
|
1531
1531
|
"type": "string"
|
|
@@ -105,7 +105,10 @@ function taskConstraintViolations(task: WorkflowTask): string[] {
|
|
|
105
105
|
* task_config is a Struct again — that is what the walker's recursion is
|
|
106
106
|
* for).
|
|
107
107
|
*/
|
|
108
|
-
function configConstraintViolations(
|
|
108
|
+
function configConstraintViolations(
|
|
109
|
+
task: WorkflowTask,
|
|
110
|
+
cfg: Message,
|
|
111
|
+
): string[] {
|
|
109
112
|
const schema = taskConfigSchemaFor(task.kind);
|
|
110
113
|
if (schema === undefined) {
|
|
111
114
|
// Unknown kinds were already rejected by validateTaskKinds; an
|
|
@@ -129,9 +132,10 @@ function configConstraintViolations(task: WorkflowTask, cfg: Message): string[]
|
|
|
129
132
|
* The WorkflowTask lists embedded in a control-flow task config, in
|
|
130
133
|
* declaration order — the same recursion set the converter walks
|
|
131
134
|
* (convertForTask/convertForkTask/convertTryTask) and the cloud Java
|
|
132
|
-
* TaskConfigStrictParser mirrors.
|
|
135
|
+
* TaskConfigStrictParser mirrors. Exported for the write-time reference
|
|
136
|
+
* collector (../agent-call-references.ts), which walks the same tree.
|
|
133
137
|
*/
|
|
134
|
-
function nestedTasks(cfg: Message): WorkflowTask[] {
|
|
138
|
+
export function nestedTasks(cfg: Message): WorkflowTask[] {
|
|
135
139
|
switch (cfg.$typeName) {
|
|
136
140
|
case ForTaskConfigSchema.typeName:
|
|
137
141
|
return (cfg as ForTaskConfig).do;
|
|
@@ -72,7 +72,10 @@ import {
|
|
|
72
72
|
TARGET_RESOURCE_KEY,
|
|
73
73
|
newLoadTargetStep,
|
|
74
74
|
} from "../../pipeline/steps/load-target.js";
|
|
75
|
-
import {
|
|
75
|
+
import {
|
|
76
|
+
newNormalizeReferencesStep,
|
|
77
|
+
newValidateReferencesStep,
|
|
78
|
+
} from "../../pipeline/steps/references.js";
|
|
76
79
|
import {
|
|
77
80
|
newCleanupIamPoliciesStep,
|
|
78
81
|
newCreateAuthorizationTuplesStep,
|
|
@@ -299,7 +302,8 @@ async function createExecution(
|
|
|
299
302
|
.addStep(newCheckDuplicateStep(deps.store))
|
|
300
303
|
.addStep(newBuildNewStateStep())
|
|
301
304
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
302
|
-
.addStep(newNormalizeReferencesStep())
|
|
305
|
+
.addStep(newNormalizeReferencesStep())
|
|
306
|
+
.addStep(newValidateReferencesStep(deps.store));
|
|
303
307
|
// The ratified sandbox-acquisition gate slot (blueprint 03 §3a; C4):
|
|
304
308
|
// the Java-verified capacity-gate position — after Authorize and every
|
|
305
309
|
// resolution step (the default instance, like Java's, side-effects
|
|
@@ -389,6 +393,7 @@ async function update(
|
|
|
389
393
|
.addStep(newBuildUpdateStateStep())
|
|
390
394
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
391
395
|
.addStep(newNormalizeReferencesStep())
|
|
396
|
+
.addStep(newValidateReferencesStep(deps.store))
|
|
392
397
|
.addStep(newPersistStep(deps.store))
|
|
393
398
|
.addStep(
|
|
394
399
|
newIndexSearchStep(
|
|
@@ -58,10 +58,6 @@ import {
|
|
|
58
58
|
newAuthorizeResolvedTargetStep,
|
|
59
59
|
} from "../../pipeline/steps/authorize-resolved-target.js";
|
|
60
60
|
import { newGuardReservedLabelsStep } from "../../pipeline/steps/guard-reserved-labels.js";
|
|
61
|
-
import {
|
|
62
|
-
newAuthorizeVisibilityTransitionStep,
|
|
63
|
-
newGuardPublicVisibilityStep,
|
|
64
|
-
} from "../../pipeline/steps/visibility-gates.js";
|
|
65
61
|
import {
|
|
66
62
|
newBuildNewStateStep,
|
|
67
63
|
setAuditFieldsForUpdate,
|
|
@@ -91,7 +87,10 @@ import {
|
|
|
91
87
|
TARGET_RESOURCE_KEY,
|
|
92
88
|
newLoadTargetStep,
|
|
93
89
|
} from "../../pipeline/steps/load-target.js";
|
|
94
|
-
import {
|
|
90
|
+
import {
|
|
91
|
+
newNormalizeReferencesStep,
|
|
92
|
+
newValidateReferencesStep,
|
|
93
|
+
} from "../../pipeline/steps/references.js";
|
|
95
94
|
import {
|
|
96
95
|
newCleanupIamPoliciesStep,
|
|
97
96
|
newCreateAuthorizationTuplesStep,
|
|
@@ -198,9 +197,9 @@ async function createInstance(
|
|
|
198
197
|
.addStep(newValidateSameOrgBusinessRuleStep(deps.logger))
|
|
199
198
|
.addStep(newCheckDuplicateStep(deps.store))
|
|
200
199
|
.addStep(newBuildNewStateStep())
|
|
201
|
-
.addStep(newGuardPublicVisibilityStep(deps.authorizer))
|
|
202
200
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
203
201
|
.addStep(newNormalizeReferencesStep())
|
|
202
|
+
.addStep(newValidateReferencesStep(deps.store))
|
|
204
203
|
.addStep(newPersistStep(deps.store))
|
|
205
204
|
.addStep(
|
|
206
205
|
newCreateAuthorizationTuplesStep(
|
|
@@ -249,6 +248,7 @@ async function update(
|
|
|
249
248
|
.addStep(newBuildUpdateStateStep())
|
|
250
249
|
.addStep(newGuardReservedLabelsStep(deps.authorizer))
|
|
251
250
|
.addStep(newNormalizeReferencesStep())
|
|
251
|
+
.addStep(newValidateReferencesStep(deps.store))
|
|
252
252
|
.addStep(newPersistStep(deps.store))
|
|
253
253
|
.addStep(
|
|
254
254
|
newIndexSearchStep(
|
|
@@ -407,12 +407,6 @@ async function updateVisibility(
|
|
|
407
407
|
),
|
|
408
408
|
)
|
|
409
409
|
.addStep(newValidateVisibilityUpdateStep())
|
|
410
|
-
.addStep(
|
|
411
|
-
newAuthorizeVisibilityTransitionStep(
|
|
412
|
-
UPDATE_VISIBILITY_INSTANCE_KEY,
|
|
413
|
-
deps.authorizer,
|
|
414
|
-
),
|
|
415
|
-
)
|
|
416
410
|
.addStep(newSetInstanceVisibilityStep())
|
|
417
411
|
.addStep(
|
|
418
412
|
newPersistInstanceStep(
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
* outsider on an EXISTING resource hears PERMISSION_DENIED, the
|
|
17
17
|
* cloud's answer; `findMyOrganizations` lists what a person may view
|
|
18
18
|
* and `find` refuses enumeration; `checkMyPermission` tells the truth;
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* the retired public level is refused for the founder too, as an
|
|
20
|
+
* invalid level and not a permission question; an unprovisioned
|
|
21
|
+
* subject writes nothing until provisioned. The LIST lanes are a member's
|
|
21
22
|
* lists: an outsider lists nothing of an organization they hold no
|
|
22
23
|
* row in; environments and API keys are their owner's even to the
|
|
23
24
|
* organization's owner; the library (a search) omits a private agent
|
|
@@ -26,8 +27,9 @@
|
|
|
26
27
|
* provisioned.
|
|
27
28
|
* - trusted-local: the permissive default stays (one caller,
|
|
28
29
|
* nothing to separate; the laptop's rows are stamped `"system"`):
|
|
29
|
-
* tokenless reads
|
|
30
|
-
*
|
|
30
|
+
* tokenless reads and organization enumeration keep working, and
|
|
31
|
+
* the retired public level is refused here exactly as it is under
|
|
32
|
+
* every other posture (the level is gone, not gated).
|
|
31
33
|
* - a unit's own Authorizer: nothing built in is installed; the unit's
|
|
32
34
|
* answer stands even against the founder.
|
|
33
35
|
*
|
|
@@ -80,7 +82,6 @@ import { loadConfig } from "../../boot/config.js";
|
|
|
80
82
|
import { composeServer } from "../../boot/compose.js";
|
|
81
83
|
import type { ComposedServer } from "../../boot/compose.js";
|
|
82
84
|
import { metadataOf } from "../../pipeline/steps/shapes.js";
|
|
83
|
-
import { PUBLIC_VISIBILITY_DENY_MESSAGE } from "../../pipeline/steps/visibility-gates.js";
|
|
84
85
|
import type { Store } from "../../store/interface.js";
|
|
85
86
|
import type { Authorizer } from "../authorizer.js";
|
|
86
87
|
import type { ListReadScope } from "../list-read-scope.js";
|
|
@@ -132,6 +133,15 @@ function organizationInput(slug: string) {
|
|
|
132
133
|
};
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
/**
|
|
137
|
+
* The one sentence for a level a kind does not support, as the agent chain
|
|
138
|
+
* answers it (pipeline/steps/validate-visibility.ts builds it from the
|
|
139
|
+
* kind's config); pinned as bytes because clients render it.
|
|
140
|
+
*/
|
|
141
|
+
const PUBLIC_LEVEL_REFUSED_FOR_AGENT =
|
|
142
|
+
"agent resources cannot be set to visibility_public. " +
|
|
143
|
+
"Supported visibility levels: visibility_private, visibility_org, visibility_platform.";
|
|
144
|
+
|
|
135
145
|
function agentInput(
|
|
136
146
|
name: string,
|
|
137
147
|
visibility: ApiResourceVisibility,
|
|
@@ -377,14 +387,14 @@ describe("built-in authorizer (composed server, OIDC with no unit Authorizer: th
|
|
|
377
387
|
);
|
|
378
388
|
});
|
|
379
389
|
|
|
380
|
-
it("
|
|
390
|
+
it("the retired public level is refused for the founder as an invalid level, before any permission question", async () => {
|
|
381
391
|
const failure = await failureOf(
|
|
382
392
|
createClient(AgentCommandController, asFounder()).create(
|
|
383
393
|
agentInput("Public Agent", ApiResourceVisibility.visibility_public),
|
|
384
394
|
),
|
|
385
395
|
);
|
|
386
|
-
expect(failure.code).toBe(Code.
|
|
387
|
-
expect(failure.rawMessage).toBe(
|
|
396
|
+
expect(failure.code).toBe(Code.InvalidArgument);
|
|
397
|
+
expect(failure.rawMessage).toBe(PUBLIC_LEVEL_REFUSED_FOR_AGENT);
|
|
388
398
|
});
|
|
389
399
|
|
|
390
400
|
describe("the list lanes (the built-in ListReadScope)", () => {
|
|
@@ -595,20 +605,18 @@ describe("built-in authorizer (composed server, trusted-local: the permissive de
|
|
|
595
605
|
expect(read.metadata?.id).toBe(created.metadata!.id);
|
|
596
606
|
});
|
|
597
607
|
|
|
598
|
-
it("the laptop keeps
|
|
608
|
+
it("the laptop keeps organization enumeration and refuses the retired public level like every posture — the level is gone, not gated", async () => {
|
|
599
609
|
const anonymous = transportFor(port);
|
|
600
|
-
const
|
|
601
|
-
AgentCommandController,
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
ApiResourceVisibility.visibility_public,
|
|
610
|
+
const failure = await failureOf(
|
|
611
|
+
createClient(AgentCommandController, anonymous).create(
|
|
612
|
+
agentInput(
|
|
613
|
+
"Public Laptop Agent",
|
|
614
|
+
ApiResourceVisibility.visibility_public,
|
|
615
|
+
),
|
|
607
616
|
),
|
|
608
617
|
);
|
|
609
|
-
expect(
|
|
610
|
-
|
|
611
|
-
);
|
|
618
|
+
expect(failure.code).toBe(Code.InvalidArgument);
|
|
619
|
+
expect(failure.rawMessage).toBe(PUBLIC_LEVEL_REFUSED_FOR_AGENT);
|
|
612
620
|
const all = await createClient(OrganizationQueryController, anonymous).find(
|
|
613
621
|
{ org: ORG },
|
|
614
622
|
);
|
|
@@ -617,6 +625,11 @@ describe("built-in authorizer (composed server, trusted-local: the permissive de
|
|
|
617
625
|
|
|
618
626
|
it("the laptop's lists are the full scan — no scope composed, the rows stamped `system` included", async () => {
|
|
619
627
|
const anonymous = transportFor(port);
|
|
628
|
+
// A second agent beside the private one the earlier test created, so
|
|
629
|
+
// the search below proves a scan and not a single-row coincidence.
|
|
630
|
+
await createClient(AgentCommandController, anonymous).create(
|
|
631
|
+
agentInput("Second Laptop Agent", ApiResourceVisibility.visibility_org),
|
|
632
|
+
);
|
|
620
633
|
const environments = createClient(EnvironmentCommandController, anonymous);
|
|
621
634
|
await environments.create(environmentInput("laptop env one"));
|
|
622
635
|
await environments.create(environmentInput("laptop env two"));
|
|
@@ -1074,7 +1074,7 @@ describe("extension composition (C2 tuple lifecycle + organization directory)",
|
|
|
1074
1074
|
});
|
|
1075
1075
|
});
|
|
1076
1076
|
|
|
1077
|
-
it("updateVisibility fires the set-diff transition (org→
|
|
1077
|
+
it("updateVisibility fires the set-diff transition (org→private deletes the org shape)", async () => {
|
|
1078
1078
|
const command = createClient(AgentCommandController, portTransport);
|
|
1079
1079
|
const agent = await command.create(
|
|
1080
1080
|
create(AgentSchema, {
|
|
@@ -1091,12 +1091,12 @@ describe("extension composition (C2 tuple lifecycle + organization directory)",
|
|
|
1091
1091
|
visibilityEvents.length = 0;
|
|
1092
1092
|
await command.updateVisibility({
|
|
1093
1093
|
resourceId: agent.metadata?.id ?? "",
|
|
1094
|
-
visibility: ApiResourceVisibility.
|
|
1094
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
1095
1095
|
});
|
|
1096
1096
|
expect(visibilityEvents).toHaveLength(1);
|
|
1097
1097
|
const event = visibilityEvents[0]!;
|
|
1098
|
-
expect(event.shapesToCreate).toEqual([
|
|
1099
|
-
expect(event.shapesToDelete).toEqual([]);
|
|
1098
|
+
expect(event.shapesToCreate).toEqual([]);
|
|
1099
|
+
expect(event.shapesToDelete).toEqual(["org-viewer"]);
|
|
1100
1100
|
});
|
|
1101
1101
|
|
|
1102
1102
|
it("delete fires the cleanup event; a cleanup failure never fails the delete", async () => {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* narrows, blank spans orgs — lane 6),
|
|
11
11
|
* - activity.listRecentActivity (enumeration verb, two kinds — lane 22),
|
|
12
12
|
* - search (enumeration verb feeding the engine allowlist, and the
|
|
13
|
-
*
|
|
13
|
+
* proof that no request shape bypasses it — lane 21),
|
|
14
14
|
* - the OUTAGE arm: a throwing scope answers the sanitized INTERNAL,
|
|
15
15
|
* never an empty (or full!) list;
|
|
16
16
|
* - the SERVER'S OWN reads over `inProcessTransport` (stigmer#1207):
|
|
@@ -277,20 +277,23 @@ describe("list read scope (composed server, fake scope)", () => {
|
|
|
277
277
|
]);
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
-
it("search narrows through the engine allowlist
|
|
280
|
+
it("search narrows through the engine allowlist on every request shape — nothing bypasses the scope (lane 21)", async () => {
|
|
281
281
|
allowed = new Set(["agt_mine"]);
|
|
282
282
|
const search = createClient(SearchService, transport);
|
|
283
283
|
const scoped = await search.search({ query: "scopedagent" });
|
|
284
284
|
expect(scoped.entries.map((e) => e.id)).toEqual(["agt_mine"]);
|
|
285
285
|
|
|
286
|
-
// The
|
|
286
|
+
// The org-filtered shape asks the scope too: the one request shape
|
|
287
|
+
// that once skipped it (the retired public level's cross-organization
|
|
288
|
+
// discovery) no longer exists on the wire.
|
|
287
289
|
seenKinds.length = 0;
|
|
288
|
-
await search.search({
|
|
290
|
+
const orgScoped = await search.search({
|
|
291
|
+
kinds: [ApiResourceKind.agent],
|
|
289
292
|
query: "scopedagent",
|
|
290
293
|
org: "acme",
|
|
291
|
-
crossOrgPublic: true,
|
|
292
294
|
});
|
|
293
|
-
expect(
|
|
295
|
+
expect(orgScoped.entries.map((e) => e.id)).toEqual(["agt_mine"]);
|
|
296
|
+
expect(seenKinds).toEqual([ApiResourceKind.agent]);
|
|
294
297
|
});
|
|
295
298
|
|
|
296
299
|
it("a scope outage answers the sanitized INTERNAL — never an unscoped or empty success", async () => {
|
|
@@ -32,9 +32,10 @@
|
|
|
32
32
|
* Semantics the controller and the conformance suite rely on (the Java
|
|
33
33
|
* check-handler posture the cloud's client already implements):
|
|
34
34
|
*
|
|
35
|
-
* - `check`
|
|
36
|
-
* "may I read this
|
|
37
|
-
*
|
|
35
|
+
* - `check` resolves usersets (a grant to `organization:acme#member`
|
|
36
|
+
* answers true for a member), so "may I read this" is the model's
|
|
37
|
+
* answer and not a lookup of who was named.
|
|
38
|
+
* - the two listings never expand usersets, and `listPrincipalIds`
|
|
38
39
|
* answers DIRECT principals only — a listing is an inventory of who
|
|
39
40
|
* was named, never a resolution of who could reach.
|
|
40
41
|
* - contextual policies are evaluated as if held, and nothing is written.
|
|
@@ -74,7 +75,7 @@ export interface AuthorizationQueryEngine {
|
|
|
74
75
|
): Promise<boolean>;
|
|
75
76
|
/**
|
|
76
77
|
* The ids of `resourceKind` resources on which `principal` holds
|
|
77
|
-
* `relation` (ListAuthorizedResourceIdsInput's field order).
|
|
78
|
+
* `relation` (ListAuthorizedResourceIdsInput's field order). Usersets
|
|
78
79
|
* are not expanded.
|
|
79
80
|
*/
|
|
80
81
|
listResourceIds(
|
|
@@ -86,7 +87,7 @@ export interface AuthorizationQueryEngine {
|
|
|
86
87
|
/**
|
|
87
88
|
* The ids of `principalKind` principals holding `relation` on `resource`
|
|
88
89
|
* (ListAuthorizedPrincipalIdsInput's field order). Direct principals
|
|
89
|
-
* only;
|
|
90
|
+
* only; usersets are not expanded.
|
|
90
91
|
*/
|
|
91
92
|
listPrincipalIds(
|
|
92
93
|
resource: ApiResourceRef,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* is yours). On a multi-tenant edition the same scans serve OTHER
|
|
9
9
|
* tenants' rows, so the cloud baseline (the Java list handlers) narrows
|
|
10
10
|
* every one of them to the caller's FGA-authorized id set (ListObjects
|
|
11
|
-
* on can_view
|
|
11
|
+
* on can_view), with a second guest
|
|
12
12
|
* cookie-label rule on the session and agent-execution lanes.
|
|
13
13
|
*
|
|
14
14
|
* This port is the ONE seam for that fork (DD-007 addendum 3: every
|
|
@@ -65,14 +65,12 @@ import type { CallerIdentity } from "./identity.js";
|
|
|
65
65
|
* The visibility tuple shapes of the shared FGA model, named
|
|
66
66
|
* edition-neutrally. The driver maps each to its tuple:
|
|
67
67
|
* - org-viewer: <kind>:<id>#viewer@organization:<org>#viewer
|
|
68
|
-
* - public-viewer: <kind>:<id>#viewer@identity_account:* (conditional)
|
|
69
68
|
* - platform-viewer: <kind>:<id>#platform_viewer@identity_provider:<idp>#platform_user
|
|
70
69
|
* (fans out per IdP the org owns — the driver's lookup, not OSS's)
|
|
70
|
+
* Every shape names a bounded set of readers; the model has no shape that
|
|
71
|
+
* reaches every account.
|
|
71
72
|
*/
|
|
72
|
-
export type VisibilityTupleShape =
|
|
73
|
-
| "org-viewer"
|
|
74
|
-
| "public-viewer"
|
|
75
|
-
| "platform-viewer";
|
|
73
|
+
export type VisibilityTupleShape = "org-viewer" | "platform-viewer";
|
|
76
74
|
|
|
77
75
|
/**
|
|
78
76
|
* One resolved structural link from the created resource to a parent
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins `supportsVisibility` and `supportedVisibilityLevels`
|
|
3
|
+
* (pipeline/apiresource-meta.ts), the one predicate behind the
|
|
4
|
+
* ValidateVisibility doors on every create and updateVisibility chain.
|
|
5
|
+
*
|
|
6
|
+
* The retired public level is the reason this file exists: no kind config
|
|
7
|
+
* declares it any more, so the predicate cannot read a flag for it and must
|
|
8
|
+
* answer from its own text. The first test walks EVERY kind that has
|
|
9
|
+
* `kind_meta` and asserts the level is refused; the door is one function,
|
|
10
|
+
* and this is the pin that it holds for kinds nobody thought to try. The
|
|
11
|
+
* rest of the file pins the levels that remain against the proto's
|
|
12
|
+
* declarations for the kinds whose configs differ (a blueprint, an
|
|
13
|
+
* instance, an org-only kind, a kind with no config), and the copy fragment
|
|
14
|
+
* both editions build the INVALID_ARGUMENT sentence from.
|
|
15
|
+
*/
|
|
16
|
+
import { describe, expect, it } from "vitest";
|
|
17
|
+
|
|
18
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
19
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
getKindMeta,
|
|
23
|
+
supportedVisibilityLevels,
|
|
24
|
+
supportsVisibility,
|
|
25
|
+
} from "../apiresource-meta.js";
|
|
26
|
+
|
|
27
|
+
const V = ApiResourceVisibility;
|
|
28
|
+
|
|
29
|
+
/** Every enum member that carries kind_meta (the unknown kind does not). */
|
|
30
|
+
const KINDS_WITH_META: ApiResourceKind[] = Object.values(ApiResourceKind)
|
|
31
|
+
.filter((value): value is ApiResourceKind => typeof value === "number")
|
|
32
|
+
.filter((kind) => {
|
|
33
|
+
try {
|
|
34
|
+
getKindMeta(kind);
|
|
35
|
+
return true;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
describe("supportsVisibility", () => {
|
|
42
|
+
it("refuses the retired public level for every kind", () => {
|
|
43
|
+
expect(KINDS_WITH_META.length).toBeGreaterThan(20);
|
|
44
|
+
for (const kind of KINDS_WITH_META) {
|
|
45
|
+
expect(supportsVisibility(kind, V.visibility_public)).toBe(false);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("private and unspecified are supported by every kind", () => {
|
|
50
|
+
for (const kind of KINDS_WITH_META) {
|
|
51
|
+
expect(supportsVisibility(kind, V.visibility_private)).toBe(true);
|
|
52
|
+
expect(
|
|
53
|
+
supportsVisibility(kind, V.api_resource_visibility_unspecified),
|
|
54
|
+
).toBe(true);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("a blueprint kind holds org and platform", () => {
|
|
59
|
+
expect(supportsVisibility(ApiResourceKind.agent, V.visibility_org)).toBe(
|
|
60
|
+
true,
|
|
61
|
+
);
|
|
62
|
+
expect(
|
|
63
|
+
supportsVisibility(ApiResourceKind.agent, V.visibility_platform),
|
|
64
|
+
).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("an instance kind holds org but never platform (tenant isolation)", () => {
|
|
68
|
+
expect(
|
|
69
|
+
supportsVisibility(ApiResourceKind.agent_instance, V.visibility_org),
|
|
70
|
+
).toBe(true);
|
|
71
|
+
expect(
|
|
72
|
+
supportsVisibility(ApiResourceKind.agent_instance, V.visibility_platform),
|
|
73
|
+
).toBe(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("an org-only kind holds org alone (environment: secrets never cross the org)", () => {
|
|
77
|
+
expect(
|
|
78
|
+
supportsVisibility(ApiResourceKind.environment, V.visibility_org),
|
|
79
|
+
).toBe(true);
|
|
80
|
+
expect(
|
|
81
|
+
supportsVisibility(ApiResourceKind.environment, V.visibility_platform),
|
|
82
|
+
).toBe(false);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("a kind with no visibility config is private-only", () => {
|
|
86
|
+
expect(supportsVisibility(ApiResourceKind.session, V.visibility_org)).toBe(
|
|
87
|
+
false,
|
|
88
|
+
);
|
|
89
|
+
expect(
|
|
90
|
+
supportsVisibility(ApiResourceKind.session, V.visibility_platform),
|
|
91
|
+
).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe("supportedVisibilityLevels (the copy fragment)", () => {
|
|
96
|
+
it("names the levels that remain, private first, never the retired one", () => {
|
|
97
|
+
expect(supportedVisibilityLevels(ApiResourceKind.agent)).toBe(
|
|
98
|
+
"visibility_private, visibility_org, visibility_platform",
|
|
99
|
+
);
|
|
100
|
+
expect(supportedVisibilityLevels(ApiResourceKind.agent_instance)).toBe(
|
|
101
|
+
"visibility_private, visibility_org",
|
|
102
|
+
);
|
|
103
|
+
expect(supportedVisibilityLevels(ApiResourceKind.session)).toBe(
|
|
104
|
+
"visibility_private",
|
|
105
|
+
);
|
|
106
|
+
for (const kind of KINDS_WITH_META) {
|
|
107
|
+
expect(supportedVisibilityLevels(kind)).not.toContain(
|
|
108
|
+
"visibility_public",
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
});
|
|
@@ -45,15 +45,16 @@ export const SYSTEM_MANAGED_LABEL = `${RESERVED_LABEL_PREFIX}system-managed`;
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Marks system content: a resource the platform itself seeded rather than a
|
|
48
|
-
* user authored
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
48
|
+
* user authored. The retired seedpack wrote it on every row it applied, and
|
|
49
|
+
* CLIs before the bootstrap stopped labelling stamped it on the `stigmer`
|
|
50
|
+
* organization they created. A plugin overlay may still carry it on a
|
|
51
|
+
* member (a reserved label, so the push charges the platform permission for
|
|
52
|
+
* it). It has one server-side meaning: a plugin
|
|
53
|
+
* push may adopt a system-content row that holds a slug the plugin needs,
|
|
54
|
+
* keeping the row's id and everything bound to it, instead of refusing the
|
|
55
|
+
* slug as taken. It never marks a user's resource, so a user's row is never
|
|
56
|
+
* adopted (domain/plugin/members.ts, judgeSlug); on an organization it is
|
|
57
|
+
* inert.
|
|
57
58
|
*/
|
|
58
59
|
export const SYSTEM_LABEL = `${RESERVED_LABEL_PREFIX}system`;
|
|
59
60
|
|
|
@@ -266,9 +266,18 @@ function tierRank(tier: ResourceTier): number {
|
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
/**
|
|
269
|
-
*
|
|
270
|
-
*
|
|
271
|
-
*
|
|
269
|
+
* Whether a kind may hold a visibility level — the one predicate behind the
|
|
270
|
+
* ValidateVisibility doors on every create and updateVisibility chain.
|
|
271
|
+
*
|
|
272
|
+
* PRIVATE and UNSPECIFIED are always supported (no visibility grant is
|
|
273
|
+
* written for them); ORG and PLATFORM require the matching supports_* flag
|
|
274
|
+
* on the kind's VisibilityConfig, so kinds with no config are private-only.
|
|
275
|
+
* PUBLIC is refused for every kind: the level is retired (it made a row
|
|
276
|
+
* readable to every account on the server), no config may declare it, and
|
|
277
|
+
* the answer is fixed here rather than read from a flag that no longer
|
|
278
|
+
* exists. Every level is named so a level added to the enum must be taught
|
|
279
|
+
* here before any row can hold it; the closing arm is unreachable by wire
|
|
280
|
+
* input, because both doors validate the field `defined_only` first.
|
|
272
281
|
*/
|
|
273
282
|
export function supportsVisibility(
|
|
274
283
|
kind: ApiResourceKind,
|
|
@@ -276,14 +285,19 @@ export function supportsVisibility(
|
|
|
276
285
|
): boolean {
|
|
277
286
|
const config = getKindMeta(kind).authorization?.visibility;
|
|
278
287
|
switch (visibility) {
|
|
279
|
-
case ApiResourceVisibility.
|
|
280
|
-
|
|
288
|
+
case ApiResourceVisibility.api_resource_visibility_unspecified:
|
|
289
|
+
case ApiResourceVisibility.visibility_private:
|
|
290
|
+
return true;
|
|
281
291
|
case ApiResourceVisibility.visibility_org:
|
|
282
292
|
return config?.supportsOrg === true;
|
|
283
293
|
case ApiResourceVisibility.visibility_platform:
|
|
284
294
|
return config?.supportsPlatform === true;
|
|
285
|
-
|
|
286
|
-
return
|
|
295
|
+
case ApiResourceVisibility.visibility_public:
|
|
296
|
+
return false;
|
|
297
|
+
default: {
|
|
298
|
+
const exhaustive: never = visibility;
|
|
299
|
+
throw new Error(`unknown visibility level: ${String(exhaustive)}`);
|
|
300
|
+
}
|
|
287
301
|
}
|
|
288
302
|
}
|
|
289
303
|
|
|
@@ -298,9 +312,6 @@ export function supportedVisibilityLevels(kind: ApiResourceKind): string {
|
|
|
298
312
|
if (config?.supportsOrg === true) {
|
|
299
313
|
levels += ", visibility_org";
|
|
300
314
|
}
|
|
301
|
-
if (config?.supportsPublic === true) {
|
|
302
|
-
levels += ", visibility_public";
|
|
303
|
-
}
|
|
304
315
|
if (config?.supportsPlatform === true) {
|
|
305
316
|
levels += ", visibility_platform";
|
|
306
317
|
}
|