pulse

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 5, 2025 License: MIT Imports: 15 Imported by: 0

README

Pulse

Pulse

A Risk and Performance measurement framework CLI application for organizational programs (e.g. Information Security, Legal).

Overview

Pulse is a command-line tool designed to report on Key Performance Indicators (KPIs) and Key Risk Indicators (KRIs) for programs. It provides a flexible framework for defining, measuring, and reporting on metrics across multiple categories.

Features

  • YAML-based Configuration: Define KPIs, KRIs, categories, and scoring mechanisms using simple YAML files
  • Static Data Storage: Store metrics in YAML files for simplicity and version control
  • Flexible Reporting: Generate reports on overall posture or drill down into specific categories
  • Customizable Scoring: Configure weights and thresholds for scoring at both global and category levels
  • Executive Levers: Adjust scoring parameters to reflect organizational priorities

Architecture

Pulse uses three main YAML configuration files:

  1. Metrics Configuration (config/metrics.yaml): Defines the KPIs and KRIs organized by categories
  2. Metrics Data (data/metrics.yaml): Contains the actual metric values (static data)
  3. Executive Levers (config/levers.yaml): Defines scoring weights and thresholds
Metrics Configuration Structure
categories:
  - id: "app_sec"
    name: "Application Security"
    description: "Metrics related to application security posture"
    kpis:
      - id: "vuln_remediation_time"
        name: "Vulnerability Remediation Time"
        description: "Average time to remediate vulnerabilities"
        unit: "days"
        scoring_bands:
          - score: 95  # 95 points
            max: 15    # for values 0-15 days
          - score: 85  # 85 points
            min: 15    # for values 15-30 days
            max: 30
          - score: 75  # 75 points
            min: 30    # for values 30-45 days
            max: 45
          - score: 65  # 65 points
            min: 45    # for values 45-60 days
            max: 60
          - score: 30  # 30 points
            min: 60    # for values > 60 days
      # More KPIs...
    kris:
      - id: "critical_vulns"
        name: "Critical Vulnerabilities"
        description: "Number of critical vulnerabilities"
        unit: "count"
        scoring_bands:
          - score: 95  # 95 points
            max: 0     # for 0 vulnerabilities
          - score: 85  # 85 points
            min: 0     # for 1-2 vulnerabilities
            max: 2
          - score: 75  # 75 points
            min: 2     # for 3-5 vulnerabilities
            max: 5
          - score: 65  # 65 points
            min: 5     # for 6-10 vulnerabilities
            max: 10
          - score: 30  # 30 points
            min: 10    # for > 10 vulnerabilities
      # More KRIs...
  # More categories...
Metrics Data Structure
metrics:
  - reference: "app_sec.KPI.vuln_remediation_time"
    value: 45
    timestamp: "2025-04-01T00:00:00Z"
  - reference: "app_sec.KRI.critical_vulns"
    value: 3
    timestamp: "2025-04-01T00:00:00Z"
  # More metrics...
Executive Levers Structure
global:
  thresholds:
    green:
      min: 80  # Minimum score for green status
      max: 100 # Maximum score for green status
    yellow:
      min: 60  # Minimum score for yellow status
      max: 79  # Maximum score for yellow status
    red:
      min: 0   # Minimum score for red status
      max: 59  # Maximum score for red status
  
  # KPI and KRI specific thresholds
  kpi_thresholds:
    green:
      min: 85
      max: 100
    yellow:
      min: 65
      max: 84
    red:
      min: 0
      max: 64
  
  kri_thresholds:
    green:
      min: 75
      max: 100
    yellow:
      min: 55
      max: 74
    red:
      min: 0
      max: 54

weights:
  categories:
    "app_sec": 0.4  # Application Security
    "infra_sec": 0.3  # Infrastructure Security
    "compliance": 0.3  # Compliance
  
  # Category-specific thresholds (optional, overrides global)
  category_thresholds:
    "compliance":
      green:
        min: 85
        max: 100
      yellow:
        min: 70
        max: 84
      red:
        min: 0
        max: 69

Installation

Prerequisites
  • Go 1.21 or higher
Building from Source
# Clone the repository
git clone https://github.com/yourusername/pulse.git
cd pulse

# Build the application
go build -o pulse cmd/main.go

Usage

# Display overall posture
pulse report

# Display metrics for a specific category
pulse report --category "Application Security"

# Generate a detailed report in JSON format
pulse report --format json --output report.json

# Generate a report in tabular format
pulse report --format table

# Update metric values
pulse update --metric "app_sec.KRI.critical_vulns" --value 2

# List all available metrics
pulse list metrics

