Files
2026-09-27 16:04:02 -06:00

150 lines
4.1 KiB
Go

package policy
import (
"strings"
"testing"
"time"
)
func TestNoBlockGivesDefaults(t *testing.T) {
// Ejemplos sueltos en el texto NO deben conceder permisos.
md := "# Agente\n\nEjemplo: EXECUTION_MODE=unrestricted\n\n```text\nALLOW_DELETE=true\n```\n"
p, err := Parse(md)
if err != nil {
t.Fatalf("Parse: %v", err)
}
if p.Declared {
t.Error("Declared should be false")
}
if p.Mode != ModeGuarded {
t.Errorf("Mode = %s, want guarded", p.Mode)
}
for _, c := range AllCapabilities {
if p.Allows(c) {
t.Errorf("%s must default to false", c)
}
}
if !p.BackupBeforeSystemEdit {
t.Error("BACKUP_BEFORE_SYSTEM_EDIT must default to true")
}
if p.DefaultCommandTimeout != 60*time.Second {
t.Errorf("timeout = %v", p.DefaultCommandTimeout)
}
}
func TestPolicyBlock(t *testing.T) {
md := strings.Join([]string{
"# Identidad",
"",
"```policy",
"# comentario",
"EXECUTION_MODE=privileged",
"ALLOW_NETWORK=true",
"ALLOW_DELETE=false",
"BACKUP_BEFORE_SYSTEM_EDIT=false",
"DEFAULT_COMMAND_TIMEOUT=120",
"TASK_ORDER=02-b.md, 01-a.md",
"SOMETHING_NEW=1",
"```",
"",
}, "\n")
p, err := Parse(md)
if err != nil {
t.Fatalf("Parse: %v", err)
}
if !p.Declared || p.Mode != ModePrivileged {
t.Fatalf("Declared=%v Mode=%s", p.Declared, p.Mode)
}
if !p.Allows(CapNetwork) || p.Allows(CapDelete) {
t.Error("capabilities not applied correctly")
}
if p.Allows(CapReboot) {
t.Error("undeclared ALLOW_REBOOT must be false")
}
if p.BackupBeforeSystemEdit {
t.Error("backup should be false")
}
if p.DefaultCommandTimeout != 120*time.Second {
t.Errorf("timeout = %v", p.DefaultCommandTimeout)
}
if strings.Join(p.TaskOrder, "|") != "02-b.md|01-a.md" {
t.Errorf("TaskOrder = %v", p.TaskOrder)
}
if len(p.Unknown) != 1 || p.Unknown[0] != "SOMETHING_NEW" {
t.Errorf("Unknown = %v", p.Unknown)
}
}
func TestUnrestrictedOnlyWhenExplicit(t *testing.T) {
p, err := Parse("```policy\nEXECUTION_MODE=unrestricted\n```\n")
if err != nil {
t.Fatal(err)
}
if p.Mode != ModeUnrestricted {
t.Errorf("Mode = %s", p.Mode)
}
// Incluso unrestricted no concede capacidades no declaradas.
if p.Allows(CapReboot) {
t.Error("unrestricted must not imply ALLOW_REBOOT")
}
}
func TestPolicyInsideOtherFenceIsIgnored(t *testing.T) {
// Un "```policy" dentro de un bloque ```` (4 backticks) es solo texto.
md := "````markdown\n```policy\nEXECUTION_MODE=unrestricted\n```\n````\n"
p, err := Parse(md)
if err != nil {
t.Fatal(err)
}
if p.Declared || p.Mode != ModeGuarded {
t.Errorf("nested example must be ignored: Declared=%v Mode=%s", p.Declared, p.Mode)
}
}
func TestParseErrors(t *testing.T) {
cases := map[string]string{
"two blocks": "```policy\nALLOW_NETWORK=true\n```\n```policy\nALLOW_DELETE=true\n```\n",
"bad mode": "```policy\nEXECUTION_MODE=god\n```\n",
"bad bool": "```policy\nALLOW_DELETE=maybe\n```\n",
"duplicate": "```policy\nALLOW_DELETE=false\nALLOW_DELETE=true\n```\n",
"no equals": "```policy\nALLOW_DELETE\n```\n",
"bad timeout": "```policy\nDEFAULT_COMMAND_TIMEOUT=0\n```\n",
"unterminated": "```policy\nALLOW_DELETE=true\n",
}
for name, md := range cases {
if _, err := Parse(md); err == nil {
t.Errorf("%s: expected error", name)
}
}
}
func TestMaxSteps(t *testing.T) {
p, _ := Parse("")
if p.MaxSteps != 40 {
t.Errorf("default MaxSteps = %d", p.MaxSteps)
}
p, err := Parse("```policy\nMAX_STEPS=12\n```\n")
if err != nil || p.MaxSteps != 12 {
t.Fatalf("%v %v", p, err)
}
if _, err := Parse("```policy\nMAX_STEPS=0\n```\n"); err == nil {
t.Error("MAX_STEPS=0 must fail")
}
}
func TestMaxDownloadSize(t *testing.T) {
p, _ := Parse("")
if p.MaxDownloadSize != 1<<30 {
t.Errorf("default = %d", p.MaxDownloadSize)
}
for in, want := range map[string]int64{"1048576": 1 << 20, "512M": 512 << 20, "2G": 2 << 30, "10KB": 10 << 10} {
p, err := Parse("```policy\nMAX_DOWNLOAD_SIZE=" + in + "\n```\n")
if err != nil || p.MaxDownloadSize != want {
t.Errorf("%s: %d %v", in, p.MaxDownloadSize, err)
}
}
if _, err := Parse("```policy\nMAX_DOWNLOAD_SIZE=lots\n```\n"); err == nil {
t.Error("invalid size must fail")
}
}