DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Kubectl Guard — DSH Plugin for DeepSeek Harness
← Plugins
K

dsh-kubectl-guard

Kubectl Guard

A dsh policy plugin that gates kubectl writes by kubeconfig context: hard-deny irreversible verbs outside local clusters, ask for the rest.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:gengwg/dsh-kubectl-guard#68a3a2edc01448a66444a9e10ab987fd63ae38d0
READMECompatibilityVersions

Compatibility and provenance

Kubectl Guard is published as dsh-kubectl-guard and currently resolves to version 0.2.1. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
github
Registry updated
9/13/2026

Versions

0.2.1stable
9/13/2026
0.2.0
stable
9/7/2026
0.1.2stable
9/6/2026

Related plugins

Loading related plugins…

Latest
0.2.1
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
any
License
MIT
Source
github
GitHub
★ 1
Weekly downloads
0
Last push
9/16/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in security-access.

Doctor@linxin666/dsh-doctorTransactional rescue mode for DSH profiles with a supervised launcher, isolated recovery capsule, deterministic repairs, health monitoring, and a local Web recovery consoleMobiledsh-mobileDeepSeek Harness mobile adaptation and secure access plugin, supporting LAN, remote connections, Android App, and mobile browsers.DSCODE@toddzheng024/dscode-bundleA complete DeepSeek coding agent with persistent shell, Ultra collaboration and automatic permission review.Auto Reviewdsh-auto-reviewSecond-model AI auto-review for DeepSeek Harness approval requests: a read-only reviewer subagent decides allow/deny on the approval answerer chain, with fail-closed fallback and full session-log audit.

README

dsh-kubectl-guard

A DeepSeek Harness policy plugin that gates kubectl by kubeconfig context.

Irreversible verbs against a non-local cluster are denied outright. Recoverable writes ask first. Reads and local clusters are untouched.

It registers no tools of its own — it inspects the command argument of shell tool calls, so it covers whatever the agent runs.

Install

Requires pnpm, which dsh plugin shells out to.

From npm:

dsh plugin --profile web add dsh-kubectl-guard

From source, if you want to hack on it:

git clone https://github.com/gengwg/dsh-kubectl-guard
cd dsh-kubectl-guard
dsh plugin --profile web add "$PWD"

Either way, activation is automatic: the package declares dsh.bundle, so dsh plugin add joins it to the profile's bundle stack. Restart dsh to load it.

Upgrading from 0.1.x, which installed as a plain dependency: delete the manual insert entry from ~/.dsh/profiles/<profile>/cordis.patch.yml. Bundle and user patch layers both apply, so leaving it in loads the guard twice.

Examples

Nothing to invoke. Ask the agent to do its normal work; the guard sits in the tool pipeline and inspects the shell command before it runs.

Blocked, with the cluster name replaced by a per-session pseudonym:

> delete the stuck nginx pod

Error: kubectl-guard: 'delete' is irreversible and ctx#4be1f92a is not a local
cluster. Denied.

Asked, so you approve it in the UI before it runs:

> roll out the new deployment

kubectl-guard: 'apply' writes to ctx#4be1f92a, which is not a local cluster.
[approve] [deny]

Untouched, because reads are not gated:

> what pods are failing in kube-system?

kubectl get pods -n kube-system --field-selector=status.phase!=Running
NAME         READY   STATUS             RESTARTS
api-7d9f8c   0/1     CrashLoopBackOff   14

Untouched, because the context is local:

> wipe the test namespace on my kind cluster

kubectl --context kind-dev delete ns test
namespace "test" deleted

Dry runs are reads, so they pass and give the agent a way to show you a change before asking for it:

kubectl apply --dry-run=server -f deploy.yaml     # allowed
kubectl apply -f deploy.yaml                      # asks

Turn the guard off for one session without editing config:

dsh web --patch <(echo '- id: kubectl-guard
  disabled: true')

Behavior

CommandNon-local contextLocal context
get, describe, logs, topallowallow
auth can-iallowallow
auth reconcileaskallow
config use-context, other mutating config subcommandsaskask
apply, patch, scale, execaskallow
delete, drain, evictdenyallow
scale --replicas=0denyallow
apply --prunedenyallow
replace --forcedenyallow
apply --dry-run=serverallowallow

A context is local only if it matches localContexts. Everything else, including a kubeconfig that cannot be read, is treated as production.

The context is resolved the way the shell would resolve it: an explicit --context wins, then --kubeconfig, then a KUBECONFIG= assignment written inline on the same command line, then the ambient environment. That last case matters -- without it, KUBECONFIG=/path/to/prod kubectl delete ... would be judged against whatever your shell happened to point at.

Config

config:
  localContexts: [minikube, 'kind-*', docker-desktop]
  binaries: [kubectl, k]
  guardedTools: [bash, pwsh]
  showContextNames: false

showContextNames is off by default: blocked-command messages go to the model, and therefore to the LLM provider. With it off the model sees a stable per-session pseudonym like ctx#4be1f92a instead of your cluster's name.

Failing closed

A gate that can be talked around is worse than none. Anything unparseable — sh -c, command substitution, an unterminated quote — is treated as a mutation: denied if the text contains an irreversible verb, asked otherwise. An unknown verb asks rather than allows.

What this is not

This gates a cooperative agent, not an adversary. It reads the command string the agent asked to run, so anything that hides the binary name from that string defeats it by construction -- $KUBECTL delete ... with the name only in the environment, a shell alias resolved at runtime, a base64 round-trip.

Indirection that still contains the literal name is caught: K=kubectl; $K delete pod foo is denied, because any $ expansion alongside a mention of a guarded binary makes the command opaque, and opaque plus an irreversible verb is a denial. But treat the guard as a seatbelt against a confused agent, not a sandbox against a hostile one. If you need the stronger property, take the credential away rather than filtering the command.

Limitations

  • Only kubectl. helm, argocd and flux are not covered; the verb table is data, so adding them is an edit to src/verbs.js.
  • Pass-through wrappers (sudo, time, nice, ...) are seen through, but only until a bare-token wrapper argument: timeout 30 kubectl delete ... is not gated, because 30 ends the wrapper chain.
  • current-context is read with a line-anchored regex, not a YAML parser. Unreadable or unmatched means production, so the failure direction is safe.
  • The pseudonym salt is per-process: ids are stable within a session, not across restarts.
  • Guards are synchronous, so the deny path does no I/O beyond a cached readFileSync.

Test

npm test

MIT.