diff --git a/.core/TODO.md b/.core/TODO.md index 8495647..e69de29 100644 --- a/.core/TODO.md +++ b/.core/TODO.md @@ -1,2 +0,0 @@ -- @hardening php/Console/Commands/PrepWorkspaceCommand.php:191 — `base64_decode()` is unchecked, so a malformed wiki payload can silently corrupt generated KB files. -- @hardening php/Console/Commands/PrepWorkspaceCommand.php:306 — `File::put()` return values are ignored, so TODO generation can fail without surfacing a write error. diff --git a/php/Console/Commands/PrepWorkspaceCommand.php b/php/Console/Commands/PrepWorkspaceCommand.php index 01acc8c..b22044f 100644 --- a/php/Console/Commands/PrepWorkspaceCommand.php +++ b/php/Console/Commands/PrepWorkspaceCommand.php @@ -46,6 +46,8 @@ class PrepWorkspaceCommand extends Command private bool $dryRun; + private bool $todoWriteFailed = false; + public function handle(): int { $this->baseUrl = rtrim((string) config('upstream.gitea.url', 'https://forge.lthn.ai'), '/'); @@ -101,6 +103,10 @@ class PrepWorkspaceCommand extends Command $this->generateTodoSkeleton($repo); } + if ($this->todoWriteFailed) { + return self::FAILURE; + } + // Step 4: Generate context from vector DB $contextCount = $this->generateContext($repo, $workspaceId, $issueTitle, $issueBody); @@ -188,7 +194,12 @@ class PrepWorkspaceCommand extends Command continue; } - $content = base64_decode($contentBase64); + $content = base64_decode($contentBase64, true); + if ($content === false) { + $this->warn(' Invalid base64 content for: ' . $title); + + continue; + } $filename = preg_replace('/[^a-zA-Z0-9_\-.]/', '-', $title) . '.md'; File::put($this->outputDir . '/kb/' . $filename, $content); @@ -303,8 +314,12 @@ class PrepWorkspaceCommand extends Command $this->line(' Checklist items: ' . count($checklistItems)); } } else { - File::put($this->outputDir . '/TODO.md', $todoContent); - $this->line(' TODO.md generated from: ' . $title); + if (File::put($this->outputDir . '/TODO.md', $todoContent) === false) { + $this->error(' Failed to write TODO.md from: ' . $title); + $this->todoWriteFailed = true; + } else { + $this->line(' TODO.md generated from: ' . $title); + } } return [$title, $body]; @@ -329,8 +344,12 @@ class PrepWorkspaceCommand extends Command if ($this->dryRun) { $this->line(' [would write] TODO.md skeleton'); } else { - File::put($this->outputDir . '/TODO.md', $content); - $this->line(' TODO.md skeleton generated (no --issue provided)'); + if (File::put($this->outputDir . '/TODO.md', $content) === false) { + $this->error(' Failed to write TODO.md skeleton'); + $this->todoWriteFailed = true; + } else { + $this->line(' TODO.md skeleton generated (no --issue provided)'); + } } }