Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
eb35ef9
feat(core): add ClassCollaborators.mentionsGrantAccess opt-in flag
MichaelUray May 25, 2026
1d4017e
feat(model/core): wire mentionsGrantAccess into TClassCollaborators m…
MichaelUray May 25, 2026
0b9fa6a
feat(tracker): opt tracker.class.Issue into collaborator-grants-read …
MichaelUray May 25, 2026
2d28f4b
feat(core/collaborators): add isomorphic resolveMentionGrantTarget he…
MichaelUray May 25, 2026
b67689c
feat(middleware/guest-permissions): veto field updates from collab-on…
MichaelUray May 25, 2026
be38db3
feat(tracker/utils): split canEditIssue into canEditIssueFields + can…
MichaelUray Jul 9, 2026
f07d6e0
feat(tracker/EditIssue): show comment composer separately from field …
MichaelUray May 25, 2026
863faf7
fix(chunter-resources): add @hcengineering/text-core dependency
MichaelUray May 25, 2026
961e33c
feat(chunter-trigger): mention-grants-access uses shared helper + gra…
MichaelUray May 25, 2026
d886ee0
feat(chunter/ChatMessageInput): warn before mention auto-grants Issue…
MichaelUray May 25, 2026
f5157a0
feat(middleware/spaceSecurity): let Guests read collab-secured docs a…
MichaelUray May 25, 2026
e6f6fcf
feat(security): allow non-System callers to read their own Collaborat…
MichaelUray May 25, 2026
bc25a70
feat(security+nav): list collab-only spaces in workbench navigator fo…
MichaelUray May 25, 2026
30ad68d
fix(nav): surface collab-only projects in tracker nav-tree
MichaelUray May 26, 2026
2c916a2
fix(tracker/nav): hide non-Issues sub-nodes on non-member projects
MichaelUray May 26, 2026
28a25d1
feat(tracker/nav): V1 - badge + tooltip for collab-only projects
MichaelUray May 27, 2026
8069e28
test(tracker): V2 - mention-grant persists after issue moves to Done
MichaelUray May 27, 2026
dc3e380
feat(text-core): V3a - grantsAccess attr on mention references
MichaelUray May 27, 2026
ddb5018
feat(chunter): V3b - per-grantee grant choices in send disclosure
MichaelUray May 27, 2026
b72c062
feat(chunter-trigger): V3c - honour grantsAccess='false' on mentions
MichaelUray May 27, 2026
1a8f324
feat(chunter-trigger): V3d - add-only re-grant on message edit
MichaelUray May 27, 2026
765da62
fix(chunter-trigger): V3d update-grant uses the edit actor + add tests
MichaelUray May 27, 2026
f9fe39f
fix(chunter): preserve unsent comment when grant dialog is cancelled
MichaelUray May 27, 2026
2f66577
test(middleware): stub hierarchy.getAncestors for guest-permission un…
MichaelUray May 30, 2026
d388c5a
fix(workbench-resources/Navigator): correct activeClasses cast to Ref…
MichaelUray May 30, 2026
4a73a17
fix: self-review BLOCKERs + IMPORTANT findings
MichaelUray May 28, 2026
34c8338
fix(tracker/V1): guard space.members against null
MichaelUray May 28, 2026
caf9ebc
docs(tracker/V1): note scope limit on sub-node hide
MichaelUray May 30, 2026
a8765c9
chore: apply repo formatting and lint fixes after develop merge
MichaelUray Jul 2, 2026
a1bb75b
fix(middleware): backend-guard collab-read space-filter bypass (H5)
MichaelUray Jul 8, 2026
97d5447
fix(middleware): collab-only Write-Veto deckt auch TxRemoveDoc (L-RM)
MichaelUray Jul 8, 2026
ec05335
fix(middleware): guestPermissions fail-closed bei fehlendem Space (L-GP)
MichaelUray Jul 8, 2026
93c13b4
fix(chunter-resources): align text-core to workspace:^0.7.19
MichaelUray Jul 9, 2026
3caba31
feat(core): Collaborator provenance + access-level fields
MichaelUray Jul 8, 2026
e112f74
feat(core): ordinal access-level helper (evolution seam for level->role)
MichaelUray Jul 8, 2026
5342459
feat(middleware): CollaboratorGuard - fail-closed gate for access-gra…
MichaelUray Jul 8, 2026
ec85084
feat(server): register CollaboratorGuardMiddleware after GuestPermiss…
MichaelUray Jul 8, 2026
3b7a33a
test(postgres): provenance fields on Collaborator are queryable via d…
MichaelUray Jul 8, 2026
70ab491
feat(security): per-doc collaborator visibility for all non-admin rol…
MichaelUray Jul 8, 2026
fccc9d2
feat(security): level-aware field-write enforcement for collab grants…
MichaelUray Jul 8, 2026
17bfee8
feat(tracker): access-grant confirm dialog + i18n strings (P3.2)
MichaelUray Jul 8, 2026
f02b5f7
feat(tracker): issue Access panel with provenance, level and grant ma…
MichaelUray Jul 8, 2026
1a810e0
feat(core): AccessGroup and GroupGrant (with level) classes + guarded…
MichaelUray Jul 8, 2026
7023bd9
feat(server): access-group grant materialization + reconcile triggers
MichaelUray Jul 8, 2026
b3c123c
feat(tracker): group grants in issue Access panel
MichaelUray Jul 8, 2026
1a48a14
feat(setting): access-group management UI + fail-closed AccessGroup g…
MichaelUray Jul 8, 2026
34b942b
fix(server): drop unused Doc import in access-group resources
MichaelUray Jul 8, 2026
7f08f62
chore(rush): register access-group packages + update lockfile (P4)
MichaelUray Jul 8, 2026
d3eb12c
feat(chunter): pure mention-grant reconcile helper + unit tests (P5.3)
MichaelUray Jul 8, 2026
8b9c61e
feat(chunter): mention grants as Grant-v2 special case (P5.1/5.2/5.3)
MichaelUray Jul 8, 2026
93f1d6e
feat(chunter): fail-closed mention consent UI + inline grant warning …
MichaelUray Jul 8, 2026
d3b06f3
fix(middleware): C-01 cross-space privilege escalation in collaborato…
MichaelUray Jul 8, 2026
119a424
fix(middleware): M-01 scope collab-read widening to grant classes only
MichaelUray Jul 8, 2026
96bc4ab
fix(access-group): M-02 teardown group-collaborators on AccessGroup d…
MichaelUray Jul 8, 2026
cdab027
fix(chunter-resources): H-02 wire up jest so the P5 client test runs …
MichaelUray Jul 8, 2026
23cc06a
fix(chunter): L-02 externalize mention-grant hint to IntlString (EN+DE)
MichaelUray Jul 8, 2026
0a331b9
fix(model-core): alias ArrOf model import to avoid duplicate identifier
MichaelUray Jul 9, 2026
ff5e447
fix(tracker-assets): i18n locale parity for access-management strings
MichaelUray Jul 9, 2026
17c2887
fix(access-management): satisfy formatting gate (prettier + array-sor…
MichaelUray Jul 9, 2026
948b75d
fix(access-management): align formatting with CI prettier/eslint output
MichaelUray Jul 9, 2026
d040054
fix(setting-assets,chunter-assets): i18n locale parity for access-man…
MichaelUray Jul 9, 2026
80b8103
test(tracker): update mention-grant E2E coverage for IssueAccessPanel
MichaelUray Jul 9, 2026
9a16196
fix(server): cap admin-grant level to prevent self-mint privilege esc…
MichaelUray Jul 10, 2026
f4681d4
fix(server): run collab-only field-update veto for all roles, not jus…
MichaelUray Jul 10, 2026
df3c8d4
style(test): wrap H-NEW-01 admin-grant test args to CI print-width (120)
MichaelUray Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 190 additions & 1 deletion common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions dev/tool/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@
"@hcengineering/server-card-resources": "workspace:^0.7.0",
"@hcengineering/server-chunter": "workspace:^0.7.0",
"@hcengineering/server-chunter-resources": "workspace:^0.7.0",
"@hcengineering/server-access-group": "workspace:^0.7.0",
"@hcengineering/server-access-group-resources": "workspace:^0.7.0",
"@hcengineering/server-contact": "workspace:^0.7.0",
"@hcengineering/server-contact-resources": "workspace:^0.7.0",
"@hcengineering/server-core": "workspace:^0.7.19",
Expand Down
2 changes: 2 additions & 0 deletions dev/tool/src/__start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { serverActivityId } from '@hcengineering/server-activity'
import { serverAiBotId } from '@hcengineering/server-ai-bot'
import { serverAttachmentId } from '@hcengineering/server-attachment'
import { serverCalendarId } from '@hcengineering/server-calendar'
import { serverAccessGroupId } from '@hcengineering/server-access-group'
import { serverCardId } from '@hcengineering/server-card'
import { serverChunterId } from '@hcengineering/server-chunter'
import { serverCollaborationId } from '@hcengineering/server-collaboration'
Expand Down Expand Up @@ -53,6 +54,7 @@ addLocation(serverCollaborationId, () => import('@hcengineering/server-collabora
addLocation(serverContactId, () => import('@hcengineering/server-contact-resources'))
addLocation(serverNotificationId, () => import('@hcengineering/server-notification-resources'))
addLocation(serverChunterId, () => import('@hcengineering/server-chunter-resources'))
addLocation(serverAccessGroupId, () => import('@hcengineering/server-access-group-resources'))
addLocation(serverInventoryId, () => import('@hcengineering/server-inventory-resources'))
addLocation(serverLeadId, () => import('@hcengineering/server-lead-resources'))
addLocation(serverRecruitId, () => import('@hcengineering/server-recruit-resources'))
Expand Down
60 changes: 60 additions & 0 deletions foundations/core/packages/core/src/__tests__/accessLevel.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import { accessLevelRank, hasAtLeast } from '../accessLevel'

describe('accessLevel helper', () => {
describe('accessLevelRank', () => {
it('ranks read < write < admin', () => {
expect(accessLevelRank('read')).toBe(1)
expect(accessLevelRank('write')).toBe(2)
expect(accessLevelRank('admin')).toBe(3)
})

it('treats undefined as read (rank 1)', () => {
expect(accessLevelRank(undefined)).toBe(1)
})
})

describe('hasAtLeast', () => {
it('read does not satisfy write', () => {
expect(hasAtLeast('read', 'write')).toBe(false)
})

it('write satisfies write', () => {
expect(hasAtLeast('write', 'write')).toBe(true)
})

it('admin satisfies write', () => {
expect(hasAtLeast('admin', 'write')).toBe(true)
})

it('undefined satisfies read (minimal)', () => {
expect(hasAtLeast(undefined, 'read')).toBe(true)
})

it('undefined does not satisfy write', () => {
expect(hasAtLeast(undefined, 'write')).toBe(false)
})

it('admin satisfies admin', () => {
expect(hasAtLeast('admin', 'admin')).toBe(true)
})

it('write does not satisfy admin', () => {
expect(hasAtLeast('write', 'admin')).toBe(false)
})
})
})
50 changes: 50 additions & 0 deletions foundations/core/packages/core/src/accessLevel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// Copyright © 2025 Hardcore Engineering Inc.
//
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. You may
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// See the License for the specific language governing permissions and
// limitations under the License.
//

import type { AccessLevel } from './classes'

/**
* Ordinal rank of an access level: read < write < admin.
*
* `undefined` (missing level at a grant record) is treated as `read` — the
* fail-safe minimal grant. This is the single place that maps the string-enum
* to a comparable number, which is the evolution seam described in the design:
* when `level` later becomes a `Ref<Role>`, only this helper (and hasAtLeast)
* changes — every enforcement call-site keeps comparing via these helpers, not
* via string equality.
*
* @public
*/
export function accessLevelRank (level?: AccessLevel): number {
switch (level) {
case 'admin':
return 3
case 'write':
return 2
default:
// 'read' | undefined | any unexpected value → minimal
return 1
}
}

/**
* True iff `level` grants at least the authority of `min` (ordinal compare).
* Higher levels include lower ones (admin ⊇ write ⊇ read).
*
* @public
*/
export function hasAtLeast (level: AccessLevel | undefined, min: AccessLevel): boolean {
return accessLevelRank(level) >= accessLevelRank(min)
}
Loading