Add web auth, infinite-scroll, agent admission and review fixes across agent/server/web

This commit is contained in:
Stanislav Rossovskii
2026-05-28 23:45:12 +04:00
parent 37b1a1d6d6
commit 1026e9ebbe
75 changed files with 3021 additions and 916 deletions

View File

@@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"os/exec"
"strconv"
"strings"
"syscall"
"time"
"unicode/utf8"
@@ -14,8 +16,9 @@ import (
var replacementRune = []byte("<22>")
const (
MaxOutputBytes = 8192
truncMarkerFmt = "...[truncated %d bytes]"
MaxOutputBytes = 8192
truncMarkerFmt = "...[truncated %d bytes]"
limitFailPrefix = "__MONLET_RESOURCE_LIMIT_FAILED__:"
)
type Status string
@@ -28,16 +31,41 @@ const (
)
type Result struct {
Status Status
ExitCode int
DurationMs int64
Output string
OutputTruncated bool
Status Status
ExitCode int
DurationMs int64
Output string
OutputTruncated bool
ResourceLimitFailure string
}
// ResourceLimits contains best-effort shell ulimit values for a check command.
type ResourceLimits struct {
CPUTime time.Duration
MemoryBytes int64
OpenFiles int
}
func (l ResourceLimits) IsZero() bool {
return l.CPUTime == 0 && l.MemoryBytes == 0 && l.OpenFiles == 0
}
// Run executes argv with timeout. Stdout+stderr are captured into a single
// buffer; both are truncated to 8 KiB UTF-8 bytes if exceeded.
func Run(ctx context.Context, argv []string, timeout time.Duration) Result {
return runArgv(ctx, argv, timeout)
}
// RunCommand executes a shell command with optional resource limits.
func RunCommand(ctx context.Context, command string, timeout time.Duration, limits ResourceLimits) Result {
argv := []string{"/bin/sh", "-c", command}
if !limits.IsZero() {
argv = limitedShellArgv(command, limits)
}
return runArgv(ctx, argv, timeout)
}
func runArgv(ctx context.Context, argv []string, timeout time.Duration) Result {
start := time.Now()
cctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
@@ -67,6 +95,23 @@ func Run(ctx context.Context, argv []string, timeout time.Duration) Result {
r.Output = fmt.Sprintf("critical: check timed out after %s", timeout)
return r
}
if isExitCode(err, 125) {
if resource, ok := detectLimitFailure(out); ok {
r.Status = StatusUnknown
r.ExitCode = -1
r.Output = "unknown: failed to apply resource limit: " + resource
r.OutputTruncated = false
r.ResourceLimitFailure = resource
return r
}
}
if isSignal(err, syscall.SIGXCPU) {
r.Status = StatusCritical
r.ExitCode = 2
r.Output = "critical: CPU time limit exceeded"
r.OutputTruncated = false
return r
}
if err != nil {
var ee *exec.ExitError
if errors.As(err, &ee) {
@@ -74,6 +119,8 @@ func Run(ctx context.Context, argv []string, timeout time.Duration) Result {
} else {
r.Status = StatusUnknown
r.ExitCode = -1
// Launch failure (e.g. shell missing); surface exec error, never check output.
r.Output, r.OutputTruncated = TruncateUTF8([]byte("unknown: failed to start check: "+err.Error()), MaxOutputBytes)
return r
}
}
@@ -81,6 +128,60 @@ func Run(ctx context.Context, argv []string, timeout time.Duration) Result {
return r
}
func isExitCode(err error, code int) bool {
var ee *exec.ExitError
return errors.As(err, &ee) && ee.ExitCode() == code
}
func limitedShellArgv(command string, limits ResourceLimits) []string {
cpu := ""
if limits.CPUTime > 0 {
cpu = strconv.FormatInt(int64((limits.CPUTime+time.Second-1)/time.Second), 10)
}
mem := ""
if limits.MemoryBytes > 0 {
mem = strconv.FormatInt((limits.MemoryBytes+1023)/1024, 10)
}
openFiles := ""
if limits.OpenFiles > 0 {
openFiles = strconv.Itoa(limits.OpenFiles)
}
script := `
cmd=$1
cpu=$2
mem=$3
open_files=$4
if [ -n "$cpu" ]; then ulimit -t "$cpu" 2>/dev/null || { printf '%s\n' '` + limitFailPrefix + `cpu_time'; exit 125; }; fi
if [ -n "$mem" ]; then ulimit -v "$mem" 2>/dev/null || { printf '%s\n' '` + limitFailPrefix + `memory'; exit 125; }; fi
if [ -n "$open_files" ]; then ulimit -n "$open_files" 2>/dev/null || { printf '%s\n' '` + limitFailPrefix + `open_files'; exit 125; }; fi
exec /bin/sh -c "$cmd"
`
return []string{"/bin/sh", "-c", script, "monlet-limit-wrapper", command, cpu, mem, openFiles}
}
func detectLimitFailure(output string) (string, bool) {
for _, line := range strings.Split(output, "\n") {
line = strings.TrimSpace(line)
if strings.HasPrefix(line, limitFailPrefix) {
resource := strings.TrimPrefix(line, limitFailPrefix)
if resource != "cpu_time" && resource != "memory" && resource != "open_files" {
resource = "unknown"
}
return resource, true
}
}
return "", false
}
func isSignal(err error, sig syscall.Signal) bool {
var ee *exec.ExitError
if !errors.As(err, &ee) {
return false
}
ws, ok := ee.Sys().(syscall.WaitStatus)
return ok && ws.Signaled() && ws.Signal() == sig
}
func MapExit(code int) Status {
switch code {
case 0:

View File

@@ -2,6 +2,7 @@ package runner
import (
"context"
"runtime"
"strings"
"testing"
"time"
@@ -114,3 +115,41 @@ func TestRunNoExec(t *testing.T) {
t.Fatalf("got %+v", r)
}
}
func TestRunCommandWithLimitsOK(t *testing.T) {
r := RunCommand(context.Background(), "echo ok", 2*time.Second, ResourceLimits{
CPUTime: time.Second,
OpenFiles: 64,
})
if r.Status != StatusOK || r.ExitCode != 0 {
t.Fatalf("got %+v", r)
}
if !strings.Contains(r.Output, "ok") {
t.Fatalf("output: %q", r.Output)
}
}
func TestRunCommandCPULimitExceeded(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("ulimit is Unix-only")
}
r := RunCommand(context.Background(), "while :; do :; done", 5*time.Second, ResourceLimits{
CPUTime: time.Second,
})
if r.Status != StatusCritical || r.ExitCode != 2 {
t.Fatalf("got %+v", r)
}
if !strings.Contains(r.Output, "CPU time limit exceeded") {
t.Fatalf("output: %q", r.Output)
}
}
func TestDetectLimitFailureBoundsResourceLabel(t *testing.T) {
resource, ok := detectLimitFailure(limitFailPrefix + "dynamic-user-output")
if !ok {
t.Fatal("expected limit failure")
}
if resource != "unknown" {
t.Fatalf("resource label must be bounded, got %q", resource)
}
}