Export document reading with Remote lease safeguards
This commit is contained in:
1 parent
228271b43b
commit
622d2f96a1
11 files changed
+299
-17
No files matched your search
@@ -296,7 +296,14 @@ func (session *Session) remote_call_locked(method string, params json.RawMessage
|
||||
if method == "remote.close" && request.Epoch <= session.remoteEpoch && (access == nil || access.epoch != request.Epoch) {
|
||||
return struct{}{}, nil
|
||||
}
|
||||
if access == nil || access.lease == "" || access.lease != request.Lease || access.epoch != request.Epoch || request.Sequence <= access.sequence || !time.Now().Before(access.deadline) || access.ctx.Err() != nil {
|
||||
if access == nil || access.lease == "" || access.lease != request.Lease || access.epoch != request.Epoch || request.Sequence <= access.sequence {
|
||||
return nil, denied
|
||||
}
|
||||
// Closing only removes authority. Allow authenticated cleanup even
|
||||
// before the expiry/policy callback acquires this lock; rejecting it
|
||||
// would make the child permanently distrust an otherwise healthy IPC
|
||||
// session. Heartbeats must never renew that cancelled authority.
|
||||
if method == "remote.heartbeat" && (!time.Now().Before(access.deadline) || access.ctx.Err() != nil) {
|
||||
return nil, denied
|
||||
}
|
||||
access.sequence = request.Sequence
|
||||
|
||||
@@ -4,13 +4,56 @@
|
||||
package tentacle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/cthulhu/internal/tentaclewire"
|
||||
)
|
||||
|
||||
func TestRemoteCloseBeforeRetirementCallback(t *testing.T) {
|
||||
for _, state := range []string{"expired", "cancelled"} {
|
||||
t.Run(state, func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(t.Context())
|
||||
defer cancel()
|
||||
access := &remoteAccess{lease: strings.Repeat("a", 32), epoch: 1,
|
||||
ctx: ctx, cancel: cancel, deadline: time.Now().Add(time.Minute)}
|
||||
if state == "expired" {
|
||||
access.deadline = time.Now().Add(-time.Second)
|
||||
} else {
|
||||
cancel()
|
||||
}
|
||||
manager := &Manager{}
|
||||
session := &Session{manager: manager, remote: access, remoteEpoch: 1,
|
||||
outbound: make(chan outgoing, 4)}
|
||||
manager.remoteOwner = session
|
||||
operation := tentaclewire.RemoteOperation{Lease: access.lease, Epoch: 1, Sequence: 1}
|
||||
data, _ := json.Marshal(operation)
|
||||
if _, failure := session.remote_call_locked("remote.heartbeat", data); failure == nil {
|
||||
t.Fatal("heartbeat revived retired authority")
|
||||
}
|
||||
wrong := operation
|
||||
wrong.Lease = strings.Repeat("b", 32)
|
||||
invalid, _ := json.Marshal(wrong)
|
||||
if _, failure := session.remote_call_locked("remote.close", invalid); failure == nil {
|
||||
t.Fatal("foreign token closed pending retirement")
|
||||
}
|
||||
if _, failure := session.remote_call_locked("remote.close", data); failure != nil {
|
||||
t.Fatal("cleanup rejected before retirement callback", failure)
|
||||
}
|
||||
if session.remote != nil || manager.remoteOwner != nil {
|
||||
t.Fatal("close retained remote ownership")
|
||||
}
|
||||
if _, failure := session.remote_call_locked("remote.close", data); failure != nil {
|
||||
t.Fatal("repeated cleanup failed", failure)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemotePolicyRevokesPendingAndLiveSDKAccess(t *testing.T) {
|
||||
for _, language := range []string{"go", "python"} {
|
||||
t.Run(language, func(t *testing.T) {
|
||||
|
||||
Reference in new issue
Block a user