# Audit Report — magento-orderwebhook

> **Audit date:** 2026-02-26 (Europe/London)
> **Scope:** Read-only discovery audit of source code and documentation
> **Auditor:** AI-assisted engineering review
> **Status:** Complete — no code changes made

---

## Project Overview

| Attribute | Value |
|-----------|-------|
| Package | `portalpeople/magento-orderwebhook` |
| Version | Conflicted: v1.0.15 (`composer.json`), `setup_version="1.0.0"` (`module.xml`) |
| Purpose | Sends Magento 2 order data as a JSON webhook to NGauge on order placement and status change; stores NGauge order reference back on the order |
| Language | PHP >= 7.4 |
| Framework | Magento 2 (`magento/module-sales`) |
| Tests | None — PHPUnit not configured |

---

## Documentation Inventory

| File | Status |
|------|--------|
| `README.md` | Pre-existing — incomplete (version history inaccurate, see F5) |
| `AI_GUIDELINES.md` | Complete |
| `docs/architecture.md` | Complete |
| `docs/API.md` | Complete |
| `docs/BOUNDARIES.md` | Complete |
| `docs/DATA_OWNERSHIP.md` | Complete |
| `docs/INTEGRATIONS.md` | Complete |
| `docs/OBSERVABILITY.md` | Complete |
| `docs/WORKFLOW.md` | Complete |
| `docs/MERMAID_DIAGRAM_STANDARDS.md` | Pre-existing — kept |
| `docs/AUDIT.md` | This file |
| `docs/SECURITY.md` | Complete |
| `docs/TODO.md` | Complete |
| `docs/SYSTEM_MAP.md` | Complete |
| `docs/adr/ADR-000-discovery-baseline.md` | Complete |

---

## Findings

### F1 — MEDIUM: ObjectManager::getInstance() used in WebhookSender

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| File | `src/Model/WebhookSender.php` |
| Impact | Anti-pattern; bypasses Magento DI; prevents unit testing |

`WebhookSender::sendRequest()` resolves `EncryptorInterface` via `\Magento\Framework\App\ObjectManager::getInstance()`. The interface is not constructor-injected. This is a Magento anti-pattern that makes the class difficult to unit test and could cause issues in non-standard DI environments.

**Recommendation:** Inject `EncryptorInterface` via constructor.

---

### F2 — MEDIUM: Incorrect extra.bootstrap in composer.json

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| File | `composer.json` |
| Impact | Bootstrap reference points to wrong module — may cause runtime errors in environments that process the `extra.bootstrap` key |

`composer.json` contains `"extra": {"bootstrap": "PortalPeople\\NgaugeBackupSql\\Module"}`. The correct module namespace is `PortalPeople\OrderWebhook`. This appears to be a copy-paste error from another module.

**Recommendation:** Correct to `PortalPeople\\OrderWebhook\\Module` or remove the `extra.bootstrap` key if it is not used.

---

### F3 — MEDIUM: src/README.md documents incorrect trigger conditions

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| File | `src/README.md` |
| Impact | Misleads developers about when `order_updated` fires; may cause incorrect troubleshooting |

`src/README.md` states that `order_updated` fires when status changes to "processing, complete, or shipped". Code inspection of `OrderSaveAfter.php` shows it fires **only** when status changes to `'processing'`. The README is inaccurate.

**Recommendation:** Correct `src/README.md` to reflect actual code behaviour.

---

### F4 — MEDIUM: Customer DOB and gender transmitted to external system

| Attribute | Detail |
|-----------|--------|
| Severity | MEDIUM |
| File | `src/Model/OrderDataBuilder.php` |
| Impact | Special-category personal data sent to third-party (NGauge) — GDPR legal basis and DPA status not documented |

`OrderDataBuilder` includes `customer.dob` (date of birth) and `customer.gender` in every webhook payload. DOB may be classified as special-category data in some contexts. No GDPR legal basis, consent mechanism, or data processor agreement reference is documented in this module.

**Recommendation:** Document legal basis and DPA status in `docs/GDPR.md` and `docs/DATA_OWNERSHIP.md`.

---

### F5 — LOW: Version mismatch across files

| Attribute | Detail |
|-----------|--------|
| Severity | LOW |
| Files | `composer.json` (v1.0.15), `src/etc/module.xml` (`setup_version="1.0.0"`) |
| Impact | Unclear what version is deployed; `setup:upgrade` uses `setup_version` for schema versioning which may be incorrect |

**Recommendation:** Align all version strings to a single canonical value.

---

### F6 — LOW: Deprecated Magento\Framework\Registry usage

| Attribute | Detail |
|-----------|--------|
| Severity | LOW |
| File | `src/Block/Adminhtml/Order/NgaugeFields.php` |
| Impact | `Magento\Framework\Registry` is deprecated since Magento 2.3; may be removed in future Magento versions |

`NgaugeFields` block retrieves the current order via `$this->registry->registry('current_order')`.

**Recommendation:** Replace with layout argument injection or use the order ID from the request.

---

### F7 — LOW: No PHPUnit tests

| Attribute | Detail |
|-----------|--------|
| Severity | LOW |
| Impact | No automated regression protection for retry logic, re-entrancy guard, observer conditions, or payload construction |

No `phpunit.xml` or PHPUnit dependency found.

**Recommendation:** Add PHPUnit; write unit tests for `WebhookSender` retry/re-entrancy, `OrderDataBuilder`, and observer trigger conditions.

---

### F8 — NOTE: Admin resend button hidden after first sync

| Attribute | Detail |
|-----------|--------|
| Severity | NOTE (by design or oversight — unknown) |
| Files | `src/view/adminhtml/templates/order/view/ngauge_fields.phtml`, `src/Block/Adminhtml/Order/NgaugeFields.php` |

Once `ngauge_order_id` is written to `sales_order`, the admin UI "Send to NGauge" button is hidden. Re-sending is only possible via CLI (`order:webhook:test`) unless `ngauge_order_id` is manually cleared from the DB.

`UNKNOWN — Requires Clarification`: Is this intentional? Should there be a force-resend option in the UI regardless of sync state?

---

## Risk Summary

| Severity | Count | Items |
|----------|-------|-------|
| MEDIUM | 4 | F1 — ObjectManager anti-pattern, F2 — Wrong bootstrap, F3 — Inaccurate README, F4 — DOB/gender GDPR |
| LOW | 3 | F5 — Version mismatch, F6 — Deprecated Registry, F7 — No tests |
| NOTE | 1 | F8 — Resend button hidden after sync |

---

## Audit Metadata

- **Method:** Static source code analysis — all source files read
- **Code changes:** None
- **Git actions:** None
- **Tools:** Claude Code AI-assisted review
- **Date:** 2026-02-26 (Europe/London)
