Skip to content

Add opt-in AURA trust-check adapter (integrations/aura)#2026

Open
luisllaver wants to merge 21 commits into
affaan-m:mainfrom
luisllaver:aura-trust-check-adapter
Open

Add opt-in AURA trust-check adapter (integrations/aura)#2026
luisllaver wants to merge 21 commits into
affaan-m:mainfrom
luisllaver:aura-trust-check-adapter

Conversation

@luisllaver
Copy link
Copy Markdown

@luisllaver luisllaver commented May 20, 2026

Opt-in, read-only AURA trust-check adapter, per the boundary agreed in discussion #2003.

What it is — a integrations/aura module that lets an ECC agent check a counterparty's
backward-looking reputation before delegating or settling. External adapter, zero core
coupling
, no escrow/wallet signing, fail-closed by default.

API

  • aura_verdict(did) → typed {verdict, reason, score, ...} (verdict ∈ trusted|caution|high_risk|new|unknown)
  • before_settle(did) / require_trust(did) → gate that raises AuraUntrusted on high_risk + unknown
  • one network call: GET /check?did=... (zero-auth). No PII, no keys, nothing stored.

Boundary — pure stdlib (no deps). On an unreachable AURA the verdict is unknown and the
default gate rejects it (fail-closed); flip fail_open=True to invert. Purely additive: remove the
module and ECC behaves exactly as before.

Testspython -m pytest integrations/aura/tests → 20 offline tests (VCR-style, no network):
every verdict class, the gate's allow-list + fail_open, the unreachable path, input validation.

See integrations/aura/README.md (enable section) and THREAT_MODEL.md (6 failure modes:
spoofed DID, stale verdict, MITM, Sybil, over-trust, unreachable).

Opened as draft for you to route against the partner/integration lane. Happy to adjust the
boundary, naming, or test layout to match ECC conventions.


Summary by cubic

Adds an opt-in, read-only AURA trust-check adapter to gate settlement or delegation on a counterparty’s reputation. One GET to AURA, fail-closed by default, zero deps, and no core coupling.

  • New Features

    • New integrations/aura module with aura_verdict, before_settle (require_trust alias), and AuraUntrusted/AuraVerdict; exports DEFAULT_BASE_URL and DEFAULT_ALLOW.
    • Verdicts: trusted, caution, high_risk, new, unknown. Result includes ok, reason, score, dimensions, has_history, and reachable; .as_dict() returns a minimal shape.
    • Default gate rejects high_risk and unknown; allows trusted, caution, new. fail_open only passes unknown when AURA is unreachable; reachable unknown is still rejected. Configurable base_url and timeout.
    • Network/parse errors return unknown (no exceptions). Pure stdlib. Remove the module to disable.
  • Migration

    • Call before_settle(did) at trust boundaries and handle AuraUntrusted.
    • Tighten policy with allow=("trusted","caution"); to avoid outage blocking use fail_open=True.

Written for commit 02996a1. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • Opt-in AURA trust-check adapter producing verdicts: trusted, caution, high_risk, new, unknown.
    • Configurable trust gates (allow-lists, fail-open, timeouts, base URL) for enforcing trust before actions.
  • Documentation

    • Usage README with interpretation of verdict fields, configuration knobs, offline test replay, and optional verdict-colored badge.
    • Threat model detailing scope, failure modes, data flows, and caller responsibilities.
  • Tests

    • Offline test suite and fixtures validating verdicts, gate behavior, and error handling.

Review Change Stack

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 20, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

📝 Walkthrough

Walkthrough

This PR adds an opt-in, stdlib-only AURA trust-check adapter that GETs /check?did=... to produce AuraVerdict objects, provides a gating API (before_settle / require_trust) with configurable allow/fail_open, and delivers docs, a threat model, offline fixtures, and pytest coverage.

Changes

AURA Trust-Check Adapter