# List all categories
pulse list categories

# Display version information
pulse version
# or
pulse --version

# Initialize configuration files in the default location
pulse init

# Initialize configuration files in a specific directory
pulse init /path/to/directory

Configuration

You can initialize the configuration files in two ways:

  1. In the default location (~/.pulse/):

    pulse init
    
  2. In a specific directory:

    pulse init /path/to/directory
    

This will create:

  • config/metrics.yaml: Define your KPIs and KRIs organized by categories
  • config/levers.yaml: Define scoring weights and thresholds
  • data/metrics/: Directory containing metric files organized by category (e.g., app_sec.yaml)

You can then customize these files according to your needs.

Development

Project Structure
pulse/
├── cmd/
│   ├── main.go                      # CLI entry point
│   ├── cmd_root.go                  # Root command definition
│   ├── cmd_report.go                # Report command
│   ├── cmd_update.go                # Update command
│   ├── cmd_list.go                  # List command
│   ├── cmd_metrics.go               # Metrics command
│   ├── cmd_levers.go                # Levers command
│   ├── cmd_init.go                  # Init command
│   ├── cmd_version.go               # Version command
│   └── ...                          # Other command files
├── config.go                        # Configuration loading
├── metrics.go                       # Metrics processing
├── report.go                        # Report generation
├── score.go                         # Scoring calculations
├── types.go                         # Type definitions
├── constants.go                     # Constants
├── version.go                       # Version information
├── config/                          # Configuration directory
│   ├── metrics.yaml                 # Metrics configuration
│   └── levers.yaml                  # Executive levers configuration
├── data/                            # Data directory
│   └── metrics/                     # Metrics data directory
│       ├── app_sec.yaml             # Application security metrics
│       └── ...                      # Other metric files
├── go.mod
├── go.sum
└── README.md

The project is structured to be used both as a CLI application and as a library:

  • The CLI artifact lives in the cmd directory
  • The main business logic lives in the root directory (package: pulse)
  • This allows other Go projects to import and use the pulse package as a library
Adding New Features
  1. Define new command in cmd/
  2. Implement supporting logic in the root package
  3. Update tests
  4. Update documentation
Building and Releasing

The project includes a Taskfile with various tasks for building, testing, and releasing:

# Build the application
task build

# Run tests
task test

# Generate test coverage report
task coverage

# Create release artifacts for Windows, Linux, and macOS
task release

The release task builds the application for multiple platforms (Windows, Linux, and macOS) and creates compressed archives in the .dist directory.

Version Information

The application includes version information that is set at build time:

  • version: Determined from the current git branch or tag
  • build: Determined from the git commit hash

When building a release, the version will be set to the git tag if the repository is checked out at a tag.

License

MIT

Documentation

Index

Constants

View Source
const ApplicationName string = "pulse"

Variables

View Source
var (
	Version = "main"
	Build   = "unknown"
)

Version information set by build flags

Functions

func FloatPtr

func FloatPtr(v float64) *float64

FloatPtr creates a pointer to a float64 value This is useful for creating min/max values for scoring bands

func GetMetricType

func GetMetricType(reference string) (string, error)

GetMetricType returns whether a metric is a KPI or KRI

Types

type Category

type Category struct {
	ID          string `yaml:"id"`
	Name        string `yaml:"name"`
	Description string `yaml:"description"`
	KPIs        []KPI  `yaml:"kpis"`
	KRIs        []KRI  `yaml:"kris"`
}

Category represents a security program category with KPIs and KRIs

type CategoryScore

type CategoryScore struct {
	ID        string
	Name      string
	Score     int
	KPIScore  int
	KRIScore  int
	Status    TrafficLightStatus
	KPIStatus TrafficLightStatus
	KRIStatus TrafficLightStatus
	Metrics   []MetricScore
}

CategoryScore represents a calculated score for a category

type CategoryThresholds

type CategoryThresholds map[string]Thresholds

CategoryThresholds represents category-specific thresholds

type CategoryWeights

type CategoryWeights map[string]float64

CategoryWeights represents the weights for each category

type ConfigLoader

type ConfigLoader struct {
	ConfigDir string
	DataDir   string
}

ConfigLoader handles loading and parsing of configuration files

func NewConfigLoader

func NewConfigLoader(configDir, dataDir string) *ConfigLoader

NewConfigLoader creates a new ConfigLoader with the specified directories

func (*ConfigLoader) CreateDefaultConfigFiles

func (c *ConfigLoader) CreateDefaultConfigFiles() error

CreateDefaultConfigFiles creates default configuration files if they don't exist

