Requirements Document

Introduction

CascadeGuard is a CLI tool for container image lifecycle management. This feature introduces config inheritance via .cascadeguard.yaml defaults, new CLI commands for state file and CI pipeline generation, updated validation logic, and documentation updates. The goal is to eliminate per-image repetition of registry/repository fields, promote standalone scripts to first-class CLI subcommands, and fix the 25 validation failures in the cascadeguard-open-secure-images repository.

Glossary

  • CLI: The cascadeguard command-line interface implemented in app.py
  • ConfigLoader: The module responsible for reading .cascadeguard.yaml and applying repo-level defaults to image entries
  • Validator: The cmd_validate function that checks images.yaml entries for required fields
  • ImageEntry: A single dictionary representing one image in images.yaml
  • MergeDefaults: The merge_defaults() function that applies config defaults to image entries
  • StateGenerator: The cmd_images_generate command handler that produces state files from images.yaml
  • CIGenerator: The cmd_ci_generate command handler that produces CI pipeline files from images.yaml
  • ConfigFile: The .cascadeguard.yaml file at the repository root containing repo-level defaults and CI settings
  • Parser: The build_parser() function that defines CLI argument structure

Requirements

Requirement 1: Load Repository Configuration

User Story: As a CascadeGuard user, I want the CLI to load repo-level defaults from .cascadeguard.yaml, so that I do not have to repeat common fields on every image entry.

Acceptance Criteria

  1. WHEN a .cascadeguard.yaml file exists in the repository root, THE ConfigLoader SHALL parse the file and return a configuration dictionary
  2. WHEN a .cascadeguard.yaml file does not exist in the repository root, THE ConfigLoader SHALL return an empty dictionary without raising an error
  3. IF the .cascadeguard.yaml file contains invalid YAML syntax, THEN THE ConfigLoader SHALL print an error to stderr and return exit code 1
  4. IF the .cascadeguard.yaml file root value is not a dictionary, THEN THE ConfigLoader SHALL print an error to stderr and return exit code 1
  5. WHEN the .cascadeguard.yaml file contains unknown keys, THE ConfigLoader SHALL ignore the unknown keys silently

Requirement 2: Merge Config Defaults into Image Entries

User Story: As a CascadeGuard user, I want repo-level defaults for registry, repository, and local.dir to be applied to each image automatically, so that I can define these values once instead of per-image.

Acceptance Criteria

  1. WHEN an ImageEntry lacks a registry field and the ConfigFile defaults.registry is set, THE MergeDefaults SHALL set the ImageEntry registry to the config default value
  2. WHEN an ImageEntry lacks a repository field and the ConfigFile defaults.repository is set, THE MergeDefaults SHALL set the ImageEntry repository to the config default value
  3. WHEN an ImageEntry lacks a local.dir field and the ConfigFile defaults.local.dir is set, THE MergeDefaults SHALL set the ImageEntry local.dir to the config default value
  4. WHEN an ImageEntry already has a registry field, THE MergeDefaults SHALL retain the ImageEntry value regardless of the ConfigFile default
  5. WHEN an ImageEntry already has a repository field, THE MergeDefaults SHALL retain the ImageEntry value regardless of the ConfigFile default
  6. WHEN an ImageEntry already has a local.dir field, THE MergeDefaults SHALL retain the ImageEntry value regardless of the ConfigFile default
  7. THE MergeDefaults SHALL return a new list without mutating the original image list
  8. THE MergeDefaults SHALL return a list of the same length as the input image list
  9. WHEN the ConfigFile has no defaults section, THE MergeDefaults SHALL return copies of the original images with no fields added

Requirement 3: Validate Images with Config Inheritance

User Story: As a CascadeGuard user, I want cascadeguard images validate to apply config defaults before checking required fields, so that images relying on repo-level defaults pass validation.

Acceptance Criteria

  1. WHEN validating images, THE Validator SHALL load the ConfigFile and merge defaults before checking required fields
  2. WHEN an enabled ImageEntry has name, registry, and dockerfile fields after merging defaults, THE Validator SHALL consider the ImageEntry valid
  3. WHEN an enabled ImageEntry is missing registry or dockerfile after merging defaults, THE Validator SHALL report a validation error indicating the missing field
  4. WHEN a disabled ImageEntry (enabled: false) has a name field, THE Validator SHALL consider the ImageEntry valid regardless of other missing fields
  5. WHEN any ImageEntry is missing the name field, THE Validator SHALL report a validation error regardless of enabled status
  6. WHEN all images pass validation, THE Validator SHALL return exit code 0 and print a success count
  7. WHEN any image fails validation, THE Validator SHALL return exit code 1 and print all errors to stderr
  8. WHEN a required field is missing after merge, THE Validator SHALL include a hint that the field can be set in .cascadeguard.yaml defaults

