Files
core/src/authorization/remediation.js
T
John Dvorak 717ae1031e initial commit: @arbiter/core authorization engine with js-rigor hardening
Zanzibar-style authorization graph engine (direct/chain/TTU/defeasible/
binary modes, condensed snapshots, value relations) with 39 rigor test
campaigns. Includes fixes for snapshot binary writer/reader format
mismatch (snapshot-of-snapshot corruption), possibility write-boundary
validation, empty-graph snapshot serialization, relation lookup cache
direction collision, config-redefinition cache invalidation, binary
threshold semantics, defeasible compiled routing, and comparator
reason whitelisting.
2026-07-31 13:44:06 -07:00

68 lines
2.2 KiB
JavaScript

export function extractRemediation(res) {
return res?.remediation || null;
}
export function mergeRemediationOptions(into, remediation) {
if (!Array.isArray(remediation?.options)) return;
for (const option of remediation.options) {
if (!option?.relation || !option?.object) continue;
into.push(option);
}
}
export function buildRemediation(remediation = null, options = {}) {
if (!remediation && !Array.isArray(options.additional_options)) return null;
const mergedOptions = [];
mergeRemediationOptions(mergedOptions, remediation);
if (Array.isArray(options.additional_options)) {
for (const option of options.additional_options) {
if (!option?.relation || !option?.object) continue;
mergedOptions.push(option);
}
}
if (mergedOptions.length === 0) return null;
const deduped = [];
const seen = new Set();
for (const option of mergedOptions) {
const key = `${option.relation}|${option.object}|${option.url || ''}|${option.method || ''}`;
if (seen.has(key)) continue;
seen.add(key);
deduped.push(option);
}
return {
status: options.status || remediation?.status || 'required',
...(options.request_id
? { request_id: options.request_id }
: (remediation?.request_id ? { request_id: remediation.request_id } : {})),
options: deduped
};
}
export function buildRemediationFromChallenges(challengeRequirements, options = {}) {
const list = Array.isArray(challengeRequirements)
? challengeRequirements
: (challengeRequirements ? [challengeRequirements] : []);
const derivedOptions = [];
for (const requirement of list) {
const challengeName = String(requirement?.name || '').trim().replace(/^!/, '');
if (!challengeName) continue;
const metadata = {};
if (requirement?.subject) metadata.subject = requirement.subject;
if (requirement?.withinMs !== undefined && requirement?.withinMs !== null) {
metadata.within_ms = requirement.withinMs;
}
derivedOptions.push({
relation: 'challenge_satisfied',
object: `challenge:${challengeName}`,
...(Object.keys(metadata).length > 0 ? { metadata } : {})
});
}
return buildRemediation(null, {
...options,
additional_options: derivedOptions
});
}