Search by

johnnickell / fight-access-control

johnnickell

Framework-neutral identity, credential, session, authorization, and account-lifecycle contracts

Package info

github.com/johnnickell/fight-access-control

pkg:composer/johnnickell/fight-access-control

Statistics

Installs: 26

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.4.0 2026-09-27 20:03 UTC

This package is auto-updated.

Last update: 2026-10-05 16:59:36 UTC


README

Framework-neutral identity, credential, session, authorization, and account-lifecycle contracts for Fight applications.

Only the current pre-v1 API and persisted contract are supported; see ADR 0011. There are no historical readers, legacy modes or migration/backfill routes. Credential delivery is recoverable and provider-neutral for invitation, password reset and email change.

The v0.4.0 release introduces the pre-1.0 Permission tier contract and requires consumer persistence and projection adoption; see the current Permission tier contract. Package publication does not certify a consumer schema or establish consumer adoption.

The 0.2.0 release adds an opt-in, non-autoloaded OpenAPI component catalog for consumer-owned documents. See OpenAPI composition.

The 0.1.x release line provides the first public-source package milestone while the API remains intentionally pre-1.0.0. It delivers the framework-neutral Domain and Application behavior described by the repository-local product specifications; consumer projects continue to own framework and infrastructure adapters. Tagged package versions intentionally precede full starter implementation so those projects can integrate against immutable version tags and return compatibility findings through later 0.x releases.

Package boundary

Production code follows Domain <- Application:

  • Domain contains framework-independent business concepts and depends on no other package layer.
  • Application coordinates use cases through Domain types and public Fight Common contracts.
  • Application owns the supported access-JWT/opaque-refresh authentication lifecycle through Fight Common ports, while consumer repositories own clients, framework integration, persistence, HTTP, cookies, signing-key configuration, mail, queues, realtime, hosting, and composition-root adapters. This package has no PHP production Adapter layer.

See CONTEXT.md for the accepted vocabulary and TICKET-00001 for the repository-local behavioral and security authority.

Transaction composition

Transaction-aware Application handlers and security services require Fight Common's supported TransactionalUnitOfWork contract. Consumer composition roots must supply an implementation whose commitTransactional() callback encloses the complete package-owned atomic operation and whose isClosed() reports whether that transaction capability remains available. The deprecated UnitOfWork contract and its standalone commit() method are not supported by AccessControl constructors.

Only the current transactional contract is supplied; no compatibility adapter is included.

Recoverable credential delivery composition

See the current credential-delivery guide for persistence, explicit claim/outcome contracts, worker composition and executable qualification evidence.

Invitation, password-reset, and email-change credentials use package-owned recoverable delivery state. Consumers supply the three purpose-specific cipher capabilities, one provider-neutral CredentialDeliveryProvider, the Domain repositories on the shared transactional connection, and worker scheduling. The package supplies direct DeliverUserInvitationHandler, DeliverPasswordResetHandler, and DeliverEmailChangeHandler registrations plus FindDueCredentialDeliveriesHandler and FindCredentialDeliveryStatusHandler query registrations.

An originating handler atomically commits its grant and encrypted delivery generation before publishing its existing success event. A delivery handler then commits an exact claim, decrypts and invokes the provider only after that transaction closes, and records the typed delivered, retryable, or permanent outcome in a separate expected-state transaction. Provider adapters receive a short-lived CredentialDeliveryInvocation; its immutable delivery ID is the idempotency identity. They must return CredentialDeliveryOutcome and must not embed vendor diagnostics in package state. Unexpected provider throwables become the package's secret-free retryable classification.

Consumers may use post-commit event subscribers for immediate dispatch, but must schedule FindDueCredentialDeliveries for restart recovery and dispatch the matching direct command using the returned purpose, User ID, and delivery ID. Pending work, due retries, and expired leases are returned in deterministic order. A crash after provider acceptance and before outcome commit can repeat the provider call with the same identity, so this contract is at-least-once and does not claim exactly-once delivery.

Feature declarations, preparation and availability (unreleased)

The Feature reference guide describes strict FeatureName validation, method-only FeatureFlag metadata, explicit registration and scoped complete/unavailable discovery. Atomic provisioning creates only missing candidate references OFF with an existing Permission, preserving stored choices and retrying from authoritative state. Completion is not activation readiness. Preparation validation rereads all complete candidate references and their stored Permission identities without mutation. Feature availability checks current stored status and Permission ID against an existing User/Agent snapshot or anonymous input on each explicit call; availability never authorizes the underlying action. Management, Permission reference guards and current-reference retirement supply the package lifecycle; the scenario/evidence inventory distinguishes preceding acceptance from TASK-00067's pending independent review/QA. Consumer adapters, scanning, UI and runtime enforcement remain consumer-owned and unqualified. Neither a package pass, preparation nor provisioning grants deployment permission or constitutes a supported partial Feature release.

Agent credential operations (unreleased)

Start with the current Agent integration guide for composition, readiness, bounded recovery and restoration. The complete scenario/evidence inventory maps all 25 proposal scenarios and ratified outcome/bounds additions to current package tests and explicit consumer gaps. The target is v0.5.0; this checkout is not a release receipt or consumer qualification.

