4.8 KiB
Review owner consent backend
createReviewOwnerConsent prepares a signed policy preview from the authenticated review intent consumer and records explicit access/retention acceptance in MongoDB. It is an unwired backend. Browser routes, CSRF protection, UI, completion-code exchange and activation remain unfinished. Capabilities continue to advertise no available integration features.
The caller must provide an account ID and session ID derived from a current authenticated browser session. Never populate this principal from request JSON or treat a service credential as an owner's identity. The factory also needs the configured intent consumer, a dedicated random 32-byte signing key held outside Git, and a connected MongoDB replica set. Configure bounded server-selection and socket timeouts on that connection. Tests use MongoDB 7 with a three-second server-selection timeout and ten-second socket timeout.
Preview checks the current account and repository before consuming the review intent, then checks them again afterward. The network request holds no MongoDB transaction or authority lock. The account must be active or have the legacy unset active status; the repository must be ready and unexpired. Ownership uses the current account ObjectId. Coauthors must match the account's current numeric GitHub ID. Legacy username-only coauthors and unrelated administrators cannot provide consent.
The signed preview binds the saved intent and exact policy to the account, hashed session ID and repository ObjectId. Changing the account, session, repository or policy invalidates confirmation. The signing context is specific to this protocol; key rotation invalidates outstanding previews. Confirmation requires both access and retention acceptance and an explicit 32-hex request ID. Preview and replay expire with the intent or retention policy.
Confirmation writes one immutable review_owner_consents record per client/intent. It records the account, repository, authority role, exact policy, request ID, confirmation time and a hash of the signed preview. It stores no raw session ID, intent token, service credential or preview ticket. Explicit retries return the same receipt only after current authority checks; another request ID or repository conflicts. No binding is created by accepting a policy.
Transactions touch the current account and repository before writing or reading the receipt. Ownership transfer, coauthor removal and account disablement therefore serialize with confirmation. The private reviewConsentRevision fields are excluded from ordinary Mongoose reads. Four transactions may be active per factory. Database commands and commits have limits; transactions are not automatically retried. A conflict or uncertain commit returns a fixed unavailable error, and the caller must retain the same ticket and request ID for explicit recovery.
The final binding flow must still revalidate the initiating review session and saved intent scope with the review service. This backend proves current upstream owner/coauthor consent, not continuing review-side author authority, immutable snapshots, restricted file access or preservation. Receipt retention/export and the HTTP adapter remain separate work; this change enables no provider or public route.
Validation
The opt-in suite runs against a disposable MongoDB replica set. It covers literal acceptance, immutable replay, stable-ID coauthors, administrator/username rejection, ticket tampering, account/session binding, disabled accounts, ownership changes, removed coauthors, archived/expired repositories, permission changes during upstream I/O, concurrent confirmations, expiry, second-repository conflicts and authority-field privacy. A held ownership-change transaction forces a real write conflict; the explicit retry is denied and no receipt is created.
Run TEST_REVIEW_CONSENT_MONGO='mongodb://127.0.0.1:28743/?replicaSet=review-consent-test' npx mocha test/review-owner-consent.test.js. Set TEST_REVIEW_CONSENT_PERF_REPORT=/tmp/review-consent-perf.json to include 100 durable receipt replays. The CI job starts and removes its own pinned MongoDB image and preserves the performance report. Local timings are synthetic and are not a production latency guarantee.
Local validation passes 12 targeted cases with the benchmark enabled, 723 full-suite cases with 51 opt-in/environment-dependent cases pending, the full TypeScript check and targeted lint. The final 100-replay run measured mean 12.85 ms, median 12.82 ms and p95 14.89 ms against a one-CPU, 512 MiB disposable database. An earlier performance attempt returned unavailable while the privacy fixture was automatically building indexes. The log does not establish the underlying database error. The final fixture disables automatic schema/index creation and creates its collections explicitly.