Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
- Implemented comprehensive unit tests for RabbitMqTransportServer, covering constructor, disposal, connection management, event handlers, and exception handling. - Added configuration tests for RabbitMqTransportServer to validate SSL, durable queues, auto-recovery, and custom virtual host options. - Created unit tests for UdpFrameProtocol, including frame parsing and serialization, header size validation, and round-trip data preservation. - Developed tests for UdpTransportClient, focusing on connection handling, event subscriptions, and exception scenarios. - Established tests for UdpTransportServer, ensuring proper start/stop behavior, connection state management, and event handling. - Included tests for UdpTransportOptions to verify default values and modification capabilities. - Enhanced service registration tests for Udp transport services in the dependency injection container.
7.9 KiB
7.9 KiB
CONTRACT-SCANNER-PHP-ANALYZER-013: PHP Language Analyzer Bootstrap
Status: Published Version: 1.0.0 Published: 2025-12-05 Owners: PHP Analyzer Guild, Scanner Guild Unblocks: SCANNER-ANALYZERS-PHP-27-001
Overview
This contract defines the PHP language analyzer bootstrap specification, including composer manifest parsing, VFS (Virtual File System) schema, and offline kit target requirements for deterministic PHP project analysis.
Scope
The PHP analyzer will:
- Parse
composer.jsonandcomposer.lockfiles - Build virtual file system from source trees, vendor directories, and configs
- Detect framework/CMS fingerprints (Laravel, Symfony, WordPress, Drupal, etc.)
- Emit SBOM components with PHP-specific PURLs
- Support offline analysis via cached dependencies
Input Normalization
Source Tree Merge
The analyzer merges these sources into a unified VFS:
Priority (highest to lowest):
1. /app (mounted application source)
2. /vendor (composer dependencies)
3. /etc/php* (PHP configuration)
4. Container layer filesystem
File Discovery
public interface IPhpSourceDiscovery
{
IAsyncEnumerable<PhpSourceFile> DiscoverAsync(
string rootPath,
PhpDiscoveryOptions options,
CancellationToken ct);
}
public record PhpDiscoveryOptions
{
public bool IncludeVendor { get; init; } = true;
public bool IncludeTests { get; init; } = false;
public string[] ExcludePatterns { get; init; } = ["*.min.php", "cache/*"];
}
Composer Schema
composer.json Parsing
{
"name": "vendor/package",
"version": "1.2.3",
"type": "library|project|metapackage|composer-plugin",
"require": {
"php": ">=8.1",
"vendor/dependency": "^2.0"
},
"require-dev": { },
"autoload": {
"psr-4": { "App\\": "src/" },
"classmap": ["database/"],
"files": ["helpers.php"]
}
}
composer.lock Parsing
Extract exact versions and content hashes:
public record ComposerLockPackage
{
public string Name { get; init; }
public string Version { get; init; }
public string Source { get; init; } // type: git|hg|svn
public string Dist { get; init; } // type: zip|tar
public string Reference { get; init; } // commit hash or tag
public string ContentHash { get; init; } // SHA256 of package contents
}
PURL Format
pkg:composer/vendor/package@version
pkg:composer/laravel/framework@10.0.0
pkg:composer/symfony/http-kernel@6.3.0
VFS Schema
Virtual File System Model
public record PhpVirtualFileSystem
{
public string RootPath { get; init; }
public IReadOnlyList<VfsEntry> Entries { get; init; }
public PhpConfiguration PhpConfig { get; init; }
public ComposerManifest Composer { get; init; }
public string ContentHash { get; init; } // BLAKE3 of sorted entries
}
public record VfsEntry
{
public string RelativePath { get; init; }
public VfsEntryType Type { get; init; }
public long Size { get; init; }
public string ContentHash { get; init; }
public DateTimeOffset ModifiedAt { get; init; }
}
public enum VfsEntryType
{
PhpSource,
PhpConfig,
ComposerJson,
ComposerLock,
Vendor,
Asset,
Config
}
Deterministic Ordering
VFS entries MUST be sorted by:
RelativePath(case-sensitive, lexicographic)- Stable hash computation across runs
Framework Detection
Fingerprint Rules
| Framework | Detection Method | Confidence |
|---|---|---|
| Laravel | artisan file + Illuminate\ namespace |
High |
| Symfony | symfony.lock or config/bundles.php |
High |
| WordPress | wp-config.php + wp-includes/ |
High |
| Drupal | core/lib/Drupal.php |
High |
| Magento | app/etc/env.php + Magento\ namespace |
High |
| CodeIgniter | system/core/CodeIgniter.php |
Medium |
| Yii | yii or yii2 in composer |
Medium |
| CakePHP | cakephp/cakephp in composer |
Medium |
Fingerprint Output
public record PhpFrameworkFingerprint
{
public string Name { get; init; }
public string Version { get; init; }
public ConfidenceLevel Confidence { get; init; }
public IReadOnlyList<string> IndicatorFiles { get; init; }
}
PHP Configuration
Config File Discovery
/etc/php/*/php.ini
/etc/php/*/conf.d/*.ini
/etc/php-fpm.d/*.conf
/usr/local/etc/php/php.ini (Alpine)
Security-Relevant Settings
Extract and report:
public record PhpSecurityConfig
{
public bool AllowUrlFopen { get; init; }
public bool AllowUrlInclude { get; init; }
public string OpenBasedir { get; init; }
public string DisableFunctions { get; init; }
public string DisableClasses { get; init; }
public bool ExposePhp { get; init; }
public bool DisplayErrors { get; init; }
}
Output Schema
SBOM Component
{
"type": "library",
"bom-ref": "pkg:composer/vendor/package@1.2.3",
"purl": "pkg:composer/vendor/package@1.2.3",
"name": "vendor/package",
"version": "1.2.3",
"properties": [
{ "name": "stellaops:php:framework", "value": "laravel" },
{ "name": "stellaops:php:phpVersion", "value": ">=8.1" },
{ "name": "stellaops:php:autoload", "value": "psr-4" }
],
"evidence": {
"identity": {
"field": "purl",
"confidence": 1.0,
"methods": [{ "technique": "manifest-analysis", "value": "composer.lock" }]
}
}
}
Analysis Store Keys
public static class PhpAnalysisKeys
{
public const string VirtualFileSystem = "php.vfs";
public const string ComposerManifest = "php.composer";
public const string FrameworkFingerprints = "php.frameworks";
public const string SecurityConfig = "php.security-config";
public const string Autoload = "php.autoload";
}
Offline Kit Target
Bundle Structure
offline/php-analyzer/
├── manifests/
│ └── php-analyzer-manifest.json
├── fixtures/
│ ├── laravel-app/
│ ├── symfony-app/
│ └── wordpress-site/
├── vendor-cache/
│ └── packages.json (Packagist mirror index)
└── SHA256SUMS
Air-Gap Operation
public interface IOfflineComposerRepository
{
Task<ComposerPackage?> ResolveAsync(string name, string version, CancellationToken ct);
Task<bool> IsAvailableOfflineAsync(string name, string version, CancellationToken ct);
}
Test Fixtures
Required Fixtures
| Fixture | Purpose |
|---|---|
laravel-10-app/ |
Laravel 10.x application with mix/vite |
symfony-6-app/ |
Symfony 6.x with Doctrine |
wordpress-6-site/ |
WordPress 6.x with plugins |
drupal-10-site/ |
Drupal 10.x with modules |
composer-only/ |
Pure library project |
legacy-php56/ |
PHP 5.6 compatibility test |
Golden Output Format
fixtures/<name>/
├── composer.json
├── composer.lock
├── src/
├── EXPECTED.sbom.json # Expected SBOM output
├── EXPECTED.vfs.json # Expected VFS structure
└── EXPECTED.meta.json # Expected fingerprints
Implementation Path
Phase 1: Core Parser
- Implement
ComposerJsonParser - Implement
ComposerLockParser - Add PURL generation
- Basic VFS construction
Phase 2: Framework Detection
- Implement fingerprint rules
- Add confidence scoring
- Version detection
Phase 3: Offline Support
- Implement vendor cache
- Add offline repository
- Bundle generation
Project Location
src/Scanner/StellaOps.Scanner.Analyzers.Lang.Php/
├── StellaOps.Scanner.Analyzers.Lang.Php.csproj
├── ComposerJsonParser.cs
├── ComposerLockParser.cs
├── PhpVirtualFileSystem.cs
├── PhpFrameworkDetector.cs
├── PhpLanguageAnalyzer.cs
├── PhpAnalyzerPlugin.cs
└── README.md
Changelog
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0.0 | 2025-12-05 | PHP Analyzer Guild | Initial contract |