Skip to content

[duplicate-code] Duplicate Code Pattern: SecrecyLabel and IntegrityLabel structural duplication in labels.go #2560

Description

@github-actions

Part of duplicate code analysis: #2557

Summary

internal/difc/labels.go defines two separate wrapper types — SecrecyLabel and IntegrityLabel — that are structurally near-identical. Each wraps a *Label, delegates all operations to the shared checkFlowHelper, and implements the same set of methods (getLabel, CanFlowTo, CheckFlow, Clone). The only semantic difference is the checkSubset boolean passed to checkFlowHelper.

Duplication Details

Pattern: Symmetric label wrapper types with identical method bodies

  • Severity: Medium

  • Occurrences: 2 types × ~18 lines = ~36 lines duplicated

  • Locations:

    • internal/difc/labels.go ~lines 156–282 (SecrecyLabel and its methods)
    • internal/difc/labels.go ~lines 296–340 (IntegrityLabel and its methods)
  • Code Sample (near-identical structure):

    // SecrecyLabel
    func NewSecrecyLabel() *SecrecyLabel          { return &SecrecyLabel{Label: NewLabel()} }
    func NewSecrecyLabelWithTags(t []Tag) *SecrecyLabel { return &SecrecyLabel{Label: newLabelWithTags(t)} }
    func (l *SecrecyLabel) getLabel() *Label      { if l == nil { return nil }; return l.Label }
    func (l *SecrecyLabel) CanFlowTo(t *SecrecyLabel) bool { ok, _ := checkFlowHelper(l.getLabel(), t.getLabel(), true, "Secrecy"); return ok }
    func (l *SecrecyLabel) CheckFlow(t *SecrecyLabel) (bool, []Tag) { return checkFlowHelper(l.getLabel(), t.getLabel(), true, "Secrecy") }
    func (l *SecrecyLabel) Clone() *SecrecyLabel  { if l.getLabel() == nil { return NewSecrecyLabel() }; return &SecrecyLabel{Label: l.Label.Clone()} }
    
    // IntegrityLabel — identical structure, checkSubset=false, "Integrity" label
    func NewIntegrityLabel() *IntegrityLabel          { ... }
    func NewIntegrityLabelWithTags(t []Tag) *IntegrityLabel { ... }
    func (l *IntegrityLabel) getLabel() *Label      { ... }
    func (l *IntegrityLabel) CanFlowTo(t *IntegrityLabel) bool { ..., false, "Integrity" ... }
    func (l *IntegrityLabel) CheckFlow(t *IntegrityLabel) (bool, []Tag) { ..., false, "Integrity" ... }
    func (l *IntegrityLabel) Clone() *IntegrityLabel  { ... }

Impact Analysis

  • Maintainability: Medium — adding a method (e.g., IsEmpty(), Merge()) or changing getLabel nil-guard logic requires updating both types identically
  • Bug Risk: Medium — a subtle fix to Clone's nil guard in one type could be missed in the other
  • Design Concern: If a third label type is needed in the future (e.g., ConfidentialityLabel), a third identical block must be added

Refactoring Recommendations

Option A — Go generics (preferred if Go 1.21+ generics constraints are acceptable):

Introduce a single generic FlowLabel[T] with a checkSubset bool field, parametrizing CanFlowTo / CheckFlow / Clone via a type constraint. This eliminates the duplicate method bodies while preserving type safety.

type labelConfig struct {
    checkSubset bool
    name        string
}

// Internal generic wrapper — not exported
type flowLabel struct {
    Label  *Label
    config labelConfig
}

func (l *flowLabel) getLabel() *Label { if l == nil { return nil }; return l.Label }
func (l *flowLabel) canFlowTo(target *flowLabel) bool {
    ok, _ := checkFlowHelper(l.getLabel(), target.getLabel(), l.config.checkSubset, l.config.name)
    return ok
}
// ... etc.

// Public types remain for callers
type SecrecyLabel   struct { fl flowLabel }
type IntegrityLabel struct { fl flowLabel }
  • Estimated effort: 1–2 hours
  • Benefits: single nil-guard, single Clone implementation, easy to add a third label type

Option B — Keep separate types, extract common nil-guard:

A smaller refactor — extract the repeated getLabel() pattern into a standalone function:

func getLabelOrNil[T interface{ getInner() *Label }](l T) *Label { ... }

This is a narrower improvement but lower risk.

Option C — Accept as intentional: The current checkFlowHelper already centralises the complex logic. The wrapper duplication is ~36 lines and well-documented. If no new label types are planned, leave as-is.

Implementation Checklist

  • Review duplication findings
  • Decide between Option A, B, or C
  • If Option A or B: implement and validate all checkFlowHelper call sites
  • Update tests to verify secrecy and integrity flow semantics are preserved
  • Verify no functionality broken

Parent Issue

See parent analysis report: #2557
Related to #2557

Generated by Duplicate Code Detector ·

  • expires on Apr 2, 2026, 3:36 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions