-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathindex.ts
More file actions
133 lines (124 loc) · 5.63 KB
/
Copy pathindex.ts
File metadata and controls
133 lines (124 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
/**
* Security capability chain — a role hierarchy, a permission set that layers
* object CRUD + field-level security (FLS) + row-level security (RLS), two
* sharing rules (criteria- and owner-based), and an org security policy.
* Together these exercise RBAC, FLS, RLS, and sharing in one place. These are
* plain objects validated by `defineStack` (which coerces string predicates
* and fills CRUD defaults).
*/
// ── Roles (hierarchy) ──────────────────────────────────────────────────────
export const ContributorRole = {
name: 'contributor',
label: 'Contributor',
description: 'Works tasks on their own projects.',
};
export const ManagerRole = {
name: 'manager',
label: 'Project Manager',
description: 'Manages projects and the contributors on them.',
parent: 'contributor',
};
export const ExecRole = {
name: 'exec',
label: 'Executive',
description: 'Read-all visibility for reporting.',
parent: 'manager',
};
// ── Permission set: CRUD + FLS + RLS ──────────────────────────────────────
export const ContributorPermissionSet = {
name: 'showcase_contributor',
label: 'Showcase Contributor',
description: 'Standard access for contributors, with budget fields hidden and row-level scoping to own records.',
isProfile: false,
objects: {
showcase_project: { allowRead: true, allowCreate: false, allowEdit: true, allowDelete: false },
showcase_task: { allowRead: true, allowCreate: true, allowEdit: true, allowDelete: false },
showcase_account: { allowRead: true, allowCreate: false, allowEdit: false, allowDelete: false },
// Invoice graph: contributors fully manage invoices + their lines. Read/write
// is scoped by the owner RLS below (invoice) and DERIVED for the lines, which
// are `controlled_by_parent` — no line RLS is authored (ADR-0055).
showcase_invoice: { allowRead: true, allowCreate: true, allowEdit: true, allowDelete: false },
showcase_invoice_line: { allowRead: true, allowCreate: true, allowEdit: true, allowDelete: false },
},
// Field-level security — contributors can read but not edit budget figures.
fields: {
budget: { readable: true, editable: false },
spent: { readable: true, editable: false },
budget_remaining: { readable: true, editable: false },
},
// Row-level security — contributors only see tasks assigned to them.
rowLevelSecurity: [
{
name: 'task_own_rows',
label: 'Own Tasks Only',
description: 'Contributors can only select tasks assigned to them.',
object: 'showcase_task',
operation: 'select' as const,
using: "assignee = current_user.email",
roles: ['contributor'],
enabled: true,
priority: 10,
},
// Owner RLS on the MASTER invoice. Because `showcase_invoice_line` is
// `controlled_by_parent`, a contributor seeing only their own invoices also
// sees only those invoices' lines — and can by-id read/write a line only when
// they can read/write its master (ADR-0055). No line rule is authored here.
{
name: 'invoice_own_rows',
label: 'Own Invoices Only',
description: "Contributors only see invoices they own; their lines follow via controlled_by_parent.",
object: 'showcase_invoice',
operation: 'select' as const,
using: "owner = current_user.email",
roles: ['contributor'],
enabled: true,
priority: 10,
},
],
};
// ── Sharing rules ──────────────────────────────────────────────────────────
/** criteria-based: red-health projects are shared up to executives. */
export const RedProjectSharingRule = {
type: 'criteria' as const,
name: 'share_red_projects_with_execs',
label: 'Red Projects → Executives',
description: 'Automatically share at-risk (red health) projects with executives.',
object: 'showcase_project',
condition: "record.health == 'red'",
accessLevel: 'read' as const,
sharedWith: { type: 'role' as const, value: 'exec' },
active: true,
};
/** owner-based: a contributor's tasks are shared read-only with managers. */
export const ContributorTaskSharingRule = {
type: 'owner' as const,
name: 'share_contributor_tasks_with_manager',
label: "Contributor Tasks → Manager",
description: "Share each contributor's tasks with managers for oversight.",
object: 'showcase_task',
ownedBy: { type: 'role' as const, value: 'contributor' },
accessLevel: 'read' as const,
sharedWith: { type: 'role' as const, value: 'manager' },
active: true,
};
// ── Org security policy ─────────────────────────────────────────────────────
export const ShowcasePolicy = {
name: 'showcase_default_policy',
password: {
minLength: 12,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSymbols: true,
expirationDays: 90,
historyCount: 5,
},
session: { idleTimeout: 30, absoluteTimeout: 480, forceMfa: false },
audit: { logRetentionDays: 365, sensitiveFields: ['budget', 'spent'], captureRead: false },
isDefault: true,
};
export const allRoles = [ContributorRole, ManagerRole, ExecRole];
export const allPermissionSets = [ContributorPermissionSet];
export const allSharingRules = [RedProjectSharingRule, ContributorTaskSharingRule];
export const allPolicies = [ShowcasePolicy];