@stigmer/server 3.15.2-dev.20260913223433 → 3.15.3-dev.20260914100347
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +103 -9
- package/dist/boot/compose.js.map +1 -1
- package/dist/domain/iampolicy/access-lists.d.ts +27 -0
- package/dist/domain/iampolicy/access-lists.d.ts.map +1 -0
- package/dist/domain/iampolicy/access-lists.js +124 -0
- package/dist/domain/iampolicy/access-lists.js.map +1 -0
- package/dist/domain/iampolicy/constants.d.ts +135 -0
- package/dist/domain/iampolicy/constants.d.ts.map +1 -0
- package/dist/domain/iampolicy/constants.js +203 -0
- package/dist/domain/iampolicy/constants.js.map +1 -0
- package/dist/domain/iampolicy/controller.d.ts +29 -0
- package/dist/domain/iampolicy/controller.d.ts.map +1 -0
- package/dist/domain/iampolicy/controller.js +451 -0
- package/dist/domain/iampolicy/controller.js.map +1 -0
- package/dist/domain/iampolicy/display-resolver.d.ts +6 -0
- package/dist/domain/iampolicy/display-resolver.d.ts.map +1 -0
- package/dist/domain/iampolicy/display-resolver.js +90 -0
- package/dist/domain/iampolicy/display-resolver.js.map +1 -0
- package/dist/domain/iampolicy/grant-path.d.ts +42 -0
- package/dist/domain/iampolicy/grant-path.d.ts.map +1 -0
- package/dist/domain/iampolicy/grant-path.js +183 -0
- package/dist/domain/iampolicy/grant-path.js.map +1 -0
- package/dist/domain/iampolicy/grant-scope.d.ts +4 -0
- package/dist/domain/iampolicy/grant-scope.d.ts.map +1 -0
- package/dist/domain/iampolicy/grant-scope.js +34 -0
- package/dist/domain/iampolicy/grant-scope.js.map +1 -0
- package/dist/domain/iampolicy/membership.d.ts +111 -0
- package/dist/domain/iampolicy/membership.d.ts.map +1 -0
- package/dist/domain/iampolicy/membership.js +152 -0
- package/dist/domain/iampolicy/membership.js.map +1 -0
- package/dist/domain/iampolicy/permissions.d.ts +19 -0
- package/dist/domain/iampolicy/permissions.d.ts.map +1 -0
- package/dist/domain/iampolicy/permissions.js +27 -0
- package/dist/domain/iampolicy/permissions.js.map +1 -0
- package/dist/domain/iampolicy/resource-store.d.ts +4 -0
- package/dist/domain/iampolicy/resource-store.d.ts.map +1 -0
- package/dist/domain/iampolicy/resource-store.js +135 -0
- package/dist/domain/iampolicy/resource-store.js.map +1 -0
- package/dist/domain/iampolicy/role-lifecycle.d.ts +9 -0
- package/dist/domain/iampolicy/role-lifecycle.d.ts.map +1 -0
- package/dist/domain/iampolicy/role-lifecycle.js +106 -0
- package/dist/domain/iampolicy/role-lifecycle.js.map +1 -0
- package/dist/domain/iampolicy/roles.d.ts +11 -0
- package/dist/domain/iampolicy/roles.d.ts.map +1 -0
- package/dist/domain/iampolicy/roles.js +78 -0
- package/dist/domain/iampolicy/roles.js.map +1 -0
- package/dist/domain/iampolicy/specs.d.ts +7 -0
- package/dist/domain/iampolicy/specs.d.ts.map +1 -0
- package/dist/domain/iampolicy/specs.js +45 -0
- package/dist/domain/iampolicy/specs.js.map +1 -0
- package/dist/domain/iampolicy/steps.d.ts +18 -0
- package/dist/domain/iampolicy/steps.d.ts.map +1 -0
- package/dist/domain/iampolicy/steps.js +117 -0
- package/dist/domain/iampolicy/steps.js.map +1 -0
- package/dist/domain/iampolicy/store-contract.d.ts +8 -0
- package/dist/domain/iampolicy/store-contract.d.ts.map +1 -0
- package/dist/domain/iampolicy/store-contract.js +258 -0
- package/dist/domain/iampolicy/store-contract.js.map +1 -0
- package/dist/domain/iampolicy/store.d.ts +78 -0
- package/dist/domain/iampolicy/store.d.ts.map +1 -0
- package/dist/domain/iampolicy/store.js +13 -0
- package/dist/domain/iampolicy/store.js.map +1 -0
- package/dist/domain/iampolicy/wire-refusals.d.ts +25 -0
- package/dist/domain/iampolicy/wire-refusals.d.ts.map +1 -0
- package/dist/domain/iampolicy/wire-refusals.js +76 -0
- package/dist/domain/iampolicy/wire-refusals.js.map +1 -0
- package/dist/domain/identityaccount/constants.d.ts +33 -0
- package/dist/domain/identityaccount/constants.d.ts.map +1 -1
- package/dist/domain/identityaccount/constants.js +2 -48
- package/dist/domain/identityaccount/constants.js.map +1 -1
- package/dist/domain/identityaccount/controller.d.ts +8 -1
- package/dist/domain/identityaccount/controller.d.ts.map +1 -1
- package/dist/domain/identityaccount/controller.js +54 -29
- package/dist/domain/identityaccount/controller.js.map +1 -1
- package/dist/domain/identityaccount/operator.d.ts.map +1 -1
- package/dist/domain/identityaccount/operator.js +2 -4
- package/dist/domain/identityaccount/operator.js.map +1 -1
- package/dist/domain/identityaccount/provisioning.d.ts +20 -1
- package/dist/domain/identityaccount/provisioning.d.ts.map +1 -1
- package/dist/domain/identityaccount/provisioning.js +17 -3
- package/dist/domain/identityaccount/provisioning.js.map +1 -1
- package/dist/domain/identityaccount/resolve.d.ts +23 -0
- package/dist/domain/identityaccount/resolve.d.ts.map +1 -1
- package/dist/domain/identityaccount/resolve.js +17 -0
- package/dist/domain/identityaccount/resolve.js.map +1 -1
- package/dist/domain/identityaccount/store-contract.d.ts +4 -18
- package/dist/domain/identityaccount/store-contract.d.ts.map +1 -1
- package/dist/domain/identityaccount/store-contract.js +12 -47
- package/dist/domain/identityaccount/store-contract.js.map +1 -1
- package/dist/extensions/authorization-queries.d.ts +81 -0
- package/dist/extensions/authorization-queries.d.ts.map +1 -0
- package/dist/extensions/authorization-queries.js +2 -0
- package/dist/extensions/authorization-queries.js.map +1 -0
- package/dist/extensions/drivers.d.ts +49 -2
- package/dist/extensions/drivers.d.ts.map +1 -1
- package/dist/extensions/identity.d.ts +14 -0
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js +18 -1
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/policy-grant-scope.d.ts +50 -0
- package/dist/extensions/policy-grant-scope.d.ts.map +1 -0
- package/dist/extensions/policy-grant-scope.js +2 -0
- package/dist/extensions/policy-grant-scope.js.map +1 -0
- package/dist/extensions/registry.d.ts +23 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/extensions/registry.js +30 -0
- package/dist/extensions/registry.js.map +1 -1
- package/dist/extensions/resource-authorization.d.ts +63 -0
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/apiresource-meta.d.ts +56 -1
- package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
- package/dist/pipeline/apiresource-meta.js +155 -1
- package/dist/pipeline/apiresource-meta.js.map +1 -1
- package/dist/pipeline/interceptors/auth.d.ts +12 -0
- package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
- package/dist/pipeline/interceptors/auth.js +13 -1
- package/dist/pipeline/interceptors/auth.js.map +1 -1
- package/dist/pipeline/steps/authorize.d.ts +20 -5
- package/dist/pipeline/steps/authorize.d.ts.map +1 -1
- package/dist/pipeline/steps/authorize.js +37 -17
- package/dist/pipeline/steps/authorize.js.map +1 -1
- package/dist/pipeline/steps/defaults.d.ts +10 -0
- package/dist/pipeline/steps/defaults.d.ts.map +1 -1
- package/dist/pipeline/steps/defaults.js +39 -0
- package/dist/pipeline/steps/defaults.js.map +1 -1
- package/dist/store/port-contract.d.ts +61 -0
- package/dist/store/port-contract.d.ts.map +1 -0
- package/dist/store/port-contract.js +67 -0
- package/dist/store/port-contract.js.map +1 -0
- package/package.json +4 -4
- package/src/boot/compose.ts +107 -10
- package/src/domain/iampolicy/__tests__/access-lists.test.ts +238 -0
- package/src/domain/iampolicy/__tests__/constants.test.ts +388 -0
- package/src/domain/iampolicy/__tests__/controller.test.ts +960 -0
- package/src/domain/iampolicy/__tests__/display-resolver.test.ts +138 -0
- package/src/domain/iampolicy/__tests__/grant-path.test.ts +474 -0
- package/src/domain/iampolicy/__tests__/grant-scope.test.ts +61 -0
- package/src/domain/iampolicy/__tests__/iampolicy.test.ts +532 -0
- package/src/domain/iampolicy/__tests__/membership.test.ts +447 -0
- package/src/domain/iampolicy/__tests__/permissions.test.ts +41 -0
- package/src/domain/iampolicy/__tests__/resource-store.test.ts +165 -0
- package/src/domain/iampolicy/__tests__/role-lifecycle.test.ts +361 -0
- package/src/domain/iampolicy/__tests__/roles.test.ts +53 -0
- package/src/domain/iampolicy/__tests__/specs.test.ts +41 -0
- package/src/domain/iampolicy/__tests__/steps.test.ts +278 -0
- package/src/domain/iampolicy/__tests__/support.ts +195 -0
- package/src/domain/iampolicy/__tests__/wire-refusals.test.ts +117 -0
- package/src/domain/iampolicy/access-lists.ts +191 -0
- package/src/domain/iampolicy/constants.ts +243 -0
- package/src/domain/iampolicy/controller.ts +798 -0
- package/src/domain/iampolicy/display-resolver.ts +123 -0
- package/src/domain/iampolicy/grant-path.ts +270 -0
- package/src/domain/iampolicy/grant-scope.ts +36 -0
- package/src/domain/iampolicy/membership.ts +298 -0
- package/src/domain/iampolicy/permissions.ts +35 -0
- package/src/domain/iampolicy/resource-store.ts +186 -0
- package/src/domain/iampolicy/role-lifecycle.ts +132 -0
- package/src/domain/iampolicy/roles.ts +95 -0
- package/src/domain/iampolicy/specs.ts +53 -0
- package/src/domain/iampolicy/steps.ts +178 -0
- package/src/domain/iampolicy/store-contract.ts +450 -0
- package/src/domain/iampolicy/store.ts +103 -0
- package/src/domain/iampolicy/wire-refusals.ts +110 -0
- package/src/domain/identityaccount/__tests__/provisioning.test.ts +19 -7
- package/src/domain/identityaccount/__tests__/resolve.test.ts +113 -2
- package/src/domain/identityaccount/constants.ts +16 -31
- package/src/domain/identityaccount/controller.ts +65 -35
- package/src/domain/identityaccount/operator.ts +5 -5
- package/src/domain/identityaccount/provisioning.ts +43 -5
- package/src/domain/identityaccount/resolve.ts +43 -0
- package/src/domain/identityaccount/store-contract.ts +22 -70
- package/src/extensions/__tests__/composed-support.ts +87 -0
- package/src/extensions/__tests__/iam-policy-composed.test.ts +373 -0
- package/src/extensions/__tests__/iam-policy-points.test.ts +169 -0
- package/src/extensions/__tests__/identity-account-composed.test.ts +12 -78
- package/src/extensions/__tests__/identity.test.ts +62 -0
- package/src/extensions/__tests__/tier-truthfulness.test.ts +8 -0
- package/src/extensions/authorization-queries.ts +97 -0
- package/src/extensions/drivers.ts +49 -2
- package/src/extensions/identity.ts +21 -0
- package/src/extensions/policy-grant-scope.ts +50 -0
- package/src/extensions/registry.ts +62 -1
- package/src/extensions/resource-authorization.ts +65 -0
- package/src/index.ts +20 -0
- package/src/pipeline/__tests__/grantable-roles-for.test.ts +87 -0
- package/src/pipeline/__tests__/kind-by-enum-name.test.ts +107 -0
- package/src/pipeline/__tests__/kind-served-by-edition.test.ts +107 -0
- package/src/pipeline/apiresource-meta.ts +181 -1
- package/src/pipeline/interceptors/auth.ts +14 -1
- package/src/pipeline/steps/__tests__/authorize-annotation-completeness.test.ts +73 -3
- package/src/pipeline/steps/__tests__/authorize.test.ts +134 -9
- package/src/pipeline/steps/__tests__/derived-id.test.ts +49 -0
- package/src/pipeline/steps/authorize.ts +46 -21
- package/src/pipeline/steps/defaults.ts +42 -0
- package/src/store/__tests__/port-contract.test.ts +123 -0
- package/src/store/port-contract.ts +102 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE grant and revoke path of the IamPolicy domain (20260913.01,
|
|
3
|
+
* T01_0_plan.md §3a; T01_1_review.md Q-OR-1), moved from the cloud's
|
|
4
|
+
* iam/policy/service.ts into open source so every edition writes and
|
|
5
|
+
* deletes a policy row the same way. Its callers: the IamPolicy command
|
|
6
|
+
* controller (user grants and the three system RPCs), the built-in role
|
|
7
|
+
* lifecycle (the organization creator's `owner` row; cleanup on delete)
|
|
8
|
+
* and the membership rules (first-sign-in roles). Nothing else builds,
|
|
9
|
+
* saves or deletes a policy row; a composition reaches this path as
|
|
10
|
+
* in-process RPCs, never through an exported constructor.
|
|
11
|
+
*
|
|
12
|
+
* The two cloud#425 ordering invariants live here, nowhere else:
|
|
13
|
+
* CREATE: row before tuple — a crash between the two leaves
|
|
14
|
+
* row-without-tuple (granted on paper, denied in practice), healed by
|
|
15
|
+
* the caller's natural retry (the tuple write deliberately runs on
|
|
16
|
+
* duplicates too — the inline heal) or the boot backfill.
|
|
17
|
+
* DELETE: tuple before row — a crash leaves row+tuple (revoke failed,
|
|
18
|
+
* retry works); the reverse order was the fail-open incident class
|
|
19
|
+
* ("revoke access" silently becoming "keep access forever").
|
|
20
|
+
* "Tuple" here is whatever the composed ResourceAuthorizationLifecycle does
|
|
21
|
+
* in `onPolicyGranted` and `onPolicyRevoked`; with none composed, or one
|
|
22
|
+
* without the two optional hooks, the path writes rows and notifies
|
|
23
|
+
* nothing (the OSS posture: rows are the record).
|
|
24
|
+
*
|
|
25
|
+
* The row for a triple is found BY TRIPLE, never by derived id. Open
|
|
26
|
+
* source's rows carry the derived id (constants.ts policyIdFor), so the
|
|
27
|
+
* two lookups would agree here; the cloud's Java-era rows carry random
|
|
28
|
+
* `iamp_<ulid>` ids and must revoke and deduplicate through this same
|
|
29
|
+
* code, so `findByTriple` (the pair's rows filtered by relation) is the
|
|
30
|
+
* one definition of "the row for this triple" and `findById` serves the
|
|
31
|
+
* `get` RPC alone. On the OSS adapter that read is one scan of the kind
|
|
32
|
+
* (resource-store.ts); §4 measures it.
|
|
33
|
+
*
|
|
34
|
+
* The path is the one writer, so it refuses before it writes (Q-S2-1;
|
|
35
|
+
* slice 1 ruling 2): before any read, write or hook, `grant` and
|
|
36
|
+
* `revokeBySpec` run the domain's wire refusals (wire-refusals.ts — a spec
|
|
37
|
+
* whose resource or principal kind is not an ApiResourceKind member name,
|
|
38
|
+
* or whose fields hold a canonical-text delimiter, is INVALID_ARGUMENT
|
|
39
|
+
* with the pinned copy; slice 5 made that module the one home of the rule
|
|
40
|
+
* the controller and the ValidateGrantableRole step share). The
|
|
41
|
+
* controller refuses the same kinds BEFORE position 1 (Q-S6-1), so a wire
|
|
42
|
+
* caller never reaches this check; it stands for the callers that enter
|
|
43
|
+
* here without the controller — the built-in lifecycle and the membership
|
|
44
|
+
* rules — and is what keeps a garbage row out of the store and a garbage
|
|
45
|
+
* spec away from a composition's tuple delete from every door.
|
|
46
|
+
* `cleanupResource` and `revokeOrgAccess` take refs and ids their callers
|
|
47
|
+
* read from rows, so they do not refuse.
|
|
48
|
+
*
|
|
49
|
+
* The row this path builds: the proto's apiVersion const and kind, the
|
|
50
|
+
* derived id, the spec as given, and the caller's audit stamp through the
|
|
51
|
+
* platform's one stamper (setAuditFieldsForCreate) — the cloud's
|
|
52
|
+
* `buildNewPolicy` stamped neither org nor creator; this path stamps the
|
|
53
|
+
* creator and, like the cloud, no `metadata.org`, because a policy may
|
|
54
|
+
* span organizations and none owns it.
|
|
55
|
+
*/
|
|
56
|
+
import { create } from "@bufbuild/protobuf";
|
|
57
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
58
|
+
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
59
|
+
import { IamPolicySchema } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/api_pb";
|
|
60
|
+
import { kindEnumName } from "../../pipeline/apiresource-meta.js";
|
|
61
|
+
import { setAuditFieldsForCreate } from "../../pipeline/steps/defaults.js";
|
|
62
|
+
import { IAM_POLICY_API_VERSION, IAM_POLICY_KIND, policyIdFor, } from "./constants.js";
|
|
63
|
+
import { DuplicatePolicyError } from "./store.js";
|
|
64
|
+
import { refsOf, requireWellFormedTriple } from "./wire-refusals.js";
|
|
65
|
+
export function newIamPolicyGrantPath(deps) {
|
|
66
|
+
const { policies, lifecycle, logger } = deps;
|
|
67
|
+
/** The row holding this exact triple — the pair's rows, filtered by relation. */
|
|
68
|
+
async function findByTriple(spec) {
|
|
69
|
+
const { principal, resource } = refsOf(spec);
|
|
70
|
+
const onPair = await policies.findByPrincipalAndResource(principal.kind, principal.id, resource.kind, resource.id);
|
|
71
|
+
return onPair.find((policy) => policy.spec !== undefined &&
|
|
72
|
+
policy.spec.relation === spec.relation &&
|
|
73
|
+
policy.spec.principal?.relation === principal.relation);
|
|
74
|
+
}
|
|
75
|
+
/** The revoke order for one row: the hook, then the delete. */
|
|
76
|
+
async function revokeRow(policy) {
|
|
77
|
+
const spec = policy.spec;
|
|
78
|
+
if (spec === undefined) {
|
|
79
|
+
throw new Error(`policy ${policy.metadata?.id ?? "?"} has no spec — corrupt row`);
|
|
80
|
+
}
|
|
81
|
+
await lifecycle?.onPolicyRevoked?.({ spec, policy });
|
|
82
|
+
const id = policy.metadata?.id ?? "";
|
|
83
|
+
await policies.deleteById(id);
|
|
84
|
+
logger.info("iam policy revoked", fieldsOf(id, spec));
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
async grant(spec, caller) {
|
|
88
|
+
requireWellFormedTriple(spec);
|
|
89
|
+
let policy = await findByTriple(spec);
|
|
90
|
+
let duplicate = policy !== undefined;
|
|
91
|
+
if (policy === undefined) {
|
|
92
|
+
const fresh = buildRow(spec, caller);
|
|
93
|
+
try {
|
|
94
|
+
await policies.save(fresh);
|
|
95
|
+
policy = fresh;
|
|
96
|
+
logger.info("iam policy granted", fieldsOf(policyIdFor(spec), spec));
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (!(error instanceof DuplicatePolicyError)) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
// Lost the race to another writer of the same triple: the
|
|
103
|
+
// winner's row is the grant, exactly as if it had been found
|
|
104
|
+
// above. A winner that cannot be read back means the refusal
|
|
105
|
+
// was not a race — propagate it.
|
|
106
|
+
const winner = await findByTriple(spec);
|
|
107
|
+
if (winner === undefined) {
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
policy = winner;
|
|
111
|
+
duplicate = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (duplicate) {
|
|
115
|
+
logger.debug("iam policy already held", fieldsOf(policy.metadata?.id ?? "", spec));
|
|
116
|
+
}
|
|
117
|
+
// Deliberately unconditional (cloud#425): a duplicate re-grant is the
|
|
118
|
+
// inline heal for a row whose tuple never landed.
|
|
119
|
+
await lifecycle?.onPolicyGranted?.({ policy, duplicate });
|
|
120
|
+
return { policy, duplicate };
|
|
121
|
+
},
|
|
122
|
+
async revokeBySpec(spec) {
|
|
123
|
+
requireWellFormedTriple(spec);
|
|
124
|
+
const existing = await findByTriple(spec);
|
|
125
|
+
if (existing === undefined) {
|
|
126
|
+
// No row: a composition still deletes the bare tuple (one written
|
|
127
|
+
// before the row mirror existed); converges the store either way.
|
|
128
|
+
await lifecycle?.onPolicyRevoked?.({ spec, policy: undefined });
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
await revokeRow(existing);
|
|
132
|
+
return existing;
|
|
133
|
+
},
|
|
134
|
+
async cleanupResource(ref) {
|
|
135
|
+
const asResource = await policies.findByResource(ref.kind, ref.id);
|
|
136
|
+
const asPrincipal = await policies.findByPrincipal(ref.kind, ref.id);
|
|
137
|
+
for (const policy of distinctById([...asResource, ...asPrincipal])) {
|
|
138
|
+
await revokeRow(policy);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
async revokeOrgAccess(identityAccountId, organizationId) {
|
|
142
|
+
const direct = await policies.findByPrincipalAndResource(kindEnumName(ApiResourceKind.identity_account), identityAccountId, kindEnumName(ApiResourceKind.organization), organizationId);
|
|
143
|
+
for (const policy of direct) {
|
|
144
|
+
await revokeRow(policy);
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/** The row for a fresh grant: the contract's identity strings, the derived id, the caller's stamp. */
|
|
150
|
+
function buildRow(spec, caller) {
|
|
151
|
+
const policy = create(IamPolicySchema, {
|
|
152
|
+
apiVersion: IAM_POLICY_API_VERSION,
|
|
153
|
+
kind: IAM_POLICY_KIND,
|
|
154
|
+
metadata: create(ApiResourceMetadataSchema, { id: policyIdFor(spec) }),
|
|
155
|
+
spec,
|
|
156
|
+
});
|
|
157
|
+
setAuditFieldsForCreate(IamPolicySchema, policy, caller);
|
|
158
|
+
return policy;
|
|
159
|
+
}
|
|
160
|
+
/** One row per id, at its first position. */
|
|
161
|
+
function distinctById(policies) {
|
|
162
|
+
const seen = new Set();
|
|
163
|
+
return policies.filter((policy) => {
|
|
164
|
+
const id = policy.metadata?.id ?? "";
|
|
165
|
+
if (seen.has(id)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
seen.add(id);
|
|
169
|
+
return true;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/** The structured fields every log line carries — ids and kinds, never a token. */
|
|
173
|
+
function fieldsOf(id, spec) {
|
|
174
|
+
return {
|
|
175
|
+
policyId: id,
|
|
176
|
+
relation: spec.relation,
|
|
177
|
+
principalKind: spec.principal?.kind ?? "",
|
|
178
|
+
principalId: spec.principal?.id ?? "",
|
|
179
|
+
resourceKind: spec.resource?.kind ?? "",
|
|
180
|
+
resourceId: spec.resource?.id ?? "",
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=grant-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-path.js","sourceRoot":"","sources":["../../../src/domain/iampolicy/grant-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PolicyGrantScope } from "../../extensions/policy-grant-scope.js";
|
|
2
|
+
/** The open-source default: organization → its proto roles; every other kind → none. */
|
|
3
|
+
export declare function newOrganizationOnlyGrantScope(): PolicyGrantScope;
|
|
4
|
+
//# sourceMappingURL=grant-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-scope.d.ts","sourceRoot":"","sources":["../../../src/domain/iampolicy/grant-scope.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wCAAwC,CAAC;AAG/E,wFAAwF;AACxF,wBAAgB,6BAA6B,IAAI,gBAAgB,CAQhE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Open source's PolicyGrantScope (20260913.01, T01_1_review.md Q-OR-3 and
|
|
3
|
+
* Q-OR-4): the ORGANIZATION grants the roles its `kind_meta` lists —
|
|
4
|
+
* owner, admin, member, viewer — and no other kind grants anything. This
|
|
5
|
+
* is what lights the console's Members page in every edition while a
|
|
6
|
+
* viewer on one agent, the per-resource grant, stays what the Enterprise
|
|
7
|
+
* and Cloud editions add by composing a wider scope
|
|
8
|
+
* (extensions/policy-grant-scope.ts carries the contract every scope is
|
|
9
|
+
* held to: narrows the proto, total over the enum, synchronous).
|
|
10
|
+
*
|
|
11
|
+
* Installed by the composition root when no unit registers
|
|
12
|
+
* `drivers.policyGrantScope` — the `newPermissiveSingleTeamAuthorizer`
|
|
13
|
+
* shape: the default lives with the domain that defines its semantics and
|
|
14
|
+
* is called at the `??` site, never held by the registry.
|
|
15
|
+
*
|
|
16
|
+
* The organization's roles are READ from the proto through
|
|
17
|
+
* `grantableRolesFor`, not written here: the four words the Members page
|
|
18
|
+
* shows and entry 3's authorizer enforces have one source, and a proto
|
|
19
|
+
* change is the only way to change them (grant-scope.test.ts pins the
|
|
20
|
+
* equality; grantable-roles-for.test.ts pins the four).
|
|
21
|
+
*/
|
|
22
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
23
|
+
import { grantableRolesFor } from "../../pipeline/apiresource-meta.js";
|
|
24
|
+
/** The open-source default: organization → its proto roles; every other kind → none. */
|
|
25
|
+
export function newOrganizationOnlyGrantScope() {
|
|
26
|
+
return {
|
|
27
|
+
grantableRoles(kind) {
|
|
28
|
+
return kind === ApiResourceKind.organization
|
|
29
|
+
? grantableRolesFor(kind)
|
|
30
|
+
: [];
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=grant-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-scope.js","sourceRoot":"","sources":["../../../src/domain/iampolicy/grant-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,qFAAqF,CAAC;AAGtH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAEvE,wFAAwF;AACxF,MAAM,UAAU,6BAA6B;IAC3C,OAAO;QACL,cAAc,CAAC,IAAI;YACjB,OAAO,IAAI,KAAK,eAAe,CAAC,YAAY;gBAC1C,CAAC,CAAC,iBAAiB,CAAC,IAAI,CAAC;gBACzB,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The open-source membership rules (20260913.01, T01_0_plan.md §3a;
|
|
3
|
+
* T01_1_review.md Q-OR-6b, Q-OR-6c; slice 4 rulings Q-S4-2 to Q-S4-7):
|
|
4
|
+
* how organization roles come to exist on a self-host that has no
|
|
5
|
+
* administrator to grant them. Core code, installed only under the
|
|
6
|
+
* built-in authorization posture (boot/compose.ts `builtInAuthorization`:
|
|
7
|
+
* no unit registered an Authorizer); a composition with its own
|
|
8
|
+
* Authorizer has its own onboarding and never constructs this.
|
|
9
|
+
*
|
|
10
|
+
* Two moments:
|
|
11
|
+
*
|
|
12
|
+
* onAccountCreated(account, caller) — a person's FIRST provisioning, and
|
|
13
|
+
* only that (the identity-account domain's AccountCreatedHook, run by
|
|
14
|
+
* provisionMyAccount on the call whose `created` is true). For every
|
|
15
|
+
* organization the account holds no row on, in this order:
|
|
16
|
+
* 1. `owner` — the organization's creator stamp is this account (its
|
|
17
|
+
* subject or its id): the founder, who founded it
|
|
18
|
+
* idp-shaped before any row existed;
|
|
19
|
+
* 2. `admin` — this account created a blueprint in it (BLUEPRINT_KINDS,
|
|
20
|
+
* constants.ts: the kinds an admin authors; sessions and
|
|
21
|
+
* executions are personal and confer nothing, DD-002
|
|
22
|
+
* rule 2);
|
|
23
|
+
* 3. `admin` — the account's email is the configured operator email
|
|
24
|
+
* (an empty configuration matches nobody);
|
|
25
|
+
* 4. `admin` — the organization has ZERO role rows and no PERSON other
|
|
26
|
+
* than this account created it or any blueprint in it:
|
|
27
|
+
* the fresh install's first caller, and the
|
|
28
|
+
* trusted-local-turned-OIDC laptop whose stamps are all
|
|
29
|
+
* "system". "Zero rows", never "no admin now" — revoking
|
|
30
|
+
* every admin of a bootstrapped organization must not
|
|
31
|
+
* hand it to the next stranger (plan finding 2); and the
|
|
32
|
+
* founder's own stamp counts as a person (Q-S4-7), so a
|
|
33
|
+
* revoked founder's empty organization is not handed
|
|
34
|
+
* over either;
|
|
35
|
+
* 5. `member` — everyone else.
|
|
36
|
+
* Arms 3 and 4 both answer `admin`; 3 is checked first because it is a
|
|
37
|
+
* string compare and 4 reads the organization's rows. `user`-class
|
|
38
|
+
* callers only (Q-OR-6b): a runner, a machine or the in-process class
|
|
39
|
+
* never earns a role. Nothing on an organization the account already
|
|
40
|
+
* holds a row on, so a run that faulted midway converges on the next.
|
|
41
|
+
*
|
|
42
|
+
* ensureOperatorOwnership(operator) — the trusted-local boot ensure
|
|
43
|
+
* (Q-OR-6c): the laptop's operator becomes `owner` of every organization
|
|
44
|
+
* that has NO owner row. "No owner row", not "no row of this operator"
|
|
45
|
+
* (Q-S4-3): a boot-time write never overrides a human grant recorded
|
|
46
|
+
* under an earlier OIDC life of the same database, and the permissive
|
|
47
|
+
* Authorizer admits the operator regardless. A second boot writes
|
|
48
|
+
* nothing. The row is granted AS the operator — the trusted-local
|
|
49
|
+
* identity shape (empty issuer and token) carrying the account's id,
|
|
50
|
+
* email and name — so its audit actor reads like every other write on
|
|
51
|
+
* that laptop.
|
|
52
|
+
*
|
|
53
|
+
* What a creator stamp is. The rules read `status.audit.spec_audit
|
|
54
|
+
* .created_by.id` off organizations and blueprints. That stamp is the
|
|
55
|
+
* caller's identityId at the time: a provisioned caller's ACCOUNT id, an
|
|
56
|
+
* unprovisioned caller's raw issuer SUBJECT, and — under the trusted-local
|
|
57
|
+
* posture — the operator's EMAIL or the "system" placeholder
|
|
58
|
+
* (pipeline/interceptors/auth.ts trustedLocalIdentityFor). So "mine" is
|
|
59
|
+
* "equals my subject or my id" (an email stamp is nobody's by this rule;
|
|
60
|
+
* the operator is covered by arm 3 and by ensureOperatorOwnership), and a
|
|
61
|
+
* stamp is a PERSON when it is non-empty and not the "system" placeholder
|
|
62
|
+
* (SYSTEM_OPERATOR_IDENTITY_ID, the one home of that word — Q-S4-6). The
|
|
63
|
+
* rules classify stamps by shape and consult no account store (Q-S4-5).
|
|
64
|
+
*
|
|
65
|
+
* Reads. Policy rows through the IamPolicyStore PORT (`policies`, the
|
|
66
|
+
* same instance the grant path writes through) — never around it
|
|
67
|
+
* (Q-S4-5). Organizations and blueprints through the generic Store,
|
|
68
|
+
* decoded with each kind's own schema (CREATOR_SCAN_SCHEMAS; Q-S4-2: the
|
|
69
|
+
* envelope shares its field numbers but each status carries its audit
|
|
70
|
+
* under its own, so no generic decode exists). Cost, measured in the
|
|
71
|
+
* entry's execution record: one scan of each of seven kinds and one row
|
|
72
|
+
* read per organization, once per account creation.
|
|
73
|
+
*
|
|
74
|
+
* The window this design accepts (Q-S4-4). A store fault after the
|
|
75
|
+
* account row persisted fails the request INTERNAL (the controller's
|
|
76
|
+
* mapping) with the account in place; later calls answer `created:
|
|
77
|
+
* false`, so the rules never run again for that person. The writes ride
|
|
78
|
+
* the idempotent grant path, so a partial run leaves only correct rows,
|
|
79
|
+
* and the recovery is an administrator's grant — or, on a fresh install,
|
|
80
|
+
* arm 3 at the operator's own sign-in. An account created through the
|
|
81
|
+
* `create` RPC (the platform's own pipelines, cloud#393) never reaches
|
|
82
|
+
* this hook either: the rules are about a person signing in.
|
|
83
|
+
*/
|
|
84
|
+
import type { DescMessage } from "@bufbuild/protobuf";
|
|
85
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
86
|
+
import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
|
|
87
|
+
import type { Store } from "../../store/interface.js";
|
|
88
|
+
import type { AccountCreatedHook } from "../identityaccount/provisioning.js";
|
|
89
|
+
import type { IamPolicyGrantPath } from "./grant-path.js";
|
|
90
|
+
import type { IamPolicyStore } from "./store.js";
|
|
91
|
+
export interface MembershipRulesDeps {
|
|
92
|
+
readonly grantPath: IamPolicyGrantPath;
|
|
93
|
+
/** The port the grant path writes through — read here for "holds a row", "zero rows", "has an owner". */
|
|
94
|
+
readonly policies: IamPolicyStore;
|
|
95
|
+
readonly store: Store;
|
|
96
|
+
/** STIGMER_OPERATOR_EMAIL as the operator seam holds it; "" when unconfigured. */
|
|
97
|
+
readonly operatorEmail: string;
|
|
98
|
+
}
|
|
99
|
+
export interface MembershipRules extends AccountCreatedHook {
|
|
100
|
+
/** The trusted-local boot ensure: `owner` wherever no owner row exists. */
|
|
101
|
+
ensureOperatorOwnership(operator: IdentityAccount): Promise<void>;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The schemas the creator scan decodes with: the organization and every
|
|
105
|
+
* BLUEPRINT_KINDS member. Pinned equal to that set by the domain's tests,
|
|
106
|
+
* so a kind added to the constant without a schema fails loudly instead
|
|
107
|
+
* of being skipped.
|
|
108
|
+
*/
|
|
109
|
+
export declare const CREATOR_SCAN_SCHEMAS: ReadonlyMap<ApiResourceKind, DescMessage>;
|
|
110
|
+
export declare function newMembershipRules(deps: MembershipRulesDeps): MembershipRules;
|
|
111
|
+
//# sourceMappingURL=membership.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"membership.d.ts","sourceRoot":"","sources":["../../../src/domain/iampolicy/membership.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkFG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAStD,OAAO,EAAE,eAAe,EAAE,MAAM,qFAAqF,CAAC;AACtH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0DAA0D,CAAC;AAShG,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,kBAAkB,CAAC;IACvC,yGAAyG;IACzG,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,kFAAkF;IAClF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eAAgB,SAAQ,kBAAkB;IACzD,2EAA2E;IAC3E,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnE;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,WAAW,CAAC,eAAe,EAAE,WAAW,CASvE,CAAC;AAiBL,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe,CAuH7E"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { fromBinary } from "@bufbuild/protobuf";
|
|
2
|
+
import { AgentSchema } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/api_pb";
|
|
3
|
+
import { EnvironmentSchema } from "@stigmer/protos/ai/stigmer/agentic/environment/v1/api_pb";
|
|
4
|
+
import { McpServerSchema } from "@stigmer/protos/ai/stigmer/agentic/mcpserver/v1/api_pb";
|
|
5
|
+
import { ScheduleSchema } from "@stigmer/protos/ai/stigmer/agentic/schedule/v1/api_pb";
|
|
6
|
+
import { SkillSchema } from "@stigmer/protos/ai/stigmer/agentic/skill/v1/api_pb";
|
|
7
|
+
import { WorkflowSchema } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/api_pb";
|
|
8
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
9
|
+
import { IamRole } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
10
|
+
import { OrganizationSchema } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
|
|
11
|
+
import { kindEnumName } from "../../pipeline/apiresource-meta.js";
|
|
12
|
+
import { SYSTEM_OPERATOR_IDENTITY_ID } from "../../pipeline/interceptors/auth.js";
|
|
13
|
+
import { auditOf } from "../../pipeline/steps/defaults.js";
|
|
14
|
+
import { metadataOf } from "../../pipeline/steps/shapes.js";
|
|
15
|
+
import { BLUEPRINT_KINDS } from "./constants.js";
|
|
16
|
+
import { organizationRole, relationOf } from "./specs.js";
|
|
17
|
+
/**
|
|
18
|
+
* The schemas the creator scan decodes with: the organization and every
|
|
19
|
+
* BLUEPRINT_KINDS member. Pinned equal to that set by the domain's tests,
|
|
20
|
+
* so a kind added to the constant without a schema fails loudly instead
|
|
21
|
+
* of being skipped.
|
|
22
|
+
*/
|
|
23
|
+
export const CREATOR_SCAN_SCHEMAS = new Map([
|
|
24
|
+
[ApiResourceKind.organization, OrganizationSchema],
|
|
25
|
+
[ApiResourceKind.agent, AgentSchema],
|
|
26
|
+
[ApiResourceKind.workflow, WorkflowSchema],
|
|
27
|
+
[ApiResourceKind.skill, SkillSchema],
|
|
28
|
+
[ApiResourceKind.mcp_server, McpServerSchema],
|
|
29
|
+
[ApiResourceKind.environment, EnvironmentSchema],
|
|
30
|
+
[ApiResourceKind.schedule, ScheduleSchema],
|
|
31
|
+
]);
|
|
32
|
+
const ORGANIZATION = kindEnumName(ApiResourceKind.organization);
|
|
33
|
+
const IDENTITY_ACCOUNT = kindEnumName(ApiResourceKind.identity_account);
|
|
34
|
+
/** A creator stamp that names a person: non-empty and not the unconfigured laptop's placeholder. */
|
|
35
|
+
function isPersonStamp(stamp) {
|
|
36
|
+
return stamp !== "" && stamp !== SYSTEM_OPERATOR_IDENTITY_ID;
|
|
37
|
+
}
|
|
38
|
+
export function newMembershipRules(deps) {
|
|
39
|
+
const { grantPath, policies, store, operatorEmail } = deps;
|
|
40
|
+
async function scan(kind) {
|
|
41
|
+
const schema = CREATOR_SCAN_SCHEMAS.get(kind);
|
|
42
|
+
if (schema === undefined) {
|
|
43
|
+
throw new Error(`no schema to decode ${kindEnumName(kind)} rows for the creator scan`);
|
|
44
|
+
}
|
|
45
|
+
const rows = await store.listResources(kind);
|
|
46
|
+
return rows.map((bytes) => {
|
|
47
|
+
const resource = fromBinary(schema, bytes);
|
|
48
|
+
const metadata = metadataOf(resource);
|
|
49
|
+
return {
|
|
50
|
+
id: metadata?.id ?? "",
|
|
51
|
+
org: metadata?.org ?? "",
|
|
52
|
+
createdBy: auditOf(schema, resource)?.specAudit?.createdBy?.id ?? "",
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async function scanBlueprints() {
|
|
57
|
+
const scanned = [];
|
|
58
|
+
for (const kind of BLUEPRINT_KINDS) {
|
|
59
|
+
scanned.push(...(await scan(kind)));
|
|
60
|
+
}
|
|
61
|
+
return scanned;
|
|
62
|
+
}
|
|
63
|
+
/** The organizations `accountId` already holds any row on — the idempotency set. */
|
|
64
|
+
async function organizationsHeldBy(accountId) {
|
|
65
|
+
const rows = await policies.findByPrincipal(IDENTITY_ACCOUNT, accountId);
|
|
66
|
+
return new Set(rows
|
|
67
|
+
.filter((row) => row.spec?.resource?.kind === ORGANIZATION)
|
|
68
|
+
.map((row) => row.spec?.resource?.id ?? ""));
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
async onAccountCreated(account, caller) {
|
|
72
|
+
if (caller.callerClass !== "user") {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const accountId = account.metadata?.id ?? "";
|
|
76
|
+
if (accountId === "") {
|
|
77
|
+
throw new Error("membership rules: the provisioned account carries no id");
|
|
78
|
+
}
|
|
79
|
+
const organizations = await scan(ApiResourceKind.organization);
|
|
80
|
+
if (organizations.length === 0) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const subject = account.spec?.idpId ?? "";
|
|
84
|
+
const email = account.spec?.email ?? "";
|
|
85
|
+
const isMine = (stamp) => stamp !== "" && (stamp === subject || stamp === accountId);
|
|
86
|
+
const held = await organizationsHeldBy(accountId);
|
|
87
|
+
const blueprints = await scanBlueprints();
|
|
88
|
+
for (const organization of organizations) {
|
|
89
|
+
if (held.has(organization.id)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const inOrganization = blueprints.filter((blueprint) => blueprint.org === organization.id);
|
|
93
|
+
let role;
|
|
94
|
+
if (isMine(organization.createdBy)) {
|
|
95
|
+
role = IamRole.owner;
|
|
96
|
+
}
|
|
97
|
+
else if (inOrganization.some((b) => isMine(b.createdBy))) {
|
|
98
|
+
role = IamRole.admin;
|
|
99
|
+
}
|
|
100
|
+
else if (operatorEmail !== "" && email === operatorEmail) {
|
|
101
|
+
role = IamRole.admin;
|
|
102
|
+
}
|
|
103
|
+
else if (![
|
|
104
|
+
organization.createdBy,
|
|
105
|
+
...inOrganization.map((b) => b.createdBy),
|
|
106
|
+
].some((stamp) => isPersonStamp(stamp) && !isMine(stamp)) &&
|
|
107
|
+
(await policies.findByResource(ORGANIZATION, organization.id))
|
|
108
|
+
.length === 0) {
|
|
109
|
+
role = IamRole.admin;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
role = IamRole.member;
|
|
113
|
+
}
|
|
114
|
+
await grantPath.grant(organizationRole(accountId, role, organization.id), caller);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
async ensureOperatorOwnership(operator) {
|
|
118
|
+
const accountId = operator.metadata?.id ?? "";
|
|
119
|
+
if (accountId === "") {
|
|
120
|
+
throw new Error("membership rules: the operator account carries no id");
|
|
121
|
+
}
|
|
122
|
+
const actor = operatorActor(operator, accountId);
|
|
123
|
+
for (const organization of await scan(ApiResourceKind.organization)) {
|
|
124
|
+
const owners = await policies.findByResourceWithRelations(ORGANIZATION, organization.id, [relationOf(IamRole.owner)]);
|
|
125
|
+
if (owners.length > 0) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
await grantPath.grant(organizationRole(accountId, IamRole.owner, organization.id), actor);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The operator acting as its account: the trusted-local identity shape
|
|
135
|
+
* (pipeline/interceptors/auth.ts trustedLocalIdentityFor — no issuer, no
|
|
136
|
+
* token; email and display name only when known) with the account id as
|
|
137
|
+
* the principal, so the row's audit actor is the account, named the way
|
|
138
|
+
* every other trusted-local write names it.
|
|
139
|
+
*/
|
|
140
|
+
function operatorActor(operator, accountId) {
|
|
141
|
+
const email = operator.spec?.email ?? "";
|
|
142
|
+
const displayName = operator.metadata?.name ?? "";
|
|
143
|
+
return {
|
|
144
|
+
identityId: accountId,
|
|
145
|
+
callerClass: "user",
|
|
146
|
+
issuer: "",
|
|
147
|
+
rawToken: "",
|
|
148
|
+
...(email !== "" ? { email } : {}),
|
|
149
|
+
...(displayName !== "" ? { displayName } : {}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=membership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"membership.js","sourceRoot":"","sources":["../../../src/domain/iampolicy/membership.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The permission vocabulary as the wire spells it (20260913.01 slice 5,
|
|
3
|
+
* Q-S5-3): `checkMyPermission` carries its `relation` as a string — the
|
|
4
|
+
* FGA relation name, which is the `IamPermission` member name — while the
|
|
5
|
+
* composed Authorizer's `AuthzCheck` carries the enum. This is the one
|
|
6
|
+
* read from the first spelling to the second. A relation that names no
|
|
7
|
+
* permission is the caller's mistake (INVALID_ARGUMENT in the controller),
|
|
8
|
+
* never a permission nobody holds: the console asks with the ten strings
|
|
9
|
+
* `IamPermission` lists (claim check C4) and a typo should be heard.
|
|
10
|
+
*
|
|
11
|
+
* A Map over the descriptor's values, never the TS enum's reverse index
|
|
12
|
+
* (the `kindsByEnumName` doctrine in pipeline/apiresource-meta.ts): a
|
|
13
|
+
* prototype key or a number spelled as text must resolve to nothing. The
|
|
14
|
+
* zero value `unspecified` is not a permission and is left out.
|
|
15
|
+
*/
|
|
16
|
+
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
17
|
+
/** The permission a wire relation names, or `undefined`. */
|
|
18
|
+
export declare function permissionByEnumName(relation: string): IamPermission | undefined;
|
|
19
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../../src/domain/iampolicy/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,aAAa,EAEd,MAAM,2CAA2C,CAAC;AAInD,4DAA4D;AAC5D,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,GACf,aAAa,GAAG,SAAS,CAS3B"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The permission vocabulary as the wire spells it (20260913.01 slice 5,
|
|
3
|
+
* Q-S5-3): `checkMyPermission` carries its `relation` as a string — the
|
|
4
|
+
* FGA relation name, which is the `IamPermission` member name — while the
|
|
5
|
+
* composed Authorizer's `AuthzCheck` carries the enum. This is the one
|
|
6
|
+
* read from the first spelling to the second. A relation that names no
|
|
7
|
+
* permission is the caller's mistake (INVALID_ARGUMENT in the controller),
|
|
8
|
+
* never a permission nobody holds: the console asks with the ten strings
|
|
9
|
+
* `IamPermission` lists (claim check C4) and a typo should be heard.
|
|
10
|
+
*
|
|
11
|
+
* A Map over the descriptor's values, never the TS enum's reverse index
|
|
12
|
+
* (the `kindsByEnumName` doctrine in pipeline/apiresource-meta.ts): a
|
|
13
|
+
* prototype key or a number spelled as text must resolve to nothing. The
|
|
14
|
+
* zero value `unspecified` is not a permission and is left out.
|
|
15
|
+
*/
|
|
16
|
+
import { IamPermission, IamPermissionSchema, } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
17
|
+
let byName;
|
|
18
|
+
/** The permission a wire relation names, or `undefined`. */
|
|
19
|
+
export function permissionByEnumName(relation) {
|
|
20
|
+
if (byName === undefined) {
|
|
21
|
+
byName = new Map(IamPermissionSchema.values
|
|
22
|
+
.filter((value) => value.number !== IamPermission.unspecified)
|
|
23
|
+
.map((value) => [value.name, value.number]));
|
|
24
|
+
}
|
|
25
|
+
return byName.get(relation);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../src/domain/iampolicy/permissions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EACL,aAAa,EACb,mBAAmB,GACpB,MAAM,2CAA2C,CAAC;AAEnD,IAAI,MAA8C,CAAC;AAEnD,4DAA4D;AAC5D,MAAM,UAAU,oBAAoB,CAClC,QAAgB;IAEhB,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,MAAM,GAAG,IAAI,GAAG,CACd,mBAAmB,CAAC,MAAM;aACvB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,aAAa,CAAC,WAAW,CAAC;aAC7D,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAuB,CAAC,CAAC,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource-store.d.ts","sourceRoot":"","sources":["../../../src/domain/iampolicy/resource-store.ts"],"names":[],"mappings":"AA2CA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAmBjD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc,CAwGtE"}
|