// Unit: the git push-gate decision matrix (issue #37, item 2).
//
// canPushGit reuses the IdentityRegistry user-perm model. This tests the
// decision branches with a faithful stand-in registry; the real
// IdentityRegistry is exercised end-to-end in the HTTP/punch ACL tests.
import test from 'brittle'
import { canPushGit } from '../lib/auth/git-acl.js'
// Faithful stand-in: same method shapes as hyper-identity IdentityRegistry.
function fakeRegistry ({ usersByIdentity = {}, identitiesByNoise = {} } = {}) {
return {
async getUserByIdentity (id) { return usersByIdentity[id] || null },
async getIdentityByNoiseKey (nk) { return identitiesByNoise[nk] || null }
}
}
test('canPushGit: UDS and ownerMatched always allowed', async (t) => {
t.ok(await canPushGit(null, { transport: 'uds' }), 'uds trusted even with no registry')
t.ok(await canPushGit(null, { ownerMatched: true }), 'owner trusted even with no registry')
})
test('canPushGit: identityId → user perms gate push', async (t) => {
const reg = fakeRegistry({
usersByIdentity: {
adminUser: { globalPermissions: ['admin'] },
writeUser: { globalPermissions: ['write'] },
readUser: { globalPermissions: ['read'] },
noPerms: { globalPermissions: [] }
}
})
t.ok(await canPushGit(reg, { transport: 'http', identityId: 'adminUser' }), 'admin can push')
t.ok(await canPushGit(reg, { transport: 'http', identityId: 'writeUser' }), 'write can push')
t.absent(await canPushGit(reg, { transport: 'http', identityId: 'readUser' }), 'read cannot push')
t.absent(await canPushGit(reg, { transport: 'http', identityId: 'noPerms' }), 'no perms cannot push')
t.absent(await canPushGit(reg, { transport: 'http', identityId: 'unknown' }), 'unknown identity cannot push')
})
test('canPushGit: swarm noise key resolves via linked identity', async (t) => {
const reg = fakeRegistry({
usersByIdentity: { 'ident-1': { globalPermissions: ['write'] } },
identitiesByNoise: { noiseAAA: { identityId: 'ident-1' } }
})
t.ok(await canPushGit(reg, { transport: 'swarm', noiseKey: 'noiseAAA' }),
'linked noise key → write user → push allowed')
t.absent(await canPushGit(reg, { transport: 'swarm', noiseKey: 'noiseUnknown' }),
'unlinked noise key → denied (safe default)')
})
test('canPushGit: no caller info or no registry → denied', async (t) => {
t.absent(await canPushGit(null, { transport: 'http' }), 'no registry → denied')
t.absent(await canPushGit(fakeRegistry(), { transport: 'swarm' }), 'no identity/noise key → denied')
})