Skip to main content
ApprovalResult is the full audit-ready record returned by every gate evaluation. It contains the final verdict, risk assessment, challenge result (if applicable), review timing, and audit metadata. ChallengeResult is a nested dataclass that captures the outcome of a specific verification challenge.

ApprovalResult

Import

from attesta import ApprovalResult

Fields

FieldTypeDefaultDescription
verdictVerdictrequiredThe outcome of the review. See Verdict enum.
risk_assessmentRiskAssessmentrequiredThe full risk assessment including score, level, and contributing factors.
challenge_resultChallengeResult | NoneNoneThe outcome of the verification challenge. None when the action was auto-approved (LOW risk).
approverslist[str][]List of approver identifiers. Populated by multi-party challenges.
review_time_secondsfloat0.0Wall-clock time from interception to final verdict, in seconds.
audit_entry_idstr | NoneNoneUnique ID of the audit log entry. Set after the audit logger persists the record.
timestampdatetimedatetime.now()When the result was produced.
modificationstr | NoneNoneDescription of how the action was modified. Populated only when verdict is MODIFIED.

Usage

from attesta import Attesta, ActionContext, Verdict

attesta = Attesta.from_config("attesta.yaml")

ctx = ActionContext(
    function_name="deploy",
    args=("api-gateway", "2.1.0"),
    environment="production",
)

result = await attesta.evaluate(ctx)

# Check the verdict
if result.verdict == Verdict.APPROVED:
    print("Action approved!")
    print(f"Risk: {result.risk_assessment.level.value}")
    print(f"Score: {result.risk_assessment.score:.2f}")
    print(f"Review time: {result.review_time_seconds:.1f}s")
    print(f"Audit ID: {result.audit_entry_id}")

elif result.verdict == Verdict.DENIED:
    print("Action denied.")
    if result.challenge_result:
        print(f"Challenge type: {result.challenge_result.challenge_type.value}")
        print(f"Questions correct: {result.challenge_result.questions_correct}"
              f"/{result.challenge_result.questions_asked}")

elif result.verdict == Verdict.MODIFIED:
    print(f"Action modified: {result.modification}")

Accessing via AttestaDenied

When a gated function is denied, the AttestaDenied exception carries the full ApprovalResult:
Python
from attesta import gate, AttestaDenied

@gate(risk="critical")
def drop_table(name: str) -> str:
    """Drop a database table."""
    return f"Dropped {name}"

try:
    drop_table("users")
except AttestaDenied as e:
    result = e.result  # ApprovalResult | None
    if result:
        print(f"Verdict: {result.verdict.value}")
        print(f"Risk score: {result.risk_assessment.score:.2f}")
        print(f"Risk level: {result.risk_assessment.level.value}")
        for factor in result.risk_assessment.factors:
            print(f"  - {factor.name}: {factor.contribution:.3f}")

ChallengeResult

Captures the outcome of a single verification challenge. This is None in the ApprovalResult when the action was auto-approved.

Import

from attesta import ChallengeResult

Fields

FieldTypeDefaultDescription
passedboolrequiredWhether the challenge was successfully completed.
challenge_typeChallengeTyperequiredThe type of challenge that was presented. See ChallengeType enum.
responderstr"default"Identifier for who completed the challenge. Defaults to "default" for single-party challenges.
response_time_secondsfloat0.0Time taken to complete the challenge, in seconds.
questions_askedint0Number of questions presented (quiz and teach-back challenges).
questions_correctint0Number of questions answered correctly (quiz challenges).
detailsdict[str, Any]{}Additional challenge-specific metadata.

Challenge-Specific Details

The details dict contains different keys depending on the challenge type: Confirm challenge:
{
    "confirmed": True,
    "review_seconds": 4.2,
}
Quiz challenge:
{
    "questions": [
        {"question": "What table will be dropped?", "expected": "users", "given": "users"},
        {"question": "Is this reversible?", "expected": "no", "given": "no"},
    ],
    "pass_threshold": 0.8,
    "actual_score": 1.0,
}
Teach-back challenge:
{
    "explanation": "This will permanently delete the users table from the production database.",
    "word_count": 12,
    "key_terms_matched": ["delete", "users", "production"],
    "key_terms_required": ["delete", "users", "production", "table"],
}
Multi-party challenge:
{
    "approvers": [
        {"id": "alice", "challenge": "teach_back", "passed": True},
        {"id": "bob", "challenge": "quiz", "passed": True},
        {"id": "carol", "challenge": "confirm", "passed": True},
    ],
    "required_approvers": 2,
    "actual_approvers": 3,
}

Example: Inspecting a Challenge Result

from attesta import Attesta, ActionContext, ChallengeType

attesta = Attesta.from_config("attesta.yaml")

ctx = ActionContext(
    function_name="delete_user",
    args=("usr_12345",),
    function_doc="Permanently delete a user account and all associated data.",
    environment="production",
)

result = await attesta.evaluate(ctx)

if result.challenge_result:
    cr = result.challenge_result
    print(f"Challenge: {cr.challenge_type.value}")
    print(f"Passed: {cr.passed}")
    print(f"Response time: {cr.response_time_seconds:.1f}s")

    if cr.challenge_type == ChallengeType.QUIZ:
        print(f"Score: {cr.questions_correct}/{cr.questions_asked}")

    if cr.challenge_type == ChallengeType.MULTI_PARTY:
        for approver in cr.details.get("approvers", []):
            print(f"  {approver['id']}: {approver['challenge']} -> {'passed' if approver['passed'] else 'failed'}")
else:
    print("Auto-approved (no challenge presented)")
The challenge_result is None when the risk level is LOW and the default challenge map routes to auto_approve. In this case, result.verdict is APPROVED and no human interaction occurred.

AttestaDenied Exception

Raised by the @gate decorator when a gated function call is denied, timed out, or escalated.

Import

from attesta import AttestaDenied

Constructor

ParameterTypeDefaultDescription
messagestr"Action denied by attesta"Human-readable error message.
resultApprovalResult | NoneNoneThe full approval result, if available.

Properties

PropertyTypeDescription
messagestrThe error message (inherited from Exception).
resultApprovalResult | NoneThe full approval result with verdict, risk assessment, and challenge details.
Always check e.result is not None before accessing result fields. The result may be None if the exception was raised before the evaluation completed (e.g., during context construction).