From 1207314cece0cd49f77aac1a95cf0e38c802df89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E9=93=AD=E9=94=8B?= Date: Fri, 15 May 2026 19:00:10 +0800 Subject: [PATCH] Add anonymous review identity escrow --- anonymous-review-identity-escrow/README.md | 34 +++ .../data/sample-escrow.json | 127 +++++++++ .../docs/demo.mp4 | Bin 0 -> 56477 bytes .../docs/demo.svg | 26 ++ .../docs/requirement-map.md | 19 ++ anonymous-review-identity-escrow/package.json | 12 + .../scripts/demo.js | 18 ++ .../src/identity-escrow.js | 265 ++++++++++++++++++ .../test/identity-escrow.test.js | 62 ++++ 9 files changed, 563 insertions(+) create mode 100644 anonymous-review-identity-escrow/README.md create mode 100644 anonymous-review-identity-escrow/data/sample-escrow.json create mode 100644 anonymous-review-identity-escrow/docs/demo.mp4 create mode 100644 anonymous-review-identity-escrow/docs/demo.svg create mode 100644 anonymous-review-identity-escrow/docs/requirement-map.md create mode 100644 anonymous-review-identity-escrow/package.json create mode 100644 anonymous-review-identity-escrow/scripts/demo.js create mode 100644 anonymous-review-identity-escrow/src/identity-escrow.js create mode 100644 anonymous-review-identity-escrow/test/identity-escrow.test.js diff --git a/anonymous-review-identity-escrow/README.md b/anonymous-review-identity-escrow/README.md new file mode 100644 index 0000000..d020490 --- /dev/null +++ b/anonymous-review-identity-escrow/README.md @@ -0,0 +1,34 @@ +# Anonymous Review Identity Escrow + +This is a self-contained module for SCIBASE issue #11, focused on the anonymous identity and privacy edge of User & Project Management. + +The module models a privacy-preserving escrow layer for optional anonymous peer review. It gives reviewers deterministic pseudonymous handles, keeps identity-provider evidence redacted from review subjects, evaluates object-level access requests, and supports policy-controlled deanonymization only through an audited break-glass flow. + +## What It Covers + +- Anonymous reviewer public handles that do not reveal real names. +- Linked identity evidence for ORCID, GitHub, and institutional SAML without exposing raw subjects. +- Identity assurance scoring for MFA, institution verification, verified providers, training, and risk flags. +- Object-level project access decisions for review comments, raw data, and identity exports. +- Deanonymization requests with policy-approved reasons, quorum, due-process notice, and evidence flags. +- Audit hashes for every access decision plus a packet-level digest. + +## Demo + +Run npm run check, npm test, and npm run demo from this directory. + +Expected demo output includes escrow-ready participants, allowed and denied grants, deanonymization approvals, and a deterministic audit digest. + +The reviewer-facing visual is in docs/demo.svg; a short demo video is in docs/demo.mp4. + +## Files + +- src/identity-escrow.js - core deterministic escrow, access, and deanonymization logic. +- data/sample-escrow.json - synthetic sample identities, project objects, access requests, and break-glass cases. +- test/identity-escrow.test.js - Node assert coverage for pseudonyms, redaction, access denial, break-glass controls, and audit hashes. +- scripts/demo.js - terminal demo for reviewers. +- docs/requirement-map.md - maps this module to issue #11 requirements. + +## Privacy Notes + +No real private identity record, credential, token, ORCID secret, SAML assertion, OAuth key, or external service call is used. All identities and project data are synthetic. diff --git a/anonymous-review-identity-escrow/data/sample-escrow.json b/anonymous-review-identity-escrow/data/sample-escrow.json new file mode 100644 index 0000000..002f291 --- /dev/null +++ b/anonymous-review-identity-escrow/data/sample-escrow.json @@ -0,0 +1,127 @@ +{ + "programId": "blind-review-cohort-q3", + "policy": { + "anonymousMode": true, + "requiredAssurance": 70, + "deanonymizationQuorum": 2, + "allowedDeanonymizationReasons": [ + "harassment", + "data-exfiltration", + "research-integrity-investigation" + ], + "restrictedScopesForAnonymousReviewers": [ + "raw-data-download", + "identity-export", + "billing-admin" + ] + }, + "participants": [ + { + "id": "reviewer-ada", + "displayName": "Ada Chen", + "role": "reviewer", + "profileMode": "anonymous-review", + "linkedIdentities": [ + { "provider": "orcid", "verified": true, "subject": "0000-0002-1825-0097" }, + { "provider": "github", "verified": true, "subject": "ada-lab" }, + { "provider": "saml", "verified": true, "subject": "university.example" } + ], + "mfaEnabled": true, + "institutionVerified": true, + "training": { + "humanSubjects": "valid", + "dataUse": "valid" + }, + "flags": [] + }, + { + "id": "reviewer-bo", + "displayName": "Bo Patel", + "role": "reviewer", + "profileMode": "anonymous-review", + "linkedIdentities": [ + { "provider": "orcid", "verified": true, "subject": "0000-0003-1111-2222" }, + { "provider": "github", "verified": false, "subject": "bo-lab" } + ], + "mfaEnabled": false, + "institutionVerified": false, + "training": { + "humanSubjects": "valid", + "dataUse": "expired" + }, + "flags": ["mfa-missing", "data-use-training-expired"] + }, + { + "id": "admin-mira", + "displayName": "Mira Santos", + "role": "admin", + "profileMode": "private", + "linkedIdentities": [ + { "provider": "saml", "verified": true, "subject": "research-office.example" }, + { "provider": "orcid", "verified": true, "subject": "0000-0001-5555-7777" } + ], + "mfaEnabled": true, + "institutionVerified": true, + "training": { + "humanSubjects": "valid", + "dataUse": "valid" + }, + "flags": [] + } + ], + "projects": [ + { + "id": "project-neuro-crispr", + "visibility": "invitation-only", + "sensitiveScopes": ["raw-data-download", "identity-export"], + "objects": [ + { "id": "manuscript-draft", "kind": "document", "scope": "review-comment" }, + { "id": "supplemental-raw-cells", "kind": "dataset", "scope": "raw-data-download" }, + { "id": "author-roster", "kind": "identity", "scope": "identity-export" } + ] + } + ], + "accessRequests": [ + { + "id": "grant-1", + "participantId": "reviewer-ada", + "projectId": "project-neuro-crispr", + "objectId": "manuscript-draft", + "requestedScope": "review-comment" + }, + { + "id": "grant-2", + "participantId": "reviewer-ada", + "projectId": "project-neuro-crispr", + "objectId": "supplemental-raw-cells", + "requestedScope": "raw-data-download" + }, + { + "id": "grant-3", + "participantId": "reviewer-bo", + "projectId": "project-neuro-crispr", + "objectId": "manuscript-draft", + "requestedScope": "review-comment" + } + ], + "deanonymizationRequests": [ + { + "id": "case-1", + "requesterId": "admin-mira", + "targetParticipantId": "reviewer-bo", + "reason": "research-integrity-investigation", + "approvals": ["admin-mira", "ethics-chair"], + "dueProcessNotice": true, + "evidenceFlags": ["data-use-training-expired", "mfa-missing"] + }, + { + "id": "case-2", + "requesterId": "admin-mira", + "targetParticipantId": "reviewer-ada", + "reason": "curiosity", + "approvals": ["admin-mira"], + "dueProcessNotice": false, + "evidenceFlags": [] + } + ] +} diff --git a/anonymous-review-identity-escrow/docs/demo.mp4 b/anonymous-review-identity-escrow/docs/demo.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..e47a0888d8b5feb531957bbb518f2adafdca12e8 GIT binary patch literal 56477 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 literal 0 HcmV?d00001 diff --git a/anonymous-review-identity-escrow/docs/demo.svg b/anonymous-review-identity-escrow/docs/demo.svg new file mode 100644 index 0000000..89a3915 --- /dev/null +++ b/anonymous-review-identity-escrow/docs/demo.svg @@ -0,0 +1,26 @@ + + Anonymous review identity escrow demo + A dashboard-style summary showing escrow-ready reviewers, access decisions, and deanonymization controls. + + + Anonymous Review Identity Escrow + Pseudonymous reviewers, redacted identity evidence, access policy, and audited break-glass release. + + Escrow-ready + 2 / 3 + + Allowed grants + 1 + + Denied grants + 2 + + Break-glass releases + 1 + + Reviewer anon-23dabcdd5e + ORCID, GitHub, and SAML verified. Real subjects are redacted from review subjects. + Access denied: raw-data-download + Anonymous reviewers can comment on manuscripts, but cannot export raw data or identities. + Audit digest: deterministic SHA-256 packet hash for project-level audit logs. + diff --git a/anonymous-review-identity-escrow/docs/requirement-map.md b/anonymous-review-identity-escrow/docs/requirement-map.md new file mode 100644 index 0000000..514f3b9 --- /dev/null +++ b/anonymous-review-identity-escrow/docs/requirement-map.md @@ -0,0 +1,19 @@ +# Requirement Map + +This module targets SCIBASE-AI/SCIBASE.AI issue #11, "User & Project Management". + +| Issue requirement | Implementation evidence | +| --- | --- | +| Optional anonymous user mode for open peer review or public browsing | src/identity-escrow.js issues deterministic pseudonymous handles for profileMode: anonymous-review and hides real display names from review subjects. | +| Account linking across ORCID, GitHub, and institutional identity | data/sample-escrow.json models linked identity providers; scoreIdentityAssurance scores verified providers without exposing subjects. | +| Public vs private profile modes | Escrow records include profileMode and identityVisibleToReviewSubject decisions. | +| Role-based and object-level access control | evaluateAccessRequest decides project/object grants by role, requested scope, assurance score, training, and anonymous-review restrictions. | +| External collaborator and reviewer governance | Access requests model reviewer grants for invitation-only projects and restricted scientific objects. | +| Project-level audit log | Every access and deanonymization decision includes an auditEventHash; the packet includes an overall auditDigest. | +| Meaningful attribution without unsafe identity exposure | Public handles, redacted identity evidence, sealed identity hashes, and break-glass policy separate credit/trust signals from real identity release. | + +## Non-goals + +- No live OAuth, SAML, ORCID, payment, email, or external API integration. +- No real private identity records are included. +- No credential, secret, or production data is required. diff --git a/anonymous-review-identity-escrow/package.json b/anonymous-review-identity-escrow/package.json new file mode 100644 index 0000000..7cbfad6 --- /dev/null +++ b/anonymous-review-identity-escrow/package.json @@ -0,0 +1,12 @@ +{ + "name": "anonymous-review-identity-escrow", + "version": "1.0.0", + "private": true, + "description": "Dependency-free anonymous review identity escrow and access audit module for SCIBASE user/project management.", + "type": "commonjs", + "scripts": { + "check": "node --check src/identity-escrow.js && node --check scripts/demo.js && node --check test/identity-escrow.test.js", + "test": "node test/identity-escrow.test.js", + "demo": "node scripts/demo.js" + } +} diff --git a/anonymous-review-identity-escrow/scripts/demo.js b/anonymous-review-identity-escrow/scripts/demo.js new file mode 100644 index 0000000..84d603a --- /dev/null +++ b/anonymous-review-identity-escrow/scripts/demo.js @@ -0,0 +1,18 @@ +"use strict"; + +const fs = require("node:fs"); +const path = require("node:path"); +const { createIdentityEscrowPacket } = require("../src/identity-escrow"); + +const fixture = JSON.parse( + fs.readFileSync(path.join(__dirname, "../data/sample-escrow.json"), "utf8") +); +const packet = createIdentityEscrowPacket(fixture); + +console.log("Program: " + packet.programId); +console.log("Escrow-ready participants: " + packet.summary.escrowReady + "/" + packet.summary.participants); +console.log("Allowed access grants: " + packet.summary.allowedAccess); +console.log("Denied access grants: " + packet.summary.deniedAccess); +console.log("Deanonymization approved: " + packet.summary.deanonymizationApproved); +console.log("Top action: " + packet.actions[0].message); +console.log("Audit digest: " + packet.auditDigest); diff --git a/anonymous-review-identity-escrow/src/identity-escrow.js b/anonymous-review-identity-escrow/src/identity-escrow.js new file mode 100644 index 0000000..63162b7 --- /dev/null +++ b/anonymous-review-identity-escrow/src/identity-escrow.js @@ -0,0 +1,265 @@ +"use strict"; + +const crypto = require("node:crypto"); + +const REDACTED = "[redacted]"; + +function stableStringify(value) { + if (Array.isArray(value)) { + return "[" + value.map(stableStringify).join(",") + "]"; + } + if (value && typeof value === "object") { + return "{" + Object.keys(value) + .sort() + .map((key) => JSON.stringify(key) + ":" + stableStringify(value[key])) + .join(",") + "}"; + } + return JSON.stringify(value); +} + +function sha256(value) { + return crypto.createHash("sha256").update(stableStringify(value)).digest("hex"); +} + +function validateEscrowInput(input) { + const issues = []; + if (!input || typeof input !== "object") issues.push("input"); + if (!input.programId) issues.push("programId"); + if (!input.policy) issues.push("policy"); + if (!Array.isArray(input.participants)) issues.push("participants"); + if (!Array.isArray(input.projects)) issues.push("projects"); + if (!Array.isArray(input.accessRequests)) issues.push("accessRequests"); + if (!Array.isArray(input.deanonymizationRequests)) issues.push("deanonymizationRequests"); + + for (const participant of input.participants || []) { + if (!participant.id) issues.push("participant.id"); + if (!participant.role) issues.push((participant.id || "unknown") + ".role"); + if (!Array.isArray(participant.linkedIdentities)) { + issues.push((participant.id || "unknown") + ".linkedIdentities"); + } + } + + for (const request of input.accessRequests || []) { + if (!request.participantId) issues.push((request.id || "unknown") + ".participantId"); + if (!request.projectId) issues.push((request.id || "unknown") + ".projectId"); + if (!request.requestedScope) issues.push((request.id || "unknown") + ".requestedScope"); + } + + if (issues.length) { + throw new Error("Invalid escrow input: " + issues.join(", ")); + } +} + +function indexById(items) { + return new Map(items.map((item) => [item.id, item])); +} + +function pseudonymFor(programId, participantId) { + return "anon-" + sha256({ programId, participantId }).slice(0, 10); +} + +function scoreIdentityAssurance(participant) { + const verifiedLinks = participant.linkedIdentities.filter((identity) => identity.verified); + const providers = new Set(verifiedLinks.map((identity) => identity.provider)); + let score = 0; + score += Math.min(45, verifiedLinks.length * 15); + score += providers.has("orcid") ? 15 : 0; + score += providers.has("saml") ? 15 : 0; + score += participant.mfaEnabled ? 15 : 0; + score += participant.institutionVerified ? 10 : 0; + score -= (participant.flags || []).length * 8; + return Math.max(0, Math.min(100, score)); +} + +function summarizeIdentityEvidence(participant) { + return { + verifiedProviders: participant.linkedIdentities + .filter((identity) => identity.verified) + .map((identity) => identity.provider) + .sort(), + redactedSubjects: participant.linkedIdentities.map((identity) => ({ + provider: identity.provider, + verified: identity.verified, + subject: REDACTED + })), + mfaEnabled: participant.mfaEnabled, + institutionVerified: participant.institutionVerified, + training: participant.training || {}, + flags: participant.flags || [] + }; +} + +function escrowParticipants(input) { + return input.participants.map((participant) => { + const anonymous = participant.profileMode === "anonymous-review"; + const assuranceScore = scoreIdentityAssurance(participant); + return { + participantId: participant.id, + role: participant.role, + publicHandle: anonymous ? pseudonymFor(input.programId, participant.id) : participant.displayName, + profileMode: participant.profileMode, + identityVisibleToReviewSubject: !anonymous, + assuranceScore, + identityEvidence: summarizeIdentityEvidence(participant), + status: assuranceScore >= input.policy.requiredAssurance ? "escrow-ready" : "needs-identity-hardening" + }; + }); +} + +function evaluateAccessRequest(request, context) { + const participant = context.participants.get(request.participantId); + const project = context.projects.get(request.projectId); + const escrow = context.escrowByParticipant.get(request.participantId); + const reasons = []; + + if (!participant) reasons.push("unknown-participant"); + if (!project) reasons.push("unknown-project"); + if (!escrow) reasons.push("missing-escrow-record"); + if (participant && participant.role !== "admin" && participant.role !== "reviewer") { + reasons.push("role-not-eligible"); + } + if (escrow && escrow.assuranceScore < context.policy.requiredAssurance) { + reasons.push("identity-assurance-below-threshold"); + } + if ( + participant && + participant.profileMode === "anonymous-review" && + context.policy.restrictedScopesForAnonymousReviewers.includes(request.requestedScope) + ) { + reasons.push("anonymous-reviewer-restricted-scope"); + } + if (participant && participant.training && participant.training.dataUse === "expired") { + reasons.push("data-use-training-expired"); + } + + return { + id: request.id, + participantId: request.participantId, + publicHandle: escrow ? escrow.publicHandle : "unknown", + projectId: request.projectId, + objectId: request.objectId, + requestedScope: request.requestedScope, + decision: reasons.length === 0 ? "allow" : "deny", + reasons: reasons.length ? reasons : ["least-privilege-review-access"], + auditEventHash: sha256({ + request, + reasons, + publicHandle: escrow ? escrow.publicHandle : "unknown" + }) + }; +} + +function evaluateDeanonymizationRequest(request, context) { + const requester = context.participants.get(request.requesterId); + const target = context.participants.get(request.targetParticipantId); + const targetEscrow = context.escrowByParticipant.get(request.targetParticipantId); + const reasons = []; + + if (!requester || requester.role !== "admin") reasons.push("requester-not-admin"); + if (!target) reasons.push("unknown-target"); + if (!context.policy.allowedDeanonymizationReasons.includes(request.reason)) { + reasons.push("reason-not-policy-approved"); + } + if ((request.approvals || []).length < context.policy.deanonymizationQuorum) { + reasons.push("quorum-not-met"); + } + if (!request.dueProcessNotice) reasons.push("due-process-notice-missing"); + if (!request.evidenceFlags || request.evidenceFlags.length === 0) { + reasons.push("no-evidence-flags"); + } + + return { + id: request.id, + targetPublicHandle: targetEscrow ? targetEscrow.publicHandle : "unknown", + reason: request.reason, + decision: reasons.length === 0 ? "release-to-authorized-admins" : "keep-sealed", + reasons: reasons.length ? reasons : ["policy-reason-approved", "quorum-met", "due-process-recorded"], + sealedIdentityHash: target ? sha256({ targetParticipantId: target.id, identities: target.linkedIdentities }) : null, + auditEventHash: sha256(request) + }; +} + +function buildActionItems(accessDecisions, deanonymizationDecisions, escrowRecords) { + const actions = []; + for (const record of escrowRecords) { + if (record.status !== "escrow-ready") { + actions.push({ + owner: record.publicHandle, + type: "identity-hardening", + message: "Require MFA, institution verification, or current training before anonymous review access." + }); + } + } + for (const decision of accessDecisions) { + if (decision.decision === "deny") { + actions.push({ + owner: decision.publicHandle, + type: "access-remediation", + message: "Denied " + decision.requestedScope + ": " + decision.reasons.join(", ") + "." + }); + } + } + for (const decision of deanonymizationDecisions) { + if (decision.decision === "release-to-authorized-admins") { + actions.push({ + owner: decision.targetPublicHandle, + type: "privacy-breakglass", + message: "Deanonymization approved only for authorized admins with audit trail." + }); + } + } + return actions; +} + +function createIdentityEscrowPacket(input) { + validateEscrowInput(input); + + const escrowRecords = escrowParticipants(input); + const context = { + policy: input.policy, + participants: indexById(input.participants), + projects: indexById(input.projects), + escrowByParticipant: indexById(escrowRecords.map((record) => ({ + ...record, + id: record.participantId + }))) + }; + const accessDecisions = input.accessRequests.map((request) => evaluateAccessRequest(request, context)); + const deanonymizationDecisions = input.deanonymizationRequests.map((request) => + evaluateDeanonymizationRequest(request, context) + ); + const actions = buildActionItems(accessDecisions, deanonymizationDecisions, escrowRecords); + const packet = { + programId: input.programId, + generatedAt: "2026-05-15T10:20:00.000Z", + policy: input.policy, + escrowRecords, + accessDecisions, + deanonymizationDecisions, + actions, + summary: { + participants: escrowRecords.length, + escrowReady: escrowRecords.filter((record) => record.status === "escrow-ready").length, + allowedAccess: accessDecisions.filter((decision) => decision.decision === "allow").length, + deniedAccess: accessDecisions.filter((decision) => decision.decision === "deny").length, + deanonymizationApproved: deanonymizationDecisions.filter((decision) => + decision.decision === "release-to-authorized-admins" + ).length + } + }; + return { + ...packet, + auditDigest: sha256(packet) + }; +} + +module.exports = { + REDACTED, + createIdentityEscrowPacket, + evaluateAccessRequest, + evaluateDeanonymizationRequest, + pseudonymFor, + scoreIdentityAssurance, + stableStringify, + validateEscrowInput +}; diff --git a/anonymous-review-identity-escrow/test/identity-escrow.test.js b/anonymous-review-identity-escrow/test/identity-escrow.test.js new file mode 100644 index 0000000..04289e2 --- /dev/null +++ b/anonymous-review-identity-escrow/test/identity-escrow.test.js @@ -0,0 +1,62 @@ +"use strict"; + +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const path = require("node:path"); +const { + REDACTED, + createIdentityEscrowPacket, + pseudonymFor, + scoreIdentityAssurance, + validateEscrowInput +} = require("../src/identity-escrow"); + +const fixture = JSON.parse( + fs.readFileSync(path.join(__dirname, "../data/sample-escrow.json"), "utf8") +); + +validateEscrowInput(fixture); + +const packet = createIdentityEscrowPacket(fixture); + +assert.equal(packet.programId, "blind-review-cohort-q3"); +assert.equal(packet.summary.participants, 3); +assert.equal(packet.summary.escrowReady, 2); +assert.equal(packet.summary.allowedAccess, 1); +assert.equal(packet.summary.deniedAccess, 2); +assert.equal(packet.summary.deanonymizationApproved, 1); +assert.match(packet.auditDigest, /^[a-f0-9]{64}$/); + +const ada = fixture.participants.find((participant) => participant.id === "reviewer-ada"); +const bo = fixture.participants.find((participant) => participant.id === "reviewer-bo"); +assert.equal(scoreIdentityAssurance(ada), 100); +assert.equal(scoreIdentityAssurance(bo), 14); + +const adaEscrow = packet.escrowRecords.find((record) => record.participantId === "reviewer-ada"); +assert.equal(adaEscrow.publicHandle, pseudonymFor(fixture.programId, "reviewer-ada")); +assert.notEqual(adaEscrow.publicHandle, ada.displayName); +assert.equal(adaEscrow.identityVisibleToReviewSubject, false); +assert.equal(adaEscrow.identityEvidence.redactedSubjects[0].subject, REDACTED); + +const rawDataDecision = packet.accessDecisions.find((decision) => decision.id === "grant-2"); +assert.equal(rawDataDecision.decision, "deny"); +assert.ok(rawDataDecision.reasons.includes("anonymous-reviewer-restricted-scope")); + +const weakReviewerDecision = packet.accessDecisions.find((decision) => decision.id === "grant-3"); +assert.equal(weakReviewerDecision.decision, "deny"); +assert.ok(weakReviewerDecision.reasons.includes("identity-assurance-below-threshold")); +assert.ok(weakReviewerDecision.reasons.includes("data-use-training-expired")); + +const approvedBreakglass = packet.deanonymizationDecisions.find((decision) => decision.id === "case-1"); +assert.equal(approvedBreakglass.decision, "release-to-authorized-admins"); +assert.match(approvedBreakglass.sealedIdentityHash, /^[a-f0-9]{64}$/); + +const rejectedBreakglass = packet.deanonymizationDecisions.find((decision) => decision.id === "case-2"); +assert.equal(rejectedBreakglass.decision, "keep-sealed"); +assert.ok(rejectedBreakglass.reasons.includes("reason-not-policy-approved")); +assert.ok(rejectedBreakglass.reasons.includes("quorum-not-met")); + +assert.ok(packet.actions.some((action) => action.type === "identity-hardening")); +assert.ok(packet.actions.some((action) => action.type === "privacy-breakglass")); + +console.log("anonymous-review-identity-escrow tests passed");