Repository navigation
Releases
v0.2.1
Docs-only patch. Covers 0.2.0 as well, which was tagged and published to npm but never got a GitHub Release.
0.2.1
- Correct the install docs.
dsh.bundle.patch(added in 0.2.0) makesdsh plugin addjoin the package to the profile's bundle stack on its own, so the README's manualcordis.patch.ymlstep and its note about adeclares no dsh.bundlewarning were both obsolete. Replaced with the upgrade hazard they created: bundle and user patch layers both apply with no id dedup, so a 0.1.x insert entry left behind loads the guard twice.
npm only refreshes a package README on publish, which is why this warranted a release rather than a docs commit.
No source change. 44/44 tests unchanged.
0.2.0
- Close flag-parsing bypasses: last-wins flags, the
--boundary, config mutations, and server overrides - See through wrappers, stop gating bare mentions, widen pseudonyms
- Declare a
dsh.bundlemanifest so the plugin activates as a profile bundle - Include
cordis.patch.ymlin the npm package files - Add the awesome-dsh-plugin badge
Install: dsh plugin --profile web add dsh-kubectl-guard
v0.1.2
Security fix.
Variable indirection could bypass the gate. K=kubectl; $K delete pod foo was allowed through. The opaque-command check that should have caught it was gated behind a binary-mention test whose boundaries missed K=kubectl; — preceded by =, followed by ; — so a $VAR expansion never reached it. Widening the mention test and treating $VAR as opaque were both required; neither alone closes the hole.
The irreversible-verb scan had the same weak boundaries and missed a verb sitting next to a quote, so CMD="kubectl delete"; $CMD pod foo degraded to an ask instead of a denial. Both now deny.
Also in this release:
auth reconcileis tiered as a write;auth can-istays a read.KUBECONFIGsplits onpath.delimiterrather than a hardcoded:.- A test workflow runs on push and pull request.
- The README states the threat model directly: this gates a cooperative agent, not an adversary. Indirection carrying the literal binary name is caught; a name held only in the environment is not, by construction.
30 tests.
v0.1.1
Security fix.
Inline KUBECONFIG could bypass the gate. The matcher stripped a leading KUBECONFIG=... kubectl ... assignment off the command and discarded it, so the context was resolved from the ambient environment instead. A command naming a production kubeconfig inline, run from a shell pointing at a local cluster, was allowed through — including delete. The assignment now overrides the environment the way the shell applies it, in both directions.
Also in this release:
- Guard the
pwshtool. The stock web profile registers it alongsidebash, and it took the samecommandargument, so it was an unguarded path. apply --pruneandreplace --forceare now irreversible. Both delete resources; they previously only asked.
25 tests, including regressions for each.
v0.1.0
First release.
Gates kubectl by kubeconfig context inside DeepSeek Harness:
delete,drain,evict, andscale --replicas=0against a non-local context are denied throughctx.tools.guard(), which no later listener can override.apply,patch,scale,execand friends return{ kind: 'ask' }fromtools/pre-execute, so the harness owns the prompt.- Reads, dry runs, and local contexts pass through untouched.
Deny-by-default on the context: local only if it matches your localContexts globs, and an unreadable kubeconfig counts as production. Unparseable commands are treated as mutations rather than allowed.
Model-facing messages carry a per-session pseudonym (ctx#4be1) instead of your cluster name, so a blocked command does not ship an internal identifier to the LLM provider. Opt out with showContextNames: true.
kubectl only; the verb table is data, so helm and argocd are an edit rather than a rewrite.