Files
cacti/tests/Unit/Core/Cli/CactiEntrypointSecurityTest.php
Thomas Vincent 1ae479d4f5 feat(cli): add unified command frontend and normalize legacy failures (#7903)
* feat(cli): add unified command frontend and normalize legacy failures

Add the Symfony-backed bin/cacti entry point while preserving legacy argument, terminal, signal, and exit-status behavior. Fold in the focused legacy CLI correctness fixes from #7906 without adding its unused parser abstraction.

Keep path containment and the PHP 8.3 floor out of this review; the latter remains in #7939.

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>

* fix(cli): enforce PHP floor and deny web dispatch

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
2026-09-07 18:36:55 -07:00

69 lines
2.6 KiB
PHP

<?php
/*
+-------------------------------------------------------------------------+
| Copyright (C) 2004-2026 The Cacti Group |
+-------------------------------------------------------------------------+
| Cacti: The Complete RRDtool-based Graphing Solution |
+-------------------------------------------------------------------------+
*/
test('the unified CLI entrypoint loads the CLI-only guard before autoloading', function () : void {
$source = file_get_contents(dirname(__DIR__, 4) . '/bin/cacti');
expect($source)->not->toBeFalse()
->and($source)->toContain("require_once \$root . '/include/cli_only.php';");
if ($source === false) {
return;
}
expect(strpos($source, 'include/cli_only.php'))->toBeLessThan(strpos($source, 'require $autoload'));
});
test('the CLI-only guard rejects non-CLI SAPIs before application bootstrap', function () : void {
$source = file_get_contents(dirname(__DIR__, 4) . '/include/cli_only.php');
expect($source)->not->toBeFalse()
->and($source)->toContain("PHP_SAPI !== 'cli'")
->and($source)->toContain('http_response_code(403)')
->and($source)->toContain('exit(1)');
});
test('the bin directory denies web access under supported Apache versions', function () : void {
$source = file_get_contents(dirname(__DIR__, 4) . '/bin/.htaccess');
expect($source)->not->toBeFalse()
->and($source)->toContain('Require all denied')
->and($source)->toContain('Order Allow,Deny')
->and($source)->toContain('Deny from all');
});
test('every executable Console fixture loads the CLI-only guard', function () : void {
$fixtures = glob(dirname(__DIR__, 3) . '/fixtures/Console/cli/*.php');
expect($fixtures)->not->toBeFalse()->not->toBeEmpty();
foreach ($fixtures ?: [] as $fixture) {
expect(file_get_contents($fixture))->toContain("require_once dirname(__DIR__, 4) . '/include/cli_only.php';");
}
});
test('the tests directory denies browsing and direct Apache access', function () : void {
$root = dirname(__DIR__, 4);
$deny = file_get_contents($root . '/tests/.htaccess');
$redirect = file_get_contents($root . '/tests/index.php');
expect($deny)->not->toBeFalse()
->and($deny)->toContain('Require all denied')
->and($deny)->toContain('Deny from all')
->and($redirect)->not->toBeFalse()
->and($redirect)->toContain("header('Location:../index.php')");
});
test('TTY handoff requires stderr to remain attached to the terminal', function () : void {
$source = file_get_contents(dirname(__DIR__, 4) . '/lib/Console/Command/LegacyScriptCommand.php');
expect($source)->not->toBeFalse()
->and($source)->toContain("stream_isatty(STDERR)");
});