Compare commits
4
Commits
7bbd911365
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41a90a10fb | ||
|
|
5f0dec5270 | ||
|
|
fe8b9a3ec0 | ||
|
|
72d85eb9ec |
@@ -0,0 +1,2 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
@@ -78,6 +78,14 @@ Already have a clone? Just run it directly:
|
|||||||
`~/.local/bin`. Persists across redeploys; only rebuilt when the venv is
|
`~/.local/bin`. Persists across redeploys; only rebuilt when the venv is
|
||||||
missing or broken. Building it may install `python3`/`python3-venv` via
|
missing or broken. Building it may install `python3`/`python3-venv` via
|
||||||
the system package manager (the one place this module uses sudo).
|
the system package manager (the one place this module uses sudo).
|
||||||
|
- `vscode/` — installs Visual Studio Code from upstream's portable tarball into
|
||||||
|
`~/.local/opt/vscode`, symlinks `code` into `~/.local/bin`, and writes a
|
||||||
|
user-level `.desktop` entry so it shows up in the application menu. **No
|
||||||
|
sudo, nothing outside `$HOME`** — the same contract as `bin/`, so it survives
|
||||||
|
a Kasm redeploy. Pinned via `VSCODE_VERSION` in the module; bump it to upgrade.
|
||||||
|
Also sets `password-store: basic` in `~/.vscode/argv.json` so KDE's kwallet
|
||||||
|
does not prompt for an unlock on every launch (see below). **No-ops on
|
||||||
|
headless hosts** — it's a ~400MB GUI app — override with `DOTFILES_VSCODE`.
|
||||||
- `docker-rootless-cgroup/` — on systemd-less hosts (e.g. Kasm), hand-delegates
|
- `docker-rootless-cgroup/` — on systemd-less hosts (e.g. Kasm), hand-delegates
|
||||||
cgroup v2 controllers to the rootless Docker daemon so per-container cgroups
|
cgroup v2 controllers to the rootless Docker daemon so per-container cgroups
|
||||||
work (rootless Docker otherwise comes up with
|
work (rootless Docker otherwise comes up with
|
||||||
@@ -111,6 +119,18 @@ item instead of `~/.zshrc.local`:
|
|||||||
don't set this by hand: run `mcp-config/install.sh` once and its shell
|
don't set this by hand: run `mcp-config/install.sh` once and its shell
|
||||||
hook exports it from `~/.config/mcp-sync/key`. Set it in `~/.zshrc.local`
|
hook exports it from `~/.config/mcp-sync/key`. Set it in `~/.zshrc.local`
|
||||||
only on a box without mcp-sync.
|
only on a box without mcp-sync.
|
||||||
|
- `DOTFILES_VSCODE` — controls the `vscode/` module. Unset (default) installs
|
||||||
|
VS Code only when a graphical session is detected; `1` forces the install on
|
||||||
|
a headless host (e.g. for `code tunnel`); `0` skips it everywhere. A plain
|
||||||
|
shell/env var, not a vault secret.
|
||||||
|
|
||||||
|
On the keyring: VS Code's secret storage reaches for the OS keyring through
|
||||||
|
libsecret, which on KDE makes kwalletd prompt for an unlock before the editor
|
||||||
|
is usable — every session, since `kwallet-pam` is not installed. The module
|
||||||
|
sets `"password-store": "basic"` in `~/.vscode/argv.json` to stop that, which
|
||||||
|
means VS Code's stored tokens are obfuscated on disk rather than sealed
|
||||||
|
behind a wallet password. To use the wallet instead, install `kwallet-pam` so
|
||||||
|
it unlocks at login, then change that value to `"kwallet5"`.
|
||||||
- `OP_SERVICE_ACCOUNT_TOKEN` — 1Password service-account token. Not a shell
|
- `OP_SERVICE_ACCOUNT_TOKEN` — 1Password service-account token. Not a shell
|
||||||
variable any more: `secrets/install.sh` asks for it once and stores it in
|
variable any more: `secrets/install.sh` asks for it once and stores it in
|
||||||
`~/.config/dotfiles/op.env`. Pass it in the env only for an unattended run.
|
`~/.config/dotfiles/op.env`. Pass it in the env only for an unattended run.
|
||||||
|
|||||||
@@ -124,6 +124,10 @@ else
|
|||||||
run_module hermes
|
run_module hermes
|
||||||
fi
|
fi
|
||||||
run_module ansible
|
run_module ansible
|
||||||
|
# GUI editor, installed from upstream's tarball into ~/.local/opt (no sudo, same
|
||||||
|
# contract as bin/). No ordering constraints — it needs nothing from bin/,
|
||||||
|
# secrets/ or node/ — and no-ops on headless hosts.
|
||||||
|
run_module vscode
|
||||||
# Runs last: needs rootless Docker already up (started at boot) so it can
|
# Runs last: needs rootless Docker already up (started at boot) so it can
|
||||||
# delegate cgroups to it. No-ops where that does not apply.
|
# delegate cgroups to it. No-ops where that does not apply.
|
||||||
run_module docker-rootless-cgroup
|
run_module docker-rootless-cgroup
|
||||||
|
|||||||
Binary file not shown.
+30
-2
@@ -8,8 +8,8 @@
|
|||||||
# reset.
|
# reset.
|
||||||
#
|
#
|
||||||
# Source this (callers already run `set -eu`), then use fetch_arch /
|
# Source this (callers already run `set -eu`), then use fetch_arch /
|
||||||
# fetch_arch_deb, have_version + mark_version, install_tarball_bin, and
|
# fetch_arch_deb, have_version + mark_version, install_tarball_bin,
|
||||||
# install_raw_bin.
|
# install_tarball_tree, and install_raw_bin.
|
||||||
|
|
||||||
BIN_DIR="${BIN_DIR:-$HOME/.local/bin}"
|
BIN_DIR="${BIN_DIR:-$HOME/.local/bin}"
|
||||||
VERSION_DIR="$BIN_DIR/.versions"
|
VERSION_DIR="$BIN_DIR/.versions"
|
||||||
@@ -93,6 +93,34 @@ install_zip_bin() {
|
|||||||
fsay "installed $BIN_DIR/$3"
|
fsay "installed $BIN_DIR/$3"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# install_tarball_tree <url> <root-within-archive> <dest-dir> — download a
|
||||||
|
# .tar.gz that holds a whole application directory rather than one binary, and
|
||||||
|
# swap it into <dest-dir>. install_tarball_bin cannot be reused here: VS Code
|
||||||
|
# is an Electron bundle of thousands of files that only runs from an intact
|
||||||
|
# tree, not a single binary that can be picked out of the archive.
|
||||||
|
#
|
||||||
|
# The new tree is staged beside the target and moved into place only once the
|
||||||
|
# download and extraction have both succeeded, so an interrupted run leaves the
|
||||||
|
# previously installed version intact instead of a half-extracted directory.
|
||||||
|
install_tarball_tree() {
|
||||||
|
_dest="$3"
|
||||||
|
_tmp="$(mktemp -d)"
|
||||||
|
_fetch_dl "$1" "$_tmp/archive.tar.gz"
|
||||||
|
tar -xzf "$_tmp/archive.tar.gz" -C "$_tmp"
|
||||||
|
if [ ! -d "$_tmp/$2" ]; then
|
||||||
|
fsay "fetch: '$2' not found in archive"; rm -rf "$_tmp"; return 1
|
||||||
|
fi
|
||||||
|
mkdir -p "$(dirname "$_dest")"
|
||||||
|
rm -rf "$_dest.new" "$_dest.old"
|
||||||
|
mv "$_tmp/$2" "$_dest.new"
|
||||||
|
if [ -e "$_dest" ]; then
|
||||||
|
mv "$_dest" "$_dest.old"
|
||||||
|
fi
|
||||||
|
mv "$_dest.new" "$_dest"
|
||||||
|
rm -rf "$_dest.old" "$_tmp"
|
||||||
|
fsay "installed $_dest"
|
||||||
|
}
|
||||||
|
|
||||||
# install_raw_bin <url> <dest-name> — download a single raw binary.
|
# install_raw_bin <url> <dest-name> — download a single raw binary.
|
||||||
install_raw_bin() {
|
install_raw_bin() {
|
||||||
mkdir -p "$BIN_DIR"
|
mkdir -p "$BIN_DIR"
|
||||||
|
|||||||
Executable
+216
@@ -0,0 +1,216 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# vscode/install.sh — install Visual Studio Code into ~/.local/opt/vscode.
|
||||||
|
#
|
||||||
|
# WHY: VS Code is the one GUI app this repo installs, and the obvious way to get
|
||||||
|
# it — Microsoft's rpm/deb repo — needs root, writes outside $HOME, and is wiped
|
||||||
|
# by a Kasm redeploy, so the editor quietly disappears on every rebuild. The box
|
||||||
|
# this was written for had exactly that half-state: /etc/yum.repos.d/vscode.repo
|
||||||
|
# present, `code` never installed, and nothing in this repo recording that VS
|
||||||
|
# Code was meant to be there at all. Upstream's portable tarball is the same
|
||||||
|
# build with none of that: everything lands under $HOME, no sudo, and it
|
||||||
|
# survives a redeploy. The only thing given up is dnf/apt-driven updates, which
|
||||||
|
# is what the pinned VSCODE_VERSION below replaces.
|
||||||
|
#
|
||||||
|
# It is not in bin/install.sh because that script installs single self-contained
|
||||||
|
# binaries; VS Code is an Electron tree of thousands of files plus a menu entry
|
||||||
|
# and an icon. It follows node/ and ansible/ instead: unpack under ~/.local/opt
|
||||||
|
# and symlink the CLI into ~/.local/bin.
|
||||||
|
#
|
||||||
|
# The Chromium sandbox still works from a userland install: the bundled
|
||||||
|
# chrome-sandbox helper is not setuid here, so Electron falls back to the
|
||||||
|
# unprivileged user-namespace sandbox. That needs user namespaces enabled
|
||||||
|
# (user.max_user_namespaces > 0, the default on every distro this repo targets).
|
||||||
|
# Verified by launching without --no-sandbox. Nothing is given up for dropping
|
||||||
|
# root; if a host ever has userns disabled, VS Code says so on startup.
|
||||||
|
#
|
||||||
|
# Idempotent and safe to re-run. To upgrade, bump VSCODE_VERSION.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||||
|
REPO_ROOT="$(dirname -- "$SCRIPT_DIR")"
|
||||||
|
|
||||||
|
# shellcheck source=../lib/fetch.sh
|
||||||
|
. "$REPO_ROOT/lib/fetch.sh"
|
||||||
|
|
||||||
|
say() { printf '%s\n' "$*" >&2; }
|
||||||
|
|
||||||
|
# Pinned deliberately. VS Code auto-updates itself on other platforms; a tarball
|
||||||
|
# install does not, which is the point — the editor runs your code and holds
|
||||||
|
# your Git and extension credentials, so the version is a supply-chain decision
|
||||||
|
# rather than whatever upstream served today. `code --version` prints this
|
||||||
|
# string verbatim, so it must match with no leading "v".
|
||||||
|
VSCODE_VERSION="1.139.0"
|
||||||
|
|
||||||
|
PREFIX="$HOME/.local/opt/vscode"
|
||||||
|
DESKTOP_DIR="$HOME/.local/share/applications"
|
||||||
|
ARGV_JSON="$HOME/.vscode/argv.json"
|
||||||
|
|
||||||
|
# has_desktop — true when this host has a graphical session to run a GUI editor
|
||||||
|
# in. VS Code is ~400MB unpacked and $HOME is the thing that persists across
|
||||||
|
# redeploys, so it is not worth carrying on a box that will never display it.
|
||||||
|
# Desktop images ship session files under /usr/share/{x,wayland-}sessions.
|
||||||
|
has_desktop() {
|
||||||
|
[ -n "${XDG_CURRENT_DESKTOP:-}" ] && return 0
|
||||||
|
for d in /usr/share/xsessions /usr/share/wayland-sessions; do
|
||||||
|
[ -d "$d" ] && [ -n "$(ls -A "$d" 2>/dev/null)" ] && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- skip on headless hosts --------------------------------------------------
|
||||||
|
# DOTFILES_VSCODE=1 forces the install anyway (e.g. for `code tunnel` on a
|
||||||
|
# server); DOTFILES_VSCODE=0 skips it even on a desktop.
|
||||||
|
case "${DOTFILES_VSCODE:-auto}" in
|
||||||
|
0) say "vscode: DOTFILES_VSCODE=0; skipping."; exit 0 ;;
|
||||||
|
1) ;;
|
||||||
|
*) if ! has_desktop; then
|
||||||
|
say "vscode: no graphical session detected; skipping (DOTFILES_VSCODE=1 to force)."
|
||||||
|
exit 0
|
||||||
|
fi ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Upstream keys its download URLs on x64/arm64 rather than amd64/arm64.
|
||||||
|
case "$(fetch_arch)" in
|
||||||
|
x86_64) VSCODE_ARCH=x64 ;;
|
||||||
|
aarch64) VSCODE_ARCH=arm64 ;;
|
||||||
|
*) say "vscode: unsupported arch $(fetch_arch)"; exit 1 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- install the app tree ----------------------------------------------------
|
||||||
|
# Verify it RUNS, not just that the tree exists: a Kasm redeploy can leave a
|
||||||
|
# present-but-broken directory behind (the same failure node/ and ansible/
|
||||||
|
# guard against).
|
||||||
|
#
|
||||||
|
# The root fallback is not optional. Run as root, `code --version` refuses --
|
||||||
|
# it prints "You are trying to start Visual Studio Code as a super user"
|
||||||
|
# instead of the version, and still exits 0 -- so a bare run-check never
|
||||||
|
# matches and would re-download 325MB on every single bootstrap, silently.
|
||||||
|
# That is the forced-install path (DOTFILES_VSCODE=1 in a container or on a
|
||||||
|
# server), so for root only, fall back to the recorded version stamp.
|
||||||
|
installed_version="$("$PREFIX/bin/code" --version 2>/dev/null | head -1 || true)"
|
||||||
|
if [ "$installed_version" = "$VSCODE_VERSION" ]; then
|
||||||
|
say "vscode: $VSCODE_VERSION already present at $PREFIX."
|
||||||
|
elif [ "$(id -u)" = "0" ] && have_version code "$VSCODE_VERSION"; then
|
||||||
|
say "vscode: $VSCODE_VERSION already present at $PREFIX (stamped; root cannot query --version)."
|
||||||
|
else
|
||||||
|
say "vscode: installing $VSCODE_VERSION into $PREFIX (this is a ~325MB download)..."
|
||||||
|
install_tarball_tree \
|
||||||
|
"https://update.code.visualstudio.com/$VSCODE_VERSION/linux-$VSCODE_ARCH/stable" \
|
||||||
|
"VSCode-linux-$VSCODE_ARCH" "$PREFIX"
|
||||||
|
|
||||||
|
# bin/code is upstream's CLI wrapper (`code .`, `code --install-extension`);
|
||||||
|
# the Electron binary at the tree root is what the menu entry launches.
|
||||||
|
mkdir -p "$BIN_DIR"
|
||||||
|
ln -sf "$PREFIX/bin/code" "$BIN_DIR/code"
|
||||||
|
mark_version code "$VSCODE_VERSION"
|
||||||
|
say "vscode: installed $VSCODE_VERSION and linked $BIN_DIR/code."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- menu entry --------------------------------------------------------------
|
||||||
|
# Icon= is an absolute path rather than a theme name: the bundled icon is a
|
||||||
|
# single 1024x1024 PNG and hicolor tops out at 512x512, so there is no correct
|
||||||
|
# themed directory to drop it in. The spec allows an absolute path, and it needs
|
||||||
|
# no icon-cache rebuild to take effect.
|
||||||
|
mkdir -p "$DESKTOP_DIR"
|
||||||
|
cat >"$DESKTOP_DIR/code.desktop" <<DESKTOP
|
||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
Name=Visual Studio Code
|
||||||
|
GenericName=Text Editor
|
||||||
|
Comment=Code Editing. Redefined.
|
||||||
|
Exec=$PREFIX/code %F
|
||||||
|
Icon=$PREFIX/resources/app/resources/linux/code.png
|
||||||
|
Terminal=false
|
||||||
|
StartupNotify=true
|
||||||
|
StartupWMClass=Code
|
||||||
|
Categories=TextEditor;Development;IDE;
|
||||||
|
MimeType=text/plain;inode/directory;
|
||||||
|
Keywords=vscode;editor;
|
||||||
|
Actions=new-window;
|
||||||
|
|
||||||
|
[Desktop Action new-window]
|
||||||
|
Name=New Empty Window
|
||||||
|
Exec=$PREFIX/code --new-window %F
|
||||||
|
Icon=$PREFIX/resources/app/resources/linux/code.png
|
||||||
|
DESKTOP
|
||||||
|
say "vscode: wrote $DESKTOP_DIR/code.desktop"
|
||||||
|
|
||||||
|
# Refresh the per-user menu caches so the entry appears without a re-login.
|
||||||
|
if command -v update-desktop-database >/dev/null 2>&1; then
|
||||||
|
update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
if command -v kbuildsycoca5 >/dev/null 2>&1; then
|
||||||
|
kbuildsycoca5 --noincremental >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- keyring prompt suppression ----------------------------------------------
|
||||||
|
# WHY: on first launch Electron's safeStorage reaches for the OS keyring through
|
||||||
|
# libsecret. On a KDE session that wakes kwalletd, which pops an unlock/create
|
||||||
|
# dialog before the editor is usable -- and since kwallet-pam is not installed
|
||||||
|
# on these hosts, nothing unlocks the wallet at login, so it prompts every
|
||||||
|
# session. "basic" keeps VS Code's secrets in its own store and never reaches
|
||||||
|
# for the wallet at all. Verified with dbus-monitor: no org.kde.KWallet traffic
|
||||||
|
# on launch.
|
||||||
|
#
|
||||||
|
# TRADE-OFF: basic is weaker than a real keyring. Secrets VS Code stores (Git
|
||||||
|
# and GitHub auth tokens, extension credentials) end up obfuscated on disk
|
||||||
|
# rather than sealed behind a wallet password. To move to the wallet later,
|
||||||
|
# install kwallet-pam so it unlocks at login, then change the value to
|
||||||
|
# "kwallet5" and restart VS Code.
|
||||||
|
#
|
||||||
|
# The path comes from product.json's dataFolderName (".vscode"), NOT the
|
||||||
|
# user-data-dir: argv.json lives at ~/.vscode/argv.json and a copy written
|
||||||
|
# anywhere else is read by nothing and silently ignored.
|
||||||
|
if [ ! -e "$ARGV_JSON" ]; then
|
||||||
|
mkdir -p "$(dirname "$ARGV_JSON")"
|
||||||
|
cat >"$ARGV_JSON" <<'ARGV'
|
||||||
|
// Runtime arguments for VS Code. See dotfiles vscode/install.sh.
|
||||||
|
{
|
||||||
|
// Keep secrets in VS Code's own store rather than the OS keyring, so KDE's
|
||||||
|
// kwallet does not prompt for an unlock on every launch.
|
||||||
|
"password-store": "basic"
|
||||||
|
}
|
||||||
|
ARGV
|
||||||
|
say "vscode: wrote $ARGV_JSON (password-store=basic)"
|
||||||
|
elif grep -q '"password-store"' "$ARGV_JSON"; then
|
||||||
|
say "vscode: $ARGV_JSON already sets password-store; leaving it alone."
|
||||||
|
else
|
||||||
|
# Merge rather than overwrite: this file is JSON-with-comments that VS Code
|
||||||
|
# and the user both own, and it carries a crash-reporter-id that should
|
||||||
|
# survive. Insert the key after the opening brace and keep the rest byte for
|
||||||
|
# byte.
|
||||||
|
cp -p "$ARGV_JSON" "$ARGV_JSON.bak"
|
||||||
|
if awk '
|
||||||
|
BEGIN { done = 0 }
|
||||||
|
{
|
||||||
|
print
|
||||||
|
if (!done && $0 ~ /^[[:space:]]*\{[[:space:]]*$/) {
|
||||||
|
print "\t// Added by dotfiles vscode/install.sh: keep secrets in VS Code'"'"'s"
|
||||||
|
print "\t// own store so kwallet does not prompt for an unlock on every launch."
|
||||||
|
print "\t\"password-store\": \"basic\","
|
||||||
|
done = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
END { exit(done ? 0 : 1) }
|
||||||
|
' "$ARGV_JSON.bak" >"$ARGV_JSON.new"; then
|
||||||
|
mv "$ARGV_JSON.new" "$ARGV_JSON"
|
||||||
|
say "vscode: set password-store=basic in $ARGV_JSON (backup: $ARGV_JSON.bak)"
|
||||||
|
else
|
||||||
|
rm -f "$ARGV_JSON.new"
|
||||||
|
say "vscode: WARNING: could not find the object opening in $ARGV_JSON."
|
||||||
|
say " Add '\"password-store\": \"basic\"' by hand to stop the keyring prompt."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# A system-wide VS Code (from Microsoft's rpm/deb repo) shadows this one in the
|
||||||
|
# menu and shows a duplicate entry. Flag it rather than touching it -- removing
|
||||||
|
# it needs the root this module deliberately avoids.
|
||||||
|
if [ -e /usr/share/applications/com.microsoft.VSCode.desktop ]; then
|
||||||
|
say ""
|
||||||
|
say "vscode: NOTE: a system-wide VS Code package is also installed."
|
||||||
|
say " You will see two menu entries until it is removed:"
|
||||||
|
say " sudo dnf remove code # or: sudo apt remove code"
|
||||||
|
say ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
say "vscode: ready."
|
||||||
@@ -69,9 +69,10 @@ _DOTFILES_CONF="$HOME/.config/dotfiles"
|
|||||||
[ -f "$_DOTFILES_CONF/secrets.env" ] && source "$_DOTFILES_CONF/secrets.env"
|
[ -f "$_DOTFILES_CONF/secrets.env" ] && source "$_DOTFILES_CONF/secrets.env"
|
||||||
|
|
||||||
# opr NAME read one field straight from the vault
|
# opr NAME read one field straight from the vault
|
||||||
# opc NAME [VALUE] create or update a field (prompts, hidden, when VALUE is
|
# opc NAME=VALUE create or update a field, then refresh and reload this
|
||||||
# omitted, which keeps the secret out of shell history),
|
# opc NAME shell; with no VALUE (NAME or NAME=) it prompts, hidden,
|
||||||
# then refresh and reload this shell
|
# which keeps the secret out of shell history.
|
||||||
|
# `opc NAME VALUE` also still works.
|
||||||
# opd NAME delete a field, refresh, and unset it in this shell
|
# opd NAME delete a field, refresh, and unset it in this shell
|
||||||
# opl [VAULT [ITEM]] show every field and its current value (default: your
|
# opl [VAULT [ITEM]] show every field and its current value (default: your
|
||||||
# vault and item from op.env)
|
# vault and item from op.env)
|
||||||
@@ -94,19 +95,47 @@ opr() {
|
|||||||
opc() {
|
opc() {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
local name=$1 value
|
local name=$1 value
|
||||||
_dotfiles_env_name "$name" opc || return
|
if [[ $1 == *=* ]]; then
|
||||||
if (( $# >= 2 )); then
|
# NAME=VALUE: split on the first '=' so values may contain '='
|
||||||
|
name=${1%%=*} value=${1#*=}
|
||||||
|
elif (( $# >= 2 )); then
|
||||||
value=$2
|
value=$2
|
||||||
else
|
fi
|
||||||
|
_dotfiles_env_name "$name" opc || return
|
||||||
|
if [[ -z $value ]]; then
|
||||||
read -rs "value?$name: " && print
|
read -rs "value?$name: " && print
|
||||||
|
[[ -n $value ]] || { print -u2 "opc: empty value for $name; nothing changed"; return 1; }
|
||||||
fi
|
fi
|
||||||
# [concealed] makes it a password field; an existing field of that name is updated.
|
# [concealed] makes it a password field; an existing field of that name is updated.
|
||||||
_dotfiles_op sh -c 'op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[concealed]=$2" >/dev/null' \
|
# op can exit non-zero with "(404) Not Found" after an edit it did save (seen with
|
||||||
opc "$name" "$value" && ops
|
# op 2.34.1 and 2.39.0), so its exit code is ignored: the field is read back instead.
|
||||||
|
_dotfiles_op sh -c '
|
||||||
|
clean() { printf "%s" "${1:-(no output)}" | sed "s/^\[ERROR\] [0-9/]* [0-9:]* //"; }
|
||||||
|
ref="op://$OP_VAULT/$OP_ITEM/$1"
|
||||||
|
err=$(op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[concealed]=$2" 2>&1 >/dev/null)
|
||||||
|
if [ "$(op read "$ref" 2>/dev/null)" = "$2" ]; then
|
||||||
|
printf "opc: saved %s\n" "$ref" >&2
|
||||||
|
else
|
||||||
|
printf "opc: could not save %s\n op said: %s\n check vault, item and service-account write access with: opl\n" \
|
||||||
|
"$ref" "$(clean "$err")" >&2
|
||||||
|
exit 1
|
||||||
|
fi' opc "$name" "$value" && ops
|
||||||
}
|
}
|
||||||
opd() {
|
opd() {
|
||||||
_dotfiles_env_name "$1" opd || return
|
_dotfiles_env_name "$1" opd || return
|
||||||
_dotfiles_op sh -c 'op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[delete]" >/dev/null' opd "$1" \
|
# As in opc, op's exit code is unreliable here: check the item's field labels instead.
|
||||||
|
_dotfiles_op sh -c '
|
||||||
|
clean() { printf "%s" "${1:-(no output)}" | sed "s/^\[ERROR\] [0-9/]* [0-9:]* //"; }
|
||||||
|
ref="op://$OP_VAULT/$OP_ITEM/$1"
|
||||||
|
err=$(op item edit "$OP_ITEM" --vault "$OP_VAULT" "$1[delete]" 2>&1 >/dev/null)
|
||||||
|
if ! item=$(op item get "$OP_ITEM" --vault "$OP_VAULT" --format json 2>&1); then
|
||||||
|
printf "opd: could not re-read %s to confirm the delete\n op said: %s\n" "$ref" "$(clean "$item")" >&2
|
||||||
|
exit 1
|
||||||
|
elif printf "%s" "$item" | jq -r ".fields[].label" | grep -qxF "$1"; then
|
||||||
|
printf "opd: could not delete %s\n op said: %s\n" "$ref" "$(clean "$err")" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
printf "opd: deleted %s\n" "$ref" >&2' opd "$1" \
|
||||||
&& unset "$1" && ops
|
&& unset "$1" && ops
|
||||||
}
|
}
|
||||||
opl() {
|
opl() {
|
||||||
|
|||||||
Reference in New Issue
Block a user