Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
25 changes: 25 additions & 0 deletions institutional-access-recertification/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Institutional Access Recertification

This module adds a focused User & Project Management slice for recertifying institutional and external collaborator access to sensitive scientific project spaces.

## What it checks

- Approved institutional domains and named external sponsors
- Current SAML assertions for elevated roles
- MFA requirements for owner, admin, editor, and data-steward access
- Verified ORCID linkage for researcher identity
- Required training and IRB approval expiry
- Project access review windows
- Stale pending invitations
- Object-level grants that exceed the member's role policy
- Deterministic audit digest for review records

## Run locally

```bash
npm run check
npm test
npm run demo
```

The sample data intentionally includes an external collaborator with expired institutional evidence, missing compliance approvals, and an object grant that exceeds the project policy.
24 changes: 24 additions & 0 deletions institutional-access-recertification/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"use strict";

const sampleBundle = require("./sample-data.json");
const {
analyzeInstitutionalAccess,
} = require("./src/institutional-access-recertification");

const result = analyzeInstitutionalAccess(sampleBundle);

console.log(`Project: ${result.projectName}`);
console.log(`Decision: ${result.decision}`);
console.log(`Audit digest: ${result.auditDigest}`);
console.log("");
console.log("Member actions:");
for (const action of result.memberActions) {
console.log(`- ${action.email}: ${action.recommendedAction} (${action.blockerCount} blocker, ${action.warningCount} warning)`);
}
console.log("");
console.log("Findings:");
for (const finding of result.findings) {
console.log(`- [${finding.severity}] ${finding.memberId} ${finding.id}: ${finding.title}`);
console.log(` detail: ${finding.detail}`);
console.log(` remediation: ${finding.remediation}`);
}
Binary file not shown.
15 changes: 15 additions & 0 deletions institutional-access-recertification/docs/requirement-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Requirement Map

| User & Project Management requirement | Implementation |
| --- | --- |
| User identity and linked researcher profiles | Members include institutional domains, SAML assertion expiry, ORCID verification timestamps, MFA posture, and email identity. |
| Project spaces and collaborators | `project` models allowed institution domains, review cadence, required training, and IRB protocols; `members` model internal and external collaborators. |
| Role-based access control | Elevated roles trigger SSO and MFA controls, and member roles are compared against object-level policies. |
| Object-level permissions | `objectPolicies` defines allowed roles per sensitive dataset/notebook, and `object-grant-exceeds-role` flags over-broad grants. |
| External collaborator management | External members require sponsors, current evidence, and stricter overdue review handling. |
| Invitations | Pending invitations older than the configured TTL are surfaced for cleanup. |
| Audit logs and review evidence | Every analysis returns member actions, findings, and a deterministic `sha256` audit digest. |

## Demo Video

The PR includes `docs/access-recertification-demo.mp4`, a real terminal walkthrough running the local check, test, and demo scripts.
12 changes: 12 additions & 0 deletions institutional-access-recertification/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "institutional-access-recertification",
"version": "1.0.0",
"description": "Institutional collaborator access recertification for scientific project spaces.",
"main": "src/institutional-access-recertification.js",
"scripts": {
"check": "node --check src/institutional-access-recertification.js && node --check test.js && node --check demo.js",
"test": "node test.js",
"demo": "node demo.js"
},
"license": "MIT"
}
93 changes: 93 additions & 0 deletions institutional-access-recertification/sample-data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"now": "2026-05-15T00:00:00.000Z",
"project": {
"id": "project-cell-atlas-17",
"name": "Cross-institution cell atlas replication",
"allowedInstitutionDomains": ["scibase.ai", "university.example"],
"requiredTraining": ["human-subjects-data", "controlled-data-handling"],
"requiredIrbProtocols": ["IRB-2026-CELL-17"],
"reviewIntervalDays": 90,
"pendingInvitationTtlDays": 14
},
"objectPolicies": [
{
"objectId": "dataset:restricted-cell-atlas",
"allowedRoles": ["owner", "admin", "data-steward"]
},
{
"objectId": "notebook:analysis-qc",
"allowedRoles": ["owner", "admin", "editor", "data-steward"]
}
],
"members": [
{
"id": "member-001",
"primaryEmail": "mira@scibase.ai",
"institutionDomain": "scibase.ai",
"external": false,
"externalSponsor": null,
"roles": ["owner", "data-steward"],
"mfaEnabled": true,
"samlAssertionExpiresAt": "2026-10-01T00:00:00.000Z",
"orcidVerifiedAt": "2026-01-15T12:00:00.000Z",
"trainingCertifications": [
{ "name": "human-subjects-data", "expiresAt": "2026-12-31T00:00:00.000Z" },
{ "name": "controlled-data-handling", "expiresAt": "2026-12-31T00:00:00.000Z" }
],
"irbApprovals": [
{ "protocolId": "IRB-2026-CELL-17", "expiresAt": "2026-12-01T00:00:00.000Z" }
],
"objectGrants": [
{ "objectId": "dataset:restricted-cell-atlas", "permission": "write" }
],
"invitationStatus": "accepted",
"invitedAt": "2026-01-02T00:00:00.000Z",
"lastAccessReviewAt": "2026-04-01T00:00:00.000Z"
},
{
"id": "member-002",
"primaryEmail": "leo@partner-lab.example",
"institutionDomain": "partner-lab.example",
"external": true,
"externalSponsor": "mira@scibase.ai",
"roles": ["editor"],
"mfaEnabled": false,
"samlAssertionExpiresAt": "2026-03-01T00:00:00.000Z",
"orcidVerifiedAt": "2026-02-10T09:30:00.000Z",
"trainingCertifications": [
{ "name": "human-subjects-data", "expiresAt": "2026-02-01T00:00:00.000Z" },
{ "name": "controlled-data-handling", "expiresAt": "2026-11-30T00:00:00.000Z" }
],
"irbApprovals": [],
"objectGrants": [
{ "objectId": "dataset:restricted-cell-atlas", "permission": "read" },
{ "objectId": "notebook:analysis-qc", "permission": "write" }
],
"invitationStatus": "accepted",
"invitedAt": "2025-11-01T00:00:00.000Z",
"lastAccessReviewAt": "2026-01-10T00:00:00.000Z"
},
{
"id": "member-003",
"primaryEmail": "guest@university.example",
"institutionDomain": "university.example",
"external": true,
"externalSponsor": "mira@scibase.ai",
"roles": ["viewer"],
"mfaEnabled": true,
"samlAssertionExpiresAt": "2026-09-01T00:00:00.000Z",
"orcidVerifiedAt": null,
"trainingCertifications": [
{ "name": "human-subjects-data", "expiresAt": "2026-12-31T00:00:00.000Z" },
{ "name": "controlled-data-handling", "expiresAt": "2026-12-31T00:00:00.000Z" }
],
"irbApprovals": [
{ "protocolId": "IRB-2026-CELL-17", "expiresAt": "2026-12-01T00:00:00.000Z" }
],
"objectGrants": [],
"invitationStatus": "pending",
"invitedAt": "2026-04-20T00:00:00.000Z",
"lastAccessReviewAt": "2026-03-20T00:00:00.000Z"
}
]
}
Loading