Layer / File(s) Summary
Documentation and Module Setup
integrations/aura/README.md, integrations/aura/THREAT_MODEL.md, integrations/aura/__init__.py, integrations/aura/adapter.py (module doc)
README documents opt-in usage, verdict meanings (trusted, caution, high_risk, new, unknown) and policy knobs; THREAT_MODEL describes semantics, failure modes, and trust boundaries; __init__.py exposes the public API and version; adapter module doc states design boundaries.
Verdict Data Model and Configuration
integrations/aura/adapter.py (constants & dataclass)
Defines defaults (DEFAULT_BASE_URL, DEFAULT_TIMEOUT, DEFAULT_ALLOW), recognized verdict vocabulary, AuraUntrusted exception, and the frozen AuraVerdict dataclass with ok, as_dict(), from_payload(), and unreachable() helpers.
Adapter Request and Gating Functions
integrations/aura/adapter.py (fetch & gates)
aura_verdict(did) validates DID, performs GET /check?did=... via an injectable _fetch, maps transport/parse/shape failures to an unreachable unknown verdict (no raise), and returns a parsed AuraVerdict; before_settle(did, allow, fail_open) enforces the allow-list, raises AuraUntrusted on disallowed verdicts, and supports fail_open=True only for transport-unreachable verdicts; require_trust aliases before_settle.
Test Fixtures and Integration Tests
integrations/aura/tests/fixtures.py, integrations/aura/tests/test_adapter.py
Adds RECORDED canned responses, make_fetch() and raising_fetch() stubs for offline testing, and pytest suite covering verdict labels, as_dict() contract, history/dimensions exposure, gating behavior (allow-list and fail-open), network-failure handling, and DID input validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through trust with care,
One GET request upon the air,
JSON verdicts bloom and shine,
Gates that check, then clear the line,
Welcome AURA to the warren's lair 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.93% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: introducing a new AURA trust-check adapter module. It is specific, clear, and captures the primary addition without extraneous details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@luisllaver luisllaver marked this pull request as ready for review May 21, 2026 00:20
@luisllaver luisllaver requested a review from affaan-m as a code owner May 21, 2026 00:20
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
integrations/aura/tests/fixtures.py (1)

83-83: ⚡ Quick win

Return a copied fixture payload to avoid shared-state test bleed.

Line 83 returns the same mutable dict instance. If one test mutates it (directly or via raw), later tests can become order-dependent.

Proposed fix
+import copy
@@
-        return table.get(did, RECORDED["did:aura:ghost-bot"])
+        return copy.deepcopy(table.get(did, RECORDED["did:aura:ghost-bot"]))

As per coding guidelines, “Always create new objects, never mutate existing ones. Use immutable patterns to prevent hidden side effects and enable safe concurrency”.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/tests/fixtures.py` at line 83, The helper currently returns
the literal dict stored in RECORDED (via table.get(...)) which allows tests to
mutate shared state; change the return to return a fresh copy of the fixture
(use copy.deepcopy) so callers get an independent object. Ensure you import the
copy module and apply copy.deepcopy to the result of table.get(did,
RECORDED["did:aura:ghost-bot"]) so both the table-provided value and the default
RECORDED entry are cloned before returning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integrations/aura/__init__.py`:
- Around line 26-34: The __all__ export list is unsorted and triggers Ruff
RUF022; sort the entries in the __all__ list alphabetically (lexicographically)
so imports like "AuraUntrusted", "AuraVerdict", "DEFAULT_ALLOW",
"DEFAULT_BASE_URL", "aura_verdict", "before_settle", and "require_trust" are in
sorted order; update the __all__ definition (the __all__ variable in this
module) to a sorted sequence of the existing symbols to satisfy the linter.

In `@integrations/aura/adapter.py`:
- Around line 194-195: Tighten the fail-open bypass so it only applies to
transport/unreachable cases: change the condition that currently reads "if
fail_open and v.verdict == 'unknown' and not v.has_history: return v" to also
require the verdict to be an unreachable/transport outage indicator (e.g., check
a field like v.unreachable or v.is_unreachable or a specific verdict value such
as 'unreachable') so genuine "unknown counterparty" outcomes are not allowed
through; then add a regression test that calling
before_settle("did:aura:ghost-bot", fail_open=True, ...) still raises
AuraUntrusted to ensure the change blocks untrusted counterparties.
- Around line 151-153: Validate that caller-provided base_url uses the HTTPS
scheme before building the request URL: parse base_url with
urllib.parse.urlparse and check parsed.scheme == "https" (and reject or raise
ValueError / log and fail if not). Apply this check where base_url is used to
construct url (the code that builds url = f"{base_url.rstrip('/')}/check?" +
urllib.parse.urlencode({"did": did})) and ensure you perform the validation
prior to calling _fetch (and before any urllib.request.urlopen usage). Keep the
error path consistent with existing error handling (raise a clear exception or
return an error) so non-HTTPS inputs are rejected early.

