First public release

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-28 14:49:00 -04:00
co-authored by Claude Opus 5.5
commit 14ba140354
14 changed files with 2390 additions and 0 deletions
+206
View File
@@ -0,0 +1,206 @@
import { describe, expect, it } from 'vitest'
import { overall, validateReport } from '@extant2000/evidence-record'
import { checkClaims, formatClaims, type CryptoInventory } from '../src/index.js'
/**
* The shape this library is built around: a notes feature that really is
* encrypted with a sound cipher, and is NOT end-to-end, because the server
* holds the key.
*/
const notes: CryptoInventory = {
claims: ['end-to-end-encrypted', 'encrypted-at-rest'],
keys: [{
keyId: 'NOTES_KEY',
heldBy: ['server', 'operator'],
location: 'config/app.env',
protects: 'note bodies',
}],
ciphers: [{
algorithm: 'AES',
mode: 'GCM',
keyBits: 256,
purpose: 'at-rest',
where: 'src/notes/store.ts',
line: 88,
}],
}
describe('custody is the check that matters', () => {
it('sound cipher, false claim', () => {
// Every cryptographic choice here is correct. The claim is still untrue,
// and no amount of checking the algorithm would have caught it.
const r = checkClaims(notes)
const e2e = r.findings.find(f => f.id === 'end-to-end-encrypted')!
const atRest = r.findings.find(f => f.id === 'encrypted-at-rest')!
expect(e2e.determination).toBe('fail')
expect(atRest.determination).toBe('pass') // the encryption really is fine
expect(overall(r)).toBe('fail')
})
it('names who holds the key, not just that the claim failed', () => {
const text = formatClaims(notes, { evidence: 'full' })
expect(text).toContain('config/app.env')
expect(text).toContain('server, operator')
expect(text).toContain('this is encryption at rest, not end-to-end')
})
it('ignores cipher strength entirely for a custody claim', () => {
// AES-256-GCM does not make an operator-held key end-to-end.
const stronger: CryptoInventory = {
...notes,
ciphers: [{ ...notes.ciphers![0]!, keyBits: 512 }],
}
expect(checkClaims(stronger).findings[0]!.determination).toBe('fail')
})
it('passes a custody claim when only the client holds the key', () => {
const r = checkClaims({
claims: ['end-to-end-encrypted'],
keys: [{ keyId: 'k', heldBy: ['client'], location: 'browser/keystore.ts', protects: 'messages' }],
})
expect(overall(r)).toBe('pass')
})
it('treats an HSM-held key as compatible with the claim', () => {
// A key that never leaves an HSM is not readable by the operator, which
// is the property the claim is about.
const r = checkClaims({
claims: ['zero-knowledge'],
keys: [{ keyId: 'k', heldBy: ['hsm'], location: 'kms://arn', protects: 'records' }],
})
expect(overall(r)).toBe('pass')
})
it('treats a third party as disqualifying', () => {
// "End-to-end with a vendor in the middle" is the marketing sense of the
// phrase, not the technical one.
const r = checkClaims({
claims: ['end-to-end-encrypted'],
keys: [{ keyId: 'k', heldBy: ['client', 'third-party'], location: 'vendor.md', protects: 'x' }],
})
expect(overall(r)).toBe('fail')
})
it('reports an undescribed custody as not-assessed, never a pass', () => {
const r = checkClaims({ claims: ['end-to-end-encrypted'] })
expect(r.findings[0]!.determination).toBe('not-assessed')
expect(overall(r)).toBe('not-assessed')
expect(formatClaims({ claims: ['end-to-end-encrypted'] })).not.toContain('✓')
})
})
describe('primitives', () => {
const at = (algorithm: string, mode?: string): CryptoInventory => ({
claims: ['encrypted-at-rest'],
ciphers: [{ algorithm, mode, purpose: 'at-rest', where: 'lib/crypto.ts', line: 4 }],
})
it('fails a broken algorithm', () => {
expect(checkClaims(at('3DES')).findings[0]!.determination).toBe('fail')
expect(checkClaims(at('RC4')).findings[0]!.detail).toContain('RFC 7465')
})
it('fails ECB regardless of the cipher', () => {
const f = checkClaims(at('AES', 'ECB')).findings[0]!
expect(f.determination).toBe('fail')
expect(f.detail).toContain('identical blocks encrypt identically')
})
it('accepts AES-GCM', () => {
expect(checkClaims(at('AES', 'GCM')).findings[0]!.determination).toBe('pass')
})
it('reports a broken primitive even when nothing was claimed about it', () => {
// The absence of a marketing sentence is not a reason to leave MD5 in a
// signature path.
const r = checkClaims({
claims: [],
ciphers: [{ algorithm: 'MD5', purpose: 'signature', where: 'lib/sign.ts', line: 12 }],
})
expect(r.findings).toHaveLength(1)
expect(r.findings[0]!.severity).toBe('critical')
expect(r.findings[0]!.detail).toContain('collision-broken')
})
})
describe('passwords', () => {
const pw = (algorithm: string): CryptoInventory => ({
claims: ['passwords-hashed'],
ciphers: [{ algorithm, purpose: 'password', where: 'server/api/auth.ts', line: 30 }],
})
it('fails a fast hash — right for integrity, wrong for a password', () => {
const f = checkClaims(pw('SHA-256')).findings[0]!
expect(f.determination).toBe('fail')
expect(f.detail).toContain('catastrophic for passwords')
})
it('fails a reversible cipher, which is not hashing at all', () => {
expect(checkClaims(pw('AES')).findings[0]!.determination).toBe('fail')
})
it('accepts a real KDF', () => {
for (const kdf of ['bcrypt', 'argon2id', 'scrypt', 'PBKDF2']) {
expect(checkClaims(pw(kdf)).findings[0]!.determination).toBe('pass')
}
})
})
describe('transport', () => {
it('fails a TLS floor below 1.2', () => {
const f = checkClaims({
claims: ['encrypted-in-transit'],
transport: [{ minTlsVersion: '1.0', where: 'config/tls.yml' }],
}).findings[0]!
expect(f.determination).toBe('fail')
expect(f.detail).toContain('RFC 8996')
})
it('accepts a 1.2 floor and a 1.3 floor', () => {
for (const v of ['1.2', '1.3']) {
expect(checkClaims({
claims: ['encrypted-in-transit'],
transport: [{ minTlsVersion: v, where: 'config/tls.yml' }],
}).findings[0]!.determination).toBe('pass')
}
})
it('reports an unpinned floor as not-assessed, not a pass', () => {
// Without a floor the answer is the runtime default, which is not a
// property of this system and can change under it.
const f = checkClaims({
claims: ['encrypted-in-transit'],
transport: [{ where: 'config/tls.yml' }],
}).findings[0]!
expect(f.determination).toBe('not-assessed')
})
it('fails forward secrecy on a non-ephemeral suite', () => {
const f = checkClaims({
claims: ['forward-secrecy'],
transport: [{ where: 'config/tls.yml', cipherSuites: ['TLS_RSA_WITH_AES_128_CBC_SHA'] }],
}).findings[0]!
expect(f.determination).toBe('fail')
expect(f.detail).toContain('retroactively decrypts')
})
it('accepts ephemeral suites', () => {
expect(checkClaims({
claims: ['forward-secrecy'],
transport: [{ where: 't.yml', cipherSuites: ['TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'] }],
}).findings[0]!.determination).toBe('pass')
})
})
describe('conformance with the evidence-record standard', () => {
it('every conclusion carries a citation', () => {
expect(validateReport(checkClaims(notes))).toEqual([])
})
it('an empty inventory is not-assessed, never clean', () => {
const r = checkClaims({ claims: [] })
expect(overall(r)).toBe('not-assessed')
expect(formatClaims({ claims: [] })).not.toContain('✓')
})
})