process method

Future<SecurityResult> process(
  1. RequestContext context
)

Runs context through every layer in order.

Behavior:

  • If a layer returns allowed: false, the pipeline stops immediately and that layer's result (blocked) is returned as the final result.
  • If a layer returns allowed: true but flags the request (verdict == flagged), the pipeline continues, but the highest risk score and accumulated flags are carried into the final result.
  • If every layer allows the request, an aggregated "allowed" result is returned, carrying the maximum risk score seen and all flags collected along the way.

Implementation

Future<SecurityResult> process(RequestContext context) async {
  final List<String> accumulatedFlags = [];
  double maxRiskScore = 0.0;
  bool sawFlag = false;

  for (final layer in layers) {
    final rawResult = await layer.check(context);
    final result = rawResult.layerName == null
        ? rawResult.withLayerName(layer.name)
        : rawResult;

    onLayerResult?.call(context, result);

    accumulatedFlags.addAll(result.flags);
    if (result.riskScore > maxRiskScore) {
      maxRiskScore = result.riskScore;
    }
    if (result.verdict == SecurityVerdict.flagged) {
      sawFlag = true;
    }

    // Fail-fast: stop the pipeline the instant a layer blocks.
    if (!result.allowed) {
      return SecurityResult(
        allowed: false,
        riskScore: maxRiskScore,
        flags: accumulatedFlags,
        message: 'Blocked at "${layer.name}": ${result.message}',
        verdict: SecurityVerdict.blocked,
        layerName: layer.name,
      );
    }
  }

  // Every layer passed. Decide between "allowed" and "flagged" based on
  // whether any layer raised a flag along the way.
  return SecurityResult(
    allowed: true,
    riskScore: maxRiskScore,
    flags: accumulatedFlags,
    message: sawFlag
        ? 'Request allowed but flagged for review'
        : 'Request allowed',
    verdict: sawFlag ? SecurityVerdict.flagged : SecurityVerdict.allowed,
    layerName: null,
  );
}