Add the SheerID student verification module (#36704)

GitOrigin-RevId: a3673c09e185c8f857d5da3e706fa9a310fba6d4
This commit is contained in:
Tim Down
2026-09-17 12:07:32 +00:00
committed by Copybot
parent 37e27bb22e
commit c3d962c075
8 changed files with 393 additions and 1 deletions
@@ -200,6 +200,26 @@ module.exports = {
price_in_cents: 1500,
features: features.collaborator,
},
// The real student plans live in settings.overrides.saas.js, but
// @overleaf/settings' merge replaces arrays wholesale rather than
// merging them, so this list (not that one) is what acceptance tests
// see. Without these, PlansLocator.findLocalPlanInSettings cannot
// resolve 'student' and any test of the student-verification gate is
// blocked before the gate is reached. Feature set is deliberately
// borrowed from collaborator: the gate only needs the plan to resolve.
{
planCode: 'student',
name: 'Student monthly',
price_in_cents: 1000,
features: features.collaborator,
},
{
planCode: 'student-annual',
name: 'Student annual',
price_in_cents: 10000,
annual: true,
features: features.collaborator,
},
{
planCode: 'professional',
name: 'Pro monthly',
@@ -1,4 +1,4 @@
import { describe, expect, it } from 'vitest'
import { afterEach, describe, expect, it } from 'vitest'
import { createRequire } from 'node:module'
const require = createRequire(import.meta.url)
@@ -88,3 +88,133 @@ describe('settings.defaults', function () {
expect(haveSameStructure(pricings)).to.be.true
})
})
describe('settings.overrides.saas', function () {
const originalEnv = {
SHEERID_ENABLED: process.env.SHEERID_ENABLED,
SHEERID_MOCK: process.env.SHEERID_MOCK,
SHEERID_CLIENT_ID: process.env.SHEERID_CLIENT_ID,
SHEERID_CLIENT_SECRET: process.env.SHEERID_CLIENT_SECRET,
SHEERID_PROGRAM_ID: process.env.SHEERID_PROGRAM_ID,
SHEERID_API_BASE_URL: process.env.SHEERID_API_BASE_URL,
SHEERID_ENABLED_COUNTRIES: process.env.SHEERID_ENABLED_COUNTRIES,
SHEERID_FALLBACK_COUNTRY: process.env.SHEERID_FALLBACK_COUNTRY,
NODE_ENV: process.env.NODE_ENV,
}
function setCredentials() {
process.env.SHEERID_CLIENT_ID = 'client-id'
process.env.SHEERID_CLIENT_SECRET = 'client-secret'
process.env.SHEERID_PROGRAM_ID = 'program-id'
}
afterEach(function () {
for (const [key, value] of Object.entries(originalEnv)) {
if (value === undefined) {
delete process.env[key]
} else {
process.env[key] = value
}
}
clearSettingsCache()
})
it('sets the verification page CSP frame-src from the configured SheerID host', function () {
process.env.SHEERID_API_BASE_URL = 'https://sandbox.sheerid.com'
clearSettingsCache()
const settings = require('../../../../config/settings.overrides.saas.js')
expect(
settings.csp.viewDirectives[
'modules/student-verification/app/views/student-verification'
]
).to.deep.equal(["frame-src 'self' https://sandbox.sheerid.com"])
})
it('upper-cases the SheerID country settings', function () {
process.env.SHEERID_ENABLED_COUNTRIES = 'gb, us ,De'
process.env.SHEERID_FALLBACK_COUNTRY = 'gb'
clearSettingsCache()
const settings = require('../../../../config/settings.overrides.saas.js')
expect(settings.sheerId.enabledCountries).to.deep.equal(['GB', 'US', 'DE'])
expect(settings.sheerId.fallbackCountry).to.equal('GB')
})
it('refuses to boot with SHEERID_ENABLED and the default mock client in production', function () {
process.env.SHEERID_ENABLED = 'true'
delete process.env.SHEERID_MOCK // defaults to mock: true
process.env.NODE_ENV = 'production'
clearSettingsCache()
expect(() =>
require('../../../../config/settings.overrides.saas.js')
).to.throw(/SHEERID_ENABLED/)
})
it('boots with SHEERID_ENABLED, SHEERID_MOCK=false and credentials in production', function () {
process.env.SHEERID_ENABLED = 'true'
process.env.SHEERID_MOCK = 'false'
process.env.NODE_ENV = 'production'
setCredentials()
clearSettingsCache()
expect(() =>
require('../../../../config/settings.overrides.saas.js')
).not.to.throw()
})
it('refuses to boot with the real client and no credentials in production', function () {
process.env.SHEERID_ENABLED = 'true'
process.env.SHEERID_MOCK = 'false'
process.env.NODE_ENV = 'production'
delete process.env.SHEERID_CLIENT_ID
delete process.env.SHEERID_CLIENT_SECRET
delete process.env.SHEERID_PROGRAM_ID
clearSettingsCache()
expect(() =>
require('../../../../config/settings.overrides.saas.js')
).to.throw(/SHEERID_CLIENT_ID, SHEERID_CLIENT_SECRET, SHEERID_PROGRAM_ID/)
})
it('names only the credentials that are missing', function () {
process.env.SHEERID_ENABLED = 'true'
process.env.SHEERID_MOCK = 'false'
process.env.NODE_ENV = 'production'
setCredentials()
delete process.env.SHEERID_PROGRAM_ID
clearSettingsCache()
expect(() =>
require('../../../../config/settings.overrides.saas.js')
).to.throw(/requires SHEERID_PROGRAM_ID/)
})
it('boots with the real client and no credentials outside production', function () {
process.env.SHEERID_ENABLED = 'true'
process.env.SHEERID_MOCK = 'false'
process.env.NODE_ENV = 'test'
delete process.env.SHEERID_CLIENT_ID
delete process.env.SHEERID_CLIENT_SECRET
delete process.env.SHEERID_PROGRAM_ID
clearSettingsCache()
expect(() =>
require('../../../../config/settings.overrides.saas.js')
).not.to.throw()
})
it('boots with SHEERID_ENABLED and the default mock client outside production', function () {
process.env.SHEERID_ENABLED = 'true'
delete process.env.SHEERID_MOCK
process.env.NODE_ENV = 'test'
clearSettingsCache()
expect(() =>
require('../../../../config/settings.overrides.saas.js')
).not.to.throw()
})
})