func (*ConfigLoader) CreateMetricFile

func (c *ConfigLoader) CreateMetricFile(fileName string) error

CreateMetricFile creates a new metric file with the given name

func (*ConfigLoader) LoadLeversConfig

func (c *ConfigLoader) LoadLeversConfig() (*LeversConfig, error)

LoadLeversConfig loads the executive levers configuration from the YAML file

func (*ConfigLoader) LoadMetricsConfig

func (c *ConfigLoader) LoadMetricsConfig() (*MetricsConfig, error)

LoadMetricsConfig loads the metrics configuration from the YAML file

func (*ConfigLoader) LoadMetricsData

func (c *ConfigLoader) LoadMetricsData() (*MetricsData, error)

LoadMetricsData loads the metrics data from YAML files in the data directory

func (*ConfigLoader) MigrateMetricsData added in v1.1.0

func (c *ConfigLoader) MigrateMetricsData() error

MigrateMetricsData migrates metrics from both legacy formats to the new format

func (*ConfigLoader) SaveMetricsData

func (c *ConfigLoader) SaveMetricsData(metricsData *MetricsData) error

SaveMetricsData saves the metrics data to YAML files in the data directory

type Global

type Global struct {
	Thresholds    Thresholds `yaml:"thresholds"`
	KPIThresholds Thresholds `yaml:"kpi_thresholds"`
	KRIThresholds Thresholds `yaml:"kri_thresholds"`
}

Global represents global configuration settings

type KPI

type KPI struct {
	ID           string        `yaml:"id"`
	Name         string        `yaml:"name"`
	Description  string        `yaml:"description"`
	Unit         string        `yaml:"unit"`
	ScoringBands []ScoringBand `yaml:"scoring_bands"`
}

KPI represents a Key Performance Indicator

type KRI

type KRI struct {
	ID           string        `yaml:"id"`
	Name         string        `yaml:"name"`
	Description  string        `yaml:"description"`
	Unit         string        `yaml:"unit"`
	ScoringBands []ScoringBand `yaml:"scoring_bands"`
}

KRI represents a Key Risk Indicator

type LeversConfig

type LeversConfig struct {
	Global  Global  `yaml:"global"`
	Weights Weights `yaml:"weights"`
}

LeversConfig represents the structure of the executive levers configuration file

type Metric

type Metric struct {
	Reference  string    `yaml:"reference"`
	Value      float64   `yaml:"value"`
	Timestamp  time.Time `yaml:"timestamp"`
	SourceFile string    `yaml:"-"` // Source file for the metric (not stored in YAML)
}

Metric represents a single metric measurement

type MetricScore

type MetricScore struct {
	Reference string
	Score     int
	Status    TrafficLightStatus
}

MetricScore represents a calculated score for a metric

type MetricsConfig

type MetricsConfig struct {
	Categories []Category `yaml:"categories"`
}

MetricsConfig represents the structure of the metrics configuration file

type MetricsData

type MetricsData struct {
	Metrics []Metric `yaml:"metrics"`
}

MetricsData represents the structure of the metrics data file

type MetricsProcessor

type MetricsProcessor struct {
	// contains filtered or unexported fields
}

MetricsProcessor handles processing and analysis of metrics

func NewMetricsProcessor

func NewMetricsProcessor(metricsConfig *MetricsConfig, leversConfig *LeversConfig, metricsData *MetricsData) *MetricsProcessor

NewMetricsProcessor creates a new MetricsProcessor with the specified configurations

func (*MetricsProcessor) GetAllCategories

func (m *MetricsProcessor) GetAllCategories() []Category

GetAllCategories returns all categories

func (*MetricsProcessor) GetAllMetrics

func (m *MetricsProcessor) GetAllMetrics() []Metric

GetAllMetrics returns all metrics

func (*MetricsProcessor) GetCategoryByID

func (m *MetricsProcessor) GetCategoryByID(categoryID string) (*Category, error)

GetCategoryByID returns a category by its ID

func (*MetricsProcessor) GetMetricByReference

func (m *MetricsProcessor) GetMetricByReference(reference string) (*Metric, error)

GetMetricByReference returns a metric by its reference

func (*MetricsProcessor) GetMetricDefinition

func (m *MetricsProcessor) GetMetricDefinition(reference string) (interface{}, error)

GetMetricDefinition returns the KPI or KRI definition for a metric

func (*MetricsProcessor) GetMetricsByCategory

func (m *MetricsProcessor) GetMetricsByCategory(categoryID string) []Metric

GetMetricsByCategory returns metrics for a specific category

func (*MetricsProcessor) UpdateMetric

