Skip to content

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:
    • panic for expected error paths (gRPC panic recovery exists as a backstop and licenses nothing)
    • InsecureSkipVerify outside explicitly dev-gated config
    • exec.Command anywhere in shipped binaries
    • storing credentials in CRs (Secrets only)
    • hostPath/hostNetwork beyond the two design-sanctioned runtime uses (threat model UR-E-01)
    • new eval/new Function/dynamic import() 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:rbac markers scoped to what they touch. make manifests + helm-verify-rbac keep 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 main commits 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.