Skip to content

Latest commit

 

History

History
86 lines (69 loc) · 3.49 KB

File metadata and controls

86 lines (69 loc) · 3.49 KB

Implementation Plan

Architecture Overview

actions_graph/
├── __init__.py          # Package version
├── cli.py               # Typer CLI app (tree, export, diff, audit commands)
├── models.py            # Data models: ActionRef, ActionNode, RiskLevel
├── parser.py            # YAML workflow parser — extracts `uses:` references
├── resolver.py          # Recursive GitHub API resolution of composite actions
├── graph.py             # NetworkX DAG builder from resolved nodes
├── render.py            # Rich tree rendering for terminal output
├── export.py            # Mermaid, DOT (pydot), JSON export
├── risk.py              # Risk assessment logic (mutable tags, unverified, depth)
├── diff.py              # Diff mode: compare two workflow files
├── cache.py             # SQLite cache with TTL for API responses
└── github.py            # GitHub API client (httpx) for fetching action.yml

Implementation Order (Critical Path)

Step 1: Models

Data classes for ActionRef (owner/repo@ref), ActionNode (resolved action with metadata), RiskLevel enum. These are used by everything else.

Step 2: Parser

Parse workflow YAML files to extract all uses: references as ActionRef objects. Handle job-level and step-level uses. Skip local actions (./path).

Step 3: GitHub API Client

httpx-based client to fetch action.yml/action.yaml from a GitHub repo at a given ref. Needs GITHUB_TOKEN support for auth.

Step 4: Cache

SQLite-based cache keyed on owner/repo@ref. Stores raw action.yml content. Configurable TTL (default 24h). Used by resolver to avoid redundant API calls.

Step 5: Resolver

Given a list of ActionRef, recursively resolve composite actions:

  • Fetch action.yml via GitHub client (with cache)
  • If action is composite, parse its steps for more uses: refs
  • Build parent→child relationships
  • Stop at non-composite actions or max depth

Step 6: Graph Builder

Take resolver output and build a NetworkX DiGraph. Nodes = ActionRef strings, edges = dependency relationships. Root nodes = workflow file actions.

Step 7: Risk Assessment

Score each node: mutable tag (not a SHA), high depth (>3), unverified creator (not in a known-good list). Produce RiskLevel per node.

Step 8: Rich Tree Renderer

Render the graph as a Rich Tree for terminal display. Color-code by risk level. Support --depth flag to limit display depth.

Step 9: Export (Mermaid, DOT, JSON)

  • Mermaid: generate flowchart string from graph
  • DOT: use pydot to create DOT format
  • JSON: serialize graph as adjacency list with metadata

Step 10: Diff Mode

Parse two workflow files, build both dependency sets, compute added/removed actions. Display as colored terminal output.

Step 11: CLI

Wire everything together with Typer:

  • actions-graph tree [FILES...] [--depth N]
  • actions-graph export [FILES...] --format mermaid|dot|json
  • actions-graph diff FILE1 FILE2
  • actions-graph audit [FILES...]

Step 12: Tests

Unit tests for each module. Integration tests for CLI commands. Use fixtures with sample workflow YAML files.

Key Decisions

  1. SQLite cache — simple, zero-config, portable
  2. No async — httpx sync client is sufficient for CLI tool
  3. NetworkX DiGraph — mature, well-tested graph library
  4. Typer — modern CLI framework with good type hint support
  5. Mock GitHub API in tests — no real network calls in test suite
  6. ActionRef as frozen dataclass — hashable, usable as dict keys and set members