Compare commits
5 Commits
081d40c208
...
v0.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 2bd4fe6189 | |||
| 5b4f77a72f | |||
| 1657be7711 | |||
| 50194c72b2 | |||
| 6bf63f1823 |
@@ -6,9 +6,15 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.2.0] — 2026-05-01
|
||||
|
||||
Render-time PII redaction utility added on the same calendar day as v0.1.0. Cut as a minor version bump rather than a patch because it adds a new public API surface (`RedactorInterface` plus the per-game implementation), which under semver is a minor change, not a patch. Consumers (notably iblogs) pin to `^0.2.0` to opt into the redactor-aware version.
|
||||
|
||||
### Added
|
||||
|
||||
- `RedactorInterface` (`src/Util/RedactorInterface.php`) and `ProjectZomboidRedactor` (`src/Util/ProjectZomboid/ProjectZomboidRedactor.php`) — render-time PII filter that scrubs Steam IDs, player names, and world coordinates from Project Zomboid log content. Three independent toggles default to on. Designed as a string-in/string-out utility so consumers can apply it at any rendering or export step. Documented v1 limitations: in PvP combat lines, only the attacker's name and coords are redacted; victim's name and coords (after `hit`) are deferred to v2. In admin lines, `teleported X to <coords>` coordinates are not redacted in v1.
|
||||
- 65 new test methods across six files under `test/tests/Util/Redactor/` — per-category unit tests, combined / toggle / idempotence matrix, and integration coverage that drives all 11 existing PZ fixtures through the redactor end-to-end. Suite total: 260 tests, 492 assertions.
|
||||
- `docs/superpowers/specs/2026-04-30-redactor-design.md` flipped from "deferred" to "implemented" status. Plan committed at `docs/superpowers/plans/2026-05-01-redactor.md`.
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -45,4 +51,5 @@ First public release. Codex is a generic PHP log parsing and analysis framework
|
||||
- **Other game implementations** — `Minecraft`, `Hytale`, and `SevenDaysToDie` are detective-stub-only. Each has a TODO `<Game>Detective` extending base `Detective`; their per-component subdirectories under `Analyser`, `Log`, `Parser`, and `Pattern` contain only `.gitkeep` placeholders. Real implementations land if and when fixtures and demand exist.
|
||||
- **Packagist publication** — v0.1.0 is consumable via Composer's `vcs` repository entry pointing at the Gitea remote. Pushing to Packagist is a separate decision and is not in scope for this release.
|
||||
|
||||
[0.2.0]: https://git.indifferentketchup.com/indifferentketchup/ik-codex/releases/tag/v0.2.0
|
||||
[0.1.0]: https://git.indifferentketchup.com/indifferentketchup/ik-codex/releases/tag/v0.1.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Codex Redactor utility — design spec
|
||||
|
||||
> Retroactive: written 2026-05-01.
|
||||
> **Status: deferred — not implemented.** This is a forward-looking design captured here for backfill symmetry and to inform iblogs's upload-time PII handling.
|
||||
> **Status: implemented on the `redactor` branch (2026-05-01).** Plan: `docs/superpowers/plans/2026-05-01-redactor.md`. Arrival commit set documented in `CHANGELOG.md` `[Unreleased]`. The "Status: deferred" framing below is preserved for historical context; treat this file as the as-built design contract.
|
||||
|
||||
## Summary
|
||||
|
||||
|
||||
@@ -69,6 +69,38 @@ class ProjectZomboidRedactorIntegrationTest extends TestCase
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields [fixturePath] for the subset of fixtures where every synthetic
|
||||
* player name (Player1 / Player2 / AdminUser / PlayerSuspect) appears
|
||||
* exclusively in a context the redactor recognises:
|
||||
*
|
||||
* - chat: ChatMessage{author='...'} envelope
|
||||
* - cmd, item, map, user: 77-char-Steam-ID followed by "..." quoted name
|
||||
*
|
||||
* Fixtures intentionally excluded:
|
||||
*
|
||||
* - admin: names appear in free-text positions (no Steam-ID anchor,
|
||||
* no quotes, no Combat:/Safety: prefix). Names survive in v1.
|
||||
* - client-action,
|
||||
* perk: names appear inside [...] brackets, not "..." quotes.
|
||||
* PLAYER_AFTER_STEAMID_REGEX requires double-quotes.
|
||||
* - pvp: attacker name redacts but victim name after `hit "..."`
|
||||
* survives in v1 (Task 3 limitation).
|
||||
* - burd-journals,
|
||||
* debug-server: no synthetic player names present.
|
||||
*/
|
||||
public static function fixturesWhereAllNamesAreInCoveredContextsProvider(): array
|
||||
{
|
||||
$dir = self::$fixturesDir;
|
||||
return [
|
||||
'chat' => [$dir . '/chat-minimal.txt'],
|
||||
'cmd' => [$dir . '/cmd-minimal.txt'],
|
||||
'item' => [$dir . '/item-minimal.txt'],
|
||||
'map' => [$dir . '/map-minimal.txt'],
|
||||
'user' => [$dir . '/user-minimal.txt'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields [fixturePath, logClass] for the fixtures whose log class parses
|
||||
* them. All 11 fixtures are represented.
|
||||
@@ -202,4 +234,39 @@ class ProjectZomboidRedactorIntegrationTest extends TestCase
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Test 4 — Player-name collapse in fully-covered fixtures
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* For fixtures where every synthetic player name appears exclusively in a
|
||||
* context the redactor recognises, no synthetic name should remain after
|
||||
* redaction.
|
||||
*
|
||||
* This addresses observation #3 from the final code review (the integration
|
||||
* tests previously asserted Steam-ID elimination + structural preservation
|
||||
* + idempotence, but did not directly verify name collapse). The unit tests
|
||||
* in ProjectZomboidRedactorPlayerNameTest cover this property exhaustively
|
||||
* per-context; this integration test re-verifies it end-to-end against the
|
||||
* fixtures that ride into iblogs.
|
||||
*/
|
||||
#[DataProvider('fixturesWhereAllNamesAreInCoveredContextsProvider')]
|
||||
public function testFixturePlayerNamesCollapseInCoveredContexts(string $fixturePath): void
|
||||
{
|
||||
$content = (new PathLogFile($fixturePath))->getContent();
|
||||
$redacted = $this->redact($content);
|
||||
|
||||
foreach (['Player1', 'Player2', 'AdminUser', 'PlayerSuspect'] as $name) {
|
||||
$this->assertStringNotContainsString(
|
||||
$name,
|
||||
$redacted,
|
||||
sprintf(
|
||||
'Fixture "%s": synthetic name %s survived redaction. Every name in this fixture should appear only in a covered lexical context.',
|
||||
basename($fixturePath),
|
||||
$name,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user