The unreleased provisioning replacement requires a retained scoped operation key, registered destination, and same-transaction authorization participation. It prepares encrypted delivery and returns only safe issuance metadata; retry resolves the same outcome after response loss. See the provisioning contract for composition, finite defaults, failure semantics, persistence requirements and executable evidence. GetAgentOperation provides an authorized safe status query, separating original issuance from recorded delivery and credential disposition without a transaction, material access or events. Credential retirement atomically revokes authority and cancels original delivery through both service and direct repository writes without key/sink access. Protected delivery adds committed claim/admission, outside-transaction fixed-sink invocation and exact receipt acknowledgement under current authority. Recoverable rotation commits a correlated successor with atomic predecessor cancellation and resolves the original request after response loss. Retired raw-return rotation APIs are removed. Discovery and restart recovery provide a bounded currently delegated scheduler pass and receipt-first reconciliation through the actual protected delivery path, without caller retry or events. Discovery excludes obsolete slot reservations before limiting so they cannot starve the current authorized write. Material maintenance adds authorized rewrapping, global diagnostic key-reference counts, retention expiry and replay-safe inert-entry cleanup. A zero reference count never authorizes key destruction; current delivered credentials are excluded from cleanup. Issuance-recovery conformance exposes consumer-bindable tests and exercises both issuance paths through scheduler-only restart, status and cleanup using behavioral adapters. It does not qualify a real database, sink or consumer activation/use path. Protected-delivery conformance adds consumer-bindable authority/lifecycle, transaction, key and sink qualification scenarios, running both receipt-lookup and repeated-invocation profiles. The current Agent model has no legacy mode or recovery marker. Validated hydration preserves authority; every lifecycle write requires operation correlation and atomic cancellation. Operation cohorts require persisted version/capability qualification and a shared transaction-duration cohort fence across every writer. Cohort generations fence delivery/cleanup acknowledgements; consumers must separately exclude old binaries at storage or a trusted boundary and qualify real writer races. The canonical operation contract uses one Unicode-aware normalization rule and persisted marker 2, preserving original keys through restart, delivery, retirement and cleanup. There is no historical reader, runtime version selection or migration of nonexistent earlier-version operations. Unsupported markers reject without fallback; current authorization, transaction and ordering fences remain mandatory. Restoration safety requires independent reconciled-generation evidence at the existing cohort boundary. Stale restored state remains unavailable until original operation/receipt/tombstone/order history is reconciled for the exact active storage incarnation at a newer generation. Consumer-bindable scenarios model restore and forward repair; no backup tool, migration engine or automatic rollback detector is supplied. Package restoration and TASK-00059's final integration guidance/traceability are independently accepted; the guidance also passed behavioral QA. These modeled interleavings do not qualify real consumer adapters, restore procedures or activation/use. The unreleased composition is not a qualified consumer deployment; release, consumer adoption and deployment remain separate gates. Existing released versions are unchanged.

Current principal composition

Consumers implement AuthenticationContextProvider to expose only the authenticated User ID, refresh-session ID, and authentication version for the current request. The composition root must create a new CurrentPrincipalProvider for each request with that context provider and the package AuthoritativePrincipalResolver. Application handlers use CurrentPrincipalProvider; its first lookup resolves all principal roles and permissions from authoritative repositories and later lookups in the same request return that cached result. Consumers cannot inject role or permission snapshots through this boundary.

After a consumer-owned framework adapter selects and resolves the request's authentication path, its composition root creates one SecurityContext from exactly one AuthenticatedUserPrincipal or AuthenticatedAgentPrincipal. The context exposes that authority's type and delegates its Permission and Role checks. Agents retain only their direct Permissions and have no package-level Roles; framework wrappers, endpoint policy, and response handling remain consumer-owned.

Local development

PHP 8.5 and Docker are required. Tooling follows the Fight Common conventions and runs in the isolated fight-access-control container through repository-owned scripts:

./bin/phpunit
./bin/phpcs
./bin/phpstan
./bin/deptrac
./bin/rector process src/
./bin/planning-check

./bin/build is the canonical completion command. It installs the tracked Composer resolution and runs the single ordered ./bin/quality gate. ./bin/build --latest checks the latest dependency versions compatible with composer.json; hosted CI performs that same latest-compatible resolution before invoking ./bin/quality directly.

For a clean, dated release candidate, ./bin/release certify <version> records its exact HEAD and the OpenAPI consumer-composition, planning, and package-quality evidence under ignored .runs/. It is verification-only and does not create a commit, merge, tag, push, or publication.

Keep scratch in purpose-named, gitignored .runs/ subdirectories following the project profile. Linked worktrees use .runs/worktree/<task-slug>/; notes, logs, handoffs and reviews remain separate. Never stage scratch. Run commands from the assigned checkout and remove resources only with separate cleanup authorization. See CONTRIBUTING.md for Git Flow, isolation, and review expectations.

Security

Do not disclose suspected vulnerabilities in public issues or pull requests. Follow the private reporting process in SECURITY.md.

Visibility and release effects

These are independent operational effects. Approval for one is not approval for another; each requires a separate approval:

  • Public repository visibility exposes the source and history under the repository license.
  • Commit creation records reviewed work in Git history.
  • Version tag creation gives a selected commit a version identifier.
  • Packagist publication makes package metadata discoverable and installable through Packagist.
  • Release publication creates a hosted release and its release notes or artifacts.

The repository is public under the MIT License. v0.1.0 is its first public package release; later 0.x versions may refine public contracts before the separate 1.0.0 stability review. A commit hash may still be used for reproducible integration testing, but it is not a version tag or release.

License

Fight AccessControl is available under the MIT License.