In `@integrations/aura/README.md`:
- Around line 87-89: Update the pytest command in the README: the current
example "python -m pytest aura/tests -q" uses an incorrect path for contributors
running from the repo root; replace it with a repo-root-friendly command such as
"python -m pytest -q" (or the correct relative test package path) so tests run
without a “path not found” error, and ensure the README example is consistent
with how tests are invoked elsewhere in the project.

---

Nitpick comments:
In `@integrations/aura/tests/fixtures.py`:
- Line 83: The helper currently returns the literal dict stored in RECORDED (via
table.get(...)) which allows tests to mutate shared state; change the return to
return a fresh copy of the fixture (use copy.deepcopy) so callers get an
independent object. Ensure you import the copy module and apply copy.deepcopy to
the result of table.get(did, RECORDED["did:aura:ghost-bot"]) so both the
table-provided value and the default RECORDED entry are cloned before returning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: cfe5b0f5-289c-4c28-9a5c-0a8dc1e77663

📥 Commits

Reviewing files that changed from the base of the PR and between 1e8c7e7 and b72715b.

📒 Files selected for processing (7)
  • integrations/aura/README.md
  • integrations/aura/THREAT_MODEL.md
  • integrations/aura/__init__.py
  • integrations/aura/adapter.py
  • integrations/aura/tests/__init__.py
  • integrations/aura/tests/fixtures.py
  • integrations/aura/tests/test_adapter.py

Comment on lines +26 to +34
__all__ = [
"aura_verdict",
"before_settle",
"require_trust",
"AuraVerdict",
"AuraUntrusted",
"DEFAULT_BASE_URL",
"DEFAULT_ALLOW",
]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Sort __all__ to satisfy Ruff (RUF022).

This list is currently unsorted and will trigger lint warnings.

Suggested fix
 __all__ = [
-    "aura_verdict",
-    "before_settle",
-    "require_trust",
-    "AuraVerdict",
     "AuraUntrusted",
-    "DEFAULT_BASE_URL",
+    "AuraVerdict",
     "DEFAULT_ALLOW",
+    "DEFAULT_BASE_URL",
+    "aura_verdict",
+    "before_settle",
+    "require_trust",
 ]

As per coding guidelines, "Use ruff for linting Python code".

🧰 Tools
🪛 Ruff (0.15.13)

[warning] 26-34: __all__ is not sorted

Apply an isort-style sorting to __all__

(RUF022)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/__init__.py` around lines 26 - 34, The __all__ export list
is unsorted and triggers Ruff RUF022; sort the entries in the __all__ list
alphabetically (lexicographically) so imports like "AuraUntrusted",
"AuraVerdict", "DEFAULT_ALLOW", "DEFAULT_BASE_URL", "aura_verdict",
"before_settle", and "require_trust" are in sorted order; update the __all__
definition (the __all__ variable in this module) to a sorted sequence of the
existing symbols to satisfy the linter.

Comment on lines +151 to +153
url = f"{base_url.rstrip('/')}/check?" + urllib.parse.urlencode({"did": did})
try:
body = _fetch(url, timeout)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current code has urlopen usage but no explicit HTTPS scheme gate.
rg -nP 'def aura_verdict|base_url|urlopen|urlparse|scheme' integrations/aura/adapter.py

Repository: affaan-m/ECC

Length of output: 423


🏁 Script executed:

sed -n '115,160p' integrations/aura/adapter.py

Repository: affaan-m/ECC

Length of output: 1971


🏁 Script executed:

rg -n 'DEFAULT_BASE_URL|DEFAULT_TIMEOUT' integrations/aura/adapter.py | head -20

Repository: affaan-m/ECC

Length of output: 344


🏁 Script executed:

rg -n 'aura_verdict\(' integrations/aura/adapter.py | head -10

Repository: affaan-m/ECC

Length of output: 288


Validate base_url scheme is HTTPS before constructing network request.

Line 151 constructs a URL from caller-provided base_url without enforcing HTTPS. Since urllib.request.urlopen at line 127 accepts any scheme (http, file, ftp, etc.), a caller could pass a non-HTTPS URL, bypassing security expectations.

Proposed fix
 def aura_verdict(
@@
 ) -> AuraVerdict:
@@
     if not did or not str(did).startswith("did:"):
         raise ValueError(f"invalid DID: {did!r} (must start with 'did:')")
+    parsed = urllib.parse.urlparse(base_url)
+    if parsed.scheme != "https":
+        raise ValueError(f"invalid base_url scheme: {parsed.scheme!r} (expected 'https')")

     url = f"{base_url.rstrip('/')}/check?" + urllib.parse.urlencode({"did": did})

Per coding guidelines: "All user inputs must be validated" and "Never trust external data."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
url = f"{base_url.rstrip('/')}/check?" + urllib.parse.urlencode({"did": did})
try:
body = _fetch(url, timeout)
if not did or not str(did).startswith("did:"):
raise ValueError(f"invalid DID: {did!r} (must start with 'did:')")
parsed = urllib.parse.urlparse(base_url)
if parsed.scheme != "https":
raise ValueError(f"invalid base_url scheme: {parsed.scheme!r} (expected 'https')")
url = f"{base_url.rstrip('/')}/check?" + urllib.parse.urlencode({"did": did})
try:
body = _fetch(url, timeout)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/adapter.py` around lines 151 - 153, Validate that
caller-provided base_url uses the HTTPS scheme before building the request URL:
parse base_url with urllib.parse.urlparse and check parsed.scheme == "https"
(and reject or raise ValueError / log and fail if not). Apply this check where
base_url is used to construct url (the code that builds url =
f"{base_url.rstrip('/')}/check?" + urllib.parse.urlencode({"did": did})) and
ensure you perform the validation prior to calling _fetch (and before any
urllib.request.urlopen usage). Keep the error path consistent with existing
error handling (raise a clear exception or return an error) so non-HTTPS inputs
are rejected early.

