Refactor policies document
Signed-off-by: Bryan Frimin <bryan@getprobo.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<83cc00d864e6388ef2156203499da849>>
|
* @generated SignedSource<<76057cc6f78c32b15c6e580c7a0c30da>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -124,13 +124,6 @@ return {
|
|||||||
"name": "expiresAt",
|
"name": "expiresAt",
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "lastUsedAt",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"alias": null,
|
"alias": null,
|
||||||
"args": null,
|
"args": null,
|
||||||
@@ -194,12 +187,12 @@ return {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "14e698e7b6edf0afe9cf3398986cd529",
|
"cacheID": "cf6f6f621bdcb1bd24a2dd94f856729f",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "APIKeysPageQuery",
|
"name": "APIKeysPageQuery",
|
||||||
"operationKind": "query",
|
"operationKind": "query",
|
||||||
"text": "query APIKeysPageQuery {\n viewer {\n ...PersonalAPIKeyListFragment\n id\n }\n}\n\nfragment PersonalAPIKeyListFragment on Identity {\n id\n personalAPIKeys(first: 1000) {\n edges {\n node {\n id\n name\n createdAt\n expiresAt\n lastUsedAt\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n"
|
"text": "query APIKeysPageQuery {\n viewer {\n ...PersonalAPIKeyListFragment\n id\n }\n}\n\nfragment PersonalAPIKeyListFragment on Identity {\n id\n personalAPIKeys(first: 1000) {\n edges {\n node {\n id\n ...PersonalAPIKeyRowFragment\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n}\n\nfragment PersonalAPIKeyRowFragment on PersonalAPIKey {\n id\n name\n createdAt\n expiresAt\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<875eae6f5455a17a1bb8e0590c7acdb0>>
|
* @generated SignedSource<<faeeb8835f77a5251a0311dbac21bfde>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -12,7 +12,6 @@ import { ConcreteRequest } from 'relay-runtime';
|
|||||||
export type CreatePersonalAPIKeyInput = {
|
export type CreatePersonalAPIKeyInput = {
|
||||||
expiresAt: any;
|
expiresAt: any;
|
||||||
name: string;
|
name: string;
|
||||||
organizationIds: ReadonlyArray<string>;
|
|
||||||
};
|
};
|
||||||
export type PersonalAPIKeyListCreateMutation$variables = {
|
export type PersonalAPIKeyListCreateMutation$variables = {
|
||||||
connections: ReadonlyArray<string>;
|
connections: ReadonlyArray<string>;
|
||||||
@@ -25,7 +24,6 @@ export type PersonalAPIKeyListCreateMutation$data = {
|
|||||||
readonly createdAt: any;
|
readonly createdAt: any;
|
||||||
readonly expiresAt: any;
|
readonly expiresAt: any;
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly lastUsedAt: any | null | undefined;
|
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -98,13 +96,6 @@ v3 = {
|
|||||||
"kind": "ScalarField",
|
"kind": "ScalarField",
|
||||||
"name": "expiresAt",
|
"name": "expiresAt",
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "lastUsedAt",
|
|
||||||
"storageKey": null
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"storageKey": null
|
"storageKey": null
|
||||||
@@ -187,16 +178,16 @@ return {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"params": {
|
"params": {
|
||||||
"cacheID": "5b1f6109730bd9f261afd6635d568b59",
|
"cacheID": "1ec09abe9f3a61e13ba2deacf1a273fb",
|
||||||
"id": null,
|
"id": null,
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"name": "PersonalAPIKeyListCreateMutation",
|
"name": "PersonalAPIKeyListCreateMutation",
|
||||||
"operationKind": "mutation",
|
"operationKind": "mutation",
|
||||||
"text": "mutation PersonalAPIKeyListCreateMutation(\n $input: CreatePersonalAPIKeyInput!\n) {\n createPersonalAPIKey(input: $input) {\n personalAPIKeyEdge {\n node {\n id\n name\n createdAt\n expiresAt\n lastUsedAt\n }\n }\n token\n }\n}\n"
|
"text": "mutation PersonalAPIKeyListCreateMutation(\n $input: CreatePersonalAPIKeyInput!\n) {\n createPersonalAPIKey(input: $input) {\n personalAPIKeyEdge {\n node {\n id\n name\n createdAt\n expiresAt\n }\n }\n token\n }\n}\n"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "c7e932ad41ff2740e8687b7edb904431";
|
(node as any).hash = "86df62e5e5f2d9f347f41648d7af9c32";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* @generated SignedSource<<e518a98137eb07e37499d945991b15ed>>
|
* @generated SignedSource<<bdb7bb502fae96e1eb5b8ae644f8bebf>>
|
||||||
* @lightSyntaxTransform
|
* @lightSyntaxTransform
|
||||||
* @nogrep
|
* @nogrep
|
||||||
*/
|
*/
|
||||||
@@ -15,11 +15,8 @@ export type PersonalAPIKeyListFragment$data = {
|
|||||||
readonly personalAPIKeys: {
|
readonly personalAPIKeys: {
|
||||||
readonly edges: ReadonlyArray<{
|
readonly edges: ReadonlyArray<{
|
||||||
readonly node: {
|
readonly node: {
|
||||||
readonly createdAt: any;
|
|
||||||
readonly expiresAt: any;
|
|
||||||
readonly id: string;
|
readonly id: string;
|
||||||
readonly lastUsedAt: any | null | undefined;
|
readonly " $fragmentSpreads": FragmentRefs<"PersonalAPIKeyRowFragment">;
|
||||||
readonly name: string;
|
|
||||||
};
|
};
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
@@ -86,32 +83,9 @@ return {
|
|||||||
"selections": [
|
"selections": [
|
||||||
(v0/*: any*/),
|
(v0/*: any*/),
|
||||||
{
|
{
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
"args": null,
|
||||||
"kind": "ScalarField",
|
"kind": "FragmentSpread",
|
||||||
"name": "name",
|
"name": "PersonalAPIKeyRowFragment"
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "createdAt",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "expiresAt",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "lastUsedAt",
|
|
||||||
"storageKey": null
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"alias": null,
|
"alias": null,
|
||||||
@@ -171,6 +145,6 @@ return {
|
|||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(node as any).hash = "70fa6b4e568fc1598b8dc23a030428b5";
|
(node as any).hash = "eac59db5cdb5d77813236a90e7fb4d94";
|
||||||
|
|
||||||
export default node;
|
export default node;
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
* @generated SignedSource<<7a6fb678e9147fd1810e02bd09d5cef1>>
|
|
||||||
* @lightSyntaxTransform
|
|
||||||
* @nogrep
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import { ConcreteRequest } from 'relay-runtime';
|
|
||||||
export type RevealPersonalAPIKeyTokenInput = {
|
|
||||||
tokenId: string;
|
|
||||||
};
|
|
||||||
export type PersonalAPIKeyListRevealTokenMutation$variables = {
|
|
||||||
input: RevealPersonalAPIKeyTokenInput;
|
|
||||||
};
|
|
||||||
export type PersonalAPIKeyListRevealTokenMutation$data = {
|
|
||||||
readonly revealPersonalAPIKeyToken: {
|
|
||||||
readonly token: string;
|
|
||||||
} | null | undefined;
|
|
||||||
};
|
|
||||||
export type PersonalAPIKeyListRevealTokenMutation = {
|
|
||||||
response: PersonalAPIKeyListRevealTokenMutation$data;
|
|
||||||
variables: PersonalAPIKeyListRevealTokenMutation$variables;
|
|
||||||
};
|
|
||||||
|
|
||||||
const node: ConcreteRequest = (function(){
|
|
||||||
var v0 = [
|
|
||||||
{
|
|
||||||
"defaultValue": null,
|
|
||||||
"kind": "LocalArgument",
|
|
||||||
"name": "input"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
v1 = [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Variable",
|
|
||||||
"name": "input",
|
|
||||||
"variableName": "input"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"concreteType": "RevealPersonalAPIKeyTokenPayload",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "revealPersonalAPIKeyToken",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "token",
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return {
|
|
||||||
"fragment": {
|
|
||||||
"argumentDefinitions": (v0/*: any*/),
|
|
||||||
"kind": "Fragment",
|
|
||||||
"metadata": null,
|
|
||||||
"name": "PersonalAPIKeyListRevealTokenMutation",
|
|
||||||
"selections": (v1/*: any*/),
|
|
||||||
"type": "Mutation",
|
|
||||||
"abstractKey": null
|
|
||||||
},
|
|
||||||
"kind": "Request",
|
|
||||||
"operation": {
|
|
||||||
"argumentDefinitions": (v0/*: any*/),
|
|
||||||
"kind": "Operation",
|
|
||||||
"name": "PersonalAPIKeyListRevealTokenMutation",
|
|
||||||
"selections": (v1/*: any*/)
|
|
||||||
},
|
|
||||||
"params": {
|
|
||||||
"cacheID": "25ffba7c8a69e22dcc46b56a6c8633ed",
|
|
||||||
"id": null,
|
|
||||||
"metadata": {},
|
|
||||||
"name": "PersonalAPIKeyListRevealTokenMutation",
|
|
||||||
"operationKind": "mutation",
|
|
||||||
"text": "mutation PersonalAPIKeyListRevealTokenMutation(\n $input: RevealPersonalAPIKeyTokenInput!\n) {\n revealPersonalAPIKeyToken(input: $input) {\n token\n }\n}\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
(node as any).hash = "7dad7ebd6e8086a01b2bac8aa80c532e";
|
|
||||||
|
|
||||||
export default node;
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
/**
|
|
||||||
* @generated SignedSource<<84eef5bca22c2ad2b73bbe068767e35a>>
|
|
||||||
* @lightSyntaxTransform
|
|
||||||
* @nogrep
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* tslint:disable */
|
|
||||||
/* eslint-disable */
|
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import { ConcreteRequest } from 'relay-runtime';
|
|
||||||
export type RevokePersonalAPIKeyInput = {
|
|
||||||
tokenId: string;
|
|
||||||
};
|
|
||||||
export type PersonalAPIKeyListRevokeMutation$variables = {
|
|
||||||
input: RevokePersonalAPIKeyInput;
|
|
||||||
};
|
|
||||||
export type PersonalAPIKeyListRevokeMutation$data = {
|
|
||||||
readonly revokePersonalAPIKey: {
|
|
||||||
readonly success: boolean;
|
|
||||||
} | null | undefined;
|
|
||||||
};
|
|
||||||
export type PersonalAPIKeyListRevokeMutation = {
|
|
||||||
response: PersonalAPIKeyListRevokeMutation$data;
|
|
||||||
variables: PersonalAPIKeyListRevokeMutation$variables;
|
|
||||||
};
|
|
||||||
|
|
||||||
const node: ConcreteRequest = (function(){
|
|
||||||
var v0 = [
|
|
||||||
{
|
|
||||||
"defaultValue": null,
|
|
||||||
"kind": "LocalArgument",
|
|
||||||
"name": "input"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
v1 = [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": [
|
|
||||||
{
|
|
||||||
"kind": "Variable",
|
|
||||||
"name": "input",
|
|
||||||
"variableName": "input"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"concreteType": "RevokePersonalAPIKeyPayload",
|
|
||||||
"kind": "LinkedField",
|
|
||||||
"name": "revokePersonalAPIKey",
|
|
||||||
"plural": false,
|
|
||||||
"selections": [
|
|
||||||
{
|
|
||||||
"alias": null,
|
|
||||||
"args": null,
|
|
||||||
"kind": "ScalarField",
|
|
||||||
"name": "success",
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"storageKey": null
|
|
||||||
}
|
|
||||||
];
|
|
||||||
return {
|
|
||||||
"fragment": {
|
|
||||||
"argumentDefinitions": (v0/*: any*/),
|
|
||||||
"kind": "Fragment",
|
|
||||||
"metadata": null,
|
|
||||||
"name": "PersonalAPIKeyListRevokeMutation",
|
|
||||||
"selections": (v1/*: any*/),
|
|
||||||
"type": "Mutation",
|
|
||||||
"abstractKey": null
|
|
||||||
},
|
|
||||||
"kind": "Request",
|
|
||||||
"operation": {
|
|
||||||
"argumentDefinitions": (v0/*: any*/),
|
|
||||||
"kind": "Operation",
|
|
||||||
"name": "PersonalAPIKeyListRevokeMutation",
|
|
||||||
"selections": (v1/*: any*/)
|
|
||||||
},
|
|
||||||
"params": {
|
|
||||||
"cacheID": "fd05bb0236b583ca54be466cffe8f45b",
|
|
||||||
"id": null,
|
|
||||||
"metadata": {},
|
|
||||||
"name": "PersonalAPIKeyListRevokeMutation",
|
|
||||||
"operationKind": "mutation",
|
|
||||||
"text": "mutation PersonalAPIKeyListRevokeMutation(\n $input: RevokePersonalAPIKeyInput!\n) {\n revokePersonalAPIKey(input: $input) {\n success\n }\n}\n"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
(node as any).hash = "34ef04d19251c479827ca5028346f65b";
|
|
||||||
|
|
||||||
export default node;
|
|
||||||
101
apps/console/src/__generated__/iam/PersonalAPIKeyRowFragment.graphql.ts
generated
Normal file
101
apps/console/src/__generated__/iam/PersonalAPIKeyRowFragment.graphql.ts
generated
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<ed51014f8f35d76faaa63c10998610be>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ReaderFragment } from 'relay-runtime';
|
||||||
|
import { FragmentRefs } from "relay-runtime";
|
||||||
|
export type PersonalAPIKeyRowFragment$data = {
|
||||||
|
readonly createdAt: any;
|
||||||
|
readonly expiresAt: any;
|
||||||
|
readonly id: string;
|
||||||
|
readonly name: string;
|
||||||
|
readonly token?: string | null | undefined;
|
||||||
|
readonly " $fragmentType": "PersonalAPIKeyRowFragment";
|
||||||
|
};
|
||||||
|
export type PersonalAPIKeyRowFragment$key = {
|
||||||
|
readonly " $data"?: PersonalAPIKeyRowFragment$data;
|
||||||
|
readonly " $fragmentSpreads": FragmentRefs<"PersonalAPIKeyRowFragment">;
|
||||||
|
};
|
||||||
|
|
||||||
|
import PersonalAPIKeyRowRefetchQuery_graphql from './PersonalAPIKeyRowRefetchQuery.graphql';
|
||||||
|
|
||||||
|
const node: ReaderFragment = {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
{
|
||||||
|
"defaultValue": false,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "includeToken"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": {
|
||||||
|
"refetch": {
|
||||||
|
"connection": null,
|
||||||
|
"fragmentPathInResult": [
|
||||||
|
"node"
|
||||||
|
],
|
||||||
|
"operation": PersonalAPIKeyRowRefetchQuery_graphql,
|
||||||
|
"identifierInfo": {
|
||||||
|
"identifierField": "id",
|
||||||
|
"identifierQueryVariableName": "id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"name": "PersonalAPIKeyRowFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "createdAt",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "expiresAt",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "includeToken",
|
||||||
|
"kind": "Condition",
|
||||||
|
"passingValue": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "token",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "PersonalAPIKey",
|
||||||
|
"abstractKey": null
|
||||||
|
};
|
||||||
|
|
||||||
|
(node as any).hash = "d17db443fa203ee5f9c7d0f4576295f0";
|
||||||
|
|
||||||
|
export default node;
|
||||||
172
apps/console/src/__generated__/iam/PersonalAPIKeyRowRefetchQuery.graphql.ts
generated
Normal file
172
apps/console/src/__generated__/iam/PersonalAPIKeyRowRefetchQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<2d413d4e4cf2528a45ff243c0fa733bb>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
import { FragmentRefs } from "relay-runtime";
|
||||||
|
export type PersonalAPIKeyRowRefetchQuery$variables = {
|
||||||
|
id: string;
|
||||||
|
includeToken?: boolean | null | undefined;
|
||||||
|
};
|
||||||
|
export type PersonalAPIKeyRowRefetchQuery$data = {
|
||||||
|
readonly node: {
|
||||||
|
readonly " $fragmentSpreads": FragmentRefs<"PersonalAPIKeyRowFragment">;
|
||||||
|
} | null | undefined;
|
||||||
|
};
|
||||||
|
export type PersonalAPIKeyRowRefetchQuery = {
|
||||||
|
response: PersonalAPIKeyRowRefetchQuery$data;
|
||||||
|
variables: PersonalAPIKeyRowRefetchQuery$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = {
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "id"
|
||||||
|
},
|
||||||
|
v1 = {
|
||||||
|
"defaultValue": false,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "includeToken"
|
||||||
|
},
|
||||||
|
v2 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "id",
|
||||||
|
"variableName": "id"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
(v0/*: any*/),
|
||||||
|
(v1/*: any*/)
|
||||||
|
],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "PersonalAPIKeyRowRefetchQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v2/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"args": [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "includeToken",
|
||||||
|
"variableName": "includeToken"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "FragmentSpread",
|
||||||
|
"name": "PersonalAPIKeyRowFragment"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Query",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
(v1/*: any*/),
|
||||||
|
(v0/*: any*/)
|
||||||
|
],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "PersonalAPIKeyRowRefetchQuery",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v2/*: any*/),
|
||||||
|
"concreteType": null,
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "node",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "__typename",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "id",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "InlineFragment",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "name",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "createdAt",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "expiresAt",
|
||||||
|
"storageKey": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"condition": "includeToken",
|
||||||
|
"kind": "Condition",
|
||||||
|
"passingValue": true,
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "token",
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "PersonalAPIKey",
|
||||||
|
"abstractKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "b4732244e28d5847baaa5520a95a4cfb",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "PersonalAPIKeyRowRefetchQuery",
|
||||||
|
"operationKind": "query",
|
||||||
|
"text": "query PersonalAPIKeyRowRefetchQuery(\n $includeToken: Boolean = false\n $id: ID!\n) {\n node(id: $id) {\n __typename\n ...PersonalAPIKeyRowFragment_2T7Twf\n id\n }\n}\n\nfragment PersonalAPIKeyRowFragment_2T7Twf on PersonalAPIKey {\n id\n name\n createdAt\n expiresAt\n token @include(if: $includeToken)\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "d17db443fa203ee5f9c7d0f4576295f0";
|
||||||
|
|
||||||
|
export default node;
|
||||||
132
apps/console/src/__generated__/iam/PersonalAPIKeyRow_revokeMutation.graphql.ts
generated
Normal file
132
apps/console/src/__generated__/iam/PersonalAPIKeyRow_revokeMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
/**
|
||||||
|
* @generated SignedSource<<64ad5ad6ff333dffc7b2d5d578028d7f>>
|
||||||
|
* @lightSyntaxTransform
|
||||||
|
* @nogrep
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// @ts-nocheck
|
||||||
|
|
||||||
|
import { ConcreteRequest } from 'relay-runtime';
|
||||||
|
export type RevokePersonalAPIKeyInput = {
|
||||||
|
personalAPIKeyId: string;
|
||||||
|
};
|
||||||
|
export type PersonalAPIKeyRow_revokeMutation$variables = {
|
||||||
|
connections: ReadonlyArray<string>;
|
||||||
|
input: RevokePersonalAPIKeyInput;
|
||||||
|
};
|
||||||
|
export type PersonalAPIKeyRow_revokeMutation$data = {
|
||||||
|
readonly revokePersonalAPIKey: {
|
||||||
|
readonly personalAPIKeyId: string;
|
||||||
|
} | null | undefined;
|
||||||
|
};
|
||||||
|
export type PersonalAPIKeyRow_revokeMutation = {
|
||||||
|
response: PersonalAPIKeyRow_revokeMutation$data;
|
||||||
|
variables: PersonalAPIKeyRow_revokeMutation$variables;
|
||||||
|
};
|
||||||
|
|
||||||
|
const node: ConcreteRequest = (function(){
|
||||||
|
var v0 = {
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "connections"
|
||||||
|
},
|
||||||
|
v1 = {
|
||||||
|
"defaultValue": null,
|
||||||
|
"kind": "LocalArgument",
|
||||||
|
"name": "input"
|
||||||
|
},
|
||||||
|
v2 = [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "input",
|
||||||
|
"variableName": "input"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
v3 = {
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"kind": "ScalarField",
|
||||||
|
"name": "personalAPIKeyId",
|
||||||
|
"storageKey": null
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
"fragment": {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
(v0/*: any*/),
|
||||||
|
(v1/*: any*/)
|
||||||
|
],
|
||||||
|
"kind": "Fragment",
|
||||||
|
"metadata": null,
|
||||||
|
"name": "PersonalAPIKeyRow_revokeMutation",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v2/*: any*/),
|
||||||
|
"concreteType": "RevokePersonalAPIKeyPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "revokePersonalAPIKey",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/)
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "Mutation",
|
||||||
|
"abstractKey": null
|
||||||
|
},
|
||||||
|
"kind": "Request",
|
||||||
|
"operation": {
|
||||||
|
"argumentDefinitions": [
|
||||||
|
(v1/*: any*/),
|
||||||
|
(v0/*: any*/)
|
||||||
|
],
|
||||||
|
"kind": "Operation",
|
||||||
|
"name": "PersonalAPIKeyRow_revokeMutation",
|
||||||
|
"selections": [
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": (v2/*: any*/),
|
||||||
|
"concreteType": "RevokePersonalAPIKeyPayload",
|
||||||
|
"kind": "LinkedField",
|
||||||
|
"name": "revokePersonalAPIKey",
|
||||||
|
"plural": false,
|
||||||
|
"selections": [
|
||||||
|
(v3/*: any*/),
|
||||||
|
{
|
||||||
|
"alias": null,
|
||||||
|
"args": null,
|
||||||
|
"filters": null,
|
||||||
|
"handle": "deleteEdge",
|
||||||
|
"key": "",
|
||||||
|
"kind": "ScalarHandle",
|
||||||
|
"name": "personalAPIKeyId",
|
||||||
|
"handleArgs": [
|
||||||
|
{
|
||||||
|
"kind": "Variable",
|
||||||
|
"name": "connections",
|
||||||
|
"variableName": "connections"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"storageKey": null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"cacheID": "29dfd9de3537585482c2863a1d547031",
|
||||||
|
"id": null,
|
||||||
|
"metadata": {},
|
||||||
|
"name": "PersonalAPIKeyRow_revokeMutation",
|
||||||
|
"operationKind": "mutation",
|
||||||
|
"text": "mutation PersonalAPIKeyRow_revokeMutation(\n $input: RevokePersonalAPIKeyInput!\n) {\n revokePersonalAPIKey(input: $input) {\n personalAPIKeyId\n }\n}\n"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(node as any).hash = "258ca02064f55b6fd4a3630ba1f904a4";
|
||||||
|
|
||||||
|
export default node;
|
||||||
@@ -6,10 +6,9 @@ import {
|
|||||||
useFragment,
|
useFragment,
|
||||||
useMutation,
|
useMutation,
|
||||||
} from "react-relay";
|
} from "react-relay";
|
||||||
import type { RecordSourceSelectorProxy } from "relay-runtime";
|
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { useTranslate } from "@probo/i18n";
|
import { useTranslate } from "@probo/i18n";
|
||||||
import { formatError, type GraphQLError } from "@probo/helpers";
|
import { formatError } from "@probo/helpers";
|
||||||
import {
|
import {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
Button,
|
Button,
|
||||||
@@ -22,15 +21,12 @@ import {
|
|||||||
Label,
|
Label,
|
||||||
Option,
|
Option,
|
||||||
Select,
|
Select,
|
||||||
useConfirm,
|
|
||||||
useDialogRef,
|
useDialogRef,
|
||||||
useToast,
|
useToast,
|
||||||
} from "@probo/ui";
|
} from "@probo/ui";
|
||||||
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
import { useFormWithSchema } from "/hooks/useFormWithSchema";
|
||||||
import type { PersonalAPIKeyListFragment$key } from "/__generated__/iam/PersonalAPIKeyListFragment.graphql";
|
import type { PersonalAPIKeyListFragment$key } from "/__generated__/iam/PersonalAPIKeyListFragment.graphql";
|
||||||
import type { PersonalAPIKeyListCreateMutation } from "/__generated__/iam/PersonalAPIKeyListCreateMutation.graphql";
|
import type { PersonalAPIKeyListCreateMutation } from "/__generated__/iam/PersonalAPIKeyListCreateMutation.graphql";
|
||||||
import type { PersonalAPIKeyListRevokeMutation } from "/__generated__/iam/PersonalAPIKeyListRevokeMutation.graphql";
|
|
||||||
import type { PersonalAPIKeyListRevealTokenMutation } from "/__generated__/iam/PersonalAPIKeyListRevealTokenMutation.graphql";
|
|
||||||
import { PersonalAPIKeysTable } from "./PersonalAPIKeysTable";
|
import { PersonalAPIKeysTable } from "./PersonalAPIKeysTable";
|
||||||
import { PersonalAPIKeyTokenDialog } from "./PersonalAPIKeyTokenDialog";
|
import { PersonalAPIKeyTokenDialog } from "./PersonalAPIKeyTokenDialog";
|
||||||
|
|
||||||
@@ -44,10 +40,7 @@ const fragment = graphql`
|
|||||||
edges @required(action: THROW) {
|
edges @required(action: THROW) {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
name
|
...PersonalAPIKeyRowFragment
|
||||||
createdAt
|
|
||||||
expiresAt
|
|
||||||
lastUsedAt
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,7 +59,6 @@ const createMutation = graphql`
|
|||||||
name
|
name
|
||||||
createdAt
|
createdAt
|
||||||
expiresAt
|
expiresAt
|
||||||
lastUsedAt
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
token
|
token
|
||||||
@@ -74,26 +66,6 @@ const createMutation = graphql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const revokeMutation = graphql`
|
|
||||||
mutation PersonalAPIKeyListRevokeMutation(
|
|
||||||
$input: RevokePersonalAPIKeyInput!
|
|
||||||
) {
|
|
||||||
revokePersonalAPIKey(input: $input) {
|
|
||||||
success
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const revealTokenMutation = graphql`
|
|
||||||
mutation PersonalAPIKeyListRevealTokenMutation(
|
|
||||||
$input: RevealPersonalAPIKeyTokenInput!
|
|
||||||
) {
|
|
||||||
revealPersonalAPIKeyToken(input: $input) {
|
|
||||||
token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const createSchema = z.object({
|
const createSchema = z.object({
|
||||||
name: z.string().min(1, "Name is required"),
|
name: z.string().min(1, "Name is required"),
|
||||||
expiresIn: z.enum(["1month", "3months", "6months", "1year"]),
|
expiresIn: z.enum(["1month", "3months", "6months", "1year"]),
|
||||||
@@ -126,7 +98,6 @@ export function PersonalAPIKeyList(props: {
|
|||||||
const { fKey } = props;
|
const { fKey } = props;
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const confirm = useConfirm();
|
|
||||||
const createDialogRef = useDialogRef();
|
const createDialogRef = useDialogRef();
|
||||||
const tokenDialogRef = useDialogRef();
|
const tokenDialogRef = useDialogRef();
|
||||||
|
|
||||||
@@ -134,9 +105,12 @@ export function PersonalAPIKeyList(props: {
|
|||||||
|
|
||||||
const viewer = useFragment(fragment, fKey);
|
const viewer = useFragment(fragment, fKey);
|
||||||
|
|
||||||
const keys = viewer.personalAPIKeys.edges.map(({ node }) => node);
|
const connectionID = ConnectionHandler.getConnectionID(
|
||||||
|
viewer.id,
|
||||||
|
"PersonalAPIKeyListFragment_personalAPIKeys"
|
||||||
|
);
|
||||||
|
|
||||||
const { formState, handleSubmit, register, control, reset, watch } =
|
const { formState, handleSubmit, register, control, reset } =
|
||||||
useFormWithSchema(createSchema, {
|
useFormWithSchema(createSchema, {
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
name: new Date().toISOString().split("T")[0],
|
name: new Date().toISOString().split("T")[0],
|
||||||
@@ -144,20 +118,14 @@ export function PersonalAPIKeyList(props: {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
watch();
|
|
||||||
|
|
||||||
const [createCommit, isCreating] =
|
const [createCommit, isCreating] =
|
||||||
useMutation<PersonalAPIKeyListCreateMutation>(createMutation);
|
useMutation<PersonalAPIKeyListCreateMutation>(createMutation);
|
||||||
const [revokeCommit] =
|
|
||||||
useMutation<PersonalAPIKeyListRevokeMutation>(revokeMutation);
|
|
||||||
const [revealTokenCommit, isRevealingToken] =
|
|
||||||
useMutation<PersonalAPIKeyListRevealTokenMutation>(revealTokenMutation);
|
|
||||||
|
|
||||||
const handleCreate = (data: CreateFormData) => {
|
const handleCreate = (data: CreateFormData) => {
|
||||||
const expiresAt = computeExpiresAt(data.expiresIn);
|
const expiresAt = computeExpiresAt(data.expiresIn);
|
||||||
const connectionID = ConnectionHandler.getConnectionID(
|
const connectionID = ConnectionHandler.getConnectionID(
|
||||||
viewer.id,
|
viewer.id,
|
||||||
"PersonalAPIKeyListFragment_personalAPIKeys",
|
"PersonalAPIKeyListFragment_personalAPIKeys"
|
||||||
);
|
);
|
||||||
|
|
||||||
createCommit({
|
createCommit({
|
||||||
@@ -165,8 +133,6 @@ export function PersonalAPIKeyList(props: {
|
|||||||
input: {
|
input: {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
expiresAt: expiresAt.toISOString(),
|
expiresAt: expiresAt.toISOString(),
|
||||||
// API keys are no longer linked to organizations; keep schema compatibility.
|
|
||||||
organizationIds: [],
|
|
||||||
},
|
},
|
||||||
connections: [connectionID],
|
connections: [connectionID],
|
||||||
},
|
},
|
||||||
@@ -194,116 +160,6 @@ export function PersonalAPIKeyList(props: {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRevoke = (key: { id: string; name: string }) => {
|
|
||||||
confirm(
|
|
||||||
async () => {
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
revokeCommit({
|
|
||||||
variables: {
|
|
||||||
input: { tokenId: key.id },
|
|
||||||
},
|
|
||||||
updater: (store: RecordSourceSelectorProxy) => {
|
|
||||||
const viewerRecord = store.getRoot().getLinkedRecord("viewer");
|
|
||||||
if (!viewerRecord) return;
|
|
||||||
const connection = ConnectionHandler.getConnection(
|
|
||||||
viewerRecord,
|
|
||||||
"PersonalAPIKeyListFragment_personalAPIKeys",
|
|
||||||
);
|
|
||||||
if (connection) {
|
|
||||||
ConnectionHandler.deleteNode(connection, key.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onCompleted: (_response, errors) => {
|
|
||||||
if (errors?.length) {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: formatError(
|
|
||||||
__("Failed to revoke API key."),
|
|
||||||
errors as GraphQLError[],
|
|
||||||
),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
reject(errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toast({
|
|
||||||
title: __("Success"),
|
|
||||||
description: __("API key revoked successfully."),
|
|
||||||
variant: "success",
|
|
||||||
});
|
|
||||||
resolve();
|
|
||||||
},
|
|
||||||
onError: (error) => {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: formatError(
|
|
||||||
__("Failed to revoke API key."),
|
|
||||||
error,
|
|
||||||
),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
reject(error);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: __("Revoke API Key"),
|
|
||||||
message: __(
|
|
||||||
`Are you sure you want to revoke the API key "${key.name}"? This action cannot be undone.`,
|
|
||||||
),
|
|
||||||
label: __("Revoke"),
|
|
||||||
variant: "danger",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleShowToken = (key: { id: string; name: string }) => {
|
|
||||||
revealTokenCommit({
|
|
||||||
variables: {
|
|
||||||
input: {
|
|
||||||
tokenId: key.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
onCompleted: (response, errors) => {
|
|
||||||
if (errors?.length) {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: formatError(
|
|
||||||
__("Failed to reveal API key token."),
|
|
||||||
errors as any,
|
|
||||||
),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokenValue = response.revealPersonalAPIKeyToken?.token;
|
|
||||||
if (!tokenValue) {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: __("No token returned."),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setToken(tokenValue);
|
|
||||||
tokenDialogRef.current?.open();
|
|
||||||
},
|
|
||||||
onError: (error: Error) => {
|
|
||||||
toast({
|
|
||||||
title: __("Error"),
|
|
||||||
description: formatError(
|
|
||||||
__("Failed to reveal API key token."),
|
|
||||||
error,
|
|
||||||
),
|
|
||||||
variant: "error",
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@@ -314,7 +170,7 @@ export function PersonalAPIKeyList(props: {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{keys.length === 0 ? (
|
{viewer.personalAPIKeys.edges.length === 0 ? (
|
||||||
<Card padded>
|
<Card padded>
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
<h3 className="text-lg font-medium text-gray-900 mb-2">
|
||||||
@@ -328,10 +184,8 @@ export function PersonalAPIKeyList(props: {
|
|||||||
) : (
|
) : (
|
||||||
<Card padded>
|
<Card padded>
|
||||||
<PersonalAPIKeysTable
|
<PersonalAPIKeysTable
|
||||||
keys={keys}
|
edges={viewer.personalAPIKeys.edges}
|
||||||
onRevoke={handleRevoke}
|
connectionId={connectionID}
|
||||||
onShowToken={handleShowToken}
|
|
||||||
isShowingToken={isRevealingToken}
|
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import { formatDate, formatError, type GraphQLError } from "@probo/helpers";
|
||||||
|
import { Button, Spinner, Td, Tr, useConfirm, useToast } from "@probo/ui";
|
||||||
|
import { graphql } from "relay-runtime";
|
||||||
|
import { useMutation, useFragment } from "react-relay";
|
||||||
|
import type { PersonalAPIKeyRowFragment$key } from "/__generated__/iam/PersonalAPIKeyRowFragment.graphql";
|
||||||
|
import type { PersonalAPIKeyRow_revokeMutation } from "/__generated__/iam/PersonalAPIKeyRow_revokeMutation.graphql";
|
||||||
|
import clsx from "clsx";
|
||||||
|
import { PersonalAPIKeyTokenAction } from "./PersonalAPIKeyTokenAction";
|
||||||
|
import { Suspense } from "react";
|
||||||
|
|
||||||
|
const revokeMutation = graphql`
|
||||||
|
mutation PersonalAPIKeyRow_revokeMutation(
|
||||||
|
$input: RevokePersonalAPIKeyInput!
|
||||||
|
$connections: [ID!]!
|
||||||
|
) {
|
||||||
|
revokePersonalAPIKey(input: $input) {
|
||||||
|
personalAPIKeyId @deleteEdge(connections: $connections)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const personalAPIKeyRowFragment = graphql`
|
||||||
|
fragment PersonalAPIKeyRowFragment on PersonalAPIKey
|
||||||
|
@refetchable(queryName: "PersonalAPIKeyRowRefetchQuery")
|
||||||
|
@argumentDefinitions(includeToken: { type: "Boolean", defaultValue: false }) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
createdAt
|
||||||
|
expiresAt
|
||||||
|
token @include(if: $includeToken)
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export function PersonalAPIKeyRow(props: {
|
||||||
|
fKey: PersonalAPIKeyRowFragment$key;
|
||||||
|
connectionId: string;
|
||||||
|
}) {
|
||||||
|
const { fKey, connectionId } = props;
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const confirm = useConfirm();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const now = new Date();
|
||||||
|
|
||||||
|
const key = useFragment(personalAPIKeyRowFragment, fKey);
|
||||||
|
const expired = new Date(key.expiresAt) < now;
|
||||||
|
|
||||||
|
const [revokeCommit, isRevoking] =
|
||||||
|
useMutation<PersonalAPIKeyRow_revokeMutation>(revokeMutation);
|
||||||
|
|
||||||
|
const handleRevoke = () => {
|
||||||
|
confirm(
|
||||||
|
async () => {
|
||||||
|
await new Promise<void>((resolve, reject) => {
|
||||||
|
revokeCommit({
|
||||||
|
variables: {
|
||||||
|
input: { personalAPIKeyId: key.id },
|
||||||
|
connections: [connectionId],
|
||||||
|
},
|
||||||
|
onCompleted: (_response, errors) => {
|
||||||
|
if (errors?.length) {
|
||||||
|
toast({
|
||||||
|
title: __("Error"),
|
||||||
|
description: formatError(
|
||||||
|
__("Failed to revoke API key."),
|
||||||
|
errors as GraphQLError[]
|
||||||
|
),
|
||||||
|
variant: "error",
|
||||||
|
});
|
||||||
|
reject(errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toast({
|
||||||
|
title: __("Success"),
|
||||||
|
description: __("API key revoked successfully."),
|
||||||
|
variant: "success",
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast({
|
||||||
|
title: __("Error"),
|
||||||
|
description: formatError(
|
||||||
|
__("Failed to revoke API key."),
|
||||||
|
error
|
||||||
|
),
|
||||||
|
variant: "error",
|
||||||
|
});
|
||||||
|
reject(error);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: __("Revoke API Key"),
|
||||||
|
message: __(
|
||||||
|
`Are you sure you want to revoke the API key "${key.name}"? This action cannot be undone.`
|
||||||
|
),
|
||||||
|
label: __("Revoke"),
|
||||||
|
variant: "danger",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tr className={clsx(isRevoking && "opacity-60 pointer-events-none")}>
|
||||||
|
<Td>
|
||||||
|
<div className="font-medium text-txt-primary">{key.name}</div>
|
||||||
|
<div className="text-xs text-txt-tertiary">
|
||||||
|
{expired ? __("Expired") : __("Active")}
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
<span className="text-sm text-txt-secondary">
|
||||||
|
{formatDate(key.createdAt)}
|
||||||
|
</span>
|
||||||
|
</Td>
|
||||||
|
<Td>
|
||||||
|
<span className="text-sm text-txt-secondary">
|
||||||
|
{formatDate(key.expiresAt)}
|
||||||
|
</span>
|
||||||
|
</Td>
|
||||||
|
<Td width={140} className="text-end">
|
||||||
|
<div className="flex gap-2 justify-end">
|
||||||
|
<Suspense fallback={<Spinner />}>
|
||||||
|
<PersonalAPIKeyTokenAction fKey={fKey} disabled={isRevoking} />
|
||||||
|
</Suspense>
|
||||||
|
<Button variant="danger" onClick={handleRevoke} disabled={isRevoking}>
|
||||||
|
{__("Revoke")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Td>
|
||||||
|
</Tr>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import { useTranslate } from "@probo/i18n";
|
||||||
|
import { Button, useDialogRef, useToast } from "@probo/ui";
|
||||||
|
import { formatError } from "@probo/helpers";
|
||||||
|
import { useRefetchableFragment } from "react-relay";
|
||||||
|
import { PersonalAPIKeyTokenDialog } from "./PersonalAPIKeyTokenDialog";
|
||||||
|
import { personalAPIKeyRowFragment } from "./PersonalAPIKeyRow";
|
||||||
|
import type { PersonalAPIKeyRowFragment$key } from "/__generated__/iam/PersonalAPIKeyRowFragment.graphql";
|
||||||
|
import type { PersonalAPIKeyRowRefetchQuery } from "/__generated__/iam/PersonalAPIKeyRowRefetchQuery.graphql";
|
||||||
|
|
||||||
|
export function PersonalAPIKeyTokenAction(props: {
|
||||||
|
fKey: PersonalAPIKeyRowFragment$key;
|
||||||
|
disabled?: boolean;
|
||||||
|
}) {
|
||||||
|
const { fKey, disabled } = props;
|
||||||
|
const { __ } = useTranslate();
|
||||||
|
const { toast } = useToast();
|
||||||
|
const dialogRef = useDialogRef();
|
||||||
|
|
||||||
|
const [data, refetch] = useRefetchableFragment<
|
||||||
|
PersonalAPIKeyRowRefetchQuery,
|
||||||
|
PersonalAPIKeyRowFragment$key
|
||||||
|
>(personalAPIKeyRowFragment, fKey);
|
||||||
|
|
||||||
|
const handleShow = () => {
|
||||||
|
dialogRef.current?.open();
|
||||||
|
|
||||||
|
refetch(
|
||||||
|
{ includeToken: true },
|
||||||
|
{
|
||||||
|
fetchPolicy: "network-only",
|
||||||
|
onComplete: (error) => {
|
||||||
|
if (error) {
|
||||||
|
toast({
|
||||||
|
title: __("Error"),
|
||||||
|
description: formatError(
|
||||||
|
__("Failed to load API key token."),
|
||||||
|
error
|
||||||
|
),
|
||||||
|
variant: "error",
|
||||||
|
});
|
||||||
|
dialogRef.current?.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button variant="secondary" onClick={handleShow} disabled={!!disabled}>
|
||||||
|
{__("Show")}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<PersonalAPIKeyTokenDialog
|
||||||
|
dialogRef={dialogRef}
|
||||||
|
token={data.token ?? ""}
|
||||||
|
onDone={() => {
|
||||||
|
dialogRef.current?.close();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
} from "@probo/ui";
|
} from "@probo/ui";
|
||||||
import { useTranslate } from "@probo/i18n";
|
import { useTranslate } from "@probo/i18n";
|
||||||
import { useCopy } from "@probo/hooks";
|
import { useCopy } from "@probo/hooks";
|
||||||
import { useEffect } from "react";
|
|
||||||
|
|
||||||
export function PersonalAPIKeyTokenDialog(props: {
|
export function PersonalAPIKeyTokenDialog(props: {
|
||||||
dialogRef: React.RefObject<{ open: () => void; close: () => void } | null>;
|
dialogRef: React.RefObject<{ open: () => void; close: () => void } | null>;
|
||||||
@@ -18,8 +17,6 @@ export function PersonalAPIKeyTokenDialog(props: {
|
|||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const [isCopied, copy] = useCopy();
|
const [isCopied, copy] = useCopy();
|
||||||
|
|
||||||
useEffect(() => {}, [token]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
ref={dialogRef}
|
ref={dialogRef}
|
||||||
|
|||||||
@@ -1,24 +1,14 @@
|
|||||||
import { useTranslate } from "@probo/i18n";
|
import { useTranslate } from "@probo/i18n";
|
||||||
import { formatDate } from "@probo/helpers";
|
import { Table, Tbody, Th, Thead, Tr } from "@probo/ui";
|
||||||
import { Button, Table, Tbody, Td, Th, Thead, Tr } from "@probo/ui";
|
import { PersonalAPIKeyRow } from "./PersonalAPIKeyRow";
|
||||||
|
import type { PersonalAPIKeyListFragment$data } from "/__generated__/iam/PersonalAPIKeyListFragment.graphql";
|
||||||
export type PersonalAPIKeyRow = {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
createdAt: string;
|
|
||||||
expiresAt: string;
|
|
||||||
lastUsedAt: string | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function PersonalAPIKeysTable(props: {
|
export function PersonalAPIKeysTable(props: {
|
||||||
keys: PersonalAPIKeyRow[];
|
edges: PersonalAPIKeyListFragment$data["personalAPIKeys"]["edges"];
|
||||||
onRevoke: (key: { id: string; name: string }) => void;
|
connectionId: string;
|
||||||
onShowToken: (key: { id: string; name: string }) => void;
|
|
||||||
isShowingToken?: boolean;
|
|
||||||
}) {
|
}) {
|
||||||
const { keys, onRevoke, onShowToken, isShowingToken } = props;
|
const { edges, connectionId } = props;
|
||||||
const { __ } = useTranslate();
|
const { __ } = useTranslate();
|
||||||
const now = new Date();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Table>
|
<Table>
|
||||||
@@ -32,51 +22,13 @@ export function PersonalAPIKeysTable(props: {
|
|||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
<Tbody>
|
<Tbody>
|
||||||
{keys.map((k) => {
|
{edges.map(({ node }) => (
|
||||||
const expired = new Date(k.expiresAt) < now;
|
<PersonalAPIKeyRow
|
||||||
return (
|
key={node.id}
|
||||||
<Tr key={k.id}>
|
fKey={node}
|
||||||
<Td>
|
connectionId={connectionId}
|
||||||
<div className="font-medium text-txt-primary">{k.name}</div>
|
/>
|
||||||
<div className="text-xs text-txt-tertiary">
|
))}
|
||||||
{expired ? __("Expired") : __("Active")}
|
|
||||||
</div>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<span className="text-sm text-txt-secondary">
|
|
||||||
{k.lastUsedAt ? formatDate(k.lastUsedAt) : "—"}
|
|
||||||
</span>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<span className="text-sm text-txt-secondary">
|
|
||||||
{formatDate(k.createdAt)}
|
|
||||||
</span>
|
|
||||||
</Td>
|
|
||||||
<Td>
|
|
||||||
<span className="text-sm text-txt-secondary">
|
|
||||||
{formatDate(k.expiresAt)}
|
|
||||||
</span>
|
|
||||||
</Td>
|
|
||||||
<Td width={140} className="text-end">
|
|
||||||
<div className="flex gap-2 justify-end">
|
|
||||||
<Button
|
|
||||||
variant="secondary"
|
|
||||||
onClick={() => onShowToken({ id: k.id, name: k.name })}
|
|
||||||
disabled={!!isShowingToken}
|
|
||||||
>
|
|
||||||
{__("Show")}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="danger"
|
|
||||||
onClick={() => onRevoke({ id: k.id, name: k.name })}
|
|
||||||
>
|
|
||||||
{__("Revoke")}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</Td>
|
|
||||||
</Tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Tbody>
|
</Tbody>
|
||||||
</Table>
|
</Table>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -56,6 +56,21 @@ func (a *Asset) CursorKey(field AssetOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (a *Asset) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM assets WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, a.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query asset authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Asset) LoadByID(
|
func (a *Asset) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -60,6 +60,21 @@ func (a *Audit) CursorKey(field AuditOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (a *Audit) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM audits WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, a.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query audit authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *Audit) LoadByID(
|
func (a *Audit) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -17,16 +17,17 @@ package coredata
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5"
|
||||||
|
"go.gearno.de/kit/pg"
|
||||||
"go.probo.inc/probo/pkg/connector"
|
"go.probo.inc/probo/pkg/connector"
|
||||||
"go.probo.inc/probo/pkg/crypto/cipher"
|
"go.probo.inc/probo/pkg/crypto/cipher"
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
"go.probo.inc/probo/pkg/page"
|
"go.probo.inc/probo/pkg/page"
|
||||||
"github.com/jackc/pgx/v5"
|
|
||||||
"go.gearno.de/kit/pg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -56,6 +57,21 @@ func (c *Connector) CursorKey(orderBy ConnectorOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (c *Connector) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM connectors WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, c.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query connector authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Connectors) LoadByOrganizationID(
|
func (c *Connectors) LoadByOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.probo.inc/probo/pkg/gid"
|
|
||||||
"go.probo.inc/probo/pkg/page"
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
|
"go.probo.inc/probo/pkg/gid"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -63,6 +64,21 @@ func (ci *ContinualImprovement) CursorKey(field ContinualImprovementOrderField)
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (ci *ContinualImprovement) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM continual_improvements WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, ci.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query continual improvement authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ci *ContinualImprovement) LoadByID(
|
func (ci *ContinualImprovement) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -57,6 +57,21 @@ func (c Control) CursorKey(orderBy ControlOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (c *Control) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM controls WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, c.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query control authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Controls) CountByDocumentID(
|
func (c *Controls) CountByDocumentID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -65,6 +65,21 @@ func NewCustomDomain(tenantID gid.TenantID, domain string) *CustomDomain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (cd *CustomDomain) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM custom_domains WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, cd.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query custom domain authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (cd *CustomDomain) CursorKey(field CustomDomainOrderField) page.CursorKey {
|
func (cd *CustomDomain) CursorKey(field CustomDomainOrderField) page.CursorKey {
|
||||||
switch field {
|
switch field {
|
||||||
case CustomDomainOrderFieldCreatedAt:
|
case CustomDomainOrderFieldCreatedAt:
|
||||||
|
|||||||
@@ -69,6 +69,21 @@ func (dpia *DataProtectionImpactAssessment) CursorKey(field DataProtectionImpact
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (dpia *DataProtectionImpactAssessment) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM processing_activity_data_protection_impact_assessments WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, dpia.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query data protection impact assessment authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (dpias *DataProtectionImpactAssessments) CountByOrganizationID(
|
func (dpias *DataProtectionImpactAssessments) CountByOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.probo.inc/probo/pkg/gid"
|
|
||||||
"go.probo.inc/probo/pkg/page"
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
|
"go.probo.inc/probo/pkg/gid"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -59,6 +60,21 @@ func (d *Datum) CursorKey(field DatumOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (d *Datum) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM data WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, d.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query datum authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Datum) LoadByID(
|
func (d *Datum) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -58,6 +58,21 @@ func (p Document) CursorKey(orderBy DocumentOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (d *Document) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM documents WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, d.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query document authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Document) LoadByID(
|
func (p *Document) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -48,6 +48,21 @@ type (
|
|||||||
DocumentVersions []*DocumentVersion
|
DocumentVersions []*DocumentVersion
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (dv *DocumentVersion) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM document_versions WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, dv.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query document version authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *DocumentVersions) LoadByDocumentID(
|
func (p *DocumentVersions) LoadByDocumentID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -62,6 +62,21 @@ func (pvs DocumentVersionSignature) CursorKey(orderBy DocumentVersionSignatureOr
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (dvs *DocumentVersionSignature) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM document_version_signatures WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, dvs.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query document version signature authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (pvs *DocumentVersionSignature) LoadByDocumentVersionIDAndSignatory(
|
func (pvs *DocumentVersionSignature) LoadByDocumentVersionIDAndSignatory(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ var (
|
|||||||
ErrNoUnsentEmail = errors.New("no unsent email found")
|
ErrNoUnsentEmail = errors.New("no unsent email found")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
// Email is identity-scoped (not org-scoped), so it returns an empty map.
|
||||||
|
func (e *Email) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
return map[string]string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewEmail(
|
func NewEmail(
|
||||||
recipientName string,
|
recipientName string,
|
||||||
recipientEmail mail.Addr,
|
recipientEmail mail.Addr,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
package coredata
|
package coredata
|
||||||
|
|
||||||
|
import "go.probo.inc/probo/pkg/gid"
|
||||||
|
|
||||||
type ctxKey struct{ name string }
|
type ctxKey struct{ name string }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -75,6 +77,109 @@ const (
|
|||||||
MembershipProfileEntityType uint16 = 51
|
MembershipProfileEntityType uint16 = 51
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func NewEntityFromID(id gid.GID) (any, bool) {
|
||||||
|
switch id.EntityType() {
|
||||||
|
case OrganizationEntityType:
|
||||||
|
return &Organization{ID: id}, true
|
||||||
|
case FrameworkEntityType:
|
||||||
|
return &Framework{ID: id}, true
|
||||||
|
case MeasureEntityType:
|
||||||
|
return &Measure{ID: id}, true
|
||||||
|
case TaskEntityType:
|
||||||
|
return &Task{ID: id}, true
|
||||||
|
case EvidenceEntityType:
|
||||||
|
return &Evidence{ID: id}, true
|
||||||
|
case ConnectorEntityType:
|
||||||
|
return &Connector{ID: id}, true
|
||||||
|
case VendorRiskAssessmentEntityType:
|
||||||
|
return &VendorRiskAssessment{ID: id}, true
|
||||||
|
case VendorEntityType:
|
||||||
|
return &Vendor{ID: id}, true
|
||||||
|
case PeopleEntityType:
|
||||||
|
return &People{ID: id}, true
|
||||||
|
case VendorComplianceReportEntityType:
|
||||||
|
return &VendorComplianceReport{ID: id}, true
|
||||||
|
case DocumentEntityType:
|
||||||
|
return &Document{ID: id}, true
|
||||||
|
case IdentityEntityType:
|
||||||
|
return &Identity{ID: id}, true
|
||||||
|
case SessionEntityType:
|
||||||
|
return &Session{ID: id}, true
|
||||||
|
case EmailEntityType:
|
||||||
|
return &Email{ID: id}, true
|
||||||
|
case ControlEntityType:
|
||||||
|
return &Control{ID: id}, true
|
||||||
|
case RiskEntityType:
|
||||||
|
return &Risk{ID: id}, true
|
||||||
|
case DocumentVersionEntityType:
|
||||||
|
return &DocumentVersion{ID: id}, true
|
||||||
|
case DocumentVersionSignatureEntityType:
|
||||||
|
return &DocumentVersionSignature{ID: id}, true
|
||||||
|
case AssetEntityType:
|
||||||
|
return &Asset{ID: id}, true
|
||||||
|
case DatumEntityType:
|
||||||
|
return &Datum{ID: id}, true
|
||||||
|
case AuditEntityType:
|
||||||
|
return &Audit{ID: id}, true
|
||||||
|
case ReportEntityType:
|
||||||
|
return &Report{ID: id}, true
|
||||||
|
case TrustCenterEntityType:
|
||||||
|
return &TrustCenter{ID: id}, true
|
||||||
|
case TrustCenterAccessEntityType:
|
||||||
|
return &TrustCenterAccess{ID: id}, true
|
||||||
|
case VendorBusinessAssociateAgreementEntityType:
|
||||||
|
return &VendorBusinessAssociateAgreement{ID: id}, true
|
||||||
|
case FileEntityType:
|
||||||
|
return &File{ID: id}, true
|
||||||
|
case VendorContactEntityType:
|
||||||
|
return &VendorContact{ID: id}, true
|
||||||
|
case VendorDataPrivacyAgreementEntityType:
|
||||||
|
return &VendorDataPrivacyAgreement{ID: id}, true
|
||||||
|
case NonconformityEntityType:
|
||||||
|
return &Nonconformity{ID: id}, true
|
||||||
|
case ObligationEntityType:
|
||||||
|
return &Obligation{ID: id}, true
|
||||||
|
case VendorServiceEntityType:
|
||||||
|
return &VendorService{ID: id}, true
|
||||||
|
case SnapshotEntityType:
|
||||||
|
return &Snapshot{ID: id}, true
|
||||||
|
case ContinualImprovementEntityType:
|
||||||
|
return &ContinualImprovement{ID: id}, true
|
||||||
|
case ProcessingActivityEntityType:
|
||||||
|
return &ProcessingActivity{ID: id}, true
|
||||||
|
case ExportJobEntityType:
|
||||||
|
return &ExportJob{ID: id}, true
|
||||||
|
case TrustCenterReferenceEntityType:
|
||||||
|
return &TrustCenterReference{ID: id}, true
|
||||||
|
case TrustCenterDocumentAccessEntityType:
|
||||||
|
return &TrustCenterDocumentAccess{ID: id}, true
|
||||||
|
case CustomDomainEntityType:
|
||||||
|
return &CustomDomain{ID: id}, true
|
||||||
|
case InvitationEntityType:
|
||||||
|
return &Invitation{ID: id}, true
|
||||||
|
case MembershipEntityType:
|
||||||
|
return &Membership{ID: id}, true
|
||||||
|
case SlackMessageEntityType:
|
||||||
|
return &SlackMessage{ID: id}, true
|
||||||
|
case TrustCenterFileEntityType:
|
||||||
|
return &TrustCenterFile{ID: id}, true
|
||||||
|
case SAMLConfigurationEntityType:
|
||||||
|
return &SAMLConfiguration{ID: id}, true
|
||||||
|
case PersonalAPIKeyEntityType:
|
||||||
|
return &PersonalAPIKey{ID: id}, true
|
||||||
|
case MeetingEntityType:
|
||||||
|
return &Meeting{ID: id}, true
|
||||||
|
case DataProtectionImpactAssessmentEntityType:
|
||||||
|
return &DataProtectionImpactAssessment{ID: id}, true
|
||||||
|
case TransferImpactAssessmentEntityType:
|
||||||
|
return &TransferImpactAssessment{ID: id}, true
|
||||||
|
case MembershipProfileEntityType:
|
||||||
|
return &MembershipProfile{ID: id}, true
|
||||||
|
default:
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type EntityInfo struct {
|
type EntityInfo struct {
|
||||||
Model string
|
Model string
|
||||||
Table string
|
Table string
|
||||||
|
|||||||
@@ -56,6 +56,21 @@ func (e Evidence) CursorKey(orderBy EvidenceOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (e *Evidence) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM evidences WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, e.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query evidence authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e Evidence) Upsert(
|
func (e Evidence) Upsert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,18 +16,18 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
ExportJob struct {
|
ExportJob struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
OrganizationID gid.GID `db:"organization_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
Type ExportJobType `db:"type"`
|
Type ExportJobType `db:"type"`
|
||||||
Arguments json.RawMessage `db:"arguments"`
|
Arguments json.RawMessage `db:"arguments"`
|
||||||
Error *string `db:"error"`
|
Error *string `db:"error"`
|
||||||
Status ExportJobStatus `db:"status"`
|
Status ExportJobStatus `db:"status"`
|
||||||
FileID *gid.GID `db:"file_id"`
|
FileID *gid.GID `db:"file_id"`
|
||||||
RecipientEmail mail.Addr `db:"recipient_email"`
|
RecipientEmail mail.Addr `db:"recipient_email"`
|
||||||
RecipientName string `db:"recipient_name"`
|
RecipientName string `db:"recipient_name"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
StartedAt *time.Time `db:"started_at"`
|
StartedAt *time.Time `db:"started_at"`
|
||||||
CompletedAt *time.Time `db:"completed_at"`
|
CompletedAt *time.Time `db:"completed_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportJobs []*ExportJob
|
ExportJobs []*ExportJob
|
||||||
@@ -48,6 +48,21 @@ var (
|
|||||||
ErrNoExportJobAvailable = errors.New("no export job available")
|
ErrNoExportJobAvailable = errors.New("no export job available")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (ej *ExportJob) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM export_jobs WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, ej.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query export job authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (ej *ExportJob) Insert(
|
func (ej *ExportJob) Insert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -44,6 +44,21 @@ type (
|
|||||||
Files []*File
|
Files []*File
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (f *File) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM files WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, f.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query file authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *File) LoadByID(
|
func (f *File) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -53,6 +53,21 @@ func (f *Framework) CursorKey(orderBy FrameworkOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (f *Framework) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM frameworks WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, f.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query framework authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Frameworks) CountByOrganizationID(
|
func (f *Frameworks) CountByOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -220,6 +220,34 @@ LIMIT 1;
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes loads the minimal authorization attributes for policy condition evaluation.
|
||||||
|
// It is intentionally lightweight and does not populate the Identity struct.
|
||||||
|
func (i *Identity) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
email_address
|
||||||
|
FROM
|
||||||
|
identities
|
||||||
|
WHERE
|
||||||
|
id = $1
|
||||||
|
LIMIT 1;
|
||||||
|
`
|
||||||
|
|
||||||
|
var (
|
||||||
|
id gid.GID
|
||||||
|
emailAddress string
|
||||||
|
)
|
||||||
|
if err := conn.QueryRow(ctx, q, i.ID).Scan(&id, &emailAddress); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query identity iam attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"id": id.String(), "email": emailAddress}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Identity) Insert(
|
func (i *Identity) Insert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -164,6 +164,35 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes loads the minimal authorization attributes for policy condition evaluation.
|
||||||
|
// It is intentionally lightweight and does not populate the Invitation struct.
|
||||||
|
func (i *Invitation) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
email
|
||||||
|
, organization_id
|
||||||
|
FROM
|
||||||
|
iam_invitations
|
||||||
|
WHERE
|
||||||
|
id = $1
|
||||||
|
LIMIT 1;
|
||||||
|
`
|
||||||
|
|
||||||
|
var email string
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, i.ID).Scan(&email, &organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query invitation iam attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{
|
||||||
|
"email": email,
|
||||||
|
"organization_id": organizationID.String(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (i *Invitation) Update(ctx context.Context, conn pg.Conn, scope Scoper) error {
|
func (i *Invitation) Update(ctx context.Context, conn pg.Conn, scope Scoper) error {
|
||||||
query := `
|
query := `
|
||||||
UPDATE
|
UPDATE
|
||||||
|
|||||||
@@ -56,6 +56,21 @@ func (m Measure) CursorKey(orderBy MeasureOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (m *Measure) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM measures WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, m.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query measure authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Measures) CountByRiskID(
|
func (m *Measures) CountByRiskID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -54,6 +54,21 @@ func (m Meeting) CursorKey(orderBy MeetingOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes returns the authorization attributes for policy evaluation.
|
||||||
|
func (m *Meeting) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM meetings WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, m.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query meeting authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Meeting) LoadByID(
|
func (m *Meeting) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -226,6 +226,33 @@ LEFT JOIN
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Membership) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
identity_id
|
||||||
|
, organization_id
|
||||||
|
FROM
|
||||||
|
iam_memberships
|
||||||
|
WHERE
|
||||||
|
id = $1
|
||||||
|
LIMIT 1;
|
||||||
|
`
|
||||||
|
|
||||||
|
var identityID gid.GID
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, m.ID).Scan(&identityID, &organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query membership iam attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{
|
||||||
|
"identity_id": identityID.String(),
|
||||||
|
"organization_id": organizationID.String(),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func LoadRoleByIdentityAndEntityIDOnly(
|
func LoadRoleByIdentityAndEntityIDOnly(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
@@ -235,7 +262,6 @@ func LoadRoleByIdentityAndEntityIDOnly(
|
|||||||
) (MembershipRole, error) {
|
) (MembershipRole, error) {
|
||||||
entityType := entityID.EntityType()
|
entityType := entityID.EntityType()
|
||||||
|
|
||||||
// For organization, the entity ID is the organization ID - optimized path
|
|
||||||
if entityType == OrganizationEntityType {
|
if entityType == OrganizationEntityType {
|
||||||
query := `
|
query := `
|
||||||
SELECT role
|
SELECT role
|
||||||
@@ -595,3 +621,39 @@ WHERE
|
|||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Memberships) LoadAllByIdentityID(
|
||||||
|
ctx context.Context,
|
||||||
|
conn pg.Conn,
|
||||||
|
identityID gid.GID,
|
||||||
|
) error {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
identity_id,
|
||||||
|
organization_id,
|
||||||
|
role,
|
||||||
|
'' as full_name,
|
||||||
|
NULL as email_address,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
FROM
|
||||||
|
iam_memberships
|
||||||
|
WHERE
|
||||||
|
identity_id = $1
|
||||||
|
;
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := conn.Query(ctx, q, identityID)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot query memberships: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
memberships, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[Membership])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot collect memberships: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*m = memberships
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,20 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (p *MembershipProfile) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT m.organization_id FROM iam_membership_profiles mp JOIN iam_memberships m ON mp.membership_id = m.id WHERE mp.id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, p.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query membership profile authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *MembershipProfile) LoadByMembershipID(
|
func (p *MembershipProfile) LoadByMembershipID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.probo.inc/probo/pkg/gid"
|
|
||||||
"go.probo.inc/probo/pkg/page"
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
|
"go.probo.inc/probo/pkg/gid"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -66,6 +67,20 @@ func (nc *Nonconformity) CursorKey(field NonconformityOrderField) page.CursorKey
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (nc *Nonconformity) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM nonconformities WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, nc.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query nonconformity authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (nc *Nonconformity) LoadByID(
|
func (nc *Nonconformity) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
@@ -399,9 +414,9 @@ WHERE %s AND nc.organization_id = @organization_id AND nc.snapshot_id IS NULL
|
|||||||
query = fmt.Sprintf(query, scope.SQLFragment())
|
query = fmt.Sprintf(query, scope.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"tenant_id": scope.GetTenantID(),
|
"tenant_id": scope.GetTenantID(),
|
||||||
"snapshot_id": snapshotID,
|
"snapshot_id": snapshotID,
|
||||||
"organization_id": organizationID,
|
"organization_id": organizationID,
|
||||||
"nonconformity_entity_type": NonconformityEntityType,
|
"nonconformity_entity_type": NonconformityEntityType,
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
@@ -64,6 +65,20 @@ func (o *Obligation) CursorKey(field ObligationOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Obligation) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM obligations WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, o.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query obligation authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Obligation) LoadByID(
|
func (o *Obligation) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -46,6 +46,20 @@ type (
|
|||||||
Organizations []*Organization
|
Organizations []*Organization
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (o *Organization) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT id FROM organizations WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var id gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, o.ID).Scan(&id); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query organization authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": o.ID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (o Organization) CursorKey(orderBy OrganizationOrderField) page.CursorKey {
|
func (o Organization) CursorKey(orderBy OrganizationOrderField) page.CursorKey {
|
||||||
switch orderBy {
|
switch orderBy {
|
||||||
case OrganizationOrderFieldName:
|
case OrganizationOrderFieldName:
|
||||||
|
|||||||
@@ -60,6 +60,20 @@ func (p People) CursorKey(orderBy PeopleOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *People) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM peoples WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, p.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query people authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *People) LoadByID(
|
func (p *People) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -91,6 +91,20 @@ LIMIT 1;
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *PersonalAPIKey) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := "SELECT identity_id FROM iam_personal_api_keys WHERE id = $1 LIMIT 1;"
|
||||||
|
|
||||||
|
var identityID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, a.ID).Scan(&identityID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query personal api key iam attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"identity_id": identityID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *PersonalAPIKeys) LoadByIdentityID(
|
func (a *PersonalAPIKeys) LoadByIdentityID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
@@ -75,6 +76,20 @@ func (p *ProcessingActivity) CursorKey(field ProcessingActivityOrderField) page.
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProcessingActivity) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM processing_activities WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, p.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query processing activity authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *ProcessingActivity) LoadByID(
|
func (p *ProcessingActivity) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -42,6 +42,20 @@ type (
|
|||||||
Reports []*Report
|
Reports []*Report
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (r *Report) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM reports WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, r.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query report authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Report) LoadByID(
|
func (r *Report) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -80,6 +80,20 @@ func (r *Risk) CursorKey(orderBy RiskOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Risk) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM risks WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, r.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query risk authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Risks) CountByMeasureID(
|
func (r *Risks) CountByMeasureID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -63,6 +63,20 @@ func (s *SAMLConfiguration) CursorKey(orderBy SAMLConfigurationOrderField) page.
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SAMLConfiguration) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM iam_saml_configurations WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, s.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query saml configuration authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SAMLConfiguration) GetIdPCertificate() (*x509.Certificate, error) {
|
func (s *SAMLConfiguration) GetIdPCertificate() (*x509.Certificate, error) {
|
||||||
block, _ := pem.Decode([]byte(s.IdPCertificate))
|
block, _ := pem.Decode([]byte(s.IdPCertificate))
|
||||||
if block == nil {
|
if block == nil {
|
||||||
|
|||||||
@@ -140,6 +140,30 @@ LIMIT 1;
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizationAttributes loads the minimal authorization attributes for policy condition evaluation.
|
||||||
|
// It is intentionally lightweight and does not populate the Session struct.
|
||||||
|
func (s *Session) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `
|
||||||
|
SELECT
|
||||||
|
identity_id
|
||||||
|
FROM
|
||||||
|
iam_sessions
|
||||||
|
WHERE
|
||||||
|
id = $1
|
||||||
|
LIMIT 1;
|
||||||
|
`
|
||||||
|
|
||||||
|
var identityID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, s.ID).Scan(&identityID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query session iam attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"identity_id": identityID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Session) Insert(
|
func (s *Session) Insert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -29,19 +29,19 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
SlackMessage struct {
|
SlackMessage struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
OrganizationID gid.GID `db:"organization_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
Type SlackMessageType `db:"type"`
|
Type SlackMessageType `db:"type"`
|
||||||
Body map[string]any `db:"body"`
|
Body map[string]any `db:"body"`
|
||||||
MessageTS *string `db:"message_ts"`
|
MessageTS *string `db:"message_ts"`
|
||||||
ChannelID *string `db:"channel_id"`
|
ChannelID *string `db:"channel_id"`
|
||||||
RequesterEmail *mail.Addr `db:"requester_email"`
|
RequesterEmail *mail.Addr `db:"requester_email"`
|
||||||
Metadata map[string]any `db:"metadata"`
|
Metadata map[string]any `db:"metadata"`
|
||||||
InitialSlackMessageID gid.GID `db:"initial_slack_message_id"`
|
InitialSlackMessageID gid.GID `db:"initial_slack_message_id"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
UpdatedAt time.Time `db:"updated_at"`
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
SentAt *time.Time `db:"sent_at"`
|
SentAt *time.Time `db:"sent_at"`
|
||||||
Error *string `db:"error"`
|
Error *string `db:"error"`
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrNoUnsentSlackMessage struct{}
|
ErrNoUnsentSlackMessage struct{}
|
||||||
@@ -57,6 +57,20 @@ func (e ErrSlackMessageNotFound) Error() string {
|
|||||||
return "slack message not found"
|
return "slack message not found"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sm *SlackMessage) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM slack_messages WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, sm.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query slack message authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewSlackMessage(
|
func NewSlackMessage(
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
organizationID gid.GID,
|
organizationID gid.GID,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
@@ -52,6 +53,20 @@ func (s *Snapshot) CursorKey(field SnapshotOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Snapshot) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM snapshots WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, s.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query snapshot authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Snapshot) LoadByID(
|
func (s *Snapshot) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -57,6 +57,20 @@ func (c Task) CursorKey(orderBy TaskOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Task) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM tasks WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, t.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query task authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Task) LoadByID(
|
func (c *Task) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -69,6 +69,20 @@ func (tia *TransferImpactAssessment) CursorKey(field TransferImpactAssessmentOrd
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", field))
|
panic(fmt.Sprintf("unsupported order by: %s", field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tia *TransferImpactAssessment) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM processing_activity_transfer_impact_assessments WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, tia.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query transfer impact assessment authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tias *TransferImpactAssessments) CountByOrganizationID(
|
func (tias *TransferImpactAssessments) CountByOrganizationID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -52,6 +52,20 @@ func (tc *TrustCenter) CursorKey(orderBy TrustCenterOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tc *TrustCenter) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM trust_centers WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, tc.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query trust center authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tc *TrustCenter) LoadByID(
|
func (tc *TrustCenter) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -32,19 +32,19 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
TrustCenterAccess struct {
|
TrustCenterAccess struct {
|
||||||
ID gid.GID `db:"id"`
|
ID gid.GID `db:"id"`
|
||||||
OrganizationID gid.GID `db:"organization_id"`
|
OrganizationID gid.GID `db:"organization_id"`
|
||||||
TenantID gid.TenantID `db:"tenant_id"`
|
TenantID gid.TenantID `db:"tenant_id"`
|
||||||
TrustCenterID gid.GID `db:"trust_center_id"`
|
TrustCenterID gid.GID `db:"trust_center_id"`
|
||||||
Email mail.Addr `db:"email"`
|
Email mail.Addr `db:"email"`
|
||||||
Name string `db:"name"`
|
Name string `db:"name"`
|
||||||
Active bool `db:"active"`
|
Active bool `db:"active"`
|
||||||
HasAcceptedNonDisclosureAgreement bool `db:"has_accepted_non_disclosure_agreement"`
|
HasAcceptedNonDisclosureAgreement bool `db:"has_accepted_non_disclosure_agreement"`
|
||||||
HasAcceptedNonDisclosureAgreementMetadata json.RawMessage `db:"has_accepted_non_disclosure_agreement_metadata"`
|
HasAcceptedNonDisclosureAgreementMetadata json.RawMessage `db:"has_accepted_non_disclosure_agreement_metadata"`
|
||||||
NDAFileID *gid.GID `db:"nda_file_id"`
|
NDAFileID *gid.GID `db:"nda_file_id"`
|
||||||
CreatedAt time.Time `db:"created_at"`
|
CreatedAt time.Time `db:"created_at"`
|
||||||
UpdatedAt time.Time `db:"updated_at"`
|
UpdatedAt time.Time `db:"updated_at"`
|
||||||
LastTokenExpiresAt *time.Time `db:"last_token_expires_at"`
|
LastTokenExpiresAt *time.Time `db:"last_token_expires_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
TrustCenterAccesses []*TrustCenterAccess
|
TrustCenterAccesses []*TrustCenterAccess
|
||||||
@@ -59,6 +59,20 @@ func (tca *TrustCenterAccess) CursorKey(orderBy TrustCenterAccessOrderField) pag
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tca *TrustCenterAccess) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM trust_center_accesses WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, tca.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query trust center access authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tca *TrustCenterAccess) LoadByID(
|
func (tca *TrustCenterAccess) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -53,6 +53,20 @@ func (tcda *TrustCenterDocumentAccess) CursorKey(orderBy TrustCenterDocumentAcce
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tcda *TrustCenterDocumentAccess) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM trust_center_document_accesses WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, tcda.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query trust center document access authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tcda *TrustCenterDocumentAccess) LoadByID(
|
func (tcda *TrustCenterDocumentAccess) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
@@ -53,6 +54,20 @@ func (t TrustCenterFile) CursorKey(orderBy TrustCenterFileOrderField) page.Curso
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TrustCenterFile) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM trust_center_files WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, t.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query trust center file authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *TrustCenterFile) LoadByID(
|
func (t *TrustCenterFile) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -59,6 +59,20 @@ func (t TrustCenterReference) CursorKey(orderBy TrustCenterReferenceOrderField)
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *TrustCenterReference) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM trust_center_references WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, t.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query trust center reference authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (t *TrustCenterReference) LoadByID(
|
func (t *TrustCenterReference) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -78,6 +78,20 @@ func (v Vendor) CursorKey(orderBy VendorOrderField) page.CursorKey {
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *Vendor) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendors WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, v.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (v *Vendor) LoadByID(
|
func (v *Vendor) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -56,6 +56,20 @@ func (v VendorBusinessAssociateAgreement) CursorKey(orderBy VendorBusinessAssoci
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vbaa *VendorBusinessAssociateAgreement) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendor_business_associate_agreements WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, vbaa.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor business associate agreement authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vbaa *VendorBusinessAssociateAgreement) LoadByVendorID(
|
func (vbaa *VendorBusinessAssociateAgreement) LoadByVendorID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,14 +16,15 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.probo.inc/probo/pkg/gid"
|
|
||||||
"go.probo.inc/probo/pkg/page"
|
|
||||||
"github.com/jackc/pgx/v5"
|
"github.com/jackc/pgx/v5"
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
|
"go.probo.inc/probo/pkg/gid"
|
||||||
|
"go.probo.inc/probo/pkg/page"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -55,6 +56,20 @@ func (c VendorComplianceReport) CursorKey(orderBy VendorComplianceReportOrderFie
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *VendorComplianceReport) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendor_compliance_reports WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, v.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor compliance report authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vcs *VendorComplianceReports) LoadForVendorID(
|
func (vcs *VendorComplianceReports) LoadForVendorID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -59,6 +59,20 @@ func (vc VendorContact) CursorKey(orderBy VendorContactOrderField) page.CursorKe
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vc *VendorContact) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendor_contacts WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, vc.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor contact authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vc *VendorContact) LoadByID(
|
func (vc *VendorContact) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -56,6 +56,20 @@ func (v VendorDataPrivacyAgreement) CursorKey(orderBy VendorDataPrivacyAgreement
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vdpa *VendorDataPrivacyAgreement) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendor_data_privacy_agreements WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, vdpa.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor data privacy agreement authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vdpa *VendorDataPrivacyAgreement) LoadByVendorID(
|
func (vdpa *VendorDataPrivacyAgreement) LoadByVendorID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ package coredata
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
"time"
|
"time"
|
||||||
@@ -56,6 +57,20 @@ func (v VendorRiskAssessment) CursorKey(orderBy VendorRiskAssessmentOrderField)
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v *VendorRiskAssessment) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendor_risk_assessments WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, v.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor risk assessment authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Insert adds a new risk assessment to the database
|
// Insert adds a new risk assessment to the database
|
||||||
func (r VendorRiskAssessment) Insert(
|
func (r VendorRiskAssessment) Insert(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|||||||
@@ -54,6 +54,20 @@ func (vs VendorService) CursorKey(orderBy VendorServiceOrderField) page.CursorKe
|
|||||||
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
panic(fmt.Sprintf("unsupported order by: %s", orderBy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (vs *VendorService) AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error) {
|
||||||
|
q := `SELECT organization_id FROM vendor_services WHERE id = $1 LIMIT 1;`
|
||||||
|
|
||||||
|
var organizationID gid.GID
|
||||||
|
if err := conn.QueryRow(ctx, q, vs.ID).Scan(&organizationID); err != nil {
|
||||||
|
if errors.Is(err, pgx.ErrNoRows) {
|
||||||
|
return nil, ErrResourceNotFound
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("cannot query vendor service authorization attributes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return map[string]string{"organization_id": organizationID.String()}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (vs *VendorService) LoadByID(
|
func (vs *VendorService) LoadByID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Conn,
|
conn pg.Conn,
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ package iam
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
|
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
@@ -25,12 +25,28 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/iam/policy"
|
"go.probo.inc/probo/pkg/iam/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// AuthorizationAttributer is implemented by entities that provide attributes
|
||||||
|
// for policy condition evaluation.
|
||||||
|
type AuthorizationAttributer interface {
|
||||||
|
AuthorizationAttributes(ctx context.Context, conn pg.Conn) (map[string]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthorizeParams contains the parameters for an authorization request.
|
||||||
|
type AuthorizeParams struct {
|
||||||
|
Principal gid.GID
|
||||||
|
Resource gid.GID
|
||||||
|
Action string
|
||||||
|
ResourceAttributes map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authorizer evaluates authorization requests against registered policies.
|
||||||
type Authorizer struct {
|
type Authorizer struct {
|
||||||
pg *pg.Client
|
pg *pg.Client
|
||||||
evaluator *policy.Evaluator
|
evaluator *policy.Evaluator
|
||||||
policySet *PolicySet
|
policySet *PolicySet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAuthorizer creates a new Authorizer instance.
|
||||||
func NewAuthorizer(pgClient *pg.Client) *Authorizer {
|
func NewAuthorizer(pgClient *pg.Client) *Authorizer {
|
||||||
return &Authorizer{
|
return &Authorizer{
|
||||||
pg: pgClient,
|
pg: pgClient,
|
||||||
@@ -39,87 +55,144 @@ func NewAuthorizer(pgClient *pg.Client) *Authorizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Authorizer) RegisterPolicySet(policySet *PolicySet) {
|
// RegisterPolicySet merges the given policy set into the authorizer.
|
||||||
a.policySet.Merge(policySet)
|
func (a *Authorizer) RegisterPolicySet(ps *PolicySet) {
|
||||||
}
|
a.policySet.Merge(ps)
|
||||||
|
|
||||||
type AuthorizeParams struct {
|
|
||||||
Principal gid.GID
|
|
||||||
Resource gid.GID
|
|
||||||
Action string
|
|
||||||
ResourceAttributes map[string]string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Authorize checks if the principal is allowed to perform the action on the resource.
|
||||||
func (a *Authorizer) Authorize(ctx context.Context, params AuthorizeParams) error {
|
func (a *Authorizer) Authorize(ctx context.Context, params AuthorizeParams) error {
|
||||||
if params.Principal.EntityType() != coredata.IdentityEntityType {
|
if params.Principal.EntityType() != coredata.IdentityEntityType {
|
||||||
return NewUnsupportedPrincipalTypeError(params.Principal.EntityType())
|
return NewUnsupportedPrincipalTypeError(params.Principal.EntityType())
|
||||||
}
|
}
|
||||||
|
|
||||||
policies := a.buildPolicies(ctx, params)
|
return a.pg.WithConn(ctx, func(conn pg.Conn) error { return a.authorize(ctx, conn, params) })
|
||||||
|
}
|
||||||
|
|
||||||
// Pre-allocate Resource map with capacity for id + attributes
|
func (a *Authorizer) authorize(ctx context.Context, conn pg.Conn, params AuthorizeParams) error {
|
||||||
resourceAttrs := make(map[string]string, 1+len(params.ResourceAttributes))
|
memberships, err := a.loadMemberships(ctx, conn, params.Principal)
|
||||||
resourceAttrs["id"] = params.Resource.String()
|
if err != nil {
|
||||||
maps.Copy(resourceAttrs, params.ResourceAttributes)
|
return err
|
||||||
|
|
||||||
conditionCtx := policy.ConditionContext{
|
|
||||||
Principal: map[string]string{
|
|
||||||
"id": params.Principal.String(),
|
|
||||||
},
|
|
||||||
Resource: resourceAttrs,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resourceAttrs, err := a.buildResourceAttributes(ctx, conn, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find role for resource's organization
|
||||||
|
resourceOrgID := resourceAttrs["organization_id"]
|
||||||
|
role := findRoleForOrg(memberships, resourceOrgID)
|
||||||
|
|
||||||
|
// Only set principal.organization_id if they have a role in this org
|
||||||
|
var principalOrgID string
|
||||||
|
if role != "" {
|
||||||
|
principalOrgID = resourceOrgID
|
||||||
|
}
|
||||||
|
|
||||||
|
principalAttrs, err := a.buildPrincipalAttributes(ctx, conn, params.Principal, principalOrgID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
policies := a.buildPoliciesForRole(role)
|
||||||
|
|
||||||
req := policy.AuthorizationRequest{
|
req := policy.AuthorizationRequest{
|
||||||
Principal: params.Principal,
|
Principal: params.Principal,
|
||||||
Resource: params.Resource,
|
Resource: params.Resource,
|
||||||
Action: params.Action,
|
Action: params.Action,
|
||||||
ConditionContext: conditionCtx,
|
ConditionContext: policy.ConditionContext{
|
||||||
|
Principal: principalAttrs,
|
||||||
|
Resource: resourceAttrs,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
result := a.evaluator.Evaluate(req, policies)
|
if a.evaluator.Evaluate(req, policies).IsAllowed() {
|
||||||
|
|
||||||
if result.IsAllowed() {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewInsufficientPermissionsError(params.Principal, params.Resource, params.Action)
|
return NewInsufficientPermissionsError(params.Principal, params.Resource, params.Action)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Authorizer) buildPolicies(ctx context.Context, params AuthorizeParams) []*policy.Policy {
|
func (a *Authorizer) loadMemberships(ctx context.Context, conn pg.Conn, principalID gid.GID) (coredata.Memberships, error) {
|
||||||
selfManageCount := len(a.policySet.SelfManagePolicies)
|
var memberships coredata.Memberships
|
||||||
|
if err := memberships.LoadAllByIdentityID(ctx, conn, principalID); err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load memberships: %w", err)
|
||||||
|
}
|
||||||
|
return memberships, nil
|
||||||
|
}
|
||||||
|
|
||||||
var rolePolicies []*policy.Policy
|
func (a *Authorizer) buildPrincipalAttributes(
|
||||||
if params.Resource.TenantID() != gid.NilTenant {
|
ctx context.Context,
|
||||||
rolePolicies = a.loadRolePolicies(ctx, params.Principal, params.Resource)
|
conn pg.Conn,
|
||||||
|
principalID gid.GID,
|
||||||
|
organizationID string,
|
||||||
|
) (map[string]string, error) {
|
||||||
|
attrs := map[string]string{
|
||||||
|
"id": principalID.String(),
|
||||||
|
"organization_id": organizationID,
|
||||||
}
|
}
|
||||||
|
|
||||||
totalCount := selfManageCount + len(rolePolicies)
|
if entity, ok := coredata.NewEntityFromID(principalID); ok {
|
||||||
policies := make([]*policy.Policy, selfManageCount, totalCount)
|
if attributer, ok := entity.(AuthorizationAttributer); ok {
|
||||||
copy(policies, a.policySet.SelfManagePolicies)
|
entityAttrs, err := attributer.AuthorizationAttributes(ctx, conn)
|
||||||
policies = append(policies, rolePolicies...)
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load principal attributes: %w", err)
|
||||||
|
}
|
||||||
|
maps.Copy(attrs, entityAttrs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authorizer) buildResourceAttributes(
|
||||||
|
ctx context.Context,
|
||||||
|
conn pg.Conn,
|
||||||
|
params AuthorizeParams,
|
||||||
|
) (map[string]string, error) {
|
||||||
|
attrs := map[string]string{
|
||||||
|
"id": params.Resource.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
entity, ok := coredata.NewEntityFromID(params.Resource)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unsupported resource type: %d", params.Resource.EntityType())
|
||||||
|
}
|
||||||
|
|
||||||
|
attributer, ok := entity.(AuthorizationAttributer)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("resource %d does not implement AuthorizationAttributer", params.Resource.EntityType())
|
||||||
|
}
|
||||||
|
|
||||||
|
entityAttrs, err := attributer.AuthorizationAttributes(ctx, conn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot load resource attributes: %w", err)
|
||||||
|
}
|
||||||
|
maps.Copy(attrs, entityAttrs)
|
||||||
|
|
||||||
|
if params.ResourceAttributes != nil {
|
||||||
|
maps.Copy(attrs, params.ResourceAttributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authorizer) buildPoliciesForRole(role string) []*policy.Policy {
|
||||||
|
policies := append([]*policy.Policy{}, a.policySet.IdentityScopedPolicies...)
|
||||||
|
|
||||||
|
if role != "" {
|
||||||
|
policies = append(policies, a.policySet.RolePolicies[role]...)
|
||||||
|
}
|
||||||
|
|
||||||
return policies
|
return policies
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Authorizer) loadRolePolicies(ctx context.Context, principalID gid.GID, resourceID gid.GID) []*policy.Policy {
|
func findRoleForOrg(memberships coredata.Memberships, orgID string) string {
|
||||||
var role coredata.MembershipRole
|
for _, m := range memberships {
|
||||||
|
if m.OrganizationID.String() == orgID {
|
||||||
err := a.pg.WithConn(
|
return string(m.Role)
|
||||||
ctx,
|
}
|
||||||
func(conn pg.Conn) (err error) {
|
|
||||||
scope := coredata.NewScopeFromObjectID(resourceID)
|
|
||||||
role, err = coredata.LoadRoleByIdentityAndEntityIDOnly(ctx, conn, scope, principalID, resourceID)
|
|
||||||
if errors.Is(err, coredata.ErrResourceNotFound) {
|
|
||||||
return nil // No membership = no role-based policies
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil || role == "" {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
return a.policySet.RolePolicies[role.String()]
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ var IAMSelfManageSessionPolicy = policy.NewPolicy(
|
|||||||
ActionIAMSessionRevoke,
|
ActionIAMSessionRevoke,
|
||||||
ActionIAMSessionRevokeAll,
|
ActionIAMSessionRevokeAll,
|
||||||
).WithSID("manage-own-sessions").
|
).WithSID("manage-own-sessions").
|
||||||
When(policy.Equals("principal.id", "resource.user_id")),
|
When(policy.Equals("principal.id", "resource.identity_id")),
|
||||||
).WithDescription("Allows users to view and revoke their own sessions")
|
).WithDescription("Allows users to view and revoke their own sessions")
|
||||||
|
|
||||||
// IAMSelfManageInvitationPolicy allows users to manage invitations sent to them.
|
// IAMSelfManageInvitationPolicy allows users to manage invitations sent to them.
|
||||||
@@ -66,7 +66,7 @@ var IAMSelfManageInvitationPolicy = policy.NewPolicy(
|
|||||||
ActionIAMInvitationGet,
|
ActionIAMInvitationGet,
|
||||||
ActionIAMInvitationAccept,
|
ActionIAMInvitationAccept,
|
||||||
).WithSID("manage-own-invitations").
|
).WithSID("manage-own-invitations").
|
||||||
When(policy.Equals("principal.id", "resource.user_id")),
|
When(policy.Equals("principal.email", "resource.email")),
|
||||||
).WithDescription("Allows users to view and accept invitations sent to them")
|
).WithDescription("Allows users to view and accept invitations sent to them")
|
||||||
|
|
||||||
// IAMSelfManageMembershipPolicy allows users to view their own memberships.
|
// IAMSelfManageMembershipPolicy allows users to view their own memberships.
|
||||||
@@ -77,7 +77,7 @@ var IAMSelfManageMembershipPolicy = policy.NewPolicy(
|
|||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionIAMMembershipGet,
|
ActionIAMMembershipGet,
|
||||||
).WithSID("view-own-memberships").
|
).WithSID("view-own-memberships").
|
||||||
When(policy.Equals("principal.id", "resource.user_id")),
|
When(policy.Equals("principal.id", "resource.identity_id")),
|
||||||
).WithDescription("Allows users to view their organization memberships")
|
).WithDescription("Allows users to view their organization memberships")
|
||||||
|
|
||||||
// IAMSelfManagePersonalAPIKeyPolicy allows users to manage their own API keys.
|
// IAMSelfManagePersonalAPIKeyPolicy allows users to manage their own API keys.
|
||||||
@@ -91,7 +91,7 @@ var IAMSelfManagePersonalAPIKeyPolicy = policy.NewPolicy(
|
|||||||
ActionIAMPersonalAPIKeyUpdate,
|
ActionIAMPersonalAPIKeyUpdate,
|
||||||
ActionIAMPersonalAPIKeyDelete,
|
ActionIAMPersonalAPIKeyDelete,
|
||||||
).WithSID("manage-own-api-keys").
|
).WithSID("manage-own-api-keys").
|
||||||
When(policy.Equals("principal.id", "resource.user_id")),
|
When(policy.Equals("principal.id", "resource.identity_id")),
|
||||||
).WithDescription("Allows users to manage their own personal API keys")
|
).WithDescription("Allows users to manage their own personal API keys")
|
||||||
|
|
||||||
// IAMOwnerPolicy defines permissions for organization owners.
|
// IAMOwnerPolicy defines permissions for organization owners.
|
||||||
@@ -99,17 +99,20 @@ var IAMOwnerPolicy = policy.NewPolicy(
|
|||||||
"iam:owner",
|
"iam:owner",
|
||||||
"Organization Owner",
|
"Organization Owner",
|
||||||
// Full access to organization management
|
// Full access to organization management
|
||||||
policy.Allow("iam:organization:*").WithSID("full-org-access"),
|
policy.Allow("iam:organization:*").WithSID("full-org-access").When(policy.Equals("principal.organization_id", "resource.id")),
|
||||||
// Full access to member management
|
// Full access to member management (scoped to own organization)
|
||||||
policy.Allow("iam:membership:*").WithSID("full-membership-access"),
|
policy.Allow("iam:membership:*").WithSID("full-membership-access").
|
||||||
// Can manage invitations
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
|
// Can manage invitations (scoped to own organization)
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionIAMInvitationCreate,
|
ActionIAMInvitationCreate,
|
||||||
ActionIAMInvitationGet,
|
ActionIAMInvitationGet,
|
||||||
ActionIAMInvitationDelete,
|
ActionIAMInvitationDelete,
|
||||||
).WithSID("manage-invitations"),
|
).WithSID("manage-invitations").
|
||||||
// Full access to SAML configuration management
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
policy.Allow("iam:saml-configuration:*").WithSID("full-saml-access"),
|
// Full access to SAML configuration management (scoped to own organization)
|
||||||
|
policy.Allow("iam:saml-configuration:*").WithSID("full-saml-access").
|
||||||
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
).WithDescription("Full IAM access for organization owners")
|
).WithDescription("Full IAM access for organization owners")
|
||||||
|
|
||||||
// IAMAdminPolicy defines permissions for organization admins.
|
// IAMAdminPolicy defines permissions for organization admins.
|
||||||
@@ -123,19 +126,22 @@ var IAMAdminPolicy = policy.NewPolicy(
|
|||||||
ActionIAMOrganizationListMembers,
|
ActionIAMOrganizationListMembers,
|
||||||
ActionIAMOrganizationListInvitations,
|
ActionIAMOrganizationListInvitations,
|
||||||
ActionIAMOrganizationInviteMember,
|
ActionIAMOrganizationInviteMember,
|
||||||
).WithSID("org-admin-access"),
|
).WithSID("org-admin-access").When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
// Can manage memberships (but not remove owner)
|
// Can manage memberships (scoped to own organization)
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionIAMMembershipGet,
|
ActionIAMMembershipGet,
|
||||||
ActionIAMMembershipUpdate,
|
ActionIAMMembershipUpdate,
|
||||||
).WithSID("membership-admin-access"),
|
).WithSID("membership-admin-access").
|
||||||
// Can manage invitations
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
|
// Can manage invitations (scoped to own organization)
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionIAMInvitationGet,
|
ActionIAMInvitationGet,
|
||||||
ActionIAMInvitationDelete,
|
ActionIAMInvitationDelete,
|
||||||
).WithSID("invitation-admin-access"),
|
).WithSID("invitation-admin-access").
|
||||||
// Can view and update SAML configurations
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
policy.Allow(ActionIAMSAMLConfigurationGet).WithSID("saml-configuration-admin-access"),
|
// Can view SAML configurations (scoped to own organization)
|
||||||
|
policy.Allow(ActionIAMSAMLConfigurationGet).WithSID("saml-configuration-admin-access").
|
||||||
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
// Cannot delete organization
|
// Cannot delete organization
|
||||||
policy.Deny(ActionIAMOrganizationDelete).WithSID("deny-org-delete"),
|
policy.Deny(ActionIAMOrganizationDelete).WithSID("deny-org-delete"),
|
||||||
// Cannot remove members (only owner can)
|
// Cannot remove members (only owner can)
|
||||||
@@ -156,7 +162,8 @@ var IAMViewerPolicy = policy.NewPolicy(
|
|||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionIAMOrganizationGet,
|
ActionIAMOrganizationGet,
|
||||||
ActionIAMOrganizationListMembers,
|
ActionIAMOrganizationListMembers,
|
||||||
).WithSID("org-viewer-access"),
|
).WithSID("org-viewer-access").When(policy.Equals("principal.organization_id", "resource.id")),
|
||||||
// Can view memberships
|
// Can view memberships (scoped to own organization)
|
||||||
policy.Allow(ActionIAMMembershipGet).WithSID("membership-viewer-access"),
|
policy.Allow(ActionIAMMembershipGet).WithSID("membership-viewer-access").
|
||||||
|
When(policy.Equals("principal.organization_id", "resource.organization_id")),
|
||||||
).WithDescription("Read-only IAM access for organization viewers")
|
).WithDescription("Read-only IAM access for organization viewers")
|
||||||
|
|||||||
@@ -131,4 +131,3 @@ func ForEntityType(entityType uint16) ResourcePattern {
|
|||||||
EntityType: &entityType,
|
EntityType: &entityType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
package policy
|
package policy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"go.probo.inc/probo/pkg/gid"
|
"go.probo.inc/probo/pkg/gid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -139,7 +141,22 @@ func (c Condition) Evaluate(ctx ConditionContext) bool {
|
|||||||
case ConditionIn:
|
case ConditionIn:
|
||||||
for _, v := range c.Values {
|
for _, v := range c.Values {
|
||||||
resolved, ok := resolveValue(v, ctx)
|
resolved, ok := resolveValue(v, ctx)
|
||||||
if ok && value == resolved {
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support a comma-separated "set" value, e.g.
|
||||||
|
// principal.organization_ids = "org_1,org_2"
|
||||||
|
if strings.Contains(resolved, ",") {
|
||||||
|
for _, item := range strings.Split(resolved, ",") {
|
||||||
|
if value == strings.TrimSpace(item) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == resolved {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,7 +165,20 @@ func (c Condition) Evaluate(ctx ConditionContext) bool {
|
|||||||
case ConditionNotIn:
|
case ConditionNotIn:
|
||||||
for _, v := range c.Values {
|
for _, v := range c.Values {
|
||||||
resolved, ok := resolveValue(v, ctx)
|
resolved, ok := resolveValue(v, ctx)
|
||||||
if ok && value == resolved {
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(resolved, ",") {
|
||||||
|
for _, item := range strings.Split(resolved, ",") {
|
||||||
|
if value == strings.TrimSpace(item) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if value == resolved {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,15 +88,28 @@ func TestCondition_Evaluate_Equals(t *testing.T) {
|
|||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "equals - match resource.user_id reference",
|
name: "equals - match resource.identity_id reference",
|
||||||
condition: Condition{
|
condition: Condition{
|
||||||
Operator: ConditionEquals,
|
Operator: ConditionEquals,
|
||||||
Key: "principal.id",
|
Key: "principal.id",
|
||||||
Values: []string{"resource.user_id"},
|
Values: []string{"resource.identity_id"},
|
||||||
},
|
},
|
||||||
ctx: ConditionContext{
|
ctx: ConditionContext{
|
||||||
Principal: map[string]string{"id": "user_123"},
|
Principal: map[string]string{"id": "user_123"},
|
||||||
Resource: map[string]string{"user_id": "user_123"},
|
Resource: map[string]string{"identity_id": "user_123"},
|
||||||
|
},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "equals - match principal.email to resource.email reference",
|
||||||
|
condition: Condition{
|
||||||
|
Operator: ConditionEquals,
|
||||||
|
Key: "principal.email",
|
||||||
|
Values: []string{"resource.email"},
|
||||||
|
},
|
||||||
|
ctx: ConditionContext{
|
||||||
|
Principal: map[string]string{"email": "user@example.com"},
|
||||||
|
Resource: map[string]string{"email": "user@example.com"},
|
||||||
},
|
},
|
||||||
want: true,
|
want: true,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,21 +16,21 @@ package iam
|
|||||||
|
|
||||||
import "go.probo.inc/probo/pkg/iam/policy"
|
import "go.probo.inc/probo/pkg/iam/policy"
|
||||||
|
|
||||||
// PolicySet holds role-based and self-management policies.
|
// PolicySet holds organization-scoped (role) policies and identity-scoped policies.
|
||||||
// Services create their own PolicySet and combine them when creating the Authorizer.
|
// Services create their own PolicySet and combine them when creating the Authorizer.
|
||||||
type PolicySet struct {
|
type PolicySet struct {
|
||||||
// RolePolicies maps role names to policies.
|
// RolePolicies maps role names to policies.
|
||||||
RolePolicies map[string][]*policy.Policy
|
RolePolicies map[string][]*policy.Policy
|
||||||
|
|
||||||
// SelfManagePolicies are applied to all authenticated users.
|
// IdentityScopedPolicies are applied to all authenticated users, independent of organization membership.
|
||||||
SelfManagePolicies []*policy.Policy
|
IdentityScopedPolicies []*policy.Policy
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPolicySet creates an empty PolicySet.
|
// NewPolicySet creates an empty PolicySet.
|
||||||
func NewPolicySet() *PolicySet {
|
func NewPolicySet() *PolicySet {
|
||||||
return &PolicySet{
|
return &PolicySet{
|
||||||
RolePolicies: make(map[string][]*policy.Policy),
|
RolePolicies: make(map[string][]*policy.Policy),
|
||||||
SelfManagePolicies: make([]*policy.Policy, 0),
|
IdentityScopedPolicies: make([]*policy.Policy, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,9 +40,9 @@ func (ps *PolicySet) AddRolePolicy(role string, policies ...*policy.Policy) *Pol
|
|||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSelfManagePolicy adds policies applied to all authenticated users.
|
// AddIdentityScopedPolicy adds policies applied to all authenticated users (identity-scoped).
|
||||||
func (ps *PolicySet) AddSelfManagePolicy(policies ...*policy.Policy) *PolicySet {
|
func (ps *PolicySet) AddIdentityScopedPolicy(policies ...*policy.Policy) *PolicySet {
|
||||||
ps.SelfManagePolicies = append(ps.SelfManagePolicies, policies...)
|
ps.IdentityScopedPolicies = append(ps.IdentityScopedPolicies, policies...)
|
||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ func (ps *PolicySet) Merge(other *PolicySet) *PolicySet {
|
|||||||
for role, policies := range other.RolePolicies {
|
for role, policies := range other.RolePolicies {
|
||||||
ps.RolePolicies[role] = append(ps.RolePolicies[role], policies...)
|
ps.RolePolicies[role] = append(ps.RolePolicies[role], policies...)
|
||||||
}
|
}
|
||||||
ps.SelfManagePolicies = append(ps.SelfManagePolicies, other.SelfManagePolicies...)
|
ps.IdentityScopedPolicies = append(ps.IdentityScopedPolicies, other.IdentityScopedPolicies...)
|
||||||
return ps
|
return ps
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ func IAMPolicySet() *PolicySet {
|
|||||||
AddRolePolicy("VIEWER", IAMViewerPolicy).
|
AddRolePolicy("VIEWER", IAMViewerPolicy).
|
||||||
AddRolePolicy("EMPLOYEE", IAMViewerPolicy).
|
AddRolePolicy("EMPLOYEE", IAMViewerPolicy).
|
||||||
AddRolePolicy("AUDITOR", IAMViewerPolicy).
|
AddRolePolicy("AUDITOR", IAMViewerPolicy).
|
||||||
AddSelfManagePolicy(
|
AddIdentityScopedPolicy(
|
||||||
IAMSelfManageIdentityPolicy,
|
IAMSelfManageIdentityPolicy,
|
||||||
IAMSelfManageSessionPolicy,
|
IAMSelfManageSessionPolicy,
|
||||||
IAMSelfManageInvitationPolicy,
|
IAMSelfManageInvitationPolicy,
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ func TestPolicySet_AddAndMerge(t *testing.T) {
|
|||||||
iamPolicies := NewPolicySet().
|
iamPolicies := NewPolicySet().
|
||||||
AddRolePolicy("OWNER", policy.NewPolicy("iam-owner", "IAM Owner", policy.Allow("iam:*"))).
|
AddRolePolicy("OWNER", policy.NewPolicy("iam-owner", "IAM Owner", policy.Allow("iam:*"))).
|
||||||
AddRolePolicy("ADMIN", policy.NewPolicy("iam-admin", "IAM Admin", policy.Allow("iam:read:*"))).
|
AddRolePolicy("ADMIN", policy.NewPolicy("iam-admin", "IAM Admin", policy.Allow("iam:read:*"))).
|
||||||
AddSelfManagePolicy(policy.NewPolicy("iam-self", "IAM Self", policy.Allow("iam:identity:get")))
|
AddIdentityScopedPolicy(policy.NewPolicy("iam-self", "IAM Self", policy.Allow("iam:identity:get")))
|
||||||
|
|
||||||
// Create second policy set (simulating Documents service)
|
// Create second policy set (simulating Documents service)
|
||||||
docsPolicies := NewPolicySet().
|
docsPolicies := NewPolicySet().
|
||||||
AddRolePolicy("OWNER", policy.NewPolicy("docs-owner", "Docs Owner", policy.Allow("docs:*"))).
|
AddRolePolicy("OWNER", policy.NewPolicy("docs-owner", "Docs Owner", policy.Allow("docs:*"))).
|
||||||
AddRolePolicy("VIEWER", policy.NewPolicy("docs-viewer", "Docs Viewer", policy.Allow("docs:read:*"))).
|
AddRolePolicy("VIEWER", policy.NewPolicy("docs-viewer", "Docs Viewer", policy.Allow("docs:read:*"))).
|
||||||
AddSelfManagePolicy(policy.NewPolicy("docs-self", "Docs Self", policy.Allow("docs:own:*")))
|
AddIdentityScopedPolicy(policy.NewPolicy("docs-self", "Docs Self", policy.Allow("docs:own:*")))
|
||||||
|
|
||||||
// Merge them
|
// Merge them
|
||||||
combined := iamPolicies.Merge(docsPolicies)
|
combined := iamPolicies.Merge(docsPolicies)
|
||||||
@@ -53,8 +53,8 @@ func TestPolicySet_AddAndMerge(t *testing.T) {
|
|||||||
require.Len(t, viewerPolicies, 1, "should have 1 VIEWER policy")
|
require.Len(t, viewerPolicies, 1, "should have 1 VIEWER policy")
|
||||||
|
|
||||||
// Test self-manage policies from both services
|
// Test self-manage policies from both services
|
||||||
selfPolicies := combined.SelfManagePolicies
|
identityPolicies := combined.IdentityScopedPolicies
|
||||||
require.Len(t, selfPolicies, 2, "should have 2 self-manage policies")
|
require.Len(t, identityPolicies, 2, "should have 2 identity-scoped policies")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIAMPolicySet(t *testing.T) {
|
func TestIAMPolicySet(t *testing.T) {
|
||||||
@@ -69,5 +69,5 @@ func TestIAMPolicySet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should have self-manage policies
|
// Should have self-manage policies
|
||||||
assert.NotEmpty(t, policySet.SelfManagePolicies, "expected self-manage policies")
|
assert.NotEmpty(t, policySet.IdentityScopedPolicies, "expected identity-scoped policies")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,3 +247,28 @@ func (s *Service) GetSAMLconfiguration(ctx context.Context, samlConfigurationID
|
|||||||
|
|
||||||
return samlConfiguration, nil
|
return samlConfiguration, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetPersonalAPIKey(ctx context.Context, personalAPIKeyID gid.GID) (*coredata.PersonalAPIKey, error) {
|
||||||
|
personalAPIKey := &coredata.PersonalAPIKey{}
|
||||||
|
|
||||||
|
err := s.pg.WithConn(
|
||||||
|
ctx,
|
||||||
|
func(conn pg.Conn) error {
|
||||||
|
err := personalAPIKey.LoadByID(ctx, conn, personalAPIKeyID)
|
||||||
|
if err != nil {
|
||||||
|
if err == coredata.ErrResourceNotFound {
|
||||||
|
return NewPersonalAPIKeyNotFoundError(personalAPIKeyID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("cannot load personal API key: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return personalAPIKey, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,34 +19,32 @@ import (
|
|||||||
"go.probo.inc/probo/pkg/iam/policy"
|
"go.probo.inc/probo/pkg/iam/policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var organizationCondition = policy.Equals("principal.organization_id", "resource.organization_id")
|
||||||
|
|
||||||
// OwnerPolicy defines permissions for organization owners.
|
// OwnerPolicy defines permissions for organization owners.
|
||||||
var OwnerPolicy = policy.NewPolicy(
|
var OwnerPolicy = policy.NewPolicy(
|
||||||
"probo:owner",
|
"probo:owner",
|
||||||
"Probo Owner",
|
"Probo Owner",
|
||||||
// Full access to all probo resources
|
policy.Allow("core:*").WithSID("full-core-access").When(organizationCondition),
|
||||||
policy.Allow("core:*").WithSID("full-core-access"),
|
|
||||||
).WithDescription("Full probo access for organization owners")
|
).WithDescription("Full probo access for organization owners")
|
||||||
|
|
||||||
// AdminPolicy defines permissions for organization admins.
|
// AdminPolicy defines permissions for organization admins.
|
||||||
var AdminPolicy = policy.NewPolicy(
|
var AdminPolicy = policy.NewPolicy(
|
||||||
"probo:admin",
|
"probo:admin",
|
||||||
"Probo Admin",
|
"Probo Admin",
|
||||||
// Full access to all probo resources (same as owner for core entities)
|
policy.Allow("core:*").WithSID("full-core-access").When(organizationCondition),
|
||||||
policy.Allow("core:*").WithSID("full-c ore-access"),
|
|
||||||
).WithDescription("Probo admin access - can manage core entities")
|
).WithDescription("Probo admin access - can manage core entities")
|
||||||
|
|
||||||
// ViewerPolicy defines read-only permissions for organization viewers.
|
// ViewerPolicy defines read-only permissions for organization viewers.
|
||||||
var ViewerPolicy = policy.NewPolicy(
|
var ViewerPolicy = policy.NewPolicy(
|
||||||
"probo:viewer",
|
"probo:viewer",
|
||||||
"Probo Viewer",
|
"Probo Viewer",
|
||||||
// Organization read actions
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionOrganizationGet,
|
ActionOrganizationGet,
|
||||||
ActionOrganizationGetLogoUrl,
|
ActionOrganizationGetLogoUrl,
|
||||||
ActionOrganizationGetHorizontalLogoUrl,
|
ActionOrganizationGetHorizontalLogoUrl,
|
||||||
).WithSID("org-read-access"),
|
).WithSID("org-read-access").When(organizationCondition),
|
||||||
|
|
||||||
// Entity read actions
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionPeopleGet, ActionPeopleList,
|
ActionPeopleGet, ActionPeopleList,
|
||||||
ActionVendorGet, ActionVendorList,
|
ActionVendorGet, ActionVendorList,
|
||||||
@@ -79,42 +77,33 @@ var ViewerPolicy = policy.NewPolicy(
|
|||||||
ActionMeetingGet, ActionMeetingList,
|
ActionMeetingGet, ActionMeetingList,
|
||||||
ActionFileGet, ActionFileDownloadUrl,
|
ActionFileGet, ActionFileDownloadUrl,
|
||||||
ActionSlackConnectionList,
|
ActionSlackConnectionList,
|
||||||
).WithSID("entity-read-access"),
|
).WithSID("entity-read-access").When(organizationCondition),
|
||||||
|
|
||||||
// TrustCenter read actions
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionTrustCenterGet,
|
ActionTrustCenterGet,
|
||||||
ActionTrustCenterAccessGet, ActionTrustCenterAccessList,
|
ActionTrustCenterAccessGet, ActionTrustCenterAccessList,
|
||||||
ActionTrustCenterDocumentAccessList,
|
ActionTrustCenterDocumentAccessList,
|
||||||
ActionTrustCenterFileGet, ActionTrustCenterFileList, ActionTrustCenterFileGetFileUrl,
|
ActionTrustCenterFileGet, ActionTrustCenterFileList, ActionTrustCenterFileGetFileUrl,
|
||||||
ActionTrustCenterReferenceList, ActionTrustCenterReferenceGetLogoUrl,
|
ActionTrustCenterReferenceList, ActionTrustCenterReferenceGetLogoUrl,
|
||||||
).WithSID("trust-center-read-access"),
|
).WithSID("trust-center-read-access").When(organizationCondition),
|
||||||
|
|
||||||
// CustomDomain read actions
|
policy.Allow(ActionCustomDomainGet).WithSID("custom-domain-read").When(organizationCondition),
|
||||||
policy.Allow(ActionCustomDomainGet).WithSID("custom-domain-read"),
|
policy.Allow(ActionOrganizationContextGet).WithSID("organization-context-read").When(organizationCondition),
|
||||||
|
|
||||||
// OrganizationContext read actions
|
|
||||||
policy.Allow(ActionOrganizationContextGet).WithSID("organization-context-read"),
|
|
||||||
|
|
||||||
// Document signing actions
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionDocumentVersionExportPDF, ActionDocumentVersionExportSignable, ActionDocumentVersionSign,
|
ActionDocumentVersionExportPDF, ActionDocumentVersionExportSignable, ActionDocumentVersionSign,
|
||||||
).WithSID("document-signing"),
|
).WithSID("document-signing").When(organizationCondition),
|
||||||
).WithDescription("Read-only probo access for organization viewers")
|
).WithDescription("Read-only probo access for organization viewers")
|
||||||
|
|
||||||
// AuditorPolicy defines permissions for auditor role.
|
// AuditorPolicy defines permissions for auditor role.
|
||||||
// Auditors have read access to non-employee content plus some specific auditor features.
|
|
||||||
var AuditorPolicy = policy.NewPolicy(
|
var AuditorPolicy = policy.NewPolicy(
|
||||||
"probo:auditor",
|
"probo:auditor",
|
||||||
"Probo Auditor",
|
"Probo Auditor",
|
||||||
// Same as viewer but without employee-specific content
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionOrganizationGet,
|
ActionOrganizationGet,
|
||||||
ActionOrganizationGetLogoUrl,
|
ActionOrganizationGetLogoUrl,
|
||||||
ActionOrganizationGetHorizontalLogoUrl,
|
ActionOrganizationGetHorizontalLogoUrl,
|
||||||
).WithSID("org-read-access"),
|
).WithSID("org-read-access").When(organizationCondition),
|
||||||
|
|
||||||
// Entity read access (same as viewer)
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionPeopleGet, ActionPeopleList,
|
ActionPeopleGet, ActionPeopleList,
|
||||||
ActionVendorGet, ActionVendorList,
|
ActionVendorGet, ActionVendorList,
|
||||||
@@ -145,40 +134,34 @@ var AuditorPolicy = policy.NewPolicy(
|
|||||||
ActionSnapshotGet, ActionSnapshotList,
|
ActionSnapshotGet, ActionSnapshotList,
|
||||||
ActionMeetingGet, ActionMeetingList,
|
ActionMeetingGet, ActionMeetingList,
|
||||||
ActionFileGet, ActionFileDownloadUrl,
|
ActionFileGet, ActionFileDownloadUrl,
|
||||||
).WithSID("entity-read-access"),
|
).WithSID("entity-read-access").When(organizationCondition),
|
||||||
|
|
||||||
// Document signing actions
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionDocumentVersionExportPDF, ActionDocumentVersionExportSignable, ActionDocumentVersionSign,
|
ActionDocumentVersionExportPDF, ActionDocumentVersionExportSignable, ActionDocumentVersionSign,
|
||||||
).WithSID("document-signing"),
|
).WithSID("document-signing").When(organizationCondition),
|
||||||
).WithDescription("Read-only probo access for auditors (excludes internal/employee content)")
|
).WithDescription("Read-only probo access for auditors (excludes internal/employee content)")
|
||||||
|
|
||||||
// EmployeePolicy defines permissions for employee role.
|
// EmployeePolicy defines permissions for employee role.
|
||||||
// Employees have access to internal documents and some limited read access.
|
|
||||||
var EmployeePolicy = policy.NewPolicy(
|
var EmployeePolicy = policy.NewPolicy(
|
||||||
"probo:employee",
|
"probo:employee",
|
||||||
"Probo Employee",
|
"Probo Employee",
|
||||||
// Basic organization access
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionOrganizationGet,
|
ActionOrganizationGet,
|
||||||
ActionOrganizationGetLogoUrl,
|
ActionOrganizationGetLogoUrl,
|
||||||
).WithSID("org-basic-access"),
|
).WithSID("org-basic-access").When(organizationCondition),
|
||||||
|
|
||||||
// Document signing access
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionDocumentGet, ActionDocumentList,
|
ActionDocumentGet, ActionDocumentList,
|
||||||
).WithSID("document-signing-access"),
|
).WithSID("document-signing-access").When(organizationCondition),
|
||||||
|
|
||||||
// Document version signing
|
|
||||||
policy.Allow(
|
policy.Allow(
|
||||||
ActionDocumentVersionGet, ActionDocumentVersionList,
|
ActionDocumentVersionGet, ActionDocumentVersionList,
|
||||||
ActionDocumentVersionSign,
|
ActionDocumentVersionSign,
|
||||||
ActionDocumentVersionExportSignable,
|
ActionDocumentVersionExportSignable,
|
||||||
).WithSID("document-version-signing"),
|
).WithSID("document-version-signing").When(organizationCondition),
|
||||||
).WithDescription("Employee access - can sign documents and view internal content")
|
).WithDescription("Employee access - can sign documents and view internal content")
|
||||||
|
|
||||||
// ProboPolicySet returns the PolicySet for the probo service.
|
// ProboPolicySet returns the PolicySet for the probo service.
|
||||||
// This is registered with the IAM Authorizer when probo.Service is created.
|
|
||||||
func ProboPolicySet() *iam.PolicySet {
|
func ProboPolicySet() *iam.PolicySet {
|
||||||
return iam.NewPolicySet().
|
return iam.NewPolicySet().
|
||||||
AddRolePolicy("OWNER", OwnerPolicy).
|
AddRolePolicy("OWNER", OwnerPolicy).
|
||||||
|
|||||||
@@ -86,9 +86,6 @@ type Mutation {
|
|||||||
createPersonalAPIKey(
|
createPersonalAPIKey(
|
||||||
input: CreatePersonalAPIKeyInput!
|
input: CreatePersonalAPIKeyInput!
|
||||||
): CreatePersonalAPIKeyPayload @session(required: PRESENT)
|
): CreatePersonalAPIKeyPayload @session(required: PRESENT)
|
||||||
revealPersonalAPIKeyToken(
|
|
||||||
input: RevealPersonalAPIKeyTokenInput!
|
|
||||||
): RevealPersonalAPIKeyTokenPayload @session(required: PRESENT)
|
|
||||||
revokePersonalAPIKey(
|
revokePersonalAPIKey(
|
||||||
input: RevokePersonalAPIKeyInput!
|
input: RevokePersonalAPIKeyInput!
|
||||||
): RevokePersonalAPIKeyPayload @session(required: PRESENT)
|
): RevokePersonalAPIKeyPayload @session(required: PRESENT)
|
||||||
@@ -285,11 +282,10 @@ type Session implements Node {
|
|||||||
type PersonalAPIKey implements Node {
|
type PersonalAPIKey implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
lastUsedAt: Datetime
|
|
||||||
expiresAt: Datetime!
|
expiresAt: Datetime!
|
||||||
createdAt: Datetime!
|
createdAt: Datetime!
|
||||||
scopes: [TokenScope!]!
|
|
||||||
organizations: [Organization!]!
|
token: String @goField(forceResolver: true)
|
||||||
|
|
||||||
permission(action: String!): Boolean!
|
permission(action: String!): Boolean!
|
||||||
@goField(forceResolver: true)
|
@goField(forceResolver: true)
|
||||||
@@ -576,15 +572,10 @@ input RevokeSessionInput {
|
|||||||
input CreatePersonalAPIKeyInput {
|
input CreatePersonalAPIKeyInput {
|
||||||
name: String!
|
name: String!
|
||||||
expiresAt: Datetime!
|
expiresAt: Datetime!
|
||||||
organizationIds: [ID!]!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input RevokePersonalAPIKeyInput {
|
input RevokePersonalAPIKeyInput {
|
||||||
tokenId: ID!
|
personalAPIKeyId: ID!
|
||||||
}
|
|
||||||
|
|
||||||
input RevealPersonalAPIKeyTokenInput {
|
|
||||||
tokenId: ID!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input CreateOrganizationInput {
|
input CreateOrganizationInput {
|
||||||
@@ -751,11 +742,7 @@ type CreatePersonalAPIKeyPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RevokePersonalAPIKeyPayload {
|
type RevokePersonalAPIKeyPayload {
|
||||||
success: Boolean!
|
personalAPIKeyId: ID!
|
||||||
}
|
|
||||||
|
|
||||||
type RevealPersonalAPIKeyTokenPayload {
|
|
||||||
token: String!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateOrganizationPayload {
|
type CreateOrganizationPayload {
|
||||||
|
|||||||
@@ -218,7 +218,6 @@ type ComplexityRoot struct {
|
|||||||
InviteMember func(childComplexity int, input types.InviteMemberInput) int
|
InviteMember func(childComplexity int, input types.InviteMemberInput) int
|
||||||
RemoveMember func(childComplexity int, input types.RemoveMemberInput) int
|
RemoveMember func(childComplexity int, input types.RemoveMemberInput) int
|
||||||
ResetPassword func(childComplexity int, input types.ResetPasswordInput) int
|
ResetPassword func(childComplexity int, input types.ResetPasswordInput) int
|
||||||
RevealPersonalAPIKeyToken func(childComplexity int, input types.RevealPersonalAPIKeyTokenInput) int
|
|
||||||
RevokeAllSessions func(childComplexity int) int
|
RevokeAllSessions func(childComplexity int) int
|
||||||
RevokePersonalAPIKey func(childComplexity int, input types.RevokePersonalAPIKeyInput) int
|
RevokePersonalAPIKey func(childComplexity int, input types.RevokePersonalAPIKeyInput) int
|
||||||
RevokeSession func(childComplexity int, input types.RevokeSessionInput) int
|
RevokeSession func(childComplexity int, input types.RevokeSessionInput) int
|
||||||
@@ -267,14 +266,12 @@ type ComplexityRoot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PersonalAPIKey struct {
|
PersonalAPIKey struct {
|
||||||
CreatedAt func(childComplexity int) int
|
CreatedAt func(childComplexity int) int
|
||||||
ExpiresAt func(childComplexity int) int
|
ExpiresAt func(childComplexity int) int
|
||||||
ID func(childComplexity int) int
|
ID func(childComplexity int) int
|
||||||
LastUsedAt func(childComplexity int) int
|
Name func(childComplexity int) int
|
||||||
Name func(childComplexity int) int
|
Permission func(childComplexity int, action string) int
|
||||||
Organizations func(childComplexity int) int
|
Token func(childComplexity int) int
|
||||||
Permission func(childComplexity int, action string) int
|
|
||||||
Scopes func(childComplexity int) int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PersonalAPIKeyConnection struct {
|
PersonalAPIKeyConnection struct {
|
||||||
@@ -302,16 +299,12 @@ type ComplexityRoot struct {
|
|||||||
Success func(childComplexity int) int
|
Success func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
RevealPersonalAPIKeyTokenPayload struct {
|
|
||||||
Token func(childComplexity int) int
|
|
||||||
}
|
|
||||||
|
|
||||||
RevokeAllSessionsPayload struct {
|
RevokeAllSessionsPayload struct {
|
||||||
RevokedCount func(childComplexity int) int
|
RevokedCount func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
RevokePersonalAPIKeyPayload struct {
|
RevokePersonalAPIKeyPayload struct {
|
||||||
Success func(childComplexity int) int
|
PersonalAPIKeyID func(childComplexity int) int
|
||||||
}
|
}
|
||||||
|
|
||||||
RevokeSessionPayload struct {
|
RevokeSessionPayload struct {
|
||||||
@@ -462,7 +455,6 @@ type MutationResolver interface {
|
|||||||
RevokeSession(ctx context.Context, input types.RevokeSessionInput) (*types.RevokeSessionPayload, error)
|
RevokeSession(ctx context.Context, input types.RevokeSessionInput) (*types.RevokeSessionPayload, error)
|
||||||
RevokeAllSessions(ctx context.Context) (*types.RevokeAllSessionsPayload, error)
|
RevokeAllSessions(ctx context.Context) (*types.RevokeAllSessionsPayload, error)
|
||||||
CreatePersonalAPIKey(ctx context.Context, input types.CreatePersonalAPIKeyInput) (*types.CreatePersonalAPIKeyPayload, error)
|
CreatePersonalAPIKey(ctx context.Context, input types.CreatePersonalAPIKeyInput) (*types.CreatePersonalAPIKeyPayload, error)
|
||||||
RevealPersonalAPIKeyToken(ctx context.Context, input types.RevealPersonalAPIKeyTokenInput) (*types.RevealPersonalAPIKeyTokenPayload, error)
|
|
||||||
RevokePersonalAPIKey(ctx context.Context, input types.RevokePersonalAPIKeyInput) (*types.RevokePersonalAPIKeyPayload, error)
|
RevokePersonalAPIKey(ctx context.Context, input types.RevokePersonalAPIKeyInput) (*types.RevokePersonalAPIKeyPayload, error)
|
||||||
CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error)
|
CreateOrganization(ctx context.Context, input types.CreateOrganizationInput) (*types.CreateOrganizationPayload, error)
|
||||||
UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error)
|
UpdateOrganization(ctx context.Context, input types.UpdateOrganizationInput) (*types.UpdateOrganizationPayload, error)
|
||||||
@@ -488,6 +480,7 @@ type OrganizationResolver interface {
|
|||||||
Permission(ctx context.Context, obj *types.Organization, action string) (bool, error)
|
Permission(ctx context.Context, obj *types.Organization, action string) (bool, error)
|
||||||
}
|
}
|
||||||
type PersonalAPIKeyResolver interface {
|
type PersonalAPIKeyResolver interface {
|
||||||
|
Token(ctx context.Context, obj *types.PersonalAPIKey) (*string, error)
|
||||||
Permission(ctx context.Context, obj *types.PersonalAPIKey, action string) (bool, error)
|
Permission(ctx context.Context, obj *types.PersonalAPIKey, action string) (bool, error)
|
||||||
}
|
}
|
||||||
type PersonalAPIKeyConnectionResolver interface {
|
type PersonalAPIKeyConnectionResolver interface {
|
||||||
@@ -1146,17 +1139,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.Mutation.ResetPassword(childComplexity, args["input"].(types.ResetPasswordInput)), true
|
return e.complexity.Mutation.ResetPassword(childComplexity, args["input"].(types.ResetPasswordInput)), true
|
||||||
case "Mutation.revealPersonalAPIKeyToken":
|
|
||||||
if e.complexity.Mutation.RevealPersonalAPIKeyToken == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
args, err := ec.field_Mutation_revealPersonalAPIKeyToken_args(ctx, rawArgs)
|
|
||||||
if err != nil {
|
|
||||||
return 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.Mutation.RevealPersonalAPIKeyToken(childComplexity, args["input"].(types.RevealPersonalAPIKeyTokenInput)), true
|
|
||||||
case "Mutation.revokeAllSessions":
|
case "Mutation.revokeAllSessions":
|
||||||
if e.complexity.Mutation.RevokeAllSessions == nil {
|
if e.complexity.Mutation.RevokeAllSessions == nil {
|
||||||
break
|
break
|
||||||
@@ -1443,24 +1425,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.PersonalAPIKey.ID(childComplexity), true
|
return e.complexity.PersonalAPIKey.ID(childComplexity), true
|
||||||
case "PersonalAPIKey.lastUsedAt":
|
|
||||||
if e.complexity.PersonalAPIKey.LastUsedAt == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.PersonalAPIKey.LastUsedAt(childComplexity), true
|
|
||||||
case "PersonalAPIKey.name":
|
case "PersonalAPIKey.name":
|
||||||
if e.complexity.PersonalAPIKey.Name == nil {
|
if e.complexity.PersonalAPIKey.Name == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.PersonalAPIKey.Name(childComplexity), true
|
return e.complexity.PersonalAPIKey.Name(childComplexity), true
|
||||||
case "PersonalAPIKey.organizations":
|
|
||||||
if e.complexity.PersonalAPIKey.Organizations == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.PersonalAPIKey.Organizations(childComplexity), true
|
|
||||||
case "PersonalAPIKey.permission":
|
case "PersonalAPIKey.permission":
|
||||||
if e.complexity.PersonalAPIKey.Permission == nil {
|
if e.complexity.PersonalAPIKey.Permission == nil {
|
||||||
break
|
break
|
||||||
@@ -1472,12 +1442,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.PersonalAPIKey.Permission(childComplexity, args["action"].(string)), true
|
return e.complexity.PersonalAPIKey.Permission(childComplexity, args["action"].(string)), true
|
||||||
case "PersonalAPIKey.scopes":
|
case "PersonalAPIKey.token":
|
||||||
if e.complexity.PersonalAPIKey.Scopes == nil {
|
if e.complexity.PersonalAPIKey.Token == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.PersonalAPIKey.Scopes(childComplexity), true
|
return e.complexity.PersonalAPIKey.Token(childComplexity), true
|
||||||
|
|
||||||
case "PersonalAPIKeyConnection.edges":
|
case "PersonalAPIKeyConnection.edges":
|
||||||
if e.complexity.PersonalAPIKeyConnection.Edges == nil {
|
if e.complexity.PersonalAPIKeyConnection.Edges == nil {
|
||||||
@@ -1554,13 +1524,6 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.ResetPasswordPayload.Success(childComplexity), true
|
return e.complexity.ResetPasswordPayload.Success(childComplexity), true
|
||||||
|
|
||||||
case "RevealPersonalAPIKeyTokenPayload.token":
|
|
||||||
if e.complexity.RevealPersonalAPIKeyTokenPayload.Token == nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return e.complexity.RevealPersonalAPIKeyTokenPayload.Token(childComplexity), true
|
|
||||||
|
|
||||||
case "RevokeAllSessionsPayload.revokedCount":
|
case "RevokeAllSessionsPayload.revokedCount":
|
||||||
if e.complexity.RevokeAllSessionsPayload.RevokedCount == nil {
|
if e.complexity.RevokeAllSessionsPayload.RevokedCount == nil {
|
||||||
break
|
break
|
||||||
@@ -1568,12 +1531,12 @@ func (e *executableSchema) Complexity(ctx context.Context, typeName, field strin
|
|||||||
|
|
||||||
return e.complexity.RevokeAllSessionsPayload.RevokedCount(childComplexity), true
|
return e.complexity.RevokeAllSessionsPayload.RevokedCount(childComplexity), true
|
||||||
|
|
||||||
case "RevokePersonalAPIKeyPayload.success":
|
case "RevokePersonalAPIKeyPayload.personalAPIKeyId":
|
||||||
if e.complexity.RevokePersonalAPIKeyPayload.Success == nil {
|
if e.complexity.RevokePersonalAPIKeyPayload.PersonalAPIKeyID == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.complexity.RevokePersonalAPIKeyPayload.Success(childComplexity), true
|
return e.complexity.RevokePersonalAPIKeyPayload.PersonalAPIKeyID(childComplexity), true
|
||||||
|
|
||||||
case "RevokeSessionPayload.success":
|
case "RevokeSessionPayload.success":
|
||||||
if e.complexity.RevokeSessionPayload.Success == nil {
|
if e.complexity.RevokeSessionPayload.Success == nil {
|
||||||
@@ -1934,7 +1897,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler {
|
|||||||
ec.unmarshalInputMembershipOrder,
|
ec.unmarshalInputMembershipOrder,
|
||||||
ec.unmarshalInputRemoveMemberInput,
|
ec.unmarshalInputRemoveMemberInput,
|
||||||
ec.unmarshalInputResetPasswordInput,
|
ec.unmarshalInputResetPasswordInput,
|
||||||
ec.unmarshalInputRevealPersonalAPIKeyTokenInput,
|
|
||||||
ec.unmarshalInputRevokePersonalAPIKeyInput,
|
ec.unmarshalInputRevokePersonalAPIKeyInput,
|
||||||
ec.unmarshalInputRevokeSessionInput,
|
ec.unmarshalInputRevokeSessionInput,
|
||||||
ec.unmarshalInputSAMLAttributeMappingsInput,
|
ec.unmarshalInputSAMLAttributeMappingsInput,
|
||||||
@@ -2131,9 +2093,6 @@ type Mutation {
|
|||||||
createPersonalAPIKey(
|
createPersonalAPIKey(
|
||||||
input: CreatePersonalAPIKeyInput!
|
input: CreatePersonalAPIKeyInput!
|
||||||
): CreatePersonalAPIKeyPayload @session(required: PRESENT)
|
): CreatePersonalAPIKeyPayload @session(required: PRESENT)
|
||||||
revealPersonalAPIKeyToken(
|
|
||||||
input: RevealPersonalAPIKeyTokenInput!
|
|
||||||
): RevealPersonalAPIKeyTokenPayload @session(required: PRESENT)
|
|
||||||
revokePersonalAPIKey(
|
revokePersonalAPIKey(
|
||||||
input: RevokePersonalAPIKeyInput!
|
input: RevokePersonalAPIKeyInput!
|
||||||
): RevokePersonalAPIKeyPayload @session(required: PRESENT)
|
): RevokePersonalAPIKeyPayload @session(required: PRESENT)
|
||||||
@@ -2330,11 +2289,10 @@ type Session implements Node {
|
|||||||
type PersonalAPIKey implements Node {
|
type PersonalAPIKey implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
lastUsedAt: Datetime
|
|
||||||
expiresAt: Datetime!
|
expiresAt: Datetime!
|
||||||
createdAt: Datetime!
|
createdAt: Datetime!
|
||||||
scopes: [TokenScope!]!
|
|
||||||
organizations: [Organization!]!
|
token: String @goField(forceResolver: true)
|
||||||
|
|
||||||
permission(action: String!): Boolean!
|
permission(action: String!): Boolean!
|
||||||
@goField(forceResolver: true)
|
@goField(forceResolver: true)
|
||||||
@@ -2621,15 +2579,10 @@ input RevokeSessionInput {
|
|||||||
input CreatePersonalAPIKeyInput {
|
input CreatePersonalAPIKeyInput {
|
||||||
name: String!
|
name: String!
|
||||||
expiresAt: Datetime!
|
expiresAt: Datetime!
|
||||||
organizationIds: [ID!]!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input RevokePersonalAPIKeyInput {
|
input RevokePersonalAPIKeyInput {
|
||||||
tokenId: ID!
|
personalAPIKeyId: ID!
|
||||||
}
|
|
||||||
|
|
||||||
input RevealPersonalAPIKeyTokenInput {
|
|
||||||
tokenId: ID!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
input CreateOrganizationInput {
|
input CreateOrganizationInput {
|
||||||
@@ -2796,11 +2749,7 @@ type CreatePersonalAPIKeyPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RevokePersonalAPIKeyPayload {
|
type RevokePersonalAPIKeyPayload {
|
||||||
success: Boolean!
|
personalAPIKeyId: ID!
|
||||||
}
|
|
||||||
|
|
||||||
type RevealPersonalAPIKeyTokenPayload {
|
|
||||||
token: String!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateOrganizationPayload {
|
type CreateOrganizationPayload {
|
||||||
@@ -3198,17 +3147,6 @@ func (ec *executionContext) field_Mutation_resetPassword_args(ctx context.Contex
|
|||||||
return args, nil
|
return args, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_revealPersonalAPIKeyToken_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
|
||||||
var err error
|
|
||||||
args := map[string]any{}
|
|
||||||
arg0, err := graphql.ProcessArgField(ctx, rawArgs, "input", ec.unmarshalNRevealPersonalAPIKeyTokenInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevealPersonalAPIKeyTokenInput)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
args["input"] = arg0
|
|
||||||
return args, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) field_Mutation_revokePersonalAPIKey_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
func (ec *executionContext) field_Mutation_revokePersonalAPIKey_args(ctx context.Context, rawArgs map[string]any) (map[string]any, error) {
|
||||||
var err error
|
var err error
|
||||||
args := map[string]any{}
|
args := map[string]any{}
|
||||||
@@ -6734,69 +6672,6 @@ func (ec *executionContext) fieldContext_Mutation_createPersonalAPIKey(ctx conte
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_revealPersonalAPIKeyToken(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
|
||||||
return graphql.ResolveField(
|
|
||||||
ctx,
|
|
||||||
ec.OperationContext,
|
|
||||||
field,
|
|
||||||
ec.fieldContext_Mutation_revealPersonalAPIKeyToken,
|
|
||||||
func(ctx context.Context) (any, error) {
|
|
||||||
fc := graphql.GetFieldContext(ctx)
|
|
||||||
return ec.resolvers.Mutation().RevealPersonalAPIKeyToken(ctx, fc.Args["input"].(types.RevealPersonalAPIKeyTokenInput))
|
|
||||||
},
|
|
||||||
func(ctx context.Context, next graphql.Resolver) graphql.Resolver {
|
|
||||||
directive0 := next
|
|
||||||
|
|
||||||
directive1 := func(ctx context.Context) (any, error) {
|
|
||||||
required, err := ec.unmarshalNSessionRequirement2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐSessionRequirement(ctx, "PRESENT")
|
|
||||||
if err != nil {
|
|
||||||
var zeroVal *types.RevealPersonalAPIKeyTokenPayload
|
|
||||||
return zeroVal, err
|
|
||||||
}
|
|
||||||
if ec.directives.Session == nil {
|
|
||||||
var zeroVal *types.RevealPersonalAPIKeyTokenPayload
|
|
||||||
return zeroVal, errors.New("directive session is not implemented")
|
|
||||||
}
|
|
||||||
return ec.directives.Session(ctx, nil, directive0, required)
|
|
||||||
}
|
|
||||||
|
|
||||||
next = directive1
|
|
||||||
return next
|
|
||||||
},
|
|
||||||
ec.marshalORevealPersonalAPIKeyTokenPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevealPersonalAPIKeyTokenPayload,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_Mutation_revealPersonalAPIKeyToken(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
|
||||||
fc = &graphql.FieldContext{
|
|
||||||
Object: "Mutation",
|
|
||||||
Field: field,
|
|
||||||
IsMethod: true,
|
|
||||||
IsResolver: true,
|
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
|
||||||
switch field.Name {
|
|
||||||
case "token":
|
|
||||||
return ec.fieldContext_RevealPersonalAPIKeyTokenPayload_token(ctx, field)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("no field named %q was found under type RevealPersonalAPIKeyTokenPayload", field.Name)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err = ec.Recover(ctx, r)
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
ctx = graphql.WithFieldContext(ctx, fc)
|
|
||||||
if fc.Args, err = ec.field_Mutation_revealPersonalAPIKeyToken_args(ctx, field.ArgumentMap(ec.Variables)); err != nil {
|
|
||||||
ec.Error(ctx, err)
|
|
||||||
return fc, err
|
|
||||||
}
|
|
||||||
return fc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) _Mutation_revokePersonalAPIKey(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
func (ec *executionContext) _Mutation_revokePersonalAPIKey(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) {
|
||||||
return graphql.ResolveField(
|
return graphql.ResolveField(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -6840,8 +6715,8 @@ func (ec *executionContext) fieldContext_Mutation_revokePersonalAPIKey(ctx conte
|
|||||||
IsResolver: true,
|
IsResolver: true,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "success":
|
case "personalAPIKeyId":
|
||||||
return ec.fieldContext_RevokePersonalAPIKeyPayload_success(ctx, field)
|
return ec.fieldContext_RevokePersonalAPIKeyPayload_personalAPIKeyId(ctx, field)
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("no field named %q was found under type RevokePersonalAPIKeyPayload", field.Name)
|
return nil, fmt.Errorf("no field named %q was found under type RevokePersonalAPIKeyPayload", field.Name)
|
||||||
},
|
},
|
||||||
@@ -8440,35 +8315,6 @@ func (ec *executionContext) fieldContext_PersonalAPIKey_name(_ context.Context,
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _PersonalAPIKey_lastUsedAt(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) {
|
|
||||||
return graphql.ResolveField(
|
|
||||||
ctx,
|
|
||||||
ec.OperationContext,
|
|
||||||
field,
|
|
||||||
ec.fieldContext_PersonalAPIKey_lastUsedAt,
|
|
||||||
func(ctx context.Context) (any, error) {
|
|
||||||
return obj.LastUsedAt, nil
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
ec.marshalODatetime2ᚖtimeᚐTime,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_PersonalAPIKey_lastUsedAt(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
|
||||||
fc = &graphql.FieldContext{
|
|
||||||
Object: "PersonalAPIKey",
|
|
||||||
Field: field,
|
|
||||||
IsMethod: false,
|
|
||||||
IsResolver: false,
|
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
|
||||||
return nil, errors.New("field of type Datetime does not have child fields")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return fc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) _PersonalAPIKey_expiresAt(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) {
|
func (ec *executionContext) _PersonalAPIKey_expiresAt(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) {
|
||||||
return graphql.ResolveField(
|
return graphql.ResolveField(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -8527,91 +8373,30 @@ func (ec *executionContext) fieldContext_PersonalAPIKey_createdAt(_ context.Cont
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _PersonalAPIKey_scopes(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) {
|
func (ec *executionContext) _PersonalAPIKey_token(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) {
|
||||||
return graphql.ResolveField(
|
return graphql.ResolveField(
|
||||||
ctx,
|
ctx,
|
||||||
ec.OperationContext,
|
ec.OperationContext,
|
||||||
field,
|
field,
|
||||||
ec.fieldContext_PersonalAPIKey_scopes,
|
ec.fieldContext_PersonalAPIKey_token,
|
||||||
func(ctx context.Context) (any, error) {
|
func(ctx context.Context) (any, error) {
|
||||||
return obj.Scopes, nil
|
return ec.resolvers.PersonalAPIKey().Token(ctx, obj)
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
ec.marshalNTokenScope2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScopeᚄ,
|
ec.marshalOString2ᚖstring,
|
||||||
true,
|
|
||||||
true,
|
true,
|
||||||
|
false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_PersonalAPIKey_scopes(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
func (ec *executionContext) fieldContext_PersonalAPIKey_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
fc = &graphql.FieldContext{
|
fc = &graphql.FieldContext{
|
||||||
Object: "PersonalAPIKey",
|
Object: "PersonalAPIKey",
|
||||||
Field: field,
|
Field: field,
|
||||||
IsMethod: false,
|
IsMethod: true,
|
||||||
IsResolver: false,
|
IsResolver: true,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
return nil, errors.New("field of type TokenScope does not have child fields")
|
return nil, errors.New("field of type String does not have child fields")
|
||||||
},
|
|
||||||
}
|
|
||||||
return fc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) _PersonalAPIKey_organizations(ctx context.Context, field graphql.CollectedField, obj *types.PersonalAPIKey) (ret graphql.Marshaler) {
|
|
||||||
return graphql.ResolveField(
|
|
||||||
ctx,
|
|
||||||
ec.OperationContext,
|
|
||||||
field,
|
|
||||||
ec.fieldContext_PersonalAPIKey_organizations,
|
|
||||||
func(ctx context.Context) (any, error) {
|
|
||||||
return obj.Organizations, nil
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
ec.marshalNOrganization2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐOrganizationᚄ,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_PersonalAPIKey_organizations(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
|
||||||
fc = &graphql.FieldContext{
|
|
||||||
Object: "PersonalAPIKey",
|
|
||||||
Field: field,
|
|
||||||
IsMethod: false,
|
|
||||||
IsResolver: false,
|
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
|
||||||
switch field.Name {
|
|
||||||
case "id":
|
|
||||||
return ec.fieldContext_Organization_id(ctx, field)
|
|
||||||
case "name":
|
|
||||||
return ec.fieldContext_Organization_name(ctx, field)
|
|
||||||
case "logoUrl":
|
|
||||||
return ec.fieldContext_Organization_logoUrl(ctx, field)
|
|
||||||
case "horizontalLogoUrl":
|
|
||||||
return ec.fieldContext_Organization_horizontalLogoUrl(ctx, field)
|
|
||||||
case "email":
|
|
||||||
return ec.fieldContext_Organization_email(ctx, field)
|
|
||||||
case "description":
|
|
||||||
return ec.fieldContext_Organization_description(ctx, field)
|
|
||||||
case "websiteUrl":
|
|
||||||
return ec.fieldContext_Organization_websiteUrl(ctx, field)
|
|
||||||
case "headquarterAddress":
|
|
||||||
return ec.fieldContext_Organization_headquarterAddress(ctx, field)
|
|
||||||
case "createdAt":
|
|
||||||
return ec.fieldContext_Organization_createdAt(ctx, field)
|
|
||||||
case "updatedAt":
|
|
||||||
return ec.fieldContext_Organization_updatedAt(ctx, field)
|
|
||||||
case "members":
|
|
||||||
return ec.fieldContext_Organization_members(ctx, field)
|
|
||||||
case "invitations":
|
|
||||||
return ec.fieldContext_Organization_invitations(ctx, field)
|
|
||||||
case "samlConfigurations":
|
|
||||||
return ec.fieldContext_Organization_samlConfigurations(ctx, field)
|
|
||||||
case "viewerMembership":
|
|
||||||
return ec.fieldContext_Organization_viewerMembership(ctx, field)
|
|
||||||
case "permission":
|
|
||||||
return ec.fieldContext_Organization_permission(ctx, field)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return fc, nil
|
return fc, nil
|
||||||
@@ -8807,16 +8592,12 @@ func (ec *executionContext) fieldContext_PersonalAPIKeyEdge_node(_ context.Conte
|
|||||||
return ec.fieldContext_PersonalAPIKey_id(ctx, field)
|
return ec.fieldContext_PersonalAPIKey_id(ctx, field)
|
||||||
case "name":
|
case "name":
|
||||||
return ec.fieldContext_PersonalAPIKey_name(ctx, field)
|
return ec.fieldContext_PersonalAPIKey_name(ctx, field)
|
||||||
case "lastUsedAt":
|
|
||||||
return ec.fieldContext_PersonalAPIKey_lastUsedAt(ctx, field)
|
|
||||||
case "expiresAt":
|
case "expiresAt":
|
||||||
return ec.fieldContext_PersonalAPIKey_expiresAt(ctx, field)
|
return ec.fieldContext_PersonalAPIKey_expiresAt(ctx, field)
|
||||||
case "createdAt":
|
case "createdAt":
|
||||||
return ec.fieldContext_PersonalAPIKey_createdAt(ctx, field)
|
return ec.fieldContext_PersonalAPIKey_createdAt(ctx, field)
|
||||||
case "scopes":
|
case "token":
|
||||||
return ec.fieldContext_PersonalAPIKey_scopes(ctx, field)
|
return ec.fieldContext_PersonalAPIKey_token(ctx, field)
|
||||||
case "organizations":
|
|
||||||
return ec.fieldContext_PersonalAPIKey_organizations(ctx, field)
|
|
||||||
case "permission":
|
case "permission":
|
||||||
return ec.fieldContext_PersonalAPIKey_permission(ctx, field)
|
return ec.fieldContext_PersonalAPIKey_permission(ctx, field)
|
||||||
}
|
}
|
||||||
@@ -9218,35 +8999,6 @@ func (ec *executionContext) fieldContext_ResetPasswordPayload_success(_ context.
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _RevealPersonalAPIKeyTokenPayload_token(ctx context.Context, field graphql.CollectedField, obj *types.RevealPersonalAPIKeyTokenPayload) (ret graphql.Marshaler) {
|
|
||||||
return graphql.ResolveField(
|
|
||||||
ctx,
|
|
||||||
ec.OperationContext,
|
|
||||||
field,
|
|
||||||
ec.fieldContext_RevealPersonalAPIKeyTokenPayload_token,
|
|
||||||
func(ctx context.Context) (any, error) {
|
|
||||||
return obj.Token, nil
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
ec.marshalNString2string,
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_RevealPersonalAPIKeyTokenPayload_token(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
|
||||||
fc = &graphql.FieldContext{
|
|
||||||
Object: "RevealPersonalAPIKeyTokenPayload",
|
|
||||||
Field: field,
|
|
||||||
IsMethod: false,
|
|
||||||
IsResolver: false,
|
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
|
||||||
return nil, errors.New("field of type String does not have child fields")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
return fc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) _RevokeAllSessionsPayload_revokedCount(ctx context.Context, field graphql.CollectedField, obj *types.RevokeAllSessionsPayload) (ret graphql.Marshaler) {
|
func (ec *executionContext) _RevokeAllSessionsPayload_revokedCount(ctx context.Context, field graphql.CollectedField, obj *types.RevokeAllSessionsPayload) (ret graphql.Marshaler) {
|
||||||
return graphql.ResolveField(
|
return graphql.ResolveField(
|
||||||
ctx,
|
ctx,
|
||||||
@@ -9276,30 +9028,30 @@ func (ec *executionContext) fieldContext_RevokeAllSessionsPayload_revokedCount(_
|
|||||||
return fc, nil
|
return fc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) _RevokePersonalAPIKeyPayload_success(ctx context.Context, field graphql.CollectedField, obj *types.RevokePersonalAPIKeyPayload) (ret graphql.Marshaler) {
|
func (ec *executionContext) _RevokePersonalAPIKeyPayload_personalAPIKeyId(ctx context.Context, field graphql.CollectedField, obj *types.RevokePersonalAPIKeyPayload) (ret graphql.Marshaler) {
|
||||||
return graphql.ResolveField(
|
return graphql.ResolveField(
|
||||||
ctx,
|
ctx,
|
||||||
ec.OperationContext,
|
ec.OperationContext,
|
||||||
field,
|
field,
|
||||||
ec.fieldContext_RevokePersonalAPIKeyPayload_success,
|
ec.fieldContext_RevokePersonalAPIKeyPayload_personalAPIKeyId,
|
||||||
func(ctx context.Context) (any, error) {
|
func(ctx context.Context) (any, error) {
|
||||||
return obj.Success, nil
|
return obj.PersonalAPIKeyID, nil
|
||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
ec.marshalNBoolean2bool,
|
ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) fieldContext_RevokePersonalAPIKeyPayload_success(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
func (ec *executionContext) fieldContext_RevokePersonalAPIKeyPayload_personalAPIKeyId(_ context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) {
|
||||||
fc = &graphql.FieldContext{
|
fc = &graphql.FieldContext{
|
||||||
Object: "RevokePersonalAPIKeyPayload",
|
Object: "RevokePersonalAPIKeyPayload",
|
||||||
Field: field,
|
Field: field,
|
||||||
IsMethod: false,
|
IsMethod: false,
|
||||||
IsResolver: false,
|
IsResolver: false,
|
||||||
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) {
|
||||||
return nil, errors.New("field of type Boolean does not have child fields")
|
return nil, errors.New("field of type ID does not have child fields")
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return fc, nil
|
return fc, nil
|
||||||
@@ -12757,7 +12509,7 @@ func (ec *executionContext) unmarshalInputCreatePersonalAPIKeyInput(ctx context.
|
|||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"name", "expiresAt", "organizationIds"}
|
fieldsInOrder := [...]string{"name", "expiresAt"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -12778,13 +12530,6 @@ func (ec *executionContext) unmarshalInputCreatePersonalAPIKeyInput(ctx context.
|
|||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.ExpiresAt = data
|
it.ExpiresAt = data
|
||||||
case "organizationIds":
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationIds"))
|
|
||||||
data, err := ec.unmarshalNID2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGIDᚄ(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
it.OrganizationIds = data
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13200,33 +12945,6 @@ func (ec *executionContext) unmarshalInputResetPasswordInput(ctx context.Context
|
|||||||
return it, nil
|
return it, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputRevealPersonalAPIKeyTokenInput(ctx context.Context, obj any) (types.RevealPersonalAPIKeyTokenInput, error) {
|
|
||||||
var it types.RevealPersonalAPIKeyTokenInput
|
|
||||||
asMap := map[string]any{}
|
|
||||||
for k, v := range obj.(map[string]any) {
|
|
||||||
asMap[k] = v
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"tokenId"}
|
|
||||||
for _, k := range fieldsInOrder {
|
|
||||||
v, ok := asMap[k]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
switch k {
|
|
||||||
case "tokenId":
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tokenId"))
|
|
||||||
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
|
||||||
if err != nil {
|
|
||||||
return it, err
|
|
||||||
}
|
|
||||||
it.TokenID = data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return it, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalInputRevokePersonalAPIKeyInput(ctx context.Context, obj any) (types.RevokePersonalAPIKeyInput, error) {
|
func (ec *executionContext) unmarshalInputRevokePersonalAPIKeyInput(ctx context.Context, obj any) (types.RevokePersonalAPIKeyInput, error) {
|
||||||
var it types.RevokePersonalAPIKeyInput
|
var it types.RevokePersonalAPIKeyInput
|
||||||
asMap := map[string]any{}
|
asMap := map[string]any{}
|
||||||
@@ -13234,20 +12952,20 @@ func (ec *executionContext) unmarshalInputRevokePersonalAPIKeyInput(ctx context.
|
|||||||
asMap[k] = v
|
asMap[k] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsInOrder := [...]string{"tokenId"}
|
fieldsInOrder := [...]string{"personalAPIKeyId"}
|
||||||
for _, k := range fieldsInOrder {
|
for _, k := range fieldsInOrder {
|
||||||
v, ok := asMap[k]
|
v, ok := asMap[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch k {
|
switch k {
|
||||||
case "tokenId":
|
case "personalAPIKeyId":
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("tokenId"))
|
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("personalAPIKeyId"))
|
||||||
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
data, err := ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it, err
|
return it, err
|
||||||
}
|
}
|
||||||
it.TokenID = data
|
it.PersonalAPIKeyID = data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -15397,10 +15115,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet)
|
|||||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||||
return ec._Mutation_createPersonalAPIKey(ctx, field)
|
return ec._Mutation_createPersonalAPIKey(ctx, field)
|
||||||
})
|
})
|
||||||
case "revealPersonalAPIKeyToken":
|
|
||||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
|
||||||
return ec._Mutation_revealPersonalAPIKeyToken(ctx, field)
|
|
||||||
})
|
|
||||||
case "revokePersonalAPIKey":
|
case "revokePersonalAPIKey":
|
||||||
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) {
|
||||||
return ec._Mutation_revokePersonalAPIKey(ctx, field)
|
return ec._Mutation_revokePersonalAPIKey(ctx, field)
|
||||||
@@ -15927,8 +15641,6 @@ func (ec *executionContext) _PersonalAPIKey(ctx context.Context, sel ast.Selecti
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
atomic.AddUint32(&out.Invalids, 1)
|
atomic.AddUint32(&out.Invalids, 1)
|
||||||
}
|
}
|
||||||
case "lastUsedAt":
|
|
||||||
out.Values[i] = ec._PersonalAPIKey_lastUsedAt(ctx, field, obj)
|
|
||||||
case "expiresAt":
|
case "expiresAt":
|
||||||
out.Values[i] = ec._PersonalAPIKey_expiresAt(ctx, field, obj)
|
out.Values[i] = ec._PersonalAPIKey_expiresAt(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
@@ -15939,16 +15651,39 @@ func (ec *executionContext) _PersonalAPIKey(ctx context.Context, sel ast.Selecti
|
|||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
atomic.AddUint32(&out.Invalids, 1)
|
atomic.AddUint32(&out.Invalids, 1)
|
||||||
}
|
}
|
||||||
case "scopes":
|
case "token":
|
||||||
out.Values[i] = ec._PersonalAPIKey_scopes(ctx, field, obj)
|
field := field
|
||||||
if out.Values[i] == graphql.Null {
|
|
||||||
atomic.AddUint32(&out.Invalids, 1)
|
innerFunc := func(ctx context.Context, _ *graphql.FieldSet) (res graphql.Marshaler) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
ec.Error(ctx, ec.Recover(ctx, r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
res = ec._PersonalAPIKey_token(ctx, field, obj)
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
case "organizations":
|
|
||||||
out.Values[i] = ec._PersonalAPIKey_organizations(ctx, field, obj)
|
if field.Deferrable != nil {
|
||||||
if out.Values[i] == graphql.Null {
|
dfs, ok := deferred[field.Deferrable.Label]
|
||||||
atomic.AddUint32(&out.Invalids, 1)
|
di := 0
|
||||||
|
if ok {
|
||||||
|
dfs.AddField(field)
|
||||||
|
di = len(dfs.Values) - 1
|
||||||
|
} else {
|
||||||
|
dfs = graphql.NewFieldSet([]graphql.CollectedField{field})
|
||||||
|
deferred[field.Deferrable.Label] = dfs
|
||||||
|
}
|
||||||
|
dfs.Concurrently(di, func(ctx context.Context) graphql.Marshaler {
|
||||||
|
return innerFunc(ctx, dfs)
|
||||||
|
})
|
||||||
|
|
||||||
|
// don't run the out.Concurrently() call below
|
||||||
|
out.Values[i] = graphql.Null
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) })
|
||||||
case "permission":
|
case "permission":
|
||||||
field := field
|
field := field
|
||||||
|
|
||||||
@@ -16317,45 +16052,6 @@ func (ec *executionContext) _ResetPasswordPayload(ctx context.Context, sel ast.S
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
var revealPersonalAPIKeyTokenPayloadImplementors = []string{"RevealPersonalAPIKeyTokenPayload"}
|
|
||||||
|
|
||||||
func (ec *executionContext) _RevealPersonalAPIKeyTokenPayload(ctx context.Context, sel ast.SelectionSet, obj *types.RevealPersonalAPIKeyTokenPayload) graphql.Marshaler {
|
|
||||||
fields := graphql.CollectFields(ec.OperationContext, sel, revealPersonalAPIKeyTokenPayloadImplementors)
|
|
||||||
|
|
||||||
out := graphql.NewFieldSet(fields)
|
|
||||||
deferred := make(map[string]*graphql.FieldSet)
|
|
||||||
for i, field := range fields {
|
|
||||||
switch field.Name {
|
|
||||||
case "__typename":
|
|
||||||
out.Values[i] = graphql.MarshalString("RevealPersonalAPIKeyTokenPayload")
|
|
||||||
case "token":
|
|
||||||
out.Values[i] = ec._RevealPersonalAPIKeyTokenPayload_token(ctx, field, obj)
|
|
||||||
if out.Values[i] == graphql.Null {
|
|
||||||
out.Invalids++
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic("unknown field " + strconv.Quote(field.Name))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.Dispatch(ctx)
|
|
||||||
if out.Invalids > 0 {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
|
|
||||||
atomic.AddInt32(&ec.deferred, int32(len(deferred)))
|
|
||||||
|
|
||||||
for label, dfs := range deferred {
|
|
||||||
ec.processDeferredGroup(graphql.DeferredGroup{
|
|
||||||
Label: label,
|
|
||||||
Path: graphql.GetPath(ctx),
|
|
||||||
FieldSet: dfs,
|
|
||||||
Context: ctx,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
var revokeAllSessionsPayloadImplementors = []string{"RevokeAllSessionsPayload"}
|
var revokeAllSessionsPayloadImplementors = []string{"RevokeAllSessionsPayload"}
|
||||||
|
|
||||||
func (ec *executionContext) _RevokeAllSessionsPayload(ctx context.Context, sel ast.SelectionSet, obj *types.RevokeAllSessionsPayload) graphql.Marshaler {
|
func (ec *executionContext) _RevokeAllSessionsPayload(ctx context.Context, sel ast.SelectionSet, obj *types.RevokeAllSessionsPayload) graphql.Marshaler {
|
||||||
@@ -16406,8 +16102,8 @@ func (ec *executionContext) _RevokePersonalAPIKeyPayload(ctx context.Context, se
|
|||||||
switch field.Name {
|
switch field.Name {
|
||||||
case "__typename":
|
case "__typename":
|
||||||
out.Values[i] = graphql.MarshalString("RevokePersonalAPIKeyPayload")
|
out.Values[i] = graphql.MarshalString("RevokePersonalAPIKeyPayload")
|
||||||
case "success":
|
case "personalAPIKeyId":
|
||||||
out.Values[i] = ec._RevokePersonalAPIKeyPayload_success(ctx, field, obj)
|
out.Values[i] = ec._RevokePersonalAPIKeyPayload_personalAPIKeyId(ctx, field, obj)
|
||||||
if out.Values[i] == graphql.Null {
|
if out.Values[i] == graphql.Null {
|
||||||
out.Invalids++
|
out.Invalids++
|
||||||
}
|
}
|
||||||
@@ -18012,36 +17708,6 @@ func (ec *executionContext) marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGI
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNID2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGIDᚄ(ctx context.Context, v any) ([]gid.GID, error) {
|
|
||||||
var vSlice []any
|
|
||||||
vSlice = graphql.CoerceList(v)
|
|
||||||
var err error
|
|
||||||
res := make([]gid.GID, len(vSlice))
|
|
||||||
for i := range vSlice {
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
|
|
||||||
res[i], err = ec.unmarshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, vSlice[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) marshalNID2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋgidᚐGIDᚄ(ctx context.Context, sel ast.SelectionSet, v []gid.GID) graphql.Marshaler {
|
|
||||||
ret := make(graphql.Array, len(v))
|
|
||||||
for i := range v {
|
|
||||||
ret[i] = ec.marshalNID2goᚗproboᚗincᚋproboᚋpkgᚋgidᚐGID(ctx, sel, v[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, e := range ret {
|
|
||||||
if e == graphql.Null {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v any) (int, error) {
|
func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v any) (int, error) {
|
||||||
res, err := graphql.UnmarshalInt(v)
|
res, err := graphql.UnmarshalInt(v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
@@ -18345,50 +18011,6 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ec *executionContext) marshalNOrganization2ᚕᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐOrganizationᚄ(ctx context.Context, sel ast.SelectionSet, v []*types.Organization) graphql.Marshaler {
|
|
||||||
ret := make(graphql.Array, len(v))
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
isLen1 := len(v) == 1
|
|
||||||
if !isLen1 {
|
|
||||||
wg.Add(len(v))
|
|
||||||
}
|
|
||||||
for i := range v {
|
|
||||||
i := i
|
|
||||||
fc := &graphql.FieldContext{
|
|
||||||
Index: &i,
|
|
||||||
Result: &v[i],
|
|
||||||
}
|
|
||||||
ctx := graphql.WithFieldContext(ctx, fc)
|
|
||||||
f := func(i int) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
|
||||||
ret = nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if !isLen1 {
|
|
||||||
defer wg.Done()
|
|
||||||
}
|
|
||||||
ret[i] = ec.marshalNOrganization2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐOrganization(ctx, sel, v[i])
|
|
||||||
}
|
|
||||||
if isLen1 {
|
|
||||||
f(i)
|
|
||||||
} else {
|
|
||||||
go f(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
for _, e := range ret {
|
|
||||||
if e == graphql.Null {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) marshalNOrganization2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐOrganization(ctx context.Context, sel ast.SelectionSet, v *types.Organization) graphql.Marshaler {
|
func (ec *executionContext) marshalNOrganization2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐOrganization(ctx context.Context, sel ast.SelectionSet, v *types.Organization) graphql.Marshaler {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
|
||||||
@@ -18487,11 +18109,6 @@ func (ec *executionContext) unmarshalNResetPasswordInput2goᚗproboᚗincᚋprob
|
|||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNRevealPersonalAPIKeyTokenInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevealPersonalAPIKeyTokenInput(ctx context.Context, v any) (types.RevealPersonalAPIKeyTokenInput, error) {
|
|
||||||
res, err := ec.unmarshalInputRevealPersonalAPIKeyTokenInput(ctx, v)
|
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNRevokePersonalAPIKeyInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevokePersonalAPIKeyInput(ctx context.Context, v any) (types.RevokePersonalAPIKeyInput, error) {
|
func (ec *executionContext) unmarshalNRevokePersonalAPIKeyInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevokePersonalAPIKeyInput(ctx context.Context, v any) (types.RevokePersonalAPIKeyInput, error) {
|
||||||
res, err := ec.unmarshalInputRevokePersonalAPIKeyInput(ctx, v)
|
res, err := ec.unmarshalInputRevokePersonalAPIKeyInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
@@ -18769,75 +18386,6 @@ func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.S
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNTokenScope2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScope(ctx context.Context, v any) (types.TokenScope, error) {
|
|
||||||
var res types.TokenScope
|
|
||||||
err := res.UnmarshalGQL(v)
|
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) marshalNTokenScope2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScope(ctx context.Context, sel ast.SelectionSet, v types.TokenScope) graphql.Marshaler {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNTokenScope2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScopeᚄ(ctx context.Context, v any) ([]types.TokenScope, error) {
|
|
||||||
var vSlice []any
|
|
||||||
vSlice = graphql.CoerceList(v)
|
|
||||||
var err error
|
|
||||||
res := make([]types.TokenScope, len(vSlice))
|
|
||||||
for i := range vSlice {
|
|
||||||
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i))
|
|
||||||
res[i], err = ec.unmarshalNTokenScope2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScope(ctx, vSlice[i])
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) marshalNTokenScope2ᚕgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScopeᚄ(ctx context.Context, sel ast.SelectionSet, v []types.TokenScope) graphql.Marshaler {
|
|
||||||
ret := make(graphql.Array, len(v))
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
isLen1 := len(v) == 1
|
|
||||||
if !isLen1 {
|
|
||||||
wg.Add(len(v))
|
|
||||||
}
|
|
||||||
for i := range v {
|
|
||||||
i := i
|
|
||||||
fc := &graphql.FieldContext{
|
|
||||||
Index: &i,
|
|
||||||
Result: &v[i],
|
|
||||||
}
|
|
||||||
ctx := graphql.WithFieldContext(ctx, fc)
|
|
||||||
f := func(i int) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
ec.Error(ctx, ec.Recover(ctx, r))
|
|
||||||
ret = nil
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
if !isLen1 {
|
|
||||||
defer wg.Done()
|
|
||||||
}
|
|
||||||
ret[i] = ec.marshalNTokenScope2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐTokenScope(ctx, sel, v[i])
|
|
||||||
}
|
|
||||||
if isLen1 {
|
|
||||||
f(i)
|
|
||||||
} else {
|
|
||||||
go f(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
for _, e := range ret {
|
|
||||||
if e == graphql.Null {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) unmarshalNUpdateMembershipInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐUpdateMembershipInput(ctx context.Context, v any) (types.UpdateMembershipInput, error) {
|
func (ec *executionContext) unmarshalNUpdateMembershipInput2goᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐUpdateMembershipInput(ctx context.Context, v any) (types.UpdateMembershipInput, error) {
|
||||||
res, err := ec.unmarshalInputUpdateMembershipInput(ctx, v)
|
res, err := ec.unmarshalInputUpdateMembershipInput(ctx, v)
|
||||||
return res, graphql.ErrorOnPath(ctx, err)
|
return res, graphql.ErrorOnPath(ctx, err)
|
||||||
@@ -19436,13 +18984,6 @@ func (ec *executionContext) marshalOResetPasswordPayload2ᚖgoᚗproboᚗincᚋp
|
|||||||
return ec._ResetPasswordPayload(ctx, sel, v)
|
return ec._ResetPasswordPayload(ctx, sel, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ec *executionContext) marshalORevealPersonalAPIKeyTokenPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevealPersonalAPIKeyTokenPayload(ctx context.Context, sel ast.SelectionSet, v *types.RevealPersonalAPIKeyTokenPayload) graphql.Marshaler {
|
|
||||||
if v == nil {
|
|
||||||
return graphql.Null
|
|
||||||
}
|
|
||||||
return ec._RevealPersonalAPIKeyTokenPayload(ctx, sel, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ec *executionContext) marshalORevokeAllSessionsPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevokeAllSessionsPayload(ctx context.Context, sel ast.SelectionSet, v *types.RevokeAllSessionsPayload) graphql.Marshaler {
|
func (ec *executionContext) marshalORevokeAllSessionsPayload2ᚖgoᚗproboᚗincᚋproboᚋpkgᚋserverᚋapiᚋconnectᚋv1ᚋtypesᚐRevokeAllSessionsPayload(ctx context.Context, sel ast.SelectionSet, v *types.RevokeAllSessionsPayload) graphql.Marshaler {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return graphql.Null
|
return graphql.Null
|
||||||
|
|||||||
@@ -78,9 +78,8 @@ type CreateOrganizationPayload struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type CreatePersonalAPIKeyInput struct {
|
type CreatePersonalAPIKeyInput struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ExpiresAt time.Time `json:"expiresAt"`
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
OrganizationIds []gid.GID `json:"organizationIds"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreatePersonalAPIKeyPayload struct {
|
type CreatePersonalAPIKeyPayload struct {
|
||||||
@@ -273,14 +272,12 @@ type PasswordRequired struct {
|
|||||||
func (PasswordRequired) IsAssumeOrganizationSessionResult() {}
|
func (PasswordRequired) IsAssumeOrganizationSessionResult() {}
|
||||||
|
|
||||||
type PersonalAPIKey struct {
|
type PersonalAPIKey struct {
|
||||||
ID gid.GID `json:"id"`
|
ID gid.GID `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
LastUsedAt *time.Time `json:"lastUsedAt,omitempty"`
|
ExpiresAt time.Time `json:"expiresAt"`
|
||||||
ExpiresAt time.Time `json:"expiresAt"`
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
Token *string `json:"token,omitempty"`
|
||||||
Scopes []TokenScope `json:"scopes"`
|
Permission bool `json:"permission"`
|
||||||
Organizations []*Organization `json:"organizations"`
|
|
||||||
Permission bool `json:"permission"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (PersonalAPIKey) IsNode() {}
|
func (PersonalAPIKey) IsNode() {}
|
||||||
@@ -312,24 +309,16 @@ type ResetPasswordPayload struct {
|
|||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RevealPersonalAPIKeyTokenInput struct {
|
|
||||||
TokenID gid.GID `json:"tokenId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RevealPersonalAPIKeyTokenPayload struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RevokeAllSessionsPayload struct {
|
type RevokeAllSessionsPayload struct {
|
||||||
RevokedCount int `json:"revokedCount"`
|
RevokedCount int `json:"revokedCount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RevokePersonalAPIKeyInput struct {
|
type RevokePersonalAPIKeyInput struct {
|
||||||
TokenID gid.GID `json:"tokenId"`
|
PersonalAPIKeyID gid.GID `json:"personalAPIKeyId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RevokePersonalAPIKeyPayload struct {
|
type RevokePersonalAPIKeyPayload struct {
|
||||||
Success bool `json:"success"`
|
PersonalAPIKeyID gid.GID `json:"personalAPIKeyId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RevokeSessionInput struct {
|
type RevokeSessionInput struct {
|
||||||
|
|||||||
@@ -677,30 +677,17 @@ func (r *mutationResolver) CreatePersonalAPIKey(ctx context.Context, input types
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevealPersonalAPIKeyToken is the resolver for the revealPersonalAPIKeyToken field.
|
|
||||||
func (r *mutationResolver) RevealPersonalAPIKeyToken(ctx context.Context, input types.RevealPersonalAPIKeyTokenInput) (*types.RevealPersonalAPIKeyTokenPayload, error) {
|
|
||||||
identity := IdentityFromContext(ctx)
|
|
||||||
|
|
||||||
token, err := r.iam.AccountService.RevealPersonalAPIKeyToken(ctx, identity.ID, input.TokenID)
|
|
||||||
if err != nil {
|
|
||||||
r.logger.ErrorCtx(ctx, "cannot reveal personal api key token", log.Error(err))
|
|
||||||
return nil, gqlutils.InternalServerError(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &types.RevealPersonalAPIKeyTokenPayload{Token: token}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RevokePersonalAPIKey is the resolver for the revokePersonalAPIKey field.
|
// RevokePersonalAPIKey is the resolver for the revokePersonalAPIKey field.
|
||||||
func (r *mutationResolver) RevokePersonalAPIKey(ctx context.Context, input types.RevokePersonalAPIKeyInput) (*types.RevokePersonalAPIKeyPayload, error) {
|
func (r *mutationResolver) RevokePersonalAPIKey(ctx context.Context, input types.RevokePersonalAPIKeyInput) (*types.RevokePersonalAPIKeyPayload, error) {
|
||||||
identity := IdentityFromContext(ctx)
|
identity := IdentityFromContext(ctx)
|
||||||
|
|
||||||
err := r.iam.AccountService.DeletePersonalAPIKey(ctx, identity.ID, input.TokenID)
|
err := r.iam.AccountService.DeletePersonalAPIKey(ctx, identity.ID, input.PersonalAPIKeyID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.ErrorCtx(ctx, "cannot delete personal api key", log.Error(err))
|
r.logger.ErrorCtx(ctx, "cannot delete personal api key", log.Error(err))
|
||||||
return nil, gqlutils.InternalServerError(ctx)
|
return nil, gqlutils.InternalServerError(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.RevokePersonalAPIKeyPayload{Success: true}, nil
|
return &types.RevokePersonalAPIKeyPayload{PersonalAPIKeyID: input.PersonalAPIKeyID}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateOrganization is the resolver for the createOrganization field.
|
// CreateOrganization is the resolver for the createOrganization field.
|
||||||
@@ -1012,6 +999,15 @@ func (r *organizationResolver) HorizontalLogoURL(ctx context.Context, obj *types
|
|||||||
|
|
||||||
// Members is the resolver for the members field.
|
// Members is the resolver for the members field.
|
||||||
func (r *organizationResolver) Members(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MembershipOrderBy) (*types.MembershipConnection, error) {
|
func (r *organizationResolver) Members(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey, orderBy *types.MembershipOrderBy) (*types.MembershipConnection, error) {
|
||||||
|
if err := r.iam.Authorizer.Authorize(ctx, iam.AuthorizeParams{
|
||||||
|
Principal: IdentityFromContext(ctx).ID,
|
||||||
|
Resource: obj.ID,
|
||||||
|
Action: iam.ActionIAMOrganizationListMembers,
|
||||||
|
ResourceAttributes: map[string]string{},
|
||||||
|
}); err != nil {
|
||||||
|
return nil, gqlutils.Forbidden(err)
|
||||||
|
}
|
||||||
|
|
||||||
if gqlutils.OnlyTotalCountSelected(ctx) {
|
if gqlutils.OnlyTotalCountSelected(ctx) {
|
||||||
return &types.MembershipConnection{
|
return &types.MembershipConnection{
|
||||||
Resolver: r,
|
Resolver: r,
|
||||||
@@ -1112,6 +1108,19 @@ func (r *organizationResolver) Permission(ctx context.Context, obj *types.Organi
|
|||||||
return r.Resolver.Permission(ctx, obj, action)
|
return r.Resolver.Permission(ctx, obj, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Token is the resolver for the token field.
|
||||||
|
func (r *personalAPIKeyResolver) Token(ctx context.Context, obj *types.PersonalAPIKey) (*string, error) {
|
||||||
|
identity := IdentityFromContext(ctx)
|
||||||
|
|
||||||
|
token, err := r.iam.AccountService.RevealPersonalAPIKeyToken(ctx, identity.ID, obj.ID)
|
||||||
|
if err != nil {
|
||||||
|
r.logger.ErrorCtx(ctx, "cannot reveal personal api key token", log.Error(err))
|
||||||
|
return nil, gqlutils.InternalServerError(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &token, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Permission is the resolver for the permission field.
|
// Permission is the resolver for the permission field.
|
||||||
func (r *personalAPIKeyResolver) Permission(ctx context.Context, obj *types.PersonalAPIKey, action string) (bool, error) {
|
func (r *personalAPIKeyResolver) Permission(ctx context.Context, obj *types.PersonalAPIKey, action string) (bool, error) {
|
||||||
return r.Resolver.Permission(ctx, obj, action)
|
return r.Resolver.Permission(ctx, obj, action)
|
||||||
@@ -1202,6 +1211,15 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
|||||||
|
|
||||||
return types.NewSAMLConfiguration(samlConfiguration), nil
|
return types.NewSAMLConfiguration(samlConfiguration), nil
|
||||||
}
|
}
|
||||||
|
case coredata.PersonalAPIKeyEntityType:
|
||||||
|
action = iam.ActionIAMPersonalAPIKeyGet
|
||||||
|
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||||
|
personalAPIKey, err := r.iam.GetPersonalAPIKey(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return types.NewPersonalAPIKey(personalAPIKey), nil
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported entity type: %d", id.EntityType())
|
return nil, fmt.Errorf("unsupported entity type: %d", id.EntityType())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user