fix: close workspace preprocessing contract gaps

This commit is contained in:
2026-08-11 01:18:29 +02:00
parent 05a6e8cc2d
commit de27275bb1
15 changed files with 516 additions and 87 deletions
+58
View File
@@ -105,6 +105,59 @@ func TestUsageDocumentsClosedConfigureUpdateSourcesAndMaintenanceRecovery(t *tes
}
}
func TestRunWorkspacePublicDispatchExitMatrix(t *testing.T) {
cases := []struct {
name, status, code string
exit int
}{
{"succeeded", "succeeded", "ok", 0},
{"blocked", "blocked", "manual_review_required", 3},
{"failed", "failed", "workspace_not_found", 1},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", fmt.Sprintf(`{"schemaVersion":1,"status":%q,"code":%q,"workspaceId":"psd","workspaceRevision":"%s","descriptorBlob":"%s","operation":"inspect","completedStages":[]}`, tc.status, tc.code, strings.Repeat("0", 40), strings.Repeat("a", 40)))
t.Setenv("THOTHCTL_FAKE_WORKSPACE_EXIT", strconv.Itoa(tc.exit))
var stdout, stderr bytes.Buffer
got := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "inspect", "--workspace", "psd", "--json"}, &stdout, &stderr)
if got != tc.exit || stderr.Len() != 0 {
t.Fatalf("exit=%d stderr=%q; want exit %d", got, stderr.String(), tc.exit)
}
if len(fixture.invocations(t)) != 1 {
t.Fatalf("workspace dispatch invocations = %#v, want one", fixture.invocations(t))
}
})
}
}
func TestRunWorkspaceOperationalFailureExitsOne(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", "not-json")
var stdout, stderr bytes.Buffer
got := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "inspect", "--workspace", "psd"}, &stdout, &stderr)
if got != 1 || !strings.Contains(stderr.String(), "invalid workspace result") {
t.Fatalf("exit=%d stderr=%q; want operational exit 1", got, stderr.String())
}
}
func TestRunWorkspaceUnsafeOutputDoesNotInvokeCompose(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)
output := filepath.Join(fixture.root, "existing.yaml")
if err := os.WriteFile(output, []byte("existing"), 0o600); err != nil {
t.Fatal(err)
}
var stdout, stderr bytes.Buffer
got := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "schema", "suggest-fks", "--workspace", "psd", "--output", output}, &stdout, &stderr)
if got != 2 || !strings.Contains(stderr.String(), "unsafe output file") {
t.Fatalf("exit=%d stderr=%q; want unsafe host failure", got, stderr.String())
}
assertDockerNotInvoked(t, fixture)
}
func TestRunWorkspaceRejectsInvalidCommandBeforeDocker(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)
@@ -750,6 +803,9 @@ case " $* " in
else
printf '%s\n' '{"volumes":{"settings":{}},"services":{"core":{"image":"thothii-core:local","environment":{"THT_LLM_URL":"https://llm.example.invalid"}}}}'
fi ;;
*" run --rm --no-deps --no-TTY workspace-maintenance "*)
printf '%s\n' "${THOTHCTL_FAKE_WORKSPACE_RESULT:-}"
exit "${THOTHCTL_FAKE_WORKSPACE_EXIT:-0}" ;;
*" run --rm --no-deps --no-TTY session-migrate "*)
if [ "${THOTHCTL_FAKE_MIGRATION_EXIT:-0}" -ne 0 ]; then
printf '%s\n' "$THOTHCTL_FAKE_MIGRATION_FAILURE" >&2
@@ -805,6 +861,8 @@ func (f cliFixture) setEnvContents(t *testing.T, env string) {
t.Setenv("THOTHCTL_FAKE_CONFIG", "")
t.Setenv("THOTHCTL_FAKE_MIGRATION_FAILURE", "")
t.Setenv("THOTHCTL_FAKE_MIGRATION_EXIT", "0")
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", "")
t.Setenv("THOTHCTL_FAKE_WORKSPACE_EXIT", "0")
}
func (f cliFixture) setProfile(t *testing.T, profile string) {