Comment thread integrations/aura/adapter.py Outdated
Comment on lines +87 to +89
```bash
python -m pytest aura/tests -q
```
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the test command path in docs.

Line 88 likely points to the wrong path for this repo layout; contributors running from repo root may get “path not found”.

Suggested doc fix
-python -m pytest aura/tests -q
+python -m pytest integrations/aura/tests -q
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```bash
python -m pytest aura/tests -q
```
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/README.md` around lines 87 - 89, Update the pytest command
in the README: the current example "python -m pytest aura/tests -q" uses an
incorrect path for contributors running from the repo root; replace it with a
repo-root-friendly command such as "python -m pytest -q" (or the correct
relative test package path) so tests run without a “path not found” error, and
ensure the README example is consistent with how tests are invoked elsewhere in
the project.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

4 similar comments
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="integrations/aura/README.md">

<violation number="1" location="integrations/aura/README.md:88">
P2: Incorrect test path in README documentation — `aura/tests` should be `integrations/aura/tests`</violation>
</file>

<file name="integrations/aura/THREAT_MODEL.md">

<violation number="1" location="integrations/aura/THREAT_MODEL.md:32">
P2: Misleading security claim in threat model: adapter docs say MITM is mitigated by 'HTTPS to a pinned host', but `base_url` is fully configurable and the code does not enforce host or certificate pinning.</violation>
</file>

<file name="integrations/aura/tests/fixtures.py">

<violation number="1" location="integrations/aura/tests/fixtures.py:82">
P2: The replay stub only checks the `did` query param, so it won’t fail if the code under test calls the wrong endpoint path.</violation>
</file>

<file name="integrations/aura/adapter.py">

<violation number="1" location="integrations/aura/adapter.py:127">
P1: `base_url` is not validated to use HTTPS, allowing HTTP connections that could be intercepted and tampered with to bypass trust gating.</violation>

<violation number="2" location="integrations/aura/adapter.py:156">
P1: Over-broad `ValueError` exception handling can mask local misconfiguration and, with `fail_open=True`, may silently allow operations that should fail.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

body = _fetch(url, timeout)
except (urllib.error.URLError, TimeoutError, OSError) as e:
return AuraVerdict.unreachable(did, f"AURA unreachable: {e}")
except (json.JSONDecodeError, ValueError) as e:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Over-broad ValueError exception handling can mask local misconfiguration and, with fail_open=True, may silently allow operations that should fail.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At integrations/aura/adapter.py, line 156:

<comment>Over-broad `ValueError` exception handling can mask local misconfiguration and, with `fail_open=True`, may silently allow operations that should fail.</comment>

<file context>
@@ -0,0 +1,200 @@
+        body = _fetch(url, timeout)
+    except (urllib.error.URLError, TimeoutError, OSError) as e:
+        return AuraVerdict.unreachable(did, f"AURA unreachable: {e}")
+    except (json.JSONDecodeError, ValueError) as e:
+        return AuraVerdict.unreachable(did, f"AURA returned non-JSON: {e}")
+
</file context>
Suggested change
except (json.JSONDecodeError, ValueError) as e:
except json.JSONDecodeError as e:

# Signature: (url: str, timeout: float) -> dict (raises on transport error)
def _http_get_json(url: str, timeout: float) -> dict[str, Any]:
req = urllib.request.Request(url, headers={"User-Agent": "aura-adapter/1.0"})
with urllib.request.urlopen(req, timeout=timeout) as resp: # noqa: S310 (https only)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: base_url is not validated to use HTTPS, allowing HTTP connections that could be intercepted and tampered with to bypass trust gating.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At integrations/aura/adapter.py, line 127:

<comment>`base_url` is not validated to use HTTPS, allowing HTTP connections that could be intercepted and tampered with to bypass trust gating.</comment>

<file context>
@@ -0,0 +1,200 @@
+# Signature: (url: str, timeout: float) -> dict   (raises on transport error)
+def _http_get_json(url: str, timeout: float) -> dict[str, Any]:
+    req = urllib.request.Request(url, headers={"User-Agent": "aura-adapter/1.0"})
+    with urllib.request.urlopen(req, timeout=timeout) as resp:  # noqa: S310 (https only)
+        return json.loads(resp.read().decode("utf-8"))
+
</file context>

Comment thread integrations/aura/adapter.py Outdated
Offline — every call replays a recorded `/check` body, no network:

```bash
python -m pytest aura/tests -q
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Incorrect test path in README documentation — aura/tests should be integrations/aura/tests

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At integrations/aura/README.md, line 88:

