mitre-attack / mitre-attack/attack-data-model

Overhaul ES6 Class Implementations

Open
#37 0 comments 0 reactions 1 assignee View on GitHub

@seansica is already working on this.

Since Jul 21, 2025.

  • #38 by @seansica — open
enhancement
Dominant language
MDX
Stars
93
Forks
25
PR merge metrics
No merged PRs in 30d

Description

Problem

The current ES6 class implementations (*Impl classes) in src/classes/[sdo, smo, sro, common]/ are sparse and require several TypeScript linting suppressions. The current approach uses interface declaration merging to extend STIX objects, which is not ideal:

/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */

export class AnalyticImpl extends AttackBaseImpl implements Analytic {
  constructor(readonly analytic: Analytic) {
    super();
    Object.assign(this, analytic);
  }
}

// Suppress the lint error for the empty interface
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
export interface AnalyticImpl extends Analytic {}

/* eslint-enable @typescript-eslint/no-unsafe-declaration-merging */

Issues with current approach:

  • Requires multiple linting error suppressions
  • Uses interface declaration merging as a workaround
  • Lacks comprehensive relationship management
  • Missing domain-specific utility methods

Proposed Solution

Replace the current implementation pattern with a more robust approach using a Validated base class that leverages Zod schemas for type safety:

New Architecture
  1. Schema-based validation: Classes extend Validated(schema) to inherit validated properties from Zod schemas
  2. Private relationship tracking: Use private fields (#property) for mutable relationship state
  3. Comprehensive API: Add domain-specific methods for relationship management and utility operations
  4. Type safety: Eliminate need for linting suppressions and declaration merging
Example Implementation
export class TechniqueImpl extends Validated(techniqueSchema) {
  // Relationship tracking (mutable, not part of JSON data)
  #subTechniques: TechniqueImpl[] = [];
  #tactics: TacticImpl[] = [];
  #mitigations: MitigationImpl[] = [];
  #parentTechnique?: TechniqueImpl;
  // ... other relationships

  // Relationship management
  addSubTechnique(subTechnique: TechniqueImpl): void {
    if (!this.#subTechniques.includes(subTechnique)) {
      this.#subTechniques.push(subTechnique);
    }
  }

  getSubTechniques(): readonly TechniqueImpl[] {
    return [...this.#subTechniques];
  }

  // Domain-specific utilities
  getAttackId(): string | undefined {
    return this.external_references?.[0]?.external_id;
  }

  getDisplayName(): string {
    const attackId = this.getAttackId();
    return attackId ? `${attackId}: ${this.name}` : this.name;
  }

  supportsPlatform(platform: string): boolean {
    return this.x_mitre_platforms?.includes(platform as XMitrePlatform) ?? false;
  }

  // Immutable updates
  with(updates: Partial<TechniqueImpl>): TechniqueImpl {
    const newData = { ...this, ...updates };
    return new TechniqueImpl(newData);
  }
}

Benefits

  • No linting suppressions needed: Clean TypeScript without workarounds
  • Better encapsulation: Private fields for relationship state management
  • Rich API: Domain-specific methods for common operations
  • Type safety: Schema-based validation ensures data integrity
  • Relationship management: Built-in support for navigating object relationships via SROs
  • Immutable patterns: Support for functional updates with with() and touch() methods

Implementation Plan

  1. Create Validated base class that accepts Zod schema parameter
  2. Refactor existing *Impl classes to use new pattern
  3. Add comprehensive relationship management methods
  4. Implement domain-specific utility methods for each object type
  5. Update relationship processing logic to populate private relationship fields
  6. Remove all linting suppressions and declaration merging interfaces

Acceptance Criteria

  • All *Impl classes use Validated base class approach
  • Zero TypeScript linting suppressions in class implementations
  • Comprehensive relationship management APIs
  • Domain-specific utility methods for each object type
  • SRO processing populates relationship fields for easy navigation
  • All existing functionality preserved
  • Type safety maintained throughout

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.