Harden published curriculum and student flows
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
// In-memory fixture only; no writes to repository, external database or network.
|
||||
require_once dirname(__DIR__) . '/app/Core/Database.php';
|
||||
require_once dirname(__DIR__) . '/app/Services/StudentAccessControlService.php';
|
||||
require_once dirname(__DIR__) . '/app/Services/PublishedContentService.php';
|
||||
require_once dirname(__DIR__) . '/app/Services/CurriculumService.php';
|
||||
|
||||
use App\Core\Database;
|
||||
use App\Services\PublishedContentService;
|
||||
use App\Services\CurriculumService;
|
||||
|
||||
$pdo = class_exists('Pdo\\Sqlite') ? new \Pdo\Sqlite('sqlite::memory:') : new PDO('sqlite::memory:');
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
(new ReflectionProperty(Database::class, 'instance'))->setValue(null, $pdo);
|
||||
$pdo->exec('CREATE TABLE auth_identities (id INTEGER PRIMARY KEY, status TEXT)');
|
||||
$pdo->exec('CREATE TABLE students (id INTEGER PRIMARY KEY, grade_level TEXT, identity_id INTEGER)');
|
||||
$pdo->exec("INSERT INTO auth_identities VALUES (1, 'active'), (2, 'disabled')");
|
||||
$pdo->exec("INSERT INTO students VALUES (7, 'grade_10', 1), (8, 'grade_9', 1), (10, 'grade_10', 2)");
|
||||
|
||||
function checkContent(bool $condition, string $message): void
|
||||
{
|
||||
if (!$condition) throw new RuntimeException($message);
|
||||
}
|
||||
|
||||
$asset = ['grade_key' => 'grade_10', 'storage_driver' => 'local', 'storage_key' => 'manifest.json'];
|
||||
checkContent(PublishedContentService::studentMayRead(7, $asset), 'Same-grade student denied');
|
||||
checkContent(!PublishedContentService::studentMayRead(8, $asset), 'Other-grade student allowed');
|
||||
checkContent(!PublishedContentService::studentMayRead(9, $asset), 'Unknown student allowed');
|
||||
checkContent(!PublishedContentService::studentMayRead(10, $asset), 'Disabled identity allowed');
|
||||
checkContent(PublishedContentService::readLocalAsset($asset) !== null, 'Exact in-root asset not found');
|
||||
checkContent(PublishedContentService::readLocalAsset(array_merge($asset, ['storage_key' => '../../database_schema.sql'])) === null, 'Traversal escaped storage root');
|
||||
checkContent(PublishedContentService::readLocalAsset(array_merge($asset, ['storage_key' => 'missing.md'])) === null, 'Missing file substituted');
|
||||
checkContent(CurriculumService::getLessonMarkdown('../manifest.json') === '', 'Unsafe lesson read returned content');
|
||||
checkContent(!CurriculumService::safeMarkdownPath('../grade_10/a.md'), 'Traversal path accepted');
|
||||
checkContent(CurriculumService::safeMarkdownPath('grade_10/math_10/semester_1/unit_01/lesson_01.md'), 'Valid markdown path rejected');
|
||||
echo "PASS 10 local content-access checks (not an HTTP/tenant test)\n";
|
||||
Reference in New Issue
Block a user