Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
131 commits
Select commit Hold shift + click to select a range
5cb5483
feat(storage): add isolated storage context
abmmhasan Sep 8, 2026
d11abdc
test(storage): cover isolated storage contexts
abmmhasan Sep 8, 2026
214bac2
fix(storage): isolate context driver resolution
abmmhasan Sep 8, 2026
27a5dc9
fix(storage): harden context path resolution
abmmhasan Sep 8, 2026
c58b80c
test(storage): cover traversal and global driver isolation
abmmhasan Sep 8, 2026
4808879
ci: align PHPForge reusable workflow inputs
abmmhasan Sep 8, 2026
67f1d0c
style(storage): order context class elements
abmmhasan Sep 8, 2026
9367f7c
refactor(files): satisfy current PHPForge rector rules
abmmhasan Sep 8, 2026
b3de10c
fix(storage): align context boundary typing
abmmhasan Sep 8, 2026
0a37c08
fix(storage): normalize filesystem configuration keys
abmmhasan Sep 8, 2026
a63b232
test(storage): harden context boundary coverage
abmmhasan Sep 8, 2026
c20ccf2
docs(storage): document instance-scoped contexts
abmmhasan Sep 8, 2026
1cb305c
worker update
abmmhasan Sep 8, 2026
f609fda
Merge remote-tracking branch 'refs/remotes/origin/pathwise-3.2/storag…
abmmhasan Sep 8, 2026
fe39b53
test(storage): make context checks platform-safe
abmmhasan Sep 8, 2026
c2d1db7
fix(storage): make logical absolute paths platform-independent
abmmhasan Sep 8, 2026
6dc22ce
test(storage): cover portable absolute path forms
abmmhasan Sep 8, 2026
ddd88d1
feat(upload): add owned upload materialization
abmmhasan Sep 8, 2026
8784461
feat(upload): add framework-neutral upload source
abmmhasan Sep 8, 2026
f4b0d14
feat(upload): complete typed source ownership
abmmhasan Sep 8, 2026
eb077fe
fix(upload): close typed source quality gates
abmmhasan Sep 8, 2026
eaf7d37
feat(upload): add typed malware scanner contract
abmmhasan Sep 8, 2026
e7aacf4
feat(download): add prepared chunk streaming
abmmhasan Sep 8, 2026
717827d
feat(filesystem): add safe symlink manager
abmmhasan Sep 8, 2026
fa66280
fix(filesystem): satisfy symlink style gate
abmmhasan Sep 8, 2026
30b5f2a
fix(filesystem): close symlink analysis gate
abmmhasan Sep 8, 2026
efc2b87
fix(filesystem): support Windows directory symlinks
abmmhasan Sep 8, 2026
e8c84f7
build(deps): require psr log explicitly
abmmhasan Sep 8, 2026
d5508e4
refactor(upload): harden malware scanning boundary
abmmhasan Sep 8, 2026
f93cb8c
test(upload): close hardened malware scanning batch
abmmhasan Sep 8, 2026
917e33c
fix(upload): close malware scanner hardening
abmmhasan Sep 8, 2026
adaec1c
style(upload): satisfy malware scan formatting gate
abmmhasan Sep 8, 2026
0bf6c98
style(upload): separate scan allocation break
abmmhasan Sep 8, 2026
2a260aa
feat(upload): add malware scan modes
abmmhasan Sep 8, 2026
651d36a
feat(upload): add scanner backend exception
abmmhasan Sep 8, 2026
58e56ae
feat(upload): add ClamAV daemon scanner
abmmhasan Sep 8, 2026
a7f38ef
refactor(upload): make malware scanning policy explicit
abmmhasan Sep 8, 2026
d570087
refactor(upload): honor explicit malware scan mode
abmmhasan Sep 8, 2026
64617f2
test(upload): cover malware scan modes
abmmhasan Sep 8, 2026
44512b0
test(upload): migrate required scanner mode
abmmhasan Sep 8, 2026
985f101
security(policy): deny unmatched operations by default
abmmhasan Sep 8, 2026
7203e70
test(policy): cover deny-by-default behavior
abmmhasan Sep 8, 2026
a53113f
fix(writer): make atomic replacement semantics truthful
abmmhasan Sep 8, 2026
00ea798
test(writer): enforce local-only atomic mode
abmmhasan Sep 8, 2026
d25037a
docs(plan): add Pathwise 4 final development plan
abmmhasan Sep 8, 2026
2d6b5ce
docs(plan): add Pathwise 4 execution tracker
abmmhasan Sep 8, 2026
f419bf6
feat(upload): close malware scanner provider batch
abmmhasan Sep 8, 2026
b9fc8e4
fix(upload): classify clamd read timeouts
abmmhasan Sep 8, 2026
a76d029
fix(security): harden upload staging permissions
abmmhasan Sep 8, 2026
eb79341
fix(security): harden local audit state permissions
abmmhasan Sep 8, 2026
230e625
fix(security): create private partitioned audit state
abmmhasan Sep 8, 2026
435fd86
fix(security): harden queue state permissions
abmmhasan Sep 8, 2026
07e33ab
test(security): verify private audit state permissions
abmmhasan Sep 8, 2026
dc6d724
test(security): verify private queue state permissions
abmmhasan Sep 8, 2026
389241a
test(security): verify private upload staging permissions
abmmhasan Sep 8, 2026
b34b517
docs(plan): advance tracker through Batch 8 permissions
abmmhasan Sep 8, 2026
b6f6cfb
docs(plan): close Batch 8 and start native execution hardening
abmmhasan Sep 8, 2026
8c313a2
feat(native): add typed execution failure reasons
abmmhasan Sep 8, 2026
67d4e5c
feat(native): define bounded execution limits
abmmhasan Sep 8, 2026
08ea864
feat(native): expose typed execution diagnostics
abmmhasan Sep 8, 2026
d27b75a
feat(native): bound process lifetime and output
abmmhasan Sep 8, 2026
631345d
feat(native): apply bounded limits to all adapters
abmmhasan Sep 8, 2026
4d17e24
test(native): cover bounded process execution
abmmhasan Sep 8, 2026
7de5313
style(native): align execution failure enum
abmmhasan Sep 8, 2026
f866522
style(native): normalize execution limits
abmmhasan Sep 8, 2026
948f75a
fix(native): make bounded execution portable
abmmhasan Sep 8, 2026
283fb03
refactor(native): simplify bounded execution capabilities
abmmhasan Sep 8, 2026
867549e
fix(native): close bounded runner quality findings
abmmhasan Sep 8, 2026
d21fe1b
fix(native): isolate final pipe drain analysis
abmmhasan Sep 8, 2026
5bdc455
docs(plan): close native runner and activate queue leases
abmmhasan Sep 8, 2026
1c39b96
feat(queue): add typed lease reservation
abmmhasan Sep 8, 2026
7c7ab08
feat(queue): add lease ownership and crash-safe state
abmmhasan Sep 8, 2026
0d327b4
test(queue): cover leases and durable state recovery
abmmhasan Sep 8, 2026
faa40a2
docs(queue): document lease ownership and durable state
abmmhasan Sep 8, 2026
1fcda46
refactor(queue): isolate durable state storage
abmmhasan Sep 8, 2026
cd0ac3f
refactor(queue): harden lease state semantics
abmmhasan Sep 8, 2026
c93b401
style(queue): normalize reservation constructor
abmmhasan Sep 8, 2026
b059f32
test(queue): reject leases immediately after expiry
abmmhasan Sep 8, 2026
70a2705
fix(queue): validate committed state on reopen
abmmhasan Sep 8, 2026
856c581
docs(plan): close queue batch and activate parser hardening
abmmhasan Sep 8, 2026
751ad44
feat(batch11): harden archives and parser boundaries
abmmhasan Sep 8, 2026
f1fe9a2
refactor(batch12): remove redundant global storage state
abmmhasan Sep 8, 2026
5560cac
hardening(batch13): strengthen operational subsystems
abmmhasan Sep 8, 2026
7f6203a
docs(plan): close batch 13 and start batch 14
abmmhasan Sep 8, 2026
3519a56
ci(batch14): gate warning-free Sphinx docs
abmmhasan Sep 8, 2026
f75c371
fix(batch14): route processors through storage contexts
abmmhasan Sep 8, 2026
e7d1d7a
fix(batch14): resolve context-backed local paths
abmmhasan Sep 8, 2026
d2bbbc9
fix(batch14): make chunk uploads context-aware
abmmhasan Sep 8, 2026
33d8a8d
fix(batch14): make upload validation context-aware
abmmhasan Sep 8, 2026
516fb14
fix(batch14): make downloads context-aware
abmmhasan Sep 8, 2026
6065e15
test(batch14): prove processor context isolation
abmmhasan Sep 8, 2026
344e313
docs(batch14): document instance-scoped storage contexts
abmmhasan Sep 8, 2026
d66f234
fix(storage): route logical schemes through context
abmmhasan Sep 8, 2026
0defa4e
fix(upload): complete context-aware storage routing
abmmhasan Sep 8, 2026
021d37c
docs(ci): exclude internal development plans
abmmhasan Sep 8, 2026
6ff6215
docs(storage): include storage context guide
abmmhasan Sep 8, 2026
806ee3d
docs(readme): rebuild for Pathwise 4
abmmhasan Sep 8, 2026
7920123
docs(quickstart): align examples with Pathwise 4
abmmhasan Sep 8, 2026
23a4453
docs(storage): replace global mount model
abmmhasan Sep 8, 2026
a19d329
docs(upload): document final 4.0 pipeline
abmmhasan Sep 8, 2026
deeddf7
docs(download): document context-aware range lifecycle
abmmhasan Sep 8, 2026
d71f5f8
docs(recipes): replace stale global storage workflow
abmmhasan Sep 8, 2026
d63feff
docs(migration): add Pathwise 4 migration guide
abmmhasan Sep 8, 2026
3400ad0
docs(api): add Pathwise 4 public surface reference
abmmhasan Sep 8, 2026
49b9d99
docs(performance): add performance and portability guide
abmmhasan Sep 8, 2026
27ac209
docs(release): add Pathwise 4 release notes
abmmhasan Sep 8, 2026
05cba71
docs(capabilities): map final Pathwise 4 modules
abmmhasan Sep 8, 2026
12a8bfe
docs(overview): describe final runtime architecture
abmmhasan Sep 8, 2026
69706f9
docs(security): document final 4.0 security boundaries
abmmhasan Sep 8, 2026
48c4c42
docs(index): publish Pathwise 4 reference set
abmmhasan Sep 8, 2026
be9cb6a
docs(facade): remove persistent storage gateways
abmmhasan Sep 8, 2026
a47f9ee
fix(storage): narrow processor read streams
abmmhasan Sep 8, 2026
93c1714
docs(reference): fix Sphinx heading markup
abmmhasan Sep 8, 2026
d1667af
docs(migration): fix Sphinx heading markup
abmmhasan Sep 8, 2026
9f8bc06
docs(storage): clarify Pathwise 4 capability model
abmmhasan Sep 8, 2026
8e53247
docs(native): document bounded execution semantics
abmmhasan Sep 8, 2026
9ceae03
docs(files): align file guarantees with Pathwise 4
abmmhasan Sep 8, 2026
84dc96a
docs(directory): clarify storage and sync semantics
abmmhasan Sep 8, 2026
e11217c
docs(observability): document durable audit sinks
abmmhasan Sep 8, 2026
fc85ca8
docs(indexing): document streaming checksum workflows
abmmhasan Sep 8, 2026
7107752
docs(retention): document preview and deterministic policy
abmmhasan Sep 8, 2026
3260590
docs(utilities): document watcher and capability bounds
abmmhasan Sep 8, 2026
5b10c97
perf(release): cover Pathwise 4 release workloads
abmmhasan Sep 8, 2026
74ca07f
perf(release): add benchmark and stress scripts
abmmhasan Sep 8, 2026
aa949d6
ci(release): enforce benchmark and stress gates
abmmhasan Sep 8, 2026
504eb17
chore(release): normalize release scripts
abmmhasan Sep 8, 2026
e54b169
style(release): align benchmark with PHPForge
abmmhasan Sep 8, 2026
dfd3b77
style(release): satisfy PHPForge benchmark ordering
abmmhasan Sep 8, 2026
1a25a37
style(release): order release benchmark imports
abmmhasan Sep 8, 2026
4c1d03e
docs(release): remove completed Pathwise 4 development plan
abmmhasan Sep 8, 2026
f82fcce
finalized
abmmhasan Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 26 additions & 30 deletions .github/workflows/security-standards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,16 @@ on:
jobs:
phpforge:
uses: infocyph/phpforge/.github/workflows/security-standards.yml@main
with:
fail_on_skipped_tests: true
integration_services: '[]'
service_topologies: '{}'
php_extensions: "fileinfo, pcntl, posix, simplexml, xmlreader, zip"
benchmark_composer_script: "benchmark:release"
permissions:
security-events: write
actions: read
contents: read
with:
php_versions: '["8.4","8.5"]'
dependency_versions: '["prefer-lowest","prefer-stable"]'
php_extensions: "fileinfo, pcntl, posix, simplexml, xmlreader, zip"
composer_flags: ""
phpstan_memory_limit: "1G"
psalm_threads: "1"
run_analysis: true
run_svg_report: true
fail_on_skipped_tests: true
run_clean_install: true
benchmark_composer_script: ""
benchmark_result_file: ""
benchmark_baseline_file: ""
benchmark_max_regression_percent: 2
benchmark_stable_environment: false
enable_redis_service: false
enable_valkey_service: false
enable_memcached_service: false
enable_postgres_service: false
enable_mysql_service: false
enable_scylladb_service: false
enable_elasticsearch_service: false
enable_mongodb_service: false
service_db_name: "phpforge"
service_db_user: "phpforge"
service_db_password: "phpforge"
artifact_retention_days: 61