<comment>Incorrect test path in README documentation — `aura/tests` should be `integrations/aura/tests`</comment>

<file context>
@@ -0,0 +1,105 @@
+Offline — every call replays a recorded `/check` body, no network:
+
+```bash
+python -m pytest aura/tests -q
+```
+
</file context>

| 1 | **Endpoint unreachable / timeout** | Returns `unknown` (never raises). Gate is fail-closed by default. | Choose `fail_open` deliberately; pick a sane `timeout`. |
| 2 | **Spoofed DID** — caller claims a DID it doesn't control | Out of scope: adapter checks reputation, not control of the key. | Verify DID control (signature challenge / auth) **before** trusting the verdict. |
| 3 | **Stale verdict** — score lags very recent bad behavior | Each call is live (no caching here). | If you cache the result, bound the TTL; don't reuse a verdict across sessions. |
| 4 | **Endpoint MITM / response tampering** | HTTPS to a pinned host (`agent.auraopenprotocol.org`). Verdict strings are validated against a fixed allow-list; unknown values collapse to `unknown`. | Don't point `base_url` at an untrusted mirror. Consider TLS pinning if your runtime supports it. |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Misleading security claim in threat model: adapter docs say MITM is mitigated by 'HTTPS to a pinned host', but base_url is fully configurable and the code does not enforce host or certificate pinning.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At integrations/aura/THREAT_MODEL.md, line 32:

<comment>Misleading security claim in threat model: adapter docs say MITM is mitigated by 'HTTPS to a pinned host', but `base_url` is fully configurable and the code does not enforce host or certificate pinning.</comment>

<file context>
@@ -0,0 +1,55 @@
+| 1 | **Endpoint unreachable / timeout** | Returns `unknown` (never raises). Gate is fail-closed by default. | Choose `fail_open` deliberately; pick a sane `timeout`. |
+| 2 | **Spoofed DID** — caller claims a DID it doesn't control | Out of scope: adapter checks reputation, not control of the key. | Verify DID control (signature challenge / auth) **before** trusting the verdict. |
+| 3 | **Stale verdict** — score lags very recent bad behavior | Each call is live (no caching here). | If you cache the result, bound the TTL; don't reuse a verdict across sessions. |
+| 4 | **Endpoint MITM / response tampering** | HTTPS to a pinned host (`agent.auraopenprotocol.org`). Verdict strings are validated against a fixed allow-list; unknown values collapse to `unknown`. | Don't point `base_url` at an untrusted mirror. Consider TLS pinning if your runtime supports it. |
+| 5 | **Score gaming / Sybil** — cheap DIDs farming a `trusted` score | Inherited from AURA's on-chain cost + dispute dimension; not solvable in the adapter. | Weight `dimensions` (e.g. require non-trivial `interactions` / `dispute_history`) for high-value actions rather than trusting the aggregate alone. |
+| 6 | **Over-trust** — using the verdict as sole gate for irreversible value | `new`/`unknown` rejected by default; `dimensions` exposed. | For high-value settlement, combine with action-risk + escrow + manual review. |
</file context>
Suggested change
| 4 | **Endpoint MITM / response tampering** | HTTPS to a pinned host (`agent.auraopenprotocol.org`). Verdict strings are validated against a fixed allow-list; unknown values collapse to `unknown`. | Don't point `base_url` at an untrusted mirror. Consider TLS pinning if your runtime supports it. |
+| 4 | **Endpoint MITM / response tampering** | HTTPS to the configured host (default `agent.auraopenprotocol.org`). Verdict strings are validated against a fixed allow-list; unknown values collapse to `unknown`. | Don't point `base_url` at an untrusted mirror. Consider TLS pinning if your runtime supports it. |

