@objectstack/platform-objects 12.6.0 → 14.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apps/index.d.mts +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.js +38 -17
- package/dist/apps/index.js.map +1 -1
- package/dist/apps/index.mjs +38 -17
- package/dist/apps/index.mjs.map +1 -1
- package/dist/audit/index.d.mts +90 -30
- package/dist/audit/index.d.ts +90 -30
- package/dist/identity/index.d.mts +1057 -280
- package/dist/identity/index.d.ts +1057 -280
- package/dist/identity/index.js +184 -29
- package/dist/identity/index.js.map +1 -1
- package/dist/identity/index.mjs +184 -29
- package/dist/identity/index.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +362 -335
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +362 -336
- package/dist/index.mjs.map +1 -1
- package/dist/metadata-translations/index.js +20 -288
- package/dist/metadata-translations/index.js.map +1 -1
- package/dist/metadata-translations/index.mjs +20 -288
- package/dist/metadata-translations/index.mjs.map +1 -1
- package/dist/pages/index.d.mts +35 -4
- package/dist/pages/index.d.ts +35 -4
- package/dist/pages/index.js +112 -1
- package/dist/pages/index.js.map +1 -1
- package/dist/pages/index.mjs +112 -2
- package/dist/pages/index.mjs.map +1 -1
- package/dist/plugin.js +37 -300
- package/dist/plugin.js.map +1 -1
- package/dist/plugin.mjs +37 -300
- package/dist/plugin.mjs.map +1 -1
- package/dist/system/index.d.mts +30 -9
- package/dist/system/index.d.ts +30 -9
- package/dist/system/index.js +8 -0
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.mjs +8 -0
- package/dist/system/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/system/index.d.mts
CHANGED
|
@@ -325,7 +325,12 @@ declare const SysSetting: Omit<{
|
|
|
325
325
|
access?: {
|
|
326
326
|
default: "public" | "private";
|
|
327
327
|
} | undefined;
|
|
328
|
-
requiredPermissions?: string[] |
|
|
328
|
+
requiredPermissions?: string[] | {
|
|
329
|
+
read?: string[] | undefined;
|
|
330
|
+
create?: string[] | undefined;
|
|
331
|
+
update?: string[] | undefined;
|
|
332
|
+
delete?: string[] | undefined;
|
|
333
|
+
} | undefined;
|
|
329
334
|
softDelete?: {
|
|
330
335
|
enabled: boolean;
|
|
331
336
|
field: string;
|
|
@@ -671,9 +676,10 @@ declare const SysSetting: Omit<{
|
|
|
671
676
|
trash: boolean;
|
|
672
677
|
mru: boolean;
|
|
673
678
|
clone: boolean;
|
|
674
|
-
apiMethods?: ("search" | "create" | "import" | "delete" | "
|
|
679
|
+
apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
|
|
675
680
|
} | undefined;
|
|
676
|
-
sharingModel?: "
|
|
681
|
+
sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
682
|
+
externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
677
683
|
publicSharing?: {
|
|
678
684
|
enabled: boolean;
|
|
679
685
|
allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
|
|
@@ -3625,7 +3631,12 @@ declare const SysSecret: Omit<{
|
|
|
3625
3631
|
access?: {
|
|
3626
3632
|
default: "public" | "private";
|
|
3627
3633
|
} | undefined;
|
|
3628
|
-
requiredPermissions?: string[] |
|
|
3634
|
+
requiredPermissions?: string[] | {
|
|
3635
|
+
read?: string[] | undefined;
|
|
3636
|
+
create?: string[] | undefined;
|
|
3637
|
+
update?: string[] | undefined;
|
|
3638
|
+
delete?: string[] | undefined;
|
|
3639
|
+
} | undefined;
|
|
3629
3640
|
softDelete?: {
|
|
3630
3641
|
enabled: boolean;
|
|
3631
3642
|
field: string;
|
|
@@ -3971,9 +3982,10 @@ declare const SysSecret: Omit<{
|
|
|
3971
3982
|
trash: boolean;
|
|
3972
3983
|
mru: boolean;
|
|
3973
3984
|
clone: boolean;
|
|
3974
|
-
apiMethods?: ("search" | "create" | "import" | "delete" | "
|
|
3985
|
+
apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
|
|
3975
3986
|
} | undefined;
|
|
3976
|
-
sharingModel?: "
|
|
3987
|
+
sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
3988
|
+
externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
3977
3989
|
publicSharing?: {
|
|
3978
3990
|
enabled: boolean;
|
|
3979
3991
|
allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
|
|
@@ -4100,6 +4112,9 @@ declare const SysSecret: Omit<{
|
|
|
4100
4112
|
readonly icon: "key";
|
|
4101
4113
|
readonly isSystem: true;
|
|
4102
4114
|
readonly managedBy: "system";
|
|
4115
|
+
readonly access: {
|
|
4116
|
+
readonly default: "private";
|
|
4117
|
+
};
|
|
4103
4118
|
readonly description: "Cipher store referenced by sys_setting handles. Never holds plaintext.";
|
|
4104
4119
|
readonly highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"];
|
|
4105
4120
|
readonly listViews: {
|
|
@@ -6101,7 +6116,12 @@ declare const SysSettingAudit: Omit<{
|
|
|
6101
6116
|
access?: {
|
|
6102
6117
|
default: "public" | "private";
|
|
6103
6118
|
} | undefined;
|
|
6104
|
-
requiredPermissions?: string[] |
|
|
6119
|
+
requiredPermissions?: string[] | {
|
|
6120
|
+
read?: string[] | undefined;
|
|
6121
|
+
create?: string[] | undefined;
|
|
6122
|
+
update?: string[] | undefined;
|
|
6123
|
+
delete?: string[] | undefined;
|
|
6124
|
+
} | undefined;
|
|
6105
6125
|
softDelete?: {
|
|
6106
6126
|
enabled: boolean;
|
|
6107
6127
|
field: string;
|
|
@@ -6447,9 +6467,10 @@ declare const SysSettingAudit: Omit<{
|
|
|
6447
6467
|
trash: boolean;
|
|
6448
6468
|
mru: boolean;
|
|
6449
6469
|
clone: boolean;
|
|
6450
|
-
apiMethods?: ("search" | "create" | "import" | "delete" | "
|
|
6470
|
+
apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
|
|
6451
6471
|
} | undefined;
|
|
6452
|
-
sharingModel?: "
|
|
6472
|
+
sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
6473
|
+
externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
6453
6474
|
publicSharing?: {
|
|
6454
6475
|
enabled: boolean;
|
|
6455
6476
|
allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
|
package/dist/system/index.d.ts
CHANGED
|
@@ -325,7 +325,12 @@ declare const SysSetting: Omit<{
|
|
|
325
325
|
access?: {
|
|
326
326
|
default: "public" | "private";
|
|
327
327
|
} | undefined;
|
|
328
|
-
requiredPermissions?: string[] |
|
|
328
|
+
requiredPermissions?: string[] | {
|
|
329
|
+
read?: string[] | undefined;
|
|
330
|
+
create?: string[] | undefined;
|
|
331
|
+
update?: string[] | undefined;
|
|
332
|
+
delete?: string[] | undefined;
|
|
333
|
+
} | undefined;
|
|
329
334
|
softDelete?: {
|
|
330
335
|
enabled: boolean;
|
|
331
336
|
field: string;
|
|
@@ -671,9 +676,10 @@ declare const SysSetting: Omit<{
|
|
|
671
676
|
trash: boolean;
|
|
672
677
|
mru: boolean;
|
|
673
678
|
clone: boolean;
|
|
674
|
-
apiMethods?: ("search" | "create" | "import" | "delete" | "
|
|
679
|
+
apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
|
|
675
680
|
} | undefined;
|
|
676
|
-
sharingModel?: "
|
|
681
|
+
sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
682
|
+
externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
677
683
|
publicSharing?: {
|
|
678
684
|
enabled: boolean;
|
|
679
685
|
allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
|
|
@@ -3625,7 +3631,12 @@ declare const SysSecret: Omit<{
|
|
|
3625
3631
|
access?: {
|
|
3626
3632
|
default: "public" | "private";
|
|
3627
3633
|
} | undefined;
|
|
3628
|
-
requiredPermissions?: string[] |
|
|
3634
|
+
requiredPermissions?: string[] | {
|
|
3635
|
+
read?: string[] | undefined;
|
|
3636
|
+
create?: string[] | undefined;
|
|
3637
|
+
update?: string[] | undefined;
|
|
3638
|
+
delete?: string[] | undefined;
|
|
3639
|
+
} | undefined;
|
|
3629
3640
|
softDelete?: {
|
|
3630
3641
|
enabled: boolean;
|
|
3631
3642
|
field: string;
|
|
@@ -3971,9 +3982,10 @@ declare const SysSecret: Omit<{
|
|
|
3971
3982
|
trash: boolean;
|
|
3972
3983
|
mru: boolean;
|
|
3973
3984
|
clone: boolean;
|
|
3974
|
-
apiMethods?: ("search" | "create" | "import" | "delete" | "
|
|
3985
|
+
apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
|
|
3975
3986
|
} | undefined;
|
|
3976
|
-
sharingModel?: "
|
|
3987
|
+
sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
3988
|
+
externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
3977
3989
|
publicSharing?: {
|
|
3978
3990
|
enabled: boolean;
|
|
3979
3991
|
allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
|
|
@@ -4100,6 +4112,9 @@ declare const SysSecret: Omit<{
|
|
|
4100
4112
|
readonly icon: "key";
|
|
4101
4113
|
readonly isSystem: true;
|
|
4102
4114
|
readonly managedBy: "system";
|
|
4115
|
+
readonly access: {
|
|
4116
|
+
readonly default: "private";
|
|
4117
|
+
};
|
|
4103
4118
|
readonly description: "Cipher store referenced by sys_setting handles. Never holds plaintext.";
|
|
4104
4119
|
readonly highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"];
|
|
4105
4120
|
readonly listViews: {
|
|
@@ -6101,7 +6116,12 @@ declare const SysSettingAudit: Omit<{
|
|
|
6101
6116
|
access?: {
|
|
6102
6117
|
default: "public" | "private";
|
|
6103
6118
|
} | undefined;
|
|
6104
|
-
requiredPermissions?: string[] |
|
|
6119
|
+
requiredPermissions?: string[] | {
|
|
6120
|
+
read?: string[] | undefined;
|
|
6121
|
+
create?: string[] | undefined;
|
|
6122
|
+
update?: string[] | undefined;
|
|
6123
|
+
delete?: string[] | undefined;
|
|
6124
|
+
} | undefined;
|
|
6105
6125
|
softDelete?: {
|
|
6106
6126
|
enabled: boolean;
|
|
6107
6127
|
field: string;
|
|
@@ -6447,9 +6467,10 @@ declare const SysSettingAudit: Omit<{
|
|
|
6447
6467
|
trash: boolean;
|
|
6448
6468
|
mru: boolean;
|
|
6449
6469
|
clone: boolean;
|
|
6450
|
-
apiMethods?: ("search" | "create" | "import" | "delete" | "
|
|
6470
|
+
apiMethods?: ("search" | "create" | "import" | "delete" | "update" | "get" | "upsert" | "list" | "bulk" | "aggregate" | "history" | "restore" | "purge" | "export")[] | undefined;
|
|
6451
6471
|
} | undefined;
|
|
6452
|
-
sharingModel?: "
|
|
6472
|
+
sharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
6473
|
+
externalSharingModel?: "private" | "public_read" | "public_read_write" | "controlled_by_parent" | undefined;
|
|
6453
6474
|
publicSharing?: {
|
|
6454
6475
|
enabled: boolean;
|
|
6455
6476
|
allowedAudiences?: ("email" | "public" | "link_only" | "signed_in")[] | undefined;
|
package/dist/system/index.js
CHANGED
|
@@ -164,6 +164,14 @@ var SysSecret = data.ObjectSchema.create({
|
|
|
164
164
|
icon: "key",
|
|
165
165
|
isSystem: true,
|
|
166
166
|
managedBy: "system",
|
|
167
|
+
// [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets
|
|
168
|
+
// store (settings/datasource credentials). Not covered by the wildcard `'*'`
|
|
169
|
+
// grant — ordinary members get 403 from the generic data layer. Platform
|
|
170
|
+
// admins retain access via the posture-gated superuser bypass. Internal
|
|
171
|
+
// readers are unaffected: `engine.resolveSecret` reads at DRIVER level,
|
|
172
|
+
// SettingsService / the datasource secret-binder read with no principal
|
|
173
|
+
// (middleware falls open for principal-less internal calls).
|
|
174
|
+
access: { default: "private" },
|
|
167
175
|
description: "Cipher store referenced by sys_setting handles. Never holds plaintext.",
|
|
168
176
|
highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"],
|
|
169
177
|
listViews: {
|
package/dist/system/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.js","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.js","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n // [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets\n // store (settings/datasource credentials). Not covered by the wildcard `'*'`\n // grant — ordinary members get 403 from the generic data layer. Platform\n // admins retain access via the posture-gated superuser bypass. Internal\n // readers are unaffected: `engine.resolveSecret` reads at DRIVER level,\n // SettingsService / the datasource secret-binder read with no principal\n // (middleware falls open for principal-less internal calls).\n access: { default: 'private' },\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
|
package/dist/system/index.mjs
CHANGED
|
@@ -162,6 +162,14 @@ var SysSecret = ObjectSchema.create({
|
|
|
162
162
|
icon: "key",
|
|
163
163
|
isSystem: true,
|
|
164
164
|
managedBy: "system",
|
|
165
|
+
// [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets
|
|
166
|
+
// store (settings/datasource credentials). Not covered by the wildcard `'*'`
|
|
167
|
+
// grant — ordinary members get 403 from the generic data layer. Platform
|
|
168
|
+
// admins retain access via the posture-gated superuser bypass. Internal
|
|
169
|
+
// readers are unaffected: `engine.resolveSecret` reads at DRIVER level,
|
|
170
|
+
// SettingsService / the datasource secret-binder read with no principal
|
|
171
|
+
// (middleware falls open for principal-less internal calls).
|
|
172
|
+
access: { default: "private" },
|
|
165
173
|
description: "Cipher store referenced by sys_setting handles. Never holds plaintext.",
|
|
166
174
|
highlightFields: ["namespace", "key", "kms_key_id", "version", "rotated_at"],
|
|
167
175
|
listViews: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.mjs","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/system/sys-setting.object.ts","../../src/system/sys-secret.object.ts","../../src/system/sys-setting-audit.object.ts"],"names":["ObjectSchema","Field"],"mappings":"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","file":"index.mjs","sourcesContent":["// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting — Generic K/V store backing the SettingsManifest contract\n *\n * Single physical table that holds *every* value for *every* settings\n * namespace declared by a `SettingsManifest`. Plugins MUST NOT define\n * per-namespace tables (e.g. `sys_mail_config`); they declare a manifest\n * and the value persists here.\n *\n * Row identity: (namespace, key, scope, user_id?).\n *\n * Resolution order (handled by `SettingsService.get`):\n * 1. process.env override (source='env', locked=true)\n * 2. sys_setting WHERE scope='global' (source='global')\n * 3. sys_setting WHERE scope='tenant' (source='tenant')\n * 4. sys_setting WHERE scope='user' (source='user')\n * 5. manifest specifier.default (source='default')\n *\n * Encryption: rows with `encrypted=true` store ciphertext in `value_enc`\n * and leave `value` null. The plain value is never written to audit log\n * or history snapshots — only an `'<encrypted>'` placeholder + a digest.\n *\n * managedBy: 'system' — the admin grid in Setup is a diagnostic surface\n * only; all writes flow through `SettingsService.set()` so the resolver\n * stays the single source of truth.\n *\n * See ADR-0007 (Settings Manifest + K/V Store + Resolver).\n *\n * @namespace sys\n */\nexport const SysSetting = ObjectSchema.create({\n name: 'sys_setting',\n label: 'Setting',\n pluralLabel: 'Settings',\n icon: 'sliders',\n isSystem: true,\n managedBy: 'system',\n description: 'Generic K/V store backing the SettingsManifest contract.',\n displayNameField: 'key',\n nameField: 'key', // [ADR-0079] canonical primary-title pointer (mirrors deprecated displayNameField)\n titleFormat: '{namespace}.{key}',\n highlightFields: ['namespace', 'key', 'scope', 'updated_at'],\n\n listViews: {\n by_namespace: {\n type: 'grid',\n name: 'by_namespace',\n label: 'By Namespace',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'encrypted', 'updated_by', 'updated_at'],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n grouping: { fields: [{ field: 'namespace', order: 'asc', collapsed: false }] },\n pagination: { pageSize: 200 },\n },\n tenant_only: {\n type: 'grid',\n name: 'tenant_only',\n label: 'Tenant',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'encrypted', 'updated_by', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'tenant' }],\n sort: [{ field: 'namespace', order: 'asc' }, { field: 'key', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n user_only: {\n type: 'grid',\n name: 'user_only',\n label: 'User',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['user_id', 'namespace', 'key', 'updated_at'],\n filter: [{ field: 'scope', operator: 'equals', value: 'user' }],\n sort: [{ field: 'user_id', order: 'asc' }, { field: 'namespace', order: 'asc' }],\n pagination: { pageSize: 200 },\n },\n all_settings: {\n type: 'grid',\n name: 'all_settings',\n label: 'All',\n data: { provider: 'object', object: 'sys_setting' },\n columns: ['namespace', 'key', 'scope', 'user_id', 'encrypted', 'updated_at'],\n sort: [{ field: 'updated_at', order: 'desc' }],\n pagination: { pageSize: 100 },\n },\n },\n\n fields: {\n id: Field.text({\n label: 'Setting ID',\n required: true,\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n updated_at: Field.datetime({\n label: 'Updated At',\n defaultValue: 'NOW()',\n readonly: true,\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 64,\n description: 'Manifest namespace (e.g. mail, branding, feature_flags).',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key inside the namespace (snake_case).',\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n { label: 'Runtime',value: 'runtime' },\n ],\n {\n label: 'Scope',\n required: true,\n defaultValue: 'tenant',\n description: 'Which layer of the config-resolution hierarchy this row belongs to.',\n },\n ),\n\n user_id: Field.lookup('sys_user', {\n label: 'User',\n description: 'Owning user when scope=user; null otherwise.',\n }),\n\n value: Field.json({\n label: 'Value',\n description: 'JSON-encoded value. Null when encrypted=true (see value_enc).',\n }),\n\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'When true, the value is stored encrypted-at-rest in value_enc; value column is null.',\n }),\n\n locked: Field.boolean({\n label: 'Locked',\n defaultValue: false,\n description:\n 'When true, lower-scope rows cannot override this value; writes against lower scopes return 409. ' +\n 'Used by platform administrators to pin a global value for all tenants (Phase 2 cascade).',\n }),\n\n locked_reason: Field.text({\n label: 'Lock Reason',\n description: 'Human-readable explanation surfaced in the UI tooltip when locked=true.',\n }),\n\n value_enc: Field.text({\n label: 'Encrypted Value',\n readonly: true,\n description: 'Ciphertext payload (KMS-wrapped). Set only when encrypted=true.',\n }),\n\n updated_by: Field.lookup('sys_user', {\n label: 'Updated By',\n readonly: true,\n description: 'Last actor who wrote this row via SettingsService.set().',\n }),\n },\n\n indexes: [\n // Primary lookup path: (namespace, key, scope, user_id?) is what\n // SettingsService.get hits on every resolve. The composite UNIQUE\n // covers both the row-identity constraint and the read path.\n { fields: ['namespace', 'key', 'scope', 'user_id'], unique: true },\n // Common range read: full namespace dump for SettingsService.getNamespace.\n { fields: ['namespace', 'scope'], unique: false },\n // Per-user listing on the user-prefs scope.\n { fields: ['user_id', 'namespace'], unique: false },\n ],\n\n enable: {\n // History on settings is opt-in per namespace (handled at service\n // layer when needed) to avoid bloating sys_history with churn from\n // feature flags and similar high-frequency toggles.\n trackHistory: false,\n searchable: false,\n apiEnabled: true,\n // Direct data API exposed for the admin grid view, but writes from\n // the UI MUST go through /api/settings/:namespace so the resolver\n // and audit hooks fire. The grid is diagnostic-only.\n apiMethods: ['get', 'list'],\n trash: false,\n mru: false,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_secret — Separated cipher store for sensitive settings values.\n *\n * Phase 3 of the settings roadmap splits secret material out of\n * `sys_setting` so they can carry their own retention/rotation/KMS\n * policies without bloating the regular settings audit trail. The\n * value column in `sys_setting` for an encrypted specifier holds a\n * *handle* (the `id` of a row here), never the ciphertext itself —\n * the resolver dereferences on read.\n *\n * Why split:\n * 1. **Key rotation.** KMS adapters (AWS/GCP) rotate keys on a\n * different cadence than user-visible settings; tracking\n * `kms_key_id` + `version` per cipher lets us re-wrap without\n * touching the value lifecycle.\n * 2. **Backup hygiene.** Operators can replicate `sys_setting` to\n * analytics/lower environments while keeping `sys_secret` pinned\n * to the primary KMS region.\n * 3. **Audit symmetry.** Every secret read can record an access row\n * (Phase 4) without polluting `sys_setting_audit` with plaintext\n * reads of e.g. feature flags.\n *\n * managedBy: 'system' — never edited from a generic Object grid. All\n * writes flow through `SettingsService` and an `ICryptoProvider`.\n *\n * @namespace sys\n */\nexport const SysSecret = ObjectSchema.create({\n name: 'sys_secret',\n label: 'Secret',\n pluralLabel: 'Secrets',\n icon: 'key',\n isSystem: true,\n managedBy: 'system',\n // [ADR-0066 D2/④] Secure-by-default: the environment's encrypted-secrets\n // store (settings/datasource credentials). Not covered by the wildcard `'*'`\n // grant — ordinary members get 403 from the generic data layer. Platform\n // admins retain access via the posture-gated superuser bypass. Internal\n // readers are unaffected: `engine.resolveSecret` reads at DRIVER level,\n // SettingsService / the datasource secret-binder read with no principal\n // (middleware falls open for principal-less internal calls).\n access: { default: 'private' },\n description: 'Cipher store referenced by sys_setting handles. Never holds plaintext.',\n highlightFields: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at'],\n listViews: {\n all: {\n type: 'grid',\n name: 'all',\n label: 'All Secrets',\n columns: ['namespace', 'key', 'kms_key_id', 'version', 'rotated_at', 'created_at'],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n description: 'Opaque handle referenced by `sys_setting.value_enc`.',\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the cipher was first written.',\n }),\n\n rotated_at: Field.datetime({\n label: 'Rotated At',\n readonly: true,\n description: 'When the cipher was last re-wrapped under a new KMS key.',\n }),\n\n /**\n * Namespace/key duplicated from `sys_setting` for forensic\n * convenience — lets operators answer \"which secret backs\n * mail.api_key right now?\" without joining the K/V table.\n * The authoritative link is `sys_setting.value_enc → sys_secret.id`.\n */\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n description: 'Settings namespace this secret belongs to.',\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n description: 'Specifier key within the namespace.',\n }),\n\n /** Identifier of the KMS key used to wrap `ciphertext`. */\n kms_key_id: Field.text({\n label: 'KMS Key ID',\n required: true,\n maxLength: 256,\n description: 'External KMS handle (ARN, GCP resource id, or `local`).',\n }),\n\n /** Algorithm tag (e.g. `aes-256-gcm`). Used by the provider on decrypt. */\n alg: Field.text({\n label: 'Algorithm',\n required: true,\n defaultValue: 'aes-256-gcm',\n maxLength: 64,\n description: 'Cipher/AEAD algorithm tag.',\n }),\n\n /** Wrapping version — bumps on every rotate(). */\n version: Field.number({\n label: 'Version',\n required: true,\n defaultValue: 1,\n description: 'Bumps each time rotateKey() re-wraps this row.',\n }),\n\n ciphertext: Field.text({\n label: 'Ciphertext',\n required: true,\n readonly: true,\n description:\n 'Provider-encoded ciphertext blob (base64 / JSON). Implementation-defined; only the matching ICryptoProvider can read it.',\n }),\n },\n\n indexes: [\n // Operators frequently look up by (namespace, key) to inspect or rotate.\n { fields: ['namespace', 'key'], unique: false },\n { fields: ['kms_key_id'], unique: false },\n ],\n\n enable: {\n trackHistory: false, // rotation events are recorded by sys_setting_audit\n audit: true,\n },\n});\n","// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.\n\nimport { ObjectSchema, Field } from '@objectstack/spec/data';\n\n/**\n * sys_setting_audit — Append-only audit trail for every settings mutation.\n *\n * Phase 3 of the settings roadmap. Each call to `SettingsService.set()`\n * (and any other mutation hook) writes a row here BEFORE returning to\n * the caller. The row records who, when, where (scope), and what\n * changed — but never the plaintext value of an encrypted field; only\n * a content digest is stored so an operator can verify \"this is the\n * same value as last week\" without exposing the secret.\n *\n * Why separate from `sys_audit_log`:\n * - The generic audit log is a high-traffic firehose (every CRUD\n * on every business object). Settings rows are low-traffic and\n * operationally critical, so they deserve dedicated retention and\n * indexing.\n * - The schema here carries settings-specific fields (`scope`,\n * `cascade_source`) that don't make sense on a generic row.\n *\n * Append-only contract: enforced at the application layer (the only\n * writer is SettingsService). Operators MUST NOT delete rows; instead\n * use lifecycle policies to archive cold rows to a separate bucket.\n *\n * @namespace sys\n */\nexport const SysSettingAudit = ObjectSchema.create({\n name: 'sys_setting_audit',\n label: 'Setting Audit Entry',\n pluralLabel: 'Setting Audit',\n icon: 'history',\n isSystem: true,\n managedBy: 'system',\n description: 'Append-only audit trail for SettingsService mutations.',\n highlightFields: ['namespace', 'key', 'scope', 'action', 'actor_id', 'created_at'],\n listViews: {\n recent: {\n type: 'grid',\n name: 'recent',\n label: 'Recent',\n columns: ['created_at', 'namespace', 'key', 'scope', 'action', 'actor_id', 'source'],\n sort: [{ field: 'created_at', order: 'desc' }],\n },\n },\n\n fields: {\n id: Field.text({\n label: 'ID',\n readonly: true,\n }),\n\n created_at: Field.datetime({\n label: 'Created At',\n readonly: true,\n description: 'When the mutation was recorded.',\n }),\n\n namespace: Field.text({\n label: 'Namespace',\n required: true,\n maxLength: 128,\n }),\n\n key: Field.text({\n label: 'Key',\n required: true,\n maxLength: 128,\n }),\n\n scope: Field.select(\n [\n { label: 'Global', value: 'global' },\n { label: 'Tenant', value: 'tenant' },\n { label: 'User', value: 'user' },\n ],\n {\n label: 'Scope',\n required: true,\n description: 'Cascade layer the row was written to.',\n },\n ),\n\n action: Field.select(\n [\n { label: 'Set', value: 'set' },\n { label: 'Reset', value: 'reset' },\n { label: 'Lock', value: 'lock' },\n { label: 'Unlock', value: 'unlock' },\n { label: 'Rotate', value: 'rotate' },\n ],\n {\n label: 'Action',\n required: true,\n description: 'Mutation kind.',\n },\n ),\n\n actor_id: Field.lookup('sys_user', {\n label: 'Actor',\n description: 'User who performed the mutation; null for system jobs.',\n }),\n\n /**\n * Where the write originated. Lets operators distinguish admin UI\n * activity from migration jobs and bulk imports during incident\n * analysis.\n */\n source: Field.select(\n [\n { label: 'UI', value: 'ui' },\n { label: 'API', value: 'api' },\n { label: 'Migration', value: 'migration' },\n { label: 'Import', value: 'import' },\n { label: 'System', value: 'system' },\n ],\n {\n label: 'Source',\n required: true,\n defaultValue: 'api',\n description: 'Mutation entry-point.',\n },\n ),\n\n /** Optional free-text reason (Phase 3+ change-management hook). */\n reason: Field.text({\n label: 'Reason',\n description: 'Free-text justification provided by the actor (optional).',\n }),\n\n /**\n * Content digest of the previous value. Never the plaintext —\n * lets operators detect duplicate writes without leaking secrets.\n * Format: hex SHA-256 of the canonicalised JSON, or null when\n * the previous value was unset.\n */\n old_hash: Field.text({\n label: 'Old Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the previous value (canonicalised). Null when previously unset.',\n }),\n\n /** Content digest of the new value. Null on `reset`. */\n new_hash: Field.text({\n label: 'New Hash',\n readonly: true,\n maxLength: 128,\n description: 'SHA-256 of the new value (canonicalised). Null on reset.',\n }),\n\n /** True when the field is encrypted — flags secret rotation events. */\n encrypted: Field.boolean({\n label: 'Encrypted',\n defaultValue: false,\n description: 'True when the field carries secret material (rotation is interesting).',\n }),\n\n /** Request id from the originating HTTP/CLI invocation. */\n request_id: Field.text({\n label: 'Request ID',\n maxLength: 128,\n description: 'Correlates with sys_audit_log / tracing.',\n }),\n },\n\n indexes: [\n // Most common query: \"what changed for namespace X in the last 7 days?\"\n { fields: ['namespace', 'created_at'], unique: false },\n // Per-actor lookup for compliance reviews.\n { fields: ['actor_id', 'created_at'], unique: false },\n ],\n\n enable: {\n trackHistory: false,\n audit: false, // this IS the audit; no recursion\n },\n});\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@objectstack/platform-objects",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.3.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Core platform object schemas for ObjectStack — identity, security, audit, tenant, and metadata objects",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
}
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@objectstack/
|
|
67
|
-
"@objectstack/
|
|
66
|
+
"@objectstack/metadata-core": "14.3.0",
|
|
67
|
+
"@objectstack/spec": "14.3.0"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
70
|
"@types/node": "^26.1.0",
|