fix(daemon): report a helper's denial over a later allowed result

Overlapping tccd requests can resolve out of order; when any result for the
denied folder class is a denial, report it.
This commit is contained in:
Jinwoo-H
2026-11-13 20:21:00 -05:00
parent 67d8a539f6
commit 508cd4b0b5
2 changed files with 22 additions and 0 deletions
@@ -173,7 +173,12 @@ export function parseTccLogVerdict(
const relevantGroups = [...groups.values()].filter((group) => group.relevant)
const decided = relevantGroups.filter((group) => group.result !== null)
// Overlapping requests can resolve out of order; a later "allowed" must not mask a denial.
const denied = decided.filter((group) => group.result?.authValue === '0')
const chosen =
denied.findLast(
(group) => group.service !== null && SERVICE_BY_NAME[group.service] === subject.cwdClass
) ??
decided.findLast(
(group) => group.service !== null && SERVICE_BY_NAME[group.service] === subject.cwdClass
) ??
@@ -149,6 +149,23 @@ describe('parseTccLogVerdict', () => {
expect(documents).toMatchObject({ service: 'documents', authValue: 'allowed' })
})
it('keeps a denial that resolves after a later request was allowed', () => {
const [send, ctx, attribution, deniedResult] = HELPER_DOWNLOADS_REFUSED
const later = [send, ctx, attribution].map((entry) =>
entry.replaceAll('msgID=153.1126', 'msgID=153.1127')
)
const allowedResult = deniedResult
.replace('msgID=153.1126', 'msgID=153.1127')
.replace('authValue=0', 'authValue=2')
// Request 1126 starts first, 1127 is allowed, then 1126 is refused.
const verdict = parseTccLogVerdict(
ndjson([send, ctx, attribution, ...later, allowedResult, deniedResult]),
SUBJECT,
'ok'
)
expect(verdict).toMatchObject({ authValue: 'denied', service: 'downloads' })
})
it('flags a failed stored requirement but not the routine "anchor apple" check', () => {
const routine = line(
'20:06:45.144194',