cli/commands/env.rs
1use clap::{Args, Subcommand};
2use std::{ffi::OsString, path::PathBuf};
3
4#[derive(Subcommand, Debug)]
5pub enum EnvCommands {
6 /// List all env variables
7 List {
8 /// Show sensitive values instead of redacting them
9 #[arg(long)]
10 reveal: bool,
11 },
12 /// Set a variable in config.toml [env]
13 Set {
14 /// Variable name (e.g. HTTP_PROXY_PORT)
15 key: String,
16 /// Variable value
17 value: String,
18 /// Write directly into the env override file that currently shadows this
19 /// key (global/overlay/project shine.env.toml) instead of refusing
20 #[arg(long)]
21 force: bool,
22 },
23 /// Delete a variable from config.toml [env]
24 Delete {
25 /// Variable name
26 key: String,
27 /// Delete directly from the env override file that currently shadows
28 /// this key (global/overlay/project shine.env.toml) instead of refusing
29 #[arg(long)]
30 force: bool,
31 },
32 /// Get a single variable value
33 Get {
34 /// Variable name
35 key: String,
36 },
37 /// Run a command with the workspace environment
38 Run(EnvRunCommand),
39 /// Encrypt, decrypt, export, and manage secret identities
40 Secret(EnvSecretCommand),
41}
42
43#[derive(Args, Debug)]
44pub struct EnvSecretCommand {
45 #[command(subcommand)]
46 pub command: EnvSecretSubcommand,
47}
48
49#[derive(Subcommand, Debug)]
50pub enum EnvSecretSubcommand {
51 /// Decode and decrypt an encrypted secret from [env] (GPG or age)
52 Decrypt {
53 /// Variable name containing encrypted ciphertext
54 key: String,
55 },
56 /// Decrypt KEY_SECRET and print shell code that exports KEY
57 Export {
58 /// Variable name to export from KEY_SECRET
59 key: String,
60 /// Export under a different name in the current shell
61 #[arg(long = "as", value_name = "ALIAS")]
62 alias: Option<String>,
63 },
64 /// Encrypt stdin and print ciphertext (GPG by default, or age with --backend age)
65 Encrypt(EnvEncryptCommand),
66 /// Seal pending secrets in workspace environment files
67 Seal(EnvSealCommand),
68 /// Manage age identities used to decrypt age-backed secrets
69 Identity(EnvIdentityCommand),
70}
71
72#[derive(Args, Debug)]
73pub struct EnvEncryptCommand {
74 /// Secret backend to use: "gpg" (default) or "age"
75 #[arg(long)]
76 pub backend: Option<String>,
77 /// Recipient (repeatable): GPG key ID/fingerprint/email, or age recipient
78 #[arg(short = 'r', long = "recipient")]
79 pub recipients: Vec<String>,
80 /// Store the encrypted ciphertext in config.toml [env] instead of printing it
81 #[arg(long)]
82 pub set: Option<String>,
83 /// Read plaintext from an existing config.toml [env] variable instead of stdin
84 #[arg(long)]
85 pub from: Option<String>,
86 /// Write directly into the env override file that currently shadows the
87 /// target key (global/overlay/project shine.env.toml) instead of refusing
88 #[arg(long)]
89 pub force: bool,
90}
91
92#[derive(Args, Debug)]
93pub struct EnvSealCommand {
94 /// Seal only this environment source file
95 #[arg(value_name = "FILE")]
96 pub file: Option<PathBuf>,
97 /// Workspace definition (defaults to the nearest shine.workspace.toml)
98 #[arg(long, value_name = "FILE")]
99 pub workspace: Option<PathBuf>,
100 /// Secret backend to use: "gpg" (default) or "age"
101 #[arg(long)]
102 pub backend: Option<String>,
103 /// Recipient (repeatable): GPG key ID/fingerprint/email, or age recipient
104 #[arg(short = 'r', long = "recipient")]
105 pub recipients: Vec<String>,
106}
107
108#[derive(Args, Debug)]
109pub struct EnvIdentityCommand {
110 #[command(subcommand)]
111 pub command: EnvIdentitySubcommand,
112}
113
114#[derive(Subcommand, Debug)]
115pub enum EnvIdentitySubcommand {
116 /// Generate a new age identity, optionally backed by Touch ID (Secure Enclave)
117 Init {
118 /// Generate a Secure Enclave identity requiring Touch ID (macOS only)
119 #[arg(long)]
120 touch_id: bool,
121 /// Secure Enclave access control policy (only with --touch-id): any-biometry
122 /// (default), any-biometry-or-passcode, current-biometry, or passcode
123 #[arg(long, value_name = "POLICY")]
124 access_control: Option<String>,
125 /// Output path (defaults to <shine_dir>/age/identity.txt)
126 #[arg(short = 'o', long, value_name = "PATH")]
127 output: Option<PathBuf>,
128 /// Overwrite an existing identity file
129 #[arg(long)]
130 force: bool,
131 },
132 /// Print the recipient(s) for the configured identity file(s)
133 List,
134}
135
136#[derive(Args, Debug)]
137pub struct EnvRunCommand {
138 /// Workspace definition (defaults to the nearest shine.workspace.toml)
139 #[arg(long, value_name = "FILE")]
140 pub workspace: Option<PathBuf>,
141 /// Environment mode used to expand {mode} paths
142 #[arg(long)]
143 pub mode: Option<String>,
144 /// Skip workspace discovery entirely; use only --with values and inherited env
145 #[arg(long, conflicts_with_all = ["workspace", "mode"])]
146 pub no_workspace: bool,
147 /// Inject a config [env] value as KEY or KEY=ALIAS (repeatable)
148 #[arg(long = "with", value_name = "KEY[=ALIAS]")]
149 pub with: Vec<String>,
150 /// Command and arguments to run
151 #[arg(required = true, trailing_var_arg = true, allow_hyphen_values = true)]
152 pub command: Vec<OsString>,
153}