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.
This commit is contained in:
1 parent
dd72793cdb
commit
eb41b991bf
70 files changed
+8182
-358
No files matched your search
@@ -10,6 +10,7 @@ type filePrecondition struct {
|
||||
filePath string
|
||||
label string
|
||||
snapshot *managedFileSnapshot
|
||||
directory os.FileInfo
|
||||
maximumSize int64
|
||||
}
|
||||
|
||||
@@ -38,7 +39,8 @@ func prepareSnapshotSourceChange(
|
||||
if original == nil && (remove || next == nil) {
|
||||
return nil, nil
|
||||
}
|
||||
if original != nil && !remove && bytes.Equal(original.contents, next) {
|
||||
if original != nil && !remove && bytes.Equal(original.contents, next) &&
|
||||
sameManagedFileMode(original.mode, mode) {
|
||||
return nil, nil
|
||||
}
|
||||
change := &fileChange{
|
||||
@@ -51,6 +53,7 @@ func prepareSnapshotSourceChange(
|
||||
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
|
||||
}
|
||||
@@ -62,7 +65,9 @@ func sameManagedSnapshot(current, expected *managedFileSnapshot) bool {
|
||||
return current == expected
|
||||
}
|
||||
return bytes.Equal(current.contents, expected.contents) &&
|
||||
os.SameFile(current.info, expected.info)
|
||||
current.identity == expected.identity &&
|
||||
os.SameFile(current.info, expected.info) &&
|
||||
sameManagedFileMode(current.mode, expected.mode)
|
||||
}
|
||||
|
||||
func assertFilePreconditions(
|
||||
@@ -70,6 +75,27 @@ func assertFilePreconditions(
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user