feat: finish Pi and workspace management updates

This commit is contained in:
2026-08-16 14:19:32 +02:00
parent 7651b63cea
commit 351361f72f
20 changed files with 2276 additions and 149 deletions
+6
View File
@@ -122,6 +122,12 @@ func extractSecretValues(contents []byte) ([]string, error) {
if whole != "" {
values = append(values, whole)
}
// PEM files (including OpenSSH private keys) can contain base64 lines that look
// like dotenv assignments. Keep the complete document opaque instead of trying
// to parse it as a dotenv bundle.
if bytes.HasPrefix(trimmed, []byte("-----BEGIN ")) {
return values, nil
}
if trimmed[0] == '{' || trimmed[0] == '[' {
var document any
@@ -105,6 +105,26 @@ func TestSecretValuesFromFilesRedactsEveryDotenvBundleValue(t *testing.T) {
}
}
func TestSecretValuesFromFilesAcceptsOpenSSHPrivateKey(t *testing.T) {
t.Parallel()
secretFile := filepath.Join(physicalTempDir(t), "git-ssh-key")
contents := "-----BEGIN OPENSSH PRIVATE KEY-----\n" +
"ZmFrZS1rZXktcGF5bG9hZA==\n" +
"-----END OPENSSH PRIVATE KEY-----\n"
if err := os.WriteFile(secretFile, []byte(contents), 0o600); err != nil {
t.Fatal(err)
}
secrets, err := SecretValuesFromFiles([]string{secretFile})
if err != nil {
t.Fatalf("SecretValuesFromFiles() error = %v, want OpenSSH key accepted", err)
}
if len(secrets) == 0 {
t.Fatal("SecretValuesFromFiles() returned no values for OpenSSH key")
}
}
func TestSanitizeRecognizesQuotedCredentialKeys(t *testing.T) {
t.Parallel()
+1 -1
View File
@@ -42,7 +42,7 @@ type settingsFileSnapshot struct {
var internalIdentityHeaders = []string{
"-H", "x-thoth-principal-issuer: tht",
"-H", "x-thoth-principal-subject: tht-maintenance",
"-H", "x-thoth-principal-display-name: Tht maintenance",
"-H", "x-thoth-principal-display-name: Tht maintenance",
"-H", "x-thoth-is-admin: 1",
}
+46
View File
@@ -0,0 +1,46 @@
package pi
import (
"bufio"
"errors"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
)
var defaultPiArgPattern = regexp.MustCompile(`^ARG[[:space:]]+PI_VERSION[[:space:]]*=(.*)$`)
// ReadPinnedVersion reads the repository's declared Pi runtime version. It deliberately reads
// only the default ARG, not the later ARG PI_VERSION declarations used by build stages.
func ReadPinnedVersion(projectDirectory string) (string, error) {
path := filepath.Join(projectDirectory, "docker", "core.Dockerfile")
file, err := os.Open(path)
if err != nil {
return "", fmt.Errorf("read Pi version pin: %w", err)
}
defer file.Close()
var version string
count := 0
scanner := bufio.NewScanner(file)
for scanner.Scan() {
match := defaultPiArgPattern.FindStringSubmatch(strings.TrimSuffix(scanner.Text(), "\r"))
if len(match) != 2 {
continue
}
count++
version = strings.TrimSpace(match[1])
}
if err := scanner.Err(); err != nil {
return "", fmt.Errorf("read Pi version pin: %w", err)
}
if count != 1 {
return "", errors.New("docker/core.Dockerfile must contain exactly one default PI_VERSION")
}
if _, err := parseSemanticVersion(version); err != nil {
return "", errors.New("docker/core.Dockerfile contains an invalid Pi version")
}
return version, nil
}
+52
View File
@@ -0,0 +1,52 @@
package pi
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestReadPinnedVersionReadsTheSingleDefaultPiArg(t *testing.T) {
root := t.TempDir()
writeCoreDockerfile(t, root, "ARG PI_VERSION=0.81.0\nARG PI_VERSION\n")
got, err := ReadPinnedVersion(root)
if err != nil {
t.Fatal(err)
}
if got != "0.81.0" {
t.Fatalf("ReadPinnedVersion() = %q, want 0.81.0", got)
}
}
func TestReadPinnedVersionRejectsMissingDuplicateAndMalformedPins(t *testing.T) {
for _, test := range []struct {
name string
file string
want string
}{
{name: "missing", file: "# no default\n", want: "one default PI_VERSION"},
{name: "duplicate", file: "ARG PI_VERSION=0.80.3\nARG PI_VERSION=0.81.0\n", want: "one default PI_VERSION"},
{name: "malformed", file: "ARG PI_VERSION=latest\n", want: "invalid Pi version"},
} {
t.Run(test.name, func(t *testing.T) {
root := t.TempDir()
writeCoreDockerfile(t, root, test.file)
_, err := ReadPinnedVersion(root)
if err == nil || !strings.Contains(err.Error(), test.want) {
t.Fatalf("ReadPinnedVersion() error = %v, want %q", err, test.want)
}
})
}
}
func writeCoreDockerfile(t *testing.T, root, contents string) {
t.Helper()
if err := os.MkdirAll(filepath.Join(root, "docker"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(root, "docker", "core.Dockerfile"), []byte(contents), 0o600); err != nil {
t.Fatal(err)
}
}
+42 -42
View File
@@ -90,14 +90,14 @@ type RunRequest struct {
Resume string
}
func (InspectRequest) workspaceRequest() {}
func (DwhRequest) workspaceRequest() {}
func (SuggestFksRequest) workspaceRequest() {}
func (CheckSchemaRequest) workspaceRequest() {}
func (InspectRequest) workspaceRequest() {}
func (DwhRequest) workspaceRequest() {}
func (SuggestFksRequest) workspaceRequest() {}
func (CheckSchemaRequest) workspaceRequest() {}
func (AcceptSchemaRequest) workspaceRequest() {}
func (IndexSchemaRequest) workspaceRequest() {}
func (EvidenceRequest) workspaceRequest() {}
func (RunRequest) workspaceRequest() {}
func (IndexSchemaRequest) workspaceRequest() {}
func (EvidenceRequest) workspaceRequest() {}
func (RunRequest) workspaceRequest() {}
func (InspectRequest) operatorCommand() string { return "inspect" }
func (DwhRequest) operatorCommand() string { return "preprocess-dwh" }
@@ -106,9 +106,9 @@ func (CheckSchemaRequest) operatorCommand() string {
return "schema-check"
}
func (AcceptSchemaRequest) operatorCommand() string { return "schema-accept" }
func (IndexSchemaRequest) operatorCommand() string { return "index-schema" }
func (EvidenceRequest) operatorCommand() string { return "preprocess-evidence" }
func (RunRequest) operatorCommand() string { return "preprocess-run" }
func (IndexSchemaRequest) operatorCommand() string { return "index-schema" }
func (EvidenceRequest) operatorCommand() string { return "preprocess-evidence" }
func (RunRequest) operatorCommand() string { return "preprocess-run" }
func (r InspectRequest) stdinEnvelope() (requestEnvelope, error) {
return requestEnvelope{SchemaVersion: 1, WorkspaceID: r.Workspace}, nil
@@ -165,19 +165,19 @@ func (r RunRequest) stdinEnvelope() (requestEnvelope, error) {
}
type requestEnvelope struct {
SchemaVersion int `json:"schemaVersion"`
WorkspaceID string `json:"workspaceId"`
Resume string `json:"resumeRunId,omitempty"`
DryRun bool `json:"dryRun,omitempty"`
Assume []string `json:"assume,omitempty"`
SQLFiles []inputFile `json:"fromSql,omitempty"`
Annotations string `json:"annotationsYaml,omitempty"`
ReviewedCandidates string `json:"reviewedCandidatesDigest,omitempty"`
Collection string `json:"collection,omitempty"`
Confirm string `json:"confirm,omitempty"`
Destroy bool `json:"destroy,omitempty"`
RunID string `json:"runId,omitempty"`
Yes bool `json:"yes,omitempty"`
SchemaVersion int `json:"schemaVersion"`
WorkspaceID string `json:"workspaceId"`
Resume string `json:"resumeRunId,omitempty"`
DryRun bool `json:"dryRun,omitempty"`
Assume []string `json:"assume,omitempty"`
SQLFiles []inputFile `json:"fromSql,omitempty"`
Annotations string `json:"annotationsYaml,omitempty"`
ReviewedCandidates string `json:"reviewedCandidatesDigest,omitempty"`
Collection string `json:"collection,omitempty"`
Confirm string `json:"confirm,omitempty"`
Destroy bool `json:"destroy,omitempty"`
RunID string `json:"runId,omitempty"`
Yes bool `json:"yes,omitempty"`
}
type inputFile struct {
@@ -186,23 +186,23 @@ type inputFile struct {
}
type Result struct {
SchemaVersion int `json:"schemaVersion"`
Status string `json:"status"`
Code string `json:"code"`
WorkspaceID string `json:"workspaceId"`
WorkspaceRevision string `json:"workspaceRevision"`
DescriptorBlob string `json:"descriptorBlob"`
Operation string `json:"operation"`
RunID string `json:"runId,omitempty"`
ChildRuns map[string]string `json:"childRuns,omitempty"`
CompletedStages []string `json:"completedStages"`
Counts map[string]int `json:"counts,omitempty"`
ArtifactIdentities []ArtifactIdentity `json:"artifactIdentities,omitempty"`
SuggestedFksYAML string `json:"suggestedFksYaml,omitempty"`
EffectiveConfigIdentity string `json:"effectiveConfigIdentity,omitempty"`
ConfigFingerprint string `json:"configFingerprint,omitempty"`
InputFingerprint string `json:"inputFingerprint,omitempty"`
Warnings []string `json:"warnings,omitempty"`
SchemaVersion int `json:"schemaVersion"`
Status string `json:"status"`
Code string `json:"code"`
WorkspaceID string `json:"workspaceId"`
WorkspaceRevision string `json:"workspaceRevision"`
DescriptorBlob string `json:"descriptorBlob"`
Operation string `json:"operation"`
RunID string `json:"runId,omitempty"`
ChildRuns map[string]string `json:"childRuns,omitempty"`
CompletedStages []string `json:"completedStages"`
Counts map[string]int `json:"counts,omitempty"`
ArtifactIdentities []ArtifactIdentity `json:"artifactIdentities,omitempty"`
SuggestedFksYAML string `json:"suggestedFksYaml,omitempty"`
EffectiveConfigIdentity string `json:"effectiveConfigIdentity,omitempty"`
ConfigFingerprint string `json:"configFingerprint,omitempty"`
InputFingerprint string `json:"inputFingerprint,omitempty"`
Warnings []string `json:"warnings,omitempty"`
}
type ArtifactIdentity struct {
@@ -883,8 +883,8 @@ type VectorRebuildRequest struct {
Destroy bool
}
func (VectorInspectRequest) workspaceRequest() {}
func (VectorRebuildRequest) workspaceRequest() {}
func (VectorInspectRequest) workspaceRequest() {}
func (VectorRebuildRequest) workspaceRequest() {}
func (VectorInspectRequest) operatorCommand() string { return "vector-inspect" }
func (VectorRebuildRequest) operatorCommand() string { return "vector-rebuild" }
func (r VectorInspectRequest) stdinEnvelope() (requestEnvelope, error) {