Files
Elydora-Go-SDK/cmd/elydora/plugins/transaction_precondition.go
T
ZacharyZhang-NY eb41b991bf feat(go): durable transaction engine and Kiro IDE 1.0 adapter
Split the monolithic transaction into focused modules: append-only
crash-recoverable journal under ~/.elydora/transactions with owner
tokens and per-transaction namespaces, staged atomic publication
(stage .pending, fsync, rename, fsync), platform-specific atomic
replacement (MoveFileEx, renameat2, renamex_np), private-directory
hardening per OS, lock-guarded recovery, and workspace cleanup that
removes only transaction-created empty directories.

Add the Kiro IDE 1.0 plugin: strict v1 hook schema with one enabled
PreToolUse guard and PostToolUse audit pair bound to the active
workspace, agent-to-workspace identity binding in runtime config, and
exact migration of the legacy elydora-audit.kiro.hook contract.

Gates: go test ./... and -race pass, go vet clean, govulncheck reports
zero reachable vulnerabilities, git diff --check clean.
2026-07-21 19:02:57 -04:00

122 lines
2.7 KiB
Go

package plugins
import (
"bytes"
"fmt"
"os"
)
type filePrecondition struct {
filePath string
label string
snapshot *managedFileSnapshot
directory os.FileInfo
maximumSize int64
}
func prepareSnapshotSourceChange(
filePath, label string,
original *managedFileSnapshot,
next []byte,
mode os.FileMode,
remove bool,
) (*fileChange, error) {
if !remove && int64(len(next)) > maxManagedSourceBytes {
return nil, fmt.Errorf(
"%s exceeds %d bytes: %s",
label,
maxManagedSourceBytes,
filePath,
)
}
current, err := readManagedFile(filePath, label, maxManagedSourceBytes)
if err != nil {
return nil, err
}
if !sameManagedSnapshot(current, original) {
return nil, fmt.Errorf("%s changed before update: %s", label, filePath)
}
if original == nil && (remove || next == nil) {
return nil, nil
}
if original != nil && !remove && bytes.Equal(original.contents, next) &&
sameManagedFileMode(original.mode, mode) {
return nil, nil
}
change := &fileChange{
filePath: filePath,
label: label,
next: append([]byte(nil), next...),
mode: mode,
remove: remove,
}
if original != nil {
change.original = append([]byte(nil), original.contents...)
change.originalInfo = original.info
change.originalID = original.identity
change.originalMode = original.mode
change.existed = true
}
return change, nil
}
func sameManagedSnapshot(current, expected *managedFileSnapshot) bool {
if current == nil || expected == nil {
return current == expected
}
return bytes.Equal(current.contents, expected.contents) &&
current.identity == expected.identity &&
os.SameFile(current.info, expected.info) &&
sameManagedFileMode(current.mode, expected.mode)
}
func assertFilePreconditions(
preconditions []filePrecondition,
operation string,
) error {
for _, condition := range preconditions {
if condition.directory != nil {
current, err := os.Lstat(condition.filePath)
if err != nil {
return fmt.Errorf(
"inspect %s at %s: %w",
condition.label,
condition.filePath,
err,
)
}
if current.Mode()&os.ModeSymlink != 0 || !current.IsDir() ||
!os.SameFile(condition.directory, current) {
return fmt.Errorf(
"%s changed during %s: %s",
condition.label,
operation,
condition.filePath,
)
}
continue
}
maximumSize := condition.maximumSize
if maximumSize <= 0 {
maximumSize = maxManagedSourceBytes
}
current, err := readManagedFile(
condition.filePath,
condition.label,
maximumSize,
)
if err != nil {
return err
}
if !sameManagedSnapshot(current, condition.snapshot) {
return fmt.Errorf(
"%s changed during %s: %s",
condition.label,
operation,
condition.filePath,
)
}
}
return nil
}