Skip to main content

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}