def _fetch(url: str, timeout: float) -> dict[str, Any]:
from urllib.parse import parse_qs, urlparse

did = parse_qs(urlparse(url).query).get("did", [""])[0]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The replay stub only checks the did query param, so it won’t fail if the code under test calls the wrong endpoint path.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At integrations/aura/tests/fixtures.py, line 82:

<comment>The replay stub only checks the `did` query param, so it won’t fail if the code under test calls the wrong endpoint path.</comment>

<file context>
@@ -0,0 +1,94 @@
+    def _fetch(url: str, timeout: float) -> dict[str, Any]:
+        from urllib.parse import parse_qs, urlparse
+
+        did = parse_qs(urlparse(url).query).get("did", [""])[0]
+        return table.get(did, RECORDED["did:aura:ghost-bot"])
+
</file context>

@luisllaver
Copy link
Copy Markdown
Author

Pushed a small hardening update: fail_open now only excuses a transport failure — a reachable AURA returning unknown is still rejected. Added a reachable flag to the verdict plus tests for both paths (22 offline tests). No API changes.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
integrations/aura/tests/test_adapter.py (1)

116-125: ⚡ Quick win

Add pytest category markers to the new tests.

These tests should be annotated with @pytest.mark.unit to align with the project's test organization pattern (used in tests/test_templates.py, tests/test_claude_provider.py, and others) and follow coding guidelines for pytest marker usage.

♻️ Suggested patch
+@pytest.mark.unit
 def test_fail_open_does_not_pass_reachable_unknown():
     # A reachable AURA that returns `unknown` (ghost DID) is still rejected even
     # with fail_open — fail_open only excuses transport failures.
     with pytest.raises(AuraUntrusted):
         before_settle("did:aura:ghost-bot", fail_open=True, _fetch=FETCH)


+@pytest.mark.unit
 def test_reachable_verdict_marked_reachable():
     v = aura_verdict("did:aura:ghost-bot", _fetch=FETCH)
     assert v.reachable is True
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations/aura/tests/test_adapter.py` around lines 116 - 125, Add the
pytest unit marker to both new tests by decorating
test_fail_open_does_not_pass_reachable_unknown and
test_reachable_verdict_marked_reachable with `@pytest.mark.unit`; ensure pytest is
imported in integrations/aura/tests/test_adapter.py if it's not already, and
place the decorator immediately above each test function definition to match
project test organization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@integrations/aura/tests/test_adapter.py`:
- Around line 116-125: Add the pytest unit marker to both new tests by
decorating test_fail_open_does_not_pass_reachable_unknown and
test_reachable_verdict_marked_reachable with `@pytest.mark.unit`; ensure pytest is
imported in integrations/aura/tests/test_adapter.py if it's not already, and
place the decorator immediately above each test function definition to match
project test organization.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e3a640fe-fba8-4a9f-a2a5-0570e1c5b00e

📥 Commits

Reviewing files that changed from the base of the PR and between b72715b and cba9204.

📒 Files selected for processing (3)
  • integrations/aura/README.md
  • integrations/aura/adapter.py
  • integrations/aura/tests/test_adapter.py
✅ Files skipped from review due to trivial changes (1)
  • integrations/aura/README.md

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

5 similar comments
@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

@ecc-tools
Copy link
Copy Markdown
Contributor

ecc-tools Bot commented May 21, 2026

ECC bundle files are already tracked in this repository. Skipping generation of another bundle PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant