Implementation Plan: CascadeGuard CLI v2

Overview

Align the CascadeGuard CLI (v0.1) with the published getting-started docs. Changes are ordered to build incrementally: alias first, then command rename, then new init command, then unified check, then cleanup of deprecated commands/workflows, then tests.

Tasks

  • 1. Add cg alias entry point

    • 1.1 Add cg entry point to pyproject.toml
      • In repos/cascadeguard/app/pyproject.toml, add cg = "app:main" under [project.scripts] alongside the existing cascadeguard entry
      • Requirements: 1.1
    • 1.2 Add cg symlink to install.sh
      • In repos/cascadeguard/install.sh, update the link_to_path function to also create a cg symlink pointing to the same venv binary
      • Ensure both cascadeguard and cg are symlinked into LINK_DIR
      • Requirements: 1.3
    • [ ]* 1.3 Write unit test for cg alias equivalence
      • Property 1: cg and cascadeguard alias equivalence
      • Verify both entry points resolve to the same app:main function
      • Validates: Requirements 1.1, 1.2
  • 2. Rename ci command group to build

    • 2.1 Replace ci parser with build parser in app.py
      • In repos/cascadeguard/app/app.py, rename the ci subparser to build in build_parser()
      • Change ci_sub / ci_command / ci_generate variable names to build_sub / build_command / build_generate
      • Remove the old ci parser registration entirely
      • Requirements: 3.1, 3.4
    • 2.2 Update dispatcher functions in app.py
      • Rename cmd_ci to cmd_build_dispatch (or similar) and update it to dispatch on args.build_command
      • Rename cmd_ci_generate to cmd_build_generate
      • Update the commands dict in main() to map "build" instead of "ci"
      • Requirements: 3.1, 3.2
    • [ ]* 2.3 Write unit test for build generate command
      • Property 5: build generate produces identical output to former ci generate
      • Verify cg build generate invokes generate_ci with the same arguments as the old cg ci generate
      • Validates: Requirements 3.2, 3.3
  • 3. Checkpoint — Verify alias and rename

    • Ensure all tests pass, ask the user if questions arise.
  • 4. Implement cg init command

    • 4.1 Add cmd_init function in app.py
      • Implement cmd_init(args) -> int that:
        • Clones the seed repo (cascadeguard-seed) to a temp directory
        • Walks all files in the clone (excluding .git/)
        • For each file: if it exists in target dir, skip with stderr warning; otherwise copy it
        • Handles .gitignore: create with .cascadeguard/.cache/ if missing, append entry if file exists but lacks it, leave unchanged if already present
        • Prints summary: N files copied, M skipped
        • Returns 0 on success, 1 on clone failure
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8
    • 4.2 Register init subcommand in build_parser()
      • Add init to the top-level subparsers in build_parser() with optional --target-dir argument (default .)
      • Add "init": cmd_init to the commands dict in main()
      • Requirements: 2.1
    • [ ]* 4.3 Write property test for init file copy/skip behavior
      • Property 2: Init copies new files and skips existing files
      • Given a mock seed repo and a target dir with some pre-existing files, verify new files are copied and existing files are untouched
      • Validates: Requirements 2.1, 2.2
    • [ ]* 4.4 Write property test for init .gitignore idempotence
      • Property 3: Init .gitignore idempotence
      • Test three cases: no .gitignore, .gitignore without cache entry, .gitignore with cache entry
      • Verify exactly one .cascadeguard/.cache/ entry exists after init and pre-existing content is preserved
      • Validates: Requirements 2.3, 2.4, 2.5
    • [ ]* 4.5 Write unit test for init summary counts
      • Property 4: Init summary counts match file disposition
      • Verify printed summary matches actual copied/skipped counts
      • Validates: Requirement 2.6
  • 5. Checkpoint — Verify init command

    • Ensure all tests pass, ask the user if questions arise.
  • 6. Unify images check command

    • 6.1 Absorb check-upstream logic into cmd_check in app.py
      • Extend the existing cmd_check function to add a Phase 4 after digest drift checking:
        • Query Docker Hub for new upstream tags on each enrolled image (port logic from cmd_images_check_upstream)
        • Append upstream tag findings to the results list with status "new-tags"
        • Update exit code logic: return 1 if drift OR new tags found
      • Requirements: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8
    • 6.2 Add --format and --image flags to images check parser
      • Ensure images check parser has --format (choices: table, json, default: table) and --image (optional filter)
      • Implement table and JSON output rendering in cmd_check
      • Requirements: 4.9, 4.10, 4.11, 7.1, 7.2, 7.3
    • [ ]* 6.3 Write property test for exit code correctness
      • Property 10: Exit code reflects drift and upstream tag status
      • Verify exit code 1 iff drift or new-tags present, 0 otherwise
      • Validates: Requirements 4.7, 4.8
    • [ ]* 6.4 Write property test for image filter scoping
      • Property 12: Image filter scoping
      • Verify --image <name> restricts output to only that image
      • Validates: Requirement 4.11
    • [ ]* 6.5 Write unit test for output format completeness
      • Property 11: Output format completeness
      • Verify both table and JSON formats include image name, status, and details for every result
      • Verify JSON output is valid JSON
      • Validates: Requirements 7.1, 7.2
  • 7. Remove check-upstream subcommand and workflow

    • 7.1 Remove check-upstream from images parser in app.py
      • Remove the images_check_upstream parser registration from build_parser()
      • Remove "check-upstream": cmd_images_check_upstream from the cmd_images dispatch dict
      • Optionally keep cmd_images_check_upstream function body for reference or remove entirely
      • Requirements: 5.1, 5.2
    • 7.2 Delete check-upstream-tags.yaml workflow from open-secure-images
      • Delete repos/cascadeguard-open-secure-images/.github/workflows/check-upstream-tags.yaml
      • Requirements: 6.1, 6.2
  • 8. Update existing tests for all changes

    • [ ]* 8.1 Update test_app.py for renamed build command and removed ci/check-upstream
      • Update any tests referencing ci generate to use build generate
      • Remove or update tests for images check-upstream
      • Add test that ci command is no longer recognized by the parser
      • Add test that images check-upstream is no longer recognized
      • Requirements: 3.4, 5.2
    • [ ]* 8.2 Update test_generate_ci.py if it references CLI entry points
      • Ensure generate_ci tests still pass (the underlying function is unchanged, only the CLI entry point name changed)
      • Requirements: 3.2
    • [ ]* 8.3 Write integration test for unified images check with mock registry
      • Test the full check flow: load images.yaml, parse Dockerfiles, write state, check drift, check upstream tags
      • Mock registry responses to test both drift and no-drift scenarios
      • Property 9: Drift detection correctness
      • Validates: Requirements 4.5, 4.6, 4.7, 4.8
  • 9. Final checkpoint — Ensure all tests pass

    • Ensure all tests pass, ask the user if questions arise.

Notes

  • Tasks marked with * are optional and can be skipped for faster MVP
  • Each task references specific requirements for traceability
  • The implementation language is Python, matching the existing codebase
  • Checkpoints ensure incremental validation after each major change
  • Property tests validate universal correctness properties from the design document
  • The underlying generate_ci.py module is unchanged; only the CLI entry point is renamed