@aifabrix/builder 2.45.0 → 2.45.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/docs-rules.mdc +3 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
- package/jest.projects.js +44 -1
- package/lib/api/agent-metadata-validation.api.js +93 -0
- package/lib/api/audit-api-helpers.js +68 -0
- package/lib/api/audit.api.js +119 -0
- package/lib/api/auth-cache.api.js +44 -0
- package/lib/api/certificates.api.js +4 -4
- package/lib/api/credential.api.js +2 -2
- package/lib/api/dataplane-health.api.js +137 -0
- package/lib/api/dataplane-sync.api.js +27 -0
- package/lib/api/datasources-core.api.js +21 -18
- package/lib/api/datasources-extended.api.js +22 -22
- package/lib/api/dimensions.api.js +3 -0
- package/lib/api/external-systems.api.js +13 -13
- package/lib/api/governance-scenarios.api.js +39 -0
- package/lib/api/groups.api.js +79 -0
- package/lib/api/index.js +45 -2
- package/lib/api/pipeline.api.js +4 -4
- package/lib/api/protection.api.js +157 -0
- package/lib/api/records-bulk.api.js +30 -0
- package/lib/api/records-search-parse.js +49 -0
- package/lib/api/records-search.api.js +29 -0
- package/lib/api/types/agent-metadata-validation.types.js +67 -0
- package/lib/api/types/audit.types.js +72 -0
- package/lib/api/types/dataplane-health.types.js +27 -0
- package/lib/api/types/dimensions.types.js +2 -0
- package/lib/api/types/governance-scenarios.types.js +39 -0
- package/lib/api/types/protection.types.js +69 -0
- package/lib/api/types/records-bulk.types.js +35 -0
- package/lib/api/types/records-search.types.js +28 -0
- package/lib/api/user-groups.api.js +50 -0
- package/lib/api/users.api.js +95 -0
- package/lib/api/validation-run.api.js +3 -3
- package/lib/api/validation-runner.js +3 -3
- package/lib/api/wizard-platform.api.js +3 -3
- package/lib/api/wizard.api.js +21 -21
- package/lib/app/deploy.js +34 -19
- package/lib/cli/index.js +4 -2
- package/lib/cli/infra-guided.js +22 -3
- package/lib/cli/setup-app.help.js +50 -2
- package/lib/cli/setup-app.js +33 -24
- package/lib/cli/setup-app.test-commands.js +80 -21
- package/lib/cli/setup-auth.js +30 -3
- package/lib/cli/setup-external-system.js +37 -3
- package/lib/cli/setup-utility-help-after.js +45 -0
- package/lib/cli/setup-utility-resolve.js +2 -2
- package/lib/cli/setup-utility.js +99 -81
- package/lib/commands/auth-status-dataplane-version.js +231 -0
- package/lib/commands/auth-status-display.js +94 -0
- package/lib/commands/auth-status.js +70 -6
- package/lib/commands/credential-push.js +10 -5
- package/lib/commands/datasource-load-export-cli.js +178 -0
- package/lib/commands/datasource-test-trust-cli.js +114 -0
- package/lib/commands/datasource-unified-test-cli.js +25 -17
- package/lib/commands/datasource-unified-test-cli.options.js +18 -3
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
- package/lib/commands/datasource-verify-audit-cli.js +96 -0
- package/lib/commands/datasource.js +68 -1
- package/lib/commands/dimension-value.js +43 -13
- package/lib/commands/dimension.js +38 -7
- package/lib/commands/identity-apply-sync.js +131 -0
- package/lib/commands/identity-group-cli.js +146 -0
- package/lib/commands/identity-membership-role-cache.js +175 -0
- package/lib/commands/identity-shared.js +94 -0
- package/lib/commands/identity-user-cli.js +158 -0
- package/lib/commands/identity.js +43 -0
- package/lib/commands/login.js +46 -16
- package/lib/commands/protection-cli-leaves.js +286 -0
- package/lib/commands/protection.js +50 -0
- package/lib/commands/repair.js +13 -3
- package/lib/commands/test-e2e-external.js +40 -9
- package/lib/commands/test-governance-cli-options.js +47 -0
- package/lib/commands/test-governance-command-action.js +55 -0
- package/lib/commands/test-governance-external.js +88 -0
- package/lib/commands/test-trust-cli-options.js +32 -0
- package/lib/commands/test-trust-command-action.js +118 -0
- package/lib/commands/test-trust-external.js +127 -0
- package/lib/commands/upload.js +34 -13
- package/lib/commands/wizard-core.js +3 -0
- package/lib/core/config-device-dataplane.js +185 -0
- package/lib/datasource/agent-trust-debug-log.js +45 -0
- package/lib/datasource/agent-trust-fetch.js +115 -0
- package/lib/datasource/agent-trust-map.js +101 -0
- package/lib/datasource/agent-trust-mock.js +44 -0
- package/lib/datasource/agent-trust-run.js +93 -0
- package/lib/datasource/agent-trust-timeout.js +25 -0
- package/lib/datasource/audit-evidence-display.js +80 -0
- package/lib/datasource/audit-evidence-extract-debug.js +103 -0
- package/lib/datasource/audit-evidence-extract.js +177 -0
- package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
- package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
- package/lib/datasource/audit-evidence-poll.js +109 -0
- package/lib/datasource/audit-evidence-run.js +177 -0
- package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
- package/lib/datasource/audit-evidence-verify-matrix.js +177 -0
- package/lib/datasource/audit-evidence-verify.js +108 -0
- package/lib/datasource/bulk-loader-run-batches.js +88 -0
- package/lib/datasource/bulk-loader-service-retry.js +52 -0
- package/lib/datasource/bulk-loader-service.js +127 -0
- package/lib/datasource/capability/run-capability-dimension.js +2 -1
- package/lib/datasource/datasource-exporter-resolve.js +82 -0
- package/lib/datasource/datasource-exporter-service.js +144 -0
- package/lib/datasource/datasource-identifier.js +148 -0
- package/lib/datasource/datasource-load-export-context.js +92 -0
- package/lib/datasource/integration-context.js +6 -4
- package/lib/datasource/local-data-paths.js +145 -0
- package/lib/datasource/log-cleaner.js +241 -0
- package/lib/datasource/log-viewer.js +111 -6
- package/lib/datasource/record-file-parser.js +85 -0
- package/lib/datasource/record-mapper.js +129 -0
- package/lib/datasource/resolve-app.js +74 -55
- package/lib/datasource/test-e2e.js +26 -2
- package/lib/datasource/unified-validation-run-resolve.js +45 -12
- package/lib/datasource/unified-validation-run.js +43 -17
- package/lib/datasource/validate.js +37 -20
- package/lib/external-system/test-system-level.js +25 -4
- package/lib/external-system/test.js +3 -1
- package/lib/governance/governance-pack-loader.js +70 -0
- package/lib/governance/governance-run-display.js +119 -0
- package/lib/identity/identity-apply-core.js +108 -0
- package/lib/identity/identity-apply-phases.js +244 -0
- package/lib/identity/identity-apply-service.js +77 -0
- package/lib/identity/identity-csv-parser.js +114 -0
- package/lib/internal/fs-real-sync.js +29 -1
- package/lib/protection/auth-context.js +45 -0
- package/lib/protection/convert-batch.js +90 -0
- package/lib/protection/load.js +41 -0
- package/lib/protection/paths.js +158 -0
- package/lib/protection/preflight-datasource-ready.js +46 -0
- package/lib/protection/protection-create-probe-lines.js +142 -0
- package/lib/protection/protection-create-probes.js +95 -0
- package/lib/protection/protection-create-scaffold.js +281 -0
- package/lib/protection/protection-display-helpers.js +445 -0
- package/lib/protection/protection-display.js +215 -0
- package/lib/protection/protection-preset-registry.js +97 -0
- package/lib/protection/report-exit.js +62 -0
- package/lib/protection/resolve.js +202 -0
- package/lib/protection/run-commands-validate.js +130 -0
- package/lib/protection/run-commands.js +216 -0
- package/lib/protection/run-protection-create-helpers.js +134 -0
- package/lib/protection/run-protection-create-probes-flow.js +43 -0
- package/lib/protection/run-protection-create.js +191 -0
- package/lib/protection/scope.js +22 -0
- package/lib/protection/sync-after-upload.js +64 -0
- package/lib/protection/upload-batch.js +127 -0
- package/lib/protection/validate-batch.js +113 -0
- package/lib/protection/validate-local.js +65 -0
- package/lib/resolvers/dimension-file.js +29 -4
- package/lib/schema/external-datasource.schema.json +47 -13
- package/lib/schema/flag-map-validation-run.json +2 -2
- package/lib/schema/protection.schema.json +374 -0
- package/lib/schema/type/credential-field-registry.json +636 -0
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/agent-trust-run-display.js +231 -0
- package/lib/utils/agent-trust-run-exit.js +59 -0
- package/lib/utils/agent-trust-wait-ui.js +94 -0
- package/lib/utils/cli-exit-codes.js +30 -0
- package/lib/utils/cli-sync-options.js +33 -0
- package/lib/utils/credential-push-ui.js +90 -0
- package/lib/utils/dataplane-cli-version-gate.js +202 -0
- package/lib/utils/dataplane-cli-version-help.js +74 -0
- package/lib/utils/datasource-export-display.js +137 -0
- package/lib/utils/datasource-load-display.js +174 -0
- package/lib/utils/datasource-load-export-ui.js +120 -0
- package/lib/utils/datasource-test-run-capability-scope.js +3 -3
- package/lib/utils/datasource-test-run-display.js +3 -3
- package/lib/utils/datasource-test-run-tty-log.js +5 -1
- package/lib/utils/help-builder.js +30 -24
- package/lib/utils/manifest-source-emit.js +22 -0
- package/lib/utils/semver-compare.js +127 -0
- package/lib/utils/upload-pipeline-ui.js +91 -0
- package/lib/utils/validation-poll-ui.js +14 -7
- package/lib/validation/wizard-config-validator.js +58 -19
- package/package.json +1 -1
- package/templates/applications/dataplane/env.template +13 -1
- package/templates/applications/dataplane/rbac.yaml +4 -0
- package/templates/external-system/README.md.hbs +56 -8
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Local AJV validation for protection manifests (shape only).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const Ajv = require('ajv');
|
|
11
|
+
const addFormats = require('ajv-formats');
|
|
12
|
+
|
|
13
|
+
const SCHEMA_PATH = path.join(__dirname, '..', 'schema', 'protection.schema.json');
|
|
14
|
+
|
|
15
|
+
let compiledValidator = null;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Strip AI Fabrix schema file metadata (not part of JSON Schema validation).
|
|
19
|
+
* @param {Object} raw
|
|
20
|
+
* @returns {Object}
|
|
21
|
+
*/
|
|
22
|
+
function protectionSchemaForAjv(raw) {
|
|
23
|
+
if (!raw || typeof raw !== 'object') {
|
|
24
|
+
return raw;
|
|
25
|
+
}
|
|
26
|
+
const { metadata: _meta, ...schema } = raw;
|
|
27
|
+
if (schema.$schema && String(schema.$schema).includes('2020-12')) {
|
|
28
|
+
delete schema.$schema;
|
|
29
|
+
}
|
|
30
|
+
return schema;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getValidator() {
|
|
34
|
+
if (compiledValidator) {
|
|
35
|
+
return compiledValidator;
|
|
36
|
+
}
|
|
37
|
+
const schema = protectionSchemaForAjv(require(SCHEMA_PATH));
|
|
38
|
+
const ajv = new Ajv({ allErrors: true, strict: false, strictSchema: false });
|
|
39
|
+
addFormats(ajv);
|
|
40
|
+
compiledValidator = ajv.compile(schema);
|
|
41
|
+
return compiledValidator;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @param {Object} manifest
|
|
46
|
+
* @returns {{ valid: boolean, errors: string[] }}
|
|
47
|
+
*/
|
|
48
|
+
function validateProtectionManifestLocal(manifest) {
|
|
49
|
+
const validate = getValidator();
|
|
50
|
+
const valid = validate(manifest);
|
|
51
|
+
if (valid) {
|
|
52
|
+
return { valid: true, errors: [] };
|
|
53
|
+
}
|
|
54
|
+
const errors = (validate.errors || []).map((err) => {
|
|
55
|
+
const at = err.instancePath || err.schemaPath || '';
|
|
56
|
+
return at ? `${at}: ${err.message}` : String(err.message || 'Schema validation failed');
|
|
57
|
+
});
|
|
58
|
+
return { valid: false, errors };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
module.exports = {
|
|
62
|
+
validateProtectionManifestLocal,
|
|
63
|
+
getValidator,
|
|
64
|
+
protectionSchemaForAjv
|
|
65
|
+
};
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
-
const fs = require('fs');
|
|
12
11
|
const path = require('path');
|
|
12
|
+
const { existsSync, readFileSync } = require('../internal/fs-real-sync');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* @typedef {Object} DimensionCreateInput
|
|
@@ -17,10 +17,28 @@ const path = require('path');
|
|
|
17
17
|
* @property {string} displayName
|
|
18
18
|
* @property {string} [description]
|
|
19
19
|
* @property {'string'|'number'|'boolean'} dataType
|
|
20
|
+
* @property {'static'|'dynamic'|'both'} [valueType]
|
|
20
21
|
* @property {boolean} [isRequired]
|
|
21
22
|
* @property {Array<{ value: string, displayName?: string, description?: string }>} [values]
|
|
22
23
|
*/
|
|
23
24
|
|
|
25
|
+
const VALUE_TYPES = new Set(['static', 'dynamic', 'both']);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {*} raw
|
|
29
|
+
* @returns {'static'|'dynamic'|'both'}
|
|
30
|
+
*/
|
|
31
|
+
function normalizeValueType(raw) {
|
|
32
|
+
if (raw === undefined || raw === null || raw === '') {
|
|
33
|
+
return 'static';
|
|
34
|
+
}
|
|
35
|
+
const vt = String(raw).trim();
|
|
36
|
+
if (!VALUE_TYPES.has(vt)) {
|
|
37
|
+
throw new Error('valueType must be one of: static, dynamic, both');
|
|
38
|
+
}
|
|
39
|
+
return /** @type {'static'|'dynamic'|'both'} */ (vt);
|
|
40
|
+
}
|
|
41
|
+
|
|
24
42
|
/**
|
|
25
43
|
* @param {string} filePath
|
|
26
44
|
* @returns {DimensionCreateInput}
|
|
@@ -30,10 +48,10 @@ function readDimensionCreateFile(filePath) {
|
|
|
30
48
|
if (!p) {
|
|
31
49
|
throw new Error('--file is required');
|
|
32
50
|
}
|
|
33
|
-
if (!
|
|
51
|
+
if (!existsSync(p)) {
|
|
34
52
|
throw new Error(`File not found: ${p}`);
|
|
35
53
|
}
|
|
36
|
-
const raw =
|
|
54
|
+
const raw = readFileSync(p, 'utf8');
|
|
37
55
|
let parsed;
|
|
38
56
|
try {
|
|
39
57
|
parsed = JSON.parse(raw);
|
|
@@ -43,10 +61,17 @@ function readDimensionCreateFile(filePath) {
|
|
|
43
61
|
if (!parsed || typeof parsed !== 'object') {
|
|
44
62
|
throw new Error(`Dimension file must be a JSON object: ${p}`);
|
|
45
63
|
}
|
|
64
|
+
if (parsed.valueType !== undefined) {
|
|
65
|
+
parsed.valueType = normalizeValueType(parsed.valueType);
|
|
66
|
+
} else {
|
|
67
|
+
parsed.valueType = 'static';
|
|
68
|
+
}
|
|
46
69
|
return parsed;
|
|
47
70
|
}
|
|
48
71
|
|
|
49
72
|
module.exports = {
|
|
50
|
-
readDimensionCreateFile
|
|
73
|
+
readDimensionCreateFile,
|
|
74
|
+
normalizeValueType,
|
|
75
|
+
VALUE_TYPES
|
|
51
76
|
};
|
|
52
77
|
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
"$schema":"https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id":"aifabrix://schema/external-datasource.schema.json",
|
|
4
4
|
"title":"External Data Source",
|
|
5
|
-
"description":"Configuration for AI Fabrix ExternalDataSource entities. Includes metadata schema, data dimensions, transformation mappings, OpenAPI/MCP exposure, execution logic, and sync behavior. Root externalSpec is the datasource-level authoritative reference for where to obtain the vendor or tooling API specification used for import and validation; external-system.schema.json openapi/mcp are system-level connectivity hints only.",
|
|
5
|
+
"description":"Configuration for AI Fabrix ExternalDataSource entities. Includes metadata schema, data dimensions, transformation mappings, OpenAPI/MCP exposure, execution logic, and sync behavior. Root externalSpec is the datasource-level authoritative reference for where to obtain the vendor or tooling API specification used for import and validation; external-system.schema.json openapi/mcp are system-level connectivity hints only. Agent-facing business metadata (epic 404): most hints are existing properties below; optional businessOrder orders datasources within a system; trust/confidence from agentValidation (404.5) is persisted separately—not in this config document.",
|
|
6
6
|
"metadata":{
|
|
7
7
|
"key":"external-datasource-schema",
|
|
8
8
|
"name":"External Data Source Configuration Schema",
|
|
9
9
|
"description":"JSON schema for validating ExternalDataSource configuration files",
|
|
10
|
-
"version":"2.4.
|
|
10
|
+
"version":"2.4.10",
|
|
11
11
|
"type":"schema",
|
|
12
12
|
"category":"integration",
|
|
13
13
|
"author":"AI Fabrix Team",
|
|
@@ -185,7 +185,24 @@
|
|
|
185
185
|
"breaking":false
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
|
-
"version":"2.4.
|
|
188
|
+
"version":"2.4.10",
|
|
189
|
+
"date":"2026-05-18T00:00:00Z",
|
|
190
|
+
"changes":[
|
|
191
|
+
"Added optional agentExposure.runtimeMeta (boolean, default false) to opt in to meta.business, meta.cip.steps, and meta.agentValidation safe subset on REST runtime responses (plan 404.2)."
|
|
192
|
+
],
|
|
193
|
+
"breaking":false
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"version":"2.4.9",
|
|
197
|
+
"date":"2026-05-18T00:00:00Z",
|
|
198
|
+
"changes":[
|
|
199
|
+
"Added optional root businessOrder (integer >= 1) for cross-datasource ordering within one external system (agent/integrator workflows; does not change CIP execution order).",
|
|
200
|
+
"Improved descriptions on context, exposed.filterable, fieldMappings.attributes.*.semantic, capabilities, and execution.cip.operations shape/safe documenting what integrators and agents receive on manifest vs published OpenAPI vs runtime meta vs agentValidation evidence (plan 404.0)."
|
|
201
|
+
],
|
|
202
|
+
"breaking":false
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"version":"2.4.9",
|
|
189
206
|
"date":"2026-05-10T00:00:00Z",
|
|
190
207
|
"changes":[
|
|
191
208
|
"Documented roles: root externalSpec is the datasource-level authoritative vendor/API specification provenance (fetch, import, validation); config.openapi is the runtime connector (operations, documentKey) and is the behavioral source of truth; external-system openapi/mcp remain connectivity/bootstrap only.",
|
|
@@ -254,6 +271,23 @@
|
|
|
254
271
|
"pattern":"^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
255
272
|
"default":"1.0.0"
|
|
256
273
|
},
|
|
274
|
+
"businessOrder":{
|
|
275
|
+
"type":"integer",
|
|
276
|
+
"minimum":1,
|
|
277
|
+
"description":"Optional sort order of this datasource within its external system (1 = first) for agent and integrator workflows when multiple record-storage datasources exist. Does not control CIP step execution order. Published to OpenAPI governance / optional runtime meta.business.businessOrder when epic 404.2 is enabled. foreignKeys alone do not define this order."
|
|
278
|
+
},
|
|
279
|
+
"agentExposure":{
|
|
280
|
+
"type":"object",
|
|
281
|
+
"description":"Opt-in surfaces for AI agent metadata on published OpenAPI and runtime REST envelopes (plans 404.2–404.3). Does not change CIP execution.",
|
|
282
|
+
"additionalProperties":false,
|
|
283
|
+
"properties":{
|
|
284
|
+
"runtimeMeta":{
|
|
285
|
+
"type":"boolean",
|
|
286
|
+
"default":false,
|
|
287
|
+
"description":"When true, REST runtime responses include meta.business (filterable echo, derived dangerousOperations, exposed semantic fields), meta.cip.steps from execution logs, and meta.agentValidation safe subset from persisted 404.5 validation."
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
},
|
|
257
291
|
"metadataSchema":{
|
|
258
292
|
"$ref":"#/$defs/metadataSchemaNode"
|
|
259
293
|
},
|
|
@@ -347,15 +381,15 @@
|
|
|
347
381
|
},
|
|
348
382
|
"semantic":{
|
|
349
383
|
"type":"object",
|
|
350
|
-
"description":"
|
|
384
|
+
"description":"Per-field business semantics for agents (manifest + OpenAPI component descriptions). Not copied to runtime REST meta by default; use published OpenAPI or manifest fetch for discovery. Validated by deterministic rules (346/370) and optional agentValidation (404.5) which may flag missing descriptions in findings—not auto-written to config.",
|
|
351
385
|
"properties":{
|
|
352
386
|
"title":{
|
|
353
387
|
"type":"string",
|
|
354
|
-
"description":"Human-friendly label for this
|
|
388
|
+
"description":"Human-friendly label for this normalized attribute (UI and OpenAPI property titles)."
|
|
355
389
|
},
|
|
356
390
|
"description":{
|
|
357
391
|
"type":"string",
|
|
358
|
-
"description":"Business
|
|
392
|
+
"description":"Business meaning of the field and how agents should use it in filters or answers. Primary authoring surface for field-level agent hints (use this, not a separate 'meaning' property)."
|
|
359
393
|
},
|
|
360
394
|
"example":{
|
|
361
395
|
"description":"Example value for this field.",
|
|
@@ -452,7 +486,7 @@
|
|
|
452
486
|
},
|
|
453
487
|
"filterable":{
|
|
454
488
|
"type":"array",
|
|
455
|
-
"description":"
|
|
489
|
+
"description":"Canonical list of normalized attribute names agents and integrators may use as deterministic API filters. Must reference materialized fields (metadataSchema index=true or filter=true). Validated by exposed_exposure_lists_validate.py. Emitted on published OpenAPI when epic 404.3 is enabled; optional runtime echo as meta.business.recommendedFilters. agentValidation (404.5) may suggest additions in observedBusinessModel only—they are not a second config field.",
|
|
456
490
|
"items":{
|
|
457
491
|
"type":"string",
|
|
458
492
|
"pattern":"^[a-z][a-zA-Z0-9]*$"
|
|
@@ -735,11 +769,11 @@
|
|
|
735
769
|
},
|
|
736
770
|
"context":{
|
|
737
771
|
"type":"object",
|
|
738
|
-
"description":"
|
|
772
|
+
"description":"Datasource-level discovery hints for agents. Copied to COM semantic_tags and OpenAPI tags when COM build runs; not included in runtime REST meta by default. Prefer structured semanticTags and fieldMappings.*.semantic.description over naturalLanguageHints (legacy prose; do not expand in new integrations).",
|
|
739
773
|
"properties":{
|
|
740
774
|
"semanticTags":{
|
|
741
775
|
"type":"array",
|
|
742
|
-
"description":"
|
|
776
|
+
"description":"Structured tags for classification and OpenAPI tag emission (e.g. ['crm', 'sales', 'deals']).",
|
|
743
777
|
"items":{
|
|
744
778
|
"type":"string"
|
|
745
779
|
}
|
|
@@ -753,7 +787,7 @@
|
|
|
753
787
|
},
|
|
754
788
|
"naturalLanguageHints":{
|
|
755
789
|
"type":"array",
|
|
756
|
-
"description":"
|
|
790
|
+
"description":"Legacy free-form strings (wizard may still emit). Not structured agent contract metadata; avoid for new authoring (plan 404.1). Not exposed on public OpenAPI or runtime meta.",
|
|
757
791
|
"items":{
|
|
758
792
|
"type":"string"
|
|
759
793
|
}
|
|
@@ -855,7 +889,7 @@
|
|
|
855
889
|
"additionalProperties":false
|
|
856
890
|
},
|
|
857
891
|
"capabilities":{
|
|
858
|
-
"description":"
|
|
892
|
+
"description":"Declared operation keys (e.g. list, get, create, update, delete, or custom names matching execution.cip.operations and openapi.operations). Dataplane derives per-operation agent semantics at publish time: core delete and custom ops with CIP shape delete map to x-ai-intent delete and high riskLevel on published OpenAPI—not a separate dangerousOperations list in config.",
|
|
859
893
|
"type":"array",
|
|
860
894
|
"items":{
|
|
861
895
|
"type":"string",
|
|
@@ -1868,7 +1902,7 @@
|
|
|
1868
1902
|
},
|
|
1869
1903
|
"safe":{
|
|
1870
1904
|
"type":"boolean",
|
|
1871
|
-
"description":"Optional
|
|
1905
|
+
"description":"Optional override when automatic shape/fetch inference misclassifies mutating risk. When wired (plan 404.3), influences COM destructive flags and x-ai-safeToRetry on published OpenAPI. Prefer shape for create/update/delete classification."
|
|
1872
1906
|
},
|
|
1873
1907
|
"lineage":{
|
|
1874
1908
|
"$ref":"#/$defs/cipLineage"
|
|
@@ -1883,7 +1917,7 @@
|
|
|
1883
1917
|
"update",
|
|
1884
1918
|
"delete"
|
|
1885
1919
|
],
|
|
1886
|
-
"description":"
|
|
1920
|
+
"description":"Manifest classification for custom operations when fetch step inference is insufficient. Resolved by resolve_cip_write_shape (precedence over fetch inference) and drives x-ai-intent, x-ai-sideEffects, and x-ai-contract.riskLevel on published OpenAPI. shape delete marks the operation as dangerous for agent policy (with core capability delete)."
|
|
1887
1921
|
},
|
|
1888
1922
|
"steps":{
|
|
1889
1923
|
"type":"array",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
{ "cliFlag": "--no-run-scenarios", "requestField": "e2eOptions.runScenarios", "runType": "e2e" },
|
|
15
15
|
{ "cliFlag": "--no-cleanup", "requestField": "e2eOptions.cleanup", "runType": "e2e" },
|
|
16
16
|
{ "cliFlag": "--primary-key-value", "requestField": "e2eOptions.primaryKeyValue", "runType": "e2e" },
|
|
17
|
-
{ "cliFlag": "
|
|
18
|
-
{ "cliFlag": "--strict-capability-scope", "requestField": null, "runType": "e2e", "note": "Client-only: exit ≥1 when capabilities[] has >1 row while
|
|
17
|
+
{ "cliFlag": "[capabilityKey] (positional)", "requestField": "e2eOptions.capabilityKeys", "runType": "e2e", "note": "Single key forwarded as capabilityKeys array in request body when set" },
|
|
18
|
+
{ "cliFlag": "--strict-capability-scope", "requestField": null, "runType": "e2e", "note": "Client-only: exit ≥1 when capabilities[] has >1 row while [capabilityKey] is set (plan §2.3)" },
|
|
19
19
|
{ "cliFlag": "--require-cert", "requestField": null, "note": "Client-only exit code 2 gate" },
|
|
20
20
|
{ "cliFlag": "--warnings-as-errors", "requestField": null, "note": "Client-only exit code 1 on warn" },
|
|
21
21
|
{ "cliFlag": "--json", "requestField": null, "note": "Stdout prints raw DatasourceTestRun" },
|
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "aifabrix://schema/protection.schema.json",
|
|
4
|
+
"title": "AI Fabrix Protection Manifest Schema",
|
|
5
|
+
"description": "Schema for Protection manifests deployed to the AI Fabrix Dataplane. A protection binds to exactly one deployed external datasource (spec.datasourceKey) and declares how synced records project principal-to-dimension-value grants during datasource sync. Distinct from datasource validation-rule 'when' in contracts/schemas/rule.schema.json: rules[].when here gates assignment and runtime using the local identity snapshot (User, Group, UserGroup) and subject dimension state only.",
|
|
6
|
+
"metadata": {
|
|
7
|
+
"key": "protection-schema",
|
|
8
|
+
"name": "Protection Manifest Schema",
|
|
9
|
+
"description": "JSON schema for validating Protection manifest documents (apiVersion/kind/metadata/spec envelope)",
|
|
10
|
+
"version": "1.0.0",
|
|
11
|
+
"type": "schema",
|
|
12
|
+
"category": "integration",
|
|
13
|
+
"author": "AI Fabrix Team",
|
|
14
|
+
"createdAt": "2026-05-18T00:00:00Z",
|
|
15
|
+
"updatedAt": "2026-05-18T00:00:00Z",
|
|
16
|
+
"compatibility": {
|
|
17
|
+
"minVersion": "1.0.0",
|
|
18
|
+
"maxVersion": "1.0.0",
|
|
19
|
+
"deprecated": false
|
|
20
|
+
},
|
|
21
|
+
"tags": [
|
|
22
|
+
"schema",
|
|
23
|
+
"protection",
|
|
24
|
+
"dataplane",
|
|
25
|
+
"integration",
|
|
26
|
+
"validation",
|
|
27
|
+
"abac",
|
|
28
|
+
"dimensions",
|
|
29
|
+
"projection"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": [
|
|
32
|
+
"external-datasource.schema.json"
|
|
33
|
+
],
|
|
34
|
+
"changelog": [
|
|
35
|
+
{
|
|
36
|
+
"version": "1.0.0",
|
|
37
|
+
"date": "2026-05-18T00:00:00Z",
|
|
38
|
+
"changes": [
|
|
39
|
+
"Initial production schema for Protection manifests (401.1 dataplane baseline).",
|
|
40
|
+
"Envelope: apiVersion dataplane.aifabrix.ai/v1, kind Protection, metadata.key/displayName, spec.enabled/datasourceKey/mode/rules.",
|
|
41
|
+
"spec.datasourceKey scopes runtime projection to one deployed datasource; do not use legacy field name 'datasource'.",
|
|
42
|
+
"spec.mode: replaceForSource — per protection, per source record, replace prior projection outputs for that record.",
|
|
43
|
+
"rules[].principal: user (field) or group (field|expression); exactly one of field or expression per principal block.",
|
|
44
|
+
"rules[].grants: required dimensionKey and valueExpression; optional valueType only when Dimension.valueType is both (catalog resolved at validate/projection).",
|
|
45
|
+
"rules[].when: optional groups.requireAny (Group.key) and/or dimensions.requireAll (subject preconditions); additionalProperties false on when/groups/dimensions.",
|
|
46
|
+
"Expression roots (v1): metadata.*, fk.<name>.metadata.*, fk.<name>.dimension.* (one-hop FK only).",
|
|
47
|
+
"principalRef storage uses normalized User.id / Group.id after projection (401.3); not validated structurally in this schema."
|
|
48
|
+
],
|
|
49
|
+
"breaking": false
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"type": "object",
|
|
54
|
+
"additionalProperties": false,
|
|
55
|
+
"required": ["apiVersion", "kind", "metadata", "spec"],
|
|
56
|
+
"properties": {
|
|
57
|
+
"apiVersion": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"const": "dataplane.aifabrix.ai/v1",
|
|
60
|
+
"description": "API version of the Protection manifest envelope. Must be dataplane.aifabrix.ai/v1 for v1 tooling and upload APIs."
|
|
61
|
+
},
|
|
62
|
+
"kind": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"const": "Protection",
|
|
65
|
+
"description": "Resource kind discriminator. Must be Protection."
|
|
66
|
+
},
|
|
67
|
+
"metadata": {
|
|
68
|
+
"type": "object",
|
|
69
|
+
"additionalProperties": false,
|
|
70
|
+
"description": "Identity and display metadata for this protection. metadata.key is globally unique in v1 and is the protection key used in APIs, lineage tables, and builder CLI.",
|
|
71
|
+
"required": ["key", "displayName"],
|
|
72
|
+
"properties": {
|
|
73
|
+
"key": {
|
|
74
|
+
"type": "string",
|
|
75
|
+
"minLength": 1,
|
|
76
|
+
"maxLength": 128,
|
|
77
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$",
|
|
78
|
+
"description": "Unique protection key (globally unique in v1). Lowercase alphanumeric and hyphens; used as protectionKey in storage and APIs.",
|
|
79
|
+
"examples": ["hubspot-country-sales", "hr-persons-protection"]
|
|
80
|
+
},
|
|
81
|
+
"displayName": {
|
|
82
|
+
"type": "string",
|
|
83
|
+
"minLength": 1,
|
|
84
|
+
"maxLength": 255,
|
|
85
|
+
"description": "Human-readable name shown in builder and operator UIs.",
|
|
86
|
+
"examples": ["HubSpot Country Sales Access", "HR Persons Protection"]
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"spec": {
|
|
91
|
+
"type": "object",
|
|
92
|
+
"additionalProperties": false,
|
|
93
|
+
"description": "Protection specification. spec.enabled is the canonical enable flag; the dataplane denormalizes it to ProtectionManifest.enabled for indexed queries.",
|
|
94
|
+
"required": ["enabled", "datasourceKey", "mode", "rules"],
|
|
95
|
+
"properties": {
|
|
96
|
+
"enabled": {
|
|
97
|
+
"type": "boolean",
|
|
98
|
+
"description": "Canonical enable flag. When false, the protection is stored but not selected for projection during datasource sync (indexed enabled column mirrors this value on upload)."
|
|
99
|
+
},
|
|
100
|
+
"datasourceKey": {
|
|
101
|
+
"type": "string",
|
|
102
|
+
"minLength": 1,
|
|
103
|
+
"maxLength": 128,
|
|
104
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$",
|
|
105
|
+
"description": "Deployed external datasource key this protection applies to. Runtime projection runs only during sync of this datasource. Must match ExternalDataSource.key. Do not use the field name 'datasource'.",
|
|
106
|
+
"examples": ["hubspot-companies", "hubspot-deals", "hr-persons"]
|
|
107
|
+
},
|
|
108
|
+
"mode": {
|
|
109
|
+
"type": "string",
|
|
110
|
+
"enum": ["replaceForSource"],
|
|
111
|
+
"description": "Projection replacement mode (v1). replaceForSource: for each source record on datasourceKey, replace all dynamic values and grants previously emitted by this protection for that sourceRecordId (per protection, not global)."
|
|
112
|
+
},
|
|
113
|
+
"rules": {
|
|
114
|
+
"type": "array",
|
|
115
|
+
"minItems": 1,
|
|
116
|
+
"description": "Projection rules. rules[].key is unique within this protection only; storage identity is (protectionKey, projectionRuleKey).",
|
|
117
|
+
"items": {
|
|
118
|
+
"$ref": "#/$defs/protectionRule"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"$defs": {
|
|
125
|
+
"protectionRule": {
|
|
126
|
+
"type": "object",
|
|
127
|
+
"additionalProperties": false,
|
|
128
|
+
"description": "One projection rule: resolve principals from synced records, optionally gate on subject when, emit dimension value grants.",
|
|
129
|
+
"required": ["key", "principal", "grants"],
|
|
130
|
+
"properties": {
|
|
131
|
+
"key": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"minLength": 1,
|
|
134
|
+
"maxLength": 128,
|
|
135
|
+
"pattern": "^[a-z0-9][a-z0-9-]*$",
|
|
136
|
+
"description": "Rule key unique within this protection (projectionRuleKey in lineage).",
|
|
137
|
+
"examples": ["sales-country-users", "hr-manager-department", "europe-region-group"]
|
|
138
|
+
},
|
|
139
|
+
"when": {
|
|
140
|
+
"$ref": "#/$defs/ruleWhen",
|
|
141
|
+
"description": "Optional subject preconditions evaluated against local identity snapshot and subject dimensions. Omitted = rule always eligible (subject to principal resolution only). Not the same as datasource validation-rule when."
|
|
142
|
+
},
|
|
143
|
+
"principal": {
|
|
144
|
+
"$ref": "#/$defs/principal",
|
|
145
|
+
"description": "How to resolve the principal (user or group) from each synced record on datasourceKey."
|
|
146
|
+
},
|
|
147
|
+
"grants": {
|
|
148
|
+
"type": "array",
|
|
149
|
+
"minItems": 1,
|
|
150
|
+
"description": "Dimension value grants to attach to the resolved principal for each qualifying record.",
|
|
151
|
+
"items": {
|
|
152
|
+
"$ref": "#/$defs/grant"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
"ruleWhen": {
|
|
158
|
+
"type": "object",
|
|
159
|
+
"additionalProperties": false,
|
|
160
|
+
"minProperties": 1,
|
|
161
|
+
"description": "Optional rule-level gate. If both groups and dimensions are present, all blocks must pass (AND). Evaluated at projection (401.3) and re-checked at runtime (401.4).",
|
|
162
|
+
"properties": {
|
|
163
|
+
"groups": {
|
|
164
|
+
"type": "object",
|
|
165
|
+
"additionalProperties": false,
|
|
166
|
+
"description": "Group membership gate. For user principals: grants are not persisted unless the user is in at least one requireAny group (UserGroup). Group-target rules typically ignore when.groups unless product overrides.",
|
|
167
|
+
"required": ["requireAny"],
|
|
168
|
+
"properties": {
|
|
169
|
+
"requireAny": {
|
|
170
|
+
"type": "array",
|
|
171
|
+
"minItems": 1,
|
|
172
|
+
"uniqueItems": true,
|
|
173
|
+
"description": "Group.key values from the local identity snapshot; subject must be a member of at least one.",
|
|
174
|
+
"items": {
|
|
175
|
+
"type": "string",
|
|
176
|
+
"minLength": 1,
|
|
177
|
+
"maxLength": 128
|
|
178
|
+
},
|
|
179
|
+
"examples": [["Manager"], ["Sales", "SalesManager"]]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"dimensions": {
|
|
184
|
+
"type": "object",
|
|
185
|
+
"additionalProperties": false,
|
|
186
|
+
"description": "Subject dimension precondition: the subject must already hold all listed dimension values before grants from this rule are applied.",
|
|
187
|
+
"required": ["requireAll"],
|
|
188
|
+
"properties": {
|
|
189
|
+
"requireAll": {
|
|
190
|
+
"type": "array",
|
|
191
|
+
"minItems": 1,
|
|
192
|
+
"description": "All entries must be satisfied (AND). Gates subject state, not record fields.",
|
|
193
|
+
"items": {
|
|
194
|
+
"$ref": "#/$defs/whenDimensionRequireAll"
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"whenDimensionRequireAll": {
|
|
202
|
+
"type": "object",
|
|
203
|
+
"additionalProperties": false,
|
|
204
|
+
"required": ["dimensionKey", "values"],
|
|
205
|
+
"properties": {
|
|
206
|
+
"dimensionKey": {
|
|
207
|
+
"type": "string",
|
|
208
|
+
"minLength": 1,
|
|
209
|
+
"maxLength": 128,
|
|
210
|
+
"description": "Dimension catalog key (Dimension.key).",
|
|
211
|
+
"examples": ["department", "sensitivity", "country"]
|
|
212
|
+
},
|
|
213
|
+
"values": {
|
|
214
|
+
"type": "array",
|
|
215
|
+
"minItems": 1,
|
|
216
|
+
"uniqueItems": true,
|
|
217
|
+
"description": "Required dimension value strings for the subject at evaluation time.",
|
|
218
|
+
"items": {
|
|
219
|
+
"type": "string",
|
|
220
|
+
"minLength": 1,
|
|
221
|
+
"maxLength": 512
|
|
222
|
+
},
|
|
223
|
+
"examples": [["restricted"], ["FI", "SE"]]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
"principal": {
|
|
228
|
+
"type": "object",
|
|
229
|
+
"additionalProperties": false,
|
|
230
|
+
"description": "Principal resolution from the syncing datasource record. Exactly one of field or expression must be set. Resolved principalRef at projection must be User.id or Group.id (never display name or raw email as canonical ref).",
|
|
231
|
+
"required": ["type"],
|
|
232
|
+
"properties": {
|
|
233
|
+
"type": {
|
|
234
|
+
"type": "string",
|
|
235
|
+
"enum": ["user", "group"],
|
|
236
|
+
"description": "Principal kind. user: resolve via field on the record to a User row. group: resolve via field or expression to a Group row (Group.key or Group.id)."
|
|
237
|
+
},
|
|
238
|
+
"field": {
|
|
239
|
+
"type": "string",
|
|
240
|
+
"minLength": 1,
|
|
241
|
+
"maxLength": 512,
|
|
242
|
+
"description": "Record field path (scalar or array path such as metadata.teamMembers[].email). Required for type=user. Allowed for type=group when resolving from record data.",
|
|
243
|
+
"examples": ["metadata.managerEmail", "metadata.teamMembers[].email"]
|
|
244
|
+
},
|
|
245
|
+
"expression": {
|
|
246
|
+
"type": "string",
|
|
247
|
+
"minLength": 1,
|
|
248
|
+
"maxLength": 512,
|
|
249
|
+
"description": "Template expression resolving to a group identifier (typically Group.key). Common for type=group. Allowed roots: metadata.*, fk.<name>.metadata.*, fk.<name>.dimension.* (one-hop FK only).",
|
|
250
|
+
"examples": [
|
|
251
|
+
"Sales {{fk.country.metadata.iso3}} Users",
|
|
252
|
+
"Sales Nordics Users"
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
"oneOf": [
|
|
257
|
+
{
|
|
258
|
+
"required": ["field"],
|
|
259
|
+
"not": {
|
|
260
|
+
"required": ["expression"]
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"required": ["expression"],
|
|
265
|
+
"not": {
|
|
266
|
+
"required": ["field"]
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
]
|
|
270
|
+
},
|
|
271
|
+
"grant": {
|
|
272
|
+
"type": "object",
|
|
273
|
+
"additionalProperties": false,
|
|
274
|
+
"description": "Grant of one dimension value to the resolved principal. effective valueType is resolved from Dimension.valueType in the synced catalog when Dimension.valueType is static or dynamic; grant.valueType is required only when catalog valueType is both.",
|
|
275
|
+
"required": ["dimensionKey", "valueExpression"],
|
|
276
|
+
"properties": {
|
|
277
|
+
"dimensionKey": {
|
|
278
|
+
"type": "string",
|
|
279
|
+
"minLength": 1,
|
|
280
|
+
"maxLength": 128,
|
|
281
|
+
"description": "Dimension catalog key (Dimension.key). Must exist in the synced dimension catalog.",
|
|
282
|
+
"examples": ["country", "region", "department", "project"]
|
|
283
|
+
},
|
|
284
|
+
"valueExpression": {
|
|
285
|
+
"type": "string",
|
|
286
|
+
"minLength": 1,
|
|
287
|
+
"maxLength": 512,
|
|
288
|
+
"description": "Expression evaluated per record/FK context to produce the dimension value string. static dimensions: value must exist in DimensionValue catalog. dynamic dimensions: value may be upserted into dynamic_dimension_values at projection.",
|
|
289
|
+
"examples": [
|
|
290
|
+
"{{fk.country.metadata.iso2}}",
|
|
291
|
+
"europe",
|
|
292
|
+
"{{metadata.departmentCode}}",
|
|
293
|
+
"{{metadata.projectCode}}"
|
|
294
|
+
]
|
|
295
|
+
},
|
|
296
|
+
"labelExpression": {
|
|
297
|
+
"type": "string",
|
|
298
|
+
"minLength": 1,
|
|
299
|
+
"maxLength": 512,
|
|
300
|
+
"description": "Optional human-readable label for dynamic dimension values (projection stores label when valueType resolves to dynamic)."
|
|
301
|
+
},
|
|
302
|
+
"valueType": {
|
|
303
|
+
"type": "string",
|
|
304
|
+
"enum": ["static", "dynamic"],
|
|
305
|
+
"description": "Disambiguates static vs dynamic assignment when Dimension.valueType in the catalog is both. Omit when catalog valueType is static or dynamic."
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
"examples": [
|
|
311
|
+
{
|
|
312
|
+
"apiVersion": "dataplane.aifabrix.ai/v1",
|
|
313
|
+
"kind": "Protection",
|
|
314
|
+
"metadata": {
|
|
315
|
+
"key": "hubspot-country-sales",
|
|
316
|
+
"displayName": "HubSpot Country Sales Access"
|
|
317
|
+
},
|
|
318
|
+
"spec": {
|
|
319
|
+
"enabled": true,
|
|
320
|
+
"datasourceKey": "hubspot-companies",
|
|
321
|
+
"mode": "replaceForSource",
|
|
322
|
+
"rules": [
|
|
323
|
+
{
|
|
324
|
+
"key": "sales-country-users",
|
|
325
|
+
"principal": {
|
|
326
|
+
"type": "group",
|
|
327
|
+
"expression": "Sales {{fk.country.metadata.iso3}} Users"
|
|
328
|
+
},
|
|
329
|
+
"grants": [
|
|
330
|
+
{
|
|
331
|
+
"dimensionKey": "country",
|
|
332
|
+
"valueExpression": "{{fk.country.metadata.iso2}}",
|
|
333
|
+
"labelExpression": "{{fk.country.metadata.name}}"
|
|
334
|
+
}
|
|
335
|
+
]
|
|
336
|
+
}
|
|
337
|
+
]
|
|
338
|
+
}
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"apiVersion": "dataplane.aifabrix.ai/v1",
|
|
342
|
+
"kind": "Protection",
|
|
343
|
+
"metadata": {
|
|
344
|
+
"key": "hr-persons-protection",
|
|
345
|
+
"displayName": "HR Persons Protection"
|
|
346
|
+
},
|
|
347
|
+
"spec": {
|
|
348
|
+
"enabled": true,
|
|
349
|
+
"datasourceKey": "hr-persons",
|
|
350
|
+
"mode": "replaceForSource",
|
|
351
|
+
"rules": [
|
|
352
|
+
{
|
|
353
|
+
"key": "hr-manager-department",
|
|
354
|
+
"when": {
|
|
355
|
+
"groups": {
|
|
356
|
+
"requireAny": ["Manager"]
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
"principal": {
|
|
360
|
+
"type": "user",
|
|
361
|
+
"field": "metadata.managerEmail"
|
|
362
|
+
},
|
|
363
|
+
"grants": [
|
|
364
|
+
{
|
|
365
|
+
"dimensionKey": "department",
|
|
366
|
+
"valueExpression": "{{metadata.departmentCode}}"
|
|
367
|
+
}
|
|
368
|
+
]
|
|
369
|
+
}
|
|
370
|
+
]
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
]
|
|
374
|
+
}
|