From 88498b877788437f6e36a0407a227c42df80bae6 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Tue, 25 Aug 2026 08:59:32 -0500 Subject: [PATCH 01/10] feat(cloudformation): add Phase 2 changesets, drift detection, and get verbs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicit changeset control (create/execute/list/delete), complementing the implicit changeset flow apply/deploy/diff already use: - atmos aws cloudformation changeset create/execute/list/delete - atmos aws cloudformation drift detect/describe (DetectStackDrift/ DescribeStackDriftDetectionStatus/DescribeStackResourceDrifts) - atmos aws cloudformation get template/policy (GetTemplate/GetStackPolicy) Also the Terraform<->CloudFormation interop bridge: - `!aws.cloudformation.output [stack] ` YAML function, sibling to !terraform.output (same cycle-detection/nested-auth machinery). - atmos.Component(...).outputs now resolves for aws/cloudformation targets, not just terraform. The CFN client interface grew ListChangeSets/DeleteChangeSet/GetTemplate/ GetStackPolicy/ListStacks/DetectStackDrift/DescribeStackDriftDetectionStatus/ DescribeStackResourceDrifts. runOperation and ComponentProvider.Execute were refactored from long switches to map-based dispatch (cyclomatic complexity had crossed the lint threshold with the new operations). The Outputs-fetching logic behind the YAML/template functions couldn't live in internal/exec directly (the provider-agnostic-auth depguard rule forbids AWS SDK imports there) or reuse pkg/component/aws/cloudformation's own client (it already imports internal/exec, so the reverse import would cycle) — added a small leaf package, pkg/aws/cloudformation, mirroring pkg/aws/identity's shape. Verified live against the Floci AWS emulator: changeset create/execute/list, get template, and both the YAML function and atmos.Component().outputs resolving a second component's real deployed Output value. drift detect and get policy hit genuine Floci/LocalStack-community limitations (confirmed via matching failures on raw AWS CLI calls against the same endpoint, not Atmos bugs) — DetectStackDrift is unimplemented and GetStackPolicy returns a malformed response Floci's own SDK client can't parse either. Every new/renamed YAML function tag required updates across five independent registries that must stay in sync with pkg/utils/yaml_utils.go's AtmosYamlFunc* constants: pkg/function/tag (the format-agnostic tag catalog), pkg/tags/selector.go (functions forbidden in metadata.tags/labels — this one matters: cross-component output resolution requires auth and a live API call, so it must be excluded from tag/label selector evaluation same as !terraform.output), pkg/config/schema/ratchet_test.go (atmos.yaml preprocessing classification), and cmd/list/utils.go (functions skipped during inventory upload when no AuthManager is available). Co-Authored-By: Claude Sonnet 5 --- .golangci.yml | 1 + cmd/aws/cloudformation/cloudformation.go | 150 ++++++++++++---- cmd/list/utils.go | 1 + errors/errors.go | 1 + internal/exec/cloudformation_output_getter.go | 94 ++++++++++ internal/exec/template_funcs_component.go | 12 ++ internal/exec/yaml_func_aws.go | 84 +++++++++ internal/exec/yaml_func_utils.go | 4 + pkg/aws/cloudformation/outputs.go | 61 +++++++ .../aws/cloudformation/changeset_verbs.go | 153 +++++++++++++++++ pkg/component/aws/cloudformation/client.go | 18 +- .../aws/cloudformation/cloudformation.go | 48 ++++-- pkg/component/aws/cloudformation/confirm.go | 17 +- pkg/component/aws/cloudformation/drift.go | 153 +++++++++++++++++ pkg/component/aws/cloudformation/executor.go | 89 ++++++++-- pkg/component/aws/cloudformation/get.go | 71 ++++++++ .../aws/cloudformation/mock_client_test.go | 160 ++++++++++++++++++ pkg/component/aws/cloudformation/types.go | 16 ++ pkg/config/schema/ratchet_test.go | 2 + pkg/function/tag/tag.go | 5 + pkg/function/tag/tag_test.go | 1 + pkg/function/tags.go | 3 + pkg/function/tags_test.go | 2 + pkg/tags/selector.go | 1 + pkg/tags/selector_test.go | 1 + pkg/utils/yaml_utils.go | 3 + pkg/utils/yaml_utils_test.go | 1 + pkg/utils/yaml_utils_unsupported_test.go | 1 + 28 files changed, 1080 insertions(+), 73 deletions(-) create mode 100644 internal/exec/cloudformation_output_getter.go create mode 100644 pkg/aws/cloudformation/outputs.go create mode 100644 pkg/component/aws/cloudformation/changeset_verbs.go create mode 100644 pkg/component/aws/cloudformation/drift.go create mode 100644 pkg/component/aws/cloudformation/get.go diff --git a/.golangci.yml b/.golangci.yml index 31d1471d790..587d0e4e461 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -89,6 +89,7 @@ linters: - "!**/pkg/aws/identity/**" - "!**/pkg/aws/organization/**" - "!**/pkg/aws/security/**" + - "!**/pkg/aws/cloudformation/**" - "!**/pkg/provisioner/backend/**" # pkg/component/aws/cloudformation is the SDK-native aws/cloudformation # component type; it deploys directly through the CloudFormation API and diff --git a/cmd/aws/cloudformation/cloudformation.go b/cmd/aws/cloudformation/cloudformation.go index a98b787bff7..ccff993bab3 100644 --- a/cmd/aws/cloudformation/cloudformation.go +++ b/cmd/aws/cloudformation/cloudformation.go @@ -25,6 +25,15 @@ const ( flagLabels = "labels" // The valueTrue const is the string representation of a set boolean flag. valueTrue = "true" + + flagAutoApprove = "auto-approve" + + // The subCommandApply/subCommandDelete consts are the Operation-dispatch + // identifiers shared by the top-level apply/deploy and delete verbs, and by + // verb-group entries that reuse the same literal (e.g. `changeset delete`'s + // use name). + subCommandApply = "apply" + subCommandDelete = "delete" ) var cloudFormationParser *flags.StandardParser @@ -61,33 +70,82 @@ func init() { panic(err) } - CloudFormationCmd.AddCommand(newOperationCommand("render", "Render the local template client-side (no API calls)")) - CloudFormationCmd.AddCommand(newOperationCommand("plan", "Preview changes an apply would make")) - CloudFormationCmd.AddCommand(newOperationCommand("diff", "Show changes an apply would make")) - CloudFormationCmd.AddCommand(newOperationCommand("apply", "Create or update the stack")) - CloudFormationCmd.AddCommand(newOperationCommand("deploy", "Apply with --auto-approve")) - CloudFormationCmd.AddCommand(newOperationCommand("delete", "Delete the stack")) - CloudFormationCmd.AddCommand(newOperationCommand("validate", "Validate the template server-side")) - outputCmd := newOperationCommand("output", "Show the deployed stack's Outputs") + CloudFormationCmd.AddCommand(newOperationCommand("render", "render", "Render the local template client-side (no API calls)")) + CloudFormationCmd.AddCommand(newOperationCommand("plan", "diff", "Preview changes an apply would make")) + CloudFormationCmd.AddCommand(newOperationCommand("diff", "diff", "Show changes an apply would make")) + CloudFormationCmd.AddCommand(newOperationCommand(subCommandApply, subCommandApply, "Create or update the stack")) + CloudFormationCmd.AddCommand(newOperationCommand("deploy", subCommandApply, "Apply with --auto-approve")) + CloudFormationCmd.AddCommand(newOperationCommand(subCommandDelete, subCommandDelete, "Delete the stack")) + CloudFormationCmd.AddCommand(newOperationCommand("validate", "validate", "Validate the template server-side")) + outputCmd := newOperationCommand("output", "output", "Show the deployed stack's Outputs") outputCmd.Aliases = []string{"outputs"} CloudFormationCmd.AddCommand(outputCmd) + CloudFormationCmd.AddCommand(newChangesetCmd()) + CloudFormationCmd.AddCommand(newDriftCmd()) + CloudFormationCmd.AddCommand(newGetCmd()) +} + +// newChangesetCmd is the `atmos aws cloudformation changeset` verb group: manual +// control over changesets, complementing apply/deploy/diff's implicit flow. +func newChangesetCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "changeset", + Short: "Manage aws/cloudformation changesets directly", + RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() }, + } + cmd.AddCommand(newOperationCommand("create", "changeset-create", "Create a changeset and leave it for later review/execution")) + cmd.AddCommand(newOperationCommand("execute", "changeset-execute", "Execute a previously-created, named changeset")) + cmd.AddCommand(newOperationCommand("list", "changeset-list", "List a stack's changesets")) + cmd.AddCommand(newOperationCommand(subCommandDelete, "changeset-delete", "Delete a named changeset")) + return cmd +} + +// newDriftCmd is the `atmos aws cloudformation drift` verb group. +func newDriftCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "drift", + Short: "Detect and describe drift against a deployed stack", + RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() }, + } + cmd.AddCommand(newOperationCommand("detect", "drift-detect", "Run drift detection against the deployed stack")) + cmd.AddCommand(newOperationCommand("describe", "drift-describe", "Show the results of the most recent drift detection")) + return cmd } -func newOperationCommand(name, short string) *cobra.Command { +// newGetCmd is the `atmos aws cloudformation get` verb group. +func newGetCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "get", + Short: "Fetch a deployed stack's template or policy", + RunE: func(cmd *cobra.Command, _ []string) error { return cmd.Usage() }, + } + cmd.AddCommand(newOperationCommand("template", "get-template", "Fetch the deployed stack's template")) + cmd.AddCommand(newOperationCommand("policy", "get-policy", "Fetch the deployed stack's policy")) + return cmd +} + +// newOperationCommand builds an `atmos aws cloudformation [component]` +// command (optionally nested under a verb group, e.g. `changeset create`). +// Use is the cobra command name (what the user types); subCommand is the +// internal Operation-dispatch identifier passed to provider.Execute (e.g. +// "changeset-create") and to operationFlagOptions/getOperationFlags — they +// differ for grouped verbs, where the same subCommand can be reached under a +// friendlier use (e.g. "plan" and "diff" both dispatch as "diff"). +func newOperationCommand(use, subCommand, short string) *cobra.Command { var parser *flags.StandardParser cmd := &cobra.Command{ - Use: name + " [component]", + Use: use + " [component]", Short: short, RunE: func(cmd *cobra.Command, args []string) error { parsed, err := parser.Parse(context.Background(), args) if err != nil { return err } - return runOperation(cmd, name, parsed.GetPositionalArgs()) + return runOperation(cmd, subCommand, parsed.GetPositionalArgs()) }, } - options := operationFlagOptions(name) + options := operationFlagOptions(use, subCommand) options = append(options, flags.WithConditionalPositionalArgPrompt( "component", "Choose an aws/cloudformation component", @@ -114,8 +172,12 @@ func newOperationCommand(name, short string) *cobra.Command { // operationFlagOptions returns the standard-parser options for an // aws/cloudformation operation command: the shared selection/affected flags -// plus operation-specific flags. -func operationFlagOptions(name string) []flags.Option { +// plus operation-specific flags. Use is the cobra command name (only needed to +// distinguish apply's and deploy's differing --auto-approve default); +// subCommand is the unique Operation-dispatch identifier every other switch +// below keys on (use alone collides across verb groups, e.g. top-level +// `delete` and `changeset delete`). +func operationFlagOptions(use, subCommand string) []flags.Option { options := []flags.Option{ flags.WithBoolFlag(flagAll, "", false, "Process all aws/cloudformation components in dependency order."), flags.WithBoolFlag(flagAffected, "", false, "Process affected aws/cloudformation components in dependency order."), @@ -130,30 +192,52 @@ func operationFlagOptions(name string) []flags.Option { flags.WithStringSliceFlag(flagTags, "", nil, "Filter by tags (comma-separated, matches any): --tags=production,tier-1"), flags.WithStringFlag(flagLabels, "", "", "Filter by labels (comma-separated key=value or key:value pairs, matches all): --labels=cost-center=platform,compliance=sox"), } + options = append(options, operationSpecificFlagOptions(use, subCommand)...) + return options +} - if name == "apply" || name == "deploy" || name == "delete" { - options = append(options, flags.WithBoolFlag("auto-approve", "", name == "deploy", "Skip interactive confirmation.")) - } - if name == "apply" || name == "deploy" { - options = append(options, flags.WithStringFlag("target", "", "", "Provision target to deliver to. Defaults to provision.default, otherwise the implicit direct-deploy target.")) - } - if name == "delete" { - options = append( - options, +// operationSpecificFlagOptions returns the flags specific to one operation, +// split out of operationFlagOptions to keep its cyclomatic complexity low. +func operationSpecificFlagOptions(use, subCommand string) []flags.Option { + switch subCommand { + case subCommandApply: + options := []flags.Option{ + flags.WithBoolFlag(flagAutoApprove, "", use == "deploy", "Skip interactive confirmation."), + flags.WithStringFlag("target", "", "", "Provision target to deliver to. Defaults to provision.default, otherwise the implicit direct-deploy target."), + } + return options + case subCommandDelete: + return []flags.Option{ + flags.WithBoolFlag(flagAutoApprove, "", false, "Skip interactive confirmation."), flags.WithStringSliceFlag("retain-resources", "", nil, "Logical IDs of resources to retain (only valid for a DELETE_FAILED stack)."), flags.WithBoolFlag("disable-termination-protection", "", false, "Disable termination protection before deleting (never done silently)."), - ) - } - if name == "output" { - options = append( - options, + } + case "output": + return []flags.Option{ flags.WithStringFlag("format", "", "table", "Output format: json|yaml|hcl|env|dotenv|bash|csv|tsv|table|github."), flags.WithBoolFlag("flatten", "", false, "Flatten nested Outputs into compound keys."), flags.WithBoolFlag("uppercase", "", false, "Uppercase Output keys."), - ) + } + case "changeset-execute": + return []flags.Option{ + flags.WithRequiredStringFlag("changeset-name", "", "Name of the changeset to execute."), + flags.WithBoolFlag(flagAutoApprove, "", false, "Skip interactive confirmation."), + } + case "changeset-delete": + return []flags.Option{ + flags.WithRequiredStringFlag("changeset-name", "", "Name of the changeset to delete."), + } + case "drift-detect": + return []flags.Option{ + flags.WithBoolFlag("fail-on-drift", "", false, "Exit non-zero if drift is detected (for CI)."), + } + case "get-template": + return []flags.Option{ + flags.WithBoolFlag("original", "", false, "Fetch the user-submitted template instead of the processed one."), + } + default: + return nil } - - return options } func validateOperationArgs(cmd *cobra.Command, args []string) error { @@ -235,12 +319,12 @@ func runOperation(cmd *cobra.Command, subCommand string, args []string) error { func getOperationFlags(cmd *cobra.Command) map[string]any { result := make(map[string]any) - for _, name := range []string{flagAll, flagAffected, "include-dependents", "clone-target-ref", "auto-approve", "disable-termination-protection", "flatten", "uppercase"} { + for _, name := range []string{flagAll, flagAffected, "include-dependents", "clone-target-ref", flagAutoApprove, "disable-termination-protection", "flatten", "uppercase", "fail-on-drift", "original"} { if flag := cmd.Flag(name); flag != nil { result[name] = flag.Value.String() == valueTrue } } - for _, name := range []string{"repo-path", "base", "ref", "sha", "ssh-key", "ssh-key-password", "target", "format"} { + for _, name := range []string{"repo-path", "base", "ref", "sha", "ssh-key", "ssh-key-password", "target", "format", "changeset-name"} { if flag := cmd.Flag(name); flag != nil { result[name] = flag.Value.String() } diff --git a/cmd/list/utils.go b/cmd/list/utils.go index ad660abb1de..b5077d30430 100644 --- a/cmd/list/utils.go +++ b/cmd/list/utils.go @@ -273,6 +273,7 @@ func skipCredentialBackedYAMLFunctionsForInventory(skip []string, authManager au u.AtmosYamlFuncAwsCallerIdentityUserID, u.AtmosYamlFuncAwsRegion, u.AtmosYamlFuncAwsOrganizationID, + u.AtmosYamlFuncAwsCloudFormationOutput, } { name := strings.TrimPrefix(functionName, "!") if !containsString(merged, name) { diff --git a/errors/errors.go b/errors/errors.go index 5b79fb8b9e8..1b6e7f5d221 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1621,6 +1621,7 @@ var ( ErrInvalidComponentsAwsCloudFormation = errors.New("invalid 'components.aws/cloudformation' section") ErrInvalidSpecificAwsCloudFormationComponent = errors.New("invalid aws/cloudformation component configuration") ErrAwsCloudFormationChangeSetFailed = errors.New("aws/cloudformation changeset failed") + ErrAwsCloudFormationChangeSetNotFound = errors.New("aws/cloudformation changeset not found") ErrAwsCloudFormationDriftDetected = errors.New("aws/cloudformation stack has drifted") ErrAwsCloudFormationFlagsMutuallyExclusive = errors.New("--all and --affected are mutually exclusive") ErrAwsCloudFormationComponentArgWithSelection = errors.New("component argument cannot be used with --all, --affected, --tags, or --labels") diff --git a/internal/exec/cloudformation_output_getter.go b/internal/exec/cloudformation_output_getter.go new file mode 100644 index 00000000000..4152580e71a --- /dev/null +++ b/internal/exec/cloudformation_output_getter.go @@ -0,0 +1,94 @@ +package exec + +import ( + "context" + "fmt" + + errUtils "github.com/cloudposse/atmos/errors" + awscfn "github.com/cloudposse/atmos/pkg/aws/cloudformation" + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/perf" + "github.com/cloudposse/atmos/pkg/schema" +) + +// CloudFormationOutputsGetter defines the interface for getting a deployed +// aws/cloudformation stack's Outputs. This interface allows dependency +// injection and testing, mirroring TerraformOutputGetter. +type CloudFormationOutputsGetter interface { + GetOutputs(ctx context.Context, region, stackName string, authContext *schema.AWSAuthContext) (map[string]any, error) +} + +// defaultCloudFormationOutputsGetter delegates to pkg/aws/cloudformation, a +// small leaf package that's allowed to import the AWS SDK directly (unlike +// internal/exec, which the provider-agnostic-auth depguard rule keeps +// cloud-SDK-free) and that pkg/component/aws/cloudformation cannot be reused +// for here: that package already imports internal/exec, so the reverse import +// would cycle. +type defaultCloudFormationOutputsGetter struct{} + +func (defaultCloudFormationOutputsGetter) GetOutputs( + ctx context.Context, + region, stackName string, + authContext *schema.AWSAuthContext, +) (map[string]any, error) { + defer perf.Track(nil, "exec.defaultCloudFormationOutputsGetter.GetOutputs")() + + return awscfn.GetOutputs(ctx, region, stackName, authContext) +} + +// cloudFormationOutputsGetter is replaceable in tests. +var cloudFormationOutputsGetter CloudFormationOutputsGetter = defaultCloudFormationOutputsGetter{} + +// GetCloudFormationOutputs fetches a deployed aws/cloudformation stack's +// Outputs, keyed by Output name. Used by both the `!aws.cloudformation.output` +// YAML function and atmos.Component(...).outputs for a CFN target. +func GetCloudFormationOutputs(ctx context.Context, region, stackName string, authContext *schema.AWSAuthContext) (map[string]any, error) { + defer perf.Track(nil, "exec.GetCloudFormationOutputs")() + + return cloudFormationOutputsGetter.GetOutputs(ctx, region, stackName, authContext) +} + +// resolveCloudFormationRegion returns the explicit region override, if any, +// from a target component's `settings.aws_cloudformation.region` — the same +// precedence source pkg/component/aws/cloudformation's own resolveRegion reads +// (duplicated here rather than imported: that package already imports +// internal/exec, so the reverse import would cycle). +func resolveCloudFormationRegion(sections map[string]any) string { + settings, ok := sections[cfg.SettingsSectionName].(map[string]any) + if !ok { + return "" + } + cfnSettings, ok := settings["aws_cloudformation"].(map[string]any) + if !ok { + return "" + } + region, _ := cfnSettings["region"].(string) + return region +} + +// cloudFormationOutputsForSections resolves a target aws/cloudformation +// component's stack_name and region from its already-described sections, and +// fetches its deployed Outputs using the resolved AuthContext (the target's +// own auth when it authenticates independently, otherwise the enclosing +// component's — callers resolve this via resolveNestedOutputAuth / +// resolveComponentFuncAuthManager before calling in). +func cloudFormationOutputsForSections( + atmosConfig *schema.AtmosConfiguration, + component string, + sections map[string]any, + authContext *schema.AuthContext, +) (map[string]any, error) { + defer perf.Track(atmosConfig, "exec.cloudFormationOutputsForSections")() + + stackName, _ := sections[cfg.StackNameSectionName].(string) + if stackName == "" { + return nil, fmt.Errorf("%w: component %q has no stack_name", errUtils.ErrMissingAwsCloudFormationStackName, component) + } + + var awsAuthContext *schema.AWSAuthContext + if authContext != nil { + awsAuthContext = authContext.AWS + } + + return GetCloudFormationOutputs(context.Background(), resolveCloudFormationRegion(sections), stackName, awsAuthContext) +} diff --git a/internal/exec/template_funcs_component.go b/internal/exec/template_funcs_component.go index 9dc50777799..967b591b417 100644 --- a/internal/exec/template_funcs_component.go +++ b/internal/exec/template_funcs_component.go @@ -139,6 +139,18 @@ func componentFunc( } sections = lo.Assign(sections, outputs) + } else if componentType == cfg.CloudFormationComponentType { + var cfnAuthContext *schema.AuthContext + if resolvedAuthMgr != nil { + if si := resolvedAuthMgr.GetStackInfo(); si != nil { + cfnAuthContext = si.AuthContext + } + } + cfnOutputs, err := cloudFormationOutputsForSections(atmosConfig, component, sections, cfnAuthContext) + if err != nil { + return nil, fmt.Errorf("atmos.Component(%s, %s) failed to get aws/cloudformation outputs: %w", component, stack, err) + } + sections = lo.Assign(sections, map[string]any{cfg.OutputsSectionName: cfnOutputs}) } // Cache the result diff --git a/internal/exec/yaml_func_aws.go b/internal/exec/yaml_func_aws.go index d924f66dd52..c86fdc09ed6 100644 --- a/internal/exec/yaml_func_aws.go +++ b/internal/exec/yaml_func_aws.go @@ -2,10 +2,13 @@ package exec import ( "context" + "fmt" errUtils "github.com/cloudposse/atmos/errors" awsIdentity "github.com/cloudposse/atmos/pkg/aws/identity" awsOrg "github.com/cloudposse/atmos/pkg/aws/organization" + cfg "github.com/cloudposse/atmos/pkg/config" + fnparser "github.com/cloudposse/atmos/pkg/function/parser" log "github.com/cloudposse/atmos/pkg/logger" "github.com/cloudposse/atmos/pkg/perf" "github.com/cloudposse/atmos/pkg/schema" @@ -199,3 +202,84 @@ func processTagAwsOrganizationID( log.Debug("Resolved !aws.organization_id", "organization_id", orgInfo.ID) return orgInfo.ID } + +// parseAwsCloudFormationOutputArgs parses `!aws.cloudformation.output`'s +// `component [stack] output-key` arguments, defaulting Stack to currentStack +// when omitted. The result's Expression field holds the output key. +func parseAwsCloudFormationOutputArgs(input, currentStack string) (fnparser.TerraformArgs, error) { + str, err := getStringAfterTag(input, u.AtmosYamlFuncAwsCloudFormationOutput) + if err != nil { + return fnparser.TerraformArgs{}, err + } + + parsed, err := fnparser.ParseTerraform(str) + if err != nil { + return fnparser.TerraformArgs{}, err + } + if parsed.Stack == "" { + parsed.Stack = currentStack + } + return parsed, nil +} + +// processTagAwsCloudFormationOutputWithContext processes the +// `!aws.cloudformation.output` YAML tag: the Terraform<->CloudFormation +// interop bridge, sibling to !terraform.output. Syntax is `component [stack] +// output-key`, reusing the same "component [stack] expression" grammar +// (fnparser.ParseTerraform is not Terraform-specific despite the name — it's +// this shared 2-3-token shape). +func processTagAwsCloudFormationOutputWithContext( + atmosConfig *schema.AtmosConfiguration, + input string, + currentStack string, + resolutionCtx *ResolutionContext, + stackInfo *schema.ConfigAndStacksInfo, +) (any, error) { + defer perf.Track(atmosConfig, "exec.processTagAwsCloudFormationOutputWithContext")() + + log.Debug(execAWSYAMLFunction, functionKey, input) + + parsed, err := parseAwsCloudFormationOutputArgs(input, currentStack) + if err != nil { + return nil, err + } + component, stack, output := parsed.Component, parsed.Stack, parsed.Expression + + cleanup, err := trackOutputDependency(atmosConfig, resolutionCtx, component, stack, input) + if err != nil { + return nil, err + } + defer cleanup() + + var authContext *schema.AuthContext + var authManager any + if stackInfo != nil { + authContext = stackInfo.AuthContext + authManager = stackInfo.AuthManager + } + resolvedAuthContext, _ := resolveNestedOutputAuth( + atmosConfig, component, stack, authContext, authManager, resolveAuthManagerForNestedComponent, + ) + + sections, err := ExecuteDescribeComponent(&ExecuteDescribeComponentParams{ + Component: component, + Stack: stack, + ComponentType: cfg.CloudFormationComponentType, + ProcessTemplates: true, + ProcessYamlFunctions: true, + }) + if err != nil { + return nil, fmt.Errorf("failed to describe aws/cloudformation component %s in stack %s: %w", component, stack, err) + } + + outputs, err := cloudFormationOutputsForSections(atmosConfig, component, sections, resolvedAuthContext) + if err != nil { + return nil, fmt.Errorf("failed to get aws/cloudformation output for component %s in stack %s, output %s: %w", component, stack, output, err) + } + + value, exists := outputs[output] + if !exists { + return nil, nil + } + return value, nil +} diff --git a/internal/exec/yaml_func_utils.go b/internal/exec/yaml_func_utils.go index 317625e8f6b..d337db969b0 100644 --- a/internal/exec/yaml_func_utils.go +++ b/internal/exec/yaml_func_utils.go @@ -292,6 +292,10 @@ func processContextAwareTags( result, err := processTagTerraformStateWithContext(atmosConfig, input, currentStack, resolutionCtx, stackInfo) return result, true, err } + if matchesPrefix(input, u.AtmosYamlFuncAwsCloudFormationOutput, skip) { + result, err := processTagAwsCloudFormationOutputWithContext(atmosConfig, input, currentStack, resolutionCtx, stackInfo) + return result, true, err + } return nil, false, nil } diff --git a/pkg/aws/cloudformation/outputs.go b/pkg/aws/cloudformation/outputs.go new file mode 100644 index 00000000000..c68383afa56 --- /dev/null +++ b/pkg/aws/cloudformation/outputs.go @@ -0,0 +1,61 @@ +// Package cloudformation provides a minimal, direct AWS SDK v2 read of a +// deployed CloudFormation stack's Outputs, for consumers outside +// pkg/component/aws/cloudformation (which already owns the full CFN component +// implementation but cannot be imported back into internal/exec — it imports +// internal/exec itself). Kept intentionally narrow: a single DescribeStacks +// call, mirroring pkg/aws/identity's and pkg/aws/organization's shape as a +// small, provider-specific leaf package. +package cloudformation + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/aws/identity" + "github.com/cloudposse/atmos/pkg/perf" + "github.com/cloudposse/atmos/pkg/schema" +) + +// GetOutputs fetches a deployed CloudFormation stack's Outputs, keyed by +// Output name. AuthContext's EndpointURL (when set) is honored so this also +// reaches a Floci-emulated CloudFormation endpoint, matching +// pkg/component/aws/cloudformation's own client construction. +func GetOutputs(ctx context.Context, region, stackName string, authContext *schema.AWSAuthContext) (map[string]any, error) { + defer perf.Track(nil, "cloudformation.GetOutputs")() + + awsCfg, err := identity.LoadConfigWithAuth(ctx, region, "", 0, authContext) + if err != nil { + return nil, err + } + + var optFns []func(*cloudformation.Options) + if authContext != nil && authContext.EndpointURL != "" { + optFns = append(optFns, func(o *cloudformation.Options) { o.BaseEndpoint = aws.String(authContext.EndpointURL) }) + } + + client := cloudformation.NewFromConfig(awsCfg, optFns...) + out, err := client.DescribeStacks(ctx, &cloudformation.DescribeStacksInput{StackName: aws.String(stackName)}) + if err != nil { + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + if len(out.Stacks) == 0 { + return nil, fmt.Errorf("%w: stack %q", errUtils.ErrAwsCloudFormationChangeSetFailed, stackName) + } + + outputs := make(map[string]any, len(out.Stacks[0].Outputs)) + for _, o := range out.Stacks[0].Outputs { + if o.OutputKey == nil { + continue + } + var value any + if o.OutputValue != nil { + value = *o.OutputValue + } + outputs[*o.OutputKey] = value + } + return outputs, nil +} diff --git a/pkg/component/aws/cloudformation/changeset_verbs.go b/pkg/component/aws/cloudformation/changeset_verbs.go new file mode 100644 index 00000000000..f0819b9e109 --- /dev/null +++ b/pkg/component/aws/cloudformation/changeset_verbs.go @@ -0,0 +1,153 @@ +package cloudformation + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/data" + "github.com/cloudposse/atmos/pkg/perf" +) + +// listChangeSets returns every changeset for a stack, paginating through +// ListChangeSets until CloudFormation stops returning a NextToken. +func listChangeSets(ctx context.Context, client CloudFormationClient, stackName string) ([]cfntypes.ChangeSetSummary, error) { + defer perf.Track(nil, "cloudformation.listChangeSets")() + + var summaries []cfntypes.ChangeSetSummary + var nextToken *string + for { + out, err := client.ListChangeSets(ctx, &cloudformation.ListChangeSetsInput{ + StackName: awsString(stackName), + NextToken: nextToken, + }) + if err != nil { + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + summaries = append(summaries, out.Summaries...) + if out.NextToken == nil { + return summaries, nil + } + nextToken = out.NextToken + } +} + +// deleteChangeSet deletes a named changeset without touching the stack itself. +func deleteChangeSet(ctx context.Context, client CloudFormationClient, stackName, changeSetName string) error { + defer perf.Track(nil, "cloudformation.deleteChangeSet")() + + _, err := client.DeleteChangeSet(ctx, &cloudformation.DeleteChangeSetInput{ + StackName: awsString(stackName), + ChangeSetName: awsString(changeSetName), + }) + if err != nil { + return fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + return nil +} + +// describeNamedChangeSet fetches a previously-created changeset by name, for the +// `changeset execute`/`changeset delete` verbs, which act on an existing changeset +// rather than creating a fresh one (unlike apply/deploy/diff/plan). +func describeNamedChangeSet(ctx context.Context, client CloudFormationClient, stackName, changeSetName string) (*changeSetResult, error) { + defer perf.Track(nil, "cloudformation.describeNamedChangeSet")() + + out, err := client.DescribeChangeSet(ctx, &cloudformation.DescribeChangeSetInput{ + ChangeSetName: awsString(changeSetName), + StackName: awsString(stackName), + }) + if err != nil { + if isStackNotFoundError(err) { + return nil, fmt.Errorf("%w: %q on stack %q", errUtils.ErrAwsCloudFormationChangeSetNotFound, changeSetName, stackName) + } + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + + return &changeSetResult{ + ChangeSetID: stringValue(out.ChangeSetId), + ChangeSetName: changeSetName, + StackID: stringValue(out.StackId), + Status: out.Status, + StatusReason: stringValue(out.StatusReason), + Changes: out.Changes, + }, nil +} + +// runChangesetCreate creates a changeset and leaves it in place for later manual +// review/execution — the explicit-control complement to diff/plan's implicit, +// preview-only changeset (which is also left in place, but framed as a preview +// rather than a named, reusable artifact). +func runChangesetCreate(ctx context.Context, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + result, err := createChangeSet(ctx, client, spec) + if err != nil { + return summary, err + } + summary["changeset_id"] = result.ChangeSetID + summary["changeset_name"] = result.ChangeSetName + summary["no_op"] = result.NoOp + summary["changes"] = result.Changes + renderDiffSummary(spec.StackName, result) + if !result.NoOp { + _ = data.Writeln(fmt.Sprintf("changeset: %s", result.ChangeSetName)) + } + return summary, nil +} + +// runChangesetExecute executes a previously-created, named changeset and streams +// stack events until the operation reaches a terminal state. +func runChangesetExecute(ctx context.Context, client CloudFormationClient, spec *stackSpec, changeSetName string, summary map[string]any) (map[string]any, error) { + result, err := describeNamedChangeSet(ctx, client, spec.StackName, changeSetName) + if err != nil { + return summary, err + } + summary["changeset_id"] = result.ChangeSetID + summary["changeset_name"] = result.ChangeSetName + + if err := executeChangeSet(ctx, client, spec, result); err != nil { + return summary, err + } + + status, err := streamStackEvents(ctx, client, spec.StackName) + if err != nil { + return summary, err + } + summary["final_status"] = string(status) + if isFailedStackStatus(status) { + return summary, fmt.Errorf("%w: stack %s ended in status %s", errUtils.ErrAwsCloudFormationChangeSetFailed, spec.StackName, status) + } + return summary, nil +} + +// runChangesetList lists a stack's changesets, newest first (ListChangeSets' +// own ordering), rendering each one's name, status, and creation time. +func runChangesetList(ctx context.Context, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + summaries, err := listChangeSets(ctx, client, spec.StackName) + if err != nil { + return summary, err + } + summary["changesets"] = summaries + + if len(summaries) == 0 { + _ = data.Writeln(fmt.Sprintf("%s: no changesets", spec.StackName)) + return summary, nil + } + for i := range summaries { + cs := &summaries[i] + line := fmt.Sprintf("%-40s %-20s %s", stringValue(cs.ChangeSetName), cs.Status, stringValue(cs.Description)) + _ = data.Writeln(line) + } + return summary, nil +} + +// runChangesetDelete deletes a named changeset without touching the stack. +func runChangesetDelete(ctx context.Context, client CloudFormationClient, spec *stackSpec, changeSetName string, summary map[string]any) (map[string]any, error) { + if err := deleteChangeSet(ctx, client, spec.StackName, changeSetName); err != nil { + return summary, err + } + summary["changeset_name"] = changeSetName + _ = data.Writeln(fmt.Sprintf("changeset %q deleted", changeSetName)) + return summary, nil +} diff --git a/pkg/component/aws/cloudformation/client.go b/pkg/component/aws/cloudformation/client.go index f4e3c30953e..c4f1cf6d48a 100644 --- a/pkg/component/aws/cloudformation/client.go +++ b/pkg/component/aws/cloudformation/client.go @@ -9,23 +9,31 @@ import ( "github.com/cloudposse/atmos/pkg/perf" ) -// CloudFormationClient is the narrow subset of the AWS SDK v2 CloudFormation API -// used by this component type. Phase 1 covers the core lifecycle (changeset-driven -// apply/deploy, delete, validate, describe); later phases extend this interface -// (drift, stack sets, GetTemplate/GetStackPolicy, ListStacks) without touching -// callers that only need the Phase 1 subset. +// CloudFormationClient is the subset of the AWS SDK v2 CloudFormation API used +// by this component type. Phase 1 covered the core lifecycle (changeset-driven +// apply/deploy, delete, validate, describe); Phase 2 adds explicit changeset +// management, drift detection, template/policy retrieval, and account-wide +// listing. Stack sets remain out of scope (Phase 3). // //go:generate go run go.uber.org/mock/mockgen@v0.6.0 -destination=mock_client_test.go -package=cloudformation -source=client.go CloudFormationClient type CloudFormationClient interface { CreateChangeSet(ctx context.Context, params *cloudformation.CreateChangeSetInput, optFns ...func(*cloudformation.Options)) (*cloudformation.CreateChangeSetOutput, error) DescribeChangeSet(ctx context.Context, params *cloudformation.DescribeChangeSetInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeChangeSetOutput, error) ExecuteChangeSet(ctx context.Context, params *cloudformation.ExecuteChangeSetInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ExecuteChangeSetOutput, error) + ListChangeSets(ctx context.Context, params *cloudformation.ListChangeSetsInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ListChangeSetsOutput, error) + DeleteChangeSet(ctx context.Context, params *cloudformation.DeleteChangeSetInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DeleteChangeSetOutput, error) DescribeStacks(ctx context.Context, params *cloudformation.DescribeStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) DescribeStackEvents(ctx context.Context, params *cloudformation.DescribeStackEventsInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStackEventsOutput, error) DeleteStack(ctx context.Context, params *cloudformation.DeleteStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DeleteStackOutput, error) ValidateTemplate(ctx context.Context, params *cloudformation.ValidateTemplateInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ValidateTemplateOutput, error) UpdateTerminationProtection(ctx context.Context, params *cloudformation.UpdateTerminationProtectionInput, optFns ...func(*cloudformation.Options)) (*cloudformation.UpdateTerminationProtectionOutput, error) SetStackPolicy(ctx context.Context, params *cloudformation.SetStackPolicyInput, optFns ...func(*cloudformation.Options)) (*cloudformation.SetStackPolicyOutput, error) + GetTemplate(ctx context.Context, params *cloudformation.GetTemplateInput, optFns ...func(*cloudformation.Options)) (*cloudformation.GetTemplateOutput, error) + GetStackPolicy(ctx context.Context, params *cloudformation.GetStackPolicyInput, optFns ...func(*cloudformation.Options)) (*cloudformation.GetStackPolicyOutput, error) + ListStacks(ctx context.Context, params *cloudformation.ListStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ListStacksOutput, error) + DetectStackDrift(ctx context.Context, params *cloudformation.DetectStackDriftInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DetectStackDriftOutput, error) + DescribeStackDriftDetectionStatus(ctx context.Context, params *cloudformation.DescribeStackDriftDetectionStatusInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStackDriftDetectionStatusOutput, error) + DescribeStackResourceDrifts(ctx context.Context, params *cloudformation.DescribeStackResourceDriftsInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStackResourceDriftsOutput, error) } // newClient constructs the real AWS SDK v2 CloudFormation client from a resolved diff --git a/pkg/component/aws/cloudformation/cloudformation.go b/pkg/component/aws/cloudformation/cloudformation.go index f6f03c73b92..351c3f58ad2 100644 --- a/pkg/component/aws/cloudformation/cloudformation.go +++ b/pkg/component/aws/cloudformation/cloudformation.go @@ -81,26 +81,40 @@ func (p *ComponentProvider) ValidateComponent(config map[string]any) error { return validateComponentConfig(config) } +// subCommandOperations maps every CLI subcommand string (including aliases) to +// the Operation it dispatches. A map keeps Execute a flat lookup instead of a +// long switch, and gives each subcommand's Operation a single source of truth +// shared with the CLI layer. +var subCommandOperations = map[string]Operation{ + "render": OperationRender, + "diff": OperationDiff, + "plan": OperationDiff, + "apply": OperationApply, + "deploy": OperationApply, + "delete": OperationDelete, + "destroy": OperationDelete, + "validate": OperationValidate, + "output": OperationOutput, + "outputs": OperationOutput, + "changeset-create": OperationChangesetCreate, + "changeset-execute": OperationChangesetExecute, + "changeset-list": OperationChangesetList, + "changeset-delete": OperationChangesetDelete, + "drift-detect": OperationDriftDetect, + "drift-describe": OperationDriftDescribe, + "get-template": OperationGetTemplate, + "get-policy": OperationGetPolicy, +} + // Execute runs the requested subcommand for an aws/cloudformation component. func (p *ComponentProvider) Execute(ctx *component.ExecutionContext) error { defer perf.Track(ctx.AtmosConfig, "cloudformation.Execute")() - switch ctx.SubCommand { - case "render": - return executeOperation(ctx, OperationRender) - case "diff", "plan": - return executeOperation(ctx, OperationDiff) - case "apply", "deploy": - return executeOperation(ctx, OperationApply) - case "delete", "destroy": - return executeOperation(ctx, OperationDelete) - case "validate": - return executeOperation(ctx, OperationValidate) - case "output", "outputs": - return executeOperation(ctx, OperationOutput) - default: + operation, ok := subCommandOperations[ctx.SubCommand] + if !ok { return fmt.Errorf("%w: %q", errUtils.ErrInvalidSpecificAwsCloudFormationComponent, ctx.SubCommand) } + return executeOperation(ctx, operation) } // GenerateArtifacts is a no-op for aws/cloudformation components (the template @@ -113,5 +127,9 @@ func (p *ComponentProvider) GenerateArtifacts(_ *component.ExecutionContext) err // GetAvailableCommands returns the subcommands aws/cloudformation components support. func (p *ComponentProvider) GetAvailableCommands() []string { defer perf.Track(nil, "cloudformation.GetAvailableCommands")() - return []string{"render", "diff", "plan", "apply", "deploy", "delete", "validate", "output"} + return []string{ + "render", "diff", "plan", "apply", "deploy", "delete", "validate", "output", + "changeset-create", "changeset-execute", "changeset-list", "changeset-delete", + "drift-detect", "drift-describe", "get-template", "get-policy", + } } diff --git a/pkg/component/aws/cloudformation/confirm.go b/pkg/component/aws/cloudformation/confirm.go index afad74e09c7..a550f885070 100644 --- a/pkg/component/aws/cloudformation/confirm.go +++ b/pkg/component/aws/cloudformation/confirm.go @@ -22,9 +22,20 @@ var confirmOperation = defaultConfirmOperation // Production code never reassigns this. var runConfirmField = func(f huh.Field) error { return f.Run() } +// confirmedOperationVerbs maps each mutating operation to the verb shown in its +// confirmation prompt. Operations absent from this map (render, diff, changeset +// create/list, drift, get, output) never require confirmation — they don't +// change a deployed stack's state. +var confirmedOperationVerbs = map[Operation]string{ + OperationApply: "apply", + OperationDelete: "delete", + OperationChangesetExecute: "execute changeset against", +} + // requireConfirmation prompts for the given operation unless auto-approve is set. func requireConfirmation(operation Operation, stackName string, flags map[string]any) error { - if operation != OperationApply && operation != OperationDelete { + verb, ok := confirmedOperationVerbs[operation] + if !ok { return nil } autoApprove, _ := flags["auto-approve"].(bool) @@ -32,10 +43,6 @@ func requireConfirmation(operation Operation, stackName string, flags map[string return nil } - verb := "apply" - if operation == OperationDelete { - verb = "delete" - } confirmed, err := confirmOperation(fmt.Sprintf("%s stack %q?", verb, stackName)) if err != nil { return err diff --git a/pkg/component/aws/cloudformation/drift.go b/pkg/component/aws/cloudformation/drift.go new file mode 100644 index 00000000000..eff23ac4d7c --- /dev/null +++ b/pkg/component/aws/cloudformation/drift.go @@ -0,0 +1,153 @@ +package cloudformation + +import ( + "context" + "fmt" + "time" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/data" + "github.com/cloudposse/atmos/pkg/perf" +) + +// driftPollInterval is how often DescribeStackDriftDetectionStatus is polled +// while a drift-detection operation is in progress. +const driftPollInterval = 3 * time.Second + +// driftDetectionTimeout bounds how long a single drift detection may run before +// this command gives up watching it. +const driftDetectionTimeout = 15 * time.Minute + +// driftDetectionResult is the outcome of running (or re-fetching the status of) +// a drift detection operation. +type driftDetectionResult struct { + DetectionID string + StackStatus cfntypes.StackDriftStatus + DriftedCount int32 + StatusReason string + DetectionDone bool +} + +// detectDrift starts a new drift detection operation and polls until it +// completes (or fails), returning the overall stack drift status. +func detectDrift(ctx context.Context, client CloudFormationClient, stackName string) (*driftDetectionResult, error) { + defer perf.Track(nil, "cloudformation.detectDrift")() + + out, err := client.DetectStackDrift(ctx, &cloudformation.DetectStackDriftInput{StackName: awsString(stackName)}) + if err != nil { + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationDriftDetected, err) + } + + detectionID := stringValue(out.StackDriftDetectionId) + return pollDriftDetection(ctx, client, detectionID) +} + +// pollDriftDetection polls DescribeStackDriftDetectionStatus until the detection +// operation reaches DETECTION_COMPLETE or DETECTION_FAILED. +func pollDriftDetection(ctx context.Context, client CloudFormationClient, detectionID string) (*driftDetectionResult, error) { + deadline := time.Now().Add(driftDetectionTimeout) + for { + out, err := client.DescribeStackDriftDetectionStatus(ctx, &cloudformation.DescribeStackDriftDetectionStatusInput{ + StackDriftDetectionId: awsString(detectionID), + }) + if err != nil { + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationDriftDetected, err) + } + + result := &driftDetectionResult{ + DetectionID: detectionID, + StackStatus: out.StackDriftStatus, + StatusReason: stringValue(out.DetectionStatusReason), + } + if out.DriftedStackResourceCount != nil { + result.DriftedCount = *out.DriftedStackResourceCount + } + + switch out.DetectionStatus { + case cfntypes.StackDriftDetectionStatusDetectionComplete: + result.DetectionDone = true + return result, nil + case cfntypes.StackDriftDetectionStatusDetectionFailed: + return result, fmt.Errorf("%w: %s", errUtils.ErrAwsCloudFormationDriftDetected, result.StatusReason) + } + + if time.Now().After(deadline) { + return result, fmt.Errorf("%w: timed out waiting for drift detection", errUtils.ErrAwsCloudFormationDriftDetected) + } + select { + case <-ctx.Done(): + return result, ctx.Err() + case <-time.After(driftPollInterval): + } + } +} + +// describeResourceDrifts fetches the per-resource drift details from the most +// recently completed drift detection for the stack (does not trigger a new +// detection — pair with detectDrift/runDriftDetect first for a fresh check). +func describeResourceDrifts(ctx context.Context, client CloudFormationClient, stackName string) ([]cfntypes.StackResourceDrift, error) { + defer perf.Track(nil, "cloudformation.describeResourceDrifts")() + + var drifts []cfntypes.StackResourceDrift + var nextToken *string + for { + out, err := client.DescribeStackResourceDrifts(ctx, &cloudformation.DescribeStackResourceDriftsInput{ + StackName: awsString(stackName), + NextToken: nextToken, + }) + if err != nil { + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationDriftDetected, err) + } + drifts = append(drifts, out.StackResourceDrifts...) + if out.NextToken == nil { + return drifts, nil + } + nextToken = out.NextToken + } +} + +// runDriftDetect triggers a fresh drift detection and renders the summary result. +// Returns ErrAwsCloudFormationDriftDetected when drift is found and failOnDrift is +// set, so callers can wire it to a non-zero exit code (e.g. `--fail-on-drift` in CI). +func runDriftDetect(ctx context.Context, client CloudFormationClient, stackName string, failOnDrift bool, summary map[string]any) (map[string]any, error) { + result, err := detectDrift(ctx, client, stackName) + if err != nil { + return summary, err + } + summary["drift_status"] = string(result.StackStatus) + summary["drifted_resource_count"] = result.DriftedCount + + _ = data.Writeln(fmt.Sprintf("%s: %s (%d resource(s) drifted)", stackName, result.StackStatus, result.DriftedCount)) + + if failOnDrift && result.StackStatus == cfntypes.StackDriftStatusDrifted { + return summary, fmt.Errorf("%w: %s", errUtils.ErrAwsCloudFormationDriftDetected, stackName) + } + return summary, nil +} + +// runDriftDescribe renders the per-resource results of the most recent drift +// detection without triggering a new one. +func runDriftDescribe(ctx context.Context, client CloudFormationClient, stackName string, summary map[string]any) (map[string]any, error) { + drifts, err := describeResourceDrifts(ctx, client, stackName) + if err != nil { + return summary, err + } + summary["drifts"] = drifts + + if len(drifts) == 0 { + _ = data.Writeln(fmt.Sprintf("%s: no drift results (run drift detect first)", stackName)) + return summary, nil + } + for i := range drifts { + d := &drifts[i] + if d.StackResourceDriftStatus == cfntypes.StackResourceDriftStatusInSync { + continue + } + line := fmt.Sprintf(" %-10s %-28s %s", d.StackResourceDriftStatus, stringValue(d.ResourceType), stringValue(d.LogicalResourceId)) + _ = data.Writeln(line) + } + return summary, nil +} diff --git a/pkg/component/aws/cloudformation/executor.go b/pkg/component/aws/cloudformation/executor.go index 139e1a30232..64e98a21caf 100644 --- a/pkg/component/aws/cloudformation/executor.go +++ b/pkg/component/aws/cloudformation/executor.go @@ -96,10 +96,25 @@ func executeSingle(ctx *component.ExecutionContext, atmosConfig *schema.AtmosCon return runWithHooks(ctx, atmosConfig, info, operation, spec) } +// operationsSkippingTemplateLoad are operations that act on a deployed stack by +// name/ID (delete, explicit changeset execute/list/delete, drift, get) and never +// send a local template to CloudFormation, so loading and reading the template +// file from disk would be pure overhead. +var operationsSkippingTemplateLoad = map[Operation]bool{ + OperationDelete: true, + OperationChangesetExecute: true, + OperationChangesetList: true, + OperationChangesetDelete: true, + OperationDriftDetect: true, + OperationDriftDescribe: true, + OperationGetTemplate: true, + OperationGetPolicy: true, +} + // resolveSpecAndTemplate resolves the component's on-disk path (including JIT // source provisioning), builds the SDK-ready stackSpec, and — for every -// operation except delete, which needs no template — loads the template body, -// registers NoEcho values with the masker, and loads the stack policy. +// operation that sends a local template to CloudFormation — loads the template +// body, registers NoEcho values with the masker, and loads the stack policy. func resolveSpecAndTemplate(atmosConfig *schema.AtmosConfiguration, info *schema.ConfigAndStacksInfo, operation Operation) (*stackSpec, error) { componentPath, err := resolveComponentPath(atmosConfig, info) if err != nil { @@ -115,7 +130,7 @@ func resolveSpecAndTemplate(atmosConfig *schema.AtmosConfiguration, info *schema return nil, err } - if operation == OperationDelete { + if operationsSkippingTemplateLoad[operation] { return spec, nil } @@ -166,6 +181,59 @@ func eventsFor(operation Operation) (hooks.HookEvent, hooks.HookEvent) { } } +// operationHandler runs one mutating/read operation against an already-built +// CloudFormationClient and stackSpec. +type operationHandler func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) + +// operationHandlers maps every non-render Operation to its handler. A map +// dispatch keeps runOperation a flat lookup instead of a long switch. +var operationHandlers = map[Operation]operationHandler{ + OperationValidate: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return summary, validateTemplate(octx.Ctx, client, spec.TemplateBody) + }, + OperationDiff: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runDiff(octx.Ctx, client, spec, summary) + }, + OperationApply: runApply, + OperationDelete: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runDelete(octx.Ctx, client, octx.Flags, spec, summary) + }, + OperationOutput: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runOutput(octx.Ctx, client, spec.StackName, octx.Flags, summary) + }, + OperationChangesetCreate: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runChangesetCreate(octx.Ctx, client, spec, summary) + }, + OperationChangesetExecute: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runChangesetExecute(octx.Ctx, client, spec, changesetNameFlag(octx.Flags), summary) + }, + OperationChangesetList: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runChangesetList(octx.Ctx, client, spec, summary) + }, + OperationChangesetDelete: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runChangesetDelete(octx.Ctx, client, spec, changesetNameFlag(octx.Flags), summary) + }, + OperationDriftDetect: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + failOnDrift, _ := octx.Flags["fail-on-drift"].(bool) + return runDriftDetect(octx.Ctx, client, spec.StackName, failOnDrift, summary) + }, + OperationDriftDescribe: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runDriftDescribe(octx.Ctx, client, spec.StackName, summary) + }, + OperationGetTemplate: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runGetTemplate(octx.Ctx, client, spec.StackName, octx.Flags, summary) + }, + OperationGetPolicy: func(octx *opContext, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { + return runGetPolicy(octx.Ctx, client, spec.StackName, summary) + }, +} + +// changesetNameFlag extracts the required --changeset-name flag value. +func changesetNameFlag(flags map[string]any) string { + name, _ := flags["changeset-name"].(string) + return name +} + // runOperation dispatches to the requested aws/cloudformation operation. func runOperation(octx *opContext, operation Operation, spec *stackSpec) (map[string]any, error) { summary := map[string]any{"stack_name": spec.StackName} @@ -186,20 +254,11 @@ func runOperation(octx *opContext, operation Operation, spec *stackSpec) (map[st } client := newClient(awsCfg, resolveEndpointURL(octx.Info)) - switch operation { - case OperationValidate: - return summary, validateTemplate(octx.Ctx, client, spec.TemplateBody) - case OperationDiff: - return runDiff(octx.Ctx, client, spec, summary) - case OperationApply: - return runApply(octx, client, spec, summary) - case OperationDelete: - return runDelete(octx.Ctx, client, octx.Flags, spec, summary) - case OperationOutput: - return runOutput(octx.Ctx, client, spec.StackName, octx.Flags, summary) - default: + handler, ok := operationHandlers[operation] + if !ok { return summary, fmt.Errorf("%w: %q", errUtils.ErrInvalidSpecificAwsCloudFormationComponent, operation) } + return handler(octx, client, spec, summary) } // runDiff creates (or reuses) a changeset and renders the predicted changes diff --git a/pkg/component/aws/cloudformation/get.go b/pkg/component/aws/cloudformation/get.go new file mode 100644 index 00000000000..647262647b0 --- /dev/null +++ b/pkg/component/aws/cloudformation/get.go @@ -0,0 +1,71 @@ +package cloudformation + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/data" + "github.com/cloudposse/atmos/pkg/perf" +) + +// getDeployedTemplate fetches a deployed stack's template body. Original selects +// the user-submitted template (TemplateStageOriginal); otherwise CloudFormation +// returns the fully-processed template (TemplateStageProcessed, its default) — +// the shape a diff against the local render should compare against. +func getDeployedTemplate(ctx context.Context, client CloudFormationClient, stackName string, original bool) (string, error) { + defer perf.Track(nil, "cloudformation.getDeployedTemplate")() + + input := &cloudformation.GetTemplateInput{StackName: awsString(stackName)} + if original { + input.TemplateStage = cfntypes.TemplateStageOriginal + } + + out, err := client.GetTemplate(ctx, input) + if err != nil { + return "", fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + return stringValue(out.TemplateBody), nil +} + +// getDeployedStackPolicy fetches a deployed stack's current stack policy. Returns +// "" (no error) when the stack has no policy set — CloudFormation's default. +func getDeployedStackPolicy(ctx context.Context, client CloudFormationClient, stackName string) (string, error) { + defer perf.Track(nil, "cloudformation.getDeployedStackPolicy")() + + out, err := client.GetStackPolicy(ctx, &cloudformation.GetStackPolicyInput{StackName: awsString(stackName)}) + if err != nil { + return "", fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + return stringValue(out.StackPolicyBody), nil +} + +// runGetTemplate renders the deployed stack's template to the data channel. +func runGetTemplate(ctx context.Context, client CloudFormationClient, stackName string, flags map[string]any, summary map[string]any) (map[string]any, error) { + original, _ := flags["original"].(bool) + body, err := getDeployedTemplate(ctx, client, stackName, original) + if err != nil { + return summary, err + } + summary["template"] = body + _ = data.Write(body) + return summary, nil +} + +// runGetPolicy renders the deployed stack's policy to the data channel. +func runGetPolicy(ctx context.Context, client CloudFormationClient, stackName string, summary map[string]any) (map[string]any, error) { + body, err := getDeployedStackPolicy(ctx, client, stackName) + if err != nil { + return summary, err + } + summary["stack_policy"] = body + if body == "" { + _ = data.Writeln(fmt.Sprintf("%s: no stack policy set", stackName)) + return summary, nil + } + _ = data.Write(body) + return summary, nil +} diff --git a/pkg/component/aws/cloudformation/mock_client_test.go b/pkg/component/aws/cloudformation/mock_client_test.go index 8c721c86911..182d6c9ada2 100644 --- a/pkg/component/aws/cloudformation/mock_client_test.go +++ b/pkg/component/aws/cloudformation/mock_client_test.go @@ -61,6 +61,26 @@ func (mr *MockCloudFormationClientMockRecorder) CreateChangeSet(ctx, params any, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChangeSet", reflect.TypeOf((*MockCloudFormationClient)(nil).CreateChangeSet), varargs...) } +// DeleteChangeSet mocks base method. +func (m *MockCloudFormationClient) DeleteChangeSet(ctx context.Context, params *cloudformation.DeleteChangeSetInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DeleteChangeSetOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteChangeSet", varargs...) + ret0, _ := ret[0].(*cloudformation.DeleteChangeSetOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteChangeSet indicates an expected call of DeleteChangeSet. +func (mr *MockCloudFormationClientMockRecorder) DeleteChangeSet(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeSet", reflect.TypeOf((*MockCloudFormationClient)(nil).DeleteChangeSet), varargs...) +} + // DeleteStack mocks base method. func (m *MockCloudFormationClient) DeleteStack(ctx context.Context, params *cloudformation.DeleteStackInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DeleteStackOutput, error) { m.ctrl.T.Helper() @@ -101,6 +121,26 @@ func (mr *MockCloudFormationClientMockRecorder) DescribeChangeSet(ctx, params an return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeChangeSet", reflect.TypeOf((*MockCloudFormationClient)(nil).DescribeChangeSet), varargs...) } +// DescribeStackDriftDetectionStatus mocks base method. +func (m *MockCloudFormationClient) DescribeStackDriftDetectionStatus(ctx context.Context, params *cloudformation.DescribeStackDriftDetectionStatusInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStackDriftDetectionStatusOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStackDriftDetectionStatus", varargs...) + ret0, _ := ret[0].(*cloudformation.DescribeStackDriftDetectionStatusOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeStackDriftDetectionStatus indicates an expected call of DescribeStackDriftDetectionStatus. +func (mr *MockCloudFormationClientMockRecorder) DescribeStackDriftDetectionStatus(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackDriftDetectionStatus", reflect.TypeOf((*MockCloudFormationClient)(nil).DescribeStackDriftDetectionStatus), varargs...) +} + // DescribeStackEvents mocks base method. func (m *MockCloudFormationClient) DescribeStackEvents(ctx context.Context, params *cloudformation.DescribeStackEventsInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStackEventsOutput, error) { m.ctrl.T.Helper() @@ -121,6 +161,26 @@ func (mr *MockCloudFormationClientMockRecorder) DescribeStackEvents(ctx, params return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackEvents", reflect.TypeOf((*MockCloudFormationClient)(nil).DescribeStackEvents), varargs...) } +// DescribeStackResourceDrifts mocks base method. +func (m *MockCloudFormationClient) DescribeStackResourceDrifts(ctx context.Context, params *cloudformation.DescribeStackResourceDriftsInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStackResourceDriftsOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStackResourceDrifts", varargs...) + ret0, _ := ret[0].(*cloudformation.DescribeStackResourceDriftsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeStackResourceDrifts indicates an expected call of DescribeStackResourceDrifts. +func (mr *MockCloudFormationClientMockRecorder) DescribeStackResourceDrifts(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackResourceDrifts", reflect.TypeOf((*MockCloudFormationClient)(nil).DescribeStackResourceDrifts), varargs...) +} + // DescribeStacks mocks base method. func (m *MockCloudFormationClient) DescribeStacks(ctx context.Context, params *cloudformation.DescribeStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) { m.ctrl.T.Helper() @@ -141,6 +201,26 @@ func (mr *MockCloudFormationClientMockRecorder) DescribeStacks(ctx, params any, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStacks", reflect.TypeOf((*MockCloudFormationClient)(nil).DescribeStacks), varargs...) } +// DetectStackDrift mocks base method. +func (m *MockCloudFormationClient) DetectStackDrift(ctx context.Context, params *cloudformation.DetectStackDriftInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DetectStackDriftOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DetectStackDrift", varargs...) + ret0, _ := ret[0].(*cloudformation.DetectStackDriftOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DetectStackDrift indicates an expected call of DetectStackDrift. +func (mr *MockCloudFormationClientMockRecorder) DetectStackDrift(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetectStackDrift", reflect.TypeOf((*MockCloudFormationClient)(nil).DetectStackDrift), varargs...) +} + // ExecuteChangeSet mocks base method. func (m *MockCloudFormationClient) ExecuteChangeSet(ctx context.Context, params *cloudformation.ExecuteChangeSetInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ExecuteChangeSetOutput, error) { m.ctrl.T.Helper() @@ -161,6 +241,86 @@ func (mr *MockCloudFormationClientMockRecorder) ExecuteChangeSet(ctx, params any return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteChangeSet", reflect.TypeOf((*MockCloudFormationClient)(nil).ExecuteChangeSet), varargs...) } +// GetStackPolicy mocks base method. +func (m *MockCloudFormationClient) GetStackPolicy(ctx context.Context, params *cloudformation.GetStackPolicyInput, optFns ...func(*cloudformation.Options)) (*cloudformation.GetStackPolicyOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetStackPolicy", varargs...) + ret0, _ := ret[0].(*cloudformation.GetStackPolicyOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetStackPolicy indicates an expected call of GetStackPolicy. +func (mr *MockCloudFormationClientMockRecorder) GetStackPolicy(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStackPolicy", reflect.TypeOf((*MockCloudFormationClient)(nil).GetStackPolicy), varargs...) +} + +// GetTemplate mocks base method. +func (m *MockCloudFormationClient) GetTemplate(ctx context.Context, params *cloudformation.GetTemplateInput, optFns ...func(*cloudformation.Options)) (*cloudformation.GetTemplateOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetTemplate", varargs...) + ret0, _ := ret[0].(*cloudformation.GetTemplateOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetTemplate indicates an expected call of GetTemplate. +func (mr *MockCloudFormationClientMockRecorder) GetTemplate(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplate", reflect.TypeOf((*MockCloudFormationClient)(nil).GetTemplate), varargs...) +} + +// ListChangeSets mocks base method. +func (m *MockCloudFormationClient) ListChangeSets(ctx context.Context, params *cloudformation.ListChangeSetsInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ListChangeSetsOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListChangeSets", varargs...) + ret0, _ := ret[0].(*cloudformation.ListChangeSetsOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListChangeSets indicates an expected call of ListChangeSets. +func (mr *MockCloudFormationClientMockRecorder) ListChangeSets(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChangeSets", reflect.TypeOf((*MockCloudFormationClient)(nil).ListChangeSets), varargs...) +} + +// ListStacks mocks base method. +func (m *MockCloudFormationClient) ListStacks(ctx context.Context, params *cloudformation.ListStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.ListStacksOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListStacks", varargs...) + ret0, _ := ret[0].(*cloudformation.ListStacksOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListStacks indicates an expected call of ListStacks. +func (mr *MockCloudFormationClientMockRecorder) ListStacks(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStacks", reflect.TypeOf((*MockCloudFormationClient)(nil).ListStacks), varargs...) +} + // SetStackPolicy mocks base method. func (m *MockCloudFormationClient) SetStackPolicy(ctx context.Context, params *cloudformation.SetStackPolicyInput, optFns ...func(*cloudformation.Options)) (*cloudformation.SetStackPolicyOutput, error) { m.ctrl.T.Helper() diff --git a/pkg/component/aws/cloudformation/types.go b/pkg/component/aws/cloudformation/types.go index 1b546a70844..2a20daea48e 100644 --- a/pkg/component/aws/cloudformation/types.go +++ b/pkg/component/aws/cloudformation/types.go @@ -16,4 +16,20 @@ const ( OperationValidate Operation = "validate" // OperationOutput renders the deployed stack's Outputs. OperationOutput Operation = "output" + // OperationChangesetCreate creates a changeset and leaves it for manual review/execution. + OperationChangesetCreate Operation = "changeset-create" + // OperationChangesetExecute executes a previously-created, named changeset. + OperationChangesetExecute Operation = "changeset-execute" + // OperationChangesetList lists a stack's changesets. + OperationChangesetList Operation = "changeset-list" + // OperationChangesetDelete deletes a named changeset. + OperationChangesetDelete Operation = "changeset-delete" + // OperationDriftDetect starts drift detection against the deployed stack. + OperationDriftDetect Operation = "drift-detect" + // OperationDriftDescribe renders the results of the most recent drift detection. + OperationDriftDescribe Operation = "drift-describe" + // OperationGetTemplate fetches the deployed stack's template. + OperationGetTemplate Operation = "get-template" + // OperationGetPolicy fetches the deployed stack's policy. + OperationGetPolicy Operation = "get-policy" ) diff --git a/pkg/config/schema/ratchet_test.go b/pkg/config/schema/ratchet_test.go index b97d2c142cf..6ac831efacf 100644 --- a/pkg/config/schema/ratchet_test.go +++ b/pkg/config/schema/ratchet_test.go @@ -93,6 +93,7 @@ var yamlFunctionClassification = map[string]string{ "AtmosYamlFuncAwsCallerIdentityArn": u.AtmosYamlFuncAwsCallerIdentityArn, "AtmosYamlFuncAwsCallerIdentityUserID": u.AtmosYamlFuncAwsCallerIdentityUserID, "AtmosYamlFuncAwsOrganizationID": u.AtmosYamlFuncAwsOrganizationID, + "AtmosYamlFuncAwsCloudFormationOutput": u.AtmosYamlFuncAwsCloudFormationOutput, "AtmosYamlFuncAwsRegion": u.AtmosYamlFuncAwsRegion, "AtmosYamlFuncCEL": u.AtmosYamlFuncCEL, "AtmosYamlFuncCwd": u.AtmosYamlFuncCwd, @@ -135,6 +136,7 @@ var stackManifestOnlyYamlFunctions = map[string]bool{ "AtmosYamlFuncAwsCallerIdentityArn": true, "AtmosYamlFuncAwsCallerIdentityUserID": true, "AtmosYamlFuncAwsOrganizationID": true, + "AtmosYamlFuncAwsCloudFormationOutput": true, "AtmosYamlFuncAwsRegion": true, "AtmosYamlFuncCEL": true, "AtmosYamlFuncEmulator": true, diff --git a/pkg/function/tag/tag.go b/pkg/function/tag/tag.go index b47d2f6ef65..0b9d20eb061 100644 --- a/pkg/function/tag/tag.go +++ b/pkg/function/tag/tag.go @@ -104,6 +104,9 @@ const ( // AwsOrganizationID returns the AWS Organization ID. AwsOrganizationID = "aws.organization_id" + // AwsCloudFormationOutput retrieves an aws/cloudformation stack Output value. + AwsCloudFormationOutput = "aws.cloudformation.output" + // Emulator resolves a value from a local emulator. Emulator = "emulator" @@ -162,6 +165,7 @@ func All() []string { AwsCallerIdentityUserID, AwsRegion, AwsOrganizationID, + AwsCloudFormationOutput, Emulator, Version, Tags, @@ -204,6 +208,7 @@ var tagsMap = map[string]bool{ AwsCallerIdentityUserID: true, AwsRegion: true, AwsOrganizationID: true, + AwsCloudFormationOutput: true, Emulator: true, Version: true, Tags: true, diff --git a/pkg/function/tag/tag_test.go b/pkg/function/tag/tag_test.go index d416454fcf6..1f7e9d42dc6 100644 --- a/pkg/function/tag/tag_test.go +++ b/pkg/function/tag/tag_test.go @@ -43,6 +43,7 @@ func TestCatalog(t *testing.T) { AwsCallerIdentityUserID, AwsRegion, AwsOrganizationID, + AwsCloudFormationOutput, Emulator, Version, Tags, diff --git a/pkg/function/tags.go b/pkg/function/tags.go index f5e83b2b75e..359359f5098 100644 --- a/pkg/function/tags.go +++ b/pkg/function/tags.go @@ -101,6 +101,9 @@ const ( // TagAwsOrganizationID returns the AWS Organization ID. TagAwsOrganizationID = fntag.AwsOrganizationID + // TagAwsCloudFormationOutput retrieves an aws/cloudformation stack Output value. + TagAwsCloudFormationOutput = fntag.AwsCloudFormationOutput + // TagEmulator resolves a value from a local emulator. TagEmulator = fntag.Emulator diff --git a/pkg/function/tags_test.go b/pkg/function/tags_test.go index f1578395d04..59d243247de 100644 --- a/pkg/function/tags_test.go +++ b/pkg/function/tags_test.go @@ -44,6 +44,7 @@ func TestAllTags(t *testing.T) { TagAwsCallerIdentityUserID, TagAwsRegion, TagAwsOrganizationID, + TagAwsCloudFormationOutput, TagEmulator, TagVersion, TagTags, @@ -93,6 +94,7 @@ func TestIsValidTag(t *testing.T) { TagAwsCallerIdentityUserID, TagAwsRegion, TagAwsOrganizationID, + TagAwsCloudFormationOutput, TagEmulator, TagVersion, } diff --git a/pkg/tags/selector.go b/pkg/tags/selector.go index bc857e7dc10..646053bff21 100644 --- a/pkg/tags/selector.go +++ b/pkg/tags/selector.go @@ -44,6 +44,7 @@ var forbiddenSelectorFunctions = map[string]struct{}{ "!aws.caller_identity_user_id": {}, "!aws.region": {}, "!aws.organization_id": {}, + "!aws.cloudformation.output": {}, "!emulator": {}, "!random": {}, } diff --git a/pkg/tags/selector_test.go b/pkg/tags/selector_test.go index 988276e2f23..bc04777b3d6 100644 --- a/pkg/tags/selector_test.go +++ b/pkg/tags/selector_test.go @@ -247,6 +247,7 @@ func TestForbiddenSelectorFunctionsMatchConstants(t *testing.T) { u.AtmosYamlFuncAwsCallerIdentityUserID, u.AtmosYamlFuncAwsRegion, u.AtmosYamlFuncAwsOrganizationID, + u.AtmosYamlFuncAwsCloudFormationOutput, u.AtmosYamlFuncEmulator, u.AtmosYamlFuncRandom, } diff --git a/pkg/utils/yaml_utils.go b/pkg/utils/yaml_utils.go index d921da90d19..5b59f070e34 100644 --- a/pkg/utils/yaml_utils.go +++ b/pkg/utils/yaml_utils.go @@ -55,6 +55,7 @@ const ( AtmosYamlFuncAwsCallerIdentityUserID = "!aws.caller_identity_user_id" AtmosYamlFuncAwsRegion = "!aws.region" AtmosYamlFuncAwsOrganizationID = "!aws.organization_id" + AtmosYamlFuncAwsCloudFormationOutput = "!aws.cloudformation.output" AtmosYamlFuncEmulator = "!emulator" AtmosYamlFuncVersion = "!version" AtmosYamlFuncTags = "!tags" @@ -98,6 +99,7 @@ var ( AtmosYamlFuncAwsCallerIdentityUserID, AtmosYamlFuncAwsRegion, AtmosYamlFuncAwsOrganizationID, + AtmosYamlFuncAwsCloudFormationOutput, AtmosYamlFuncEmulator, AtmosYamlFuncVersion, AtmosYamlFuncTags, @@ -139,6 +141,7 @@ var ( AtmosYamlFuncAwsCallerIdentityUserID: true, AtmosYamlFuncAwsRegion: true, AtmosYamlFuncAwsOrganizationID: true, + AtmosYamlFuncAwsCloudFormationOutput: true, AtmosYamlFuncEmulator: true, AtmosYamlFuncVersion: true, AtmosYamlFuncTags: true, diff --git a/pkg/utils/yaml_utils_test.go b/pkg/utils/yaml_utils_test.go index e182f46abf6..96110629e14 100644 --- a/pkg/utils/yaml_utils_test.go +++ b/pkg/utils/yaml_utils_test.go @@ -886,6 +886,7 @@ func TestAtmosYamlTagsMap_ContainsAllTags(t *testing.T) { AtmosYamlFuncAwsCallerIdentityUserID, AtmosYamlFuncAwsRegion, AtmosYamlFuncAwsOrganizationID, + AtmosYamlFuncAwsCloudFormationOutput, AtmosYamlFuncEmulator, AtmosYamlFuncVersion, AtmosYamlFuncTags, diff --git a/pkg/utils/yaml_utils_unsupported_test.go b/pkg/utils/yaml_utils_unsupported_test.go index 182f4b6b6f4..133d2d5011e 100644 --- a/pkg/utils/yaml_utils_unsupported_test.go +++ b/pkg/utils/yaml_utils_unsupported_test.go @@ -279,6 +279,7 @@ func TestAllSupportedYamlTagsList(t *testing.T) { "!aws.caller_identity_user_id", "!aws.region", "!aws.organization_id", + "!aws.cloudformation.output", "!emulator", "!version", "!tags", From 07dea447e93fcf618518dd586f40fdf902ae8507 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Tue, 25 Aug 2026 10:21:19 -0500 Subject: [PATCH 02/10] test(cloudformation): raise Phase 2 coverage to 93.5%/100% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pkg/component/aws/cloudformation was at 74.6% after the Phase 2 commit added changeset_verbs.go/drift.go/get.go with no tests of their own; pkg/aws/cloudformation (the new leaf package backing the YAML/template function interop bridge) had none at all. Now 93.5% and 100% respectively, plus full coverage on the new internal/exec functions (cloudformation_output_getter.go, the !aws.cloudformation.output YAML function, and componentFunc's new CFN branch). Two small testability seams, matching each file's own existing convention: - pkg/aws/cloudformation/outputs.go had none at all — extracted a cloudFormationAPI interface + loadAWSConfig/newCloudFormationClient vars, mirroring pkg/aws/organization's identical pattern. - drift.go's poll interval/timeout became vars instead of consts so tests can shrink them, rather than requiring a real 15-minute wait to exercise the timeout branch. New fixture: tests/fixtures/scenarios/aws-cloudformation-outputs/, needed because the YAML/template function tests call through the real ExecuteDescribeComponent (no existing seam for it). Co-Authored-By: Claude Sonnet 5 --- internal/exec/cloudformation_output_getter.go | 2 + .../exec/cloudformation_output_getter_test.go | 180 ++++++++++ .../exec/mock_cloudformation_output_getter.go | 57 +++ ...ate_funcs_component_cloudformation_test.go | 90 +++++ ...aml_func_aws_cloudformation_output_test.go | 255 ++++++++++++++ pkg/aws/cloudformation/mock_outputs_test.go | 62 ++++ pkg/aws/cloudformation/outputs.go | 38 +- pkg/aws/cloudformation/outputs_test.go | 197 +++++++++++ .../cloudformation/changeset_verbs_test.go | 331 ++++++++++++++++++ .../aws/cloudformation/cloudformation_test.go | 8 + .../aws/cloudformation/confirm_test.go | 37 ++ pkg/component/aws/cloudformation/drift.go | 10 +- .../aws/cloudformation/drift_test.go | 324 +++++++++++++++++ .../aws/cloudformation/executor_test.go | 251 +++++++++++++ pkg/component/aws/cloudformation/get_test.go | 176 ++++++++++ .../aws-cloudformation-outputs/atmos.yaml | 15 + .../stacks/test.yaml | 22 ++ 17 files changed, 2046 insertions(+), 9 deletions(-) create mode 100644 internal/exec/cloudformation_output_getter_test.go create mode 100644 internal/exec/mock_cloudformation_output_getter.go create mode 100644 internal/exec/template_funcs_component_cloudformation_test.go create mode 100644 internal/exec/yaml_func_aws_cloudformation_output_test.go create mode 100644 pkg/aws/cloudformation/mock_outputs_test.go create mode 100644 pkg/aws/cloudformation/outputs_test.go create mode 100644 pkg/component/aws/cloudformation/changeset_verbs_test.go create mode 100644 pkg/component/aws/cloudformation/drift_test.go create mode 100644 pkg/component/aws/cloudformation/get_test.go create mode 100644 tests/fixtures/scenarios/aws-cloudformation-outputs/atmos.yaml create mode 100644 tests/fixtures/scenarios/aws-cloudformation-outputs/stacks/test.yaml diff --git a/internal/exec/cloudformation_output_getter.go b/internal/exec/cloudformation_output_getter.go index 4152580e71a..c766e5a41f8 100644 --- a/internal/exec/cloudformation_output_getter.go +++ b/internal/exec/cloudformation_output_getter.go @@ -1,5 +1,7 @@ package exec +//go:generate go run go.uber.org/mock/mockgen@v0.6.0 -source=$GOFILE -destination=mock_$GOFILE -package=$GOPACKAGE + import ( "context" "fmt" diff --git a/internal/exec/cloudformation_output_getter_test.go b/internal/exec/cloudformation_output_getter_test.go new file mode 100644 index 00000000000..942f11fb035 --- /dev/null +++ b/internal/exec/cloudformation_output_getter_test.go @@ -0,0 +1,180 @@ +package exec + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/schema" +) + +// stubCloudFormationOutputsGetter replaces the cloudFormationOutputsGetter +// seam for a single test, restoring the original on cleanup. +func stubCloudFormationOutputsGetter(t *testing.T, getter CloudFormationOutputsGetter) { + t.Helper() + original := cloudFormationOutputsGetter + cloudFormationOutputsGetter = getter + t.Cleanup(func() { cloudFormationOutputsGetter = original }) +} + +// defaultCloudFormationOutputsGetter.GetOutputs must actually delegate to +// pkg/aws/cloudformation.GetOutputs (not silently no-op) — asserted here by +// pointing it at a closed local server (guaranteed to refuse the connection) +// and confirming the underlying network call was actually attempted. +func TestDefaultCloudFormationOutputsGetter_GetOutputs_Delegates(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) + unreachable := srv.URL + srv.Close() + + getter := defaultCloudFormationOutputsGetter{} + _, err := getter.GetOutputs(context.Background(), "us-east-1", "vpc", &schema.AWSAuthContext{EndpointURL: unreachable}) + require.Error(t, err, "GetOutputs must delegate to pkg/aws/cloudformation and surface the (unreachable) endpoint's failure") +} + +// GetCloudFormationOutputs must delegate to the cloudFormationOutputsGetter +// seam, forwarding every argument unchanged. +func TestGetCloudFormationOutputs_DelegatesToSeam(t *testing.T) { + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + + authContext := &schema.AWSAuthContext{Profile: "dev"} + want := map[string]any{"VpcId": "vpc-123"} + mockGetter.EXPECT().GetOutputs(gomock.Any(), "us-west-2", "vpc", authContext).Return(want, nil) + + stubCloudFormationOutputsGetter(t, mockGetter) + + got, err := GetCloudFormationOutputs(context.Background(), "us-west-2", "vpc", authContext) + require.NoError(t, err) + assert.Equal(t, want, got) +} + +// GetCloudFormationOutputs must propagate a seam error unchanged. +func TestGetCloudFormationOutputs_PropagatesError(t *testing.T) { + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + + sentinel := errors.New("stack not found") + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, sentinel) + stubCloudFormationOutputsGetter(t, mockGetter) + + _, err := GetCloudFormationOutputs(context.Background(), "us-east-1", "vpc", nil) + require.Error(t, err) + assert.ErrorIs(t, err, sentinel) +} + +// resolveCloudFormationRegion must extract settings.aws_cloudformation.region +// when present, and return "" for every absent-nesting shape. +func TestResolveCloudFormationRegion(t *testing.T) { + tests := []struct { + name string + sections map[string]any + want string + }{ + { + name: "region present", + sections: map[string]any{ + cfg.SettingsSectionName: map[string]any{"aws_cloudformation": map[string]any{"region": "us-west-2"}}, + }, + want: "us-west-2", + }, + {"no settings section", map[string]any{}, ""}, + { + name: "settings present but not a map", + sections: map[string]any{cfg.SettingsSectionName: "not-a-map"}, + want: "", + }, + { + name: "settings present without aws_cloudformation", + sections: map[string]any{cfg.SettingsSectionName: map[string]any{}}, + want: "", + }, + { + name: "aws_cloudformation present but not a map", + sections: map[string]any{ + cfg.SettingsSectionName: map[string]any{"aws_cloudformation": "not-a-map"}, + }, + want: "", + }, + { + name: "aws_cloudformation present without region", + sections: map[string]any{ + cfg.SettingsSectionName: map[string]any{"aws_cloudformation": map[string]any{}}, + }, + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.want, resolveCloudFormationRegion(tt.sections)) + }) + } +} + +// cloudFormationOutputsForSections must error when the target section has no +// stack_name, without ever reaching the outputs getter. +func TestCloudFormationOutputsForSections_MissingStackName(t *testing.T) { + stubCloudFormationOutputsGetter(t, nil) // any call would nil-panic, proving it's never reached. + + _, err := cloudFormationOutputsForSections(&schema.AtmosConfiguration{}, "vpc", map[string]any{}, nil) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrMissingAwsCloudFormationStackName) + assert.Contains(t, err.Error(), "vpc") +} + +// cloudFormationOutputsForSections must resolve stack_name/region from +// sections and forward the AWS-specific slice of a nil AuthContext. +func TestCloudFormationOutputsForSections_NilAuthContext(t *testing.T) { + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + + var gotAuth *schema.AWSAuthContext + mockGetter.EXPECT().GetOutputs(gomock.Any(), "us-east-1", "vpc", gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string, authCtx *schema.AWSAuthContext) (map[string]any, error) { + gotAuth = authCtx + return map[string]any{"VpcId": "vpc-123"}, nil + }, + ) + stubCloudFormationOutputsGetter(t, mockGetter) + + sections := map[string]any{ + cfg.StackNameSectionName: "vpc", + cfg.SettingsSectionName: map[string]any{"aws_cloudformation": map[string]any{"region": "us-east-1"}}, + } + got, err := cloudFormationOutputsForSections(&schema.AtmosConfiguration{}, "vpc", sections, nil) + require.NoError(t, err) + assert.Equal(t, map[string]any{"VpcId": "vpc-123"}, got) + assert.Nil(t, gotAuth, "a nil AuthContext must forward a nil AWSAuthContext, not panic") +} + +// cloudFormationOutputsForSections must forward the populated AuthContext's +// AWS sub-context to the outputs getter. +func TestCloudFormationOutputsForSections_PopulatedAuthContext(t *testing.T) { + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + + awsAuth := &schema.AWSAuthContext{Profile: "dev"} + authContext := &schema.AuthContext{AWS: awsAuth} + + var gotAuth *schema.AWSAuthContext + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), "vpc", gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string, authCtx *schema.AWSAuthContext) (map[string]any, error) { + gotAuth = authCtx + return map[string]any{}, nil + }, + ) + stubCloudFormationOutputsGetter(t, mockGetter) + + sections := map[string]any{cfg.StackNameSectionName: "vpc"} + _, err := cloudFormationOutputsForSections(&schema.AtmosConfiguration{}, "vpc", sections, authContext) + require.NoError(t, err) + assert.Same(t, awsAuth, gotAuth) +} diff --git a/internal/exec/mock_cloudformation_output_getter.go b/internal/exec/mock_cloudformation_output_getter.go new file mode 100644 index 00000000000..3d6a7fd1f31 --- /dev/null +++ b/internal/exec/mock_cloudformation_output_getter.go @@ -0,0 +1,57 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: cloudformation_output_getter.go +// +// Generated by this command: +// +// mockgen -source=cloudformation_output_getter.go -destination=mock_cloudformation_output_getter.go -package=exec +// + +// Package exec is a generated GoMock package. +package exec + +import ( + context "context" + reflect "reflect" + + schema "github.com/cloudposse/atmos/pkg/schema" + gomock "go.uber.org/mock/gomock" +) + +// MockCloudFormationOutputsGetter is a mock of CloudFormationOutputsGetter interface. +type MockCloudFormationOutputsGetter struct { + ctrl *gomock.Controller + recorder *MockCloudFormationOutputsGetterMockRecorder + isgomock struct{} +} + +// MockCloudFormationOutputsGetterMockRecorder is the mock recorder for MockCloudFormationOutputsGetter. +type MockCloudFormationOutputsGetterMockRecorder struct { + mock *MockCloudFormationOutputsGetter +} + +// NewMockCloudFormationOutputsGetter creates a new mock instance. +func NewMockCloudFormationOutputsGetter(ctrl *gomock.Controller) *MockCloudFormationOutputsGetter { + mock := &MockCloudFormationOutputsGetter{ctrl: ctrl} + mock.recorder = &MockCloudFormationOutputsGetterMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockCloudFormationOutputsGetter) EXPECT() *MockCloudFormationOutputsGetterMockRecorder { + return m.recorder +} + +// GetOutputs mocks base method. +func (m *MockCloudFormationOutputsGetter) GetOutputs(ctx context.Context, region, stackName string, authContext *schema.AWSAuthContext) (map[string]any, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOutputs", ctx, region, stackName, authContext) + ret0, _ := ret[0].(map[string]any) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetOutputs indicates an expected call of GetOutputs. +func (mr *MockCloudFormationOutputsGetterMockRecorder) GetOutputs(ctx, region, stackName, authContext any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOutputs", reflect.TypeOf((*MockCloudFormationOutputsGetter)(nil).GetOutputs), ctx, region, stackName, authContext) +} diff --git a/internal/exec/template_funcs_component_cloudformation_test.go b/internal/exec/template_funcs_component_cloudformation_test.go new file mode 100644 index 00000000000..3f4a6fdbbdf --- /dev/null +++ b/internal/exec/template_funcs_component_cloudformation_test.go @@ -0,0 +1,90 @@ +package exec + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/schema" +) + +// clearComponentFuncSyncMap empties componentFuncSyncMap, restoring it after +// the test — componentFunc caches its result by stack/component, so tests +// must not leak cache entries into (or read stale ones from) other tests. +func clearComponentFuncSyncMap(t *testing.T) { + t.Helper() + clear := func() { + componentFuncSyncMap.Range(func(key, _ any) bool { + componentFuncSyncMap.Delete(key) + return true + }) + } + clear() + t.Cleanup(clear) +} + +// componentFunc's aws/cloudformation branch must populate the result's +// `outputs` section from cloudFormationOutputsForSections (via the stubbed +// cloudFormationOutputsGetter seam), the CFN counterpart to the Terraform +// branch already covered by TestComponentFunc. +func TestComponentFunc_CloudFormationBranch_PopulatesOutputs(t *testing.T) { + clearComponentFuncSyncMap(t) + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + mockGetter.EXPECT().GetOutputs(gomock.Any(), "us-east-1", "test-vpc", gomock.Any()). + Return(map[string]any{"VpcId": "vpc-123"}, nil) + stubCloudFormationOutputsGetter(t, mockGetter) + + result, err := componentFunc(&atmosConfig, nil, "vpc", "test") + require.NoError(t, err) + + sections, ok := result.(map[string]any) + require.True(t, ok, "componentFunc must return the sections map") + outputs, ok := sections[cfg.OutputsSectionName].(map[string]any) + require.True(t, ok, "sections must carry a populated outputs map") + assert.Equal(t, "vpc-123", outputs["VpcId"]) +} + +// componentFunc's aws/cloudformation branch must propagate a +// cloudFormationOutputsForSections failure, such as a missing stack_name, +// wrapped with the atmos.Component context. +func TestComponentFunc_CloudFormationBranch_OutputsError(t *testing.T) { + clearComponentFuncSyncMap(t) + atmosConfig := setupAwsCloudFormationOutputFixture(t) + stubCloudFormationOutputsGetter(t, nil) // any call would nil-panic, proving it's never reached. + + _, err := componentFunc(&atmosConfig, nil, "no-stack-name", "test") + require.Error(t, err) + assert.Contains(t, err.Error(), "atmos.Component") +} + +// componentFunc's aws/cloudformation branch must forward the resolved +// AuthManager's AuthContext (mirroring the Terraform branch) rather than +// always using a nil AuthContext. +func TestComponentFunc_CloudFormationBranch_PassesResolvedAuthContext(t *testing.T) { + clearComponentFuncSyncMap(t) + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + var gotAuth *schema.AWSAuthContext + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string, authCtx *schema.AWSAuthContext) (map[string]any, error) { + gotAuth = authCtx + return map[string]any{"VpcId": "vpc-123"}, nil + }, + ) + stubCloudFormationOutputsGetter(t, mockGetter) + + parentContext := &schema.AuthContext{AWS: &schema.AWSAuthContext{Profile: "enclosing-identity"}} + _, err := componentFunc(&atmosConfig, &schema.ConfigAndStacksInfo{AuthContext: parentContext}, "vpc", "test") + require.NoError(t, err) + require.NotNil(t, gotAuth, "the enclosing AuthContext must reach cloudFormationOutputsForSections") + assert.Equal(t, "enclosing-identity", gotAuth.Profile) +} diff --git a/internal/exec/yaml_func_aws_cloudformation_output_test.go b/internal/exec/yaml_func_aws_cloudformation_output_test.go new file mode 100644 index 00000000000..1ecea1eaf1e --- /dev/null +++ b/internal/exec/yaml_func_aws_cloudformation_output_test.go @@ -0,0 +1,255 @@ +package exec + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/schema" +) + +// parseAwsCloudFormationOutputArgs must parse the `component [stack] +// output-key` grammar, defaulting Stack to currentStack when omitted, and +// must propagate a malformed-input error. +func TestParseAwsCloudFormationOutputArgs(t *testing.T) { + t.Run("stack omitted defaults to currentStack", func(t *testing.T) { + parsed, err := parseAwsCloudFormationOutputArgs("!aws.cloudformation.output vpc VpcId", "current-stack") + require.NoError(t, err) + assert.Equal(t, "vpc", parsed.Component) + assert.Equal(t, "current-stack", parsed.Stack) + assert.Equal(t, "VpcId", parsed.Expression) + }) + + t.Run("explicit stack overrides currentStack", func(t *testing.T) { + parsed, err := parseAwsCloudFormationOutputArgs("!aws.cloudformation.output vpc other-stack VpcId", "current-stack") + require.NoError(t, err) + assert.Equal(t, "vpc", parsed.Component) + assert.Equal(t, "other-stack", parsed.Stack) + assert.Equal(t, "VpcId", parsed.Expression) + }) + + t.Run("empty arguments propagate the getStringAfterTag error", func(t *testing.T) { + _, err := parseAwsCloudFormationOutputArgs("!aws.cloudformation.output", "current-stack") + require.Error(t, err) + }) + + t.Run("a single argument propagates a ParseTerraform error (2 or 3 arguments required)", func(t *testing.T) { + _, err := parseAwsCloudFormationOutputArgs("!aws.cloudformation.output vpc", "current-stack") + require.Error(t, err) + }) +} + +// setupAwsCloudFormationOutputFixture chdirs into the shared aws/cloudformation +// output fixture (tests/fixtures/scenarios/aws-cloudformation-outputs) and +// returns its loaded AtmosConfiguration. +func setupAwsCloudFormationOutputFixture(t *testing.T) schema.AtmosConfiguration { + t.Helper() + t.Chdir("../../tests/fixtures/scenarios/aws-cloudformation-outputs") + t.Setenv("ATMOS_CLI_CONFIG_PATH", ".") + + atmosConfig, err := cfg.InitCliConfig(schema.ConfigAndStacksInfo{}, true) + require.NoError(t, err) + return atmosConfig +} + +// processTagAwsCloudFormationOutputWithContext must propagate a +// parseAwsCloudFormationOutputArgs failure (malformed input) without ever +// reaching trackOutputDependency, describe, or the outputs getter. +func TestProcessTagAwsCloudFormationOutputWithContext_ParseArgsError(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + stubCloudFormationOutputsGetter(t, nil) // any call would nil-panic, proving it's never reached. + + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output", "test", nil, nil, + ) + require.Error(t, err) +} + +// processTagAwsCloudFormationOutputWithContext's happy path: resolves the +// target's stack_name/region from its described sections and returns the +// requested output's value from the (stubbed) outputs getter. +func TestProcessTagAwsCloudFormationOutputWithContext_Success(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + mockGetter.EXPECT().GetOutputs(gomock.Any(), "us-east-1", "test-vpc", gomock.Any()). + Return(map[string]any{"VpcId": "vpc-123"}, nil) + stubCloudFormationOutputsGetter(t, mockGetter) + + result, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test VpcId", "test", nil, nil, + ) + require.NoError(t, err) + assert.Equal(t, "vpc-123", result) +} + +// A requested output key absent from the deployed stack's Outputs must +// return (nil, nil) — not an error — matching !terraform.output's own +// "output not found" contract. +func TestProcessTagAwsCloudFormationOutputWithContext_OutputKeyNotFound(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(map[string]any{"OtherKey": "other-value"}, nil) + stubCloudFormationOutputsGetter(t, mockGetter) + + result, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test MissingKey", "test", nil, nil, + ) + require.NoError(t, err) + assert.Nil(t, result) +} + +// A component with no stack_name must surface +// ErrMissingAwsCloudFormationStackName without ever reaching the outputs +// getter. +func TestProcessTagAwsCloudFormationOutputWithContext_MissingStackName(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + stubCloudFormationOutputsGetter(t, nil) // any call would nil-panic, proving it's never reached. + + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output no-stack-name test SomeKey", "test", nil, nil, + ) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrMissingAwsCloudFormationStackName) +} + +// A target component that doesn't exist in the stack must surface a +// describe-component error. +func TestProcessTagAwsCloudFormationOutputWithContext_DescribeComponentError(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + stubCloudFormationOutputsGetter(t, nil) // any call would nil-panic, proving it's never reached. + + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output does-not-exist test SomeKey", "test", nil, nil, + ) + require.Error(t, err) + assert.Contains(t, err.Error(), "does-not-exist") +} + +// processTagAwsCloudFormationOutputWithContext must extract authContext and +// authManager from a populated stackInfo and thread the resolved AWS auth +// context through to the outputs getter (via resolveNestedOutputAuth and +// cloudFormationOutputsForSections), not just handle the nil-stackInfo case. +func TestProcessTagAwsCloudFormationOutputWithContext_PopulatedStackInfo(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + var gotAuth *schema.AWSAuthContext + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string, authCtx *schema.AWSAuthContext) (map[string]any, error) { + gotAuth = authCtx + return map[string]any{"VpcId": "vpc-123"}, nil + }, + ) + stubCloudFormationOutputsGetter(t, mockGetter) + + awsAuth := &schema.AWSAuthContext{Profile: "dev"} + stackInfo := &schema.ConfigAndStacksInfo{AuthContext: &schema.AuthContext{AWS: awsAuth}} + + result, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test VpcId", "test", nil, stackInfo, + ) + require.NoError(t, err) + assert.Equal(t, "vpc-123", result) + require.NotNil(t, gotAuth, "the enclosing stackInfo's AWS auth context must reach the outputs getter") + assert.Equal(t, "dev", gotAuth.Profile) +} + +// A CloudFormationOutputsGetter error must propagate, wrapped with the +// component/stack/output context. +func TestProcessTagAwsCloudFormationOutputWithContext_GetterError(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + sentinel := errors.New("stack not found") + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, sentinel) + stubCloudFormationOutputsGetter(t, mockGetter) + + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test VpcId", "test", nil, nil, + ) + require.Error(t, err) + assert.ErrorIs(t, err, sentinel) +} + +// processTagAwsCloudFormationOutputWithContext must actually push onto the +// given ResolutionContext (via trackOutputDependency) and surface +// ErrCircularDependency when the target component/stack pair is already on +// the call stack — proving cycle detection is wired in, not merely present +// in a shared helper that's never reached from this code path. +func TestProcessTagAwsCloudFormationOutputWithContext_CycleDetection(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + stubCloudFormationOutputsGetter(t, nil) // any call would nil-panic, proving it's never reached. + + resolutionCtx := NewResolutionContext() + require.NoError(t, resolutionCtx.Push(&atmosConfig, DependencyNode{ + Component: "vpc", + Stack: "test", + FunctionType: "terraform.output", + FunctionCall: "!aws.cloudformation.output vpc test VpcId", + })) + t.Cleanup(func() { resolutionCtx.Pop(&atmosConfig) }) + + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test VpcId", "test", resolutionCtx, nil, + ) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrCircularDependency) +} + +// A valid resolutionCtx must still push/pop cleanly through a successful +// call, leaving the stack empty afterward — the complement of the cycle test +// above (context is used correctly, not merely present). +func TestProcessTagAwsCloudFormationOutputWithContext_ResolutionContextCleansUpOnSuccess(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()). + Return(map[string]any{"VpcId": "vpc-123"}, nil) + stubCloudFormationOutputsGetter(t, mockGetter) + + resolutionCtx := NewResolutionContext() + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test VpcId", "test", resolutionCtx, nil, + ) + require.NoError(t, err) + assert.Empty(t, resolutionCtx.CallStack, "the pushed node must be popped after a successful resolution") + assert.Empty(t, resolutionCtx.Visited) +} + +// context.Background usage sanity: the getter must actually be invoked with +// a non-nil context (guards against a future refactor accidentally passing +// a nil context.Context to the AWS SDK layer). +func TestProcessTagAwsCloudFormationOutputWithContext_PassesNonNilContext(t *testing.T) { + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + var gotCtx context.Context + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(ctx context.Context, _, _ string, _ *schema.AWSAuthContext) (map[string]any, error) { + gotCtx = ctx + return map[string]any{"VpcId": "vpc-123"}, nil + }, + ) + stubCloudFormationOutputsGetter(t, mockGetter) + + _, err := processTagAwsCloudFormationOutputWithContext( + &atmosConfig, "!aws.cloudformation.output vpc test VpcId", "test", nil, nil, + ) + require.NoError(t, err) + require.NotNil(t, gotCtx) +} diff --git a/pkg/aws/cloudformation/mock_outputs_test.go b/pkg/aws/cloudformation/mock_outputs_test.go new file mode 100644 index 00000000000..474aafd3c97 --- /dev/null +++ b/pkg/aws/cloudformation/mock_outputs_test.go @@ -0,0 +1,62 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: outputs.go +// +// Generated by this command: +// +// mockgen -source=outputs.go -destination=mock_outputs_test.go -package=cloudformation +// + +// Package cloudformation is a generated GoMock package. +package cloudformation + +import ( + context "context" + reflect "reflect" + + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" + gomock "go.uber.org/mock/gomock" +) + +// MockcloudFormationAPI is a mock of cloudFormationAPI interface. +type MockcloudFormationAPI struct { + ctrl *gomock.Controller + recorder *MockcloudFormationAPIMockRecorder + isgomock struct{} +} + +// MockcloudFormationAPIMockRecorder is the mock recorder for MockcloudFormationAPI. +type MockcloudFormationAPIMockRecorder struct { + mock *MockcloudFormationAPI +} + +// NewMockcloudFormationAPI creates a new mock instance. +func NewMockcloudFormationAPI(ctrl *gomock.Controller) *MockcloudFormationAPI { + mock := &MockcloudFormationAPI{ctrl: ctrl} + mock.recorder = &MockcloudFormationAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockcloudFormationAPI) EXPECT() *MockcloudFormationAPIMockRecorder { + return m.recorder +} + +// DescribeStacks mocks base method. +func (m *MockcloudFormationAPI) DescribeStacks(ctx context.Context, params *cloudformation.DescribeStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) { + m.ctrl.T.Helper() + varargs := []any{ctx, params} + for _, a := range optFns { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStacks", varargs...) + ret0, _ := ret[0].(*cloudformation.DescribeStacksOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DescribeStacks indicates an expected call of DescribeStacks. +func (mr *MockcloudFormationAPIMockRecorder) DescribeStacks(ctx, params any, optFns ...any) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]any{ctx, params}, optFns...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStacks", reflect.TypeOf((*MockcloudFormationAPI)(nil).DescribeStacks), varargs...) +} diff --git a/pkg/aws/cloudformation/outputs.go b/pkg/aws/cloudformation/outputs.go index c68383afa56..4a37fe4d1f8 100644 --- a/pkg/aws/cloudformation/outputs.go +++ b/pkg/aws/cloudformation/outputs.go @@ -20,6 +20,34 @@ import ( "github.com/cloudposse/atmos/pkg/schema" ) +// cloudFormationAPI is the subset of the AWS SDK v2 CloudFormation client used +// by this package. A seam for testing GetOutputs without real AWS credentials +// or network access. +// +//go:generate go run go.uber.org/mock/mockgen@v0.6.0 -source=$GOFILE -destination=mock_outputs_test.go -package=cloudformation +type cloudFormationAPI interface { + DescribeStacks(ctx context.Context, params *cloudformation.DescribeStacksInput, optFns ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) +} + +// Seams for testing. +var ( + loadAWSConfig = identity.LoadConfigWithAuth + newCloudFormationClient = defaultNewCloudFormationClient +) + +// defaultNewCloudFormationClient constructs the real AWS SDK v2 CloudFormation +// client from a resolved aws.Config. The endpointURL parameter overrides the +// service endpoint (e.g. a Floci-emulated CloudFormation endpoint) when set, +// matching pkg/component/aws/cloudformation's own client construction +// (client.go's newClient). +func defaultNewCloudFormationClient(cfg aws.Config, endpointURL string) cloudFormationAPI { //nolint:gocritic // aws.Config-by-value matches cloudformation.NewFromConfig's own signature. + var optFns []func(*cloudformation.Options) + if endpointURL != "" { + optFns = append(optFns, func(o *cloudformation.Options) { o.BaseEndpoint = aws.String(endpointURL) }) + } + return cloudformation.NewFromConfig(cfg, optFns...) +} + // GetOutputs fetches a deployed CloudFormation stack's Outputs, keyed by // Output name. AuthContext's EndpointURL (when set) is honored so this also // reaches a Floci-emulated CloudFormation endpoint, matching @@ -27,17 +55,17 @@ import ( func GetOutputs(ctx context.Context, region, stackName string, authContext *schema.AWSAuthContext) (map[string]any, error) { defer perf.Track(nil, "cloudformation.GetOutputs")() - awsCfg, err := identity.LoadConfigWithAuth(ctx, region, "", 0, authContext) + awsCfg, err := loadAWSConfig(ctx, region, "", 0, authContext) if err != nil { return nil, err } - var optFns []func(*cloudformation.Options) - if authContext != nil && authContext.EndpointURL != "" { - optFns = append(optFns, func(o *cloudformation.Options) { o.BaseEndpoint = aws.String(authContext.EndpointURL) }) + endpointURL := "" + if authContext != nil { + endpointURL = authContext.EndpointURL } - client := cloudformation.NewFromConfig(awsCfg, optFns...) + client := newCloudFormationClient(awsCfg, endpointURL) out, err := client.DescribeStacks(ctx, &cloudformation.DescribeStacksInput{StackName: aws.String(stackName)}) if err != nil { return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) diff --git a/pkg/aws/cloudformation/outputs_test.go b/pkg/aws/cloudformation/outputs_test.go new file mode 100644 index 00000000000..898360d6e91 --- /dev/null +++ b/pkg/aws/cloudformation/outputs_test.go @@ -0,0 +1,197 @@ +package cloudformation + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/schema" +) + +// stubOutputsSeams overrides loadAWSConfig and newCloudFormationClient for a +// single test, restoring the originals on cleanup. +func stubOutputsSeams(t *testing.T, cfgErr error, client cloudFormationAPI) { + t.Helper() + + origLoadConfig := loadAWSConfig + origNewClient := newCloudFormationClient + + loadAWSConfig = func(_ context.Context, _, _ string, _ time.Duration, _ *schema.AWSAuthContext) (aws.Config, error) { + if cfgErr != nil { + return aws.Config{}, cfgErr + } + return aws.Config{}, nil + } + newCloudFormationClient = func(_ aws.Config, _ string) cloudFormationAPI { return client } + + t.Cleanup(func() { + loadAWSConfig = origLoadConfig + newCloudFormationClient = origNewClient + }) +} + +// GetOutputs must extract every Output's key/value pair from a successful +// DescribeStacks response. +func TestGetOutputs_Success(t *testing.T) { + ctrl := gomock.NewController(t) + mockClient := NewMockcloudFormationAPI(ctrl) + + mockClient.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []cfntypes.Stack{{ + Outputs: []cfntypes.Output{ + {OutputKey: aws.String("VpcId"), OutputValue: aws.String("vpc-123")}, + {OutputKey: aws.String("SubnetId"), OutputValue: aws.String("subnet-456")}, + }, + }}, + }, nil) + + stubOutputsSeams(t, nil, mockClient) + + outputs, err := GetOutputs(context.Background(), "us-east-1", "vpc", nil) + require.NoError(t, err) + assert.Equal(t, map[string]any{"VpcId": "vpc-123", "SubnetId": "subnet-456"}, outputs) +} + +// GetOutputs must skip an Output with a nil OutputKey (unnamed/malformed +// entry) rather than panicking, and must represent a nil OutputValue as a nil +// map value rather than dropping the key. +func TestGetOutputs_NilKeyAndValue(t *testing.T) { + ctrl := gomock.NewController(t) + mockClient := NewMockcloudFormationAPI(ctrl) + + mockClient.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []cfntypes.Stack{{ + Outputs: []cfntypes.Output{ + {OutputKey: nil, OutputValue: aws.String("ignored")}, + {OutputKey: aws.String("EmptyValue"), OutputValue: nil}, + }, + }}, + }, nil) + + stubOutputsSeams(t, nil, mockClient) + + outputs, err := GetOutputs(context.Background(), "us-east-1", "vpc", nil) + require.NoError(t, err) + assert.Len(t, outputs, 1, "the nil-OutputKey entry must be skipped") + value, ok := outputs["EmptyValue"] + require.True(t, ok, "a nil OutputValue must still produce the key") + assert.Nil(t, value) +} + +// GetOutputs must error when the stack has no matching Stacks entry +// (CloudFormation's shape for "stack not found" via a successful, empty +// response rather than an API error). +func TestGetOutputs_StackNotFound(t *testing.T) { + ctrl := gomock.NewController(t) + mockClient := NewMockcloudFormationAPI(ctrl) + + mockClient.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []cfntypes.Stack{}, + }, nil) + + stubOutputsSeams(t, nil, mockClient) + + _, err := GetOutputs(context.Background(), "us-east-1", "missing-stack", nil) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.Contains(t, err.Error(), "missing-stack") +} + +// GetOutputs must wrap a DescribeStacks API error. +func TestGetOutputs_APIError(t *testing.T) { + ctrl := gomock.NewController(t) + mockClient := NewMockcloudFormationAPI(ctrl) + + sentinel := errors.New("access denied") + mockClient.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, sentinel) + + stubOutputsSeams(t, nil, mockClient) + + _, err := GetOutputs(context.Background(), "us-east-1", "vpc", nil) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.ErrorIs(t, err, sentinel) +} + +// GetOutputs must propagate a config-loading failure without ever +// constructing a client or calling DescribeStacks. +func TestGetOutputs_LoadConfigError(t *testing.T) { + sentinel := errors.New("no credentials") + ctrl := gomock.NewController(t) + mockClient := NewMockcloudFormationAPI(ctrl) // no expectations: must never be called. + + stubOutputsSeams(t, sentinel, mockClient) + + _, err := GetOutputs(context.Background(), "us-east-1", "vpc", nil) + require.Error(t, err) + assert.ErrorIs(t, err, sentinel) +} + +// GetOutputs must forward the AuthContext through to loadAWSConfig unchanged. +func TestGetOutputs_PassesAuthContext(t *testing.T) { + ctrl := gomock.NewController(t) + mockClient := NewMockcloudFormationAPI(ctrl) + mockClient.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []cfntypes.Stack{{}}, + }, nil) + + authContext := &schema.AWSAuthContext{Profile: "dev", EndpointURL: "http://localhost:4566"} + + origLoadConfig := loadAWSConfig + origNewClient := newCloudFormationClient + var capturedAuth *schema.AWSAuthContext + var capturedEndpoint string + loadAWSConfig = func(_ context.Context, _, _ string, _ time.Duration, authCtx *schema.AWSAuthContext) (aws.Config, error) { + capturedAuth = authCtx + return aws.Config{}, nil + } + newCloudFormationClient = func(_ aws.Config, endpointURL string) cloudFormationAPI { + capturedEndpoint = endpointURL + return mockClient + } + t.Cleanup(func() { + loadAWSConfig = origLoadConfig + newCloudFormationClient = origNewClient + }) + + _, err := GetOutputs(context.Background(), "us-east-1", "vpc", authContext) + require.NoError(t, err) + assert.Same(t, authContext, capturedAuth) + assert.Equal(t, "http://localhost:4566", capturedEndpoint, "the auth context's emulator endpoint override must reach client construction") +} + +// defaultNewCloudFormationClient must target the custom endpoint when one is +// configured. Mirrors pkg/component/aws/cloudformation/client_test.go's +// TestNewClient_SetsCustomEndpoint: we assert the real SDK client's resolved +// Options().BaseEndpoint rather than just checking it doesn't panic. +func TestDefaultNewCloudFormationClient_SetsCustomEndpoint(t *testing.T) { + client := defaultNewCloudFormationClient(aws.Config{Region: "us-east-1"}, "http://localhost:4566") + + real, ok := client.(*cloudformation.Client) + require.True(t, ok, "defaultNewCloudFormationClient must return the real SDK client") + + opts := real.Options() + require.NotNil(t, opts.BaseEndpoint, "BaseEndpoint must be set when an endpoint override is configured") + assert.Equal(t, "http://localhost:4566", *opts.BaseEndpoint) +} + +// Without an endpoint override, BaseEndpoint must be left nil so the client +// targets real AWS via the SDK's normal region-based endpoint resolution. +func TestDefaultNewCloudFormationClient_NoEndpointOverride(t *testing.T) { + client := defaultNewCloudFormationClient(aws.Config{Region: "us-east-1"}, "") + + real, ok := client.(*cloudformation.Client) + require.True(t, ok) + + opts := real.Options() + assert.Nil(t, opts.BaseEndpoint, "BaseEndpoint must stay nil (real AWS) when no override is configured") +} diff --git a/pkg/component/aws/cloudformation/changeset_verbs_test.go b/pkg/component/aws/cloudformation/changeset_verbs_test.go new file mode 100644 index 00000000000..06fc9904268 --- /dev/null +++ b/pkg/component/aws/cloudformation/changeset_verbs_test.go @@ -0,0 +1,331 @@ +package cloudformation + +import ( + "context" + "errors" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" +) + +// listChangeSets must paginate through every NextToken until CloudFormation +// stops returning one, accumulating every page's Summaries. +func TestListChangeSets_Paginates(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + token := "page-2" + gomock.InOrder( + client.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.ListChangeSetsInput, _ ...func(*cloudformation.Options)) (*cloudformation.ListChangeSetsOutput, error) { + assert.Nil(t, input.NextToken, "the first page request must not carry a token") + return &cloudformation.ListChangeSetsOutput{ + Summaries: []cfntypes.ChangeSetSummary{{ChangeSetName: awsString("cs-1")}}, + NextToken: &token, + }, nil + }, + ), + client.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.ListChangeSetsInput, _ ...func(*cloudformation.Options)) (*cloudformation.ListChangeSetsOutput, error) { + assert.Equal(t, &token, input.NextToken, "the second page request must carry the first page's token") + return &cloudformation.ListChangeSetsOutput{ + Summaries: []cfntypes.ChangeSetSummary{{ChangeSetName: awsString("cs-2")}}, + }, nil + }, + ), + ) + + summaries, err := listChangeSets(context.Background(), client, "vpc") + require.NoError(t, err) + require.Len(t, summaries, 2) + assert.Equal(t, "cs-1", stringValue(summaries[0].ChangeSetName)) + assert.Equal(t, "cs-2", stringValue(summaries[1].ChangeSetName)) +} + +// listChangeSets must wrap a ListChangeSets API error. +func TestListChangeSets_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + _, err := listChangeSets(context.Background(), client, "vpc") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) +} + +// deleteChangeSet must succeed on the happy path and wrap an API error. +func TestDeleteChangeSet(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DeleteChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DeleteChangeSetOutput{}, nil) + + err := deleteChangeSet(context.Background(), client, "vpc", "cs-1") + require.NoError(t, err) +} + +func TestDeleteChangeSet_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DeleteChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("boom")) + + err := deleteChangeSet(context.Background(), client, "vpc", "cs-1") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) +} + +// describeNamedChangeSet must return a populated changeSetResult on success. +func TestDescribeNamedChangeSet_Success(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + ChangeSetId: awsString("cs-id-1"), + StackId: awsString("stack-id-1"), + Status: cfntypes.ChangeSetStatusCreateComplete, + Changes: []cfntypes.Change{{Type: cfntypes.ChangeTypeResource}}, + }, nil) + + result, err := describeNamedChangeSet(context.Background(), client, "vpc", "cs-1") + require.NoError(t, err) + assert.Equal(t, "cs-id-1", result.ChangeSetID) + assert.Equal(t, "cs-1", result.ChangeSetName) + assert.Equal(t, "stack-id-1", result.StackID) + assert.Equal(t, cfntypes.ChangeSetStatusCreateComplete, result.Status) + assert.Len(t, result.Changes, 1) +} + +// describeNamedChangeSet must translate a "not found" DescribeChangeSet error +// into ErrAwsCloudFormationChangeSetNotFound, distinct from a generic failure. +func TestDescribeNamedChangeSet_NotFound(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("ChangeSet [cs-1] does not exist")) + + _, err := describeNamedChangeSet(context.Background(), client, "vpc", "cs-1") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetNotFound) + assert.Contains(t, err.Error(), "cs-1") + assert.Contains(t, err.Error(), "vpc") +} + +// describeNamedChangeSet must wrap any other API error as a generic failure, +// not the not-found sentinel. +func TestDescribeNamedChangeSet_OtherError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("access denied")) + + _, err := describeNamedChangeSet(context.Background(), client, "vpc", "cs-1") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.NotErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetNotFound) +} + +// runChangesetCreate must render the diff summary and populate the summary +// map from the created changeset, leaving it in place (no execute call). +func TestRunChangesetCreate_Success(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + client.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{}, nil) + client.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{}, nil) + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil) + + spec := &stackSpec{StackName: "vpc", TemplateBody: "AWSTemplateFormatVersion: '2010-09-09'"} + out := captureStdout(t, func() { + summary, err := runChangesetCreate(context.Background(), client, spec, map[string]any{}) + require.NoError(t, err) + assert.False(t, summary["no_op"].(bool)) + assert.NotEmpty(t, summary["changeset_name"]) + }) + assert.Contains(t, out, "changeset:") +} + +// runChangesetCreate must propagate a createChangeSet failure. +func TestRunChangesetCreate_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, errors.New("access denied")) + + spec := &stackSpec{StackName: "vpc", TemplateBody: "AWSTemplateFormatVersion: '2010-09-09'"} + _, err := runChangesetCreate(context.Background(), client, spec, map[string]any{}) + require.Error(t, err) +} + +// runChangesetExecute's happy path: describe the named changeset, execute it, +// stream events to a terminal success status. +func TestRunChangesetExecute_Success(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + gomock.InOrder( + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + ChangeSetId: awsString("cs-id-1"), + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil), + client.EXPECT().ExecuteChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.ExecuteChangeSetOutput{}, nil), + client.EXPECT().DescribeStackEvents(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackEventsOutput{}, nil), + client.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []cfntypes.Stack{{StackStatus: cfntypes.StackStatusUpdateComplete}}, + }, nil), + ) + + spec := &stackSpec{StackName: "vpc"} + summary, err := runChangesetExecute(context.Background(), client, spec, "cs-1", map[string]any{}) + require.NoError(t, err) + assert.Equal(t, "cs-id-1", summary["changeset_id"]) + assert.Equal(t, string(cfntypes.StackStatusUpdateComplete), summary["final_status"]) +} + +// runChangesetExecute must propagate a describeNamedChangeSet failure without +// ever calling ExecuteChangeSet. +func TestRunChangesetExecute_DescribeError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("not found")) + + spec := &stackSpec{StackName: "vpc"} + _, err := runChangesetExecute(context.Background(), client, spec, "cs-1", map[string]any{}) + require.Error(t, err) +} + +// runChangesetExecute must propagate an executeChangeSet failure without +// streaming events. +func TestRunChangesetExecute_ExecuteError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil) + client.EXPECT().ExecuteChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("boom")) + + spec := &stackSpec{StackName: "vpc"} + _, err := runChangesetExecute(context.Background(), client, spec, "cs-1", map[string]any{}) + require.Error(t, err) +} + +// runChangesetExecute must propagate a streamStackEvents failure (e.g. the +// DescribeStackEvents API call itself failing) without misreporting it as a +// terminal stack status. +func TestRunChangesetExecute_StreamEventsError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + gomock.InOrder( + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil), + client.EXPECT().ExecuteChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.ExecuteChangeSetOutput{}, nil), + client.EXPECT().DescribeStackEvents(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")), + ) + + spec := &stackSpec{StackName: "vpc"} + _, err := runChangesetExecute(context.Background(), client, spec, "cs-1", map[string]any{}) + require.Error(t, err) +} + +// runChangesetExecute must report a failed terminal stack status as an error. +func TestRunChangesetExecute_FailedStatus(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + gomock.InOrder( + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil), + client.EXPECT().ExecuteChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.ExecuteChangeSetOutput{}, nil), + client.EXPECT().DescribeStackEvents(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackEventsOutput{}, nil), + client.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []cfntypes.Stack{{StackStatus: cfntypes.StackStatusUpdateRollbackComplete}}, + }, nil), + ) + + spec := &stackSpec{StackName: "vpc"} + _, err := runChangesetExecute(context.Background(), client, spec, "cs-1", map[string]any{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) +} + +// runChangesetList must render a "no changesets" line and leave summary's +// changesets empty when the stack has none. +func TestRunChangesetList_Empty(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).Return(&cloudformation.ListChangeSetsOutput{}, nil) + + spec := &stackSpec{StackName: "vpc"} + out := captureStdout(t, func() { + summary, err := runChangesetList(context.Background(), client, spec, map[string]any{}) + require.NoError(t, err) + assert.Empty(t, summary["changesets"]) + }) + assert.Contains(t, out, "vpc: no changesets") +} + +// runChangesetList must render one line per changeset and populate the +// summary with every entry. +func TestRunChangesetList_Populated(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).Return(&cloudformation.ListChangeSetsOutput{ + Summaries: []cfntypes.ChangeSetSummary{ + {ChangeSetName: awsString("cs-1"), Status: cfntypes.ChangeSetStatusCreateComplete, Description: awsString("first")}, + {ChangeSetName: awsString("cs-2"), Status: cfntypes.ChangeSetStatusFailed, Description: awsString("second")}, + }, + }, nil) + + spec := &stackSpec{StackName: "vpc"} + out := captureStdout(t, func() { + summary, err := runChangesetList(context.Background(), client, spec, map[string]any{}) + require.NoError(t, err) + assert.Len(t, summary["changesets"].([]cfntypes.ChangeSetSummary), 2) + }) + assert.Contains(t, out, "cs-1") + assert.Contains(t, out, "cs-2") + assert.Contains(t, out, "first") + assert.Contains(t, out, "second") +} + +// runChangesetList must propagate a listChangeSets failure. +func TestRunChangesetList_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + spec := &stackSpec{StackName: "vpc"} + _, err := runChangesetList(context.Background(), client, spec, map[string]any{}) + require.Error(t, err) +} + +// runChangesetDelete must delete the named changeset and report success. +func TestRunChangesetDelete_Success(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DeleteChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DeleteChangeSetOutput{}, nil) + + spec := &stackSpec{StackName: "vpc"} + out := captureStdout(t, func() { + summary, err := runChangesetDelete(context.Background(), client, spec, "cs-1", map[string]any{}) + require.NoError(t, err) + assert.Equal(t, "cs-1", summary["changeset_name"]) + }) + assert.Contains(t, out, `changeset "cs-1" deleted`) +} + +// runChangesetDelete must propagate a deleteChangeSet failure. +func TestRunChangesetDelete_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DeleteChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("boom")) + + spec := &stackSpec{StackName: "vpc"} + _, err := runChangesetDelete(context.Background(), client, spec, "cs-1", map[string]any{}) + require.Error(t, err) +} diff --git a/pkg/component/aws/cloudformation/cloudformation_test.go b/pkg/component/aws/cloudformation/cloudformation_test.go index 4e35c26fe21..904535ca362 100644 --- a/pkg/component/aws/cloudformation/cloudformation_test.go +++ b/pkg/component/aws/cloudformation/cloudformation_test.go @@ -105,6 +105,14 @@ func TestComponentProvider_Execute_MapsSubcommandsToOperations(t *testing.T) { {"validate", OperationValidate}, {"output", OperationOutput}, {"outputs", OperationOutput}, + {"changeset-create", OperationChangesetCreate}, + {"changeset-execute", OperationChangesetExecute}, + {"changeset-list", OperationChangesetList}, + {"changeset-delete", OperationChangesetDelete}, + {"drift-detect", OperationDriftDetect}, + {"drift-describe", OperationDriftDescribe}, + {"get-template", OperationGetTemplate}, + {"get-policy", OperationGetPolicy}, } original := executeOperation diff --git a/pkg/component/aws/cloudformation/confirm_test.go b/pkg/component/aws/cloudformation/confirm_test.go index eb5c1d2a620..980446210f8 100644 --- a/pkg/component/aws/cloudformation/confirm_test.go +++ b/pkg/component/aws/cloudformation/confirm_test.go @@ -50,6 +50,43 @@ func TestRequireConfirmation_AutoApproveSkipsPrompt(t *testing.T) { require.NoError(t, requireConfirmation(OperationDelete, "vpc", flags)) } +// changeset-execute must prompt for confirmation, using the distinct "execute +// changeset against" verb, and must skip the prompt when --auto-approve is set. +func TestRequireConfirmation_ChangesetExecutePrompts(t *testing.T) { + var gotMessage string + original := confirmOperation + confirmOperation = func(message string) (bool, error) { + gotMessage = message + return true, nil + } + t.Cleanup(func() { confirmOperation = original }) + + require.NoError(t, requireConfirmation(OperationChangesetExecute, "vpc", map[string]any{})) + assert.Contains(t, gotMessage, "execute changeset against") + assert.Contains(t, gotMessage, "vpc") +} + +// changeset-execute must respect --auto-approve like apply/delete. +func TestRequireConfirmation_ChangesetExecuteAutoApproveSkipsPrompt(t *testing.T) { + original := confirmOperation + confirmOperation = func(_ string) (bool, error) { + t.Fatal("confirmOperation must not be called when --auto-approve is set") + return false, nil + } + t.Cleanup(func() { confirmOperation = original }) + + require.NoError(t, requireConfirmation(OperationChangesetExecute, "vpc", map[string]any{"auto-approve": true})) +} + +// changeset-execute must abort with ErrUserAborted when declined, same as +// apply/delete. +func TestRequireConfirmation_ChangesetExecuteDeclinedAborts(t *testing.T) { + stubConfirmOperation(t, false, nil) + err := requireConfirmation(OperationChangesetExecute, "vpc", map[string]any{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrUserAborted) +} + // A confirmed prompt allows the operation to proceed. func TestRequireConfirmation_ConfirmedProceeds(t *testing.T) { stubConfirmOperation(t, true, nil) diff --git a/pkg/component/aws/cloudformation/drift.go b/pkg/component/aws/cloudformation/drift.go index eff23ac4d7c..2092447b8f0 100644 --- a/pkg/component/aws/cloudformation/drift.go +++ b/pkg/component/aws/cloudformation/drift.go @@ -14,12 +14,14 @@ import ( ) // driftPollInterval is how often DescribeStackDriftDetectionStatus is polled -// while a drift-detection operation is in progress. -const driftPollInterval = 3 * time.Second +// while a drift-detection operation is in progress. A var (not const) so +// tests can shrink it and exercise the polling loop without a real 3s sleep. +var driftPollInterval = 3 * time.Second // driftDetectionTimeout bounds how long a single drift detection may run before -// this command gives up watching it. -const driftDetectionTimeout = 15 * time.Minute +// this command gives up watching it. A var (not const) so tests can shrink it +// to exercise the timeout branch without waiting 15 real minutes. +var driftDetectionTimeout = 15 * time.Minute // driftDetectionResult is the outcome of running (or re-fetching the status of) // a drift detection operation. diff --git a/pkg/component/aws/cloudformation/drift_test.go b/pkg/component/aws/cloudformation/drift_test.go new file mode 100644 index 00000000000..0a2d3c701dc --- /dev/null +++ b/pkg/component/aws/cloudformation/drift_test.go @@ -0,0 +1,324 @@ +package cloudformation + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" +) + +// shrinkDriftTiming replaces the package's poll interval/timeout with tiny +// values for the duration of a test, restoring the originals on cleanup — +// otherwise the timeout and multi-poll tests below would take real minutes. +func shrinkDriftTiming(t *testing.T, interval, timeout time.Duration) { + t.Helper() + origInterval := driftPollInterval + origTimeout := driftDetectionTimeout + driftPollInterval = interval + driftDetectionTimeout = timeout + t.Cleanup(func() { + driftPollInterval = origInterval + driftDetectionTimeout = origTimeout + }) +} + +// detectDrift's happy path: start detection, then poll once to DETECTION_COMPLETE. +func TestDetectDrift_Success(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Minute) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(&cloudformation.DetectStackDriftOutput{ + StackDriftDetectionId: awsString("detection-1"), + }, nil) + count := int32(2) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionComplete, + StackDriftStatus: cfntypes.StackDriftStatusDrifted, + DriftedStackResourceCount: &count, + }, nil) + + result, err := detectDrift(context.Background(), client, "vpc") + require.NoError(t, err) + assert.Equal(t, "detection-1", result.DetectionID) + assert.True(t, result.DetectionDone) + assert.Equal(t, cfntypes.StackDriftStatusDrifted, result.StackStatus) + assert.Equal(t, int32(2), result.DriftedCount) +} + +// detectDrift must wrap a DetectStackDrift API error without polling. +func TestDetectDrift_StartError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + _, err := detectDrift(context.Background(), client, "vpc") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) +} + +// pollDriftDetection must wrap a DescribeStackDriftDetectionStatus API error. +func TestPollDriftDetection_APIError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(nil, errors.New("access denied")) + + _, err := pollDriftDetection(context.Background(), client, "detection-1") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) +} + +// pollDriftDetection must report DETECTION_FAILED as an error, carrying the +// status reason through. +func TestPollDriftDetection_DetectionFailed(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionFailed, + DetectionStatusReason: awsString("internal failure"), + }, nil) + + result, err := pollDriftDetection(context.Background(), client, "detection-1") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.Contains(t, err.Error(), "internal failure") + assert.False(t, result.DetectionDone) +} + +// pollDriftDetection must keep polling (not return) while DetectionStatus is +// still IN_PROGRESS, then return once it reaches DETECTION_COMPLETE. +func TestPollDriftDetection_ContinuesUntilComplete(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Minute) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + gomock.InOrder( + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionInProgress, + }, nil), + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionComplete, + StackDriftStatus: cfntypes.StackDriftStatusInSync, + }, nil), + ) + + result, err := pollDriftDetection(context.Background(), client, "detection-1") + require.NoError(t, err) + assert.True(t, result.DetectionDone) + assert.Equal(t, cfntypes.StackDriftStatusInSync, result.StackStatus) +} + +// pollDriftDetection must give up once the deadline passes, without ever +// reaching a terminal detection status. +func TestPollDriftDetection_Timeout(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Millisecond) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + // Always in-progress: the timeout, not a terminal status, must end the loop. + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionInProgress, + }, nil).AnyTimes() + + _, err := pollDriftDetection(context.Background(), client, "detection-1") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.Contains(t, err.Error(), "timed out") +} + +// pollDriftDetection must return ctx.Err() when the context is cancelled +// while waiting between polls. +func TestPollDriftDetection_ContextCancelled(t *testing.T) { + shrinkDriftTiming(t, time.Minute, time.Hour) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionInProgress, + }, nil) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + _, err := pollDriftDetection(ctx, client, "detection-1") + require.Error(t, err) + assert.ErrorIs(t, err, context.Canceled) +} + +// describeResourceDrifts must paginate through every NextToken. +func TestDescribeResourceDrifts_Paginates(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + token := "page-2" + gomock.InOrder( + client.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackResourceDriftsOutput{ + StackResourceDrifts: []cfntypes.StackResourceDrift{{LogicalResourceId: awsString("R1")}}, + NextToken: &token, + }, nil), + client.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackResourceDriftsOutput{ + StackResourceDrifts: []cfntypes.StackResourceDrift{{LogicalResourceId: awsString("R2")}}, + }, nil), + ) + + drifts, err := describeResourceDrifts(context.Background(), client, "vpc") + require.NoError(t, err) + require.Len(t, drifts, 2) + assert.Equal(t, "R1", stringValue(drifts[0].LogicalResourceId)) + assert.Equal(t, "R2", stringValue(drifts[1].LogicalResourceId)) +} + +// describeResourceDrifts must wrap an API error. +func TestDescribeResourceDrifts_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + _, err := describeResourceDrifts(context.Background(), client, "vpc") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) +} + +// runDriftDetect's happy path (no --fail-on-drift): renders the summary line +// and never errors, even when drift was actually found. +func TestRunDriftDetect_Success_NoFailOnDrift(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Minute) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(&cloudformation.DetectStackDriftOutput{ + StackDriftDetectionId: awsString("detection-1"), + }, nil) + count := int32(3) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionComplete, + StackDriftStatus: cfntypes.StackDriftStatusDrifted, + DriftedStackResourceCount: &count, + }, nil) + + out := captureStdout(t, func() { + summary, err := runDriftDetect(context.Background(), client, "vpc", false, map[string]any{}) + require.NoError(t, err) + assert.Equal(t, string(cfntypes.StackDriftStatusDrifted), summary["drift_status"]) + assert.Equal(t, int32(3), summary["drifted_resource_count"]) + }) + assert.Contains(t, out, "vpc: DRIFTED (3 resource(s) drifted)") +} + +// runDriftDetect must return ErrAwsCloudFormationDriftDetected when +// --fail-on-drift is set and the stack is drifted. +func TestRunDriftDetect_FailOnDrift(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Minute) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(&cloudformation.DetectStackDriftOutput{ + StackDriftDetectionId: awsString("detection-1"), + }, nil) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionComplete, + StackDriftStatus: cfntypes.StackDriftStatusDrifted, + }, nil) + + _, err := runDriftDetect(context.Background(), client, "vpc", true, map[string]any{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) +} + +// runDriftDetect must NOT fail even with --fail-on-drift set when the stack +// is in fact IN_SYNC — the negative-path complement to +// TestRunDriftDetect_FailOnDrift, proving the failure trigger is gated on the +// drift status, not merely on the flag being set. +func TestRunDriftDetect_FailOnDrift_InSyncDoesNotFail(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Minute) + + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(&cloudformation.DetectStackDriftOutput{ + StackDriftDetectionId: awsString("detection-1"), + }, nil) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionComplete, + StackDriftStatus: cfntypes.StackDriftStatusInSync, + }, nil) + + _, err := runDriftDetect(context.Background(), client, "vpc", true, map[string]any{}) + require.NoError(t, err) +} + +// runDriftDetect must propagate a detectDrift failure. +func TestRunDriftDetect_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(nil, errors.New("boom")) + + _, err := runDriftDetect(context.Background(), client, "vpc", false, map[string]any{}) + require.Error(t, err) +} + +// runDriftDescribe must render a "no drift results" line when the stack has +// none. +func TestRunDriftDescribe_Empty(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackResourceDriftsOutput{}, nil) + + out := captureStdout(t, func() { + summary, err := runDriftDescribe(context.Background(), client, "vpc", map[string]any{}) + require.NoError(t, err) + assert.Empty(t, summary["drifts"]) + }) + assert.Contains(t, out, "vpc: no drift results") +} + +// runDriftDescribe must skip IN_SYNC resources from the rendered output while +// still including them in the summary map, and must print every non-IN_SYNC +// resource. Asserted by presence/absence, not just a non-error return — per +// the no-coverage-theater rule for this exact filter. +func TestRunDriftDescribe_SkipsInSyncResources(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackResourceDriftsOutput{ + StackResourceDrifts: []cfntypes.StackResourceDrift{ + { + StackResourceDriftStatus: cfntypes.StackResourceDriftStatusInSync, + ResourceType: awsString("AWS::S3::Bucket"), + LogicalResourceId: awsString("InSyncBucket"), + }, + { + StackResourceDriftStatus: cfntypes.StackResourceDriftStatusModified, + ResourceType: awsString("AWS::IAM::Role"), + LogicalResourceId: awsString("ModifiedRole"), + }, + }, + }, nil) + + out := captureStdout(t, func() { + summary, err := runDriftDescribe(context.Background(), client, "vpc", map[string]any{}) + require.NoError(t, err) + // The summary keeps every drift result, including IN_SYNC ones — only the + // rendered text output filters them. + assert.Len(t, summary["drifts"].([]cfntypes.StackResourceDrift), 2) + }) + assert.NotContains(t, out, "InSyncBucket", "an IN_SYNC resource must be filtered from the rendered output") + assert.Contains(t, out, "ModifiedRole", "a non-IN_SYNC resource must still be rendered") +} + +// runDriftDescribe must propagate a describeResourceDrifts failure. +func TestRunDriftDescribe_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + _, err := runDriftDescribe(context.Background(), client, "vpc", map[string]any{}) + require.Error(t, err) +} diff --git a/pkg/component/aws/cloudformation/executor_test.go b/pkg/component/aws/cloudformation/executor_test.go index 65eb63e4ff1..5336c2fe04d 100644 --- a/pkg/component/aws/cloudformation/executor_test.go +++ b/pkg/component/aws/cloudformation/executor_test.go @@ -3,9 +3,12 @@ package cloudformation import ( "context" "errors" + "net/http" + "net/http/httptest" "os" "path/filepath" "testing" + "time" "github.com/aws/aws-sdk-go-v2/service/cloudformation" cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" @@ -630,6 +633,31 @@ func TestRunOperation_Apply_ConfirmationDeclined(t *testing.T) { assert.ErrorIs(t, err, errUtils.ErrUserAborted) } +// runOperation must, once confirmation passes and a client is built, look up +// and actually invoke the matching operationHandlers entry (not just resolve +// it) — asserted here by confirming the underlying (real, unreachable) +// endpoint was actually hit rather than merely that runOperation returns. +func TestRunOperation_DispatchesToHandler(t *testing.T) { + // A real server, closed immediately: the port is guaranteed to refuse + // connections, so the real AWS SDK call the dispatched handler makes fails + // fast and deterministically rather than depending on network access. + srv := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) + unreachable := srv.URL + srv.Close() + + info := &schema.ConfigAndStacksInfo{ + ComponentSection: map[string]any{ + "settings": map[string]any{"aws_cloudformation": map[string]any{"region": "us-east-1"}}, + }, + AuthContext: &schema.AuthContext{AWS: &schema.AWSAuthContext{EndpointURL: unreachable}}, + } + spec := &stackSpec{StackName: "vpc"} + octx := &opContext{Ctx: context.Background(), Info: info, Flags: map[string]any{}} + + _, err := runOperation(octx, OperationGetPolicy, spec) + require.Error(t, err, "the dispatched handler must have actually called the (unreachable) endpoint and surfaced its failure") +} + func TestRunOperation_Render_NoAPICalls(t *testing.T) { // Render must never touch the AWS API — no mock expectations set means any // call would fail the test via gomock's unexpected-call panic. @@ -639,3 +667,226 @@ func TestRunOperation_Render_NoAPICalls(t *testing.T) { require.NoError(t, err) assert.Equal(t, spec.TemplateBody, summary["template"]) } + +// changesetNameFlag must extract the string --changeset-name flag, defaulting +// to "" for both an absent key and a wrong-typed value. +func TestChangesetNameFlag(t *testing.T) { + assert.Equal(t, "my-cs", changesetNameFlag(map[string]any{"changeset-name": "my-cs"})) + assert.Empty(t, changesetNameFlag(map[string]any{})) + assert.Empty(t, changesetNameFlag(map[string]any{"changeset-name": 123})) +} + +// operationHandlers must map every Phase 2 Operation to a handler that +// delegates to the matching run*/validateTemplate call — exercised here +// through the map lookup itself (runOperation's real dispatch path), not by +// calling the underlying run* function directly. +func TestOperationHandlers_Dispatch(t *testing.T) { + spec := &stackSpec{StackName: "vpc", TemplateBody: "AWSTemplateFormatVersion: '2010-09-09'"} + octx := &opContext{Ctx: context.Background(), Flags: map[string]any{}} + + tests := []struct { + name string + op Operation + setup func(m *MockCloudFormationClient) + check func(t *testing.T, summary map[string]any) + }{ + { + name: "validate", + op: OperationValidate, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().ValidateTemplate(gomock.Any(), gomock.Any()).Return(&cloudformation.ValidateTemplateOutput{}, nil) + }, + }, + { + name: "diff", + op: OperationDiff, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{}, nil) + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{}, nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil) + }, + check: func(t *testing.T, summary map[string]any) { + assert.False(t, summary["no_op"].(bool)) + }, + }, + { + name: "delete", + op: OperationDelete, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().DeleteStack(gomock.Any(), gomock.Any()).Return(&cloudformation.DeleteStackOutput{}, nil) + m.EXPECT().DescribeStackEvents(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackEventsOutput{}, nil) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{}, nil) + }, + check: func(t *testing.T, summary map[string]any) { + assert.Equal(t, string(cfntypes.StackStatusDeleteComplete), summary["final_status"]) + }, + }, + { + name: "output", + op: OperationOutput, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{}, nil) + }, + }, + { + name: "changeset-create", + op: OperationChangesetCreate, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{}, nil) + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{}, nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeChangeSetOutput{ + Status: cfntypes.ChangeSetStatusCreateComplete, + }, nil) + }, + }, + { + name: "changeset-list", + op: OperationChangesetList, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().ListChangeSets(gomock.Any(), gomock.Any()).Return(&cloudformation.ListChangeSetsOutput{}, nil) + }, + }, + { + name: "drift-describe", + op: OperationDriftDescribe, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().DescribeStackResourceDrifts(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackResourceDriftsOutput{}, nil) + }, + }, + { + name: "get-template", + op: OperationGetTemplate, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).Return(&cloudformation.GetTemplateOutput{TemplateBody: awsString("body")}, nil) + }, + }, + { + name: "get-policy", + op: OperationGetPolicy, + setup: func(m *MockCloudFormationClient) { + m.EXPECT().GetStackPolicy(gomock.Any(), gomock.Any()).Return(&cloudformation.GetStackPolicyOutput{}, nil) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + tt.setup(client) + + handler, ok := operationHandlers[tt.op] + require.True(t, ok, "operationHandlers must have an entry for %q", tt.op) + + captureStdout(t, func() { + summary, err := handler(octx, client, spec, map[string]any{}) + require.NoError(t, err) + if tt.check != nil { + tt.check(t, summary) + } + }) + }) + } +} + +// operationHandlers' changeset-execute entry must thread the --changeset-name +// flag through to runChangesetExecute (via changesetNameFlag). +func TestOperationHandlers_ChangesetExecute_ThreadsChangesetNameFlag(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + var gotChangeSetName *string + gomock.InOrder( + client.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.DescribeChangeSetInput, _ ...func(*cloudformation.Options)) (*cloudformation.DescribeChangeSetOutput, error) { + gotChangeSetName = input.ChangeSetName + return &cloudformation.DescribeChangeSetOutput{Status: cfntypes.ChangeSetStatusCreateComplete}, nil + }, + ), + client.EXPECT().ExecuteChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.ExecuteChangeSetOutput{}, nil), + client.EXPECT().DescribeStackEvents(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackEventsOutput{}, nil), + client.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{}, nil), + ) + + spec := &stackSpec{StackName: "vpc"} + octx := &opContext{Ctx: context.Background(), Flags: map[string]any{"changeset-name": "my-named-cs"}} + + handler, ok := operationHandlers[OperationChangesetExecute] + require.True(t, ok) + _, err := handler(octx, client, spec, map[string]any{}) + require.NoError(t, err) + require.NotNil(t, gotChangeSetName) + assert.Equal(t, "my-named-cs", *gotChangeSetName) +} + +// operationHandlers' changeset-delete entry must thread the --changeset-name +// flag through to runChangesetDelete (via changesetNameFlag). +func TestOperationHandlers_ChangesetDelete_ThreadsChangesetNameFlag(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + var gotChangeSetName *string + client.EXPECT().DeleteChangeSet(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.DeleteChangeSetInput, _ ...func(*cloudformation.Options)) (*cloudformation.DeleteChangeSetOutput, error) { + gotChangeSetName = input.ChangeSetName + return &cloudformation.DeleteChangeSetOutput{}, nil + }, + ) + + spec := &stackSpec{StackName: "vpc"} + octx := &opContext{Ctx: context.Background(), Flags: map[string]any{"changeset-name": "doomed-cs"}} + + handler, ok := operationHandlers[OperationChangesetDelete] + require.True(t, ok) + _, err := handler(octx, client, spec, map[string]any{}) + require.NoError(t, err) + require.NotNil(t, gotChangeSetName) + assert.Equal(t, "doomed-cs", *gotChangeSetName) +} + +// operationHandlers' drift-detect entry must thread the --fail-on-drift flag +// through to runDriftDetect, both when set and when absent. +func TestOperationHandlers_DriftDetect_ThreadsFailOnDriftFlag(t *testing.T) { + shrinkDriftTiming(t, time.Millisecond, time.Minute) + + tests := []struct { + name string + flags map[string]any + driftStatus cfntypes.StackDriftStatus + wantErr bool + }{ + {"fail-on-drift set, stack drifted", map[string]any{"fail-on-drift": true}, cfntypes.StackDriftStatusDrifted, true}, + {"fail-on-drift absent, stack drifted", map[string]any{}, cfntypes.StackDriftStatusDrifted, false}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().DetectStackDrift(gomock.Any(), gomock.Any()).Return(&cloudformation.DetectStackDriftOutput{ + StackDriftDetectionId: awsString("detection-1"), + }, nil) + client.EXPECT().DescribeStackDriftDetectionStatus(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackDriftDetectionStatusOutput{ + DetectionStatus: cfntypes.StackDriftDetectionStatusDetectionComplete, + StackDriftStatus: tt.driftStatus, + }, nil) + + spec := &stackSpec{StackName: "vpc"} + octx := &opContext{Ctx: context.Background(), Flags: tt.flags} + + handler, ok := operationHandlers[OperationDriftDetect] + require.True(t, ok) + captureStdout(t, func() { + _, err := handler(octx, client, spec, map[string]any{}) + if tt.wantErr { + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + } else { + require.NoError(t, err) + } + }) + }) + } +} diff --git a/pkg/component/aws/cloudformation/get_test.go b/pkg/component/aws/cloudformation/get_test.go new file mode 100644 index 00000000000..435474eb9db --- /dev/null +++ b/pkg/component/aws/cloudformation/get_test.go @@ -0,0 +1,176 @@ +package cloudformation + +import ( + "context" + "errors" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" +) + +// getDeployedTemplate must request TemplateStageOriginal only when original +// is true, and the processed (default) stage otherwise. +func TestGetDeployedTemplate_OriginalVsProcessed(t *testing.T) { + tests := []struct { + name string + original bool + wantStage cfntypes.TemplateStage + wantNoneSet bool + }{ + {"original stage", true, cfntypes.TemplateStageOriginal, false}, + {"default (processed) stage", false, "", true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + var gotStage cfntypes.TemplateStage + client.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.GetTemplateInput, _ ...func(*cloudformation.Options)) (*cloudformation.GetTemplateOutput, error) { + gotStage = input.TemplateStage + return &cloudformation.GetTemplateOutput{TemplateBody: awsString("Resources: {}")}, nil + }, + ) + + body, err := getDeployedTemplate(context.Background(), client, "vpc", tt.original) + require.NoError(t, err) + assert.Equal(t, "Resources: {}", body) + if tt.wantNoneSet { + assert.Empty(t, gotStage, "the zero-value TemplateStage must be left unset (processed, CloudFormation's default) when original is false") + } else { + assert.Equal(t, tt.wantStage, gotStage) + } + }) + } +} + +// getDeployedTemplate must wrap a GetTemplate API error. +func TestGetDeployedTemplate_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).Return(nil, errors.New("access denied")) + + _, err := getDeployedTemplate(context.Background(), client, "vpc", false) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) +} + +// getDeployedStackPolicy must return the policy body on success, including +// "" when the stack has no policy set (CloudFormation's own contract — no +// error in that case). +func TestGetDeployedStackPolicy_Success(t *testing.T) { + tests := []struct { + name string + body *string + want string + }{ + {"policy set", awsString(`{"Statement": []}`), `{"Statement": []}`}, + {"no policy set", nil, ""}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetStackPolicy(gomock.Any(), gomock.Any()).Return(&cloudformation.GetStackPolicyOutput{ + StackPolicyBody: tt.body, + }, nil) + + body, err := getDeployedStackPolicy(context.Background(), client, "vpc") + require.NoError(t, err) + assert.Equal(t, tt.want, body) + }) + } +} + +// getDeployedStackPolicy must wrap a GetStackPolicy API error. +func TestGetDeployedStackPolicy_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetStackPolicy(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + _, err := getDeployedStackPolicy(context.Background(), client, "vpc") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) +} + +// runGetTemplate must write the template body to the data channel and +// populate the summary, honoring the --original flag. +func TestRunGetTemplate_Success(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + var gotStage cfntypes.TemplateStage + client.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.GetTemplateInput, _ ...func(*cloudformation.Options)) (*cloudformation.GetTemplateOutput, error) { + gotStage = input.TemplateStage + return &cloudformation.GetTemplateOutput{TemplateBody: awsString("AWSTemplateFormatVersion: '2010-09-09'")}, nil + }, + ) + + out := captureStdout(t, func() { + summary, err := runGetTemplate(context.Background(), client, "vpc", map[string]any{"original": true}, map[string]any{}) + require.NoError(t, err) + assert.Equal(t, "AWSTemplateFormatVersion: '2010-09-09'", summary["template"]) + }) + assert.Equal(t, cfntypes.TemplateStageOriginal, gotStage) + assert.Contains(t, out, "AWSTemplateFormatVersion") +} + +// runGetTemplate must propagate a getDeployedTemplate failure. +func TestRunGetTemplate_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).Return(nil, errors.New("boom")) + + _, err := runGetTemplate(context.Background(), client, "vpc", map[string]any{}, map[string]any{}) + require.Error(t, err) +} + +// runGetPolicy must write the policy body to the data channel when set. +func TestRunGetPolicy_PolicySet(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetStackPolicy(gomock.Any(), gomock.Any()).Return(&cloudformation.GetStackPolicyOutput{ + StackPolicyBody: awsString(`{"Statement": []}`), + }, nil) + + out := captureStdout(t, func() { + summary, err := runGetPolicy(context.Background(), client, "vpc", map[string]any{}) + require.NoError(t, err) + assert.Equal(t, `{"Statement": []}`, summary["stack_policy"]) + }) + assert.Contains(t, out, `{"Statement": []}`) +} + +// runGetPolicy must render a "no stack policy set" line, not the raw body, +// when the stack has no policy — the branch this test targets. +func TestRunGetPolicy_NoPolicySet(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetStackPolicy(gomock.Any(), gomock.Any()).Return(&cloudformation.GetStackPolicyOutput{}, nil) + + out := captureStdout(t, func() { + summary, err := runGetPolicy(context.Background(), client, "vpc", map[string]any{}) + require.NoError(t, err) + assert.Empty(t, summary["stack_policy"]) + }) + assert.Contains(t, out, "vpc: no stack policy set") +} + +// runGetPolicy must propagate a getDeployedStackPolicy failure. +func TestRunGetPolicy_Error(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + client.EXPECT().GetStackPolicy(gomock.Any(), gomock.Any()).Return(nil, errors.New("throttled")) + + _, err := runGetPolicy(context.Background(), client, "vpc", map[string]any{}) + require.Error(t, err) +} diff --git a/tests/fixtures/scenarios/aws-cloudformation-outputs/atmos.yaml b/tests/fixtures/scenarios/aws-cloudformation-outputs/atmos.yaml new file mode 100644 index 00000000000..e611ac07c2e --- /dev/null +++ b/tests/fixtures/scenarios/aws-cloudformation-outputs/atmos.yaml @@ -0,0 +1,15 @@ +base_path: "./" + +components: + "aws/cloudformation": + base_path: "components/cloudformation" + +stacks: + base_path: "stacks" + included_paths: + - "**/*" + excluded_paths: [] + name_template: "{{ .vars.stage }}" + +logs: + level: Info diff --git a/tests/fixtures/scenarios/aws-cloudformation-outputs/stacks/test.yaml b/tests/fixtures/scenarios/aws-cloudformation-outputs/stacks/test.yaml new file mode 100644 index 00000000000..be26edeafed --- /dev/null +++ b/tests/fixtures/scenarios/aws-cloudformation-outputs/stacks/test.yaml @@ -0,0 +1,22 @@ +# Minimal fixture for testing the `!aws.cloudformation.output` YAML function +# and atmos.Component(...).outputs' aws/cloudformation branch, both of which +# resolve a target component's sections via ExecuteDescribeComponent and then +# fetch its deployed Outputs through the cloudFormationOutputsGetter seam +# (stubbed in tests — no real AWS call happens against this fixture). +vars: + stage: test + +components: + "aws/cloudformation": + vpc: + metadata: + component: vpc + template: template.yaml + stack_name: "test-vpc" + settings: + aws_cloudformation: + region: us-east-1 + no-stack-name: + metadata: + component: no-stack-name + template: template.yaml From 84feebfba35f7a6a8cec80a52654b357da669770 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Tue, 25 Aug 2026 10:46:46 -0500 Subject: [PATCH 03/10] feat(cloudformation): add fmt, list, and source inspection verbs (Phase 2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - atmos aws cloudformation fmt [--check]: native, dependency-free comment-preserving YAML round-trip via yaml.v3's Node API (no cfn-format binary exists to shell out to, and Rain's own formatter is archived along with the rest of Rain). Both fmt and render are exempted from the auth-manager setup every other operation requires — neither calls the CloudFormation API. - atmos aws cloudformation list [--status ...] [--region ...]: account-wide ListStacks, annotated "managed"/"unmanaged" against the queried stack's configured aws/cloudformation components by stack_name. Unlike every other verb this isn't scoped to one component, so it bypasses ComponentProvider.Execute entirely and calls the new pkg/component/aws/cloudformation.ListDeployedStacks directly. - atmos aws cloudformation source pull/list/describe/delete: wired onto the existing generic pkg/provisioner/source/cmd builders already shared by terraform/helmfile/packer — needed one addition, Config.CLIName, since those three all happen to have a CLI command name identical to their internal ComponentType string ("terraform" IS "terraform"), which "aws/cloudformation" (type) vs. "aws cloudformation" (CLI path) breaks; CLIName defaults to ComponentType so the other three callers are unaffected. Verified live against the Floci AWS emulator: fmt --check/apply against the example's template (confirmed short-form intrinsic tags like !Sub/!Ref round-trip correctly, comments survive), list correctly marking a deployed stack "managed" against its configured stack_name, and source describe correctly reporting "not configured" for a component with no source: section. Co-Authored-By: Claude Sonnet 5 --- cmd/aws/cloudformation/cloudformation.go | 10 +- cmd/aws/cloudformation/list.go | 128 ++++++++++++++++++ cmd/aws/cloudformation/source/source.go | 47 +++++++ errors/errors.go | 1 + .../aws/cloudformation/cloudformation.go | 1 + pkg/component/aws/cloudformation/executor.go | 15 +- pkg/component/aws/cloudformation/fmt.go | 83 ++++++++++++ pkg/component/aws/cloudformation/list.go | 116 ++++++++++++++++ pkg/component/aws/cloudformation/spec.go | 1 + pkg/component/aws/cloudformation/template.go | 15 +- pkg/component/aws/cloudformation/types.go | 2 + pkg/provisioner/source/cmd/config.go | 16 ++- pkg/provisioner/source/cmd/delete.go | 4 +- pkg/provisioner/source/cmd/describe.go | 2 +- pkg/provisioner/source/cmd/list.go | 5 +- pkg/provisioner/source/cmd/pull.go | 2 +- 16 files changed, 435 insertions(+), 13 deletions(-) create mode 100644 cmd/aws/cloudformation/list.go create mode 100644 cmd/aws/cloudformation/source/source.go create mode 100644 pkg/component/aws/cloudformation/fmt.go create mode 100644 pkg/component/aws/cloudformation/list.go diff --git a/cmd/aws/cloudformation/cloudformation.go b/cmd/aws/cloudformation/cloudformation.go index ccff993bab3..5118508efad 100644 --- a/cmd/aws/cloudformation/cloudformation.go +++ b/cmd/aws/cloudformation/cloudformation.go @@ -9,6 +9,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" + "github.com/cloudposse/atmos/cmd/aws/cloudformation/source" errUtils "github.com/cloudposse/atmos/errors" e "github.com/cloudposse/atmos/internal/exec" "github.com/cloudposse/atmos/pkg/component" @@ -83,6 +84,9 @@ func init() { CloudFormationCmd.AddCommand(newChangesetCmd()) CloudFormationCmd.AddCommand(newDriftCmd()) CloudFormationCmd.AddCommand(newGetCmd()) + CloudFormationCmd.AddCommand(newOperationCommand("fmt", "fmt", "Format the local template in place (or check formatting with --check)")) + CloudFormationCmd.AddCommand(newListCmd()) + CloudFormationCmd.AddCommand(source.GetSourceCommand()) } // newChangesetCmd is the `atmos aws cloudformation changeset` verb group: manual @@ -235,6 +239,10 @@ func operationSpecificFlagOptions(use, subCommand string) []flags.Option { return []flags.Option{ flags.WithBoolFlag("original", "", false, "Fetch the user-submitted template instead of the processed one."), } + case "fmt": + return []flags.Option{ + flags.WithBoolFlag("check", "", false, "Report whether the template is formatted without writing changes (non-zero exit if not)."), + } default: return nil } @@ -319,7 +327,7 @@ func runOperation(cmd *cobra.Command, subCommand string, args []string) error { func getOperationFlags(cmd *cobra.Command) map[string]any { result := make(map[string]any) - for _, name := range []string{flagAll, flagAffected, "include-dependents", "clone-target-ref", flagAutoApprove, "disable-termination-protection", "flatten", "uppercase", "fail-on-drift", "original"} { + for _, name := range []string{flagAll, flagAffected, "include-dependents", "clone-target-ref", flagAutoApprove, "disable-termination-protection", "flatten", "uppercase", "fail-on-drift", "original", "check"} { if flag := cmd.Flag(name); flag != nil { result[name] = flag.Value.String() == valueTrue } diff --git a/cmd/aws/cloudformation/list.go b/cmd/aws/cloudformation/list.go new file mode 100644 index 00000000000..c793d33b485 --- /dev/null +++ b/cmd/aws/cloudformation/list.go @@ -0,0 +1,128 @@ +package cloudformation + +import ( + "context" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + + e "github.com/cloudposse/atmos/internal/exec" + "github.com/cloudposse/atmos/pkg/auth" + pkgcfn "github.com/cloudposse/atmos/pkg/component/aws/cloudformation" + cfg "github.com/cloudposse/atmos/pkg/config" + "github.com/cloudposse/atmos/pkg/flags" + "github.com/cloudposse/atmos/pkg/schema" +) + +// newListCmd is the `atmos aws cloudformation list` command: an account-wide +// ListStacks, annotated against the queried stack's configured +// aws/cloudformation components by stack_name. Unlike every other verb, this +// is not scoped to one component (there is no `[component]` argument), so it +// doesn't go through newOperationCommand/ComponentProvider.Execute — it calls +// pkg/component/aws/cloudformation.ListDeployedStacks directly, the same way +// cmd/aws/cloudformation/source's verbs bypass Execute for their own +// non-component-scoped inspection commands. +func newListCmd() *cobra.Command { + parser := flags.NewStandardParser( + flags.WithStackFlag(), + flags.WithIdentityFlag(), + flags.WithStringSliceFlag("status", "", nil, "Filter by stack status (comma-separated, e.g. CREATE_COMPLETE,UPDATE_COMPLETE)."), + flags.WithStringFlag("region", "", "", "AWS region to list stacks in. Defaults to the active identity's region, then the SDK's standard resolution chain."), + ) + + cmd := &cobra.Command{ + Use: "list", + Short: "List deployed CloudFormation stacks in the account", + Long: `List the account's deployed CloudFormation stacks (ListStacks), annotated with +whether each one matches an aws/cloudformation component's stack_name configured +in the given stack.`, + Example: ` # List all stacks in the account, annotated against the "dev" stack's components + atmos aws cloudformation list --stack dev + + # Only stacks currently in a *_COMPLETE status + atmos aws cloudformation list --stack dev --status CREATE_COMPLETE,UPDATE_COMPLETE`, + RunE: runList, + } + parser.RegisterFlags(cmd) + if err := parser.BindToViper(viper.GetViper()); err != nil { + panic(err) + } + return cmd +} + +func runList(cmd *cobra.Command, _ []string) error { + info := buildConfigAndStacksInfo(cmd) + atmosConfig, err := cfnInitCliConfig(info, true) + if err != nil { + return err + } + + authManager, err := e.SetupComponentAuthForCLI(&atmosConfig, &info) + if err != nil { + return err + } + e.PropagateAuth(&info, authManager) + + configuredStackNames, err := configuredCloudFormationStackNames(&atmosConfig, info.Stack, authManager) + if err != nil { + return err + } + + statusFilter, _ := cmd.Flags().GetStringSlice("status") + region, _ := cmd.Flags().GetString("region") + + stacks, err := pkgcfn.ListDeployedStacks(context.Background(), &info, region, statusFilter, configuredStackNames) + if err != nil { + return err + } + pkgcfn.RenderDeployedStacksList(stacks) + return nil +} + +// configuredCloudFormationStackNames returns the set of stack_name values +// configured on aws/cloudformation components in the given Atmos stack, used +// to annotate `list`'s output as "managed" vs. "unmanaged". Templates are +// processed (so a component's stack_name may reference {{ .vars.stage }}) but +// YAML functions are not — they aren't needed to resolve stack_name and some +// require their own authentication, which would slow this down unnecessarily. +func configuredCloudFormationStackNames(atmosConfig *schema.AtmosConfiguration, stack string, authManager auth.AuthManager) (map[string]bool, error) { + stacksMap, err := cfnDescribeStacks(atmosConfig, stack, nil, []string{cfg.CloudFormationComponentType}, nil, false, true, false, false, nil, authManager) + if err != nil { + return nil, err + } + componentNames, err := cfnListAllComponents(context.Background(), cfg.CloudFormationComponentType, stacksMap) + if err != nil { + return nil, err + } + + names := make(map[string]bool, len(componentNames)) + for _, componentName := range componentNames { + if name, ok := cloudFormationComponentStackName(stacksMap, stack, componentName); ok { + names[name] = true + } + } + return names, nil +} + +// cloudFormationComponentStackName reads components.aws/cloudformation..stack_name +// out of a stacksMap built by ExecuteDescribeStacks. +func cloudFormationComponentStackName(stacksMap map[string]any, stack, componentName string) (string, bool) { + stackSection, ok := stacksMap[stack].(map[string]any) + if !ok { + return "", false + } + componentsSection, ok := stackSection["components"].(map[string]any) + if !ok { + return "", false + } + typeSection, ok := componentsSection[cfg.CloudFormationComponentType].(map[string]any) + if !ok { + return "", false + } + componentSection, ok := typeSection[componentName].(map[string]any) + if !ok { + return "", false + } + name, ok := componentSection[cfg.StackNameSectionName].(string) + return name, ok && name != "" +} diff --git a/cmd/aws/cloudformation/source/source.go b/cmd/aws/cloudformation/source/source.go new file mode 100644 index 00000000000..d933746076b --- /dev/null +++ b/cmd/aws/cloudformation/source/source.go @@ -0,0 +1,47 @@ +// Package source provides CLI commands for inspecting aws/cloudformation component sources. +// This includes JIT (just-in-time) vendoring from source configuration. +package source + +import ( + "github.com/spf13/cobra" + + cfg "github.com/cloudposse/atmos/pkg/config" + sourcecmd "github.com/cloudposse/atmos/pkg/provisioner/source/cmd" +) + +// cloudFormationConfig holds the component-type-specific configuration for aws/cloudformation. +var cloudFormationConfig = &sourcecmd.Config{ + ComponentType: cfg.CloudFormationComponentType, + TypeLabel: "CloudFormation", + CLIName: "aws cloudformation", +} + +// sourceCmd represents the source command. +var sourceCmd = &cobra.Command{ + Use: "source", + Short: "Manage aws/cloudformation component sources (JIT vendoring)", + Long: `Manage aws/cloudformation component sources defined in stack configuration. + +The source provisioner enables just-in-time (JIT) vendoring of component sources +directly from stack configuration. Components can declare their source location +inline using the source field without requiring a separate component.yaml file. + +Commands: + pull Vendor component source (use --force to re-vendor) + list List components with source in a stack + describe Show source configuration for a component + delete Remove vendored source directory`, +} + +func init() { + // Add subcommands from shared package. + sourceCmd.AddCommand(sourcecmd.PullCommand(cloudFormationConfig)) + sourceCmd.AddCommand(sourcecmd.ListCommand(cloudFormationConfig)) + sourceCmd.AddCommand(sourcecmd.DescribeCommand(cloudFormationConfig)) + sourceCmd.AddCommand(sourcecmd.DeleteCommand(cloudFormationConfig)) +} + +// GetSourceCommand returns the source command for parent registration. +func GetSourceCommand() *cobra.Command { + return sourceCmd +} diff --git a/errors/errors.go b/errors/errors.go index 1b6e7f5d221..9c8374e6ca4 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1628,6 +1628,7 @@ var ( ErrAwsCloudFormationComponentArgRequired = errors.New("requires exactly one component argument unless --all or --affected is set") ErrAwsCloudFormationIdentityResolutionFailed = errors.New("aws/cloudformation component requested an identity, but the auth manager could not resolve it") ErrAwsCloudFormationAPICallFailed = errors.New("aws/cloudformation API call failed") + ErrAwsCloudFormationFmtNotClean = errors.New("aws/cloudformation template is not formatted") ) // Stack dependency (`depends_on`) resolution errors. diff --git a/pkg/component/aws/cloudformation/cloudformation.go b/pkg/component/aws/cloudformation/cloudformation.go index 351c3f58ad2..64cf7e4aa4c 100644 --- a/pkg/component/aws/cloudformation/cloudformation.go +++ b/pkg/component/aws/cloudformation/cloudformation.go @@ -104,6 +104,7 @@ var subCommandOperations = map[string]Operation{ "drift-describe": OperationDriftDescribe, "get-template": OperationGetTemplate, "get-policy": OperationGetPolicy, + "fmt": OperationFmt, } // Execute runs the requested subcommand for an aws/cloudformation component. diff --git a/pkg/component/aws/cloudformation/executor.go b/pkg/component/aws/cloudformation/executor.go index 64e98a21caf..6c9479ccd64 100644 --- a/pkg/component/aws/cloudformation/executor.go +++ b/pkg/component/aws/cloudformation/executor.go @@ -80,7 +80,7 @@ func executeSingle(ctx *component.ExecutionContext, atmosConfig *schema.AtmosCon return err } - if operation != OperationRender { + if !operationsSkippingAuth[operation] { authManager, err := setupComponentAuthForCLI(atmosConfig, info) if err != nil { return err @@ -96,6 +96,15 @@ func executeSingle(ctx *component.ExecutionContext, atmosConfig *schema.AtmosCon return runWithHooks(ctx, atmosConfig, info, operation, spec) } +// operationsSkippingAuth are operations that never call the CloudFormation API +// and so need no active identity: render (client-side template rendering) and +// fmt (a local YAML round-trip, no different from running it against a file +// with a text editor). +var operationsSkippingAuth = map[Operation]bool{ + OperationRender: true, + OperationFmt: true, +} + // operationsSkippingTemplateLoad are operations that act on a deployed stack by // name/ID (delete, explicit changeset execute/list/delete, drift, get) and never // send a local template to CloudFormation, so loading and reading the template @@ -134,6 +143,7 @@ func resolveSpecAndTemplate(atmosConfig *schema.AtmosConfiguration, info *schema return spec, nil } + spec.TemplateAbsPath = resolveTemplateFilePath(componentPath, spec) spec.TemplateBody, err = loadTemplateBody(componentPath, spec) if err != nil { return nil, err @@ -242,6 +252,9 @@ func runOperation(octx *opContext, operation Operation, spec *stackSpec) (map[st summary["template"] = spec.TemplateBody return summary, nil } + if operation == OperationFmt { + return runFmt(spec, octx.Flags, summary) + } if err := requireConfirmation(operation, spec.StackName, octx.Flags); err != nil { return summary, err diff --git a/pkg/component/aws/cloudformation/fmt.go b/pkg/component/aws/cloudformation/fmt.go new file mode 100644 index 00000000000..9bca15c01e1 --- /dev/null +++ b/pkg/component/aws/cloudformation/fmt.go @@ -0,0 +1,83 @@ +package cloudformation + +import ( + "bytes" + "fmt" + "os" + + "gopkg.in/yaml.v3" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/data" + "github.com/cloudposse/atmos/pkg/perf" +) + +// yamlIndent is the indentation width formatTemplate re-emits with, matching +// this codebase's general YAML formatting convention. +const yamlIndent = 2 + +// templateFilePermissions matches the mode template files are typically +// authored with. +const templateFilePermissions = 0o644 + +// formatTemplate re-serializes a CloudFormation template with consistent +// indentation, preserving comments and key order via yaml.v3's Node API. +// Plain gopkg.in/yaml.v3 (not the Atmos custom-tag-aware u.UnmarshalYAML) is +// used deliberately, matching parameters.go's registerNoEchoValues. CFN's +// short-form intrinsic function tags (such as Ref, Sub, and GetAtt) would +// otherwise be rejected as unknown Atmos custom tags. There is no cfn-format +// binary to shell out to (and Rain's own formatter is archived along with the +// rest of Rain — see the PRD's migration notes), so this is a native, +// dependency-free round-trip rather than a wrapped external tool. +func formatTemplate(body string) (string, error) { + defer perf.Track(nil, "cloudformation.formatTemplate")() + + var doc yaml.Node + if err := yaml.Unmarshal([]byte(body), &doc); err != nil { + return "", fmt.Errorf("%w: %w", errUtils.ErrInvalidAwsCloudFormationSettings, err) + } + + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + enc.SetIndent(yamlIndent) + if err := enc.Encode(&doc); err != nil { + return "", fmt.Errorf("%w: %w", errUtils.ErrInvalidAwsCloudFormationSettings, err) + } + if err := enc.Close(); err != nil { + return "", fmt.Errorf("%w: %w", errUtils.ErrInvalidAwsCloudFormationSettings, err) + } + + return buf.String(), nil +} + +// runFmt formats the component's local template. With --check, reports +// whether the file is already formatted (via ErrAwsCloudFormationFmtNotClean, +// for CI) without writing; otherwise formats in place. +func runFmt(spec *stackSpec, flags map[string]any, summary map[string]any) (map[string]any, error) { + formatted, err := formatTemplate(spec.TemplateBody) + if err != nil { + return summary, err + } + + clean := formatted == spec.TemplateBody + summary["formatted"] = !clean + + check, _ := flags["check"].(bool) + if check { + if !clean { + _ = data.Writeln(fmt.Sprintf("%s: not formatted", spec.TemplateAbsPath)) + return summary, fmt.Errorf("%w: %s", errUtils.ErrAwsCloudFormationFmtNotClean, spec.TemplateAbsPath) + } + _ = data.Writeln(fmt.Sprintf("%s: formatted", spec.TemplateAbsPath)) + return summary, nil + } + + if clean { + return summary, nil + } + if err := os.WriteFile(spec.TemplateAbsPath, []byte(formatted), templateFilePermissions); err != nil { + return summary, fmt.Errorf("%w: %s: %w", errUtils.ErrAwsCloudFormationFmtNotClean, spec.TemplateAbsPath, err) + } + _ = data.Writeln(fmt.Sprintf("%s: formatted", spec.TemplateAbsPath)) + return summary, nil +} diff --git a/pkg/component/aws/cloudformation/list.go b/pkg/component/aws/cloudformation/list.go new file mode 100644 index 00000000000..abafc16a4ff --- /dev/null +++ b/pkg/component/aws/cloudformation/list.go @@ -0,0 +1,116 @@ +package cloudformation + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/data" + "github.com/cloudposse/atmos/pkg/perf" + "github.com/cloudposse/atmos/pkg/schema" +) + +// DeployedStackSummary is one entry in `atmos aws cloudformation list`'s +// output: a live CloudFormation stack, annotated with whether its name matches +// an aws/cloudformation component's stack_name configured in the queried +// Atmos stack. +type DeployedStackSummary struct { + StackName string + Status string + Managed bool +} + +// listDeployedStacks fetches account stacks via ListStacks, paginating +// through NextToken, optionally filtered by status. +func listDeployedStacks(ctx context.Context, client CloudFormationClient, statusFilter []cfntypes.StackStatus) ([]cfntypes.StackSummary, error) { + defer perf.Track(nil, "cloudformation.listDeployedStacks")() + + var stacks []cfntypes.StackSummary + var nextToken *string + for { + out, err := client.ListStacks(ctx, &cloudformation.ListStacksInput{ + StackStatusFilter: statusFilter, + NextToken: nextToken, + }) + if err != nil { + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + } + stacks = append(stacks, out.StackSummaries...) + if out.NextToken == nil { + return stacks, nil + } + nextToken = out.NextToken + } +} + +// ListDeployedStacks resolves credentials for the active identity, fetches the +// account's deployed CloudFormation stacks, and annotates each one with +// whether it matches a configured aws/cloudformation component's stack_name +// (configuredStackNames — built by the CLI layer from the queried Atmos +// stack's components, since matching stack_name against Atmos configuration is +// outside this SDK-only package's concern). +func ListDeployedStacks( + ctx context.Context, + info *schema.ConfigAndStacksInfo, + region string, + statusFilter []string, + configuredStackNames map[string]bool, +) ([]DeployedStackSummary, error) { + defer perf.Track(nil, "cloudformation.ListDeployedStacks")() + + awsCfg, err := buildAWSConfig(ctx, info, region) + if err != nil { + return nil, err + } + client := newClient(awsCfg, resolveEndpointURL(info)) + + stacks, err := listDeployedStacks(ctx, client, toStackStatuses(statusFilter)) + if err != nil { + return nil, err + } + + summaries := make([]DeployedStackSummary, 0, len(stacks)) + for i := range stacks { + s := &stacks[i] + name := stringValue(s.StackName) + summaries = append(summaries, DeployedStackSummary{ + StackName: name, + Status: string(s.StackStatus), + Managed: configuredStackNames[name], + }) + } + return summaries, nil +} + +// toStackStatuses converts CLI-provided status strings to the SDK's enum type. +func toStackStatuses(statusFilter []string) []cfntypes.StackStatus { + if len(statusFilter) == 0 { + return nil + } + statuses := make([]cfntypes.StackStatus, 0, len(statusFilter)) + for _, s := range statusFilter { + statuses = append(statuses, cfntypes.StackStatus(s)) + } + return statuses +} + +// RenderDeployedStacksList writes the list to the data channel (stdout) as a +// simple table: one line per stack, with a "MANAGED"/"unmanaged" marker. +func RenderDeployedStacksList(stacks []DeployedStackSummary) { + defer perf.Track(nil, "cloudformation.RenderDeployedStacksList")() + + if len(stacks) == 0 { + _ = data.Writeln("No stacks found.") + return + } + for _, s := range stacks { + managed := "unmanaged" + if s.Managed { + managed = "managed" + } + _ = data.Writeln(fmt.Sprintf("%-9s %-30s %s", managed, s.Status, s.StackName)) + } +} diff --git a/pkg/component/aws/cloudformation/spec.go b/pkg/component/aws/cloudformation/spec.go index 22554ba717e..ba827ccbbce 100644 --- a/pkg/component/aws/cloudformation/spec.go +++ b/pkg/component/aws/cloudformation/spec.go @@ -18,6 +18,7 @@ import ( type stackSpec struct { StackName string TemplatePath string + TemplateAbsPath string TemplateBody string Parameters []cfntypes.Parameter Capabilities []cfntypes.Capability diff --git a/pkg/component/aws/cloudformation/template.go b/pkg/component/aws/cloudformation/template.go index 1c01eca2f69..3427d262d06 100644 --- a/pkg/component/aws/cloudformation/template.go +++ b/pkg/component/aws/cloudformation/template.go @@ -20,16 +20,23 @@ func resolveComponentPath(atmosConfig *schema.AtmosConfiguration, info *schema.C return u.GetComponentPath(atmosConfig, cfg.CloudFormationComponentType, info.ComponentFolderPrefix, info.FinalComponent) } +// resolveTemplateFilePath resolves the component's template file's absolute +// path, joined with componentPath when spec.TemplatePath is relative. +func resolveTemplateFilePath(componentPath string, spec *stackSpec) string { + templateFile := spec.TemplatePath + if !filepath.IsAbs(templateFile) { + templateFile = filepath.Join(componentPath, templateFile) + } + return templateFile +} + // loadTemplateBody reads the component's template file from disk, resolved // relative to componentPath. Returns ErrMissingAwsCloudFormationTemplate wrapped // with the resolved path when the file cannot be read. func loadTemplateBody(componentPath string, spec *stackSpec) (string, error) { defer perf.Track(nil, "cloudformation.loadTemplateBody")() - templateFile := spec.TemplatePath - if !filepath.IsAbs(templateFile) { - templateFile = filepath.Join(componentPath, templateFile) - } + templateFile := resolveTemplateFilePath(componentPath, spec) data, err := os.ReadFile(templateFile) if err != nil { diff --git a/pkg/component/aws/cloudformation/types.go b/pkg/component/aws/cloudformation/types.go index 2a20daea48e..91000933746 100644 --- a/pkg/component/aws/cloudformation/types.go +++ b/pkg/component/aws/cloudformation/types.go @@ -32,4 +32,6 @@ const ( OperationGetTemplate Operation = "get-template" // OperationGetPolicy fetches the deployed stack's policy. OperationGetPolicy Operation = "get-policy" + // OperationFmt formats the local template in place (or checks formatting with --check). + OperationFmt Operation = "fmt" ) diff --git a/pkg/provisioner/source/cmd/config.go b/pkg/provisioner/source/cmd/config.go index 5c81ab52b57..c090cba7f0b 100644 --- a/pkg/provisioner/source/cmd/config.go +++ b/pkg/provisioner/source/cmd/config.go @@ -5,8 +5,22 @@ package cmd // Config holds component-type-specific configuration for source commands. type Config struct { - // ComponentType identifies the component type (e.g., "terraform", "helmfile", "packer"). + // ComponentType identifies the component type (e.g., "terraform", "helmfile", "packer", + // "aws/cloudformation") for internal dispatch (stack-config lookups, perf.Track labels). ComponentType string // TypeLabel is the display name for the component type (e.g., "Terraform", "Helmfile", "Packer"). TypeLabel string + // CLIName is the command path used in generated Example/Long text (e.g. "terraform", + // "aws cloudformation"). Falls back to ComponentType via CLI() when unset — the common + // case for types whose CLI command name matches their internal ComponentType exactly. + CLIName string +} + +// CLI returns the command path to use in generated help/example text, falling +// back to ComponentType for types whose CLI invocation matches it exactly. +func (c *Config) CLI() string { + if c.CLIName != "" { + return c.CLIName + } + return c.ComponentType } diff --git a/pkg/provisioner/source/cmd/delete.go b/pkg/provisioner/source/cmd/delete.go index bf77cd9a914..32a8025f2df 100644 --- a/pkg/provisioner/source/cmd/delete.go +++ b/pkg/provisioner/source/cmd/delete.go @@ -32,12 +32,12 @@ func DeleteCommand(config *Config) *cobra.Command { This command removes the component directory that was created by 'atmos %s source pull'. -If component is not specified, prompts interactively for selection.`, config.TypeLabel, config.ComponentType), +If component is not specified, prompts interactively for selection.`, config.TypeLabel, config.CLI()), Example: fmt.Sprintf(` # Delete vendored source atmos %s source delete vpc --stack dev --force # Interactive: prompts for component and stack - atmos %s source delete`, config.ComponentType, config.ComponentType), + atmos %s source delete`, config.CLI(), config.CLI()), Args: cobra.RangeArgs(0, 1), RunE: func(cmd *cobra.Command, args []string) error { return executeDelete(cmd, args, config, parser) diff --git a/pkg/provisioner/source/cmd/describe.go b/pkg/provisioner/source/cmd/describe.go index 5df2ed0a05e..192b110905b 100644 --- a/pkg/provisioner/source/cmd/describe.go +++ b/pkg/provisioner/source/cmd/describe.go @@ -33,7 +33,7 @@ If component is not specified, prompts interactively for selection.`, cfg.TypeLa atmos %s source describe vpc --stack dev # Interactive: prompts for component and stack - atmos %s source describe`, cfg.ComponentType, cfg.ComponentType), + atmos %s source describe`, cfg.CLI(), cfg.CLI()), Args: cobra.RangeArgs(0, 1), RunE: func(cmd *cobra.Command, args []string) error { return executeDescribe(cmd, args, cfg, parser) diff --git a/pkg/provisioner/source/cmd/list.go b/pkg/provisioner/source/cmd/list.go index 99225602294..ee5ca0ed8af 100644 --- a/pkg/provisioner/source/cmd/list.go +++ b/pkg/provisioner/source/cmd/list.go @@ -60,7 +60,7 @@ This command shows which components can be vendored using the source provisioner atmos %s source list # Output as JSON - atmos %s source list --format json`, cfg.ComponentType, cfg.ComponentType, cfg.ComponentType, cfg.ComponentType, cfg.ComponentType), + atmos %s source list --format json`, cfg.CLI(), cfg.CLI(), cfg.CLI(), cfg.CLI(), cfg.CLI()), Args: cobra.RangeArgs(0, 1), RunE: func(cmd *cobra.Command, args []string) error { return executeList(cmd, args, cfg, parser) @@ -258,7 +258,8 @@ func getSourceListColumnsForContext(hasStack, hasFolderDiff bool) []column.Confi } // URI and Version always shown. - columns = append(columns, + columns = append( + columns, column.Config{Name: "URI", Value: "{{ .uri }}"}, column.Config{Name: "Version", Value: "{{ .version }}"}, ) diff --git a/pkg/provisioner/source/cmd/pull.go b/pkg/provisioner/source/cmd/pull.go index 77734dc35af..e33eefb68f4 100644 --- a/pkg/provisioner/source/cmd/pull.go +++ b/pkg/provisioner/source/cmd/pull.go @@ -39,7 +39,7 @@ If component is not specified, prompts interactively for selection.`, cfg.TypeLa atmos %s source pull vpc --stack dev --force # Interactive: prompts for component and stack - atmos %s source pull`, cfg.ComponentType, cfg.ComponentType, cfg.ComponentType), + atmos %s source pull`, cfg.CLI(), cfg.CLI(), cfg.CLI()), Args: cobra.RangeArgs(0, 1), RunE: func(cmd *cobra.Command, args []string) error { return executePull(cmd, args, cfg, parser) From 32c25159203edd8c870141912434acbebaead144 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Tue, 25 Aug 2026 11:09:37 -0500 Subject: [PATCH 04/10] test(cloudformation): raise fmt/list/source coverage to 93.7% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pkg/component/aws/cloudformation dropped to 86.6% after the fmt/list/source commit added fmt.go/list.go with no tests; now 93.7%. cmd/aws/cloudformation went from 0% (no test file existed) to 50%, covering the pure extraction logic (cloudFormationComponentStackName, configuredCloudFormationStackNames) that list's managed/unmanaged annotation depends on — the remaining gap there is mostly RunE plumbing (real auth/config init), consistent with how the rest of this file is tested. One small extraction for testability: list.go's Managed-annotation loop is now its own pure function, annotateManagedStacks, so the managed/unmanaged boolean per stack is asserted directly rather than only through a full AWS-client round-trip. cmd/aws/cloudformation/source has no test file, matching cmd/terraform/source's own precedent — it's a config literal plus four delegated AddCommand calls with nothing to assert beyond "it builds," which the parent package's own tests already exercise. Co-Authored-By: Claude Sonnet 5 --- cmd/aws/cloudformation/cloudformation_test.go | 52 +++++ cmd/aws/cloudformation/list_test.go | 168 ++++++++++++++++ .../aws/cloudformation/cloudformation_test.go | 1 + .../aws/cloudformation/executor_test.go | 72 +++++++ pkg/component/aws/cloudformation/fmt_test.go | 166 ++++++++++++++++ pkg/component/aws/cloudformation/list.go | 11 +- pkg/component/aws/cloudformation/list_test.go | 179 ++++++++++++++++++ pkg/provisioner/source/cmd/config_test.go | 23 +++ 8 files changed, 671 insertions(+), 1 deletion(-) create mode 100644 cmd/aws/cloudformation/cloudformation_test.go create mode 100644 cmd/aws/cloudformation/list_test.go create mode 100644 pkg/component/aws/cloudformation/fmt_test.go create mode 100644 pkg/component/aws/cloudformation/list_test.go create mode 100644 pkg/provisioner/source/cmd/config_test.go diff --git a/cmd/aws/cloudformation/cloudformation_test.go b/cmd/aws/cloudformation/cloudformation_test.go new file mode 100644 index 00000000000..5332229197f --- /dev/null +++ b/cmd/aws/cloudformation/cloudformation_test.go @@ -0,0 +1,52 @@ +package cloudformation + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// The fmt operation command must register the fmt-only --check flag (via +// operationSpecificFlagOptions's "fmt" case), defaulting to false. +func TestOperationSpecificFlagOptions_Fmt_RegistersCheckFlag(t *testing.T) { + fmtCmd := newOperationCommand("fmt", "fmt", "Format the local template in place") + + checkFlag := fmtCmd.Flag("check") + require.NotNil(t, checkFlag, "expected fmt to register --check") + assert.Equal(t, "false", checkFlag.DefValue) + + // --check is fmt-only: an unrelated operation must not pick it up. + applyCmd := newOperationCommand("apply", subCommandApply, "Create or update the stack") + assert.Nil(t, applyCmd.Flag("check"), "--check must be fmt-only") +} + +// getOperationFlags must surface fmt's --check flag as a bool, both when set +// and when left at its default. +func TestGetOperationFlags_IncludesCheck(t *testing.T) { + fmtCmd := newOperationCommand("fmt", "fmt", "Format the local template in place") + require.NoError(t, fmtCmd.Flags().Set("check", "true")) + + flags := getOperationFlags(fmtCmd) + assert.Equal(t, true, flags["check"]) + + fmtCmdDefault := newOperationCommand("fmt", "fmt", "Format the local template in place") + flags = getOperationFlags(fmtCmdDefault) + assert.Equal(t, false, flags["check"]) +} + +// CloudFormationCmd must mount the fmt subcommand, registered via +// subCommandOperations' "fmt" -> OperationFmt entry (exercised end-to-end +// through cmd registration rather than the internal map directly, since the +// map itself lives in pkg/component/aws/cloudformation and is covered there). +func TestCloudFormationCmd_RegistersFmtSubcommand(t *testing.T) { + var found *cobra.Command + for _, sub := range CloudFormationCmd.Commands() { + if sub.Name() == "fmt" { + found = sub + } + } + require.NotNil(t, found, "expected `atmos aws cloudformation fmt` to be registered") + assert.NotNil(t, found.Flag("check")) +} diff --git a/cmd/aws/cloudformation/list_test.go b/cmd/aws/cloudformation/list_test.go new file mode 100644 index 00000000000..cfa2948c2a2 --- /dev/null +++ b/cmd/aws/cloudformation/list_test.go @@ -0,0 +1,168 @@ +package cloudformation + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/cloudposse/atmos/pkg/auth" + "github.com/cloudposse/atmos/pkg/schema" +) + +// cloudFormationComponentStackName must extract +// components.aws/cloudformation..stack_name, returning ("", false) +// gracefully at every level where the expected shape is absent instead of +// panicking on a bad type assertion. +func TestCloudFormationComponentStackName(t *testing.T) { + validStacksMap := map[string]any{ + "dev": map[string]any{ + "components": map[string]any{ + "aws/cloudformation": map[string]any{ + "vpc": map[string]any{ + "stack_name": "my-vpc-stack", + }, + "no-stack-name": map[string]any{}, + "empty-stack-name": map[string]any{ + "stack_name": "", + }, + }, + }, + }, + } + + tests := []struct { + name string + stacksMap map[string]any + stack string + componentName string + wantName string + wantOK bool + }{ + { + name: "resolves configured stack_name", + stacksMap: validStacksMap, + stack: "dev", + componentName: "vpc", + wantName: "my-vpc-stack", + wantOK: true, + }, + { + name: "missing stack key", + stacksMap: validStacksMap, + stack: "does-not-exist", + componentName: "vpc", + }, + { + name: "missing components key", + stacksMap: map[string]any{"dev": map[string]any{}}, + stack: "dev", + componentName: "vpc", + }, + { + name: "missing type key", + stacksMap: map[string]any{ + "dev": map[string]any{"components": map[string]any{}}, + }, + stack: "dev", + componentName: "vpc", + }, + { + name: "missing component key", + stacksMap: validStacksMap, + stack: "dev", + componentName: "does-not-exist", + }, + { + name: "missing stack_name field", + stacksMap: validStacksMap, + stack: "dev", + componentName: "no-stack-name", + }, + { + name: "empty stack_name field", + stacksMap: validStacksMap, + stack: "dev", + componentName: "empty-stack-name", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + name, ok := cloudFormationComponentStackName(tt.stacksMap, tt.stack, tt.componentName) + assert.Equal(t, tt.wantOK, ok) + assert.Equal(t, tt.wantName, name) + }) + } +} + +// configuredCloudFormationStackNames must build the set of configured +// stack_name values (only including components that actually configured one) +// from the described stacks map. +func TestConfiguredCloudFormationStackNames(t *testing.T) { + origDescribe, origList := cfnDescribeStacks, cfnListAllComponents + t.Cleanup(func() { + cfnDescribeStacks = origDescribe + cfnListAllComponents = origList + }) + + stacksMap := map[string]any{ + "dev": map[string]any{ + "components": map[string]any{ + "aws/cloudformation": map[string]any{ + "vpc": map[string]any{"stack_name": "my-vpc-stack"}, + "no-stack-name": map[string]any{}, + }, + }, + }, + } + + cfnDescribeStacks = func(*schema.AtmosConfiguration, string, []string, []string, []string, bool, bool, bool, bool, []string, auth.AuthManager) (map[string]any, error) { + return stacksMap, nil + } + cfnListAllComponents = func(context.Context, string, map[string]any) ([]string, error) { + return []string{"vpc", "no-stack-name"}, nil + } + + names, err := configuredCloudFormationStackNames(&schema.AtmosConfiguration{}, "dev", nil) + require.NoError(t, err) + assert.Equal(t, map[string]bool{"my-vpc-stack": true}, names) +} + +// configuredCloudFormationStackNames must propagate a describe-stacks failure. +func TestConfiguredCloudFormationStackNames_DescribeError(t *testing.T) { + origDescribe := cfnDescribeStacks + t.Cleanup(func() { cfnDescribeStacks = origDescribe }) + + sentinel := errors.New("describe failed") + cfnDescribeStacks = func(*schema.AtmosConfiguration, string, []string, []string, []string, bool, bool, bool, bool, []string, auth.AuthManager) (map[string]any, error) { + return nil, sentinel + } + + _, err := configuredCloudFormationStackNames(&schema.AtmosConfiguration{}, "dev", nil) + require.Error(t, err) + assert.ErrorIs(t, err, sentinel) +} + +// configuredCloudFormationStackNames must propagate a list-components failure. +func TestConfiguredCloudFormationStackNames_ListError(t *testing.T) { + origDescribe, origList := cfnDescribeStacks, cfnListAllComponents + t.Cleanup(func() { + cfnDescribeStacks = origDescribe + cfnListAllComponents = origList + }) + + cfnDescribeStacks = func(*schema.AtmosConfiguration, string, []string, []string, []string, bool, bool, bool, bool, []string, auth.AuthManager) (map[string]any, error) { + return map[string]any{}, nil + } + sentinel := errors.New("list failed") + cfnListAllComponents = func(context.Context, string, map[string]any) ([]string, error) { + return nil, sentinel + } + + _, err := configuredCloudFormationStackNames(&schema.AtmosConfiguration{}, "dev", nil) + require.Error(t, err) + assert.ErrorIs(t, err, sentinel) +} diff --git a/pkg/component/aws/cloudformation/cloudformation_test.go b/pkg/component/aws/cloudformation/cloudformation_test.go index 904535ca362..0c24f8e53ca 100644 --- a/pkg/component/aws/cloudformation/cloudformation_test.go +++ b/pkg/component/aws/cloudformation/cloudformation_test.go @@ -113,6 +113,7 @@ func TestComponentProvider_Execute_MapsSubcommandsToOperations(t *testing.T) { {"drift-describe", OperationDriftDescribe}, {"get-template", OperationGetTemplate}, {"get-policy", OperationGetPolicy}, + {"fmt", OperationFmt}, } original := executeOperation diff --git a/pkg/component/aws/cloudformation/executor_test.go b/pkg/component/aws/cloudformation/executor_test.go index 5336c2fe04d..c37471ab8c9 100644 --- a/pkg/component/aws/cloudformation/executor_test.go +++ b/pkg/component/aws/cloudformation/executor_test.go @@ -521,6 +521,78 @@ func TestExecute_Single_Render_Success(t *testing.T) { require.NoError(t, err) } +// Execute's full single-component happy path for fmt — the other operation +// operationsSkippingAuth exempts from auth setup, alongside render — exercised +// the same way TestExecute_Single_Render_Success exercises render. +func TestExecute_Single_Fmt_Success(t *testing.T) { + tempDir := t.TempDir() + templateBody := "AWSTemplateFormatVersion: '2010-09-09'" + require.NoError(t, os.WriteFile(filepath.Join(tempDir, "template.yaml"), []byte(templateBody), 0o644)) + + installExecutorSeamStubs(t, executorSeamStubs{ + initCliConfig: func(_ schema.ConfigAndStacksInfo, _ bool) (schema.AtmosConfiguration, error) { + return schema.AtmosConfiguration{}, nil + }, + processStacks: func(_ *schema.AtmosConfiguration, info schema.ConfigAndStacksInfo, _, _, _ bool, _ []string, _ auth.AuthManager) (schema.ConfigAndStacksInfo, error) { + info.ComponentIsEnabled = true + info.ComponentSection = map[string]any{"stack_name": "vpc", "template": "template.yaml"} + return info, nil + }, + setupComponentAuthForCLI: func(_ *schema.AtmosConfiguration, _ *schema.ConfigAndStacksInfo) (auth.AuthManager, error) { + t.Fatal("fmt must never set up AWS auth") + return nil, nil + }, + propagateAuth: func(_ *schema.ConfigAndStacksInfo, _ auth.AuthManager) { + t.Fatal("fmt must never propagate auth") + }, + provisionAndResolveComponentPath: func(_ context.Context, _ provisioner.OutputWriters, _ *schema.AtmosConfiguration, _ *schema.ConfigAndStacksInfo, _, _ string) (string, bool, error) { + return tempDir, false, nil + }, + getHooks: noopGetHooks, + }) + + ctx := &component.ExecutionContext{ConfigAndStacksInfo: schema.ConfigAndStacksInfo{ComponentFromArg: "vpc"}} + err := Execute(ctx, OperationFmt) + require.NoError(t, err, "fmt on an already-formatted template must succeed as a no-op") +} + +// operationsSkippingAuth must contain exactly render and fmt — the only two +// operations that never touch the CloudFormation API — and nothing else. +func TestOperationsSkippingAuth_Contents(t *testing.T) { + assert.True(t, operationsSkippingAuth[OperationRender]) + assert.True(t, operationsSkippingAuth[OperationFmt]) + assert.Len(t, operationsSkippingAuth, 2, "adding an operation here must be a deliberate decision, not an accident") + + for _, op := range []Operation{OperationDiff, OperationApply, OperationDelete, OperationValidate, OperationOutput} { + assert.False(t, operationsSkippingAuth[op], "operation %q must require auth setup", op) + } +} + +// executeSingle must call auth setup for OperationDiff specifically (not just +// "some non-render operation" as TestExecuteSingle_AuthSetupError already +// covers via apply) — confirming the operationsSkippingAuth[operation] guard +// is keyed correctly per-operation rather than by a broader default. +func TestExecuteSingle_Diff_CallsAuthSetup(t *testing.T) { + authCalled := false + sentinel := errors.New("auth setup failed") + installExecutorSeamStubs(t, executorSeamStubs{ + processStacks: func(_ *schema.AtmosConfiguration, info schema.ConfigAndStacksInfo, _, _, _ bool, _ []string, _ auth.AuthManager) (schema.ConfigAndStacksInfo, error) { + info.ComponentIsEnabled = true + info.ComponentSection = map[string]any{"stack_name": "vpc", "template": "template.yaml"} + return info, nil + }, + setupComponentAuthForCLI: func(_ *schema.AtmosConfiguration, _ *schema.ConfigAndStacksInfo) (auth.AuthManager, error) { + authCalled = true + return nil, sentinel + }, + }) + + err := executeSingle(&component.ExecutionContext{}, &schema.AtmosConfiguration{}, &schema.ConfigAndStacksInfo{}, OperationDiff) + require.Error(t, err) + assert.ErrorIs(t, err, sentinel) + assert.True(t, authCalled, "OperationDiff must reach auth setup") +} + // executeSingle must skip validation/auth/resolution entirely and return nil // when the discovered component is disabled. func TestExecuteSingle_ComponentDisabled(t *testing.T) { diff --git a/pkg/component/aws/cloudformation/fmt_test.go b/pkg/component/aws/cloudformation/fmt_test.go new file mode 100644 index 00000000000..0b8debeb453 --- /dev/null +++ b/pkg/component/aws/cloudformation/fmt_test.go @@ -0,0 +1,166 @@ +package cloudformation + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + errUtils "github.com/cloudposse/atmos/errors" +) + +// formatTemplate must round-trip a valid YAML template, preserving comments +// and CFN's short-form intrinsic function tags (Ref, Sub, GetAtt) — plain +// yaml.v3 rather than the Atmos custom-tag-aware unmarshaler is what makes +// those tags survive instead of being rejected as unknown. +func TestFormatTemplate_ValidYAML_PreservesCommentsAndIntrinsicTags(t *testing.T) { + body := "# top-level comment\n" + + "AWSTemplateFormatVersion: '2010-09-09'\n" + + "Resources:\n" + + " Bucket:\n" + + " Type: AWS::S3::Bucket\n" + + " Properties:\n" + + " BucketName: !Sub '${AWS::StackName}-bucket'\n" + + "Outputs:\n" + + " BucketArn:\n" + + " Value: !GetAtt Bucket.Arn\n" + + " BucketRef:\n" + + " Value: !Ref Bucket\n" + + got, err := formatTemplate(body) + require.NoError(t, err) + assert.Contains(t, got, "# top-level comment") + assert.Contains(t, got, "!Sub") + assert.Contains(t, got, "!GetAtt") + assert.Contains(t, got, "!Ref") + + // Re-formatting the already-formatted output must be a no-op (idempotent). + again, err := formatTemplate(got) + require.NoError(t, err) + assert.Equal(t, got, again) +} + +// formatTemplate must reject malformed YAML with +// ErrInvalidAwsCloudFormationSettings, not a bare yaml.v3 error. +func TestFormatTemplate_MalformedYAML(t *testing.T) { + _, err := formatTemplate("Resources:\n Bucket: [unterminated\n") + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrInvalidAwsCloudFormationSettings) +} + +// runFmt on an already-formatted file must be a no-op: no error, and +// summary["formatted"] reports false. +func TestRunFmt_CleanNoCheck_NoOp(t *testing.T) { + tempDir := t.TempDir() + templatePath := filepath.Join(tempDir, "template.yaml") + body := "AWSTemplateFormatVersion: \"2010-09-09\"\n" + require.NoError(t, os.WriteFile(templatePath, []byte(body), 0o644)) + + // The formatted output of body must equal body itself for this to + // actually exercise the "clean" branch instead of accidentally the dirty one. + formatted, err := formatTemplate(body) + require.NoError(t, err) + require.Equal(t, body, formatted, "test fixture must already be in formatTemplate's canonical form") + + spec := &stackSpec{TemplateBody: body, TemplateAbsPath: templatePath} + summary, err := runFmt(spec, map[string]any{}, map[string]any{}) + require.NoError(t, err) + assert.False(t, summary["formatted"].(bool)) + + // The file on disk must be untouched. + onDisk, readErr := os.ReadFile(templatePath) + require.NoError(t, readErr) + assert.Equal(t, body, string(onDisk)) +} + +// runFmt with --check on a dirty (not-yet-formatted) file must return +// ErrAwsCloudFormationFmtNotClean without writing anything to disk. +func TestRunFmt_Check_Dirty_ReturnsErrorWithoutWriting(t *testing.T) { + tempDir := t.TempDir() + templatePath := filepath.Join(tempDir, "template.yaml") + dirty := "AWSTemplateFormatVersion: '2010-09-09'\nResources: {}\n" + require.NoError(t, os.WriteFile(templatePath, []byte(dirty), 0o644)) + + spec := &stackSpec{TemplateBody: dirty, TemplateAbsPath: templatePath} + _, err := runFmt(spec, map[string]any{"check": true}, map[string]any{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationFmtNotClean) + + onDisk, readErr := os.ReadFile(templatePath) + require.NoError(t, readErr) + assert.Equal(t, dirty, string(onDisk), "--check must never write changes to disk") +} + +// runFmt with --check on an already-clean file must return nil. +func TestRunFmt_Check_Clean_ReturnsNil(t *testing.T) { + tempDir := t.TempDir() + templatePath := filepath.Join(tempDir, "template.yaml") + body := "AWSTemplateFormatVersion: \"2010-09-09\"\n" + formatted, err := formatTemplate(body) + require.NoError(t, err) + require.Equal(t, body, formatted) + require.NoError(t, os.WriteFile(templatePath, []byte(body), 0o644)) + + spec := &stackSpec{TemplateBody: body, TemplateAbsPath: templatePath} + summary, err := runFmt(spec, map[string]any{"check": true}, map[string]any{}) + require.NoError(t, err) + assert.False(t, summary["formatted"].(bool)) +} + +// runFmt in non-check mode on a dirty file must actually write the formatted +// content to disk. +func TestRunFmt_NonCheck_Dirty_WritesFormattedContent(t *testing.T) { + tempDir := t.TempDir() + templatePath := filepath.Join(tempDir, "template.yaml") + dirty := "AWSTemplateFormatVersion: '2010-09-09'\nResources: {}\n" + require.NoError(t, os.WriteFile(templatePath, []byte(dirty), 0o644)) + + spec := &stackSpec{TemplateBody: dirty, TemplateAbsPath: templatePath} + summary, err := runFmt(spec, map[string]any{}, map[string]any{}) + require.NoError(t, err) + assert.True(t, summary["formatted"].(bool)) + + wantFormatted, err := formatTemplate(dirty) + require.NoError(t, err) + + onDisk, readErr := os.ReadFile(templatePath) + require.NoError(t, readErr) + assert.Equal(t, wantFormatted, string(onDisk)) + assert.NotEqual(t, dirty, string(onDisk), "the write must have actually changed the file's contents") +} + +// runFmt must propagate a formatTemplate error (malformed template body) +// without touching disk. +func TestRunFmt_FormatTemplateError(t *testing.T) { + tempDir := t.TempDir() + templatePath := filepath.Join(tempDir, "template.yaml") + malformed := "Resources:\n Bucket: [unterminated\n" + require.NoError(t, os.WriteFile(templatePath, []byte(malformed), 0o644)) + + spec := &stackSpec{TemplateBody: malformed, TemplateAbsPath: templatePath} + _, err := runFmt(spec, map[string]any{}, map[string]any{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrInvalidAwsCloudFormationSettings) + + onDisk, readErr := os.ReadFile(templatePath) + require.NoError(t, readErr) + assert.Equal(t, malformed, string(onDisk), "a formatTemplate failure must never write to disk") +} + +// runFmt must propagate a write failure (e.g. the resolved path's parent +// directory does not exist) wrapped in ErrAwsCloudFormationFmtNotClean. +func TestRunFmt_WriteFailure(t *testing.T) { + tempDir := t.TempDir() + // A path whose parent directory does not exist: os.WriteFile fails the + // same deterministic way on both Unix and Windows, unlike a + // permissions-based approach. + unwritablePath := filepath.Join(tempDir, "missing-subdir", "template.yaml") + dirty := "AWSTemplateFormatVersion: '2010-09-09'\n" + + spec := &stackSpec{TemplateBody: dirty, TemplateAbsPath: unwritablePath} + _, err := runFmt(spec, map[string]any{}, map[string]any{}) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationFmtNotClean) +} diff --git a/pkg/component/aws/cloudformation/list.go b/pkg/component/aws/cloudformation/list.go index abafc16a4ff..0edbd4ca46c 100644 --- a/pkg/component/aws/cloudformation/list.go +++ b/pkg/component/aws/cloudformation/list.go @@ -72,6 +72,15 @@ func ListDeployedStacks( return nil, err } + return annotateManagedStacks(stacks, configuredStackNames), nil +} + +// annotateManagedStacks converts raw ListStacks summaries into +// DeployedStackSummary entries, annotating each one's Managed field against +// configuredStackNames. Split out of ListDeployedStacks so the annotation +// logic (a pure function) is testable independent of AWS config/client +// construction. +func annotateManagedStacks(stacks []cfntypes.StackSummary, configuredStackNames map[string]bool) []DeployedStackSummary { summaries := make([]DeployedStackSummary, 0, len(stacks)) for i := range stacks { s := &stacks[i] @@ -82,7 +91,7 @@ func ListDeployedStacks( Managed: configuredStackNames[name], }) } - return summaries, nil + return summaries } // toStackStatuses converts CLI-provided status strings to the SDK's enum type. diff --git a/pkg/component/aws/cloudformation/list_test.go b/pkg/component/aws/cloudformation/list_test.go new file mode 100644 index 00000000000..bd35900c787 --- /dev/null +++ b/pkg/component/aws/cloudformation/list_test.go @@ -0,0 +1,179 @@ +package cloudformation + +import ( + "context" + "errors" + "net/http" + "net/http/httptest" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" + cfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" + + errUtils "github.com/cloudposse/atmos/errors" + "github.com/cloudposse/atmos/pkg/schema" +) + +// listDeployedStacks must return the single page's stacks when ListStacks +// reports no NextToken. +func TestListDeployedStacks_SinglePage(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + client.EXPECT().ListStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.ListStacksOutput{ + StackSummaries: []cfntypes.StackSummary{ + {StackName: awsString("vpc"), StackStatus: cfntypes.StackStatusCreateComplete}, + }, + }, nil) + + stacks, err := listDeployedStacks(context.Background(), client, nil) + require.NoError(t, err) + require.Len(t, stacks, 1) + assert.Equal(t, "vpc", *stacks[0].StackName) +} + +// listDeployedStacks must page through NextToken, accumulating every page's +// stacks and threading the token to the following ListStacks call. +func TestListDeployedStacks_Pagination(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + token := "page-2-token" + gomock.InOrder( + client.EXPECT().ListStacks(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.ListStacksInput, _ ...func(*cloudformation.Options)) (*cloudformation.ListStacksOutput, error) { + assert.Nil(t, input.NextToken, "the first call must not carry a NextToken") + return &cloudformation.ListStacksOutput{ + StackSummaries: []cfntypes.StackSummary{{StackName: awsString("vpc")}}, + NextToken: &token, + }, nil + }, + ), + client.EXPECT().ListStacks(gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, input *cloudformation.ListStacksInput, _ ...func(*cloudformation.Options)) (*cloudformation.ListStacksOutput, error) { + require.NotNil(t, input.NextToken) + assert.Equal(t, token, *input.NextToken) + return &cloudformation.ListStacksOutput{ + StackSummaries: []cfntypes.StackSummary{{StackName: awsString("dns")}}, + }, nil + }, + ), + ) + + stacks, err := listDeployedStacks(context.Background(), client, nil) + require.NoError(t, err) + require.Len(t, stacks, 2) + assert.Equal(t, "vpc", *stacks[0].StackName) + assert.Equal(t, "dns", *stacks[1].StackName) +} + +// listDeployedStacks must wrap a ListStacks API error with +// ErrAwsCloudFormationChangeSetFailed. +func TestListDeployedStacks_APIError(t *testing.T) { + ctrl := gomock.NewController(t) + client := NewMockCloudFormationClient(ctrl) + + sentinel := errors.New("throttled") + client.EXPECT().ListStacks(gomock.Any(), gomock.Any()).Return(nil, sentinel) + + _, err := listDeployedStacks(context.Background(), client, nil) + require.Error(t, err) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.ErrorIs(t, err, sentinel) +} + +// toStackStatuses must return nil for an empty filter (ListStacks defaults to +// all non-deleted statuses in that case) and convert each string otherwise. +func TestToStackStatuses(t *testing.T) { + assert.Nil(t, toStackStatuses(nil)) + assert.Nil(t, toStackStatuses([]string{})) + + got := toStackStatuses([]string{"CREATE_COMPLETE", "UPDATE_COMPLETE"}) + assert.Equal(t, []cfntypes.StackStatus{cfntypes.StackStatusCreateComplete, cfntypes.StackStatusUpdateComplete}, got) +} + +// annotateManagedStacks must set Managed=true only for stacks whose name is +// present (and true) in configuredStackNames, and Managed=false for every +// other stack — asserted per-entry, not just "returns without error". +func TestAnnotateManagedStacks(t *testing.T) { + stacks := []cfntypes.StackSummary{ + {StackName: awsString("vpc"), StackStatus: cfntypes.StackStatusCreateComplete}, + {StackName: awsString("orphaned-stack"), StackStatus: cfntypes.StackStatusUpdateComplete}, + } + configured := map[string]bool{"vpc": true} + + got := annotateManagedStacks(stacks, configured) + require.Len(t, got, 2) + + assert.Equal(t, DeployedStackSummary{StackName: "vpc", Status: "CREATE_COMPLETE", Managed: true}, got[0]) + assert.Equal(t, DeployedStackSummary{StackName: "orphaned-stack", Status: "UPDATE_COMPLETE", Managed: false}, got[1]) +} + +// annotateManagedStacks must return an empty (not nil-panicking) slice for no +// stacks. +func TestAnnotateManagedStacks_Empty(t *testing.T) { + got := annotateManagedStacks(nil, map[string]bool{}) + assert.Empty(t, got) +} + +// ListDeployedStacks must propagate a buildAWSConfig failure without ever +// reaching listDeployedStacks/the API. +func TestListDeployedStacks_AuthConfigError(t *testing.T) { + info := &schema.ConfigAndStacksInfo{ + AuthContext: &schema.AuthContext{ + AWS: &schema.AWSAuthContext{ + CredentialsFile: "/this/path/does/not/exist/credentials", + ConfigFile: "/this/path/does/not/exist/config", + Profile: "bogus-profile", + }, + }, + } + + _, err := ListDeployedStacks(context.Background(), info, "us-east-1", nil, map[string]bool{}) + require.Error(t, err, "an unresolvable shared-config profile must surface as an error before any API call") +} + +// ListDeployedStacks must propagate the underlying ListStacks failure once +// auth/config resolution succeeds — exercised via an endpoint that refuses +// connections, mirroring executor_test.go's TestRunOperation_DispatchesToHandler. +func TestListDeployedStacks_ClientError(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) + unreachable := srv.URL + srv.Close() + + info := &schema.ConfigAndStacksInfo{ + AuthContext: &schema.AuthContext{AWS: &schema.AWSAuthContext{EndpointURL: unreachable}}, + } + + _, err := ListDeployedStacks(context.Background(), info, "us-east-1", nil, map[string]bool{}) + require.Error(t, err, "the dispatched call must have actually hit the (unreachable) endpoint") +} + +// RenderDeployedStacksList must print a "no stacks" message for an empty +// list, never a blank table. +func TestRenderDeployedStacksList_Empty(t *testing.T) { + out := captureStdout(t, func() { + RenderDeployedStacksList(nil) + }) + assert.Contains(t, out, "No stacks found.") +} + +// RenderDeployedStacksList must print one line per stack, distinguishing +// managed from unmanaged stacks in the marker column. +func TestRenderDeployedStacksList_Populated(t *testing.T) { + stacks := []DeployedStackSummary{ + {StackName: "vpc", Status: "CREATE_COMPLETE", Managed: true}, + {StackName: "orphaned-stack", Status: "UPDATE_COMPLETE", Managed: false}, + } + + out := captureStdout(t, func() { + RenderDeployedStacksList(stacks) + }) + assert.Contains(t, out, "managed") + assert.Contains(t, out, "vpc") + assert.Contains(t, out, "unmanaged") + assert.Contains(t, out, "orphaned-stack") +} diff --git a/pkg/provisioner/source/cmd/config_test.go b/pkg/provisioner/source/cmd/config_test.go new file mode 100644 index 00000000000..637cf6b39cb --- /dev/null +++ b/pkg/provisioner/source/cmd/config_test.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// Config.CLI() must fall back to ComponentType when CLIName is unset — the +// common case for types whose CLI invocation matches their internal +// ComponentType exactly (terraform, helmfile, packer). +func TestConfig_CLI_FallsBackToComponentType(t *testing.T) { + c := &Config{ComponentType: "terraform"} + assert.Equal(t, "terraform", c.CLI()) +} + +// Config.CLI() must return CLIName verbatim when set — used by types whose +// CLI command path differs from their internal ComponentType (e.g. +// aws/cloudformation is invoked as "aws cloudformation"). +func TestConfig_CLI_UsesCLINameWhenSet(t *testing.T) { + c := &Config{ComponentType: "aws/cloudformation", CLIName: "aws cloudformation"} + assert.Equal(t, "aws cloudformation", c.CLI()) +} From 7efd3461c8ac7ae4d666412482a6645d60377344 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Tue, 25 Aug 2026 11:09:54 -0500 Subject: [PATCH 05/10] docs(cloudformation): document Phase 2 verbs and the interop bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CLI docs for changeset create/execute/list/delete, drift detect/describe, get template/policy, fmt, list, and source pull/list/describe/delete (mirroring the existing terraform/helmfile/packer source docs pattern). Also documents the Terraform<->CloudFormation interop bridge: !aws.cloudformation.output alongside the other YAML functions (including its forbidden-in-selectors restriction, same as !terraform.output), and atmos.Component(...).outputs now resolving aws/cloudformation targets. No config/schema reference changes needed — Phase 2 added CLI verbs only, no new stack-manifest or atmos.yaml fields. Co-Authored-By: Claude Sonnet 5 --- .../cloudformation/changeset/_category_.json | 8 + .../cloudformation/changeset/changeset.mdx | 36 ++ .../aws/cloudformation/changeset/create.mdx | 76 ++++ .../aws/cloudformation/changeset/delete.mdx | 63 +++ .../aws/cloudformation/changeset/execute.mdx | 79 ++++ .../aws/cloudformation/changeset/list.mdx | 63 +++ .../aws/cloudformation/cloudformation.mdx | 16 + .../aws/cloudformation/drift/_category_.json | 8 + .../aws/cloudformation/drift/describe.mdx | 66 +++ .../aws/cloudformation/drift/detect.mdx | 84 ++++ .../aws/cloudformation/drift/drift.mdx | 33 ++ .../cli/commands/aws/cloudformation/fmt.mdx | 77 ++++ .../aws/cloudformation/get/_category_.json | 8 + .../commands/aws/cloudformation/get/get.mdx | 33 ++ .../aws/cloudformation/get/policy.mdx | 65 +++ .../aws/cloudformation/get/template.mdx | 69 ++++ .../cli/commands/aws/cloudformation/list.mdx | 79 ++++ .../aws/cloudformation/source/_category_.json | 8 + .../aws/cloudformation/source/delete.mdx | 104 +++++ .../aws/cloudformation/source/describe.mdx | 124 ++++++ .../aws/cloudformation/source/list.mdx | 136 +++++++ .../aws/cloudformation/source/pull.mdx | 122 ++++++ .../aws/cloudformation/source/source.mdx | 382 ++++++++++++++++++ .../functions/template/atmos.Component.mdx | 26 +- .../yaml/aws.cloudformation.output.mdx | 113 ++++++ website/docs/functions/yaml/index.mdx | 7 + 26 files changed, 1884 insertions(+), 1 deletion(-) create mode 100644 website/docs/cli/commands/aws/cloudformation/changeset/_category_.json create mode 100644 website/docs/cli/commands/aws/cloudformation/changeset/changeset.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/changeset/create.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/changeset/delete.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/changeset/execute.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/changeset/list.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/drift/_category_.json create mode 100644 website/docs/cli/commands/aws/cloudformation/drift/describe.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/drift/detect.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/drift/drift.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/fmt.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/get/_category_.json create mode 100644 website/docs/cli/commands/aws/cloudformation/get/get.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/get/policy.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/get/template.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/list.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/source/_category_.json create mode 100644 website/docs/cli/commands/aws/cloudformation/source/delete.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/source/describe.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/source/list.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/source/pull.mdx create mode 100644 website/docs/cli/commands/aws/cloudformation/source/source.mdx create mode 100644 website/docs/functions/yaml/aws.cloudformation.output.mdx diff --git a/website/docs/cli/commands/aws/cloudformation/changeset/_category_.json b/website/docs/cli/commands/aws/cloudformation/changeset/_category_.json new file mode 100644 index 00000000000..867bc7d68f3 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/changeset/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "changeset", + "className": "command", + "link": { + "type": "doc", + "id": "cli/commands/aws/cloudformation/changeset/changeset" + } +} diff --git a/website/docs/cli/commands/aws/cloudformation/changeset/changeset.mdx b/website/docs/cli/commands/aws/cloudformation/changeset/changeset.mdx new file mode 100644 index 00000000000..3e33aa5be61 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/changeset/changeset.mdx @@ -0,0 +1,36 @@ +--- +title: atmos aws cloudformation changeset +sidebar_label: changeset +sidebar_class_name: command +id: changeset +description: Manage aws/cloudformation changesets directly. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import DocCardList from '@theme/DocCardList' +import Experimental from '@site/src/components/Experimental' + + +Manage `aws/cloudformation` changesets directly — manual control over changesets, +complementing [`apply`](/cli/commands/aws/cloudformation/apply)/[`deploy`](/cli/commands/aws/cloudformation/deploy)/[`diff`](/cli/commands/aws/cloudformation/diff)'s +implicit flow (each of those creates or reuses a changeset internally). Use these +verbs when you need to review a changeset before executing it, name it for later +execution, or manage changesets outside a normal deploy. + + + + + + +## Usage + +```shell +atmos aws cloudformation changeset create --stack +atmos aws cloudformation changeset execute --stack --changeset-name +atmos aws cloudformation changeset list --stack +atmos aws cloudformation changeset delete --stack --changeset-name +``` + +## Subcommands + + diff --git a/website/docs/cli/commands/aws/cloudformation/changeset/create.mdx b/website/docs/cli/commands/aws/cloudformation/changeset/create.mdx new file mode 100644 index 00000000000..f13514ebedd --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/changeset/create.mdx @@ -0,0 +1,76 @@ +--- +title: atmos aws cloudformation changeset create +sidebar_label: create +sidebar_class_name: command +id: create +description: Create a changeset and leave it for later review or execution. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Create a CloudFormation changeset for the component and leave it in place for + later manual review and execution — the explicit-control complement to + [`diff`](/cli/commands/aws/cloudformation/diff)/[`plan`](/cli/commands/aws/cloudformation/plan)'s + implicit, preview-only changeset (which is also left in place, but framed as + a one-off preview rather than a named, reusable artifact). + + + + + + +## Usage + +```shell +atmos aws cloudformation changeset create --stack [options] +``` + +```shell +atmos aws cloudformation changeset create vpc -s plat-ue2-dev +``` + +Create changesets for all or affected components in dependency order: + +```shell +atmos aws cloudformation changeset create --all -s plat-ue2-dev +atmos aws cloudformation changeset create --affected --base origin/main +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--all` (optional)
+
Create changesets for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Create changesets for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +## Output + +On success, the summary includes the changeset's ID and name, whether it was a +no-op (no changes to apply), and the predicted changes — the same diff summary +[`diff`](/cli/commands/aws/cloudformation/diff) renders. Execute the named +changeset later with +[`changeset execute`](/cli/commands/aws/cloudformation/changeset/execute). + +:::note +`changeset create` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/changeset/delete.mdx b/website/docs/cli/commands/aws/cloudformation/changeset/delete.mdx new file mode 100644 index 00000000000..400db442252 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/changeset/delete.mdx @@ -0,0 +1,63 @@ +--- +title: atmos aws cloudformation changeset delete +sidebar_label: delete +sidebar_class_name: command +id: delete +description: Delete a named changeset without touching the stack. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Delete a named changeset (`DeleteChangeSet`) without touching the stack + itself. Use this to clean up changesets created with + [`changeset create`](/cli/commands/aws/cloudformation/changeset/create) that + you decided not to execute. + + + + + + +## Usage + +```shell +atmos aws cloudformation changeset delete --stack --changeset-name [options] +``` + +```shell +atmos aws cloudformation changeset delete vpc -s plat-ue2-dev --changeset-name vpc-2026-08-25 +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--changeset-name` (required)
+
Name of the changeset to delete.
+ +
`--all` (optional)
+
Delete the named changeset for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Delete the named changeset for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +:::note +`changeset delete` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/changeset/execute.mdx b/website/docs/cli/commands/aws/cloudformation/changeset/execute.mdx new file mode 100644 index 00000000000..738c9fabe26 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/changeset/execute.mdx @@ -0,0 +1,79 @@ +--- +title: atmos aws cloudformation changeset execute +sidebar_label: execute +sidebar_class_name: command +id: execute +description: Execute a previously-created, named changeset. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Execute a previously-created, named changeset (`ExecuteChangeSet`) and stream + stack events until the operation reaches a terminal state — unlike + [`apply`](/cli/commands/aws/cloudformation/apply), which creates (or reuses) + and executes a changeset in one step, `changeset execute` acts on an + existing changeset by name, created earlier with + [`changeset create`](/cli/commands/aws/cloudformation/changeset/create). + + + + + + +## Usage + +```shell +atmos aws cloudformation changeset execute --stack --changeset-name [options] +``` + +```shell +atmos aws cloudformation changeset execute vpc -s plat-ue2-dev --changeset-name vpc-2026-08-25 +``` + +Skip the interactive confirmation prompt: + +```shell +atmos aws cloudformation changeset execute vpc -s plat-ue2-dev --changeset-name vpc-2026-08-25 --auto-approve +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--changeset-name` (required)
+
Name of the changeset to execute.
+ +
`--auto-approve` (optional)
+
Skip the interactive confirmation prompt. Without it, `changeset execute` prompts for confirmation on a TTY before executing the changeset.
+ +
`--all` (optional)
+
Execute the named changeset for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Execute the named changeset for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +## Behavior + +If the stack ends in a failed status after executing the changeset (e.g. +`UPDATE_ROLLBACK_COMPLETE`), `changeset execute` exits non-zero. + +:::note +`changeset execute` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/changeset/list.mdx b/website/docs/cli/commands/aws/cloudformation/changeset/list.mdx new file mode 100644 index 00000000000..5db17099db8 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/changeset/list.mdx @@ -0,0 +1,63 @@ +--- +title: atmos aws cloudformation changeset list +sidebar_label: list +sidebar_class_name: command +id: list +description: List a stack's changesets. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + List a CloudFormation stack's changesets (`ListChangeSets`), newest first — + each entry's name, status, and description. + + + + + + +## Usage + +```shell +atmos aws cloudformation changeset list --stack [options] +``` + +```shell +atmos aws cloudformation changeset list vpc -s plat-ue2-dev +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--all` (optional)
+
List changesets for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
List changesets for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +## Output + +If the stack has no changesets, `changeset list` prints a single line saying +so instead of an empty table. + +:::note +`changeset list` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/cloudformation.mdx b/website/docs/cli/commands/aws/cloudformation/cloudformation.mdx index b290c0836b6..c5bfe1f71a4 100644 --- a/website/docs/cli/commands/aws/cloudformation/cloudformation.mdx +++ b/website/docs/cli/commands/aws/cloudformation/cloudformation.mdx @@ -43,6 +43,22 @@ atmos aws cloudformation delete --stack atmos aws cloudformation validate --stack atmos aws cloudformation output --stack +atmos aws cloudformation changeset create --stack +atmos aws cloudformation changeset execute --stack --changeset-name +atmos aws cloudformation changeset list --stack +atmos aws cloudformation changeset delete --stack --changeset-name + +atmos aws cloudformation drift detect --stack +atmos aws cloudformation drift describe --stack + +atmos aws cloudformation get template --stack +atmos aws cloudformation get policy --stack + +atmos aws cloudformation fmt --stack +atmos aws cloudformation list --stack + +atmos aws cloudformation source pull --stack + atmos aws cloudformation apply --all --stack atmos aws cloudformation apply --affected --base origin/main diff --git a/website/docs/cli/commands/aws/cloudformation/drift/_category_.json b/website/docs/cli/commands/aws/cloudformation/drift/_category_.json new file mode 100644 index 00000000000..7927e23abbf --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/drift/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "drift", + "className": "command", + "link": { + "type": "doc", + "id": "cli/commands/aws/cloudformation/drift/drift" + } +} diff --git a/website/docs/cli/commands/aws/cloudformation/drift/describe.mdx b/website/docs/cli/commands/aws/cloudformation/drift/describe.mdx new file mode 100644 index 00000000000..08d215d5360 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/drift/describe.mdx @@ -0,0 +1,66 @@ +--- +title: atmos aws cloudformation drift describe +sidebar_label: describe +sidebar_class_name: command +id: describe +description: Show the results of the most recent drift detection. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Show the per-resource results of the most recently completed drift + detection (`DescribeStackResourceDrifts`) without triggering a new one. Run + [`drift detect`](/cli/commands/aws/cloudformation/drift/detect) first — this + command only reads existing results. + + + + + + +## Usage + +```shell +atmos aws cloudformation drift describe --stack [options] +``` + +```shell +atmos aws cloudformation drift describe vpc -s plat-ue2-dev +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--all` (optional)
+
Describe drift for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Describe drift for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +## Output + +Only resources that are not `IN_SYNC` are printed. If the stack has no drift +results at all (no detection has ever run), `drift describe` says so and +suggests running [`drift detect`](/cli/commands/aws/cloudformation/drift/detect) first. + +:::note +`drift describe` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/drift/detect.mdx b/website/docs/cli/commands/aws/cloudformation/drift/detect.mdx new file mode 100644 index 00000000000..e252cd7aff6 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/drift/detect.mdx @@ -0,0 +1,84 @@ +--- +title: atmos aws cloudformation drift detect +sidebar_label: detect +sidebar_class_name: command +id: detect +description: Run drift detection against the deployed stack. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Trigger a fresh CloudFormation drift detection (`DetectStackDrift`) against + the deployed stack and poll until it completes, then render the overall + drift status and drifted-resource count. Use + [`drift describe`](/cli/commands/aws/cloudformation/drift/describe) + afterward to see per-resource results. + + + + + + +## Usage + +```shell +atmos aws cloudformation drift detect --stack [options] +``` + +```shell +atmos aws cloudformation drift detect vpc -s plat-ue2-dev +``` + +Fail the command (non-zero exit) when drift is found, for CI: + +```shell +atmos aws cloudformation drift detect vpc -s plat-ue2-dev --fail-on-drift +``` + +Run drift detection for all or affected components in dependency order: + +```shell +atmos aws cloudformation drift detect --all -s plat-ue2-dev --fail-on-drift +atmos aws cloudformation drift detect --affected --base origin/main --fail-on-drift +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--fail-on-drift` (optional)
+
Exit non-zero if drift is detected. Useful for CI drift-detection jobs.
+ +
`--all` (optional)
+
Run drift detection for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Run drift detection for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +## Behavior + +`drift detect` polls CloudFormation every 3 seconds until the detection +operation completes, and gives up after 15 minutes if it hasn't. A detection +that itself fails (`DETECTION_FAILED`) is always an error, independent of +`--fail-on-drift`. + +:::note +`drift detect` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/drift/drift.mdx b/website/docs/cli/commands/aws/cloudformation/drift/drift.mdx new file mode 100644 index 00000000000..235f38426a3 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/drift/drift.mdx @@ -0,0 +1,33 @@ +--- +title: atmos aws cloudformation drift +sidebar_label: drift +sidebar_class_name: command +id: drift +description: Detect and describe drift against a deployed stack. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import DocCardList from '@theme/DocCardList' +import Experimental from '@site/src/components/Experimental' + + +Detect and describe drift between a deployed CloudFormation stack's actual +resource configuration and its stack template — CloudFormation's own +[stack drift detection](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-stack-drift.html), +wired into the same stack-based workflow as every other `aws/cloudformation` verb. + + + + + + +## Usage + +```shell +atmos aws cloudformation drift detect --stack +atmos aws cloudformation drift describe --stack +``` + +## Subcommands + + diff --git a/website/docs/cli/commands/aws/cloudformation/fmt.mdx b/website/docs/cli/commands/aws/cloudformation/fmt.mdx new file mode 100644 index 00000000000..45dea7b926b --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/fmt.mdx @@ -0,0 +1,77 @@ +--- +title: atmos aws cloudformation fmt +sidebar_label: fmt +sidebar_class_name: command +id: fmt +description: Format the local template in place, or check formatting with --check. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Format the component's local template in place: a dependency-free, native + round-trip through the YAML parser that re-serializes the template with + consistent indentation, preserving comments and key order. There is no + `cfn-format` binary to shell out to (Rain's own formatter is archived along + with the rest of Rain), so this is entirely native. + + + + + + +## Usage + +```shell +atmos aws cloudformation fmt --stack [options] +``` + +```shell +atmos aws cloudformation fmt vpc -s plat-ue2-dev +``` + +Check whether the template is formatted without writing changes (for CI): + +```shell +atmos aws cloudformation fmt vpc -s plat-ue2-dev --check +``` + +Format all or affected components' templates in dependency order: + +```shell +atmos aws cloudformation fmt --all -s plat-ue2-dev +atmos aws cloudformation fmt --affected --base origin/main --check +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--check` (optional)
+
Report whether the template is formatted without writing changes. Exits non-zero if the template is not formatted — use this in CI instead of the default write-in-place behavior.
+ +
`--all` (optional)
+
Format all `aws/cloudformation` components' templates in dependency order.
+ +
`--affected` (optional)
+
Format affected `aws/cloudformation` components' templates and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +:::note +`fmt` never calls the CloudFormation API and does not fire `before`/`after` +hook events — only [`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/get/_category_.json b/website/docs/cli/commands/aws/cloudformation/get/_category_.json new file mode 100644 index 00000000000..ed74d52f71e --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/get/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "get", + "className": "command", + "link": { + "type": "doc", + "id": "cli/commands/aws/cloudformation/get/get" + } +} diff --git a/website/docs/cli/commands/aws/cloudformation/get/get.mdx b/website/docs/cli/commands/aws/cloudformation/get/get.mdx new file mode 100644 index 00000000000..15bd5671103 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/get/get.mdx @@ -0,0 +1,33 @@ +--- +title: atmos aws cloudformation get +sidebar_label: get +sidebar_class_name: command +id: get +description: Fetch a deployed stack's template or policy. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import DocCardList from '@theme/DocCardList' +import Experimental from '@site/src/components/Experimental' + + +Fetch a deployed CloudFormation stack's template or stack policy directly from +the CloudFormation API — the live, deployed artifacts, as opposed to +[`render`](/cli/commands/aws/cloudformation/render), which only ever reads the +local template file. + + + + + + +## Usage + +```shell +atmos aws cloudformation get template --stack +atmos aws cloudformation get policy --stack +``` + +## Subcommands + + diff --git a/website/docs/cli/commands/aws/cloudformation/get/policy.mdx b/website/docs/cli/commands/aws/cloudformation/get/policy.mdx new file mode 100644 index 00000000000..70972110a5e --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/get/policy.mdx @@ -0,0 +1,65 @@ +--- +title: atmos aws cloudformation get policy +sidebar_label: policy +sidebar_class_name: command +id: policy +description: Fetch the deployed stack's policy. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Fetch the deployed stack's current stack policy (`GetStackPolicy`) and write + it to stdout — the policy CloudFormation is actually enforcing, as opposed + to the `stack_policy` configured on the component (which `apply` only + applies after a successful deploy). + + + + + + +## Usage + +```shell +atmos aws cloudformation get policy --stack [options] +``` + +```shell +atmos aws cloudformation get policy vpc -s plat-ue2-dev +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--all` (optional)
+
Fetch the policy for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Fetch the policy for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +## Output + +If the stack has no policy set (CloudFormation's default), `get policy` prints +a message saying so instead of an empty body. + +:::note +`get policy` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/get/template.mdx b/website/docs/cli/commands/aws/cloudformation/get/template.mdx new file mode 100644 index 00000000000..65f6d6588d5 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/get/template.mdx @@ -0,0 +1,69 @@ +--- +title: atmos aws cloudformation get template +sidebar_label: template +sidebar_class_name: command +id: template +description: Fetch the deployed stack's template. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + Fetch the deployed stack's template (`GetTemplate`) and write it to stdout. + By default this is the fully-processed template CloudFormation actually + deployed — the same shape a diff against the local render should compare + against — not the user-submitted source. + + + + + + +## Usage + +```shell +atmos aws cloudformation get template --stack [options] +``` + +```shell +atmos aws cloudformation get template vpc -s plat-ue2-dev +``` + +Fetch the original, user-submitted template instead of the processed one: + +```shell +atmos aws cloudformation get template vpc -s plat-ue2-dev --original +``` + +## Flags + +
+
`--stack`, `-s` (required)
+
Atmos stack.
+ +
`--original` (optional)
+
Fetch the user-submitted template instead of the processed one CloudFormation deployed.
+ +
`--all` (optional)
+
Fetch the template for all `aws/cloudformation` components in dependency order.
+ +
`--affected` (optional)
+
Fetch the template for affected `aws/cloudformation` components and their dependencies.
+ +
`--include-dependents` (optional)
+
With `--affected`, include dependent `aws/cloudformation` components.
+ +
`--tags` (optional)
+
Filter by tags (comma-separated, matches any): `--tags=production,tier-1`. Composes with `--all`/`--affected` to narrow the selected set further; cannot be combined with a single component argument.
+ +
`--labels` (optional)
+
Filter by labels (comma-separated `key=value` or `key:value` pairs, matches all): `--labels=cost-center=platform,compliance=sox`. Composes with `--all`/`--affected`/`--tags`; cannot be combined with a single component argument.
+
+ +:::note +`get template` does not fire `before`/`after` hook events — only +[`apply`](/cli/commands/aws/cloudformation/apply), +[`diff`](/cli/commands/aws/cloudformation/diff), and +[`delete`](/cli/commands/aws/cloudformation/delete) do. +::: diff --git a/website/docs/cli/commands/aws/cloudformation/list.mdx b/website/docs/cli/commands/aws/cloudformation/list.mdx new file mode 100644 index 00000000000..50f2e2a496d --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/list.mdx @@ -0,0 +1,79 @@ +--- +title: atmos aws cloudformation list +sidebar_label: list +sidebar_class_name: command +id: list +description: List deployed CloudFormation stacks in the account. +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import Experimental from '@site/src/components/Experimental' + + + List the account's deployed CloudFormation stacks (`ListStacks`), annotated + with whether each one matches an `aws/cloudformation` component's + `stack_name` configured in the given Atmos stack. Unlike every other verb, + `list` is account-wide, not scoped to a single component — there is no + `[component]` argument, and it does not support `--all`/`--affected`/`--tags`/`--labels`. + + + + + + +## Usage + +```shell +atmos aws cloudformation list --stack [options] +``` + +```shell +atmos aws cloudformation list --stack plat-ue2-dev +``` + +Only stacks currently in a `*_COMPLETE` status: + +```shell +atmos aws cloudformation list --stack plat-ue2-dev --status CREATE_COMPLETE,UPDATE_COMPLETE +``` + +List stacks in a specific region: + +```shell +atmos aws cloudformation list --stack plat-ue2-dev --region us-west-2 +``` + +## Flags + +
+
`--stack`, `-s` (optional)
+
+ Atmos stack to annotate against. Its configured `aws/cloudformation` + components' `stack_name` values determine which deployed stacks are + marked `managed` vs. `unmanaged`. Templates are processed (so + `stack_name` may reference e.g. `{{ .vars.stage }}`), but YAML functions + are not — they aren't needed to resolve `stack_name`, and some require + their own authentication, which would slow this command down + unnecessarily. +
+ +
`--identity`, `-i` (optional)
+
Identity to use for authentication.
+ +
`--status` (optional)
+
Filter by stack status (comma-separated, e.g. `CREATE_COMPLETE,UPDATE_COMPLETE`).
+ +
`--region` (optional)
+
AWS region to list stacks in. Defaults to the active identity's region, then the AWS SDK's standard resolution chain.
+
+ +## Output + +Each line shows whether the stack is `managed` (its name matches an +`aws/cloudformation` component's configured `stack_name` in the queried +stack) or `unmanaged`, its status, and its name: + +``` +managed CREATE_COMPLETE vpc-plat-ue2-dev +unmanaged UPDATE_COMPLETE some-other-stack +``` diff --git a/website/docs/cli/commands/aws/cloudformation/source/_category_.json b/website/docs/cli/commands/aws/cloudformation/source/_category_.json new file mode 100644 index 00000000000..b4a12d0cc25 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/source/_category_.json @@ -0,0 +1,8 @@ +{ + "label": "source", + "className": "command", + "link": { + "type": "doc", + "id": "cli/commands/aws/cloudformation/source/source" + } +} diff --git a/website/docs/cli/commands/aws/cloudformation/source/delete.mdx b/website/docs/cli/commands/aws/cloudformation/source/delete.mdx new file mode 100644 index 00000000000..45706809fc4 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/source/delete.mdx @@ -0,0 +1,104 @@ +--- +title: atmos aws cloudformation source delete +sidebar_label: source delete +sidebar_class_name: command +id: delete +description: Remove vendored source directory +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import ActionCard from '@site/src/components/ActionCard' +import PrimaryCTA from '@site/src/components/PrimaryCTA' + + +Use this command to delete the vendored source directory for an `aws/cloudformation` component. This removes the component directory that was created by `atmos aws cloudformation source pull`. + + + + Learn how to configure the `source` field for per-environment version control. +
+ Design Pattern +
+
+ + + +## Usage + +```shell +atmos aws cloudformation source delete --stack --force +``` + +## Description + +The `delete` command removes the vendored component directory. For safety, this command requires the `--force` flag to confirm deletion. + +This is useful for: +- Cleaning up vendored components before re-vendoring +- Removing components that are no longer needed +- Resetting to a clean state for troubleshooting + +## Examples + +### Delete Vendored Component + +Remove a vendored component directory: + +```shell +atmos aws cloudformation source delete vpc --stack dev --force +``` + +Output: +``` +Deleting directory: components/cloudformation/vpc +✓ Successfully deleted: components/cloudformation/vpc +``` + +### Without Force Flag + +Attempting to delete without `--force` shows an error: + +```shell +atmos aws cloudformation source delete vpc --stack dev +``` + +Output: +``` +Error: --force flag is required + +Explanation: Deletion requires --force flag for safety + +Hint: Use --force to confirm deletion +``` + +## Arguments + +
+
`component`
+
**Required.** The name of the Atmos component to delete.
+
+ +## Flags + +
+
`--stack` / `-s`
+
**Required.** The Atmos stack name. Can also be set via `ATMOS_STACK` environment variable.
+ +
`--force` / `-f`
+
**Required.** Confirm deletion. Without this flag, the command fails for safety.
+
+ +## Safety + +The `delete` command has several safety features: + +1. **Requires --force** - Prevents accidental deletion +2. **Only deletes source-managed components** - Only works on components with `source` configured +3. **Non-destructive on missing directories** - Shows a warning if the directory doesn't exist instead of failing + +## See Also + +- [Source-Based Version Pinning](/design-patterns/version-management/source-based-versioning) — Design pattern for per-environment version control +- [`atmos aws cloudformation source`](/cli/commands/aws/cloudformation/source) — Parent command overview +- [`atmos aws cloudformation source pull`](/cli/commands/aws/cloudformation/source/pull) — Vendor component source +- [`atmos aws cloudformation source list`](/cli/commands/aws/cloudformation/source/list) — List components with sources diff --git a/website/docs/cli/commands/aws/cloudformation/source/describe.mdx b/website/docs/cli/commands/aws/cloudformation/source/describe.mdx new file mode 100644 index 00000000000..dec642f0e5f --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/source/describe.mdx @@ -0,0 +1,124 @@ +--- +title: atmos aws cloudformation source describe +sidebar_label: source describe +sidebar_class_name: command +id: describe +description: Show source configuration for a component +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import ActionCard from '@site/src/components/ActionCard' +import PrimaryCTA from '@site/src/components/PrimaryCTA' + + +Use this command to display the `source` configuration for an `aws/cloudformation` component. This shows the source URI, version, and any path filters configured for vendoring. + + + + Learn how to configure the `source` field for per-environment version control. +
+ Design Pattern +
+
+ + + +## Usage + +```shell +atmos aws cloudformation source describe --stack +``` + +## Description + +The `describe` command extracts and displays the `source` configuration from a component's stack manifest. The output matches the stack manifest schema format, making it easy to copy and paste into your configuration. This is useful for: + +- Verifying source configuration before vendoring +- Checking the version configured for a component +- Reviewing included/excluded path filters +- Debugging source provisioning issues + +## Examples + +### View Source Configuration + +Display the source configuration for a component: + +```shell +atmos aws cloudformation source describe vpc --stack dev +``` + +Output: +```yaml +components: + "aws/cloudformation": + vpc: + source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 + included_paths: + - "*.yaml" + - "modules/**" + excluded_paths: + - "*.md" + - "tests/**" +``` + +### String Format Source + +When source is configured as a simple string: + +```shell +atmos aws cloudformation source describe vpc --stack dev +``` + +Output: +```yaml +components: + "aws/cloudformation": + vpc: + source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc?ref=1.0.0 +``` + +## Arguments + +
+
`component`
+
**Required.** The name of the Atmos component to describe.
+
+ +## Flags + +
+
`--stack` / `-s`
+
**Required.** The Atmos stack name. Can also be set via `ATMOS_STACK` environment variable.
+
+ +## Output Format + +The command outputs YAML matching the stack manifest schema: + +
+
`components."aws/cloudformation"..source`
+
The parsed source specification for the component.
+ +
`source.uri`
+
The go-getter-compatible source URI.
+ +
`source.version`
+
The version tag, branch, or commit (if specified separately).
+ +
`source.included_paths`
+
List of glob patterns for files to include.
+ +
`source.excluded_paths`
+
List of glob patterns for files to exclude.
+
+ +## See Also + +- [Source-Based Version Pinning](/design-patterns/version-management/source-based-versioning) — Design pattern for per-environment version control +- [`atmos aws cloudformation source`](/cli/commands/aws/cloudformation/source) — Parent command overview +- [`atmos aws cloudformation source pull`](/cli/commands/aws/cloudformation/source/pull) — Vendor component source +- [`atmos aws cloudformation source list`](/cli/commands/aws/cloudformation/source/list) — List components with sources diff --git a/website/docs/cli/commands/aws/cloudformation/source/list.mdx b/website/docs/cli/commands/aws/cloudformation/source/list.mdx new file mode 100644 index 00000000000..b152ca14ffd --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/source/list.mdx @@ -0,0 +1,136 @@ +--- +title: atmos aws cloudformation source list +sidebar_label: source list +sidebar_class_name: command +id: list +description: List aws/cloudformation components with source configuration +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import ActionCard from '@site/src/components/ActionCard' +import PrimaryCTA from '@site/src/components/PrimaryCTA' + + +Use this command to list all `aws/cloudformation` components that have `source` configured. This shows which components can be vendored using the source provisioner. + + + + Learn how to configure the `source` field for per-environment version control. +
+ Design Pattern +
+
+ + + +## Usage + +```shell +atmos aws cloudformation source list [component] [flags] +``` + +## Description + +The `list` command scans component configurations and displays all +`aws/cloudformation` components that have `source` defined. This helps +identify: + +- Which components are configured for JIT vendoring +- The source URIs and versions for each component +- Components that may need to be vendored before use + +:::tip +To list sources across all component types (Terraform, Helmfile, Packer, `aws/cloudformation`) in a unified view, use [`atmos list sources`](/cli/commands/list/sources). +::: + +## Examples + +### List All aws/cloudformation Sources Across All Stacks + +```shell +atmos aws cloudformation source list +``` + +Output: +``` +STACK COMPONENT URI VERSION +plat-ue2-dev vpc github.com/cloudposse/cloudformation-aws-components//modules/vpc 1.0.0 +plat-ue2-prod vpc github.com/cloudposse/cloudformation-aws-components//modules/vpc 1.1.0 +``` + +### List Sources in a Specific Stack + +```shell +atmos aws cloudformation source list --stack plat-ue2-dev +``` + +When filtering by stack, the Stack column is omitted: +``` +COMPONENT URI VERSION +vpc github.com/cloudposse/cloudformation-aws-components//modules/vpc 1.0.0 +``` + +### List Sources for a Specific Component + +```shell +atmos aws cloudformation source list vpc +``` + +Shows the component across all stacks: +``` +STACK COMPONENT URI VERSION +plat-ue2-dev vpc github.com/cloudposse/cloudformation-aws-components//modules/vpc 1.0.0 +plat-ue2-prod vpc github.com/cloudposse/cloudformation-aws-components//modules/vpc 1.1.0 +``` + +### Output in Different Formats + +```shell +# JSON format +atmos aws cloudformation source list --format json + +# YAML format +atmos aws cloudformation source list --format yaml + +# CSV format +atmos aws cloudformation source list --format csv + +# TSV format (tab-separated, for pipelines) +atmos aws cloudformation source list --format tsv +``` + +## Dynamic Columns + +The command automatically adjusts columns based on context: + +| Context | Columns Shown | +|---------|---------------| +| All stacks | Stack, Component, Folder*, URI, Version | +| Single stack (`--stack`) | Component, Folder*, URI, Version | + +*The Folder column only appears when any component uses `metadata.component` to specify a different folder name than the component instance name. + +## Arguments + +
+
`component` (optional)
+
Filter results to a specific component name or folder (`metadata.component`). When provided, only shows sources for components matching this name across all stacks.
+
+ +## Flags + +
+
`--stack` / `-s` (optional)
+
Filter by stack name. When provided, only shows sources within that stack and omits the Stack column from output.
Environment variable: `ATMOS_STACK`
+ +
`--format` / `-f`
+
Output format: `table`, `json`, `yaml`, `csv`, `tsv` (default: `table`).
Environment variable: `ATMOS_FORMAT`
+
+ +## See Also + +- [Source-Based Version Pinning](/design-patterns/version-management/source-based-versioning) - Design pattern for per-environment version control +- [`atmos list sources`](/cli/commands/list/sources) - Unified view across all component types +- [`atmos aws cloudformation source`](/cli/commands/aws/cloudformation/source) - Parent command overview +- [`atmos aws cloudformation source describe`](/cli/commands/aws/cloudformation/source/describe) - View source configuration for a specific component +- [`atmos aws cloudformation source pull`](/cli/commands/aws/cloudformation/source/pull) - Vendor a specific component diff --git a/website/docs/cli/commands/aws/cloudformation/source/pull.mdx b/website/docs/cli/commands/aws/cloudformation/source/pull.mdx new file mode 100644 index 00000000000..0b76388f06d --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/source/pull.mdx @@ -0,0 +1,122 @@ +--- +title: atmos aws cloudformation source pull +sidebar_label: source pull +sidebar_class_name: command +id: pull +description: Vendor component source from source configuration +--- +import Intro from '@site/src/components/Intro' +import CastPlayer from '@site/src/components/CastPlayer' +import ActionCard from '@site/src/components/ActionCard' +import PrimaryCTA from '@site/src/components/PrimaryCTA' + + +Use this command to vendor an `aws/cloudformation` component source based on its `source` configuration. This downloads the component from the specified URI and places it in the appropriate component directory. + + + + Learn how to configure the `source` field for per-environment version control. +
+ Design Pattern +
+
+ + + +## Usage + +```shell +atmos aws cloudformation source pull --stack [flags] +``` + +## Description + +The `pull` command vendors an `aws/cloudformation` component source by: + +1. Reading the `source` configuration from the component's stack manifest +2. Downloading the source from the specified URI using go-getter +3. Applying any `included_paths` and `excluded_paths` filters +4. Copying the filtered content to the component directory + +If the component is already vendored, it will be skipped unless `--force` is specified. + +## Examples + +### Basic Usage + +Vendor a component source for a specific stack: + +```shell +atmos aws cloudformation source pull vpc --stack dev +``` + +### Force Re-vendor + +Re-vendor even if the component directory already exists: + +```shell +atmos aws cloudformation source pull vpc --stack dev --force +``` + +### With Identity Override + +Use a specific identity for authentication: + +```shell +atmos aws cloudformation source pull vpc --stack dev --identity admin +``` + +## Arguments + +
+
`component`
+
**Required.** The name of the Atmos component to vendor.
+
+ +## Flags + +
+
`--stack` / `-s`
+
**Required.** The Atmos stack name. Can also be set via `ATMOS_STACK` environment variable.
+ +
`--force` / `-f`
+
Force re-vendor even if the component directory already exists. Without this flag, the command skips vendoring if the directory exists.
+ +
`--identity` / `-i`
+
Identity to use for authentication when downloading from protected sources. Overrides the component's default identity.
+
+ +## Configuration + +The component must have `source` configured in its stack manifest: + +```yaml +components: + "aws/cloudformation": + vpc: + source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 + included_paths: + - "*.yaml" + excluded_paths: + - "*.md" + - "tests/**" +``` + +## Output + +On success: +``` +Vendoring component 'vpc' from source... +Downloading from github.com/cloudposse/cloudformation-aws-components//modules/vpc?ref=1.0.0 +✓ Successfully vendored component to components/cloudformation/vpc +``` + +## See Also + +- [Source-Based Version Pinning](/design-patterns/version-management/source-based-versioning) — Design pattern for per-environment version control +- [`atmos aws cloudformation source`](/cli/commands/aws/cloudformation/source) — Parent command overview +- [`atmos aws cloudformation source describe`](/cli/commands/aws/cloudformation/source/describe) — View source configuration +- [`atmos aws cloudformation source list`](/cli/commands/aws/cloudformation/source/list) — List components with source +- [`atmos aws cloudformation source delete`](/cli/commands/aws/cloudformation/source/delete) — Remove vendored source diff --git a/website/docs/cli/commands/aws/cloudformation/source/source.mdx b/website/docs/cli/commands/aws/cloudformation/source/source.mdx new file mode 100644 index 00000000000..0374aecb9d5 --- /dev/null +++ b/website/docs/cli/commands/aws/cloudformation/source/source.mdx @@ -0,0 +1,382 @@ +--- +title: atmos aws cloudformation source +sidebar_label: source +sidebar_class_name: command +id: source +description: Manage aws/cloudformation component sources with JIT vendoring +--- +import Intro from '@site/src/components/Intro' +import Experimental from '@site/src/components/Experimental' +import CastPlayer from '@site/src/components/CastPlayer' +import DocCardList from '@theme/DocCardList' +import ActionCard from '@site/src/components/ActionCard' +import PrimaryCTA from '@site/src/components/PrimaryCTA' + + +Use these commands to manage `aws/cloudformation` component sources with just-in-time (JIT) vendoring. This enables components to declare their source location inline using the top-level `source` field without requiring a separate `component.yaml` file. Sources are automatically provisioned when running `aws cloudformation` commands—just run `atmos aws cloudformation plan` and the source is downloaded on first use. + + + + + + Learn how to use the source field for native per-environment version control directly in stack configuration. +
+ Design Pattern +
+
+ + + +## Usage + +```shell +atmos aws cloudformation source [options] +``` + +## Subcommands + + + +## Automatic Provisioning + +Sources are automatically provisioned when running any `aws cloudformation` command. If a component has `source` configured and the target directory doesn't exist, Atmos downloads the source before running the operation: + +```shell +# Source is automatically provisioned on first use +atmos aws cloudformation plan vpc --stack dev +# → Auto-provisioning source for component 'vpc' +# → Auto-provisioned source to components/cloudformation/vpc +# → CloudFormation operation runs +``` + +This means you can simply configure your component's source and run `atmos aws cloudformation` commands—no explicit vendor step needed. + +## CLI Commands + +The explicit CLI commands are useful for fine-grained control: +- Force re-vendor to get the latest version +- Describe source configuration +- Delete vendored sources +- List components with sources + +## How It Works + +The source provisioner enables just-in-time vendoring of `aws/cloudformation` components directly from stack configuration. Instead of pre-vendoring components or maintaining separate `component.yaml` files, you can declare the source inline: + +```yaml +# stacks/dev.yaml +components: + "aws/cloudformation": + vpc: + source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 + included_paths: + - "*.yaml" + - "modules/**" + excluded_paths: + - "*.md" + - "tests/**" + stack_name: vpc-dev +``` + +When you run `atmos aws cloudformation source pull vpc --stack dev`, Atmos: + +1. **Reads Configuration** - Extracts `source` from the component's stack manifest. +2. **Resolves Source** - Parses the go-getter-compatible URI with optional version. +3. **Downloads Content** - Fetches the source using go-getter (supports git, s3, http, oci, etc.). +4. **Filters Files** - Applies `included_paths` and `excluded_paths` patterns. +5. **Copies to Target** - Places files in the component directory. + +## Source Specification + +The `source` field supports two formats: + +### String Format (Simple) + +For simple cases, use a go-getter URI string: + +```yaml +source: "github.com/cloudposse/cloudformation-aws-components//modules/vpc?ref=1.0.0" +``` + +### Map Format (Full Control) + +For more control, use a map with explicit fields: + +```yaml +source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 + included_paths: + - "*.yaml" + - "*.json" + - "modules/**" + excluded_paths: + - "*.md" + - "tests/**" + - "examples/**" +``` + +### Source Fields + +
+
`uri`
+
Go-getter compatible source URI. Supports git, s3, http, gcs, oci, and other protocols.
+ +
`version`
+
Version tag, branch, or commit. Appended as `?ref=` for git sources. For non-git sources (S3, HTTP, OCI), the version should be embedded in the URI itself.
+ +
`included_paths`
+
Glob patterns for files to include. If specified, only matching files are copied.
+ +
`excluded_paths`
+
Glob patterns for files to exclude. Applied after included_paths filtering.
+ +
`ttl`
+
+ Cache duration for JIT-vendored sources. Controls how long a cached source is reused before re-pulling from the remote. When set, Atmos checks the source's last update time against this TTL. If expired, the source is re-pulled automatically on the next command invocation. If not set, cached sources are reused indefinitely (only re-pulled on version or URI changes). + + Examples: `"0s"` (always re-pull), `"1h"` (hourly), `"7d"` (weekly), `"daily"`. + + A global default can be set in `atmos.yaml` under `components."aws/cloudformation".source.ttl` and overridden per-component. +
+ +
`retry`
+
+ Optional retry configuration for handling transient network errors during download. Useful for unreliable networks or when hitting rate limits. + + ```yaml + retry: + max_attempts: 5 + initial_delay: 2s + max_delay: 60s + backoff_strategy: exponential + ``` + + All fields are optional. Recommended: `max_attempts`, `initial_delay`, `max_delay`, `backoff_strategy` (`exponential`, `linear`, `constant`). Additional options: `multiplier`, `random_jitter`, `max_elapsed_time`. +
+
+ +## Examples + +### Vendor a Component + +Download and vendor a component source: + +```shell +atmos aws cloudformation source pull vpc --stack dev +``` + +Output: +``` +Vendoring component 'vpc' from source... +Downloading from github.com/cloudposse/cloudformation-aws-components//modules/vpc?ref=1.0.0 +✓ Successfully vendored component to components/cloudformation/vpc +``` + +### Force Re-vendor + +Force re-download even if the component directory exists: + +```shell +atmos aws cloudformation source pull vpc --stack dev --force +``` + +### View Source Configuration + +Display the source configuration for a component: + +```shell +atmos aws cloudformation source describe vpc --stack dev +``` + +Output: +```yaml +components: + "aws/cloudformation": + vpc: + source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 + included_paths: + - "*.yaml" + - "modules/**" + excluded_paths: + - "*.md" + - "tests/**" +``` + +### List Components with Sources + +List all components that have source configured: + +```shell +atmos aws cloudformation source list --stack dev +``` + +### Delete Vendored Source + +Remove the vendored component directory (requires --force for safety): + +```shell +atmos aws cloudformation source delete vpc --stack dev --force +``` + +## Arguments + +
+
`component`
+
The Atmos component name (required for pull, describe, delete)
+
+ +## Flags + +
+
`--stack` / `-s`
+
Atmos stack name (required). Can also be set via `ATMOS_STACK` environment variable.
+ +
`--identity` / `-i`
+
Identity to use for authentication when downloading from protected sources (`pull` only).
+ +
`--force` / `-f`
+
Force re-vendor even if component directory exists (`pull` command), or confirm deletion (`delete` command).
+
+ +## Authentication + +Source commands support authentication for accessing private repositories or cloud storage. + +### Component-Level Identity + +Components can specify an authentication identity: + +```yaml +components: + "aws/cloudformation": + vpc: + source: + uri: github.com/my-org/private-components//modules/vpc + version: v1.0.0 + auth: + identities: + github-deployer: + default: true + kind: github/app + via: + provider: github-app +``` + +### Identity Flag Override + +Override the component's default identity: + +```shell +atmos aws cloudformation source pull vpc --stack dev --identity admin +``` + +For more details on configuring authentication identities, see the [Authentication Guide](/stacks/auth). + +## Configuration Patterns + +### Inheritance with source + +Use stack inheritance to share source configurations: + +```yaml +# stacks/catalog/vpc/defaults.yaml +components: + "aws/cloudformation": + vpc/defaults: + source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 + +# stacks/dev.yaml +components: + "aws/cloudformation": + vpc: + metadata: + inherits: [vpc/defaults] + # Inherits source configuration + stack_name: vpc-dev +``` + +### Version Override per Environment + +Override the version per environment: + +```yaml +# stacks/dev.yaml +components: + "aws/cloudformation": + vpc: + metadata: + inherits: [vpc/defaults] + source: + version: 1.1.0 # Override version for dev + +# stacks/prod.yaml +components: + "aws/cloudformation": + vpc: + metadata: + inherits: [vpc/defaults] + source: + version: 1.0.0 # Pin to stable version for prod +``` + +## Supported Source Types + +The source provisioner uses go-getter and supports multiple protocols: + +### Git Sources + +Shortened GitHub syntax (recommended): +```yaml +source: + uri: github.com/cloudposse/cloudformation-aws-components//modules/vpc + version: 1.0.0 +``` + +Explicit HTTPS: +```yaml +source: + uri: git::https://github.com/org/repo.git//path + version: main +``` + +Explicit SSH: +```yaml +source: + uri: git::ssh://git@github.com/org/repo.git//path + version: main +``` + +### S3 Sources + +```yaml +source: + uri: s3::https://s3-us-east-1.amazonaws.com/my-bucket/components/vpc.tar.gz +``` + +### HTTP/HTTPS Sources + +```yaml +source: + uri: https://releases.example.com/components/vpc-1.0.0.tar.gz +``` + +### OCI Registry Sources + +```yaml +source: + uri: oci::registry.example.com/components/vpc:v1.0.0 +``` + +## See Also + +- [Source-Based Version Pinning](/design-patterns/version-management/source-based-versioning) — Design pattern for per-environment version management +- [Stack Configuration](/learn/stacks) — Learn about Atmos stacks +- [`atmos aws cloudformation`](/cli/commands/aws/cloudformation) — Parent command overview +- [Vendoring](/vendor) — Pre-vendor components for immutability and audit trails diff --git a/website/docs/functions/template/atmos.Component.mdx b/website/docs/functions/template/atmos.Component.mdx index faa09020dde..48cd5122410 100644 --- a/website/docs/functions/template/atmos.Component.mdx +++ b/website/docs/functions/template/atmos.Component.mdx @@ -32,7 +32,8 @@ Atmos component in a stack, and use it in `Go` templates in Atmos component conf
`section`
Atmos section name. Any section returned by the CLI command atmos describe component can be used. - A special `outputs` section is also supported to get the outputs (remote state) of Terraform/OpenTofu components.
+ A special `outputs` section is also supported to get the outputs (remote state) of Terraform/OpenTofu components, + or the deployed Outputs of native `aws/cloudformation` components.
`outputs`
Using the `outputs` section in the `atmos.Component` command is an convenient way to read the outputs (remote state) @@ -205,6 +206,29 @@ Then we can use the [`toRawJson` or `toJson`](https://masterminds.github.io/spri The results of the `toRawJson` function are serialized into JSON, which can be safely embedded in the YAML stack configuration. The single quotes around the braces in the `delimiters` setting ensure that the JSON is not parsed as YAML, but then processed as a template function which removes the single quotes and replaces it with the JSON string. +## Using `atmos.Component` with `aws/cloudformation` Components + +The `outputs` section is not limited to Terraform/OpenTofu targets: when `component` resolves to a native +`aws/cloudformation` component, `atmos.Component(...).outputs` returns the deployed CloudFormation stack's +[Outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html) instead +— fetched live via `DescribeStacks`. This is the same Terraform↔CloudFormation interop bridge as the +[`!aws.cloudformation.output`](/functions/yaml/aws.cloudformation.output) YAML function; use whichever fits the +call site (`atmos.Component` when you also need other sections of the target, like `vars` or `settings`; +`!aws.cloudformation.output` for a single Output value). + +```yaml +components: + terraform: + my_lambda_component: + vars: + # Read the `VpcId` Output of the native aws/cloudformation `vpc` component in the current stack + vpc_id: '{{ (atmos.Component "vpc" .stack).outputs.VpcId }}' +``` + +The target `aws/cloudformation` component must have a resolved `stack_name` and already be deployed — +`atmos.Component` calls the live CloudFormation API for these targets, the same as for Terraform/OpenTofu targets +without a `static` remote state backend. + ## Examples The following configurations show different ways of using the `atmos.Component` template function to read values from diff --git a/website/docs/functions/yaml/aws.cloudformation.output.mdx b/website/docs/functions/yaml/aws.cloudformation.output.mdx new file mode 100644 index 00000000000..43ad9f06449 --- /dev/null +++ b/website/docs/functions/yaml/aws.cloudformation.output.mdx @@ -0,0 +1,113 @@ +--- +title: "!aws.cloudformation.output" +sidebar_position: 16 +sidebar_label: "!aws.cloudformation.output" +sidebar_class_name: command +description: Read the deployed Outputs of an aws/cloudformation component directly in Atmos stack manifests +--- +import File from '@site/src/components/File' +import Intro from '@site/src/components/Intro' +import Experimental from '@site/src/components/Experimental' + + +The `!aws.cloudformation.output` YAML function reads the deployed +[Outputs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html) +of a native `aws/cloudformation` component directly in Atmos stack manifests, +by calling the CloudFormation `DescribeStacks` API. It is the Terraform↔CloudFormation +interop bridge: the sibling of [`!terraform.output`](/functions/yaml/terraform.output), +but for `aws/cloudformation` targets instead of Terraform/OpenTofu ones. + + + + +## Usage + +The `!aws.cloudformation.output` function is called with either two or three parameters: + +```yaml + # Get the `output-key` Output of the `component` in the current stack + !aws.cloudformation.output + + # Get the `output-key` Output of the `component` in the provided `stack` + !aws.cloudformation.output +``` + +## Arguments + +
+
`component`
+
The `aws/cloudformation` component name.
+ +
`stack`
+
(Optional) Atmos stack name. Defaults to the current stack when omitted.
+ +
`output-key`
+
+ The exact CloudFormation Output's logical key (the value of the `Outputs.` entry + in the target's template). Unlike [`!terraform.output`](/functions/yaml/terraform.output), + this is a direct lookup by key, not a [YQ](https://mikefarah.gitbook.io/yq) expression — + CloudFormation Outputs are always a flat key/value map, so there is nothing to query into. +
+
+ +:::tip +You can use [Atmos Stack Manifest Templating](/templates) in the `!aws.cloudformation.output` YAML function expressions. +Atmos processes the templates first, and then executes the `!aws.cloudformation.output` function, allowing you to provide the parameters to +the function dynamically. +::: + +:::note Type-Aware Merging +Atmos supports type-aware merging of YAML functions and concrete values, allowing them to coexist in the inheritance chain without type conflicts. +See the full explanation: [YAML Function Merging](/reference/yaml-function-merging) +::: + +## Requirements + +- The target component must be a native `aws/cloudformation` component with a resolved `stack_name` — `!aws.cloudformation.output` errors if the target has no `stack_name` configured. +- The target stack must already be deployed. `!aws.cloudformation.output` calls the live `DescribeStacks` API; there is no local-state equivalent (`aws/cloudformation` has no Terraform/OpenTofu-style state file to read instead). +- Resolving the function requires AWS authentication — it uses the target component's own auth if it authenticates independently, otherwise the enclosing component's (propagated from `--identity`). + +## Examples + + +```yaml +components: + terraform: + my_lambda_component: + vars: + # Read the `VpcId` Output of the aws/cloudformation `vpc` component in the current stack + vpc_id: !aws.cloudformation.output vpc VpcId + + # Read an Output from a different, hardcoded stack + shared_bucket: !aws.cloudformation.output logging plat-ue2-audit LogBucketName + + # Use the `.stack` template identifier to reference the current stack explicitly + subnet_ids: !aws.cloudformation.output vpc {{ .stack }} PrivateSubnetIds +``` + + +## Caching the result of `!aws.cloudformation.output` function + +Atmos caches (in memory) the results of the `!aws.cloudformation.output` function. + +The cache is per Atmos CLI command execution, e.g., each new execution of a command like `atmos terraform plan` +or `atmos describe component` will create and use a new memory cache, re-invoking `DescribeStacks` on the next run. + +If you define the function in stack manifests for the same component in a stack more than once, the first call will +produce the result and cache it, and all the consecutive calls will just use the cached data. + +## Considerations + +- `!aws.cloudformation.output` **is not allowed** in `metadata.tags` or `metadata.labels` values — the same restriction as [`!terraform.output`](/functions/yaml/terraform.output#considerations). Selectors (`--tags`/`--labels`) drive component-scoping decisions before evaluation, so they must be resolvable without authentication, API calls, or nondeterminism. + +- Using `!aws.cloudformation.output` with secrets can expose sensitive data to standard output (stdout) in any commands that describe stacks or components. + +- Consider cold-start scenarios: if the dependent `aws/cloudformation` stack has not yet been deployed, the function returns an error. + +- Be mindful of disaster recovery (DR) implications when using it across regions. + +## See Also + +- [`!terraform.output`](/functions/yaml/terraform.output) — The Terraform/OpenTofu equivalent +- [`atmos.Component`](/functions/template/atmos.Component) — The template-function equivalent, which also resolves `.outputs` for `aws/cloudformation` targets +- [`atmos aws cloudformation output`](/cli/commands/aws/cloudformation/output) — Show a deployed stack's Outputs from the CLI diff --git a/website/docs/functions/yaml/index.mdx b/website/docs/functions/yaml/index.mdx index 651ee513828..80401b0231c 100644 --- a/website/docs/functions/yaml/index.mdx +++ b/website/docs/functions/yaml/index.mdx @@ -125,6 +125,10 @@ YAML supports three types of data: core, defined, and user-defined. - The [__`!aws.region`__](/functions/yaml/aws.region) YAML function retrieves the AWS region from the current SDK configuration. + - The [__`!aws.cloudformation.output`__](/functions/yaml/aws.cloudformation.output) YAML function allows you to + read the deployed Outputs of a native `aws/cloudformation` component directly within Atmos stack manifests — + the Terraform↔CloudFormation interop bridge, sibling to `!terraform.output`. + - The [__`!tags`__](/functions/yaml/tags) and [__`!labels`__](/functions/yaml/labels) YAML functions return the current component's own `metadata.tags` (list) and `metadata.labels` (map), typed correctly with no `!template`/`toJson` boilerplate — commonly used to bridge `metadata.labels` @@ -228,6 +232,9 @@ components: # Get the current AWS region aws_region: !aws.region + # Read the `VpcId` Output of a native aws/cloudformation component in the current stack + vpc_id: !aws.cloudformation.output vpc VpcId + # Preserve template syntax for downstream tools (Terraform, Helm, ArgoCD) helm_annotation: !literal "{{ .Values.ingress.class }}" terraform_var: !literal "${var.hostname}" From 977015a4f8ae58b30e3b4f369c7e86df0bdf172f Mon Sep 17 00:00:00 2001 From: "atmos-pro[bot]" <173522224+atmos-pro[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 11:48:48 +0000 Subject: [PATCH 06/10] [autocommit] formatting fixes From 4909a618e8b755772a80afac63aa631db43f352e Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 27 Aug 2026 10:39:31 -0500 Subject: [PATCH 07/10] fix(cloudformation): key atmos.Component() output cache on resolved identity componentFunc cached its result under stack+component alone, computed after resolving the nested target's AuthManager. Two calls for the same component/stack under two different resolved identities (e.g. two callers passing different --identity, or a target whose own auth section only applies on one call) could silently return the other identity's/region's cached outputs. Move the AuthManager resolution ahead of the cache lookup and fold the resolved identity/region into the cache key. Found via CodeRabbit review. Co-Authored-By: Claude Sonnet 5 --- internal/exec/template_funcs_component.go | 63 ++++++++++++------- ...ate_funcs_component_cloudformation_test.go | 30 +++++++++ 2 files changed, 72 insertions(+), 21 deletions(-) diff --git a/internal/exec/template_funcs_component.go b/internal/exec/template_funcs_component.go index 967b591b417..4372c1f0037 100644 --- a/internal/exec/template_funcs_component.go +++ b/internal/exec/template_funcs_component.go @@ -57,7 +57,6 @@ func componentFunc( stack string, ) (any, error) { functionName := fmt.Sprintf("atmos.Component(%s, %s)", component, stack) - stackSlug := fmt.Sprintf("%s-%s", stack, component) log.Debug("Executing template function", "function", functionName) @@ -71,6 +70,27 @@ func componentFunc( return emptyComponentSections(), nil } + // Resolve the AuthManager for this nested component. The target's own auth section (when it + // declares a default identity) overrides the enclosing component's propagated AuthContext, + // mirroring !terraform.state / !terraform.output via resolveAuthManagerForNestedComponent. + // Without this, atmos.Component() always reused the enclosing component's credentials verbatim, + // even for a target that authenticates independently. + // + // This resolution must happen before the cache lookup below: the cache key includes the + // resolved identity/region so that the same component+stack requested under two different + // enclosing identities (e.g. two callers with different --identity, or a target whose own + // auth section is only honored on one of the calls) never collide on a single cached result — + // a prior version keyed the cache on stack+component alone and could silently return another + // identity's/region's outputs. + resolvedAuthMgr := resolveComponentFuncAuthManager(atmosConfig, configAndStacksInfo, component, stack, resolveAuthManagerForNestedComponent) + var authContext *schema.AuthContext + if resolvedAuthMgr != nil { + if si := resolvedAuthMgr.GetStackInfo(); si != nil { + authContext = si.AuthContext + } + } + stackSlug := fmt.Sprintf("%s-%s-%s", stack, component, authCacheKeySuffix(authContext)) + // If the result for the component in the stack already exists in the cache, return it existingSections, found := componentFuncSyncMap.Load(stackSlug) if found && existingSections != nil { @@ -88,13 +108,6 @@ func componentFunc( return existingSections, nil } - // Resolve the AuthManager for this nested component. The target's own auth section (when it - // declares a default identity) overrides the enclosing component's propagated AuthContext, - // mirroring !terraform.state / !terraform.output via resolveAuthManagerForNestedComponent. - // Without this, atmos.Component() always reused the enclosing component's credentials verbatim, - // even for a target that authenticates independently. - resolvedAuthMgr := resolveComponentFuncAuthManager(atmosConfig, configAndStacksInfo, component, stack, resolveAuthManagerForNestedComponent) - sections, err := ExecuteDescribeComponent(&ExecuteDescribeComponentParams{ Component: component, Stack: stack, @@ -122,12 +135,6 @@ func componentFunc( // Execute `terraform output` using the resolved AuthContext: the target's own if it // authenticated independently, otherwise the enclosing component's (propagated from the // --identity flag). - var authContext *schema.AuthContext - if resolvedAuthMgr != nil { - if si := resolvedAuthMgr.GetStackInfo(); si != nil { - authContext = si.AuthContext - } - } terraformOutputs, err = componentFuncOutputsExecutor.ExecuteWithSections(atmosConfig, component, stack, sections, authContext) if err != nil { return nil, fmt.Errorf("atmos.Component(%s, %s) failed to get terraform outputs: %w", component, stack, err) @@ -140,13 +147,7 @@ func componentFunc( sections = lo.Assign(sections, outputs) } else if componentType == cfg.CloudFormationComponentType { - var cfnAuthContext *schema.AuthContext - if resolvedAuthMgr != nil { - if si := resolvedAuthMgr.GetStackInfo(); si != nil { - cfnAuthContext = si.AuthContext - } - } - cfnOutputs, err := cloudFormationOutputsForSections(atmosConfig, component, sections, cfnAuthContext) + cfnOutputs, err := cloudFormationOutputsForSections(atmosConfig, component, sections, authContext) if err != nil { return nil, fmt.Errorf("atmos.Component(%s, %s) failed to get aws/cloudformation outputs: %w", component, stack, err) } @@ -171,6 +172,26 @@ func componentFunc( return sections, nil } +// authCacheKeySuffix derives a cache-key fragment from the resolved AuthContext, so +// componentFunc's cache never conflates two calls to the same stack+component that resolved to +// different identities/regions. Empty when authContext is nil (no identity resolved), matching +// the pre-existing stack+component-only key for that common case. +func authCacheKeySuffix(authContext *schema.AuthContext) string { + if authContext == nil { + return "" + } + switch { + case authContext.AWS != nil: + return fmt.Sprintf("aws:%s:%s", authContext.AWS.Profile, authContext.AWS.Region) + case authContext.Azure != nil: + return fmt.Sprintf("azure:%s:%s", authContext.Azure.Profile, authContext.Azure.SubscriptionID) + case authContext.GCP != nil: + return fmt.Sprintf("gcp:%s", authContext.GCP.ProjectID) + default: + return "" + } +} + // componentFuncAuthResolver builds the AuthManager for a nested target — used by atmos.Component() // (resolveComponentFuncAuthManager) and `!terraform.output` (resolveNestedOutputAuth). Matches the // signature of resolveAuthManagerForNestedComponent so tests can inject a spy. diff --git a/internal/exec/template_funcs_component_cloudformation_test.go b/internal/exec/template_funcs_component_cloudformation_test.go index 3f4a6fdbbdf..d97d8726259 100644 --- a/internal/exec/template_funcs_component_cloudformation_test.go +++ b/internal/exec/template_funcs_component_cloudformation_test.go @@ -88,3 +88,33 @@ func TestComponentFunc_CloudFormationBranch_PassesResolvedAuthContext(t *testing require.NotNil(t, gotAuth, "the enclosing AuthContext must reach cloudFormationOutputsForSections") assert.Equal(t, "enclosing-identity", gotAuth.Profile) } + +// componentFunc's cache must be keyed on the resolved identity, not just stack+component: two +// calls for the same aws/cloudformation target under two different enclosing identities (e.g. +// two callers with different --identity) must each hit the outputs getter and must never return +// the other identity's cached result. +func TestComponentFunc_CloudFormationBranch_CacheKeyIncludesIdentity(t *testing.T) { + clearComponentFuncSyncMap(t) + atmosConfig := setupAwsCloudFormationOutputFixture(t) + + ctrl := gomock.NewController(t) + mockGetter := NewMockCloudFormationOutputsGetter(ctrl) + mockGetter.EXPECT().GetOutputs(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn( + func(_ context.Context, _, _ string, authCtx *schema.AWSAuthContext) (map[string]any, error) { + return map[string]any{"VpcId": "vpc-" + authCtx.Profile}, nil + }, + ).Times(2) + stubCloudFormationOutputsGetter(t, mockGetter) + + identityA := &schema.AuthContext{AWS: &schema.AWSAuthContext{Profile: "identity-a"}} + resultA, err := componentFunc(&atmosConfig, &schema.ConfigAndStacksInfo{AuthContext: identityA}, "vpc", "test") + require.NoError(t, err) + outputsA := resultA.(map[string]any)[cfg.OutputsSectionName].(map[string]any) + assert.Equal(t, "vpc-identity-a", outputsA["VpcId"]) + + identityB := &schema.AuthContext{AWS: &schema.AWSAuthContext{Profile: "identity-b"}} + resultB, err := componentFunc(&atmosConfig, &schema.ConfigAndStacksInfo{AuthContext: identityB}, "vpc", "test") + require.NoError(t, err) + outputsB := resultB.(map[string]any)[cfg.OutputsSectionName].(map[string]any) + assert.Equal(t, "vpc-identity-b", outputsB["VpcId"]) +} From 54994faf8aff38e733d653a5157a3abd1838bebd Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 27 Aug 2026 10:47:23 -0500 Subject: [PATCH 08/10] fix(cloudformation): use the plain API-call sentinel in drift/get, not confirmed-drift/changeset ones DetectStackDrift/DescribeStackDriftDetectionStatus/DescribeStackResourceDrifts API failures and detection timeouts were wrapped in ErrAwsCloudFormationDriftDetected, which should mean drift was actually confirmed (runDriftDetect's --fail-on-drift case, left unchanged). Likewise GetTemplate/GetStackPolicy failures were wrapped in ErrAwsCloudFormationChangeSetFailed despite having nothing to do with a changeset. Swapped both to ErrAwsCloudFormationAPICallFailed. Found via CodeRabbit review. Co-Authored-By: Claude Sonnet 5 --- pkg/component/aws/cloudformation/drift.go | 10 +++++----- pkg/component/aws/cloudformation/drift_test.go | 10 +++++----- pkg/component/aws/cloudformation/get.go | 4 ++-- pkg/component/aws/cloudformation/get_test.go | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/component/aws/cloudformation/drift.go b/pkg/component/aws/cloudformation/drift.go index 2092447b8f0..b00fbc4e235 100644 --- a/pkg/component/aws/cloudformation/drift.go +++ b/pkg/component/aws/cloudformation/drift.go @@ -40,7 +40,7 @@ func detectDrift(ctx context.Context, client CloudFormationClient, stackName str out, err := client.DetectStackDrift(ctx, &cloudformation.DetectStackDriftInput{StackName: awsString(stackName)}) if err != nil { - return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationDriftDetected, err) + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationAPICallFailed, err) } detectionID := stringValue(out.StackDriftDetectionId) @@ -56,7 +56,7 @@ func pollDriftDetection(ctx context.Context, client CloudFormationClient, detect StackDriftDetectionId: awsString(detectionID), }) if err != nil { - return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationDriftDetected, err) + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationAPICallFailed, err) } result := &driftDetectionResult{ @@ -73,11 +73,11 @@ func pollDriftDetection(ctx context.Context, client CloudFormationClient, detect result.DetectionDone = true return result, nil case cfntypes.StackDriftDetectionStatusDetectionFailed: - return result, fmt.Errorf("%w: %s", errUtils.ErrAwsCloudFormationDriftDetected, result.StatusReason) + return result, fmt.Errorf("%w: %s", errUtils.ErrAwsCloudFormationAPICallFailed, result.StatusReason) } if time.Now().After(deadline) { - return result, fmt.Errorf("%w: timed out waiting for drift detection", errUtils.ErrAwsCloudFormationDriftDetected) + return result, fmt.Errorf("%w: timed out waiting for drift detection", errUtils.ErrAwsCloudFormationAPICallFailed) } select { case <-ctx.Done(): @@ -101,7 +101,7 @@ func describeResourceDrifts(ctx context.Context, client CloudFormationClient, st NextToken: nextToken, }) if err != nil { - return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationDriftDetected, err) + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationAPICallFailed, err) } drifts = append(drifts, out.StackResourceDrifts...) if out.NextToken == nil { diff --git a/pkg/component/aws/cloudformation/drift_test.go b/pkg/component/aws/cloudformation/drift_test.go index 0a2d3c701dc..fc19dfbe3ab 100644 --- a/pkg/component/aws/cloudformation/drift_test.go +++ b/pkg/component/aws/cloudformation/drift_test.go @@ -63,7 +63,7 @@ func TestDetectDrift_StartError(t *testing.T) { _, err := detectDrift(context.Background(), client, "vpc") require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) } // pollDriftDetection must wrap a DescribeStackDriftDetectionStatus API error. @@ -74,7 +74,7 @@ func TestPollDriftDetection_APIError(t *testing.T) { _, err := pollDriftDetection(context.Background(), client, "detection-1") require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) } // pollDriftDetection must report DETECTION_FAILED as an error, carrying the @@ -89,7 +89,7 @@ func TestPollDriftDetection_DetectionFailed(t *testing.T) { result, err := pollDriftDetection(context.Background(), client, "detection-1") require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) assert.Contains(t, err.Error(), "internal failure") assert.False(t, result.DetectionDone) } @@ -131,7 +131,7 @@ func TestPollDriftDetection_Timeout(t *testing.T) { _, err := pollDriftDetection(context.Background(), client, "detection-1") require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) assert.Contains(t, err.Error(), "timed out") } @@ -185,7 +185,7 @@ func TestDescribeResourceDrifts_Error(t *testing.T) { _, err := describeResourceDrifts(context.Background(), client, "vpc") require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationDriftDetected) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) } // runDriftDetect's happy path (no --fail-on-drift): renders the summary line diff --git a/pkg/component/aws/cloudformation/get.go b/pkg/component/aws/cloudformation/get.go index 647262647b0..cb43bc52d9a 100644 --- a/pkg/component/aws/cloudformation/get.go +++ b/pkg/component/aws/cloudformation/get.go @@ -26,7 +26,7 @@ func getDeployedTemplate(ctx context.Context, client CloudFormationClient, stack out, err := client.GetTemplate(ctx, input) if err != nil { - return "", fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + return "", fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationAPICallFailed, err) } return stringValue(out.TemplateBody), nil } @@ -38,7 +38,7 @@ func getDeployedStackPolicy(ctx context.Context, client CloudFormationClient, st out, err := client.GetStackPolicy(ctx, &cloudformation.GetStackPolicyInput{StackName: awsString(stackName)}) if err != nil { - return "", fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + return "", fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationAPICallFailed, err) } return stringValue(out.StackPolicyBody), nil } diff --git a/pkg/component/aws/cloudformation/get_test.go b/pkg/component/aws/cloudformation/get_test.go index 435474eb9db..7792b17c6bd 100644 --- a/pkg/component/aws/cloudformation/get_test.go +++ b/pkg/component/aws/cloudformation/get_test.go @@ -60,7 +60,7 @@ func TestGetDeployedTemplate_Error(t *testing.T) { _, err := getDeployedTemplate(context.Background(), client, "vpc", false) require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) } // getDeployedStackPolicy must return the policy body on success, including @@ -98,7 +98,7 @@ func TestGetDeployedStackPolicy_Error(t *testing.T) { _, err := getDeployedStackPolicy(context.Background(), client, "vpc") require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) } // runGetTemplate must write the template body to the data channel and From 659ccdafce0d0b53b03dc63ace42d26d25b802e9 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 27 Aug 2026 11:26:47 -0500 Subject: [PATCH 09/10] fix(cloudformation): sync GetAvailableCommands, fix outputs sentinel, strengthen tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GetAvailableCommands() now derives its list from subCommandOperations instead of a hand-maintained literal, which was missing "destroy", "outputs", and "fmt" — those verbs were dispatchable via Execute but rejected by pkg/composition's verb-allowlist check (GetAvailableCommands is its source of truth). - pkg/aws/cloudformation's GetOutputs (the !aws.cloudformation.output interop bridge) wrapped both a DescribeStacks API failure and a genuine stack-not-found result in the same ErrAwsCloudFormationChangeSetFailed, despite neither being changeset-related. Split into ErrAwsCloudFormationAPICallFailed and a new ErrAwsCloudFormationStackNotFound. - Fixed a stale doc comment on runChangesetList (said "creation time", renders "description"). - Strengthened TestRenderDeployedStacksList_Populated: "managed" is a substring of "unmanaged", so the old assert.Contains checks would still pass even if both rows rendered as unmanaged. Now asserts full rendered lines. Found via CodeRabbit review. Several other findings from the same pass were verified against current code and are false positives (not fixed): the --affected/--all doc examples correctly omit --stack per this codebase's bulk-selection convention; `plan` is a genuinely registered alias for `diff`; `list`'s empty --stack behavior matches every other describe-stacks command's "no filter = all stacks" convention; the NextToken-nil pagination check matches every other pagination loop in this package and the AWS SDK's documented contract; and yaml_func_aws.go's discarded second return value from resolveNestedOutputAuth is the resolved auth manager, not an error — the function has no error return at all. Co-Authored-By: Claude Sonnet 5 --- errors/errors.go | 1 + pkg/aws/cloudformation/outputs.go | 4 ++-- pkg/aws/cloudformation/outputs_test.go | 4 ++-- .../aws/cloudformation/changeset_verbs.go | 2 +- .../aws/cloudformation/cloudformation.go | 13 ++++++++----- .../aws/cloudformation/cloudformation_test.go | 19 +++++++++++++++---- pkg/component/aws/cloudformation/list_test.go | 10 ++++++---- 7 files changed, 35 insertions(+), 18 deletions(-) diff --git a/errors/errors.go b/errors/errors.go index 9c8374e6ca4..380ccbbbf4e 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -1629,6 +1629,7 @@ var ( ErrAwsCloudFormationIdentityResolutionFailed = errors.New("aws/cloudformation component requested an identity, but the auth manager could not resolve it") ErrAwsCloudFormationAPICallFailed = errors.New("aws/cloudformation API call failed") ErrAwsCloudFormationFmtNotClean = errors.New("aws/cloudformation template is not formatted") + ErrAwsCloudFormationStackNotFound = errors.New("aws/cloudformation stack not found") ) // Stack dependency (`depends_on`) resolution errors. diff --git a/pkg/aws/cloudformation/outputs.go b/pkg/aws/cloudformation/outputs.go index 4a37fe4d1f8..69db2d77e80 100644 --- a/pkg/aws/cloudformation/outputs.go +++ b/pkg/aws/cloudformation/outputs.go @@ -68,10 +68,10 @@ func GetOutputs(ctx context.Context, region, stackName string, authContext *sche client := newCloudFormationClient(awsCfg, endpointURL) out, err := client.DescribeStacks(ctx, &cloudformation.DescribeStacksInput{StackName: aws.String(stackName)}) if err != nil { - return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationChangeSetFailed, err) + return nil, fmt.Errorf("%w: %w", errUtils.ErrAwsCloudFormationAPICallFailed, err) } if len(out.Stacks) == 0 { - return nil, fmt.Errorf("%w: stack %q", errUtils.ErrAwsCloudFormationChangeSetFailed, stackName) + return nil, fmt.Errorf("%w: stack %q", errUtils.ErrAwsCloudFormationStackNotFound, stackName) } outputs := make(map[string]any, len(out.Stacks[0].Outputs)) diff --git a/pkg/aws/cloudformation/outputs_test.go b/pkg/aws/cloudformation/outputs_test.go index 898360d6e91..1b3d6791df7 100644 --- a/pkg/aws/cloudformation/outputs_test.go +++ b/pkg/aws/cloudformation/outputs_test.go @@ -102,7 +102,7 @@ func TestGetOutputs_StackNotFound(t *testing.T) { _, err := GetOutputs(context.Background(), "us-east-1", "missing-stack", nil) require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationStackNotFound) assert.Contains(t, err.Error(), "missing-stack") } @@ -118,7 +118,7 @@ func TestGetOutputs_APIError(t *testing.T) { _, err := GetOutputs(context.Background(), "us-east-1", "vpc", nil) require.Error(t, err) - assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationChangeSetFailed) + assert.ErrorIs(t, err, errUtils.ErrAwsCloudFormationAPICallFailed) assert.ErrorIs(t, err, sentinel) } diff --git a/pkg/component/aws/cloudformation/changeset_verbs.go b/pkg/component/aws/cloudformation/changeset_verbs.go index f0819b9e109..cc86e7ec2a0 100644 --- a/pkg/component/aws/cloudformation/changeset_verbs.go +++ b/pkg/component/aws/cloudformation/changeset_verbs.go @@ -122,7 +122,7 @@ func runChangesetExecute(ctx context.Context, client CloudFormationClient, spec } // runChangesetList lists a stack's changesets, newest first (ListChangeSets' -// own ordering), rendering each one's name, status, and creation time. +// own ordering), rendering each one's name, status, and description. func runChangesetList(ctx context.Context, client CloudFormationClient, spec *stackSpec, summary map[string]any) (map[string]any, error) { summaries, err := listChangeSets(ctx, client, spec.StackName) if err != nil { diff --git a/pkg/component/aws/cloudformation/cloudformation.go b/pkg/component/aws/cloudformation/cloudformation.go index 64cf7e4aa4c..8b3b6a7d933 100644 --- a/pkg/component/aws/cloudformation/cloudformation.go +++ b/pkg/component/aws/cloudformation/cloudformation.go @@ -125,12 +125,15 @@ func (p *ComponentProvider) GenerateArtifacts(_ *component.ExecutionContext) err return nil } -// GetAvailableCommands returns the subcommands aws/cloudformation components support. +// GetAvailableCommands returns the subcommands aws/cloudformation components +// support, derived from subCommandOperations so this list can never drift out +// of sync with what Execute actually dispatches. func (p *ComponentProvider) GetAvailableCommands() []string { defer perf.Track(nil, "cloudformation.GetAvailableCommands")() - return []string{ - "render", "diff", "plan", "apply", "deploy", "delete", "validate", "output", - "changeset-create", "changeset-execute", "changeset-list", "changeset-delete", - "drift-detect", "drift-describe", "get-template", "get-policy", + commands := make([]string, 0, len(subCommandOperations)) + for name := range subCommandOperations { + commands = append(commands, name) } + sort.Strings(commands) + return commands } diff --git a/pkg/component/aws/cloudformation/cloudformation_test.go b/pkg/component/aws/cloudformation/cloudformation_test.go index 0c24f8e53ca..9ea0b432a37 100644 --- a/pkg/component/aws/cloudformation/cloudformation_test.go +++ b/pkg/component/aws/cloudformation/cloudformation_test.go @@ -2,6 +2,7 @@ package cloudformation import ( "context" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -67,13 +68,23 @@ func TestComponentProvider_ValidateComponent(t *testing.T) { require.NoError(t, p.ValidateComponent(map[string]any{"template": "t.yaml", "stack_name": "vpc"})) } +// GetAvailableCommands must stay in sync with subCommandOperations — every +// dispatchable subcommand (including aliases like "destroy"/"outputs") must be +// reported, so callers like pkg/composition's verb-allowlist check don't +// reject a subcommand Execute actually supports. func TestComponentProvider_GetAvailableCommands(t *testing.T) { p := &ComponentProvider{} commands := p.GetAvailableCommands() - assert.Contains(t, commands, "apply") - assert.Contains(t, commands, "delete") - assert.Contains(t, commands, "output") - assert.Contains(t, commands, "validate") + + want := make([]string, 0, len(subCommandOperations)) + for name := range subCommandOperations { + want = append(want, name) + } + sort.Strings(want) + assert.Equal(t, want, commands) + assert.Contains(t, commands, "destroy") + assert.Contains(t, commands, "outputs") + assert.Contains(t, commands, "fmt") } func TestComponentProvider_GenerateArtifacts_NoOp(t *testing.T) { diff --git a/pkg/component/aws/cloudformation/list_test.go b/pkg/component/aws/cloudformation/list_test.go index bd35900c787..330293fe9f3 100644 --- a/pkg/component/aws/cloudformation/list_test.go +++ b/pkg/component/aws/cloudformation/list_test.go @@ -3,6 +3,7 @@ package cloudformation import ( "context" "errors" + "fmt" "net/http" "net/http/httptest" "testing" @@ -172,8 +173,9 @@ func TestRenderDeployedStacksList_Populated(t *testing.T) { out := captureStdout(t, func() { RenderDeployedStacksList(stacks) }) - assert.Contains(t, out, "managed") - assert.Contains(t, out, "vpc") - assert.Contains(t, out, "unmanaged") - assert.Contains(t, out, "orphaned-stack") + // "managed" is a substring of "unmanaged", so assert full rendered lines + // (not bare substrings) to actually distinguish the two rows, rather than + // a check that would still pass if vpc's row were also marked unmanaged. + assert.Contains(t, out, fmt.Sprintf("%-9s %-30s %s", "managed", "CREATE_COMPLETE", "vpc")) + assert.Contains(t, out, fmt.Sprintf("%-9s %-30s %s", "unmanaged", "UPDATE_COMPLETE", "orphaned-stack")) } From 430dd8730b0ec25e57289374be15eda681f11a08 Mon Sep 17 00:00:00 2001 From: Erik Osterman Date: Thu, 27 Aug 2026 13:08:06 -0500 Subject: [PATCH 10/10] fix(cloudformation): record screengrab casts for Phase 2 verbs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This branch's own docs (changeset/drift/fmt/get/list/source, 18 verbs) referenced screengrab casts that were never recorded, and cli.yaml's command manifest never listed them — the same gap fixed cumulatively on the top of the stack, but each PR in this stack is validated against its own branch tip, not the final merged result, so this layer needs its own fix. Also recorded the original 8 top-level verbs' casts (render/plan/ diff/apply/deploy/delete/validate/output) plus --help, which had never been committed at all on this branch either. atmos --chdir=demo/casts casts generate screengrabs cli --filter=cloudformation Co-Authored-By: Claude Sonnet 5 --- demo/casts/atmos.d/screengrabs/cli.yaml | 36 +++ .../atmos-aws-cloudformation--help.cast | 295 ++++++++++++++++++ .../atmos-aws-cloudformation-apply--help.cast | 121 +++++++ ...os-aws-cloudformation-changeset--help.cast | 40 +++ ...cloudformation-changeset-create--help.cast | 107 +++++++ ...cloudformation-changeset-delete--help.cast | 114 +++++++ ...loudformation-changeset-execute--help.cast | 119 +++++++ ...s-cloudformation-changeset-list--help.cast | 107 +++++++ ...atmos-aws-cloudformation-delete--help.cast | 129 ++++++++ ...atmos-aws-cloudformation-deploy--help.cast | 121 +++++++ .../atmos-aws-cloudformation-diff--help.cast | 107 +++++++ .../atmos-aws-cloudformation-drift--help.cast | 32 ++ ...s-cloudformation-drift-describe--help.cast | 107 +++++++ ...aws-cloudformation-drift-detect--help.cast | 112 +++++++ .../atmos-aws-cloudformation-fmt--help.cast | 113 +++++++ .../atmos-aws-cloudformation-get--help.cast | 32 ++ ...s-aws-cloudformation-get-policy--help.cast | 107 +++++++ ...aws-cloudformation-get-template--help.cast | 113 +++++++ .../atmos-aws-cloudformation-list--help.cast | 55 ++++ ...atmos-aws-cloudformation-output--help.cast | 130 ++++++++ .../atmos-aws-cloudformation-plan--help.cast | 107 +++++++ ...atmos-aws-cloudformation-render--help.cast | 107 +++++++ ...atmos-aws-cloudformation-source--help.cast | 40 +++ ...ws-cloudformation-source-delete--help.cast | 36 +++ ...-cloudformation-source-describe--help.cast | 31 ++ ...-aws-cloudformation-source-list--help.cast | 38 +++ ...-aws-cloudformation-source-pull--help.cast | 44 +++ ...mos-aws-cloudformation-validate--help.cast | 107 +++++++ 28 files changed, 2607 insertions(+) create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-apply--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-changeset--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-create--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-delete--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-execute--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-list--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-delete--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-deploy--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-diff--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-drift--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-drift-describe--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-drift-detect--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-fmt--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-get--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-get-policy--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-get-template--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-list--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-output--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-plan--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-render--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-source--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-source-delete--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-source-describe--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-source-list--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-source-pull--help.cast create mode 100644 website/static/casts/screengrabs/atmos-aws-cloudformation-validate--help.cast diff --git a/demo/casts/atmos.d/screengrabs/cli.yaml b/demo/casts/atmos.d/screengrabs/cli.yaml index a63b316a904..c76c53c49f0 100644 --- a/demo/casts/atmos.d/screengrabs/cli.yaml +++ b/demo/casts/atmos.d/screengrabs/cli.yaml @@ -104,6 +104,24 @@ commands: atmos aws cloudformation delete --help atmos aws cloudformation validate --help atmos aws cloudformation output --help + atmos aws cloudformation changeset --help + atmos aws cloudformation changeset create --help + atmos aws cloudformation changeset delete --help + atmos aws cloudformation changeset execute --help + atmos aws cloudformation changeset list --help + atmos aws cloudformation drift --help + atmos aws cloudformation drift describe --help + atmos aws cloudformation drift detect --help + atmos aws cloudformation fmt --help + atmos aws cloudformation get --help + atmos aws cloudformation get policy --help + atmos aws cloudformation get template --help + atmos aws cloudformation list --help + atmos aws cloudformation source --help + atmos aws cloudformation source delete --help + atmos aws cloudformation source describe --help + atmos aws cloudformation source list --help + atmos aws cloudformation source pull --help atmos completion --help atmos describe --help atmos describe affected --help @@ -515,6 +533,24 @@ commands: atmos aws cloudformation delete --help atmos aws cloudformation validate --help atmos aws cloudformation output --help + atmos aws cloudformation changeset --help + atmos aws cloudformation changeset create --help + atmos aws cloudformation changeset delete --help + atmos aws cloudformation changeset execute --help + atmos aws cloudformation changeset list --help + atmos aws cloudformation drift --help + atmos aws cloudformation drift describe --help + atmos aws cloudformation drift detect --help + atmos aws cloudformation fmt --help + atmos aws cloudformation get --help + atmos aws cloudformation get policy --help + atmos aws cloudformation get template --help + atmos aws cloudformation list --help + atmos aws cloudformation source --help + atmos aws cloudformation source delete --help + atmos aws cloudformation source describe --help + atmos aws cloudformation source list --help + atmos aws cloudformation source pull --help atmos completion --help atmos describe --help atmos describe affected --help diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation--help.cast new file mode 100644 index 00000000000..5e176aa0903 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation--help.cast @@ -0,0 +1,295 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853921,"command":"aws cloudformation --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.209135042,"o","\n"] +[0.000172833,"o","\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\n\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\n\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\n\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\n\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\n\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\n\n"] +[0.00015075,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.00000175,"o","\n"] +[0.000019292,"o","\u001b[48;2;236;201;75m \u001b[0m\u001b[1;38;2;26;32;44;48;2;236;201;75mEXPERIMENTAL\u001b[0m\u001b[48;2;236;201;75m \u001b[0m\n"] +[0.000001167,"o","\n"] +[0.001897166,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mDeploy, inspect, and delete native aws/cloudformation stacks using the AWS SDK for Go\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mv2. No external binary\u001b[0m\u001b[38;2;247;250;252m dependency.\u001b[0m\n"] +[0.00001375,"o","\n"] +[0.000006292,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000090458,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[sub-command]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000003084,"o","\n"] +[0.000003541,"o","\u001b[1;38;2;0;163;224mALIASES\u001b[0m\n"] +[9.17e-7,"o","\n"] +[0.000003458,"o"," \u001b[38;2;73;85;104mcloudformation, cfn\u001b[0m\n"] +[8.34e-7,"o","\n"] +[0.000003583,"o","\u001b[1;38;2;0;163;224mSUBCOMMAND ALIASES\u001b[0m\n"] +[8.75e-7,"o","\n"] +[0.001715625,"o"," \u001b[1;38;2;0;163;224moutputs \u001b[0m \u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mAlias of \u001b[0m\u001b[38;2;0;255;255;1mcloudformation output\u001b[0m\u001b[38;2;247;250;252m command\u001b[0m\n"] +[0.000001917,"o","\n"] +[0.000111708,"o","\u001b[1;38;2;0;163;224mBUILT-IN COMMANDS\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.00000125,"o"," "] +[0.000002708,"o","\u001b[1;38;2;0;163;224mapply\u001b[0m"] +[0.000002459,"o"," "] +[0.000942333,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mCreate or update the\u001b[0m\u001b[38;2;255;255;255m stack\u001b[0m\u001b[0m\n"] +[0.000020083,"o"," "] +[0.000048667,"o","\u001b[1;38;2;0;163;224mchangeset\u001b[0m"] +[0.00000425,"o"," \u001b[38;2;73;85;104m[command]\u001b[0m"] +[0.000002083,"o"," "] +[0.000280584,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mManage aws/cloudformation changesets\u001b[0m\u001b[38;2;255;255;255m directly\u001b[0m\u001b[0m\n"] +[0.000007583,"o"," "] +[0.000005583,"o","\u001b[1;38;2;0;163;224mdelete\u001b[0m"] +[0.000004667,"o"," "] +[0.000340417,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mDelete the\u001b[0m\u001b[38;2;255;255;255m stack\u001b[0m\u001b[0m\n"] +[0.000008208,"o"," "] +[0.000008083,"o","\u001b[1;38;2;0;163;224mdeploy\u001b[0m"] +[0.000002334,"o"," "] +[0.000153,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mApply with\u001b[0m\u001b[38;2;255;255;255m --auto-approve\u001b[0m\u001b[0m\n"] +[0.000002875,"o"," "] +[0.000002833,"o","\u001b[1;38;2;0;163;224mdiff\u001b[0m"] +[0.000001708,"o"," "] +[0.000111334,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mShow changes an apply would\u001b[0m\u001b[38;2;255;255;255m make\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," "] +[0.000002875,"o","\u001b[1;38;2;0;163;224mdrift\u001b[0m"] +[0.000001416,"o"," \u001b[38;2;73;85;104m[command]\u001b[0m"] +[0.000173834,"o"," "] +[0.000099791,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mDetect and describe drift against a deployed\u001b[0m\u001b[38;2;255;255;255m stack\u001b[0m\u001b[0m\n"] +[0.000001959,"o"," "] +[0.000002791,"o","\u001b[1;38;2;0;163;224mfmt\u001b[0m"] +[0.000001459,"o"," "] +[0.000119375,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFormat the local template in place (or check formatting with\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000003666,"o"," \u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcheck)\u001b[0m\u001b[0m\n"] +[0.000003125,"o"," "] +[0.000002709,"o","\u001b[1;38;2;0;163;224mget\u001b[0m"] +[0.000001333,"o"," \u001b[38;2;73;85;104m[command]\u001b[0m"] +[0.0000015,"o"," "] +[0.000124708,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFetch a deployed stack's template or\u001b[0m\u001b[38;2;255;255;255m policy\u001b[0m\u001b[0m\n"] +[0.000001459,"o"," "] +[0.000003041,"o","\u001b[1;38;2;0;163;224mlist\u001b[0m"] +[0.000001584,"o"," "] +[0.000105166,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mList deployed CloudFormation stacks in the\u001b[0m\u001b[38;2;255;255;255m account\u001b[0m\u001b[0m\n"] +[0.000001459,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224moutput\u001b[0m"] +[0.000001875,"o"," "] +[0.000127333,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mShow the deployed stack's\u001b[0m\u001b[38;2;255;255;255m Outputs\u001b[0m\u001b[0m\n"] +[0.000001542,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224mplan\u001b[0m"] +[0.0000015,"o"," "] +[0.000106541,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPreview changes an apply would\u001b[0m\u001b[38;2;255;255;255m make\u001b[0m\u001b[0m\n"] +[0.000001417,"o"," "] +[0.000002792,"o","\u001b[1;38;2;0;163;224mrender\u001b[0m"] +[0.000001708,"o"," "] +[0.000106667,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mRender the local template client-side (no API\u001b[0m\u001b[38;2;255;255;255m calls)\u001b[0m\u001b[0m\n"] +[0.000002875,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224msource\u001b[0m"] +[0.000001583,"o"," \u001b[38;2;73;85;104m[command]\u001b[0m"] +[0.000001292,"o"," "] +[0.0001045,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mManage aws/cloudformation component sources (JIT\u001b[0m\u001b[38;2;255;255;255m vendoring)\u001b[0m\u001b[0m\n"] +[0.000001375,"o"," "] +[0.000002791,"o","\u001b[1;38;2;0;163;224mvalidate\u001b[0m"] +[0.000001709,"o"," "] +[0.000101875,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mValidate the template\u001b[0m\u001b[38;2;255;255;255m server-side\u001b[0m\u001b[0m\n"] +[0.000007583,"o","\n"] +[0.000017792,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000096833,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --ai\u001b[0m"] +[0.000001667,"o"," "] +[0.000099333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mEnable AI-powered analysis of command\u001b[0m\u001b[38;2;255;255;255m output\u001b[0m\u001b[0m\n"] +[0.000013875,"o","\n"] +[0.000001292,"o"," "] +[0.00000375,"o","\u001b[1;38;2;0;163;224m --base-path\u001b[0m"] +[0.000001208,"o"," "] +[0.000002458,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001084,"o"," "] +[0.000101916,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mBase path for Atmos\u001b[0m\u001b[38;2;255;255;255m project\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001084,"o"," "] +[0.000002958,"o","\u001b[1;38;2;0;163;224m --cast\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002959,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001041,"o"," "] +[0.000123334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mRecord command output as an asciinema\u001b[0m\u001b[38;2;255;255;255m cast\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.000001125,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m-C, --chdir\u001b[0m"] +[8.75e-7,"o"," "] +[0.000002417,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.58e-7,"o"," "] +[0.00010075,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mChange working directory before\u001b[0m\u001b[38;2;255;255;255m processing\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.000001042,"o"," "] +[0.000003417,"o","\u001b[1;38;2;0;163;224m --config\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002583,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001,"o"," "] +[0.00011275,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPaths to configuration files \u001b[0m\u001b[38;2;255;255;255m(comma-\u001b[0m\u001b[0m\n"] +[0.000003959,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mseparated or repeated\u001b[0m\u001b[38;2;255;255;255m flag)\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001125,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --config-path\u001b[0m"] +[7.92e-7,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001125,"o"," "] +[0.000114083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPaths to configuration directories \u001b[0m\u001b[38;2;255;255;255m(comma-\u001b[0m\u001b[0m\n"] +[0.000005,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mseparated or repeated\u001b[0m\u001b[38;2;255;255;255m flag)\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.00000125,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --dry-run\u001b[0m"] +[0.000001333,"o"," "] +[0.00010675,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPerform dry run without making\u001b[0m\u001b[38;2;255;255;255m actual\u001b[0m\u001b[0m\n"] +[0.000007792,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mchanges\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001125,"o"," "] +[0.000003334,"o","\u001b[1;38;2;0;163;224m --edition\u001b[0m"] +[7.91e-7,"o"," "] +[0.000010959,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000105666,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPin defaults to a date-anchored\u001b[0m\u001b[38;2;255;255;255m edition\u001b[0m\u001b[0m\n"] +[0.000003584,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255m(YYYY, YYYY-MM, or\u001b[0m\u001b[38;2;255;255;255m YYYY-MM-DD)\u001b[0m\u001b[0m\n"] +[0.000001541,"o","\n"] +[0.000001209,"o"," "] +[0.000002833,"o","\u001b[1;38;2;0;163;224m --force-color\u001b[0m"] +[0.000001042,"o"," "] +[0.000119208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mForce color output even when not a\u001b[0m\u001b[38;2;255;255;255m TTY\u001b[0m\u001b[0m\n"] +[0.000003958,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255m(useful for\u001b[0m\u001b[38;2;255;255;255m screenshots)\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001167,"o"," "] +[0.000002625,"o","\u001b[1;38;2;0;163;224m --force-tty\u001b[0m"] +[0.000001083,"o"," "] +[0.000151542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mForce TTY mode with sane\u001b[0m\u001b[38;2;255;255;255m defaults\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255m(width=120, height=40) when\u001b[0m\u001b[38;2;255;255;255m terminal\u001b[0m\u001b[0m\n"] +[0.000003708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection\u001b[0m\u001b[38;2;255;255;255m fails\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000001416,"o"," "] +[0.000002584,"o","\u001b[1;38;2;0;163;224m --heatmap\u001b[0m"] +[0.000001208,"o"," "] +[0.000096875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mShow performance heatmap\u001b[0m\u001b[38;2;255;255;255m visualization\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001042,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --heatmap-mode\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000114167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mHeatmap visualization mode (bar,\u001b[0m\u001b[38;2;255;255;255m sparkline,\u001b[0m\u001b[0m\n"] +[0.000004166,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtable) (default \u001b[0m\u001b[38;2;155;81;224;1mbar\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[9.59e-7,"o","\n"] +[0.000001291,"o"," "] +[0.000002584,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001166,"o"," "] +[0.000093875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m cloudformation\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000008125,"o"," "] +[0.000002833,"o","\u001b[1;38;2;0;163;224m-i, --identity\u001b[0m"] +[8.75e-7,"o"," "] +[0.000003084,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000107,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mIdentity to use for authentication \u001b[0m\u001b[38;2;255;255;255m(use\u001b[0m\u001b[0m\n"] +[0.000007042,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mwithout value to select\u001b[0m\u001b[38;2;255;255;255m interactively)\u001b[0m\u001b[0m\n"] +[0.000001041,"o","\n"] +[0.000001084,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --logs-file\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002208,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000105292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFile to write logs to \u001b[0m\u001b[38;2;255;255;255m(default\u001b[0m\u001b[0m\n"] +[0.000003916,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;155;81;224;1m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;155;81;224;1m/dev/stderr\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000001291,"o"," "] +[0.0000025,"o","\u001b[1;38;2;0;163;224m --logs-level\u001b[0m"] +[9.59e-7,"o"," "] +[0.000002833,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001,"o"," "] +[0.000112458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mLogs level (Trace, Debug, Info,\u001b[0m\u001b[38;2;255;255;255m Warning,\u001b[0m\u001b[0m\n"] +[0.000003917,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mOff) (default \u001b[0m\u001b[38;2;155;81;224;1mInfo\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.00000125,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m --mask\u001b[0m"] +[0.000001042,"o"," "] +[0.000109083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mEnable automatic masking of secrets\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255moutput (default \u001b[0m\u001b[38;2;155;81;224;1mtrue\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000001042,"o"," "] +[0.000002458,"o","\u001b[1;38;2;0;163;224m --no-color\u001b[0m"] +[0.000001125,"o"," "] +[0.000096042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mDisable color\u001b[0m\u001b[38;2;255;255;255m output\u001b[0m\u001b[0m\n"] +[0.000001166,"o","\n"] +[0.000001,"o"," "] +[0.000003334,"o","\u001b[1;38;2;0;163;224m --pager\u001b[0m"] +[7.91e-7,"o"," "] +[0.000002209,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001,"o"," "] +[0.000094833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mEnable pager for\u001b[0m\u001b[38;2;255;255;255m output\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001083,"o"," "] +[0.000002584,"o","\u001b[1;38;2;0;163;224m --profile\u001b[0m"] +[0.000007166,"o"," "] +[0.000002792,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001083,"o"," "] +[0.0001065,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mActivate configuration profiles \u001b[0m\u001b[38;2;255;255;255m(comma-\u001b[0m\u001b[0m\n"] +[0.000003917,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mseparated or repeated\u001b[0m\u001b[38;2;255;255;255m flag)\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000001208,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --profile-file\u001b[0m"] +[7.92e-7,"o"," "] +[0.00005025,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001417,"o"," "] +[0.000103541,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mWrite profiling data to\u001b[0m\u001b[38;2;255;255;255m file\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001125,"o"," "] +[0.000002834,"o","\u001b[1;38;2;0;163;224m --profile-type\u001b[0m"] +[9.16e-7,"o"," "] +[0.00000225,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001375,"o"," "] +[0.000116542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mType of profile to collect (cpu,\u001b[0m\u001b[38;2;255;255;255m heap,\u001b[0m\u001b[0m\n"] +[0.000004042,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mallocs, goroutine, block,\u001b[0m\u001b[38;2;255;255;255m mutex,\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthreadcreate, trace) (default \u001b[0m\u001b[38;2;155;81;224;1mcpu\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000001,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --profiler-enabled\u001b[0m"] +[0.000001208,"o"," "] +[0.000097458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mEnable pprof profiling\u001b[0m\u001b[38;2;255;255;255m server\u001b[0m\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000001083,"o"," "] +[0.000003458,"o","\u001b[1;38;2;0;163;224m --profiler-host\u001b[0m"] +[9.59e-7,"o"," "] +[0.000002416,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.59e-7,"o"," "] +[0.000117,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mHost for pprof profiling server \u001b[0m\u001b[38;2;255;255;255m(default\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;155;81;224;1m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;155;81;224;1mlocalhost\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000001042,"o"," "] +[0.000002916,"o","\u001b[1;38;2;0;163;224m --profiler-port\u001b[0m"] +[7.92e-7,"o"," "] +[0.000002458,"o","\u001b[38;2;73;85;104mint\u001b[0m"] +[9.17e-7,"o"," "] +[0.000105875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPort for pprof profiling server \u001b[0m\u001b[38;2;255;255;255m(default\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;155;81;224;1m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;155;81;224;1m6060\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000006417,"o","\n"] +[0.000001166,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --redirect-stderr\u001b[0m"] +[7.92e-7,"o"," "] +[0.000002458,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001,"o"," "] +[0.000095584,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mRedirect stderr to\u001b[0m\u001b[38;2;255;255;255m file\u001b[0m\u001b[0m\n"] +[0.000001166,"o","\n"] +[0.000001042,"o"," "] +[0.000003958,"o","\u001b[1;38;2;0;163;224m --settings-list-merge-strategy\u001b[0m"] +[8.75e-7,"o"," "] +[0.000003125,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.75e-7,"o"," "] +[0.000116792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mOverride settings.list_\u001b[0m\u001b[38;2;255;255;255mmerge_\u001b[0m\u001b[38;2;255;255;255mstrategy\u001b[0m\u001b[38;2;255;255;255m for\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthis invocation (replace, append,\u001b[0m\u001b[38;2;255;255;255m merge)\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.000001125,"o"," "] +[0.000002709,"o","\u001b[1;38;2;0;163;224m --skill\u001b[0m"] +[8.75e-7,"o"," "] +[0.000002291,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001459,"o"," "] +[0.000110666,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mSpecify skills for AI analysis\u001b[0m\u001b[38;2;255;255;255m context\u001b[0m\u001b[0m\n"] +[0.000008,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255m(comma-separated or repeated flag, requires\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.00000325,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mai)\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000002042,"o"," "] +[0.0000025,"o","\u001b[1;38;2;0;163;224m-s, --stack\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002459,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.58e-7,"o"," "] +[0.000092125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mStack\u001b[0m\u001b[38;2;255;255;255m name\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[8.75e-7,"o","\n"] +[0.001673041,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1matmos cloudformation [command] --help\u001b[0m\u001b[38;2;247;250;252m for more information about a\u001b[0m\u001b[38;2;247;250;252m command.\u001b[0m\u001b[0m\n"] +[0.001640334,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-apply--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-apply--help.cast new file mode 100644 index 00000000000..3c387b1af55 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-apply--help.cast @@ -0,0 +1,121 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853925,"command":"aws cloudformation apply --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.198179417,"o","\n"] +[0.00016525,"o","\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\n\n"] +[0.000082166,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002209,"o","\n"] +[0.002859791,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mCreate or update the\u001b[0m\u001b[38;2;247;250;252m stack\u001b[0m\n"] +[0.00000975,"o","\n"] +[0.000034542,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000005375,"o","\n"] +[0.000224042,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mapply\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000035125,"o","\n"] +[0.0000205,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000147791,"o"," "] +[0.000007875,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.00000175,"o"," "] +[0.000151792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000005083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.00000175,"o","\n"] +[0.000001459,"o"," "] +[0.000003166,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001334,"o"," "] +[0.000124208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004458,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001334,"o"," "] +[0.000003791,"o","\u001b[1;38;2;0;163;224m --auto-approve\u001b[0m"] +[0.000001459,"o"," "] +[0.0001115,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mSkip interactive\u001b[0m\u001b[38;2;255;255;255m confirmation.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001083,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.00000125,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000104875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.0000035,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000001042,"o"," "] +[0.000003708,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001334,"o"," "] +[0.000187291,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000006084,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000025333,"o","\n"] +[0.00000175,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001042,"o"," "] +[0.000140583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m apply\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001,"o"," "] +[0.000002667,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001208,"o"," "] +[0.000111458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003334,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001125,"o"," "] +[0.000002541,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001625,"o"," "] +[0.000003334,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.58e-7,"o"," "] +[0.000120208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000003542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[8.33e-7,"o","\n"] +[0.000001375,"o"," "] +[0.000002125,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[7.09e-7,"o"," "] +[0.000002708,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001458,"o"," "] +[0.000092667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[8.34e-7,"o"," "] +[0.000002541,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[6.67e-7,"o"," "] +[0.000002417,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001583,"o"," "] +[0.000095,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000003542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[7.91e-7,"o"," "] +[0.000002334,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001208,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.75e-7,"o"," "] +[0.000099208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[8.33e-7,"o"," "] +[0.000002209,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[6.66e-7,"o"," "] +[0.000002125,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000010084,"o"," "] +[0.000095625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004416,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000001208,"o"," "] +[0.000003292,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001041,"o"," "] +[0.000002792,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000105959,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000003625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001958,"o"," "] +[0.000002542,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001166,"o"," "] +[0.000100959,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004208,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.000014917,"o"," "] +[0.000011542,"o","\u001b[1;38;2;0;163;224m --target\u001b[0m"] +[0.000001958,"o"," "] +[0.00000525,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001667,"o"," "] +[0.000162166,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProvision target to deliver to. Defaults\u001b[0m\u001b[38;2;255;255;255m to\u001b[0m\u001b[0m\n"] +[0.000005459,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mprovision.default, otherwise the implicit\u001b[0m\u001b[38;2;255;255;255m direct-deploy\u001b[0m\u001b[0m\n"] +[0.000004791,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001209,"o","\n"] +[0.001623833,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset--help.cast new file mode 100644 index 00000000000..51266b4c237 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset--help.cast @@ -0,0 +1,40 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853931,"command":"aws cloudformation changeset --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.209557792,"o","\n"] +[0.000132541,"o","\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m \u001b[0m\n\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\n\n"] +[0.000067125,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001875,"o","\n"] +[0.001663167,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mManage aws/cloudformation changesets\u001b[0m\u001b[38;2;247;250;252m directly\u001b[0m\n"] +[0.000001875,"o","\n"] +[0.000004125,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000068667,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mchangeset\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mchangeset\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[sub-command]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.00001475,"o","\n"] +[0.000118458,"o","\u001b[1;38;2;0;163;224mBUILT-IN COMMANDS\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.0000015,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224mcreate\u001b[0m"] +[0.000002208,"o"," "] +[0.000127625,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mCreate a changeset and leave it for later\u001b[0m\u001b[38;2;255;255;255m review/execution\u001b[0m\u001b[0m\n"] +[0.000002292,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224mdelete\u001b[0m"] +[0.000001833,"o"," "] +[0.000114959,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mDelete a named\u001b[0m\u001b[38;2;255;255;255m changeset\u001b[0m\u001b[0m\n"] +[0.000001791,"o"," "] +[0.000003084,"o","\u001b[1;38;2;0;163;224mexecute\u001b[0m"] +[0.000002208,"o"," "] +[0.000114542,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mExecute a previously-created, named\u001b[0m\u001b[38;2;255;255;255m changeset\u001b[0m\u001b[0m\n"] +[0.000001541,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224mlist\u001b[0m"] +[0.000007375,"o"," "] +[0.000101667,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mList a stack's\u001b[0m\u001b[38;2;255;255;255m changesets\u001b[0m\u001b[0m\n"] +[0.000001792,"o","\n"] +[0.000011458,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000101542,"o"," "] +[0.000003417,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001291,"o"," "] +[0.000149417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m changeset\u001b[0m\u001b[0m\n"] +[0.000003542,"o","\n"] +[0.000001708,"o","\n"] +[0.001691417,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1matmos cloudformation changeset [command] --help\u001b[0m\u001b[38;2;247;250;252m for more information about a\u001b[0m\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mcommand.\u001b[0m\u001b[0m \n"] +[0.001659375,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-create--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-create--help.cast new file mode 100644 index 00000000000..1e92a901d0a --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-create--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853932,"command":"aws cloudformation changeset create --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.195869458,"o","\n"] +[0.000354292,"o","\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\n\n"] +[0.000233625,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000010666,"o","\n"] +[0.002385834,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mCreate a changeset and leave it for later\u001b[0m\u001b[38;2;247;250;252m review/execution\u001b[0m\n"] +[0.00000475,"o","\n"] +[0.000004583,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000057958,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mchangeset\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcreate\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000035709,"o","\n"] +[0.000015208,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000112708,"o"," "] +[0.000005042,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001875,"o"," "] +[0.000138833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001166,"o"," "] +[0.000002709,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001083,"o"," "] +[0.000130833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.000001417,"o"," "] +[0.000003917,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001166,"o"," "] +[0.000003125,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001375,"o"," "] +[0.000116667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003792,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001125,"o"," "] +[0.000002958,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001292,"o"," "] +[0.000122708,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001125,"o"," "] +[0.000002542,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001041,"o"," "] +[0.000106167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m create\u001b[0m\u001b[0m\n"] +[0.000015583,"o","\n"] +[0.0000015,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001375,"o"," "] +[0.0001195,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001209,"o","\n"] +[0.00000125,"o"," "] +[0.000002666,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[9.59e-7,"o"," "] +[0.000003083,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001167,"o"," "] +[0.000135125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000003916,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004042,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001041,"o"," "] +[0.0000025,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[9.59e-7,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001541,"o"," "] +[0.000110542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001083,"o"," "] +[0.000002667,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002458,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001209,"o"," "] +[0.00011,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001041,"o"," "] +[0.000002417,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[7.92e-7,"o"," "] +[0.000002416,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000107,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001042,"o"," "] +[0.000002583,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002334,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.58e-7,"o"," "] +[0.000104833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000015084,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001125,"o"," "] +[0.000002833,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[8.75e-7,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.75e-7,"o"," "] +[0.00011275,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000003833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001084,"o"," "] +[0.000002541,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[7.92e-7,"o"," "] +[0.0000025,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.00000125,"o"," "] +[0.000107292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000003458,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[9.58e-7,"o","\n"] +[0.001635375,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-delete--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-delete--help.cast new file mode 100644 index 00000000000..431e82e37e7 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-delete--help.cast @@ -0,0 +1,114 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853933,"command":"aws cloudformation changeset delete --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.198520167,"o","\n"] +[0.000152583,"o","\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\n\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\n\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\n\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\n\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m \u001b[0m\n\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\n\n"] +[0.000063333,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001834,"o","\n"] +[0.001822625,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mDelete a named\u001b[0m\u001b[38;2;247;250;252m changeset\u001b[0m\n"] +[0.000002583,"o","\n"] +[0.000004333,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001209,"o","\n"] +[0.000064833,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mchangeset\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdelete\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000018333,"o","\n"] +[0.00001925,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000114042,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001208,"o"," "] +[0.000148125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001209,"o","\n"] +[0.000001208,"o"," "] +[0.000002583,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.00000125,"o"," "] +[0.000134959,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.00000425,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001583,"o"," "] +[0.000005,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001208,"o"," "] +[0.000002834,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.00012625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001125,"o"," "] +[0.000002708,"o","\u001b[1;38;2;0;163;224m --changeset-name\u001b[0m"] +[0.000001,"o"," "] +[0.000002292,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000115,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mName of the changeset to\u001b[0m\u001b[38;2;255;255;255m delete.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001042,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001291,"o"," "] +[0.000121959,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.00000525,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000013083,"o","\n"] +[0.000001542,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001291,"o"," "] +[0.000137209,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m delete\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001333,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001375,"o"," "] +[0.000133417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.00000425,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001375,"o"," "] +[0.000002625,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[8.75e-7,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001291,"o"," "] +[0.000132667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000003792,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001292,"o"," "] +[0.000003083,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[0.000001125,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.0000015,"o"," "] +[0.000117542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001,"o"," "] +[0.000003083,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001083,"o"," "] +[0.000002667,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000112167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.00000575,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001291,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001084,"o"," "] +[0.000003166,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001459,"o"," "] +[0.000127125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000010708,"o","\n"] +[0.000001375,"o"," "] +[0.000003833,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001084,"o"," "] +[0.000003583,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000121834,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004666,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.000001333,"o"," "] +[0.000004208,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001875,"o"," "] +[0.000002792,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000120292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000005083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001209,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001,"o"," "] +[0.000002916,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001584,"o"," "] +[0.000119708,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001041,"o","\n"] +[0.001632167,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-execute--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-execute--help.cast new file mode 100644 index 00000000000..3927ad7f5e0 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-execute--help.cast @@ -0,0 +1,119 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853934,"command":"aws cloudformation changeset execute --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.204565542,"o","\n"] +[0.000130583,"o","\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\n\u001b[38;5;83m█\u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\n\n"] +[0.000050625,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002,"o","\n"] +[0.001837584,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mExecute a previously-created, named\u001b[0m\u001b[38;2;247;250;252m changeset\u001b[0m\n"] +[0.000003166,"o","\n"] +[0.000005,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000053667,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mchangeset\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mexecute\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000016291,"o","\n"] +[0.000016167,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.0001135,"o"," "] +[0.000004583,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.0000015,"o"," "] +[0.000133292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000005,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001416,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001667,"o"," "] +[0.000124125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004167,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.00000175,"o","\n"] +[0.000001375,"o"," "] +[0.000003666,"o","\u001b[1;38;2;0;163;224m --auto-approve\u001b[0m"] +[0.000001417,"o"," "] +[0.000116792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mSkip interactive\u001b[0m\u001b[38;2;255;255;255m confirmation.\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001542,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001458,"o"," "] +[0.00000325,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001542,"o"," "] +[0.000120708,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001292,"o"," "] +[0.000003667,"o","\u001b[1;38;2;0;163;224m --changeset-name\u001b[0m"] +[0.000001125,"o"," "] +[0.000002416,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.59e-7,"o"," "] +[0.000114916,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mName of the changeset to\u001b[0m\u001b[38;2;255;255;255m execute.\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.000001375,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000010917,"o"," "] +[0.000136958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001334,"o"," "] +[0.000003041,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001334,"o"," "] +[0.000125083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m execute\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001416,"o"," "] +[0.000002834,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001041,"o"," "] +[0.000154542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000008125,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001334,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[9.58e-7,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000166208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.0000055,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004834,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000001167,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[9.58e-7,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001292,"o"," "] +[0.000122958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001542,"o","\n"] +[0.000001208,"o"," "] +[0.000003292,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001041,"o"," "] +[0.000003,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001292,"o"," "] +[0.000125667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000005166,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000016417,"o","\n"] +[0.0000015,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001042,"o"," "] +[0.000002791,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001209,"o"," "] +[0.00011375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001958,"o","\n"] +[0.000001333,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001042,"o"," "] +[0.000003167,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001583,"o"," "] +[0.000110667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001292,"o"," "] +[0.000004125,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001042,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000113625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004125,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000001416,"o"," "] +[0.000002709,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002583,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001292,"o"," "] +[0.000121583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004167,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001125,"o","\n"] +[0.001702791,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-list--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-list--help.cast new file mode 100644 index 00000000000..6304ba7bf46 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-changeset-list--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853935,"command":"aws cloudformation changeset list --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.195990416,"o","\n"] +[0.000134584,"o","\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\n\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\n\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m \u001b[0m\n\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\n\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\n\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\n\n"] +[0.00006375,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001541,"o","\n"] +[0.001854084,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mList a stack's\u001b[0m\u001b[38;2;247;250;252m changesets\u001b[0m\n"] +[0.000002083,"o","\n"] +[0.000003958,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000073292,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mchangeset\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mlist\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.00001425,"o","\n"] +[0.000015875,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000125416,"o"," "] +[0.000003792,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001583,"o"," "] +[0.000148584,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004916,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000002542,"o","\n"] +[0.000001417,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001125,"o"," "] +[0.000122458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000003834,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.00000175,"o","\n"] +[0.000001083,"o"," "] +[0.000002583,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001042,"o"," "] +[0.000002417,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001416,"o"," "] +[0.000120834,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.00000425,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.00000125,"o"," "] +[0.000003417,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001417,"o"," "] +[0.000136583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000006375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001375,"o"," "] +[0.000002542,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001083,"o"," "] +[0.000137375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m list\u001b[0m\u001b[0m\n"] +[0.000010375,"o","\n"] +[0.000002834,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000004,"o"," "] +[0.000182167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000010833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001958,"o","\n"] +[0.000001959,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001083,"o"," "] +[0.000002708,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001209,"o"," "] +[0.00019775,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000007625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.00000125,"o"," "] +[0.000002916,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.75e-7,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000002959,"o"," "] +[0.000146208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001792,"o","\n"] +[0.000001458,"o"," "] +[0.000005417,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.00000175,"o"," "] +[0.000004125,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001291,"o"," "] +[0.000110834,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000001208,"o"," "] +[0.000002084,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001291,"o"," "] +[0.000002375,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001625,"o"," "] +[0.00010975,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.000001208,"o"," "] +[0.000002667,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[7.08e-7,"o"," "] +[0.00000225,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.17e-7,"o"," "] +[0.000107416,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000030875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001209,"o","\n"] +[9.58e-7,"o"," "] +[0.000002708,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[8.34e-7,"o"," "] +[0.000002125,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[7.91e-7,"o"," "] +[0.000109875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000003375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000003167,"o","\n"] +[0.00000125,"o"," "] +[0.000003458,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[7.5e-7,"o"," "] +[0.000002209,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001583,"o"," "] +[0.000108875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000001542,"o","\n"] +[0.001560167,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-delete--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-delete--help.cast new file mode 100644 index 00000000000..1ecf8aa66a6 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-delete--help.cast @@ -0,0 +1,129 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853927,"command":"aws cloudformation delete --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.194950167,"o","\n"] +[0.000166541,"o","\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\n\n"] +[0.000067375,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001625,"o","\n"] +[0.001782792,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mDelete the\u001b[0m\u001b[38;2;247;250;252m stack\u001b[0m\n"] +[0.000002625,"o","\n"] +[0.000004125,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000078875,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdelete\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.00002025,"o","\n"] +[0.00001925,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000130083,"o"," "] +[0.000004083,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001292,"o"," "] +[0.00014375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components\u001b[0m\u001b[0m\n"] +[0.000005375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255min dependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001417,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001417,"o"," "] +[0.000112541,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004667,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001292,"o"," "] +[0.00000375,"o","\u001b[1;38;2;0;163;224m --auto-approve\u001b[0m"] +[0.000002,"o"," "] +[0.000116125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mSkip interactive\u001b[0m\u001b[38;2;255;255;255m confirmation.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001041,"o"," "] +[0.0000025,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001,"o"," "] +[0.000002375,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001084,"o"," "] +[0.00011475,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against\u001b[0m\u001b[38;2;255;255;255m for\u001b[0m\u001b[0m\n"] +[0.0000045,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maffected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.00000125,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001583,"o"," "] +[0.000119417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it\u001b[0m\u001b[38;2;255;255;255m out\u001b[0m\u001b[0m\n"] +[0.000004542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255min the current repository for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004208,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000011,"o","\n"] +[0.000001625,"o"," "] +[0.000003917,"o","\u001b[1;38;2;0;163;224m --disable-termination-protection\u001b[0m"] +[0.00000125,"o"," "] +[0.000123458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mDisable termination protection before\u001b[0m\u001b[38;2;255;255;255m deleting\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255m(never done\u001b[0m\u001b[38;2;255;255;255m silently).\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001292,"o"," "] +[0.000004416,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001417,"o"," "] +[0.000097625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m delete\u001b[0m\u001b[0m\n"] +[0.000001792,"o","\n"] +[0.000001125,"o"," "] +[0.000003416,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001417,"o"," "] +[0.000124083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when\u001b[0m\u001b[38;2;255;255;255m processing\u001b[0m\u001b[0m\n"] +[0.000003667,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maffected aws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001,"o"," "] +[0.000002917,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000118917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value\u001b[0m\u001b[38;2;255;255;255m or\u001b[0m\u001b[0m\n"] +[0.000005208,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mkey:value pairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.00000125,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.34e-7,"o"," "] +[0.000002291,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000100625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001708,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001083,"o"," "] +[0.000002917,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000112417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository\u001b[0m\u001b[38;2;255;255;255m to\u001b[0m\u001b[0m\n"] +[0.00001375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255muse as the affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.00000125,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --retain-resources\u001b[0m"] +[0.000001083,"o"," "] +[0.000002792,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.00000125,"o"," "] +[0.000112708,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mLogical IDs of resources to retain (only\u001b[0m\u001b[38;2;255;255;255m valid\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mfor a DELETE_\u001b[0m\u001b[38;2;255;255;255mFAILED\u001b[0m\u001b[38;2;255;255;255m stack).\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001166,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[9.59e-7,"o"," "] +[0.000002708,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000002458,"o"," "] +[0.000099834,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004041,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.00000125,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001,"o"," "] +[0.000002958,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.75e-7,"o"," "] +[0.000108334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001458,"o"," "] +[0.000003459,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000002125,"o"," "] +[0.000003,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001625,"o"," "] +[0.000134208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to\u001b[0m\u001b[38;2;255;255;255m clone\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe target ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001166,"o"," "] +[0.000003459,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001,"o"," "] +[0.000003291,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001209,"o"," "] +[0.000109916,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000014834,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001167,"o","\n"] +[0.001665666,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-deploy--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-deploy--help.cast new file mode 100644 index 00000000000..b19d64e6850 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-deploy--help.cast @@ -0,0 +1,121 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853926,"command":"aws cloudformation deploy --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.195151792,"o","\n"] +[0.000133625,"o","\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\n\n"] +[0.000062458,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002,"o","\n"] +[0.001720709,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mApply with\u001b[0m\u001b[38;2;247;250;252m --auto-approve\u001b[0m\n"] +[0.000001958,"o","\n"] +[0.000003625,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000047208,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdeploy\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000014459,"o","\n"] +[0.000014666,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000115541,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001125,"o"," "] +[0.000138792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001792,"o"," "] +[0.000006083,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001125,"o"," "] +[0.00010975,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004125,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001292,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --auto-approve\u001b[0m"] +[0.000001417,"o"," "] +[0.000113583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mSkip interactive confirmation. (default \u001b[0m\u001b[38;2;155;81;224;1mtrue\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001459,"o"," "] +[0.000003083,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001,"o"," "] +[0.000003,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001583,"o"," "] +[0.000113375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003959,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.00000125,"o"," "] +[0.000003666,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001584,"o"," "] +[0.000111083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000010042,"o","\n"] +[0.000001417,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001333,"o"," "] +[0.000113334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m deploy\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001208,"o"," "] +[0.000003334,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001208,"o"," "] +[0.000114583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004584,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001167,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001,"o"," "] +[0.000002833,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000131917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000005791,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001208,"o"," "] +[0.000002625,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.75e-7,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000117,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.00000125,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.00000125,"o"," "] +[0.000002709,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001166,"o"," "] +[0.000110917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004583,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.00000125,"o"," "] +[0.000002875,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001417,"o"," "] +[0.000003041,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.59e-7,"o"," "] +[0.000103958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001125,"o"," "] +[0.000002959,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.0000085,"o"," "] +[0.000003083,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000126292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000007125,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001541,"o","\n"] +[0.00000125,"o"," "] +[0.000005917,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[9.17e-7,"o"," "] +[0.000002166,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.75e-7,"o"," "] +[0.000103,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004459,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001041,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001042,"o"," "] +[0.000112375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.00001275,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[9.58e-7,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --target\u001b[0m"] +[9.17e-7,"o"," "] +[0.00000225,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000132291,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProvision target to deliver to. Defaults\u001b[0m\u001b[38;2;255;255;255m to\u001b[0m\u001b[0m\n"] +[0.000005334,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mprovision.default, otherwise the implicit\u001b[0m\u001b[38;2;255;255;255m direct-deploy\u001b[0m\u001b[0m\n"] +[0.000004541,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget.\u001b[0m\u001b[0m\n"] +[0.000001209,"o","\n"] +[0.000001083,"o","\n"] +[0.001608375,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-diff--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-diff--help.cast new file mode 100644 index 00000000000..e17a67360d8 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-diff--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853924,"command":"aws cloudformation diff --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.193125042,"o","\n"] +[0.000130875,"o","\u001b[38;5;163m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\n\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\n\n"] +[0.000059583,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002792,"o","\n"] +[0.001695166,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mShow changes an apply would\u001b[0m\u001b[38;2;247;250;252m make\u001b[0m\n"] +[0.000002084,"o","\n"] +[0.000004125,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001041,"o","\n"] +[0.000048667,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdiff\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000014042,"o","\n"] +[0.000018083,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000103625,"o"," "] +[0.000004083,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.0000015,"o"," "] +[0.000124334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.00000775,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000001584,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001166,"o"," "] +[0.000111542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.0000025,"o"," "] +[0.000009125,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001167,"o"," "] +[0.000003083,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000112917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001459,"o","\n"] +[0.000001375,"o"," "] +[0.000003666,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001417,"o"," "] +[0.000119333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001292,"o"," "] +[0.000003833,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001292,"o"," "] +[0.000106375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m diff\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001458,"o"," "] +[0.000003917,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001417,"o"," "] +[0.000121833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000014542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001333,"o"," "] +[0.000003209,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001041,"o"," "] +[0.000003042,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001292,"o"," "] +[0.000123958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004292,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004541,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001209,"o","\n"] +[0.000001208,"o"," "] +[0.000003042,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002458,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000106917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.000003334,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001083,"o"," "] +[0.000002917,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001166,"o"," "] +[0.000116792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.0000045,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001208,"o"," "] +[0.000003292,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000122292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.000003417,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[9.58e-7,"o"," "] +[0.000002708,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001167,"o"," "] +[0.000114458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.0000045,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000008625,"o","\n"] +[0.00000375,"o"," "] +[0.000004125,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001084,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000113042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004541,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001167,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001041,"o"," "] +[0.000002917,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.00000125,"o"," "] +[0.000119208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004125,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001417,"o","\n"] +[0.001583583,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-drift--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-drift--help.cast new file mode 100644 index 00000000000..26d8343492f --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-drift--help.cast @@ -0,0 +1,32 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853936,"command":"aws cloudformation drift --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.198572834,"o","\n"] +[0.000133291,"o","\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\n\n"] +[0.000054167,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001917,"o","\n"] +[0.001693708,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mDetect and describe drift against a deployed\u001b[0m\u001b[38;2;247;250;252m stack\u001b[0m\n"] +[0.000002583,"o","\n"] +[0.00000425,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000064834,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdrift\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdrift\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[sub-command]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000015208,"o","\n"] +[0.000112417,"o","\u001b[1;38;2;0;163;224mBUILT-IN COMMANDS\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001667,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224mdescribe\u001b[0m"] +[0.000002167,"o"," "] +[0.000139375,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mShow the results of the most recent drift\u001b[0m\u001b[38;2;255;255;255m detection\u001b[0m\u001b[0m\n"] +[0.000002292,"o"," "] +[0.000003666,"o","\u001b[1;38;2;0;163;224mdetect\u001b[0m"] +[0.00000225,"o"," "] +[0.0001105,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mRun drift detection against the deployed\u001b[0m\u001b[38;2;255;255;255m stack\u001b[0m\u001b[0m\n"] +[0.00000525,"o","\n"] +[0.000012167,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000100292,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.00000125,"o"," "] +[0.000105416,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m drift\u001b[0m\u001b[0m\n"] +[0.000001542,"o","\n"] +[0.000001,"o","\n"] +[0.001610292,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1matmos cloudformation drift [command] --help\u001b[0m\u001b[38;2;247;250;252m for more information about a\u001b[0m\u001b[38;2;247;250;252m command.\u001b[0m\u001b[0m\n"] +[0.001643083,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-drift-describe--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-drift-describe--help.cast new file mode 100644 index 00000000000..43f1d986639 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-drift-describe--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853937,"command":"aws cloudformation drift describe --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.195245541,"o","\n"] +[0.000154917,"o","\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\n\n"] +[0.00006325,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001833,"o","\n"] +[0.002576917,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mShow the results of the most recent drift\u001b[0m\u001b[38;2;247;250;252m detection\u001b[0m\n"] +[0.000007458,"o","\n"] +[0.000006209,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000076,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdrift\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdescribe\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000024833,"o","\n"] +[0.000022917,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000265542,"o"," "] +[0.000005208,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001709,"o"," "] +[0.0001345,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000006333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.000001167,"o"," "] +[0.000007125,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001333,"o"," "] +[0.0001205,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004209,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001541,"o","\n"] +[0.000001375,"o"," "] +[0.000003959,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001208,"o"," "] +[0.000002958,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001459,"o"," "] +[0.0001465,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000008041,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001917,"o","\n"] +[0.00000175,"o"," "] +[0.000004542,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001541,"o"," "] +[0.000153459,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000005375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.000001417,"o"," "] +[0.000002583,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.00000125,"o"," "] +[0.000117292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m describe\u001b[0m\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.000001375,"o"," "] +[0.000003583,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000017709,"o"," "] +[0.00013675,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004291,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001709,"o","\n"] +[0.000001208,"o"," "] +[0.000003583,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001875,"o"," "] +[0.000140834,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004416,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004334,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001166,"o","\n"] +[0.00000125,"o"," "] +[0.000002792,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[9.17e-7,"o"," "] +[0.000002375,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001291,"o"," "] +[0.000102459,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.000001208,"o"," "] +[0.000003875,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001292,"o"," "] +[0.000003208,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001292,"o"," "] +[0.000110875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004458,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001084,"o"," "] +[0.000002958,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[9.17e-7,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000097416,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001125,"o"," "] +[0.000003542,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001,"o"," "] +[0.000003042,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000117958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004709,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000012333,"o","\n"] +[0.0000015,"o"," "] +[0.000003875,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001125,"o"," "] +[0.000003208,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001584,"o"," "] +[0.000115666,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.00000475,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.0000015,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001084,"o"," "] +[0.000003333,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001208,"o"," "] +[0.000119709,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000003875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001041,"o","\n"] +[0.001603125,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-drift-detect--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-drift-detect--help.cast new file mode 100644 index 00000000000..0dcdd1253f6 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-drift-detect--help.cast @@ -0,0 +1,112 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853938,"command":"aws cloudformation drift detect --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.198129459,"o","\n"] +[0.00072225,"o","\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\n\n"] +[0.0000665,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001875,"o","\n"] +[0.002090208,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mRun drift detection against the deployed\u001b[0m\u001b[38;2;247;250;252m stack\u001b[0m\n"] +[0.000002417,"o","\n"] +[0.000004666,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000051625,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdrift\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdetect\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000018375,"o","\n"] +[0.000019292,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000108583,"o"," "] +[0.000003917,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001958,"o"," "] +[0.000122083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.00000125,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001333,"o"," "] +[0.000112209,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004291,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001334,"o"," "] +[0.000003291,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001125,"o"," "] +[0.000002834,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000113083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.00000125,"o"," "] +[0.00000475,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001583,"o"," "] +[0.000112,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000005084,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001209,"o"," "] +[0.0000035,"o","\u001b[1;38;2;0;163;224m --fail-on-drift\u001b[0m"] +[0.000001333,"o"," "] +[0.000108167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mExit non-zero if drift is detected (for\u001b[0m\u001b[38;2;255;255;255m CI).\u001b[0m\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000001584,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000010166,"o"," "] +[0.00012575,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m detect\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.00000125,"o"," "] +[0.000003459,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001208,"o"," "] +[0.000117333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004167,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.00000125,"o"," "] +[0.000003917,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.00000125,"o"," "] +[0.000002958,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001,"o"," "] +[0.000112917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004334,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001791,"o"," "] +[0.000002792,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.33e-7,"o"," "] +[0.000003042,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001167,"o"," "] +[0.000104458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001209,"o"," "] +[0.000003458,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001,"o"," "] +[0.000002917,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001375,"o"," "] +[0.000109208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[9.59e-7,"o"," "] +[0.000005583,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000113417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001167,"o"," "] +[0.000003583,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[9.59e-7,"o"," "] +[0.000003166,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000107334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000012166,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[9.59e-7,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001041,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000111042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004416,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001209,"o"," "] +[0.000003166,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[9.59e-7,"o"," "] +[0.000003,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001,"o"," "] +[0.000103666,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001042,"o","\n"] +[0.001612333,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-fmt--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-fmt--help.cast new file mode 100644 index 00000000000..5ece25297fd --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-fmt--help.cast @@ -0,0 +1,113 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853939,"command":"aws cloudformation fmt --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.200816875,"o","\n"] +[0.00013525,"o","\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\n\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\n\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m \u001b[0m\n\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\n\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\n\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\n\n"] +[0.000066833,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001958,"o","\n"] +[0.00174375,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mFormat the local template in place (or check formatting with\u001b[0m\u001b[38;2;247;250;252m --check)\u001b[0m\n"] +[0.000003292,"o","\n"] +[0.000005042,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000051584,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mfmt\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000027333,"o","\n"] +[0.000018417,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001166,"o","\n"] +[0.000115959,"o"," "] +[0.000004166,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001459,"o"," "] +[0.00012325,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.0000055,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001417,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001541,"o"," "] +[0.000123084,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001375,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001125,"o"," "] +[0.000003084,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001541,"o"," "] +[0.000114042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.00000425,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001166,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --check\u001b[0m"] +[0.000001417,"o"," "] +[0.000114333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mReport whether the template is formatted\u001b[0m\u001b[38;2;255;255;255m without\u001b[0m\u001b[0m\n"] +[0.0000055,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mwriting changes (non-zero exit if\u001b[0m\u001b[38;2;255;255;255m not).\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.000001458,"o"," "] +[0.000003667,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001458,"o"," "] +[0.000117917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000018833,"o","\n"] +[0.000001584,"o"," "] +[0.000004083,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001625,"o"," "] +[0.000104708,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m fmt\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.000001334,"o"," "] +[0.000003416,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001209,"o"," "] +[0.000114833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.00000525,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001541,"o"," "] +[0.000003667,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001167,"o"," "] +[0.000003291,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001542,"o"," "] +[0.000121792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[0.000001125,"o"," "] +[0.000003209,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000004958,"o"," "] +[0.000106875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001291,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001,"o"," "] +[0.000003209,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001166,"o"," "] +[0.000115959,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.0000045,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.000002958,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001,"o"," "] +[0.000002709,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.58e-7,"o"," "] +[0.000104875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000011458,"o","\n"] +[0.000001334,"o"," "] +[0.000002791,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001,"o"," "] +[0.000002209,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000109083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004792,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001959,"o"," "] +[0.000003458,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001,"o"," "] +[0.000002667,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000108875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001209,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001041,"o"," "] +[0.000107917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.000001083,"o","\n"] +[0.001658417,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-get--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-get--help.cast new file mode 100644 index 00000000000..1cda1c86cc4 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-get--help.cast @@ -0,0 +1,32 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853941,"command":"aws cloudformation get --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.205255375,"o","\n"] +[0.000160792,"o","\u001b[38;5;63m \u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\n\n"] +[0.000066916,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002084,"o","\n"] +[0.00176775,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mFetch a deployed stack's template or\u001b[0m\u001b[38;2;247;250;252m policy\u001b[0m\n"] +[0.000002083,"o","\n"] +[0.000004083,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000078041,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mget\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mget\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[sub-command]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000015375,"o","\n"] +[0.00012,"o","\u001b[1;38;2;0;163;224mBUILT-IN COMMANDS\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001625,"o"," "] +[0.000003542,"o","\u001b[1;38;2;0;163;224mpolicy\u001b[0m"] +[0.000002166,"o"," "] +[0.000130167,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFetch the deployed stack's\u001b[0m\u001b[38;2;255;255;255m policy\u001b[0m\u001b[0m\n"] +[0.000001958,"o"," "] +[0.00000425,"o","\u001b[1;38;2;0;163;224mtemplate\u001b[0m"] +[0.000002459,"o"," "] +[0.000118291,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFetch the deployed stack's\u001b[0m\u001b[38;2;255;255;255m template\u001b[0m\u001b[0m\n"] +[0.000001667,"o","\n"] +[0.000018,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.000098667,"o"," "] +[0.000003583,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001334,"o"," "] +[0.000108958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m get\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[8.33e-7,"o","\n"] +[0.001624375,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1matmos cloudformation get [command] --help\u001b[0m\u001b[38;2;247;250;252m for more information about a\u001b[0m\u001b[38;2;247;250;252m command.\u001b[0m\u001b[0m\n"] +[0.00167325,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-get-policy--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-get-policy--help.cast new file mode 100644 index 00000000000..f3a516de3a7 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-get-policy--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853942,"command":"aws cloudformation get policy --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.205853666,"o","\n"] +[0.00014125,"o","\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\n\n"] +[0.000070709,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.001603875,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mFetch the deployed stack's\u001b[0m\u001b[38;2;247;250;252m policy\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.0000035,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000054667,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mget\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mpolicy\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000011958,"o","\n"] +[0.000015834,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[9.16e-7,"o","\n"] +[0.000099209,"o"," "] +[0.0000035,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001375,"o"," "] +[0.000130458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004292,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001375,"o"," "] +[0.000002791,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001,"o"," "] +[0.0001095,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000002959,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001666,"o","\n"] +[0.0000015,"o"," "] +[0.000002417,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.00000125,"o"," "] +[0.000002583,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001292,"o"," "] +[0.000107208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003459,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[0.00000175,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001333,"o"," "] +[0.000109625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000003709,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001875,"o"," "] +[0.000003667,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001083,"o"," "] +[0.000098875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m policy\u001b[0m\u001b[0m\n"] +[0.000008458,"o","\n"] +[0.000001084,"o"," "] +[0.000003541,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001084,"o"," "] +[0.000103791,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003709,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[9.16e-7,"o"," "] +[0.000017459,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000010416,"o"," "] +[0.000009875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001875,"o"," "] +[0.000183375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000007542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000005667,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001834,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[9.58e-7,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000157583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000002917,"o","\n"] +[0.000001667,"o"," "] +[0.000003833,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001083,"o"," "] +[0.000002959,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000131333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000005625,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001667,"o","\n"] +[0.000001458,"o"," "] +[0.000003833,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001125,"o"," "] +[0.000002959,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001833,"o"," "] +[0.000143875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001875,"o","\n"] +[0.000001417,"o"," "] +[0.00000375,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001083,"o"," "] +[0.000002917,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001291,"o"," "] +[0.000118167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000031833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001542,"o","\n"] +[0.000001125,"o"," "] +[0.000002792,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001375,"o"," "] +[0.000002416,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000005209,"o"," "] +[0.00012225,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004416,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000001375,"o"," "] +[0.000002458,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[9.59e-7,"o"," "] +[0.000003166,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001167,"o"," "] +[0.000114083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000003584,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001416,"o","\n"] +[0.001683959,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-get-template--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-get-template--help.cast new file mode 100644 index 00000000000..e5c92ff4ebe --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-get-template--help.cast @@ -0,0 +1,113 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853943,"command":"aws cloudformation get template --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.250838875,"o","\n"] +[0.000145542,"o","\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\n\n"] +[0.000066833,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001875,"o","\n"] +[0.001692875,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mFetch the deployed stack's\u001b[0m\u001b[38;2;247;250;252m template\u001b[0m\n"] +[0.000001792,"o","\n"] +[0.00000325,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[9.17e-7,"o","\n"] +[0.000053958,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mget\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mtemplate\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000012792,"o","\n"] +[0.000015208,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[9.17e-7,"o","\n"] +[0.000107208,"o"," "] +[0.000003417,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001208,"o"," "] +[0.00012,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004208,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000001042,"o"," "] +[0.000002541,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001209,"o"," "] +[0.000113333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000003375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000001208,"o"," "] +[0.0000025,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001,"o"," "] +[0.000002584,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000113166,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000001125,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001,"o"," "] +[0.000113292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000003583,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001084,"o"," "] +[0.000002375,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001166,"o"," "] +[0.000121792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m template\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.00000125,"o"," "] +[0.000002667,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001,"o"," "] +[0.00012525,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003833,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[8.34e-7,"o"," "] +[0.000002666,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001375,"o"," "] +[0.000137417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000003708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004709,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000001125,"o"," "] +[0.000002458,"o","\u001b[1;38;2;0;163;224m --original\u001b[0m"] +[9.59e-7,"o"," "] +[0.000179583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFetch the user-submitted template instead of\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000006875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mprocessed\u001b[0m\u001b[38;2;255;255;255m one.\u001b[0m\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.000001792,"o"," "] +[0.000003708,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[0.000001084,"o"," "] +[0.000002958,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001333,"o"," "] +[0.000113042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001958,"o","\n"] +[0.000001417,"o"," "] +[0.00000375,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001208,"o"," "] +[0.000003084,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001375,"o"," "] +[0.0001235,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004583,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001333,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001417,"o"," "] +[0.000004083,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000117458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000016917,"o","\n"] +[0.000001167,"o"," "] +[0.000002791,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001084,"o"," "] +[0.000002666,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.59e-7,"o"," "] +[0.000115291,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001958,"o"," "] +[0.000004125,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001042,"o"," "] +[0.000003417,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001541,"o"," "] +[0.000116417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.0000015,"o"," "] +[0.000003833,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001125,"o"," "] +[0.000002834,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001208,"o"," "] +[0.000111458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.0000045,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.000001083,"o","\n"] +[0.001653917,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-list--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-list--help.cast new file mode 100644 index 00000000000..7585ed9b070 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-list--help.cast @@ -0,0 +1,55 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853944,"command":"aws cloudformation list --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.214095292,"o","\n"] +[0.000190791,"o","\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\n\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\n\n"] +[0.000062459,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002041,"o","\n"] +[0.001877042,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mList the account's deployed CloudFormation stacks (ListStacks), annotated\u001b[0m\u001b[38;2;247;250;252m with \u001b[0m\u001b[38;2;247;250;252mwhether\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252meach one matches an aws/cloudformation component's stack_\u001b[0m\u001b[38;2;247;250;252mname\u001b[0m\u001b[38;2;247;250;252m configured \u001b[0m\u001b[38;2;247;250;252min the given\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mstack.\u001b[0m\n"] +[0.000023042,"o","\n"] +[0.000004625,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001166,"o","\n"] +[0.0000505,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mlist\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000001709,"o","\n"] +[0.000003375,"o","\u001b[1;38;2;0;163;224mEXAMPLES\u001b[0m\n"] +[8.33e-7,"o","\n"] +[0.000049292,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m# List all stacks in the account, annotated against the \"dev\" stack's components\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation list --stack dev\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # Only stacks currently in a *_COMPLETE status\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation list --stack dev --status CREATE_COMPLETE,UPDATE_COMPLETE\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.0000025,"o","\n"] +[0.000013041,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[9.17e-7,"o","\n"] +[0.00011075,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001292,"o"," "] +[0.000120792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m list\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001083,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m-i, --identity\u001b[0m"] +[0.000001,"o"," "] +[0.000002541,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.0000015,"o"," "] +[0.000119292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mIdentity to use for authentication (use without value to\u001b[0m\u001b[38;2;255;255;255m select\u001b[0m\u001b[0m\n"] +[0.00000425,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255minteractively)\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000001042,"o"," "] +[0.000002583,"o","\u001b[1;38;2;0;163;224m --region\u001b[0m"] +[0.000028209,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001041,"o"," "] +[0.000119792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mAWS region to list stacks in. Defaults to the active\u001b[0m\u001b[38;2;255;255;255m identity's\u001b[0m\u001b[0m\n"] +[0.000003875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mregion, then the SDK's standard resolution\u001b[0m\u001b[38;2;255;255;255m chain.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001,"o"," "] +[0.000002625,"o","\u001b[1;38;2;0;163;224m-s, --stack\u001b[0m"] +[9.16e-7,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000107959,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mStack\u001b[0m\u001b[38;2;255;255;255m name\u001b[0m\u001b[0m\n"] +[0.000001666,"o","\n"] +[0.000001334,"o"," "] +[0.000003208,"o","\u001b[1;38;2;0;163;224m --status\u001b[0m"] +[0.000001,"o"," "] +[0.00000375,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.0000015,"o"," "] +[0.000155083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by stack status (comma-separated,\u001b[0m\u001b[38;2;255;255;255m e.g.\u001b[0m\u001b[0m\n"] +[0.000022875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mCREATE_\u001b[0m\u001b[38;2;255;255;255mCOMPLETE,UPDATE_\u001b[0m\u001b[38;2;255;255;255mCOMPLETE).\u001b[0m\u001b[0m\n"] +[0.000002167,"o","\n"] +[0.000001208,"o","\n"] +[0.001696417,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-output--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-output--help.cast new file mode 100644 index 00000000000..bc155fbc20c --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-output--help.cast @@ -0,0 +1,130 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853929,"command":"aws cloudformation output --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.203141,"o","\n"] +[0.000120917,"o","\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\n\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\n\n"] +[0.000058417,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001666,"o","\n"] +[0.001702834,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mShow the deployed stack's\u001b[0m\u001b[38;2;247;250;252m Outputs\u001b[0m\n"] +[0.000002208,"o","\n"] +[0.000003417,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000064791,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54moutput\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000011125,"o","\n"] +[0.000004,"o","\u001b[1;38;2;0;163;224mALIASES\u001b[0m\n"] +[0.000001209,"o","\n"] +[0.000004,"o"," \u001b[38;2;73;85;104moutput, outputs\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000016208,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[8.75e-7,"o","\n"] +[0.000098583,"o"," "] +[0.000002625,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001084,"o"," "] +[0.000111208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001208,"o"," "] +[0.000002667,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001208,"o"," "] +[0.000109125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000003375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[9.59e-7,"o"," "] +[0.000002625,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[9.16e-7,"o"," "] +[0.000002542,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.0000015,"o"," "] +[0.000117125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000037875,"o"," "] +[0.000004458,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001625,"o"," "] +[0.000124584,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.00000475,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001333,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --flatten\u001b[0m"] +[0.000001167,"o"," "] +[0.000120583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFlatten nested Outputs into compound\u001b[0m\u001b[38;2;255;255;255m keys.\u001b[0m\u001b[0m\n"] +[0.000008834,"o","\n"] +[0.000001083,"o"," "] +[0.000002875,"o","\u001b[1;38;2;0;163;224m --format\u001b[0m"] +[0.000001,"o"," "] +[0.000002667,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000128916,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mOutput format\u001b[0m\u001b[38;2;255;255;255m:\u001b[0m\u001b[0m\n"] +[0.000004667,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mjson|yaml|hcl|env|dotenv|bash|csv|tsv|table|github.\u001b[0m\u001b[0m\n"] +[0.000003583,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255m(default \u001b[0m\u001b[38;2;155;81;224;1mtable\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000001083,"o"," "] +[0.000002334,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001208,"o"," "] +[0.000108625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m output\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[9.17e-7,"o"," "] +[0.0000035,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000001291,"o"," "] +[0.000112792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003542,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000002083,"o"," "] +[0.000002667,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[7.5e-7,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[9.17e-7,"o"," "] +[0.000121416,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004125,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000003584,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001291,"o"," "] +[0.000002584,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[0.000001125,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000015166,"o"," "] +[0.000186792,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000275,"o","\n"] +[0.000001625,"o"," "] +[0.000004208,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001334,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000017375,"o"," "] +[0.0001325,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.00000175,"o"," "] +[0.000003083,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001375,"o"," "] +[0.000002917,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.00010825,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.000001416,"o"," "] +[0.000002875,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.00000125,"o"," "] +[0.000002584,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000175,"o"," "] +[0.000116666,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.00000425,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000001375,"o"," "] +[0.000004041,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[9.17e-7,"o"," "] +[0.000003083,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001167,"o"," "] +[0.000110375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.00000375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000002167,"o","\n"] +[0.00000125,"o"," "] +[0.000002833,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[8.33e-7,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.00000125,"o"," "] +[0.000115834,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000003791,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001667,"o","\n"] +[0.00000125,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --uppercase\u001b[0m"] +[0.000002,"o"," "] +[0.00010175,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mUppercase Output\u001b[0m\u001b[38;2;255;255;255m keys.\u001b[0m\u001b[0m\n"] +[0.000001167,"o","\n"] +[8.75e-7,"o","\n"] +[0.001617833,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-plan--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-plan--help.cast new file mode 100644 index 00000000000..79c2c1d603b --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-plan--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853923,"command":"aws cloudformation plan --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.200041666,"o","\n"] +[0.000167,"o","\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\n\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\n\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\n\n"] +[0.000068542,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001958,"o","\n"] +[0.001732042,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mPreview changes an apply would\u001b[0m\u001b[38;2;247;250;252m make\u001b[0m\n"] +[0.000001792,"o","\n"] +[0.000004375,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001166,"o","\n"] +[0.000091042,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mplan\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.00001525,"o","\n"] +[0.00001425,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000103834,"o"," "] +[0.000003916,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001417,"o"," "] +[0.000132375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000004958,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001583,"o"," "] +[0.000003042,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001333,"o"," "] +[0.000119292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001292,"o"," "] +[0.000003333,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001125,"o"," "] +[0.000002792,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000130666,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000003959,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001291,"o","\n"] +[0.000001334,"o"," "] +[0.000003625,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.00000175,"o"," "] +[0.0001125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000004666,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.00000125,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001209,"o"," "] +[0.000100916,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m plan\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.00000125,"o"," "] +[0.000003417,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.00000125,"o"," "] +[0.0001275,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004708,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.0000015,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001041,"o"," "] +[0.000002834,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001041,"o"," "] +[0.000122334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000004333,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004792,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[9.16e-7,"o","\n"] +[0.00000125,"o"," "] +[0.000003292,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.75e-7,"o"," "] +[0.00000225,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000105167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001292,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001375,"o"," "] +[0.000002583,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000121042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000006917,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.00000925,"o"," "] +[0.000010833,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001792,"o"," "] +[0.00000425,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001625,"o"," "] +[0.000153375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000002417,"o","\n"] +[0.000001666,"o"," "] +[0.00000375,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[0.000001167,"o"," "] +[0.000003375,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001458,"o"," "] +[0.000129042,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000005,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000014875,"o","\n"] +[0.00000175,"o"," "] +[0.000003917,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001125,"o"," "] +[0.000003291,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.00011775,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000005209,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001291,"o"," "] +[0.000003709,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.000001125,"o"," "] +[0.00000275,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001416,"o"," "] +[0.000133334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004416,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001292,"o","\n"] +[0.000001042,"o","\n"] +[0.001585458,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-render--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-render--help.cast new file mode 100644 index 00000000000..c0f55b0dd04 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-render--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853922,"command":"aws cloudformation render --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.211591458,"o","\n"] +[0.000160333,"o","\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\n\n"] +[0.000078,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000004542,"o","\n"] +[0.00178075,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mRender the local template client-side (no API\u001b[0m\u001b[38;2;247;250;252m calls)\u001b[0m\n"] +[0.000002333,"o","\n"] +[0.000003959,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000062291,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mrender\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000015792,"o","\n"] +[0.000017458,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.0001405,"o"," "] +[0.000006417,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001458,"o"," "] +[0.000150709,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000007458,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.000001625,"o"," "] +[0.00000325,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001125,"o"," "] +[0.000134917,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001917,"o","\n"] +[0.00000125,"o"," "] +[0.000003666,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001292,"o"," "] +[0.000002792,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001375,"o"," "] +[0.000151166,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004709,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.0000015,"o"," "] +[0.00000425,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000001292,"o"," "] +[0.0001205,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000011416,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.00000125,"o"," "] +[0.000002375,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[9.58e-7,"o"," "] +[0.000121583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m render\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001125,"o"," "] +[0.00000275,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.000003667,"o"," "] +[0.000147667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000015291,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.000001667,"o","\n"] +[0.000001375,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[9.58e-7,"o"," "] +[0.000003667,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001292,"o"," "] +[0.000127458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000006792,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000005041,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001125,"o","\n"] +[0.000001084,"o"," "] +[0.000002375,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[8.75e-7,"o"," "] +[0.00000225,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001208,"o"," "] +[0.000121667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001541,"o","\n"] +[0.000001417,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[9.58e-7,"o"," "] +[0.000003334,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001166,"o"," "] +[0.00012275,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.000001042,"o","\n"] +[9.17e-7,"o"," "] +[0.000002541,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[7.92e-7,"o"," "] +[0.000002333,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000114167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000001084,"o"," "] +[0.000003458,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[9.58e-7,"o"," "] +[0.000002834,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001291,"o"," "] +[0.000147375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000004875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.0000095,"o","\n"] +[0.000001417,"o"," "] +[0.000004833,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001209,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000139458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000003417,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000001084,"o"," "] +[0.000002458,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[0.00000275,"o"," "] +[0.000002333,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[9.17e-7,"o"," "] +[0.000132167,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004916,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001334,"o","\n"] +[0.000001125,"o","\n"] +[0.002467125,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-source--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-source--help.cast new file mode 100644 index 00000000000..db5106c7e4a --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-source--help.cast @@ -0,0 +1,40 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853945,"command":"aws cloudformation source --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.211290834,"o","\n"] +[0.000153333,"o","\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\n\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\n\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m \u001b[0m\n\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\n\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\n\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;128m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\n\n"] +[0.00008125,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001458,"o","\n"] +[0.002027167,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mManage aws/cloudformation component sources defined in stack\u001b[0m\u001b[38;2;247;250;252m configuration.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mThe source provisioner enables just-in-time (JIT) vendoring of component\u001b[0m\u001b[38;2;247;250;252m sources\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mdirectly from stack configuration. Components can declare their source\u001b[0m\u001b[38;2;247;250;252m location \u001b[0m\u001b[38;2;247;250;252minline\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252musing the source field without requiring a separate component.yaml\u001b[0m\u001b[38;2;247;250;252m file.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mCommands: \u001b[0m\u001b[38;2;247;250;252mpull Vendor component source (use --force to\u001b[0m\u001b[38;2;247;250;252m re-vendor) \u001b[0m\u001b[38;2;247;250;252mlist List\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mcomponents with source in a\u001b[0m\u001b[38;2;247;250;252m stack \u001b[0m\u001b[38;2;247;250;252mdescribe Show source configuration for a\u001b[0m\u001b[38;2;247;250;252m component\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mdelete Remove vendored source\u001b[0m\u001b[38;2;247;250;252m directory\u001b[0m\n"] +[0.000021417,"o","\n"] +[0.000004125,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[8.75e-7,"o","\n"] +[0.000055458,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54msource\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[sub-command]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000002167,"o","\n"] +[0.000115875,"o","\u001b[1;38;2;0;163;224mBUILT-IN COMMANDS\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000001834,"o"," "] +[0.000003291,"o","\u001b[1;38;2;0;163;224mdelete\u001b[0m"] +[0.000002375,"o"," "] +[0.000135917,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mRemove vendored CloudFormation source\u001b[0m\u001b[38;2;255;255;255m directory\u001b[0m\u001b[0m\n"] +[0.000001875,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224mdescribe\u001b[0m"] +[0.00000225,"o"," "] +[0.000127333,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mShow source configuration for a CloudFormation\u001b[0m\u001b[38;2;255;255;255m component\u001b[0m\u001b[0m\n"] +[0.000001667,"o"," "] +[0.000003041,"o","\u001b[1;38;2;0;163;224mlist\u001b[0m"] +[0.000001875,"o"," "] +[0.000119709,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mList CloudFormation components with source\u001b[0m\u001b[38;2;255;255;255m configuration\u001b[0m\u001b[0m\n"] +[0.000001583,"o"," "] +[0.000002917,"o","\u001b[1;38;2;0;163;224mpull\u001b[0m"] +[0.000001875,"o"," "] +[0.000370416,"o","\u001b[38;2;73;85;104m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mVendor CloudFormation component source from source\u001b[0m\u001b[38;2;255;255;255m configuration\u001b[0m\u001b[0m\n"] +[0.00000225,"o","\n"] +[0.000187,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.0000415,"o","\n"] +[0.000374875,"o"," "] +[0.000008542,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001542,"o"," "] +[0.000211541,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m source\u001b[0m\u001b[0m\n"] +[0.000002459,"o","\n"] +[0.000001041,"o","\n"] +[0.001959584,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1matmos cloudformation source [command] --help\u001b[0m\u001b[38;2;247;250;252m for more information about a\u001b[0m\u001b[38;2;247;250;252m command.\u001b[0m\u001b[0m\n"] +[0.001644416,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-source-delete--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-delete--help.cast new file mode 100644 index 00000000000..b4bcf633beb --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-delete--help.cast @@ -0,0 +1,36 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853946,"command":"aws cloudformation source delete --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.2074755,"o","\n"] +[0.000137708,"o","\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\n\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m█\u001b[0m\u001b[38;5;84m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\n\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;48m \u001b[0m\u001b[38;5;84m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\n\n"] +[0.000052542,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002166,"o","\n"] +[0.001831875,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mDelete the vendored source directory for a CloudFormation\u001b[0m\u001b[38;2;247;250;252m component.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mThis command removes the component directory that was created by 'atmos aws\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mcloudformation source\u001b[0m\u001b[38;2;247;250;252m pull'.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mIf component is not specified, prompts interactively for\u001b[0m\u001b[38;2;247;250;252m selection.\u001b[0m\n"] +[0.000012959,"o","\n"] +[0.000004916,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001,"o","\n"] +[0.000052,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54msource\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdelete\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.0000025,"o","\n"] +[0.00000425,"o","\u001b[1;38;2;0;163;224mEXAMPLES\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000041291,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m# Delete vendored source\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source delete vpc --stack dev --force\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # Interactive: prompts for component and stack\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source delete\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000002667,"o","\n"] +[0.000013083,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001167,"o","\n"] +[0.000117667,"o"," "] +[0.000003916,"o","\u001b[1;38;2;0;163;224m-f, --force\u001b[0m"] +[0.000001625,"o"," "] +[0.000122667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mForce deletion without\u001b[0m\u001b[38;2;255;255;255m confirmation\u001b[0m\u001b[0m\n"] +[0.000001708,"o","\n"] +[0.000001375,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001375,"o"," "] +[0.000104334,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m delete\u001b[0m\u001b[0m\n"] +[0.000001416,"o","\n"] +[0.000001292,"o"," "] +[0.000003,"o","\u001b[1;38;2;0;163;224m-s, --stack\u001b[0m"] +[0.000001167,"o"," "] +[0.000003416,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001167,"o"," "] +[0.000104417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mStack\u001b[0m\u001b[38;2;255;255;255m name\u001b[0m\u001b[0m\n"] +[0.000009458,"o","\n"] +[0.00000125,"o","\n"] +[0.001661542,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-source-describe--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-describe--help.cast new file mode 100644 index 00000000000..8352f3bbbd5 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-describe--help.cast @@ -0,0 +1,31 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853947,"command":"aws cloudformation source describe --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.203101417,"o","\n"] +[0.000157541,"o","\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\n\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m \u001b[0m\n\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;44m█\u001b[0m\u001b[38;5;43m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m█\u001b[0m\u001b[38;5;49m \u001b[0m\n\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;38m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;44m \u001b[0m\u001b[38;5;43m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\u001b[38;5;49m \u001b[0m\n\n"] +[0.000059959,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002416,"o","\n"] +[0.001835959,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mDisplay the source configuration for a CloudFormation\u001b[0m\u001b[38;2;247;250;252m component.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mThis command shows the source URI, version, and any path filters\u001b[0m\u001b[38;2;247;250;252m configured \u001b[0m\u001b[38;2;247;250;252mfor the\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mcomponent. Output matches the stack manifest schema\u001b[0m\u001b[38;2;247;250;252m format.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mIf component is not specified, prompts interactively for\u001b[0m\u001b[38;2;247;250;252m selection.\u001b[0m\n"] +[0.000014208,"o","\n"] +[0.000003875,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[9.17e-7,"o","\n"] +[0.000048375,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54msource\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mdescribe\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000002375,"o","\n"] +[0.000004166,"o","\u001b[1;38;2;0;163;224mEXAMPLES\u001b[0m\n"] +[0.000001084,"o","\n"] +[0.000040125,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m# Describe source configuration\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source describe vpc --stack dev\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # Interactive: prompts for component and stack\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source describe\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000003125,"o","\n"] +[0.000012375,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001083,"o","\n"] +[0.000109542,"o"," "] +[0.000003875,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.00000175,"o"," "] +[0.000116333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m describe\u001b[0m\u001b[0m\n"] +[0.000001542,"o","\n"] +[0.000001416,"o"," "] +[0.000003125,"o","\u001b[1;38;2;0;163;224m-s, --stack\u001b[0m"] +[0.000001,"o"," "] +[0.000003084,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001541,"o"," "] +[0.000102375,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mStack\u001b[0m\u001b[38;2;255;255;255m name\u001b[0m\u001b[0m\n"] +[0.000001459,"o","\n"] +[0.000001,"o","\n"] +[0.001610291,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-source-list--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-list--help.cast new file mode 100644 index 00000000000..74c5beb0a15 --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-list--help.cast @@ -0,0 +1,38 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853948,"command":"aws cloudformation source list --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.202964541,"o","\n"] +[0.000152209,"o","\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\n\u001b[38;5;128m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\n\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m█\u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m█\u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m█\u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;33m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m█\u001b[0m\u001b[38;5;39m \u001b[0m\n\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;129m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;93m \u001b[0m\u001b[38;5;99m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;63m \u001b[0m\u001b[38;5;69m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;33m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\u001b[38;5;39m \u001b[0m\n\n"] +[0.000048625,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001666,"o","\n"] +[0.0020065,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mList all CloudFormation components that have source\u001b[0m\u001b[38;2;247;250;252m configured.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mIf component is specified, shows source info for that component across\u001b[0m\u001b[38;2;247;250;252m stacks. \u001b[0m\u001b[38;2;247;250;252mIf --\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mstack is specified, limits to that\u001b[0m\u001b[38;2;247;250;252m stack. \u001b[0m\u001b[38;2;247;250;252mIf neither specified, lists all components\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mwith source across all\u001b[0m\u001b[38;2;247;250;252m stacks.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mThis command shows which components can be vendored using the source\u001b[0m\u001b[38;2;247;250;252m provisioner.\u001b[0m\n"] +[0.000018209,"o","\n"] +[0.000004166,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[9.59e-7,"o","\n"] +[0.000068291,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54msource\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mlist\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000002125,"o","\n"] +[0.000003417,"o","\u001b[1;38;2;0;163;224mEXAMPLES\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000087875,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m# List all sources in a stack\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source list --stack dev\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # List sources for a specific component across all stacks\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source list vpc\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # List source for a specific component in a specific stack\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source list vpc --stack dev\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # List all sources across all stacks\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source list\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # Output as JSON\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source list --format json\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000010584,"o","\n"] +[0.000014125,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[9.16e-7,"o","\n"] +[0.00010325,"o"," "] +[0.000003875,"o","\u001b[1;38;2;0;163;224m-f, --format\u001b[0m"] +[0.000001334,"o"," "] +[0.000002708,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001042,"o"," "] +[0.000134166,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mOutput format: table, json, yaml, csv, tsv (default \u001b[0m\u001b[38;2;155;81;224;1mtable\u001b[0m\u001b[38;2;255;255;255m)\u001b[0m\u001b[0m\n"] +[0.000002167,"o","\n"] +[0.000001458,"o"," "] +[0.0000035,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001459,"o"," "] +[0.000111958,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m list\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001041,"o"," "] +[0.0000025,"o","\u001b[1;38;2;0;163;224m-s, --stack\u001b[0m"] +[0.00000125,"o"," "] +[0.000002334,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001083,"o"," "] +[0.000119583,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mStack\u001b[0m\u001b[38;2;255;255;255m name\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[7.92e-7,"o","\n"] +[0.001805333,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-source-pull--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-pull--help.cast new file mode 100644 index 00000000000..a26a011eeef --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-source-pull--help.cast @@ -0,0 +1,44 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853950,"command":"aws cloudformation source pull --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.217043458,"o","\n"] +[0.000159584,"o","\u001b[38;5;83m \u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\n\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m█\u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;83m \u001b[0m\u001b[38;5;119m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\n\u001b[38;5;83m█\u001b[0m\u001b[38;5;119m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;148m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m█\u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m█\u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\n\u001b[38;5;118m \u001b[0m\u001b[38;5;118m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;154m \u001b[0m\u001b[38;5;148m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;184m \u001b[0m\u001b[38;5;178m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\n\n"] +[0.000077041,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000002959,"o","\n"] +[0.002059625,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mVendor a CloudFormation component source based on source\u001b[0m\u001b[38;2;247;250;252m configuration.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mThis command downloads the component source from the URI specified in the source\u001b[0m\u001b[38;2;247;250;252m field\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mand places it in the appropriate component directory. The source can be any\u001b[0m\u001b[38;2;247;250;252m go-getter\u001b[0m\n\u001b[38;2;73;85;104m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mcompatible URI (git, s3, http, oci,\u001b[0m\u001b[38;2;247;250;252m etc.).\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mIf the component is already vendored, it will be skipped unless --force is\u001b[0m\u001b[38;2;247;250;252m specified.\u001b[0m\n\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mIf component is not specified, prompts interactively for\u001b[0m\u001b[38;2;247;250;252m selection.\u001b[0m\n"] +[0.000026541,"o","\n"] +[0.00000425,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[0.000001875,"o","\n"] +[0.000051542,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54msource\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mpull\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000001958,"o","\n"] +[0.000003542,"o","\u001b[1;38;2;0;163;224mEXAMPLES\u001b[0m\n"] +[9.58e-7,"o","\n"] +[0.000103042,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m# Vendor component source (downloads if missing or outdated)\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source pull vpc --stack dev\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # Force re-vendor even if up-to-date\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source pull vpc --stack dev --force\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m # Interactive: prompts for component and stack\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;231;229;227;48;2;47;46;54m atmos aws cloudformation source pull\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.000028333,"o","\n"] +[0.000014292,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001042,"o","\n"] +[0.000106375,"o"," "] +[0.000003083,"o","\u001b[1;38;2;0;163;224m-f, --force\u001b[0m"] +[0.000001292,"o"," "] +[0.000121875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mForce re-vendor even if component directory\u001b[0m\u001b[38;2;255;255;255m exists\u001b[0m\u001b[0m\n"] +[0.000001333,"o","\n"] +[0.000001,"o"," "] +[0.000002417,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[9.58e-7,"o"," "] +[0.000100542,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m pull\u001b[0m\u001b[0m\n"] +[0.000001541,"o","\n"] +[0.000001334,"o"," "] +[0.000002333,"o","\u001b[1;38;2;0;163;224m-i, --identity\u001b[0m"] +[0.00000125,"o"," "] +[0.000002833,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.75e-7,"o"," "] +[0.000097125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mIdentity to use for authentication (use without value to\u001b[0m\u001b[38;2;255;255;255m select\u001b[0m\u001b[0m\n"] +[0.000003167,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255minteractively)\u001b[0m\u001b[0m\n"] +[9.58e-7,"o","\n"] +[9.17e-7,"o"," "] +[0.000002542,"o","\u001b[1;38;2;0;163;224m-s, --stack\u001b[0m"] +[0.00000175,"o"," "] +[0.000002291,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[8.34e-7,"o"," "] +[0.000092458,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mStack\u001b[0m\u001b[38;2;255;255;255m name\u001b[0m\u001b[0m\n"] +[0.000001458,"o","\n"] +[9.17e-7,"o","\n"] +[0.001661667,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"] diff --git a/website/static/casts/screengrabs/atmos-aws-cloudformation-validate--help.cast b/website/static/casts/screengrabs/atmos-aws-cloudformation-validate--help.cast new file mode 100644 index 00000000000..7afe17a887e --- /dev/null +++ b/website/static/casts/screengrabs/atmos-aws-cloudformation-validate--help.cast @@ -0,0 +1,107 @@ +{"version":3,"term":{"cols":90,"rows":36,"type":"xterm-256color"},"timestamp":1787853928,"command":"aws cloudformation validate --help","env":{"COLORTERM":"truecolor","SHELL":"/bin/zsh"}} +[0.202914333,"o","\n"] +[0.000122459,"o","\u001b[38;5;184m \u001b[0m\u001b[38;5;184m█\u001b[0m\u001b[38;5;178m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\n\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m█\u001b[0m\u001b[38;5;214m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m \u001b[0m\n\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m█\u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m█\u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;198m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;199m█\u001b[0m\u001b[38;5;163m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m█\u001b[0m\u001b[38;5;164m \u001b[0m\n\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;208m \u001b[0m\u001b[38;5;209m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;203m \u001b[0m\u001b[38;5;204m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;198m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;199m \u001b[0m\u001b[38;5;163m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\u001b[38;5;164m \u001b[0m\n\n"] +[0.000061333,"o","👽 \u001b[38;2;73;85;104mtest\u001b[0m \u001b[38;2;73;85;104mdarwin/arm64\u001b[0m\n"] +[0.000001833,"o","\n"] +[0.001747542,"o","\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mValidate the template\u001b[0m\u001b[38;2;247;250;252m server-side\u001b[0m\n"] +[0.000002542,"o","\n"] +[0.00000375,"o","\u001b[1;38;2;0;163;224mUSAGE\u001b[0m\n"] +[8.75e-7,"o","\n"] +[0.000049208,"o"," \u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m\u001b[38;2;87;83;78;48;2;47;46;54m$ \u001b[0m\u001b[1;38;2;155;81;224;48;2;47;46;54matmos\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mcloudformation\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54mvalidate\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[component]\u001b[0m\u001b[38;2;231;229;227;48;2;47;46;54m \u001b[0m\u001b[3;38;2;231;229;227;48;2;47;46;54m[flags]\u001b[0m\u001b[0m\u001b[48;2;47;46;54m \u001b[0m\n \u001b[48;2;47;46;54m \u001b[0m\n"] +[0.00001775,"o","\n"] +[0.00001525,"o","\u001b[1;38;2;0;163;224mFLAGS\u001b[0m\n"] +[0.000001208,"o","\n"] +[0.00013325,"o"," "] +[0.000004042,"o","\u001b[1;38;2;0;163;224m --affected\u001b[0m"] +[0.000001625,"o"," "] +[0.000125708,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess affected aws/cloudformation components\u001b[0m\u001b[38;2;255;255;255m in\u001b[0m\u001b[0m\n"] +[0.000005667,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdependency\u001b[0m\u001b[38;2;255;255;255m order.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001708,"o"," "] +[0.000003334,"o","\u001b[1;38;2;0;163;224m --all\u001b[0m"] +[0.000001333,"o"," "] +[0.000119292,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mProcess all aws/cloudformation components in\u001b[0m\u001b[38;2;255;255;255m dependency\u001b[0m\u001b[0m\n"] +[0.000004083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255morder.\u001b[0m\u001b[0m\n"] +[0.000001375,"o","\n"] +[0.000001208,"o"," "] +[0.000003584,"o","\u001b[1;38;2;0;163;224m --base\u001b[0m"] +[0.000001166,"o"," "] +[0.000002875,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001084,"o"," "] +[0.000120083,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit base ref or SHA to compare against for\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000004167,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mdetection.\u001b[0m\u001b[0m\n"] +[0.000001625,"o","\n"] +[0.000001291,"o"," "] +[0.000014167,"o","\u001b[1;38;2;0;163;224m --clone-target-ref\u001b[0m"] +[0.000003875,"o"," "] +[0.000141667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mClone the target ref instead of checking it out in\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.00000575,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcurrent repository for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.000001416,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m-h, --help\u001b[0m"] +[0.000001375,"o"," "] +[0.000121333,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mhelp for\u001b[0m\u001b[38;2;255;255;255m validate\u001b[0m\u001b[0m\n"] +[0.000019,"o","\n"] +[0.000001667,"o"," "] +[0.000004042,"o","\u001b[1;38;2;0;163;224m --include-dependents\u001b[0m"] +[0.00000125,"o"," "] +[0.000143125,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mInclude dependent components when processing\u001b[0m\u001b[38;2;255;255;255m affected\u001b[0m\u001b[0m\n"] +[0.000005291,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255maws/cloudformation\u001b[0m\u001b[38;2;255;255;255m components.\u001b[0m\u001b[0m\n"] +[0.0000015,"o","\n"] +[0.000001417,"o"," "] +[0.000003167,"o","\u001b[1;38;2;0;163;224m --labels\u001b[0m"] +[0.000001125,"o"," "] +[0.000003458,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001417,"o"," "] +[0.000123625,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by labels (comma-separated key=value or key\u001b[0m\u001b[38;2;255;255;255m:value\u001b[0m\u001b[0m\n"] +[0.000005916,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mpairs, matches all):\u001b[0m\u001b[38;2;255;255;255m --labels=cost-\u001b[0m\u001b[0m\n"] +[0.000004834,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mcenter=platform,compliance=sox\u001b[0m\u001b[0m\n"] +[0.000001583,"o","\n"] +[0.000001292,"o"," "] +[0.000003375,"o","\u001b[1;38;2;0;163;224m --ref\u001b[0m"] +[9.58e-7,"o"," "] +[0.000002625,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000102875,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit ref to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000001417,"o","\n"] +[0.000001208,"o"," "] +[0.000003042,"o","\u001b[1;38;2;0;163;224m --repo-path\u001b[0m"] +[0.000001083,"o"," "] +[0.000002708,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.00000125,"o"," "] +[0.000119667,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the already cloned target repository to use\u001b[0m\u001b[38;2;255;255;255m as\u001b[0m\u001b[0m\n"] +[0.000004667,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mthe affected\u001b[0m\u001b[38;2;255;255;255m baseline.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.00000125,"o"," "] +[0.0000035,"o","\u001b[1;38;2;0;163;224m --sha\u001b[0m"] +[0.000001,"o"," "] +[0.000002375,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001125,"o"," "] +[0.000104208,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mGit SHA to compare against for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.00000125,"o","\n"] +[0.000001042,"o"," "] +[0.000002791,"o","\u001b[1;38;2;0;163;224m --ssh-key\u001b[0m"] +[9.17e-7,"o"," "] +[0.000009333,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.0000055,"o"," "] +[0.000147417,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPath to the SSH private key used to clone the\u001b[0m\u001b[38;2;255;255;255m target\u001b[0m\u001b[0m\n"] +[0.000008875,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000013333,"o","\n"] +[0.000001709,"o"," "] +[0.000004125,"o","\u001b[1;38;2;0;163;224m --ssh-key-password\u001b[0m"] +[0.000001208,"o"," "] +[0.000003583,"o","\u001b[38;2;73;85;104mstring\u001b[0m"] +[0.000001084,"o"," "] +[0.0001205,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mPassword for the SSH private key used to clone\u001b[0m\u001b[38;2;255;255;255m the\u001b[0m\u001b[0m\n"] +[0.000005375,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtarget ref for affected\u001b[0m\u001b[38;2;255;255;255m detection.\u001b[0m\u001b[0m\n"] +[0.000003708,"o","\n"] +[0.000001208,"o"," "] +[0.000003542,"o","\u001b[1;38;2;0;163;224m --tags\u001b[0m"] +[9.17e-7,"o"," "] +[0.000002541,"o","\u001b[38;2;73;85;104mstrings\u001b[0m"] +[0.000001084,"o"," "] +[0.000099833,"o","\u001b[38;2;255;255;255m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mFilter by tags (comma-separated, matches any):\u001b[0m\u001b[38;2;255;255;255m --\u001b[0m\u001b[0m\n"] +[0.000004083,"o"," \u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m\u001b[38;2;255;255;255m\u001b[0m \u001b[38;2;255;255;255m \u001b[0m\u001b[38;2;255;255;255mtags=production,tier-1\u001b[0m\u001b[0m\n"] +[0.000001209,"o","\n"] +[9.16e-7,"o","\n"] +[0.001577209,"o","\n\u001b[38;2;73;85;104m\u001b[38;2;247;250;252m\u001b[0m\u001b[38;2;247;250;252m\u001b[0m \u001b[38;2;247;250;252mUse \u001b[0m\u001b[38;2;0;255;255;1m--help=usage\u001b[0m\u001b[38;2;247;250;252m for examples or \u001b[0m\u001b[38;2;0;255;255;1m--help=all\u001b[0m\u001b[38;2;247;250;252m for all flags and full\u001b[0m\u001b[38;2;247;250;252m help.\u001b[0m\u001b[0m\n"]