1use std::path::PathBuf;
2
3use clap::{Args, CommandFactory, Parser, Subcommand, ValueEnum};
4use clap_complete::Shell;
5
6#[derive(Debug, Clone, Parser)]
7#[command(
8 name = "sbox",
9 version,
10 about = "Policy-driven sandboxed command runner"
11)]
12pub struct Cli {
13 #[arg(long, global = true)]
14 pub config: Option<PathBuf>,
15
16 #[arg(long, global = true)]
17 pub workspace: Option<PathBuf>,
18
19 #[arg(long, global = true, value_enum)]
20 pub backend: Option<CliBackendKind>,
21
22 #[arg(long, global = true)]
23 pub image: Option<String>,
24
25 #[arg(long, global = true)]
26 pub profile: Option<String>,
27
28 #[arg(long, global = true, value_enum)]
29 pub mode: Option<CliExecutionMode>,
30
31 #[arg(short = 'v', long, global = true, action = clap::ArgAction::Count)]
32 pub verbose: u8,
33
34 #[arg(long, global = true)]
35 pub quiet: bool,
36
37 #[arg(long, global = true)]
38 pub strict_security: bool,
39
40 #[command(subcommand)]
41 pub command: Commands,
42}
43
44#[derive(Debug, Clone, Subcommand)]
45pub enum Commands {
46 Init(InitCommand),
47 Run(RunCommand),
48 Exec(ExecCommand),
49 Shell(ShellCommand),
50 Plan(PlanCommand),
51 Doctor(DoctorCommand),
52 Clean(CleanCommand),
53 Shim(ShimCommand),
54 Bootstrap(BootstrapCommand),
55 Audit(AuditCommand),
56 Completions(CompletionsCommand),
57}
58
59#[derive(Debug, Clone, Args)]
60pub struct InitCommand {
61 #[arg(long)]
62 pub force: bool,
63
64 #[arg(long)]
65 pub preset: Option<String>,
66
67 #[arg(long)]
68 pub output: Option<PathBuf>,
69
70 #[arg(long, short = 'i')]
72 pub interactive: bool,
73
74 #[arg(long, conflicts_with_all = ["preset", "interactive"])]
77 pub from_lockfile: bool,
78}
79
80#[derive(Debug, Clone, Args)]
81#[command(trailing_var_arg = true)]
82pub struct RunCommand {
83 #[arg(long)]
85 pub dry_run: bool,
86
87 #[arg(short = 'e', long = "env", value_name = "NAME=VALUE")]
89 pub env: Vec<String>,
90
91 #[arg(required = true, num_args = 1.., allow_hyphen_values = true)]
92 pub command: Vec<String>,
93}
94
95#[derive(Debug, Clone, Args)]
96#[command(trailing_var_arg = true)]
97pub struct ExecCommand {
98 pub profile: String,
99
100 #[arg(required = true, num_args = 1.., allow_hyphen_values = true)]
101 pub command: Vec<String>,
102}
103
104#[derive(Debug, Clone, Args, Default)]
105pub struct ShellCommand {
106 #[arg(long)]
107 pub shell: Option<String>,
108}
109
110#[derive(Debug, Clone, Args)]
111#[command(trailing_var_arg = true)]
112pub struct PlanCommand {
113 #[arg(long)]
114 pub show_command: bool,
115
116 #[arg(long)]
118 pub audit: bool,
119
120 #[arg(num_args = 0.., allow_hyphen_values = true)]
122 pub command: Vec<String>,
123}
124
125#[derive(Debug, Clone, Args, Default)]
126pub struct DoctorCommand {
127 #[arg(long)]
128 pub strict: bool,
129}
130
131#[derive(Debug, Clone, Args, Default)]
132pub struct CleanCommand {
133 #[arg(long)]
134 pub sessions: bool,
135
136 #[arg(long)]
137 pub images: bool,
138
139 #[arg(long)]
140 pub caches: bool,
141
142 #[arg(long)]
143 pub all: bool,
144
145 #[arg(long = "global")]
146 pub global_scope: bool,
147}
148
149#[derive(Debug, Clone, Copy, ValueEnum)]
150pub enum CliBackendKind {
151 Podman,
152 Docker,
153}
154
155#[derive(Debug, Clone, Copy, ValueEnum)]
156pub enum CliExecutionMode {
157 Host,
158 Sandbox,
159}
160
161#[derive(Debug, Clone, Args, Default)]
165pub struct AuditCommand {
166 #[arg(num_args = 0.., allow_hyphen_values = true)]
168 pub extra_args: Vec<String>,
169}
170
171#[derive(Debug, Clone, Args, Default)]
175pub struct BootstrapCommand {}
176
177#[derive(Debug, Clone, Args)]
182pub struct CompletionsCommand {
183 pub shell: Shell,
184}
185
186pub fn generate_completions(shell: Shell) {
187 use std::io;
188 clap_complete::generate(shell, &mut Cli::command(), "sbox", &mut io::stdout());
189}
190
191#[derive(Debug, Clone, Args)]
192pub struct ShimCommand {
193 #[arg(long)]
195 pub dir: Option<PathBuf>,
196
197 #[arg(long)]
199 pub force: bool,
200
201 #[arg(long)]
203 pub dry_run: bool,
204
205 #[arg(long)]
207 pub verify: bool,
208}