feat(cli): prepare and validate application documents offline

This commit is contained in:
Codex
2026-09-28 16:33:07 +02:00
parent 64e6b9664a
commit b9c3369e7b
20 changed files with 1164 additions and 49 deletions
+22 -1
View File
@@ -98,6 +98,16 @@ type Installation struct {
// Load reads and validates an installation descriptor at an absolute path.
func Load(path string) (Installation, error) {
return load(path, false)
}
// LoadPrepared applies the same authored configuration rules before release assets exist.
// Only standard distribution-owned Compose assets are deferred, never custom overrides.
func LoadPrepared(path string) (Installation, error) {
return load(path, true)
}
func load(path string, prepared bool) (Installation, error) {
if !filepath.IsAbs(path) {
return Installation{}, fmt.Errorf("installation path must be absolute")
}
@@ -143,6 +153,11 @@ func Load(path string) (Installation, error) {
if err := requireDirectory(raw.ProjectDirectory, "projectDirectory"); err != nil {
return Installation{}, err
}
if prepared {
if err := requireCanonicalDirectory(raw.ProjectDirectory); err != nil {
return Installation{}, errors.New("projectDirectory must be canonical and accessible")
}
}
for _, legacyProjection := range []string{
filepath.Join(raw.ProjectDirectory, "deploy", "pi", "models.json"),
filepath.Join(raw.ProjectDirectory, "deploy", "pi", "settings.json"),
@@ -195,7 +210,8 @@ func Load(path string) (Installation, error) {
return Installation{}, errors.New("authentication.configDirectory must match THT_AUTH_CONFIG_ROOT")
}
for _, override := range raw.Overrides {
if err := requireRegularFile(override, "override"); err != nil {
standardAsset := override == filepath.Join(installation.ProjectDirectory, "deploy", "compose.git-https.yaml") || override == filepath.Join(installation.ProjectDirectory, "deploy", "compose.git-ssh.yaml")
if err := requireRegularFile(override, "override"); err != nil && !(prepared && standardAsset && errors.Is(statPathError(override), os.ErrNotExist)) {
return Installation{}, err
}
installation.Overrides = append(installation.Overrides, filepath.Clean(override))
@@ -209,6 +225,9 @@ func Load(path string) (Installation, error) {
}
}
for _, composeFile := range installation.ComposeFiles()[:2] {
if prepared && errors.Is(statPathError(composeFile), os.ErrNotExist) {
continue
}
if err := requireRegularFile(composeFile, "Compose file"); err != nil {
return Installation{}, err
}
@@ -226,6 +245,8 @@ func Load(path string) (Installation, error) {
return installation, nil
}
func statPathError(path string) error { _, err := os.Lstat(path); return err }
var metadataSecretBundleKeyPattern = regexp.MustCompile(`^[A-Z][A-Z0-9_]{0,127}$`)
var metadataAPIKeyEnvironments = map[string]struct{}{
"THT_MODEL_API_KEY": {},