fix workspace output and cleanup uncertainty

This commit is contained in:
2026-08-11 04:46:48 +02:00
parent c7f7a6e1b0
commit 69cc47c13f
12 changed files with 358 additions and 91 deletions
+85 -2
View File
@@ -3,6 +3,8 @@ package main
import (
"bytes"
"context"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -134,12 +136,21 @@ func TestRunWorkspacePublicDispatchExitMatrix(t *testing.T) {
}
func TestRunWorkspaceBoundsFinalJSONEncoding(t *testing.T) {
for _, tc := range []struct{ name string; final int; wantCode int }{{"exact", 1 << 20, 0}, {"one-over", (1 << 20) + 1, 1}} {
for _, tc := range []struct {
name string
final int
wantCode int
}{
{name: "exact", final: 1 << 20, wantCode: 0},
{name: "one-over", final: (1 << 20) + 1, wantCode: 1},
} {
t.Run(tc.name, func(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)
payload, encodedLength := boundedWorkspaceResultPayload(t, tc.final)
if encodedLength != tc.final { t.Fatalf("final encoded length = %d, want %d", encodedLength, tc.final) }
if encodedLength != tc.final {
t.Fatalf("final encoded length = %d, want %d", encodedLength, tc.final)
}
writeWorkspaceResultFile(t, fixture, payload)
var stdout, stderr bytes.Buffer
code := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "inspect", "--workspace", "psd", "--json"}, &stdout, &stderr)
@@ -150,6 +161,78 @@ func TestRunWorkspaceBoundsFinalJSONEncoding(t *testing.T) {
}
}
type failingWorkspaceWriter struct{}
func (failingWorkspaceWriter) Write([]byte) (int, error) {
return 0, errors.New("injected stdout failure")
}
func TestRunWorkspaceReportsCommittedReconcileOnStdoutFailure(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", `{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"0000000000000000000000000000000000000000","descriptorBlob":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","operation":"inspect","completedStages":[]}`)
var stderr bytes.Buffer
code := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "inspect", "--workspace", "psd"}, failingWorkspaceWriter{}, &stderr)
if code != 1 || !strings.Contains(stderr.String(), "reconcile") {
t.Fatalf("exit=%d stderr=%q, want committed reconcile guidance", code, stderr.String())
}
}
func TestRunWorkspaceRejectsDeclaredSecretInFinalJSONKeyBeforeCandidateCommit(t *testing.T) {
fixture := newCLIFixture(t, "UNLABELLED_SECRET_FILE=%s\n")
secretPath := filepath.Join(fixture.root, "secret")
if err := os.WriteFile(secretPath, []byte("schemaVersion"), 0o600); err != nil {
t.Fatal(err)
}
fixture.setEnvironment(t, secretPath)
candidate := []byte("candidates: []\n")
digest := fmt.Sprintf("%x", sha256.Sum256(candidate))
result := fmt.Sprintf(`{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"%s","descriptorBlob":"%s","operation":"suggest-fks","runId":"0123456789abcdef0123456789abcdef","completedStages":[],"artifactIdentities":[{"kind":"fk-candidates","digest":"%s"}],"hostExport":{"mediaType":"application/yaml","sha256":"%s","contentBase64":"%s"}}`, strings.Repeat("0", 40), strings.Repeat("a", 40), digest, digest, base64.StdEncoding.EncodeToString(candidate))
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", result)
output := filepath.Join(fixture.root, "candidate.yaml")
var stdout, stderr bytes.Buffer
code := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "schema", "suggest-fks", "--workspace", "psd", "--output", output, "--json"}, &stdout, &stderr)
if code != 1 || stdout.Len() != 0 {
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout.String(), stderr.String())
}
if _, err := os.Stat(output); !os.IsNotExist(err) {
t.Fatalf("candidate exists after final-byte secret rejection: %v", err)
}
if strings.Contains(stderr.String(), "schemaVersion") {
t.Fatalf("stderr leaked declared secret: %q", stderr.String())
}
}
func TestRunWorkspaceRejectsDeclaredSecretInHumanChrome(t *testing.T) {
fixture := newCLIFixture(t, "UNLABELLED_SECRET_FILE=%s\n")
secretPath := filepath.Join(fixture.root, "secret")
if err := os.WriteFile(secretPath, []byte("Workspace"), 0o600); err != nil {
t.Fatal(err)
}
fixture.setEnvironment(t, secretPath)
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", `{"schemaVersion":1,"status":"succeeded","code":"ok","workspaceId":"psd","workspaceRevision":"0000000000000000000000000000000000000000","descriptorBlob":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","operation":"inspect","completedStages":[]}`)
var stdout, stderr bytes.Buffer
code := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "inspect", "--workspace", "psd"}, &stdout, &stderr)
if code != 1 || stdout.Len() != 0 || strings.Contains(stderr.String(), "Workspace") {
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout.String(), stderr.String())
}
}
func TestRunWorkspaceErrorPrefixNeverLeaksDeclaredSecret(t *testing.T) {
fixture := newCLIFixture(t, "UNLABELLED_SECRET_FILE=%s\n")
secretPath := filepath.Join(fixture.root, "secret")
if err := os.WriteFile(secretPath, []byte("thothctl:"), 0o600); err != nil {
t.Fatal(err)
}
fixture.setEnvironment(t, secretPath)
t.Setenv("THOTHCTL_FAKE_WORKSPACE_RESULT", "not-json")
var stdout, stderr bytes.Buffer
code := run(context.Background(), []string{"--installation", fixture.installationPath, "workspace", "inspect", "--workspace", "psd"}, &stdout, &stderr)
if code != 1 || stdout.Len() != 0 || strings.Contains(stderr.String(), "thothctl:") {
t.Fatalf("exit=%d stdout=%q stderr=%q", code, stdout.String(), stderr.String())
}
}
func TestRunWorkspaceBoundsFinalHumanEncoding(t *testing.T) {
fixture := newCLIFixture(t, "")
fixture.setEnvironment(t)