Problem
The sidecar's task engine today exposes lifecycle, query, and one-shot mutation tasks but no chain-transaction-signing tasks. To enable in-pod governance operations (the migration target for slanders/seienv once validators move to Kubernetes), the sidecar needs a task family that signs and broadcasts Cosmos SDK messages using the mounted operator-account keyring.
seienv today SSHes into validator hosts and runs printf "12345678\n" | sudo /root/go/bin/seid tx gov vote ... — works for EC2 + systemd, doesn't translate to containers. The sidecar should sign in-process using Cosmos SDK libraries, not shell out to seid. Precedent: sidecar/tasks/generate_gentx.go already imports sei-cosmos/client/tx and sei-cosmos/crypto/keyring and signs gentx transactions via library calls.
Impact
- Final on-cluster execution piece for K8s validator governance flows.
- Establishes the pattern for future tx-signing tasks (staking, distribution, IBC).
- Replaces the SSH +
seid tx shell-out pattern from slanders/seienv.
⚠️ Security posture during the gap before authn lands
This task family is being shipped before sidecar API authentication (sister issue: "Sidecar authn + authz middleware on mutating endpoints"), which is the explicit last item in this sequence per a deliberate team scheduling decision.
The current deployment posture treats the sidecar API as accessible only to actors with kubectl-exec / port-forward / cluster-network access — parallel to today's SSH-key boundary on EC2 hosts in the seienv flow (anyone with the SSH key has equivalent power; here, anyone with cluster network access does).
Operators MUST NOT expose the sidecar API to multi-tenant clusters or untrusted in-cluster workloads until the authn issue lands. Acceptance criterion below includes a warning comment at the top of each new task handler referencing the authn issue.
Relevant experts
- blockchain-developer — Msg semantics, fee/gas calculation, account sequence handling
- platform-engineer — task engine integration, idempotency, error handling
- security-specialist — review of pre-authn warning comments + chain-confusion guard
Proposed approach
Library-based signing (NOT shell-out to seid binary) using the SDK packages already in go.mod. Pattern follows sidecar/tasks/generate_gentx.go.
- New task types in
sidecar/engine/types.go:
TaskTypeGovVote — params: proposalId, option (yes|no|abstain|no_with_veto), keyName, memo (opt), gasFees (opt)
TaskTypeGovSubmitProposal — params: proposalType (initially software-upgrade), proposal-specific subparams, keyName, deposit, memo, gasFees
TaskTypeGovDeposit — params: proposalId, amount, keyName, gasFees
- Handlers in
sidecar/tasks/gov_vote.go, gov_submit_proposal.go, gov_deposit.go. Shared helper sidecar/tasks/sign_and_broadcast.go:
- Builds
client.Context from sidecar env + keyring factory (sister issue: "production keyring backend")
- Constructs
tx.Factory, marshals the typed Msg, signs, broadcasts via the existing sidecar/rpc/client.go
- Returns
{txHash, height, rawLog} in the task result
- Account sequence/number resolution: query the node's auth module via the RPC client at sign time. Cache per-key for the duration of a single task; do NOT persist across tasks (avoids stale-sequence retry hazards).
- Chain-confusion guard: every handler refuses if
params.chainId != os.Getenv("SEI_CHAIN_ID") — defense against accidental cross-chain key reuse.
- Idempotency: relies on existing engine UUID dedupe (
sidecar/engine/engine.go:91-138). Critical: a retry with the same caller-supplied UUID after a successful broadcast must NOT re-broadcast. Documented loudly in the task type docstrings.
- Per-Msg typed param schemas (not a generic
signAndBroadcast with raw Msg bytes) — better validation, better audit, easier authn-policy enforcement when authn lands.
- OpenAPI schema update:
sidecar/api/openapi.yaml adds new task type enum values + per-type param schemas.
- Client SDK helpers in
sidecar/client/tasks.go: SubmitGovVoteTask(...), SubmitGovSubmitProposalTask(...), SubmitGovDepositTask(...).
Acceptance criteria
Out of scope
- Authn middleware (separate issue, scheduled last)
- Staking (
MsgDelegate / MsgUndelegate), distribution (MsgWithdrawDelegatorReward), IBC — same pattern, separate issues if needed
- Multi-msg transactions (single Msg per task for now)
- EVM transactions
References
- Coral session 2026-05-11
- Reference impl:
sidecar/tasks/generate_gentx.go (in-process SDK signing already in this sidecar)
- Reference impl: sei-cosmos
x/gov/client/cli/tx.go (the seid CLI's own impl — direct copy-shape target)
- Existing RPC client:
sidecar/rpc/client.go
- Idempotency machinery:
sidecar/engine/engine.go:91-138
- Predecessor:
slanders/seienv cmd/vote.go, propose.sh
- Sister issues: operator-keyring CRD surface (
sei-protocol/sei-node-controller), production keyring backend (this repo), seictl gov CLI (this repo), sidecar authn (this repo)
Sequencing
Phase 1, step 3 of 5 in the governance-flow migration. Depends on steps 1 (CRD operator-keyring in sei-node-controller) and 2 (sidecar keyring backend). Blocks step 4 (seictl CLI commands). Step 5 (authn) is the final hardening pass and lands after this.
Problem
The sidecar's task engine today exposes lifecycle, query, and one-shot mutation tasks but no chain-transaction-signing tasks. To enable in-pod governance operations (the migration target for
slanders/seienvonce validators move to Kubernetes), the sidecar needs a task family that signs and broadcasts Cosmos SDK messages using the mounted operator-account keyring.seienv today SSHes into validator hosts and runs
printf "12345678\n" | sudo /root/go/bin/seid tx gov vote ...— works for EC2 + systemd, doesn't translate to containers. The sidecar should sign in-process using Cosmos SDK libraries, not shell out to seid. Precedent:sidecar/tasks/generate_gentx.goalready importssei-cosmos/client/txandsei-cosmos/crypto/keyringand signs gentx transactions via library calls.Impact
seid txshell-out pattern fromslanders/seienv.This task family is being shipped before sidecar API authentication (sister issue: "Sidecar authn + authz middleware on mutating endpoints"), which is the explicit last item in this sequence per a deliberate team scheduling decision.
The current deployment posture treats the sidecar API as accessible only to actors with kubectl-exec / port-forward / cluster-network access — parallel to today's SSH-key boundary on EC2 hosts in the seienv flow (anyone with the SSH key has equivalent power; here, anyone with cluster network access does).
Operators MUST NOT expose the sidecar API to multi-tenant clusters or untrusted in-cluster workloads until the authn issue lands. Acceptance criterion below includes a warning comment at the top of each new task handler referencing the authn issue.
Relevant experts
Proposed approach
Library-based signing (NOT shell-out to seid binary) using the SDK packages already in
go.mod. Pattern followssidecar/tasks/generate_gentx.go.sidecar/engine/types.go:TaskTypeGovVote— params:proposalId,option(yes|no|abstain|no_with_veto),keyName,memo(opt),gasFees(opt)TaskTypeGovSubmitProposal— params:proposalType(initiallysoftware-upgrade), proposal-specific subparams,keyName,deposit,memo,gasFeesTaskTypeGovDeposit— params:proposalId,amount,keyName,gasFeessidecar/tasks/gov_vote.go,gov_submit_proposal.go,gov_deposit.go. Shared helpersidecar/tasks/sign_and_broadcast.go:client.Contextfrom sidecar env + keyring factory (sister issue: "production keyring backend")tx.Factory, marshals the typed Msg, signs, broadcasts via the existingsidecar/rpc/client.go{txHash, height, rawLog}in the task resultparams.chainId != os.Getenv("SEI_CHAIN_ID")— defense against accidental cross-chain key reuse.sidecar/engine/engine.go:91-138). Critical: a retry with the same caller-supplied UUID after a successful broadcast must NOT re-broadcast. Documented loudly in the task type docstrings.signAndBroadcastwith raw Msg bytes) — better validation, better audit, easier authn-policy enforcement when authn lands.sidecar/api/openapi.yamladds new task type enum values + per-type param schemas.sidecar/client/tasks.go:SubmitGovVoteTask(...),SubmitGovSubmitProposalTask(...),SubmitGovDepositTask(...).Acceptance criteria
sign_and_broadcast.gohelper used by all three handlerssidecar/client/tasks.goOut of scope
MsgDelegate/MsgUndelegate), distribution (MsgWithdrawDelegatorReward), IBC — same pattern, separate issues if neededReferences
sidecar/tasks/generate_gentx.go(in-process SDK signing already in this sidecar)x/gov/client/cli/tx.go(the seid CLI's own impl — direct copy-shape target)sidecar/rpc/client.gosidecar/engine/engine.go:91-138slanders/seienvcmd/vote.go,propose.shsei-protocol/sei-node-controller), production keyring backend (this repo), seictl gov CLI (this repo), sidecar authn (this repo)Sequencing
Phase 1, step 3 of 5 in the governance-flow migration. Depends on steps 1 (CRD operator-keyring in
sei-node-controller) and 2 (sidecar keyring backend). Blocks step 4 (seictl CLI commands). Step 5 (authn) is the final hardening pass and lands after this.