Files
cthulhu/internal/tentacle/remote_policy_test.go

136 lines
5.5 KiB
Go

// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
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) {
manager := test_manager(t, DefaultLimits(), nil)
policy := NewRemotePolicy()
if err := manager.UseRemotePolicy(policy); err != nil {
t.Fatal(err)
}
session := startSessionSDK(t, manager, language, "policy-probe")
if _, err := session.AuthorizeRemote("controlled", []string{"output-observe"}); !errors.Is(err, ErrPermission) {
t.Fatal("fixture authorizer bypassed policy", err)
}
stale, _ := session.BeginRemoteApproval("controlled", []string{"output-observe"})
policy.SetAvailable(false)
if _, err := session.BeginRemoteApproval("controlled", []string{"output-observe"}); !errors.Is(err, ErrPermission) {
t.Fatal("unavailable policy issued ticket", err)
}
policy.SetAvailable(true)
if _, err := session.AuthorizeRemoteWithApproval(stale, "controlled", []string{"output-observe"}); !errors.Is(err, ErrPermission) {
t.Fatal("lock round trip revived ticket", err)
}
foreign := &RemoteApproval{policy: NewRemotePolicy()}
if _, err := session.AuthorizeRemoteWithApproval(foreign, "controlled", []string{"output-observe"}); !errors.Is(err, ErrPermission) {
t.Fatal("foreign ticket accepted", err)
}
for _, opened := range []bool{false, true} {
approval, _ := session.BeginRemoteApproval("controlled", []string{"output-observe"})
action, err := session.AuthorizeRemoteWithApproval(approval, "controlled", []string{"output-observe"})
if err != nil {
t.Fatal(err)
}
if _, err := session.AuthorizeRemoteWithApproval(approval, "controlled", []string{"output-observe"}); !errors.Is(err, ErrPermission) {
t.Fatal("replayed approval", err)
}
invokeSessionSDK(t, session, "event", nil)
var lease tentaclewire.RemoteLease
request := tentaclewire.RemoteOpen{Action: action.Action, Epoch: action.Epoch, Role: action.Role, Grants: action.Grants}
if opened {
value, code := remoteCall(t, session, "remote.open", request)
if code != 0 || json.Unmarshal(value, &lease) != nil {
t.Fatal("open failed", code)
}
}
// Hold the session lock so asynchronous event cleanup cannot run.
// Policy cancellation must already invalidate every delivery context.
session.mutex.Lock()
access := session.remote
policy.SetAvailable(false)
cancelled := access.ctx.Err() != nil
session.mutex.Unlock()
if !cancelled {
t.Fatal("revocation waited for session worker")
}
policy.SetAvailable(true)
if _, code := remoteCall(t, session, "remote.open", request); code != -32001 {
t.Fatal("stale open revived approval", code)
}
if opened {
if _, err := session.RemoteContext(lease, "output-observe"); !errors.Is(err, ErrPermission) {
t.Fatal("delivery survived policy", err)
}
if _, code := remoteCall(t, session, "remote.heartbeat", tentaclewire.RemoteOperation{Lease: lease.Lease, Epoch: lease.Epoch, Sequence: 1}); code != -32001 {
t.Fatal("heartbeat revived lease", code)
}
}
var event tentaclewire.SessionEvent
if json.Unmarshal(invokeSessionSDK(t, session, "event", nil), &event) != nil || event.Kind != "remote.revoked" || event.Epoch != action.Epoch || event.Lease != lease.Lease || (!opened && event.Action != action.Action) {
t.Fatal("revocation event", event)
}
}
// A fresh approval can replace the cancelled epoch even if its
// asynchronous policy callback has not acquired the session lock yet.
fresh, _ := session.BeginRemoteApproval("controlled", []string{"output-observe"})
if _, err := session.AuthorizeRemoteWithApproval(fresh, "controlled", []string{"output-observe"}); err != nil {
t.Fatal("fresh approval failed", err)
}
})
}
}