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.
This commit is contained in:
@@ -0,0 +1,260 @@
|
||||
import { BaseNode } from './BaseNode.js';
|
||||
|
||||
/**
|
||||
* AST node for expressions (variables, literals, attribute access, etc.)
|
||||
*/
|
||||
export class ExpressionNode extends BaseNode {
|
||||
constructor(expressionType, location = null) {
|
||||
super('Expression', location);
|
||||
this.expressionType = expressionType; // 'variable', 'literal', 'attribute', 'function', etc.
|
||||
this.value = null;
|
||||
this.name = null;
|
||||
this.attribute = null;
|
||||
this.object = null;
|
||||
this.arguments = [];
|
||||
this.operator = null;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value for this expression
|
||||
* @param {*} value - Value to set
|
||||
*/
|
||||
setValue(value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name for this expression
|
||||
* @param {string} name - Name to set
|
||||
*/
|
||||
setName(name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the attribute for this expression
|
||||
* @param {string} attribute - Attribute to set
|
||||
*/
|
||||
setAttribute(attribute) {
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the object for this expression
|
||||
* @param {ExpressionNode} object - Object to set
|
||||
*/
|
||||
setObject(object) {
|
||||
this.object = object;
|
||||
this.addChild(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an argument to this expression
|
||||
* @param {ExpressionNode} argument - Argument to add
|
||||
*/
|
||||
addArgument(argument) {
|
||||
this.arguments.push(argument);
|
||||
this.addChild(argument);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the operator for this expression
|
||||
* @param {string} operator - Operator to set
|
||||
*/
|
||||
setOperator(operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the left operand for this expression
|
||||
* @param {ExpressionNode} left - Left operand to set
|
||||
*/
|
||||
setLeft(left) {
|
||||
this.left = left;
|
||||
this.addChild(left);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the right operand for this expression
|
||||
* @param {ExpressionNode} right - Right operand to set
|
||||
*/
|
||||
setRight(right) {
|
||||
this.right = right;
|
||||
this.addChild(right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a variable expression
|
||||
* @returns {boolean} True if variable
|
||||
*/
|
||||
isVariable() {
|
||||
return this.expressionType === 'variable';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a literal expression
|
||||
* @returns {boolean} True if literal
|
||||
*/
|
||||
isLiteral() {
|
||||
return this.expressionType === 'literal';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is an attribute access expression
|
||||
* @returns {boolean} True if attribute access
|
||||
*/
|
||||
isAttributeAccess() {
|
||||
return this.expressionType === 'attribute';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a function call expression
|
||||
* @returns {boolean} True if function call
|
||||
*/
|
||||
isFunctionCall() {
|
||||
return this.expressionType === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a binary operation expression
|
||||
* @returns {boolean} True if binary operation
|
||||
*/
|
||||
isBinaryOperation() {
|
||||
return this.expressionType === 'binary';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this is a wildcard variable
|
||||
* @returns {boolean} True if wildcard
|
||||
*/
|
||||
isWildcard() {
|
||||
return this.isVariable() && this.name && this.name.startsWith('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variable name (without wildcard prefix)
|
||||
* @returns {string|null} Variable name or null
|
||||
*/
|
||||
getVariableName() {
|
||||
if (this.isVariable() && this.name) {
|
||||
return this.name.startsWith('*') ? this.name.substring(1) : this.name;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full attribute path
|
||||
* @returns {string|null} Full attribute path or null
|
||||
*/
|
||||
getAttributePath() {
|
||||
if (this.isAttributeAccess()) {
|
||||
const objStr = this.object ? this.object.toString() : '';
|
||||
return `${objStr}.${this.attribute}`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the function signature
|
||||
* @returns {string|null} Function signature or null
|
||||
*/
|
||||
getFunctionSignature() {
|
||||
if (this.isFunctionCall()) {
|
||||
const argStr = this.arguments.map(arg => arg.toString()).join(', ');
|
||||
return `${this.name}(${argStr})`;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the expression
|
||||
* @returns {string[]} Array of error messages
|
||||
*/
|
||||
validate() {
|
||||
const errors = [];
|
||||
|
||||
// Validate expression type
|
||||
const validTypes = ['variable', 'literal', 'attribute', 'function', 'binary'];
|
||||
if (!validTypes.includes(this.expressionType)) {
|
||||
errors.push(`Invalid expression type: ${this.expressionType}`);
|
||||
}
|
||||
|
||||
// Validate variable expressions
|
||||
if (this.isVariable() && !this.name) {
|
||||
errors.push('Variable expression must have a name');
|
||||
}
|
||||
|
||||
// Validate literal expressions
|
||||
if (this.isLiteral() && this.value === null) {
|
||||
errors.push('Literal expression must have a value');
|
||||
}
|
||||
|
||||
// Validate attribute access expressions
|
||||
if (this.isAttributeAccess()) {
|
||||
if (!this.attribute) {
|
||||
errors.push('Attribute access expression must have an attribute');
|
||||
}
|
||||
if (this.object) {
|
||||
const objErrors = this.object.validate ? this.object.validate() : [];
|
||||
errors.push(...objErrors);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate function call expressions
|
||||
if (this.isFunctionCall()) {
|
||||
if (!this.name) {
|
||||
errors.push('Function call expression must have a name');
|
||||
}
|
||||
this.arguments.forEach((arg, index) => {
|
||||
const argErrors = arg.validate ? arg.validate() : [];
|
||||
errors.push(...argErrors.map(err => `Argument ${index + 1}: ${err}`));
|
||||
});
|
||||
}
|
||||
|
||||
// Validate binary operation expressions
|
||||
if (this.isBinaryOperation()) {
|
||||
if (!this.operator) {
|
||||
errors.push('Binary operation expression must have an operator');
|
||||
}
|
||||
if (!this.left) {
|
||||
errors.push('Binary operation expression must have a left operand');
|
||||
}
|
||||
if (!this.right) {
|
||||
errors.push('Binary operation expression must have a right operand');
|
||||
}
|
||||
if (this.left) {
|
||||
const leftErrors = this.left.validate ? this.left.validate() : [];
|
||||
errors.push(...leftErrors);
|
||||
}
|
||||
if (this.right) {
|
||||
const rightErrors = this.right.validate ? this.right.validate() : [];
|
||||
errors.push(...rightErrors);
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
toString() {
|
||||
switch (this.expressionType) {
|
||||
case 'variable':
|
||||
return `Variable(${this.name})`;
|
||||
case 'literal':
|
||||
return `Literal(${this.value})`;
|
||||
case 'attribute':
|
||||
const objStr = this.object ? this.object.toString() : '';
|
||||
return `Attribute(${objStr}.${this.attribute})`;
|
||||
case 'function':
|
||||
const argStr = this.arguments.map(arg => arg.toString()).join(', ');
|
||||
return `Function(${this.name}(${argStr}))`;
|
||||
case 'binary':
|
||||
const leftStr = this.left ? this.left.toString() : 'null';
|
||||
const rightStr = this.right ? this.right.toString() : 'null';
|
||||
return `Binary(${leftStr} ${this.operator} ${rightStr})`;
|
||||
default:
|
||||
return `Expression(${this.expressionType})`;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user