Requirement 4: Generate State Files via CLI

User Story: As a CascadeGuard user, I want a cascadeguard images generate command, so that I can generate state files without relying on Taskfile wrappers or Docker indirection.

Acceptance Criteria

  1. WHEN a user runs cascadeguard images generate, THE StateGenerator SHALL load the ConfigFile, merge defaults, and generate state files for each image
  2. WHEN the --output-dir flag is provided, THE StateGenerator SHALL write state files to the specified directory
  3. WHEN the --output-dir flag is not provided, THE StateGenerator SHALL write state files to the current working directory
  4. WHEN state generation succeeds, THE StateGenerator SHALL return exit code 0 and print a summary of generated files
  5. IF the specified images.yaml file does not exist, THEN THE StateGenerator SHALL print an error to stderr and return exit code 1
  6. WHEN cascadeguard images generate is run twice with the same inputs, THE StateGenerator SHALL produce identical output files

Requirement 5: Generate CI Pipelines via CLI

User Story: As a CascadeGuard user, I want a cascadeguard ci generate command, so that I can generate CI pipeline files without relying on Taskfile wrappers or Docker indirection.

Acceptance Criteria

  1. WHEN a user runs cascadeguard ci generate, THE CIGenerator SHALL load the ConfigFile, merge defaults, and generate CI pipeline files
  2. WHEN the --platform flag is provided, THE CIGenerator SHALL use the specified platform for pipeline generation
  3. WHEN the --platform flag is not provided and the ConfigFile has ci.platform set, THE CIGenerator SHALL use the ConfigFile platform value
  4. WHEN neither the --platform flag nor the ConfigFile ci.platform is set, THE CIGenerator SHALL default to “github”
  5. WHEN the --output-dir flag is provided, THE CIGenerator SHALL write pipeline files to the specified directory
  6. WHEN the --output-dir flag is not provided, THE CIGenerator SHALL write pipeline files to the current working directory
  7. WHEN the --dry-run flag is provided, THE CIGenerator SHALL preview the output without writing files
  8. IF the specified images.yaml file does not exist, THEN THE CIGenerator SHALL print an error to stderr and return exit code 1
  9. WHEN cascadeguard ci generate is run twice with the same inputs, THE CIGenerator SHALL produce identical output files

Requirement 6: CLI Argument Registration

User Story: As a CascadeGuard user, I want the new commands registered in the CLI parser, so that I can discover and use them via --help and standard argument parsing.

Acceptance Criteria

  1. THE Parser SHALL register generate as a subcommand under the images command group
  2. THE Parser SHALL register ci as a new top-level command with a generate subcommand
  3. WHEN a user runs cascadeguard images generate --help, THE CLI SHALL display help text describing the command and its flags
  4. WHEN a user runs cascadeguard ci generate --help, THE CLI SHALL display help text describing the command and its flags
  5. THE Parser SHALL accept --images-yaml, --output-dir, and --cache-dir flags for images generate
  6. THE Parser SHALL accept --images-yaml, --output-dir, --platform, and --dry-run flags for ci generate

Requirement 7: Backward Compatibility

User Story: As an existing CascadeGuard user, I want the CLI to behave identically to before when no .cascadeguard.yaml defaults section exists, so that my existing workflows are not broken.

Acceptance Criteria

  1. WHEN the ConfigFile has no defaults section, THE Validator SHALL behave identically to the current validation logic
  2. WHEN the ConfigFile does not exist, THE CLI SHALL proceed with per-image fields only and produce the same results as the current behavior
  3. THE CLI SHALL preserve all existing commands and their behavior without modification

Requirement 8: Error Handling for State and CI Generation

User Story: As a CascadeGuard user, I want clear error messages when generation fails, so that I can diagnose and fix issues quickly.

Acceptance Criteria

  1. IF a source repository is unreachable during state generation, THEN THE StateGenerator SHALL print a warning and continue generating state for remaining images
  2. WHEN state generation encounters a partial failure, THE StateGenerator SHALL preserve existing state files for images that failed
  3. IF CI generation encounters an error, THEN THE CIGenerator SHALL print the error to stderr and return exit code 1