Secure Coding Standard¶
The secure-implementation practice (62443-4-1 Practice 4, SI-1/SI-2) for
Cloud-Native DCS. The standard's defining property: wherever possible a
rule is enforced by a gate. The gate list is the living,
machine-checked part of this standard, and make verify runs every gate
identically locally and in CI.
Languages in scope¶
Go for the operators, gateway, engine, and CLI (memory-safe, CGO_ENABLED=0),
JavaScript (gateway UI), YAML/Helm (manifests), Structured Text (ISA-88
phase logic, executed by our own runtime).
Enforced rules (SI-2 c/d)¶
| Rule | Enforcement |
|---|---|
| Static code analysis on all Go code and every change | golangci-lint v2 in CI + pre-commit: errcheck, govet, staticcheck, revive, unused, misspell, goconst, gocyclo; goimports formatting |
| Known-vulnerability scanning of dependencies | govulncheck in CI; Trivy on release images; Dependabot weekly with go.sum integrity |
| No unchecked errors | errcheck (banned construct: discarding error returns) |
| Input validation on every state-changing gateway endpoint | Typed request DTOs + go-playground/validator, custom k8s-name/ISA-88 validators, DisallowUnknownFields — new endpoints must follow the same shape (reviewed under SI-1) |
| UI API calls carry authentication + anti-replay | Banned construct: raw fetch() against /api/v1/ — only apiFetch()/hmiFetch() transports (make lint-js-api-auth, #788) |
| No semantics derived from tag names in the HMI | Declared role/deviceClass/publishMode only (make lint-js-hmi-semantics, ADR 0016 and ADR 0025 — allowlist permanently empty) |
| Data-quality cues qualify data on evidence alone | Staleness is judged against the tag's declared publishMode. An onChange tag falls back to feed liveness, because its own age is unbounded by design (ADR 0025, #975). A cue that fires on healthy data trains operators to ignore it |
| No raw color/DOM-convention drift in UI code | ESLint + the lint-js- / lint-css- families (tokens, classes, colors) |
| ST builtins in docs/examples carry the sandbox-visible shebang | make lint-docs-st-shebang |
| Generated artifacts never hand-edited | CI drift check via make verify (manifests/generate diff); the ESLint globals list is checked against its generator by make lint-js-globals (#1180) |
| Release binaries exclude internal command surface | make lint-cli-internal-excluded (#614) |
Practice rules (SI-2 a/b/e/f)¶
Rules the reviewer applies where no gate exists (candidates for future gates, per SM-13):
- Banned patterns:
panicfor expected error paths (gRPC panic recovery exists as a backstop and licenses nothing)InsecureSkipVerifyoutside explicitly dev-gated configexec.Commandanywhere in shipped binaries- storing credentials in CRs (Secrets only)
hostPath/hostNetworkbeyond the two design-sanctioned runtime uses (threat model UR-E-01)- new
eval/new Function/dynamicimport()in UI JS - string-concatenated SQL in the historian (parameterized queries only)
- Trust-boundary input validation (SI-2 e): any input crossing a boundary in the interface catalog is validated at the boundary: gateway DTO validation, CRD OpenAPI + CEL validation, webhook required-field checks, and historian topic-shape checks with quality-flagged fallbacks.
- Error handling (SI-2 f): errors returned to external callers carry field-level validation detail but never internal state, stack traces, or dependency version strings. Controllers log structured errors server-side (SR 3.7 row).
- Least privilege in code: new controllers add
+kubebuilder:rbacmarkers scoped to what they touch.make manifests+helm-verify-rbackeep generated RBAC in sync.
Implementation review (SI-1)¶
- Every commit runs the static-analysis gates (no independence required, per Table 3's "None" for SCA).
- The standing daily review agent (#483) audits each day's
maincommits against this standard and the repo conventions, with public dispositions. That is the SI-1 "identify, characterize, track to closure" record. - Security-relevant changes (auth, audit, session, crypto, RBAC, interface catalog rows) additionally get an issue-level review note tracing the implementation to the security requirement it serves.
- Findings feed defect management. Repeated finding classes become new lint gates (SM-13).
Review cadence of this standard¶
Reviewed at least annually alongside the DM-6 review, and whenever a
field-escaped defect or review finding exposes a missing rule. The gate
list changes by adding a make lint-* target so the rule cannot drift
back out.