feat: admin, security & access module (SEC-01..08, v14.5.0)#266
Merged
Conversation
Foundation for the guest/client role (external users restricted to their assigned projects). Wiring these guards onto the detail endpoints follows. - ROLE_GUEST (4) + guestProjectIds on company_users. - Pure guestAccessRules (isGuest, guestAllowsProject) + 10 unit tests. - Reusable guards in permissionGuard: requireGuestProjectAccess / requireGuestTaskAccess β these enforce for ALL clients (guests are web users), while every non-guest passes straight through untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- getProjectList: a guest (roleType 4) sees ONLY the projects in their guestProjectIds β short-circuits the public/private logic. - requireGuestProjectAccess() guard on the project :id routes (detail / update / allTask / sprintFolder) β a guest hitting a non-assigned project now gets 403. Non-guests are unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
β¦-01) - GET /api/v1/task/:id -> requireGuestTaskAccess() (403 if the task's project isn't assigned to the guest). - GET /api/v1/projectdata/taskData -> requireGuestProjectAccess() (by projectId). Note: the query endpoints (tabSyncTask, task/find) and comments still need controller-level query-scoping for guests (follow-up within SEC-01) β handled carefully to avoid false denials on a guest's own assigned-project boards. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- tabSyncTask -> requireGuestProjectAccess by req.body.pid; task/find -> guests denied (arbitrary query, no project context β they use the scoped board). - Comments save/update guarded by objId.projectId; paginated/searched reads by query.projectId. A guest only touches comments on assigned projects. - updateMember now invalidates the cached roleType so a role/guest-projects change takes effect in the guards immediately (was 60s stale). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
10 API/UI verification cases for the guest/client role + the pre-existing detail-endpoint access gap now closed for guests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the βοΈ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
β¨ Finishing Touchesπ§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
- New per-company sso_configs collection + admin config CRUD (owner/admin gated; secret-free public view for the login page). - OIDC: /sso/oidc/initiate + /callback (openid-client, lazy-required) with state(CSRF)+nonce+PKCE, single-use 5-min cache. - SAML: /sso/saml/initiate + /acs + /metadata (samlify, lazy-required; signature-validated). - JIT provisioning mirrors the OAuth signup (global userAuth+users + company_users + notifications); reuses the session/JWT pipeline via a redirect-style finalizeSsoSession. - Auth wiring: only /sso/config requires JWT; the login-flow routes are public. - Deps added (lazy): openid-client, samlify, @authenio/samlify-node-saml2 (run npm install on the server). 13 unit tests; full suite 319 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Settings β SSO page (SsoSettings.vue): provider/OIDC/SAML fields, enable + auto-provision toggles, and the login/redirect/ACS/metadata URLs to hand to the IdP. Owner/admin gated (server-side); configured via /api/v2/sso/config. - Settings tab + route + env constant + i18n. - .claude/test-cases/SSO.md (9 IdP/UI cases). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- manifest.webmanifest (standalone, theme color, logo icons) + a conservative service worker: network-first navigations with an offline shell fallback, cache-first hashed assets, NEVER caches /api or sockets, old caches purged on activate. - index.html: manifest link, theme-color + apple mobile meta, apple-touch-icon, viewport-fit=cover, and a non-fatal SW registration. The app now installs to a home screen and runs standalone; offline opens the cached shell. Native apps + a deeper mobile UX pass remain follow-ups. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Immutable, insert-only audit trail scoped per company: - audit_logs collection (8-edit registration): indexed on createdAt, actorId+createdAt, entityType+entityId+createdAt, action+createdAt. - Modules/Audit/recorder.js: recordAudit / recordAuditFromReq are fire-and-forget and never throw, so a logging failure can never break the request that triggered it. runAuditRetentionForAllCompanies prunes rows older than AUDIT_RETENTION_DAYS (default 365) via a daily 02:00 cron. - Modules/Audit/controller.js: GET /api/v1/audit-logs is owner/admin-gated (getRoleType + isPrivileged), with actor/entity/action/date filters and $facet pagination, newest first. JWT+companyId enforced in setMiddleware. - helpers/auditRules.js (pure): normalizeAuditEntry bounds field lengths, requires action, rejects non-plain meta; retentionCutoff for the cron. - First hooks: member.update (role / guest-project / status changes) and sso.config_update - both best-effort, wrapped so they cannot fail the mutation. Full suite green (29 suites / 327 tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Settings β Audit Log (owner/admin tab): read-only, filterable, paginated view onto the immutable trail. - AuditLog.vue: action / entity-type / date-range filters, server-side $facet pagination (25/page), newest first, meta rendered compactly. Calls GET /api/v1/audit-logs (env.AUDIT_LOGS); 403 for non-privileged. - Route (settings/audit-logs β AuditLog) + Settings tab gated by settings.settings_security_permissions, beside SSO. - i18n: settingslider "Audit Log" + full Audit block in en.js (other locales fall back to en). - Self-namespaced button styles (audit-btn*) to avoid the global .btn_btn navy-on-navy trap. - Test cases: .claude/test-cases/AuditLog.md (14 cases; AUD-14 unit-green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Auto provision/deprovision members from an IdP (Okta, Azure AD, OneLogin).
Backend (Modules/Scim):
- scim_configs collection (8-edit registration). The IdP bearer token is
stored ONLY as a bcrypt hash + last4; the company is encoded into the
token (base64url "companyId:secret") so SCIM requests β which carry no
companyId header β resolve their tenant before the secret is verified.
- scimAuth middleware on /scim/v2/* (router-scoped, NOT JWT); also accepts
application/scim+json.
- Protocol: GET/POST/GET{id}/PUT/PATCH/DELETE Users + ServiceProviderConfig
/ResourceTypes/Schemas discovery. Createβprovision, PATCH active:false /
DELETEβdeactivate (soft, this-company-only), filter by userName, paginated
ListResponse.
- Reuses SSO jitProvisionUser, so a SCIM user and an SSO login for the same
email are the SAME global user. Deactivation flips company_users
status/isDelete + invalidates the role cache.
- Admin config: GET/PUT /api/v2/scim/config + POST /api/v2/scim/token
(owner/admin), token shown once. SCIM mutations recorded to the SEC-04
audit trail.
- helpers/scimRules.js is pure (token build/parse, email/filter parsing,
Okta/Azure PATCH normalization, resource shaping) + 19 unit tests.
Frontend: Settings β SCIM tab (ScimSettings.vue) β enable, default role,
SCIM base URL, generate/rotate token (shown once, copyable). i18n in en.js.
Verify: 30 suites / 346 tests green. Test cases: .claude/test-cases/ScimProvisioning.md (18).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The SEC-03 PWA worker cached build assets cache-first. Against the dev server's HMR (non-hashed bundles) it served stale JS, so the HMR runtime forced a full reload, got stale JS again, and looped. A registered worker persists in the browser, so the loop survived later changes. - service-worker.js is now a self-unregistering kill-switch: it claims clients, drops the alianhub-pwa caches, and unregisters. It has NO fetch handler, so the moment it activates the browser stops serving stale assets and the loop ends. Browsers re-check this script on navigation, so affected clients heal with no user action. - index.html: registration replaced with a targeted unregister of any /service-worker.js registration (the firebase-messaging worker is left intact). Manifest + PWA meta stay (harmless; no worker = no install prompt). A production-only PWA worker (https + non-localhost, hashed-asset aware) can be reintroduced later. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Offline mode WITHOUT a service worker β pure app code, so it behaves identically on localhost/staging/production and cannot cause the kind of asset-cache reload loop the withdrawn SEC-03 worker did. - frontend/src/offline: offlineRules.js (pure whitelists + offline-error detection + synthetic responses, unit-tested), db.js (fail-soft IndexedDB read-cache + write-queue), index.js (cache, queue, FIFO reconnect sync, online/offline state). - Hooked into services/index.js with ZERO change to online behaviour: it caches successful whitelisted GETs (fire-and-forget) and acts only on the request FAILURE path (which already rejected). Offline β whitelisted GETs are served from cache; whitelisted writes (task update/PATCH, comment, time log) are queued and replayed FIFO on reconnect (or on the next successful request, so a recovered-but-still-"online" server also drains). Offline data is cleared on logout (no cross-account bleed). - OfflineBanner.vue mounted in App.vue: "offline" / "syncing Nβ¦" status; hidden when online with nothing queued. i18n in en.js. Verify: 31 suites / 356 tests green (incl. offline-rules); frontend `npm run build` compiles clean. Test cases: .claude/test-cases/OfflineMode.md (16). Done-when met: cached data viewable offline + queued writes sync on reconnect. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Published compliance documentation for the self-hosted model β maps real, implemented AlianHub controls and tracks the gaps honestly. - security-whitepaper.md β architecture, authn/z, tenant isolation, audit, data protection, hardening (cites shipped controls: bcrypt, 2FA, SSO, SCIM, RBAC + guest scoping, immutable audit logs, companyId isolation, Helmet, rate limiting). - control-mapping.md β controls mapped to SOC 2 TSC, ISO/IEC 27001:2022 Annex A, and the HIPAA Security Rule, each with responsibility (AlianHub / Operator / Shared) + status. - shared-responsibility.md β responsibility matrix + operator hardening checklist (software vs. operator β the self-hosting nuance). - gaps.md β 12-item gap register (encryption-at-rest, secret-at-rest, audit tamper-evidence, pen-test, SBOM, session revocation, automatic logoff, β¦) with owner, severity, status, target. - README.md index; SECURITY.md links the pack. Publishes via GitBook from docs/. Done-when met: compliance docs are published and gaps are tracked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
.claude/test-cases/CompliancePosture.md β 10-point review checklist for the compliance docs (coverage, accuracy, no over-claim, links, maintainability). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Track holidays/leave that reduce a user's available capacity. Backend (Modules/Pto): - pto_entries collection (8-edit registration; indexed userId+startDate, status). - helpers/ptoRules.js (pure): validation, MonβFri working-day counting, range overlap, and computeAvailableCapacity β available = workingDays Γ hours/day β APPROVED PTO hours in range (pending/rejected don't count; floors at 0). - controller: create (members request own/pending; owner/admin may create for others + set status), list (own for members, team for admins), approve/reject (owner/admin only), soft-delete (own or admin), and GET /pto/capacity β the done-when. companyId-scoped; mutations recorded to the SEC-04 audit trail. - routes + init; JWT+company via setMiddleware (prefix /api/v1/pto). Frontend: Settings -> Time Off (TimeOff.vue) β request form, this-month capacity card (working hours β time off = available), team/own schedule with approve/reject (admins) + delete. i18n in en.js. Verify: 32 suites / 369 tests green (incl. 13 pto-rules); frontend build clean. Test cases: .claude/test-cases/PtoCalendar.md (15). Done-when met: PTO entries reduce a user's available capacity (feeds REP-06). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8d150d2 to
898f1c0
Compare
@authenio/samlify-node-saml2 (added in SEC-02) does not exist on npm, so `npm ci` / `npm install` failed with a 404 β which would have broken the build/deploy on every environment, not just the lint job. Switch to the published, pure-JS validator @authenio/samlify-xsd-schema-validator@^1.0.5 (no native/binary deps) and refresh package-lock.json so `npm ci` resolves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Admin, Security & Access (v14.5.0)
The complete Admin, Security & Access module β 8 tasks (SEC-01..08), one per commit, each with tests/docs and tracker updates (AHE-3758..3765).
What's included
roleType 4guest; project/task/comment endpoints enforce guest project scope server-side (non-guests pass straight through). Guest branch ingetProjectList.audit_logs+ retention cron + owner/admin read API & viewer. Hooks on member / SSO / SCIM / PTO changes.docs/compliance/β whitepaper, SOC 2 / ISO 27001 / HIPAA control mapping, self-hosted shared-responsibility model, tracked gap register.pto_entries+ capacity engine (approved PTO reduces available capacity), CRUD + approval API + capacity endpoint, Settings β Time Off.Reliability fix included
Verification
npm install).Operational note
npm installfor the new lazy deps (openid-client,samlify,pdfmake). Core works without them; only SSO/SCIM/PDF features need them.π€ Generated with Claude Code