From adeb2e5669d738ff93b975ae622ca35bafd518e9 Mon Sep 17 00:00:00 2001 From: Sam Manzer Date: Thu, 5 Oct 2023 16:20:38 -0400 Subject: [PATCH] vibe check update - just a preview so folks see where I am going --- README.md | 91 +++++++- docs/foundations/args.md | 4 + docs/foundations/cleanup-actions.md | 73 +++++++ docs/foundations/design-philosophy.md | 16 ++ docs/foundations/steps.md | 59 +++++ docs/ttp-dev.md | 201 ------------------ ttps/examples/steps/create-file/README.md | 22 ++ .../create-file/create-file-example.yaml | 13 ++ ttps/examples/steps/edit-file/README.md | 22 ++ .../steps/edit-file/edit-file-example.yaml | 50 +++++ ttps/examples/steps/edit-step/README.md | 75 ------- ttps/examples/steps/edit-step/edit-step.yaml | 33 --- .../examples/steps/edit-step/file-to-edit.txt | 21 -- 13 files changed, 349 insertions(+), 331 deletions(-) create mode 100644 docs/foundations/args.md create mode 100644 docs/foundations/cleanup-actions.md create mode 100644 docs/foundations/design-philosophy.md create mode 100644 docs/foundations/steps.md delete mode 100644 docs/ttp-dev.md create mode 100644 ttps/examples/steps/create-file/README.md create mode 100644 ttps/examples/steps/create-file/create-file-example.yaml create mode 100644 ttps/examples/steps/edit-file/README.md create mode 100644 ttps/examples/steps/edit-file/edit-file-example.yaml delete mode 100644 ttps/examples/steps/edit-step/README.md delete mode 100644 ttps/examples/steps/edit-step/edit-step.yaml delete mode 100644 ttps/examples/steps/edit-step/file-to-edit.txt diff --git a/README.md b/README.md index cc45df0..a6c3574 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,96 @@ [![Pre-Commit](https://github.com/facebookincubator/ForgeArmory/actions/workflows/pre-commit.yaml/badge.svg)](https://github.com/facebookincubator/ForgeArmory/actions/workflows/pre-commit.yaml) [![Renovate](https://github.com/facebookincubator/ForgeArmory/actions/workflows/renovate.yaml/badge.svg)](https://github.com/facebookincubator/ForgeArmory/actions/workflows/renovate.yaml) -This repo hosts the community-driven TTPs that Meta's TTPForge can consume. +TTPForge is a cyber attack simulation platform. This project promotes a +Purple Team approach to cybersecurity with the following goals: + +* To help blue teams accurately measure their detection and response capabilities + through high-fidelity simulations of real attacker activity. +* To help red teams improve the ROI/actionability of their findings by packaging + their attacks as automated, repeatable simulations. + +TTPForge allows you to automate attacker tactics, techniques, and procedures (TTPs) +using a powerful but easy-to-use YAML format. This repo +contains our open-source catalog of TTPForge-powered TTPs - +check out the links below to learn more: + +* [Install TTPForge](#installation) +* [TTPForge Design Philosophy](docs/foundations/design-philosophy.md) +* [Writing TTPs with TTPForge](docs/foundations/writing-ttps.md) +* [Our TTP Library](https://github.com/facebookincubator/ForgeArmory/tree/main/ttps) + +## Installation + +1. Get latest TTPForge release: + + ```bash + bashutils_url="https://raw.githubusercontent.com/l50/dotfiles/main/bashutils" + + bashutils_path="/tmp/bashutils" + + if [[ ! -f "${bashutils_path}" ]]; then + curl -s "${bashutils_url}" -o "${bashutils_path}" + fi + + source "${bashutils_path}" + + fetchFromGithub "facebookincubator" "TTPForge" "latest" ttpforge + ``` + + At this point, the latest `ttpforge` release should be in + `~/.local/bin/ttpforge` and subsequently, the `$USER`'s `$PATH`. + + If running in a stripped down system, you can add TTPForge to your `$PATH` + with the following command: + + ```bash + export PATH=$HOME/.local/bin:$PATH + ``` + +1. Initialize TTPForge configuration + + This command will place a configuration file at the default location + `~/.ttpforge/config.yaml` and download the + [ForgeArmory](https://github.com/facebookincubator/ForgeArmory) + TTPs repository: + + ```bash + ttpforge init + ``` + +TTPForge is now ready to use - check out our [tutorial](#tutorial) to +start exploring its capabilities. + +## Tutorial + +1. List available TTP repositories (should show `forgearmory`) + + ```bash + ttpforge list repos + ``` + +1. List available TTPs that you can run: + + ```bash + ttpforge list ttps + ``` + +1. Examine an example TTP: + + ```bash + ttpforge show ttp forgearmory//examples/args/define-args.yaml + ``` + +1. Run the specified example: + + ```bash + ttpforge run \ + forgearmory//examples/args/define-args.yaml \ + --arg a_message="hello" \ + --arg a_number=1337 + ``` + +1. Next, check out the Armory's collection of [TTPs](https://github.com/facebookincubator/ForgeArmory/tree/main/ttps) and learn to [write your own TTPs](docs/foundations/writing-ttps.md) --- diff --git a/docs/foundations/args.md b/docs/foundations/args.md new file mode 100644 index 0000000..af8f115 --- /dev/null +++ b/docs/foundations/args.md @@ -0,0 +1,4 @@ +# Command-line Arguments: Making TTPs Configurable + +The TTPForge YAML format provides a rich syntax for specifying and validating +command-line arguments and using them to control TTP execution. \ No newline at end of file diff --git a/docs/foundations/cleanup-actions.md b/docs/foundations/cleanup-actions.md new file mode 100644 index 0000000..ce0bb27 --- /dev/null +++ b/docs/foundations/cleanup-actions.md @@ -0,0 +1,73 @@ +# Reliable Post-Execution Cleanup + +## Goals + +TTPs will often include destructive (or at the very least, messy) actions, such as: + +* Editing System Files (such as `/etc/sudoers` or `/root/.ssh/authorized_keys`) +* Killing/Disabling Critical System Services (especially endpoint security solutions such as MDE) +* Launching Cloud Resources (EC2 Instances/Docker Containers/Kubernetes Pods) + +Failure to clean up properly after such activity will at the very least inconvenience the user, +and at worst may actually create severe new security vulnerabilities in the target system. + +Interpreter scripts usually lack standardized, platform-independent, and reliable methods for +cleaning up attacker activity. In particular, it is especially difficult to ensure that these clean up +processes are resilient to runtime errors. For example, when writing TTPs in bash, one would +need to make very careful use of the [trap](https://tldp.org/LDP/Bash-Beginners-Guide/html/sect_12_02.html) feature. + +TTPForge's native support for cleanup actions provides users +a reliable solution to these problems. + +## A Basic Cleanup Action + +Every [step](steps.md) in a TTPForge TTP can be associated with a specific cleanup action. +For example, we could create a cleanup action that removes a file created during the +execution of the TTP, as shown below: + +https://github.com/facebookincubator/TTPForge/blob/main/cmd/test-resources/repos/example-ttps/cleanup/single.yaml + +This cleanup action will be executed once the TTP completes. +Cleanup actions are most commonly `inline:` commands, as in the example above. +However, you can use any valid TTPForge step type as a cleanup action. + +## Multiple Cleanup Actions for Multiple Steps + +If we have multiple steps, we can create an appropriate cleanup action for each one. +The example TTP below demonstrates how this works - for clarity, we've simplified the actual +commands by replacing them with placeholders: + +https://github.com/facebookincubator/TTPForge/blob/main/cmd/test-resources/repos/example-ttps/cleanup/multiple.yaml + +This example highlights a crucial TTPForge feature: cleanup actions are run in last-in, +first-out (LIFO) order. Therefore, In this example, the malicious launch agent will be deleted prior to +re-enabling EDR. This is critical; if cleanup actions were instead run in the same +order as the steps themselves (first in, first out), then defenders would +receive unrealistic signal (EDR would detect the payload) and the fidelity of the simulation +would be compromised. + +## Fault Tolerance - Cleaning When Things Go Wrong + +If a particular step from the TTP fails to execute, prior steps that already executed +still need to be cleaned up properly. Therefore, after each step, the corresponding +cleanup action is enqueued and, in the case of failure, all enqueued steps are executed +in reverse (LIFO) order. The below TTP illustrates this behavior: + +https://github.com/facebookincubator/TTPForge/blob/main/cmd/test-resources/repos/example-ttps/cleanup/lifo.yaml + +As the third step is guaranteed to fail, +this TTP will always print the following cleanup activity + +``` +cleaning up second step +cleaning up first step +``` + +## Delaying or Disabling Cleanup + +Sometimes, one may wish to execute a given TTP and then to leave the target system in +a "dirty" state for further analysis. For these purposes, TTPForge provides +two useful command line flags for the `ttpforge run` command: + +* `--cleanup-delay-seconds` - delay cleanup execution for the specified integer number of seconds +* `--no-cleanup` - do not run any cleanup actions; instead, simply exit when the last step completes. \ No newline at end of file diff --git a/docs/foundations/design-philosophy.md b/docs/foundations/design-philosophy.md new file mode 100644 index 0000000..5f2cd6b --- /dev/null +++ b/docs/foundations/design-philosophy.md @@ -0,0 +1,16 @@ +# Design Philosophy - TTPForge + +By far the fastest and easiest way to create an automated simulation of +attacker TTPs is to simply write a script that downloads +any required attacker tooling and then runs the appropriate commands. +We'll refer to all such scripts (bash/powershell/python/etc.) as "interpreter scripts." +Interpreter scripts are delightfully simple and quick to implement; +however, attempts to scale attack simulation efforts based on collections of interpreter +scripts quickly run into a variety of problems listed below. TTPForge attempts to solve +these problems while keeping TTP development just as fast and simple as interpreter scripts +- click each link to see how the project aims to address that particular challenge: + +1. [High-Fidelity Telemetry Generation](steps.md) +1. [Reliable Post-Execution Cleanup](cleanup-actions.md) +1. [Convenient and Powerful Command Line Arguments](args.md) +1. [Composability - Avoiding Reinventing the Wheel](steps.md#subttp-step) \ No newline at end of file diff --git a/docs/foundations/steps.md b/docs/foundations/steps.md new file mode 100644 index 0000000..8c1e068 --- /dev/null +++ b/docs/foundations/steps.md @@ -0,0 +1,59 @@ +# Steps + +Relying on interpreter scripts for attack simulation will often provide defenders with logs/telemetry +that differs from what they would observer in real cyber threat situations. For instance, +an attacker who is maliciously editing a configuration file is unlikely to +do so by running a shell command such as: + +``` +sed -ie 's/benign/malicious/' sabotaged.cfg +``` + +The code above will generate a varienty of indicators of compromise (IOCs) that would be visible +to defenders: + +1. Shell History Logs +1. Process Execution Logs + +In reality, an attacker would likely simply edit the file with an existing editor program (such as VS Code) +or modify it directly from their C2 implant with no shell involved. Raw file modification telemetry +would likely be necessary to detect this malicious action, and the attack simulation should reflect +that reality. + +TTPForge solves this problem by providing a wide range of native YAML-based steps from +which attack chains can be constructed. These steps (downloading files, editing files, etc.) are +natively built into the TTPForge engine itself and do not produce unrealistic shell history telemetry. + +Note that the logs associated with execution of `ttpforge` itself from an interactive shell might be considered undesirable telemetry in certain situations - should this be the case, one can consider +obfuscating `ttpforge` by renaming the binary or employing purpose-built obfuscation tools such as +[garble](https://github.com/burrowers/garble). + +Each of TTPForge's step types is described below. + +# Create File Step + +This step will create a file the specified contents +on disk. Example use cases include: + +* Writing a malicious `crontab` file to establish persistence. +* Dropping a malicious PHP webshell in `/var/www/html`. + +Usage of the `create_file:` step is demonstrated below: + +https://github.com/facebookincubator/TTPForge/blob/main/ttps/examples/steps/create-file/create-file-example.yaml + +Run this example as follows: + +```bash +ttpforge run forgearmory//examples/steps/edit-file/edit-file-example.yaml +``` + +[create_file](../../ttps/examples/steps/create-file/README.md) +[edit_file](../../ttps/examples/steps/edit-file/README.md) + +COMING SOON + +`file:` +`inline:` +`fetch_uri:` +`ttp:` \ No newline at end of file diff --git a/docs/ttp-dev.md b/docs/ttp-dev.md deleted file mode 100644 index 0492a46..0000000 --- a/docs/ttp-dev.md +++ /dev/null @@ -1,201 +0,0 @@ -# TTP Development - -This document introduces concepts to help developers -create their own TTPs for use in TTPForge. - -## TTP Anatomy - -ForgeArmory TTPs are designed to be consumed by [TTPForge](https://github.com/facebookincubator/TTPForge), -which provides an interface to execute TTPs across various targets and mediums. -Each ForgeArmory TTP consists of metadata and optional argument declarations. -The steps define the TTP implementation logic. - -### Metadata - -TTP metadata must include the name of the TTP and a description of that TTP's -behavior. MITRE ATT&CK IDs are optional but recommended. If the TTP cannot be -mapped to MITRE ATT&CK then the `mitre` mapping and its child mappings should be -omitted. - -An example of TTP metadata is shown below. - -```yaml ---- -name: Leverage mdfind to search for aws credentials on disk. -description: | - This TTP runs a search using mdfind to search for AKIA strings in files, - which would likely indicate that the file is an aws key. -mitre: - tactics: - - TA0006 Credential Access - techniques: - - T1552 Unsecured Credentials - subtechniques: - - "T1552.001 Unsecured Credentials: Credentials In Files" -``` - -### Arguments - -Arguments are defined after the TTP metadata. Arguments are uniquely named, -may be strongly typed, and may contain default values. Using an argument in -the TTP is done with the argument syntax, `{{ .Args.arg_name }}`. -A complete example is shown below. - -```yaml -args: - - name: a_message - - name: a_number - type: int - - name: has_a_default - default: this is the default value -steps: - - name: print_args - inline: | - set -e - - echo "hi! You passed the message: {{ .Args.a_message }}" - echo "You passed the number: {{ .Args.a_number }}" - echo "has_a_default has the value: '{{ .Args.has_a_default }}'" -``` - -### Steps - -Steps are uniquely named blocks of implementation logic which are executed in -sequence. Steps help developers organize and manage the complexity of TTPs. - -In general, steps will fall into one of the following high-level categories; - -- Assessment -- Shaping -- Execution -- Cleanup - -Additionally, TTPs may be daisy-chained enabling developers to create complex -sequences of TTPs. In doing so, each daisy-chained TTP is represented in the -parent TTP as a sub-TTP. We'll see an example of this shortly and some -recommendations on developing sub-TTPs as common building blocks. - -#### Assessment - -It is often necessary for a TTP to test execution requirements, such as whether -a necessary environment variable is set, and bail out of the TTP if it is not. -In this example, if the `AWS_DEFAULT_REGION` environment variable is not set, -the TTP returns exit code 1 and no further blocks are executed. - -```yaml -steps: - - name: ensure-aws-creds-present - inline: | - set -e - - if [[ -z "${AWS_DEFAULT_REGION}" ]]; then - echo "Error: AWS_DEFAULT_REGION must be set." - exit 1 - fi - -<- snip -> -``` - -When creating assessment type blocks, it's preferable to place each test in its -own block rather than a single block that tests all prerequisites. This approach -will make your TTPs much easier to maintain as they become more complex. - -#### Shaping - -It is often necessary for a TTP to install dependencies, stage files, or shape -the target environment prior to executing the core TTP logic. As with assessment -type blocks, when creating shaping type blocks, it's preferable to place each -action in its own block. - -```yaml -<- snip -> - - - name: setup - inline: | - set -e - - if [[ -d "{{ .Args.eiam_path }}" ]]; then - echo "Info: enumerate-iam already present on the current system" - else - git clone https://github.com/andresriancho/enumerate-iam.git {{ .Args.eiam_path }} - fi - -<- snip -> -``` - -#### Execution - -The execution blocks contain the core TTP logic. A single execution block may -be sufficient for simple TTPs such as atomics, which contain a single procedure. -For complex TTPs, the core logic should be broken up across multiple steps or -sub-TTPs. In general, if the core logic implements multiple procedures or the -procedure can be reasonably divided, refactoring into smaller steps will enhance -maintainability. - -Code likely to be reused in other TTPs should be placed in a sub-TTP and imported -where needed. It's easier to maintain building blocks than to modify the same -(reimplemented) code in multiple places. Good candidates for sub-TTPs include -assessment and shaping operations. Here, you might check for commonly used -prerequisites, install frequent tools, or tamper with security controls before -the primary execution block. - -```yaml -steps: - - name: first_sub_ttp - ttp: examples/sub-ttps/my-sub-ttps/ttp1.yaml - - name: second_sub_ttp - ttp: examples/sub-ttps/my-sub-ttps/ttp2.yaml -``` - -#### Cleanup - -In addition to the implementation logic, each TTP must contain a `cleanup` block -to revert artifacts from the preceding blocks. If no implementation blocks produce -artifacts, the `cleanup` block should just return a success log. - -Example with implementation block artifacts: Here, we revert changes made in -previous steps. - -```yaml -steps: - - name: disable-updates - inline: | - set -e - - echo -e "===> Disabling automatic installation of security updates..." - sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool NO - echo "[+] DONE!" - - cleanup: - inline: | - set -e - - echo -e "===> Enabling automatic installation of security updates..." - sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate.plist CriticalUpdateInstall -bool YES - echo "[+] DONE!" -``` - -Example without implementation block artifacts: No changes were made to the -target system. This is reported in the success log. - -```yaml -steps: - - name: clipdump_cli - inline: | - echo -e "===> Dumping clipboard to stdout..." - pbpaste - echo "[+] DONE!" - cleanup: - inline: | - echo "No cleanup needed, as this TTP simply dumped clipboard contents to stdout." -``` - -### Pre-Commit Hooks - -Every so often, we introduce pre-commit hooks to ensure that -the developer experience is easy and has a low barrier to entry. - -However, some hooks may introduce unnecessary overhead. -To address this, all new pre-commit hooks will undergo a one-month -trial period. If they hinder the developer experience during this time, -we will remove them. diff --git a/ttps/examples/steps/create-file/README.md b/ttps/examples/steps/create-file/README.md new file mode 100644 index 0000000..3b278d8 --- /dev/null +++ b/ttps/examples/steps/create-file/README.md @@ -0,0 +1,22 @@ +# The `create_file:` Step + +This step type will edit the contents of a specified existing +target file. Reach for this step in a situation where you +might use `sed`. Example use cases include: + +* Adding a malicious `/etc/sudoers` entry. +* Commenting out authorization checks in critical server-side code. + +## Example Usage + +Usage of the `create_file:` step is demonstrated in the below TTP: + +https://github.com/facebookincubator/TTPForge/blob/main/ttps/examples/steps/create-file/create-file-example.yaml + +## Run This Example + +Run this example as follows: + +```bash +ttpforge run forgearmory//examples/steps/create-file/create-file-example.yaml +``` \ No newline at end of file diff --git a/ttps/examples/steps/create-file/create-file-example.yaml b/ttps/examples/steps/create-file/create-file-example.yaml new file mode 100644 index 0000000..a72cbd3 --- /dev/null +++ b/ttps/examples/steps/create-file/create-file-example.yaml @@ -0,0 +1,13 @@ +--- +name: create-file-example +description: | + This TTP demonstrates usage of the create-file-step +steps: + - name: create-new-file + create_file: /tmp/file-path-you-want-to-write + contents: | + The contents string that you specfify here + will be written to the new file + overwrite: true # should we overwrite the file if it already exists + cleanup: false # whether you want the new file cleaned up when the TTP is done (default true) + mode: 0400 # chmod-style octal permission mode \ No newline at end of file diff --git a/ttps/examples/steps/edit-file/README.md b/ttps/examples/steps/edit-file/README.md new file mode 100644 index 0000000..910d9d7 --- /dev/null +++ b/ttps/examples/steps/edit-file/README.md @@ -0,0 +1,22 @@ +# The `edit_file:` Step + +This step type will edit the contents of a specified existing +target file. Reach for this step in a situation where you +might use `sed`. Example use cases include: + +* Adding a malicious `/etc/sudoers` entry. +* Commenting out authorization checks in critical server-side code. + +## Example Usage + +Usage of the `edit_file:` step is demonstrated in the below TTP: + +https://github.com/facebookincubator/TTPForge/blob/main/ttps/examples/steps/edit-file/edit-file-example.yaml + +## Run This Example + +Run this example as follows: + +```bash +ttpforge run forgearmory//examples/steps/edit-file/edit-file-example.yaml +``` \ No newline at end of file diff --git a/ttps/examples/steps/edit-file/edit-file-example.yaml b/ttps/examples/steps/edit-file/edit-file-example.yaml new file mode 100644 index 0000000..5cd2852 --- /dev/null +++ b/ttps/examples/steps/edit-file/edit-file-example.yaml @@ -0,0 +1,50 @@ +--- +name: edit-file-example +description: edits a file in various ways +args: + - name: target_file_path + default: /tmp/edit-file-example-target +steps: + - name: create-target-file + create_file: {{ .Args.target_file_path }} + overwrite: true + cleanup: false + contents: | + This is an example file. + + The TTP will replace the string below: + + REPLACE_ME + + It will also delete the multi-line string below and replace + it with a comment: + + + result = await myclass.multi_line_function_call( + param1, + param2, + ) + + Finally, it will comment out the line below using a C-Style /* ... */ comment. + + another_multline_function_call( + param1, + param2, + ) + - name: edit-target-file + edit_file: {{ .Args.target_file_path }} + backup_file: "/tmp/my-backup.txt" + edits: + - old: REPLACE_ME + new: REPLACED_BY_EDIT # replace all instances of REPLACE_ME with REPLACED_BY_EDIT + - old: (?ms:^result = await myclass\.multi_line_function_call\(.*?\)$) # golang format regexp + new: "# replaced with comment" # replace all matching lines with this string + regexp: true # specify use of regexp rather than literal matches + - old: (?P(?ms:^another_multline_function_call\(.*?\)$)) + new: "/*${fn_call}*/" # use backreferences to prefix the original line with a comment + regexp: true + cleanup: false # whether you want the original file restored from the backup automatically + - name: view-edited-file + inline: cat {{ .Args.target_file_path }} + + \ No newline at end of file diff --git a/ttps/examples/steps/edit-step/README.md b/ttps/examples/steps/edit-step/README.md deleted file mode 100644 index 6735c06..0000000 --- a/ttps/examples/steps/edit-step/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# File Modification using `edit_file` Step - -Discover how to make amendments to files leveraging the `edit_file` step, -a versatile tool for editing files through string matching or regular expressions. - ---- - -## Running `edit-step.yaml` Demonstration - -Execute the following command to illustrate the power of the `edit_file` step: - -```bash -ttpforge run forgearmory//examples/steps/edit-step/edit-step.yaml -``` - ---- - -## Expected Output - -```text -INFO [*] Validating Steps -INFO [+] Finished validating steps -INFO [+] Running current TTP: edit_step_example -INFO [+] Running current step: target-file-pre-edit -INFO ========= Executing ========== -This is an example file. - -The TTP will replace the string below: - -REPLACE_ME - -It will also delete the multi-line string below and replace -it with a comment: - -result = await myclass.multi_line_function_call( - param1, - param2, -) - -Lastly, it will comment out the subsequent lines using a C-Style /* ... */ comment. - -another_multline_function_call( - param1, - param2, -) -INFO ========= Done ========== -INFO [+] Finished running step: target-file-pre-edit -INFO [+] Running current step: edit-target-file -INFO [+] Finished running step: edit-target-file -INFO [+] Running current step: target-file-post-edit -INFO ========= Executing ========== -This is an example file. - -The TTP has replaced the string below with: - -REPLACED_BY_EDIT - -The multi-line string was deleted and replaced with a comment: - -# replaced with comment - -The following lines have been commented using a C-Style /* ... */ comment: - -/*another_multline_function_call( - param1, - param2, -)*/ -INFO ========= Done ========== -INFO [+] Finished running step: target-file-post-edit -INFO [*] Completed TTP -INFO [*] Starting Cleanup -INFO ========= Executing ========== -INFO ========= Done ========== -INFO [*] Cleanup Complete -``` diff --git a/ttps/examples/steps/edit-step/edit-step.yaml b/ttps/examples/steps/edit-step/edit-step.yaml deleted file mode 100644 index 8f83961..0000000 --- a/ttps/examples/steps/edit-step/edit-step.yaml +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: edit_step_example -description: edits a file in various ways -steps: - - name: target-file-pre-edit - inline: | - set -e - - echo -e "Target file pre-edit:" - cat file-to-edit.txt - - name: edit-target-file - edit_file: "file-to-edit.txt" - backup_file: "/tmp/my-backup.txt" - edits: - - old: REPLACE_ME - new: REPLACED_BY_EDIT - - old: (?ms:^result = await myclass\.multi_line_function_call\(.*?\)$) - new: "# replaced with comment" - regexp: true - - old: (?P(?ms:^another_multline_function_call\(.*?\)$)) - new: "/*${fn_call}*/" - regexp: true - - name: target-file-post-edit - inline: | - set -e - - echo -e "Target file post-edit:" - cat $HOME/.ttpforge/repos/forgearmory/ttps/examples/steps/edit-step/file-to-edit.txt - cleanup: - inline: | - set -e - - mv /tmp/my-backup.txt $HOME/.ttpforge/repos/forgearmory/ttps/examples/steps/edit-step/file-to-edit.txt diff --git a/ttps/examples/steps/edit-step/file-to-edit.txt b/ttps/examples/steps/edit-step/file-to-edit.txt deleted file mode 100644 index 1fdc49e..0000000 --- a/ttps/examples/steps/edit-step/file-to-edit.txt +++ /dev/null @@ -1,21 +0,0 @@ -This is an example file. - -The TTP will replace the string below: - -REPLACE_ME - -It will also delete the multi-line string below and replace -it with a comment: - - -result = await myclass.multi_line_function_call( - param1, - param2, -) - -Finally, it will comment out the line below using a C-Style /* ... */ comment. - -another_multline_function_call( - param1, - param2, -)