NeoNos Portfolio

DevTools

Audit the artifact that actually ships.

Tooling
$ composer require all1web/nativephp-devtools

Developer tools for NativePHP Mobile apps: a host-side release audit that opens the artifact that actually ships, and an on-device inspector for dev builds.

  • Release audit opens the real build artifact, not your source tree
  • CI-friendly JSON output via --json
  • On-device inspector for dev builds

Documentation

Synced from GitHub 0 seconds ago

nativephp-devtools

Developer tools for NativePHP Mobile apps — dev builds only.

Nobody checks the seam between what your Laravel project contains and what got zipped into the app package. MobSF can crack an APK but has no concept of a Laravel bundle, auth.json, cleanup_env_keys or a plugin manifest. native:debug never opens the artifact at all.

devtools:audit opens the artifact that actually ships and tells you what is in it.

composer require --dev all1web/nativephp-devtools
php artisan devtools:audit

What it does

Two halves, one package:

  • Release audit (devtools:audit) — opens the shipped bundle and the generated native project, and reports what leaked, what is misconfigured, and what the app declares. This is v1.
  • Device inspector — an on-device UI for dev builds. Not in v1; two questions about EDGE routing have to be answered on hardware first, and guessing at them would be worse than waiting.

Eight checks run over the artifact: bundle leak scan, .env residue, dependency and native-surface analysis, Android release hardening, iOS release hardening, composer advisories, capability truth, and a store-submission evidence pack. See docs/REFERENCE.md.

Why the artifact and not your config

The two code paths that build a bundle use different exclusion matchers, and on Windows the zip step ignores cleanup_exclude_files entirely — the only filter is robocopy /XD, which takes directories, so a file pattern silently does nothing. Your config describes what was meant to happen. Only the bundle records what did.

Run against a real production bundle of 57,722 entries, the audit found plaintext third-party licence credentials in a bundled auth.json; APP_KEY, MAIL_PASSWORD and REDIS_PASSWORD surviving cleanup_env_keys; the complete commit history of three private packages pulled in through composer path repositories; two vendored packages shipping their own vendor/ trees totalling 33,649 files including Pest and PHPUnit; and a shipped SQLite database. It took six seconds.

Exit codes

Code Meaning
0 Ran, found nothing at or above the threshold
1 Ran, found something
2 Could not run

2 is deliberately not 0. A CI step that reads "bundle not found" as a pass is worse than no CI step at all.

The command does not gate a release and does not pretend to — the framework's build-hook runner warns on a non-zero hook exit and carries on, so no build hook can stop anything. Wire it into your own pipeline:

php artisan devtools:audit --json > audit.json || exit 1

Secret values are redacted by default. --show-values exists, and the docs tell you not to use it in CI.

This never ships to production

There is no hidden mode, no secret key, no production admin surface. The package is require-dev, contributes zero native code — no Kotlin, no Swift, no manifest nodes, no bridge functions — and its service provider registers nothing at all outside a development environment with APP_DEBUG on.

Zero native code is a security property rather than a style choice. The plugin compiler does not consult the composer section a package was installed from, so a plugin contributing native code ships its Kotlin into release builds even as require-dev, while --no-dev strips the PHP that was supposed to gate it. A test fails the build if this package ever grows a .kt, a .swift or a bridge function. The audit reports that exact failure in other packages.

Removal

Uninstall is one command, with nothing else to undo:

composer remove --dev all1web/nativephp-devtools

No plugin allowlist entry to clean up and no native:install --force afterwards, because there is no native code to unregister. That is verified rather than assumed: the framework filters on composer type before it consults its allowlist, so this package is absent from plugin discovery even if you add its service provider to NativeServiceProvider::plugins() by hand. Registration is not just unnecessary, it is impossible.

If you do nothing, a release build already strips it: native:build runs composer install --no-dev. Debug builds keep it deliberately, and that is fine — nothing in a debug bundle reaches a user.

If you want to be certain, keep it installed but exclude it from bundles:

// config/nativephp.php
'cleanup_exclude_files' => [
    // keep the framework defaults
    'storage/framework/sessions',
    'storage/framework/cache',
    'storage/framework/testing',
    'storage/logs',
    // and exclude this package
    'vendor/all1web/nativephp-devtools',
],

Then prove it. Re-run php artisan devtools:audit and confirm the self-present finding is gone. Do not take the config's word for it — on Windows those patterns are ignored at zip time. The audit reports its own presence in any bundle it analyses, because a tool that finds everyone else's leaked dev dependencies while staying quiet about its own is a defect.

php artisan devtools:doctor reports the gate state, which composer section the package landed in, and this removal path.

Documentation

  • DESIGN.md — what it deliberately does not do, and why
  • REFERENCE.md — commands, checks, findings, corpus format
  • PLATFORM-NOTES.md — verified build behaviour, and the limits of what an artifact can tell you
  • STORE-REVIEW.md — the evidence pack, and its boundary

Requirements

PHP 8.2+, Laravel 10/11/12, ext-zip. nativephp/mobile is not required: the audit reads build artifacts, so the test suite runs off-device.


Status: v1 in development. Half A complete and tested; Half B pending on-device verification. No public claims yet.