File size: 3,013 Bytes
f909af8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6f6baad
f909af8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
"""
Data models for the ForensicShell OpenEnv environment.

ForensicShell simulates a pre-seeded "breached" Linux box. The agent investigates
via structured read-only actions (list_dir, read_file, grep, stat) and ultimately
submits a ForensicReport. A deterministic grader scores the report against hidden
ground truth per task (easy/medium/hard).
"""

from typing import List, Literal, Optional

from openenv.core.env_server.types import Action, Observation
from pydantic import BaseModel, Field


class TimelineEvent(BaseModel):
    """One step in the attacker's kill chain (used in hard task)."""

    phase: Literal["login", "recon", "privesc", "persistence", "exfil"]
    detail: str = Field(default="", description="Short description of the event")


class ForensicReport(BaseModel):
    """The agent's final investigation report. Submitted via action_type='submit_report'."""

    compromised_user: Optional[str] = Field(
        default=None, description="Username of the compromised account"
    )
    initial_ip: Optional[str] = Field(
        default=None, description="Source IP of the initial login"
    )
    modified_files: List[str] = Field(
        default_factory=list,
        description="Absolute paths of files modified after compromise",
    )
    backdoor_sha256: Optional[str] = Field(
        default=None,
        description="SHA256 of the attacker-dropped backdoor binary (lowercase hex)",
    )
    timeline: List[TimelineEvent] = Field(
        default_factory=list,
        description="Ordered attacker kill chain (login→recon→privesc→persistence→exfil)",
    )


class ForensicShellAction(Action):
    """Agent action. Use action_type to pick the verb; set only the fields that verb needs."""

    action_type: Literal[
        "list_dir", "read_file", "grep", "stat", "find", "submit_report"
    ] = Field(..., description="Which verb to execute")
    path: Optional[str] = Field(
        default=None, description="Target path for list_dir / read_file / grep / stat"
    )
    pattern: Optional[str] = Field(
        default=None, description="Substring pattern for grep"
    )
    max_bytes: int = Field(
        default=2048, description="Max bytes to return from read_file (truncated)"
    )
    report: Optional[ForensicReport] = Field(
        default=None, description="Investigation report (only for action_type='submit_report')"
    )


class ForensicShellObservation(Observation):
    """Result of the agent's last action."""

    output: str = Field(default="", description="Human-readable result of the action")
    task_id: str = Field(default="", description="Current task identifier")
    task_description: str = Field(
        default="", description="What the agent is being asked to investigate"
    )
    steps_remaining: int = Field(
        default=0, description="How many more actions allowed this episode"
    )
    action_error: Optional[str] = Field(
        default=None, description="Error message if the action failed; None otherwise"
    )