# Scoped Attack Surface

- schema_version: 1
- built_at_commit: `accf8a8e9e52410579abc70b436635139cad2236`
- built_at_date: `2026-08-13`
- scope: Translation finalization authorization and backend/local job identity binding introduced or affected by `accf8a8e9`.

## Mapped files

| File | Baseline identity |
| --- | --- |
| `plugins/international-press-zone/includes/Translation/TranslationFinalizer.php` | sha256 `98233537358b7c5b25fff49932cc38b49439bc3ac40a94c02ad2e1d466d5f186` |
| `plugins/international-press-zone/includes/Translation/SiteContentTranslationResourceHandler.php` | git blob `3518d2829bac8026cf8c290b0d863a2cc27a0e67` |
| `plugins/international-press-zone/includes/API/TranslateJobsController.php` | sha256 `8c207298e005140c3785df6ea4d264087aa9f9edffa1511734b1bd4249623807` |
| `plugins/international-press-zone/includes/Translation/JobReceiver.php` | git blob `cd4e660f554d9b5f2db7e9cde984faa5ef26236f` |
| `plugins/international-press-zone/tests/Unit/Translation/TranslationResourcePipelineTest.php` | sha256 `a60ffe684a85333f5b0564223419786fbae274ba20d5f1711ee8dcaac794efdd` |
| `plugins/international-press-zone/tests/unit/ReviewDefectsContractStandaloneTest.php` | git blob `3297bce3ae5f8e0741576b556ec62c7c8b772f9f` |
| `plugins/international-press-zone/tests/unit/Translation/TranslationFinalizerJobIdentityStandaloneTest.php` | sha256 `e2241fbb005177b4a936c610b19c97923e4bd132d96a43c95e1c832c98b2dafd` |

The baseline identity is a Git blob when the mapped worktree file equals an indexed/committed object; otherwise it is a SHA-256 of the preserved worktree candidate. Refresh only an entry whose file hash changes or whose relevant trust contract changes at a later commit.

## Trust boundaries and entry points

- `TranslateJobsController` polling and webhook completion paths accept backend-controlled completion bodies after their route/authentication checks, load a local job, and call `TranslationFinalizer::finalize()` for non-string resources.
- `JobReceiver` accepts signed webhook fields, resolves a numeric local job ID, loads the job, and delegates completion to a resource handler.
- `TranslationFinalizer::finalize()` is an internal mutation boundary whose object/array job argument and completion data must be treated as hostile or stale even when its current callers normally pass database rows.
- `SiteContentTranslationResourceHandler::finalize()` is a persistence boundary for compiled site-content overlays and jobs-table terminal state.

## Untrusted inputs

- Numeric/local job identifiers and caller-supplied job objects.
- Backend job/token aliases: `api_job_id`, `apiJobId`, `job_id`, and `jobId`.
- Resource type, content/resource ID, source and target languages, initiating user ID, status, translated segments, character/cost values, and datastore rows.
- Existing site-content records, source revisions, block documents, segment IDs/text, and serialized translation context.

## AuthN/Z and branch identity rules

- Every completion route must authenticate the backend callback before mutation; HMAC checks do not replace per-job authorization.
- The local jobs-table row selected by the numeric ID is canonical. Resource type, resource ID, languages, initiating user, status, and stored backend identity must come from that row, not from a caller object.
- Post finalization must hold the per-job database lock, reload the canonical row, reject missing and failed/cancelled jobs, return completed jobs idempotently, require non-empty constant-time backend identity equality, and constrain persistence to `status = processing`.
- Delegated/non-post finalization must resolve its handler from the canonical row, require `processing` before mutation (or return an already-completed resource idempotently), require non-empty constant-time stored/backend identity equality, and pass the canonical row to the handler.
- Site-content finalization must bind job ID, resource ID, `content_type = site_content`, target language, and backend identity; actor attribution must derive from the canonical initiating user. Its terminal update must affect exactly one processing job.
- Publish/private post status may be applied only when the initiating canonical user has the post type's publish capability; otherwise status is draft.

## Invariants and sinks

- A completion for job A cannot mutate the resource, actor attribution, or terminal state belonging to job B.
- Empty, malformed, mismatched, duplicated, terminal, or stale identities fail closed before content mutation.
- Handler selection is unique and based on canonical resource type.
- Segment sets are exact, bounded, and revision-checked; malformed/duplicate/unknown/omitted segments do not overwrite the last ready overlay.
- Jobs-table state changes use prepared identifiers/values and compare-and-swap status predicates; multi-write site-content completion is transactional and rolls back on terminal-state failure.
- Post creation/update, ACF application, site-content `saveReview`, jobs-table updates, reconciliation records, cache invalidation, and error/log messages are mutation or disclosure sinks.