windows:
name: "Windows / PHP ${{ matrix.php }}"
Expand All @@ -52,7 +30,7 @@ jobs:
matrix:
php: ["8.4", "8.5"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: "Set up PHP"
uses: shivammathur/setup-php@v2
with:
Expand All @@ -71,7 +49,7 @@ jobs:
env:
PATHWISE_REQUIRE_ADAPTER_CONTRACTS: "1"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: "Set up PHP"
uses: shivammathur/setup-php@v2
with:
Expand All @@ -85,3 +63,21 @@ jobs:
composer require --dev --no-interaction --prefer-dist league/flysystem-memory:^3 league/flysystem-read-only:^3 league/flysystem-path-prefixing:^3
- name: "Run adapter contracts"
run: composer ic:test:code

release-stress:
name: "Release stress / PHP 8.4"
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: "Set up PHP"
uses: shivammathur/setup-php@v2
with:
php-version: "8.4"
extensions: "fileinfo, pcntl, posix, simplexml, xmlreader, zip"
coverage: none
tools: composer:v2
- name: "Install dependencies"
run: composer install --no-interaction --prefer-dist
- name: "Run release stress workloads"
run: composer stress:release
194 changes: 112 additions & 82 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,127 +1,157 @@
# Pathwise

[![Security & Standards](https://github.com/infocyph/Pathwise/actions/workflows/security-standards.yml/badge.svg)](https://github.com/infocyph/Pathwise/actions/workflows/security-standards.yml)
![Packagist Downloads](https://img.shields.io/packagist/dt/infocyph/Pathwise?color=green\&link=https%3A%2F%2Fpackagist.org%2Fpackages%2Finfocyph%2FPathwise)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
![Packagist Version](https://img.shields.io/packagist/v/infocyph/Pathwise)
![Packagist PHP Version](https://img.shields.io/packagist/dependency-v/infocyph/Pathwise/php)
![GitHub Code Size](https://img.shields.io/github/languages/code-size/infocyph/Pathwise)
[![Documentation](https://img.shields.io/badge/Documentation-Pathwise-blue?logo=readthedocs&logoColor=white)](https://docs.infocyph.com/projects/Pathwise/en/latest/)
Pathwise 4 is a framework-neutral PHP 8.4+ filesystem toolkit built on Flysystem 3. It combines safe local file operations with instance-scoped storage topology, hardened upload/download pipelines, archive controls, file-backed queueing, observability, retention, indexing, policy enforcement, and bounded native execution.

High-level PHP filesystem workflows powered by Flysystem, including safe I/O, uploads, downloads, archives, directory synchronization, retention, policy enforcement, auditing and storage adapters.
## Requirements

Pathwise 3.0 requires PHP 8.4 or newer. It is a direct breaking release: reader and writer methods are explicit, complex operations return readonly result objects, and unsupported mounted-storage operations fail with focused exceptions.
- PHP `>=8.4`
- `ext-fileinfo`
- `league/flysystem ^3.35.2`
- `psr/log ^3.0.2`

## Installation
ZIP, POSIX ownership, XML parsing, and remote Flysystem adapters are optional capabilities. Install only the extensions/adapters your application uses.

```bash
composer require infocyph/pathwise
composer require infocyph/pathwise:^4.0
```

`ext-fileinfo` is required. ZIP and XML features check for `ext-zip`, `ext-xmlreader`, and `ext-simplexml` at runtime and report a clear `MissingExtensionException` when unavailable.
## Storage topology

## Quick start
Use `StorageContext` for applications, workers, long-lived runtimes, or any process that can host more than one storage topology. Contexts do not register process-global mounts.

```php
use Infocyph\Pathwise\FileManager\FileOperations;
use Infocyph\Pathwise\FileManager\SafeFileReader;
use Infocyph\Pathwise\FileManager\SafeFileWriter;
use Infocyph\Pathwise\Storage\StorageContext;

$file = new FileOperations('/tmp/example.txt');
$file->create('hello')->append("\nworld");
$storage = new StorageContext([
'primary' => ['driver' => 'local', 'root' => '/srv/app/storage'],
'archive' => ['driver' => 'local', 'root' => '/srv/app/archive'],
], 'primary');

foreach ((new SafeFileReader('/tmp/example.txt'))->lines() as $line) {
echo $line;
}
[$filesystem, $location] = $storage->resolve('archive://reports/q1.txt');
$filesystem->write($location, "ready\n");

$writer = new SafeFileWriter('/tmp/events.json');
$writer->writeJson(['status' => 'ready']);
$writer->close();
$local = $storage->localPath('documents/readme.txt');
```

The reader exposes `lines()`, `characters()`, `chunks()`, `csv()`, `jsonLines()`, `jsonArray()`, `fixedWidth()`, `xmlElements()`, `serializedValues()`, and `matchingLines()`. The writer exposes the corresponding `write*` methods. There is no runtime `__call()` dispatch and no global helper-function autoloading.
`StorageFactory::createFilesystem()` remains the stateless constructor for built-in/official Flysystem adapters. Custom driver factories belong to a `StorageContext`, not a global registry.

## Storage model
## File and directory operations

```php
use Infocyph\Pathwise\Storage\StorageFactory;
use Infocyph\Pathwise\Utils\FlysystemHelper;
use Infocyph\Pathwise\PathwiseFacade;

StorageFactory::mount('assets', [
'driver' => 'local',
'root' => '/srv/storage/assets',
]);
$file = PathwiseFacade::at('/tmp/example.txt')->file();
$file->create("v1\n")->append("v2\n");

FlysystemHelper::write('assets://reports/a.txt', 'hello');
$report = PathwiseFacade::at('/tmp/source')
->directory()
->syncTo('/tmp/backup', deleteOrphans: true);
```

Storage-neutral reads, writes, copies, streams, uploads, downloads, ZIP staging, retention, and synchronization accept local, default-Flysystem, and mounted scheme paths where the adapter supplies the required capability. POSIX modes/ownership, native processes, shell searching, direct locks/handles, and transactions are local-filesystem-only and throw `UnsupportedStorageOperationException` for mounted paths.
The facade is stateless convenience. Persistent storage topology belongs to `StorageContext`.

## Framework-neutral uploads

```php
use Infocyph\Pathwise\StreamHandler\MalwareScanMode;
use Infocyph\Pathwise\StreamHandler\UploadProcessor;
use Infocyph\Pathwise\StreamHandler\UploadSource;

$uploader = new UploadProcessor();
$uploader->setStorageContext($storage);
$uploader->setDirectorySettings('primary://uploads', tempDir: sys_get_temp_dir());
$uploader->setValidationProfile('document');
$uploader->setMalwareScanMode(MalwareScanMode::REQUIRED);
$uploader->setMalwareScanner($scanner);

$source = UploadSource::fromMover(
mover: fn (string $target): void => $uploadedFile->moveTo($target),
clientFilename: $uploadedFile->getClientFilename() ?? 'upload.bin',
size: $uploadedFile->getSize(),
clientMediaType: $uploadedFile->getClientMediaType(),
error: $uploadedFile->getError(),
);

Local `append()` uses native append mode. Mounted stores must opt into `appendEmulated()`, which visibly represents a complete object replacement. Local transactions use a structured, disk-backed rollback journal and reject nesting.
$path = $uploader->ingestSource($source);
```

See the `storage capability contract` in the documentation for the compatibility matrix, atomicity, locking, sync, native execution, archive security, and performance characteristics.
Pathwise owns the staging file created for `UploadSource`, cleans it on success/failure, scans before content parsing, and fails closed when malware scanning is required.

## Synchronization and result types
## Secure downloads and ranges

```php
use Infocyph\Pathwise\Core\SyncComparison;
use Infocyph\Pathwise\DirectoryManager\DirectoryOperations;
use Infocyph\Pathwise\StreamHandler\DownloadProcessor;

$downloads = new DownloadProcessor();
$downloads->setStorageContext($storage);
$downloads->setAllowedRoots(['primary://downloads']);

$report = (new DirectoryOperations('/srv/source'))->syncTo(
'/srv/target',
deleteOrphans: true,
comparison: SyncComparison::SIZE_AND_MODIFIED_TIME,
$prepared = $downloads->prepareDownload(
'primary://downloads/video.mp4',
rangeHeader: $_SERVER['HTTP_RANGE'] ?? null,
);

foreach ($downloads->streamChunks($prepared) as $chunk) {
echo $chunk;
}
```

`syncTo()` returns a readonly `SyncReport`. Download preparation/ranges, chunk uploads, queue processing, native execution, retention, deduplication, and file watching likewise return dedicated readonly result objects rather than significant associative arrays.
`DownloadPreparation` carries status/headers/range metadata. `streamChunks()` revalidates the preparation, reads exactly the prepared range, and closes the source stream even when iteration ends early.

## Secure archives
## Durable local file queue

Every extraction path validates every ZIP member before writing. Absolute paths, Windows drive paths, null bytes, traversal segments, symbolic-link entries, extraction-root escapes, and existing destination-symlink breakouts are rejected with `UnsafeArchiveEntryException`. Default entry-count, per-entry size, total uncompressed-size, and compression-ratio limits mitigate ZIP bombs and can be configured explicitly.
```php
use Infocyph\Pathwise\Queue\FileJobQueue;

`FileJobQueue` is direct-local-only and intended for bounded, lightweight single-host workloads—not as a remote or distributed broker.
$queue = new FileJobQueue('/var/lib/app/jobs.json');
$queue->enqueue('thumbnail', ['id' => 'asset-42']);

## Auditing
$reservation = $queue->reserve();
if ($reservation !== null) {
// Work with $reservation->payload, renew long jobs when required.
$queue->acknowledge($reservation);
}
```

The queue is intentionally direct-local: it uses typed opaque leases, stale-worker rejection, strict versioned state, locking, and crash-safe persistence. It is not a distributed broker.

## Security model

Pathwise 4 includes explicit controls for:

`AuditTrail` accepts a local JSONL path or an `AuditSink`. `LocalJsonlAuditSink` uses locked append. `PartitionedAuditSink` writes one object per event and is suitable for mounted object stores. `CallbackAuditSink` integrates application loggers. Remote audit append is never silently emulated by reading and rewriting a log object.
- extension/MIME/signature validation and optional malware scanning;
- path/root restrictions, hidden-file blocking, safe symlink management;
- ZIP manifest validation, traversal/collision/special-entry rejection and extraction limits;
- bounded native commands with timeout/output ceilings and deterministic cleanup;
- safe serialization boundaries that do not instantiate untrusted objects;
- queue state size/payload/job limits and lease ownership;
- policy enforcement, audit sinks, retention, indexing, and watcher workloads.

## Native execution
Security-sensitive behavior is fail-closed where a configured capability is required. Adapter/native/metadata capabilities remain explicit rather than silently emulated.

`ExecutionStrategy::PHP` always uses PHP, `AUTO` may use an available native executable and fall back, and `NATIVE` either completes natively or throws `NativeExecutionException`. Native execution accepts local paths only; commands are executed as argument arrays without a shell, and execution results retain command, output, and exit code.
## Documentation

## Security
The Sphinx documentation is the canonical user guide and is built in CI with warnings treated as errors. Start with:

Do not disclose suspected vulnerabilities in a public issue, discussion or pull request. Review the
[security policy](SECURITY.md), then use [GitHub private vulnerability reporting](https://github.com/infocyph/Pathwise/security/advisories/new)
to contact the maintainers confidentially.
- `docs/quickstart.rst`
- `docs/storage-context.rst`
- `docs/upload-processing.rst`
- `docs/download-processing.rst`
- `docs/security.rst`
- `docs/migration-4.0.rst`
- `docs/api-reference.rst`
- `docs/performance-portability.rst`

## Development

```bash
composer install
composer ic:test:code
composer ic:qa
```

Pathwise is protected by [PHPForge](https://github.com/infocyph/PHPForge), an automated quality and security gate covering
tests, static and taint analysis, dependency auditing, architecture checks, and release readiness. Automated controls reduce
risk but do not replace responsible disclosure or manual review.
The release matrix covers PHP 8.4/8.5, stable and lowest dependencies, Windows, optional adapter contracts, static analysis/quality gates, clean install, documentation, and release workloads.

---
## License

<div align="center">
<sub><strong>Made with ❤️ for the PHP community</strong></sub><br />
<sub><a href="LICENSE">MIT Licensed</a></sub><br />
<a href="https://docs.infocyph.com/projects/Pathwise/en/latest/">Documentation</a> •
<a href="SECURITY.md">Security</a> •
<a href="CODE_OF_CONDUCT.md">Code of Conduct</a> •
<a href="CONTRIBUTING.md">Contributing</a><br />
<span title="Issue templates" aria-label="Issue templates">🗂️</span>
<a href="https://github.com/infocyph/Pathwise/issues/new?template=bug_report.yml">Bug</a> •
<a href="https://github.com/infocyph/Pathwise/issues/new?template=feature_request.yml">Feature</a> •
<a href="https://github.com/infocyph/Pathwise/issues/new?template=docs_improvement.yml">Documentation</a> •
<a href="https://github.com/infocyph/Pathwise/issues/new?template=question.yml">Question</a> •
<a href="https://github.com/infocyph/Pathwise/issues/new?template=ci_failure.yml">CI failure</a><br />
<span title="Pull request templates" aria-label="Pull request templates">🔀</span>
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=PULL_REQUEST_TEMPLATE.md">General</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=bug_fix.md">Bug fix</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=feature.md">Feature</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=refactor.md">Refactor</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=performance.md">Performance</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=security_reliability.md">Security &amp; reliability</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=documentation.md">Documentation</a> •
<a href="https://github.com/infocyph/Pathwise/compare/main...HEAD?quick_pull=1&amp;template=maintenance.md">Maintenance</a>
</div>
MIT
Loading
Loading