fix: harden model catalog projections
This commit is contained in:
@@ -528,8 +528,13 @@ func piCommand(ctx context.Context, installation config.Installation, runner com
|
||||
defer func() { _ = lock.Release() }()
|
||||
}
|
||||
if args[0] == "restart" || args[0] == "update" || args[0] == "rollback" {
|
||||
if err := modelprojection.Generate(installation); err != nil {
|
||||
return commandUsageError(stderr, "installation model catalog could not be projected: "+err.Error())
|
||||
drift, err := modelprojection.Check(installation)
|
||||
if err != nil {
|
||||
return commandUsageError(stderr, "installation model catalog could not be verified: "+err.Error())
|
||||
}
|
||||
if len(drift) > 0 {
|
||||
return commandUsageError(stderr,
|
||||
"installation model catalog changed; run tht start to apply the complete runtime projection")
|
||||
}
|
||||
}
|
||||
controlled := compose.InstallationRunner{Installation: installation, Runner: runner}
|
||||
|
||||
@@ -1057,6 +1057,7 @@ func TestRunPiStatusUsesImageBundledPi(t *testing.T) {
|
||||
func TestRunPiUpdateResolvesLatestStableVersionWhenVersionIsOmitted(t *testing.T) {
|
||||
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
|
||||
fixture.setEnvironment(t)
|
||||
fixture.generateModelProjection(t)
|
||||
if err := os.WriteFile(filepath.Join(fixture.projectDirectory, "docker", "core.Dockerfile"), []byte("ARG PI_VERSION=0.79.0\n"), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -1079,6 +1080,7 @@ func TestRunPiUpdateResolvesLatestStableVersionWhenVersionIsOmitted(t *testing.T
|
||||
func TestRunPiUpdateRequiresExplicitConfirmationWithoutInvokingDocker(t *testing.T) {
|
||||
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
|
||||
fixture.setEnvironment(t)
|
||||
fixture.generateModelProjection(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
exitCode := run(context.Background(), []string{"--installation", fixture.installationPath, "pi", "update", "--version", "0.81.0", "--source", "build"}, &stdout, &stderr)
|
||||
@@ -1095,6 +1097,7 @@ func TestRunPiUpdateRequiresExplicitConfirmationWithoutInvokingDocker(t *testing
|
||||
func TestRunPiRestartRequiresExplicitConfirmationWithoutInvokingDocker(t *testing.T) {
|
||||
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
|
||||
fixture.setEnvironment(t)
|
||||
fixture.generateModelProjection(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
exitCode := run(context.Background(), []string{
|
||||
@@ -1117,6 +1120,7 @@ func TestRunPiRestartSanitizesSuccessOutput(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fixture.setEnvironment(t, secretPath)
|
||||
fixture.generateModelProjection(t)
|
||||
t.Setenv("THT_FAKE_PI_VERSION", "pi-restart-secret")
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
@@ -1138,6 +1142,7 @@ func TestRunPiRestartSanitizesSuccessOutput(t *testing.T) {
|
||||
func TestRunPiUpdateAcceptsExplicitVersionWithoutAdvancedFlags(t *testing.T) {
|
||||
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
|
||||
fixture.setEnvironment(t)
|
||||
fixture.generateModelProjection(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
exitCode := run(context.Background(), []string{
|
||||
@@ -1152,6 +1157,21 @@ func TestRunPiUpdateAcceptsExplicitVersionWithoutAdvancedFlags(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunPiRestartRejectsCatalogDriftBeforeInvokingDocker(t *testing.T) {
|
||||
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
|
||||
fixture.setEnvironment(t)
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
exitCode := run(context.Background(), []string{
|
||||
"--installation", fixture.installationPath, "pi", "restart", "--yes",
|
||||
}, &stdout, &stderr)
|
||||
|
||||
if exitCode != 2 || !strings.Contains(stderr.String(), "run tht start") {
|
||||
t.Fatalf("run() = %d, stderr=%q; want complete projection guidance", exitCode, stderr.String())
|
||||
}
|
||||
assertDockerNotInvoked(t, fixture)
|
||||
}
|
||||
|
||||
func TestRunPiMaintenanceStatusAndRecoverConfirmationContract(t *testing.T) {
|
||||
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
|
||||
fixture.setEnvironment(t)
|
||||
|
||||
Reference in New Issue
Block a user