Files
Elydora-Go-SDK/cmd/elydora/plugins/kiroide_transaction_test.go
T
雷电芽衣 96489cd051 chore(go): audit providers kirocli kiroide opencode
Move Kiro IDE onto managed_runtime.go and shell_command.go, share
cloneJSONObject across providers, make OpenCode status verify the managed
runtime contract instead of any hook.js, propagate script removal errors,
and build the legacy runtime config through buildManagedRuntimeConfig.

Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
2026-09-03 02:32:20 -04:00

381 lines
14 KiB
Go

package plugins
import (
"bytes"
"encoding/base64"
"errors"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
func TestKiroIdeRollbackRestoresRuntimeWorkspaceAndLegacySources(t *testing.T) {
original := `{"version":"v1","owner":"workspace","hooks":[]}`
fixture := prepareKiroIdeFixture(t, &original, nil)
writeKiroIdeJSON(
t,
fixture.legacyPath,
legacyKiroIdeGoDocument(fixture, kiroIdeTestAgentID),
)
fixture.plugin.rename = func(source, destination string) error {
if sameManagedPath(source, fixture.legacyPath) &&
strings.HasSuffix(destination, ".rollback") {
return errors.New("injected Kiro IDE legacy cleanup failure")
}
return os.Rename(source, destination)
}
err := fixture.plugin.Install(fixture.config)
if err == nil || !strings.Contains(err.Error(), "injected Kiro IDE legacy cleanup failure") {
t.Fatalf("install error = %v", err)
}
actual, readErr := os.ReadFile(fixture.configPath)
if readErr != nil || string(actual) != original {
t.Fatalf("workspace source after rollback = %q, %v", actual, readErr)
}
if _, err := os.Lstat(fixture.legacyPath); err != nil {
t.Fatalf("legacy source was not restored: %v", err)
}
assertNoKiroIdeRuntimeFiles(t, fixture)
assertNoKiroIdeTransactionArtifacts(t, fixture.homeDir)
assertNoKiroIdeTransactionArtifacts(t, fixture.workspace)
}
func TestKiroIdePreparedInstallProtectsUnchangedSources(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
if err := fixture.plugin.Install(fixture.config); err != nil {
t.Fatalf("install Kiro IDE hooks: %v", err)
}
if err := os.WriteFile(fixture.guardPath, []byte("repair me\n"), 0700); err != nil {
t.Fatalf("damage guard runtime: %v", err)
}
prepared := prepareKiroIdeInstallForTest(t, fixture)
concurrent := `{"version":"v1","owner":"concurrent","hooks":[]}`
if err := os.WriteFile(fixture.configPath, []byte(concurrent), 0600); err != nil {
t.Fatalf("write concurrent workspace source: %v", err)
}
err := commitKiroIdeInstallation(prepared, nil)
if err == nil || !strings.Contains(err.Error(), "changed during Kiro IDE installation") {
t.Fatalf("prepared install error = %v", err)
}
actual, readErr := os.ReadFile(fixture.configPath)
if readErr != nil || string(actual) != concurrent {
t.Fatalf("concurrent workspace source changed: %q, %v", actual, readErr)
}
guard, readErr := os.ReadFile(fixture.guardPath)
if readErr != nil || string(guard) != "repair me\n" {
t.Fatalf("runtime changed after source race: %q, %v", guard, readErr)
}
assertNoKiroIdeTransactionArtifacts(t, fixture.homeDir)
assertNoKiroIdeTransactionArtifacts(t, fixture.workspace)
}
func TestKiroIdeInstallRepairsRuntimeModesOnPOSIX(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("POSIX file modes are unavailable on Windows")
}
fixture := prepareKiroIdeFixture(t, nil, nil)
if err := fixture.plugin.Install(fixture.config); err != nil {
t.Fatalf("install Kiro IDE hooks: %v", err)
}
files := []struct {
path string
drift os.FileMode
want os.FileMode
}{
{fixture.runtimeConfig, 0644, 0600},
{fixture.privateKey, 0644, 0600},
{fixture.guardPath, 0600, 0700},
{fixture.auditPath, 0600, 0700},
}
for _, file := range files {
if err := os.Chmod(file.path, file.drift); err != nil {
t.Fatalf("drift runtime mode at %s: %v", file.path, err)
}
}
status, err := fixture.plugin.Status()
if err != nil || status.Installed || !status.HookConfigured {
t.Fatalf("mode-drifted Kiro IDE status = %#v, %v", status, err)
}
if err := fixture.plugin.Install(fixture.config); err != nil {
t.Fatalf("repair Kiro IDE runtime modes: %v", err)
}
for _, file := range files {
info, err := os.Stat(file.path)
if err != nil || info.Mode().Perm() != file.want {
t.Fatalf("runtime mode at %s = %v, %v", file.path, infoMode(info), err)
}
}
status, err = fixture.plugin.Status()
if err != nil || !status.Installed || !status.HookConfigured {
t.Fatalf("repaired Kiro IDE status = %#v, %v", status, err)
}
}
func TestKiroIdePreparedInstallDetectsConcurrentModeChangesOnPOSIX(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("POSIX file modes are unavailable on Windows")
}
t.Run("changed private key", func(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
if err := fixture.plugin.Install(fixture.config); err != nil {
t.Fatalf("install Kiro IDE hooks: %v", err)
}
fixture.config.PrivateKey = base64.RawURLEncoding.EncodeToString(
bytes.Repeat([]byte{12}, 32),
)
prepared := prepareKiroIdeInstallForTest(t, fixture)
if err := os.Chmod(fixture.privateKey, 0644); err != nil {
t.Fatalf("concurrently chmod private key: %v", err)
}
err := commitKiroIdeInstallation(prepared, nil)
if err == nil || !strings.Contains(err.Error(), "private key changed during installation") {
t.Fatalf("concurrent private key mode error = %v", err)
}
key, readErr := os.ReadFile(fixture.privateKey)
if readErr != nil || string(key) != kiroIdePrivateKey {
t.Fatalf("private key changed after mode race: %q, %v", key, readErr)
}
info, statErr := os.Stat(fixture.privateKey)
if statErr != nil || info.Mode().Perm() != 0644 {
t.Fatalf("private key mode after race = %v, %v", infoMode(info), statErr)
}
assertNoKiroIdeTransactionArtifacts(t, fixture.homeDir)
})
t.Run("unchanged runtime config", func(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
if err := fixture.plugin.Install(fixture.config); err != nil {
t.Fatalf("install Kiro IDE hooks: %v", err)
}
if err := os.WriteFile(fixture.guardPath, []byte("repair me\n"), 0700); err != nil {
t.Fatalf("damage guard runtime: %v", err)
}
prepared := prepareKiroIdeInstallForTest(t, fixture)
if err := os.Chmod(fixture.runtimeConfig, 0644); err != nil {
t.Fatalf("concurrently chmod runtime config: %v", err)
}
err := commitKiroIdeInstallation(prepared, nil)
if err == nil || !strings.Contains(err.Error(), "runtime config changed during Kiro IDE installation") {
t.Fatalf("concurrent runtime config mode error = %v", err)
}
guard, readErr := os.ReadFile(fixture.guardPath)
if readErr != nil || string(guard) != "repair me\n" {
t.Fatalf("guard changed after mode race: %q, %v", guard, readErr)
}
assertNoKiroIdeTransactionArtifacts(t, fixture.homeDir)
})
}
func infoMode(info os.FileInfo) os.FileMode {
if info == nil {
return 0
}
return info.Mode().Perm()
}
func TestKiroIdePreparedInstallRejectsFreshWorkspaceDirectoryReplacement(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
prepared := prepareKiroIdeInstallForTest(t, fixture)
external := filepath.Join(filepath.Dir(fixture.homeDir), "external-workspace")
if err := os.MkdirAll(external, 0700); err != nil {
t.Fatalf("create external workspace directory: %v", err)
}
if err := os.Symlink(external, filepath.Join(fixture.workspace, ".kiro")); err != nil {
t.Skipf("directory symbolic links unavailable: %v", err)
}
err := commitKiroIdeInstallation(prepared, nil)
if err == nil || !strings.Contains(err.Error(), "changed during Kiro IDE installation") {
t.Fatalf("workspace replacement error = %v", err)
}
if _, err := os.Lstat(filepath.Join(external, "hooks", kiroIdeConfigFile)); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("external workspace received hooks: %v", err)
}
assertNoKiroIdeRuntimeFiles(t, fixture)
}
func TestKiroIdePreparedInstallRejectsFreshRuntimeDirectoryReplacements(t *testing.T) {
for _, target := range []string{"root", "agent"} {
t.Run(target, func(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
runtimeRoot := filepath.Join(fixture.homeDir, ".elydora")
if target == "agent" {
if err := os.Mkdir(runtimeRoot, 0700); err != nil {
t.Fatalf("create physical runtime root: %v", err)
}
}
prepared := prepareKiroIdeInstallForTest(t, fixture)
external := filepath.Join(filepath.Dir(fixture.homeDir), "external-runtime-"+target)
if err := os.MkdirAll(external, 0700); err != nil {
t.Fatalf("create external runtime directory: %v", err)
}
linkPath := runtimeRoot
if target == "agent" {
linkPath = fixture.agentDir
}
if err := os.Symlink(external, linkPath); err != nil {
t.Skipf("directory symbolic links unavailable: %v", err)
}
err := commitKiroIdeInstallation(prepared, nil)
if err == nil || !strings.Contains(err.Error(), "changed during Kiro IDE installation") {
t.Fatalf("runtime %s replacement error = %v", target, err)
}
if _, err := os.Lstat(filepath.Join(external, "private.key")); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("external runtime received private key: %v", err)
}
if _, err := os.Lstat(filepath.Join(external, kiroIdeGuardScript)); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("external runtime received guard: %v", err)
}
})
}
}
func TestKiroIdePreparedInstallRejectsExistingWorkspaceIdentityReplacement(t *testing.T) {
source := `{"version":"v1","owner":"workspace","hooks":[]}`
fixture := prepareKiroIdeFixture(t, &source, nil)
prepared := prepareKiroIdeInstallForTest(t, fixture)
kiroDirectory := filepath.Join(fixture.workspace, ".kiro")
backup := kiroDirectory + ".original"
external := filepath.Join(filepath.Dir(fixture.homeDir), "external-existing-workspace")
if err := os.MkdirAll(filepath.Join(external, "hooks"), 0700); err != nil {
t.Fatalf("create external hooks directory: %v", err)
}
if err := os.WriteFile(
filepath.Join(external, "hooks", kiroIdeConfigFile),
[]byte(source),
0600,
); err != nil {
t.Fatalf("write external matching source: %v", err)
}
if err := os.Rename(kiroDirectory, backup); err != nil {
t.Fatalf("move physical Kiro directory: %v", err)
}
if err := os.Symlink(external, kiroDirectory); err != nil {
_ = os.Rename(backup, kiroDirectory)
t.Skipf("directory symbolic links unavailable: %v", err)
}
err := commitKiroIdeInstallation(prepared, nil)
if err == nil || !strings.Contains(err.Error(), "changed during Kiro IDE installation") {
t.Fatalf("existing workspace replacement error = %v", err)
}
actual, readErr := os.ReadFile(filepath.Join(external, "hooks", kiroIdeConfigFile))
if readErr != nil || string(actual) != source {
t.Fatalf("external matching source changed: %q, %v", actual, readErr)
}
assertNoKiroIdeRuntimeFiles(t, fixture)
}
func TestKiroIdeRejectsFileAndDirectoryLinksBeforeRuntimeWrites(t *testing.T) {
for _, kind := range []string{"workspace-config", "workspace-directory", "runtime-directory"} {
t.Run(kind, func(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
external := filepath.Join(filepath.Dir(fixture.homeDir), "external-"+kind)
if kind == "workspace-config" {
if err := os.MkdirAll(filepath.Dir(fixture.configPath), 0700); err != nil {
t.Fatalf("create hooks directory: %v", err)
}
if err := os.WriteFile(external, []byte(`{"version":"v1","hooks":[]}`), 0600); err != nil {
t.Fatalf("write external config: %v", err)
}
if err := os.Symlink(external, fixture.configPath); err != nil {
t.Skipf("file symbolic links unavailable: %v", err)
}
} else {
if err := os.MkdirAll(external, 0700); err != nil {
t.Fatalf("create external directory: %v", err)
}
linkPath := filepath.Join(fixture.workspace, ".kiro")
if kind == "runtime-directory" {
linkPath = filepath.Join(fixture.homeDir, ".elydora")
}
if err := os.MkdirAll(filepath.Dir(linkPath), 0700); err != nil {
t.Fatalf("create link parent: %v", err)
}
if err := os.Symlink(external, linkPath); err != nil {
t.Skipf("directory symbolic links unavailable: %v", err)
}
}
err := fixture.plugin.Install(fixture.config)
if err == nil || !strings.Contains(err.Error(), "physical") {
t.Fatalf("linked %s error = %v", kind, err)
}
assertNoKiroIdeRuntimeFiles(t, fixture)
})
}
}
func TestKiroIdeInstallSurvivesAdversarialWorkspaceLinkSwap(t *testing.T) {
fixture := prepareKiroIdeFixture(t, nil, nil)
kiroDirectory := filepath.Join(fixture.workspace, ".kiro")
external := filepath.Join(filepath.Dir(fixture.homeDir), "external-link-swap")
probe := filepath.Join(filepath.Dir(fixture.homeDir), "link-probe")
if err := os.MkdirAll(external, 0700); err != nil {
t.Fatalf("create external directory: %v", err)
}
if err := os.Symlink(external, probe); err != nil {
t.Skipf("directory symbolic links unavailable: %v", err)
}
if err := os.Remove(probe); err != nil {
t.Fatalf("remove link probe: %v", err)
}
swapped := false
fixture.plugin.rename = func(source, destination string) error {
if !swapped && sameManagedPath(destination, fixture.configPath) &&
strings.HasSuffix(source, ".tmp") {
swapped = true
backup := kiroDirectory + ".original"
if err := os.Rename(kiroDirectory, backup); err != nil {
return err
}
if err := os.Symlink(external, kiroDirectory); err != nil {
_ = os.Rename(backup, kiroDirectory)
return err
}
renameErr := os.Rename(source, destination)
_ = os.Remove(kiroDirectory)
restoreErr := os.Rename(backup, kiroDirectory)
return errors.Join(renameErr, restoreErr)
}
return os.Rename(source, destination)
}
err := fixture.plugin.Install(fixture.config)
if err == nil || !swapped {
t.Fatalf("link-swap install error = %v, swapped=%v", err, swapped)
}
if _, err := os.Lstat(filepath.Join(external, "hooks", kiroIdeConfigFile)); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("external hook was written during link swap: %v", err)
}
assertNoKiroIdeRuntimeFiles(t, fixture)
assertNoKiroIdeTransactionArtifacts(t, fixture.homeDir)
assertNoKiroIdeTransactionArtifacts(t, fixture.workspace)
}
func TestKiroIdeInstallDetectsConcurrentSourceIdentityReplacement(t *testing.T) {
source := `{"version":"v1","owner":"original","hooks":[]}`
fixture := prepareKiroIdeFixture(t, &source, nil)
mutated := false
fixture.plugin.rename = func(stagedPath, destination string) error {
if !mutated && strings.HasSuffix(stagedPath, ".tmp") {
mutated = true
external := fixture.configPath + ".external"
if err := os.Rename(fixture.configPath, external); err != nil {
return err
}
if err := os.WriteFile(fixture.configPath, []byte(source), 0600); err != nil {
return err
}
}
return os.Rename(stagedPath, destination)
}
err := fixture.plugin.Install(fixture.config)
if err == nil || !strings.Contains(err.Error(), "changed during installation") {
t.Fatalf("concurrent identity error = %v", err)
}
actual, readErr := os.ReadFile(fixture.configPath)
if readErr != nil || string(actual) != source {
t.Fatalf("replacement source changed: %q, %v", actual, readErr)
}
assertNoKiroIdeRuntimeFiles(t, fixture)
assertNoKiroIdeTransactionArtifacts(t, fixture.homeDir)
}