test: cover cursor decoding and script integrity metrics
This commit is contained in:
@@ -1157,8 +1157,10 @@ Use one declared test matrix and the same harness entry points everywhere:
|
||||
native Windows integration suites, plus `smoke`, `idempotency`, `reconnect`,
|
||||
and `retention` E2E scenarios;
|
||||
- release candidates run every E2E scenario, including the resettable
|
||||
interactive Windows VM matrix, Server Core smoke, destructive fault cases,
|
||||
upgrade/recovery, and soak.
|
||||
interactive Windows 10 VM matrix, destructive fault cases, upgrade/recovery,
|
||||
and soak. Server Core, older-build, and ambiguous-multi-session smoke lanes
|
||||
run when their dedicated fixtures are provisioned; they are explicitly
|
||||
deferred compatibility work and do not block the Windows 10 v1 baseline.
|
||||
|
||||
CI allocates a run ID per job, always invokes `collect` after failure, and invokes
|
||||
`reset` in an unconditional finalizer. Upload only the bounded redacted report,
|
||||
|
||||
+5
-3
@@ -286,6 +286,8 @@ execution context. The normal `rvboxtest` console session remains the subject
|
||||
of active-user and elevation tests. See [testing-vm.md](testing-vm.md) for the
|
||||
exact fixture contract.
|
||||
|
||||
The VM is the minimum smoke lane, so native multi-session/ambiguous-session,
|
||||
Server Core, and older-build entries remain explicitly blocked until their own
|
||||
fixtures exist. Their pure selector tests remain mandatory.
|
||||
The VM is the current Windows 10 v1 smoke lane. Native
|
||||
multi-session/ambiguous-session, Server Core, and older-build entries are
|
||||
explicitly deferred compatibility work until their own fixtures exist; they do
|
||||
not block the Windows 10 v1 baseline. Their pure selector tests remain
|
||||
mandatory.
|
||||
|
||||
@@ -72,3 +72,24 @@ func TestCursorInputBounds_BH_CTL_01(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FuzzDecodeCursorBounded_SEC_CTL_02 exercises the token boundary shared by
|
||||
// every cursor-resumable control read. Decode must reject malformed or forged
|
||||
// input without panicking or allocating past its documented token ceiling.
|
||||
func FuzzDecodeCursorBounded_SEC_CTL_02(f *testing.F) {
|
||||
codec, err := NewCursorCodec(bytes.Repeat([]byte{0x42}, 32))
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
filters := HashCursorFilters([]byte("client=host-1\x00streams=stdout"))
|
||||
valid, err := codec.Encode(Cursor{Kind: CursorKindOutput, FilterHash: filters, Position: []byte("event/offset"), SnapshotBoundary: []byte("upper-event")})
|
||||
if err != nil {
|
||||
f.Fatal(err)
|
||||
}
|
||||
for _, seed := range []string{"", "***", valid, strings.Repeat("a", 4096)} {
|
||||
f.Add(seed)
|
||||
}
|
||||
f.Fuzz(func(t *testing.T, token string) {
|
||||
_, _ = codec.Decode(token, CursorKindOutput, filters)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -256,6 +256,7 @@ func (service *Service) RunCommand(ctx context.Context, request *rvboxv1.RunComm
|
||||
descriptor := spec.GetScript()
|
||||
digest := sha256.Sum256(request.GetScriptContent())
|
||||
if descriptor == nil || uint64(len(request.GetScriptContent())) != descriptor.GetSizeBytes() || !bytes.Equal(digest[:], descriptor.GetSha256()) {
|
||||
service.incMetric("script_verification_failure")
|
||||
return nil, controlError(codes.InvalidArgument, rvboxv1.ControlError_INVALID_ARGUMENT, "script_content does not match the script descriptor")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1"
|
||||
"github.com/rvbox/rvbox/internal/agentproto"
|
||||
"github.com/rvbox/rvbox/internal/domain"
|
||||
"github.com/rvbox/rvbox/internal/observability"
|
||||
"github.com/rvbox/rvbox/internal/server/store"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -70,6 +71,8 @@ func TestControlListAndGetViews_HP_CONTROL_01(t *testing.T) {
|
||||
func TestRunCommandRequestIDIdempotencyAndValidation_BH_CONTROL_02(t *testing.T) {
|
||||
service, persistence := newTestService(t)
|
||||
defer persistence.Close()
|
||||
metrics := observability.New()
|
||||
service.metrics = metrics
|
||||
ctx := context.Background()
|
||||
registerControlClient(t, persistence, "win-a", rvboxv1.Platform_PLATFORM_WINDOWS, rvboxv1.ShellType_SHELL_POWERSHELL, 3)
|
||||
issue := fixedIssue(0xa2)
|
||||
@@ -102,6 +105,10 @@ func TestRunCommandRequestIDIdempotencyAndValidation_BH_CONTROL_02(t *testing.T)
|
||||
if _, err := service.RunCommand(ctx, badScript); status.Code(err) != codes.InvalidArgument {
|
||||
t.Fatalf("mismatched script code = %v", status.Code(err))
|
||||
}
|
||||
_, _, counters := metrics.Snapshot()
|
||||
if counters["script_verification_failure"] != 1 {
|
||||
t.Fatalf("script verification metrics = %#v", counters)
|
||||
}
|
||||
badTTL := proto.Clone(request).(*rvboxv1.RunCommandRequest)
|
||||
badTTL.RequestId = fixedIssue(0xa4).String()
|
||||
badTTL.QueueTtl = durationpb.New(-time.Second)
|
||||
|
||||
@@ -182,6 +182,7 @@ tests = [
|
||||
"internal/agentproto/validate_test.go:FuzzDecodeOutputChunkBounded_SEC_PROTO_02",
|
||||
"internal/server/control/jsonrpc_test.go:FuzzDecodeJSONRPCRequestBounded_SEC_CTL_01",
|
||||
"internal/server/store/segment_test.go:FuzzDecodeSegmentRecordDoesNotEscapeBounds",
|
||||
"internal/domain/cursor_test.go:FuzzDecodeCursorBounded_SEC_CTL_02",
|
||||
]
|
||||
|
||||
[[requirements]]
|
||||
|
||||
Reference in New Issue
Block a user