Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/EXTENSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ Extensions receive pup's auth credentials via environment variables. This means
| `DD_SITE` | Always | Datadog site (e.g., `datadoghq.com`) |
| `DD_ORG` | Org is specified | Named org session |
| `PUP_OUTPUT` | Always | Output format (`json`, `table`, `yaml`, `csv`, `tsv`) |
| `PUP_FILTER` | `--jq` flag is set | The jq expression, verbatim |
| `PUP_AUTO_APPROVE` | `--yes` flag or agent mode | `true` |
| `PUP_READ_ONLY` | Read-only mode | `true` |
| `PUP_AGENT_MODE` | Agent mode | `true` |
Expand All @@ -118,7 +119,7 @@ Pup refreshes the OAuth2 token if needed before passing it to the extension, so

Variables not active in the current session are explicitly removed from the child environment to prevent stale credentials from leaking through the parent shell.

The `PUP_OUTPUT`, `PUP_AGENT_MODE`, `PUP_READ_ONLY`, and `PUP_AUTO_APPROVE` variables are read back by a child `pup` process. So if your extension shells out to `pup` (see below), those nested calls automatically inherit the format and mode the user selected on the parent command.
The `PUP_OUTPUT`, `PUP_FILTER`, `PUP_AGENT_MODE`, `PUP_READ_ONLY`, and `PUP_AUTO_APPROVE` variables are read back by a child `pup` process. So if your extension shells out to `pup` (see below), those nested calls automatically inherit the format, `--jq` filter, and mode the user selected on the parent command. An extension that prints its own JSON directly — rather than delegating to a nested `pup` call — still needs to read `PUP_FILTER` itself and apply the jq expression if it wants to honor `--jq`.

### Example: using auth in a Python extension

Expand Down
15 changes: 14 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,10 @@ impl Config {
|| env_bool("DD_CLI_READ_ONLY")
|| env_bool("PUP_READ_ONLY")
|| file_cfg.read_only.unwrap_or(false),
jq: None, // set by caller from --jq flag
// `PUP_FILTER` is injected into extension subprocesses (like
// `PUP_OUTPUT` above) so a child `pup` call inherits the parent's
// --jq expression; an explicit --jq flag still overrides it.
jq: env_or("PUP_FILTER", None),
};

Ok(cfg)
Expand Down Expand Up @@ -1665,6 +1668,7 @@ mod tests {
"DD_AUTO_APPROVE",
"DD_CLI_AUTO_APPROVE",
"PUP_AUTO_APPROVE",
"PUP_FILTER",
] {
std::env::remove_var(var);
}
Expand All @@ -1681,6 +1685,15 @@ mod tests {
std::env::remove_var("DD_OUTPUT");
std::env::remove_var("PUP_OUTPUT");

// PUP_FILTER drives cfg.jq so a nested `pup` call spawned by an extension
// (e.g. `pup api` invoked from inside a `pup-<ext>` process) inherits the
// outer --jq expression, the same way it inherits --output.
assert_eq!(Config::from_env().unwrap().jq, None);
std::env::set_var("PUP_FILTER", ".[] | .id");
let cfg = Config::from_env().unwrap();
assert_eq!(cfg.jq.as_deref(), Some(".[] | .id"));
std::env::remove_var("PUP_FILTER");

// PUP_READ_ONLY / PUP_AUTO_APPROVE flip the mode flags.
std::env::set_var("PUP_READ_ONLY", "true");
std::env::set_var("PUP_AUTO_APPROVE", "true");
Expand Down
Loading