150 lines
4.1 KiB
Go
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")
|
|
}
|
|
}
|