func (m *MetricsProcessor) UpdateMetric(reference string, value float64) error

UpdateMetric updates a metric value or adds a new metric if it doesn't exist

type OverallScore

type OverallScore struct {
	Score      int
	KPIScore   int
	KRIScore   int
	Status     TrafficLightStatus
	KPIStatus  TrafficLightStatus
	KRIStatus  TrafficLightStatus
	Categories []CategoryScore
}

OverallScore represents the overall security posture score

type ReportFormat

type ReportFormat string

ReportFormat defines the format of the report

const (
	TextFormat  ReportFormat = "text"
	JSONFormat  ReportFormat = "json"
	TableFormat ReportFormat = "table"
)

type ReportGenerator

type ReportGenerator struct {
	// contains filtered or unexported fields
}

ReportGenerator handles generation of reports

func NewReportGenerator

func NewReportGenerator(scoreCalculator *ScoreCalculator, labelType ThresholdLabelType) *ReportGenerator

NewReportGenerator creates a new ReportGenerator

func (*ReportGenerator) GenerateCategoryReport

func (r *ReportGenerator) GenerateCategoryReport(categoryID string, format ReportFormat) (string, error)

GenerateCategoryReport generates a report for a specific category

func (*ReportGenerator) GenerateOverallReport

func (r *ReportGenerator) GenerateOverallReport(format ReportFormat) (string, error)

GenerateOverallReport generates an overall security posture report

type ScoreCalculator

type ScoreCalculator struct {
	// contains filtered or unexported fields
}

ScoreCalculator handles calculation of scores for metrics and categories

func NewScoreCalculator

func NewScoreCalculator(metricsProcessor *MetricsProcessor, scoringMethod ScoringMethod) *ScoreCalculator

NewScoreCalculator creates a new ScoreCalculator

func (*ScoreCalculator) CalculateCategoryScore

func (s *ScoreCalculator) CalculateCategoryScore(categoryID string) (*CategoryScore, error)

CalculateCategoryScore calculates the score for a category

func (*ScoreCalculator) CalculateMetricScore

func (s *ScoreCalculator) CalculateMetricScore(metric Metric) (*MetricScore, error)

CalculateMetricScore calculates the score for a single metric

func (*ScoreCalculator) CalculateOverallScore

func (s *ScoreCalculator) CalculateOverallScore() (*OverallScore, error)

CalculateOverallScore calculates the overall security posture score

type ScoringBand

type ScoringBand struct {
	Min   *float64 `yaml:"min,omitempty"`
	Max   *float64 `yaml:"max,omitempty"`
	Score int      `yaml:"score"`
}

ScoringBand represents a single scoring band with min/max values and the resulting score

type ScoringMethod

type ScoringMethod string

ScoringMethod defines the method used for score calculation

const (
	// MedianScoring uses median for category scores and weighted median for overall score
	MedianScoring ScoringMethod = "median"
	// AverageScoring uses average for category scores and weighted average for overall score
	AverageScoring ScoringMethod = "average"
)

type ThresholdLabelType added in v1.1.0

type ThresholdLabelType string

ThresholdLabelType defines the type of threshold labels to use

const (
	// EmojiLabels uses emoji symbols for threshold labels
	EmojiLabels ThresholdLabelType = "emoji"
	// TextLabels uses text labels for thresholds
	TextLabels ThresholdLabelType = "text"
)

type ThresholdRange

type ThresholdRange struct {
	Min int `yaml:"min"` // Minimum value (inclusive)
	Max int `yaml:"max"` // Maximum value (inclusive)
}

ThresholdRange represents a range with min and max values

type Thresholds

type Thresholds struct {
	Green  ThresholdRange `yaml:"green"`  // Green threshold range
	Yellow ThresholdRange `yaml:"yellow"` // Yellow threshold range
	Red    ThresholdRange `yaml:"red"`    // Red threshold range
}

Thresholds represents the traffic light thresholds with ranges

type TrafficLightStatus

type TrafficLightStatus string

TrafficLightStatus represents the status in the traffic light model

const (
	Green  TrafficLightStatus = "green"
	Yellow TrafficLightStatus = "yellow"
	Red    TrafficLightStatus = "red"
)

type Weights

type Weights struct {
	Categories            CategoryWeights    `yaml:"categories"`
	CategoryThresholds    CategoryThresholds `yaml:"category_thresholds"`
	CategoryKPIThresholds CategoryThresholds `yaml:"category_kpi_thresholds"`
	CategoryKRIThresholds CategoryThresholds `yaml:"category_kri_thresholds"`
}

Weights represents the weights configuration

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL