All skills
cxuu avatar

/go-defensive

@91f0c2e
by Charles Xucxuu/golang-skills165 stars
19

Use when hardening Go code at API boundaries — copying slices/maps, verifying interface compliance, using defer for cleanup, time.Time/time.Duration, or avoiding mutable globals. Also use when reviewing for robustness concerns like missing cleanup or unsafe crypto usage, even if the user doesn't mention "defensive programming." Does not cover error handling strategy (see go-error-handling).

Use this Skill: https://skilld.dev/gh/cxuu/golang-skills/go-defensive

This session only. Nothing lands on disk.

referencesBOUNDARY-COPYING.md

≈550 tokens on demand. Your agent reads this file only when SKILL.md points to it.

Copying Slices and Maps at API Boundaries

Source: Uber Style Guide

Slices and maps contain references to their underlying data. Copy them at API boundaries to prevent callers from mutating internal state (or vice versa).

Receiving Slices and Maps

When a function stores a slice or map passed by the caller, always make a defensive copy. The caller retains the original reference and can modify it after your function returns.

Slices

Bad

func (d *Driver) SetTrips(trips []Trip) {
  d.trips = trips  // caller can still modify d.trips
}

Good

func (d *Driver) SetTrips(trips []Trip) {
  d.trips = make([]Trip, len(trips))
  copy(d.trips, trips)
}

Maps

Bad

func (s *Server) SetConfig(cfg map[string]string) {
  s.config = cfg  // caller can still modify s.config
}

Good

func (s *Server) SetConfig(cfg map[string]string) {
  s.config = make(map[string]string, len(cfg))
  for k, v := range cfg {
    s.config[k] = v
  }
}

Returning Slices and Maps

When returning internal slices or maps, return a copy to prevent callers from modifying your internal state.

Returning a Map

Bad

func (s *Stats) Snapshot() map[string]int {
  s.mu.Lock()
  defer s.mu.Unlock()
  return s.counters  // exposes internal state!
}

Good

func (s *Stats) Snapshot() map[string]int {
  s.mu.Lock()
  defer s.mu.Unlock()
  result := make(map[string]int, len(s.counters))
  for k, v := range s.counters {
    result[k] = v
  }
  return result
}

Returning a Slice

Bad

func (q *Queue) Items() []Item {
  return q.items  // caller can append, modify, or reslice
}

Good

func (q *Queue) Items() []Item {
  result := make([]Item, len(q.items))
  copy(result, q.items)
  return result
}

When Copies Are Not Needed

Defensive copies have a cost. Skip them when:

  • The data is immutable by convention and clearly documented
  • The slice/map is created fresh for the caller (not stored internally)
  • Performance profiling shows the copy is a bottleneck in a hot path

When in doubt, copy. The cost is usually negligible compared to the bugs that shared references cause.

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    No security issues or malicious patterns were detected. The skill contains standard best-practice reference material and patterns for defensive programming in Go.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer6mo

    6 files scanned · No issues

  • ZeroLeaks5mo

    1 finding · Score: 86/100

Signed by skilld at 91f0c2e. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago

README badge

README badge for cxuu/golang-skills/go-defensive