Plan: CLI Noun-Verb Reorganisation

Status: Draft

Overview

Reorganise the CascadeGuard CLI from flat top-level verbs to a consistent noun-verb pattern. The actions group already follows this convention (actions pin, actions audit, actions policy init). This plan extends it to all commands.

Current → Proposed Mapping

Current commandNew commandNoun group
validateimages validateimages
enrolimages enrolimages
checkimages checkimages
statusimages statusimages
buildpipeline buildpipeline
deploypipeline deploypipeline
testpipeline testpipeline
pipelinepipeline runpipeline
scan-reportvuln reportvuln
scan-issuesvuln issuesvuln
actions pinactions pinactions (unchanged)
actions auditactions auditactions (unchanged)
actions policy initactions policy initactions (unchanged)
(new) scanscantop-level

Noun Groups

images — Image lifecycle management

cascadeguard images validate       Validate images.yaml configuration
cascadeguard images enrol          Enrol a new image in images.yaml
cascadeguard images check          Check image and base image states
cascadeguard images status         Show status of all images

pipeline — CI/CD orchestration

cascadeguard pipeline run          Run full pipeline (validate → check → build → deploy → test)
cascadeguard pipeline build        Trigger a build via GitHub Actions
cascadeguard pipeline deploy       Deploy via ArgoCD
cascadeguard pipeline test         Check build test results via GitHub Actions

vuln — Vulnerability management

cascadeguard vuln report           Parse scanner output, write diffable vulnerability reports
cascadeguard vuln issues           Create/update/reopen per-CVE GitHub issues

actions — GitHub Actions utilities (unchanged)

cascadeguard actions pin           Pin action refs to full commit SHAs
cascadeguard actions audit         Audit workflow files for pinning status / policy
cascadeguard actions policy init   Scaffold a starter actions-policy.yaml

scan — Repository scanner (top-level, new)

cascadeguard scan                  Discover and analyse container artifacts in a repo

Implementation Approach

Parser restructure in build_parser()

Replace the flat subparser with noun-level subparsers, each containing their own verb subparsers:

sub = parser.add_subparsers(dest="command", metavar="command")
sub.required = True
 
# images
images = sub.add_parser("images", help="Image lifecycle management")
images_sub = images.add_subparsers(dest="images_command", metavar="subcommand")
images_sub.required = True
images_sub.add_parser("validate", help="Validate images.yaml")
# ... enrol, check, status
 
# pipeline
pipeline = sub.add_parser("pipeline", help="CI/CD orchestration")
pipeline_sub = pipeline.add_subparsers(dest="pipeline_command", metavar="subcommand")
pipeline_sub.required = True
pipeline_sub.add_parser("run", help="Run full pipeline")
# ... build, deploy, test
 
# vuln
vuln = sub.add_parser("vuln", help="Vulnerability management")
vuln_sub = vuln.add_subparsers(dest="vuln_command", metavar="subcommand")
vuln_sub.required = True
# ... report, issues
 
# actions — already structured this way, no change
 
# scan — top-level
sub.add_parser("scan", help="Discover and analyse container artifacts")

Dispatch restructure in main()

Replace the flat dispatch dict with noun-level dispatchers (same pattern as existing cmd_actions):

def cmd_images(args) -> int:
    return {
        "validate": cmd_validate,
        "enrol":    cmd_enrol,
        "check":    cmd_check,
        "status":   cmd_status,
    }[args.images_command](args)
 
def cmd_pipeline(args) -> int:
    return {
        "run":    cmd_pipeline_run,  # renamed from cmd_pipeline
        "build":  cmd_build,
        "deploy": cmd_deploy,
        "test":   cmd_test,
    }[args.pipeline_command](args)
 
def cmd_vuln(args) -> int:
    return {
        "report": cmd_scan_report,
        "issues": cmd_scan_issues,
    }[args.vuln_command](args)
 
commands = {
    "images":   cmd_images,
    "pipeline": cmd_pipeline,
    "vuln":     cmd_vuln,
    "actions":  cmd_actions,
    "scan":     cmd_scan,
}

Handler functions

No changes to the actual handler logic (cmd_validate, cmd_enrol, etc.) — only the dispatch wiring changes. The one rename is cmd_pipelinecmd_pipeline_run to avoid collision with the new cmd_pipeline dispatcher.

Backward Compatibility

Remove old commands. The tool is pre-1.0 and not widely distributed yet. Update all references in:

  • Taskfile.docker.yaml (Docker entrypoint tasks)
  • Taskfile.shared.yaml (state repo shared tasks)
  • README and docs
  • Generated CI workflow files (generate-ci output)

Option B: Deprecation aliases

Keep old commands as hidden aliases that print a deprecation warning and delegate to the new structure. Remove after one release cycle.

Files to Change

FileChange
app/app.pyRestructure build_parser() and main() dispatch
Taskfile.docker.yamlUpdate command references
Taskfile.shared.yamlUpdate command references
README.mdUpdate command examples
app/tests/Update any tests that invoke CLI commands

Global Options

The existing --images-yaml and --state-dir flags are currently global. After reorganisation they only make sense for the images noun group. Move them to the images subparser.

# Before (global)
cascadeguard --images-yaml custom.yaml validate

# After (scoped)
cascadeguard images --images-yaml custom.yaml validate

Help Output (target)

$ cascadeguard --help
CascadeGuard — container image lifecycle tool

Commands:
  images      Image lifecycle management
  pipeline    CI/CD orchestration
  vuln        Vulnerability management
  actions     GitHub Actions utilities
  scan        Discover and analyse container artifacts

$ cascadeguard images --help
Image lifecycle management

Subcommands:
  validate    Validate images.yaml configuration
  enrol       Enrol a new image in images.yaml
  check       Check image and base image states
  status      Show status of all images

Phases

Phase 1: Restructure parser and dispatch

  • Refactor build_parser() into noun groups
  • Add noun-level dispatchers
  • Rename cmd_pipelinecmd_pipeline_run
  • Move --images-yaml / --state-dir to images subparser
  • Update tests

Phase 2: Update references

  • Taskfile.docker.yaml
  • Taskfile.shared.yaml
  • README.md
  • Generated CI workflow templates (if generate-ci emits cascadeguard commands)

Phase 3: Add scan command (separate plan)

  • Wire up scan subparser at top level
  • Implement discovery modules per the scan command plan