feat: finish Pi and workspace management updates
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user